changes to support outbound-addr
Fixes #6064 Signed-off-by: Bohumil Cervenka <5eraph@protonmail.com>
This commit is contained in:
		
							parent
							
								
									2e3928ee17
								
							
						
					
					
						commit
						e6a5a56aa6
					
				| 
						 | 
				
			
			@ -560,9 +560,14 @@ Valid values are:
 | 
			
		|||
- `ns:<path>`: path to a network namespace to join
 | 
			
		||||
- `private`: create a new namespace for the container (default)
 | 
			
		||||
- `slirp4netns[:OPTIONS,...]`: use slirp4netns to create a user network stack.  This is the default for rootless containers.  It is possible to specify these additional options:
 | 
			
		||||
  **port_handler=rootlesskit**: Use rootlesskit for port forwarding.  Default.
 | 
			
		||||
  **port_handler=slirp4netns**: Use the slirp4netns port forwarding.
 | 
			
		||||
  **allow_host_loopback=true|false**: Allow the slirp4netns to reach the host loopback IP (`10.0.2.2`).  Default to false.
 | 
			
		||||
  - **allow_host_loopback=true|false**: Allow the slirp4netns to reach the host loopback IP (`10.0.2.2`). Default is false.
 | 
			
		||||
  - **enable_ipv6=true|false**: Enable IPv6. Default is false. (Required for `outbound_addr6`).
 | 
			
		||||
  - **outbound_addr=INTERFACE**: Specify the outbound interface slirp should bind to (ipv4 traffic only).
 | 
			
		||||
  - **outbound_addr=IPv4**: Specify the outbound ipv4 address slirp should bind to.
 | 
			
		||||
  - **outbound_addr6=INTERFACE**: Specify the outbound interface slirp should bind to (ipv6 traffic only).
 | 
			
		||||
  - **outbound_addr6=IPv6**: Specify the outbound ipv6 address slirp should bind to.
 | 
			
		||||
  - **port_handler=rootlesskit**: Use rootlesskit for port forwarding. Default.
 | 
			
		||||
  - **port_handler=slirp4netns**: Use the slirp4netns port forwarding.
 | 
			
		||||
 | 
			
		||||
**--network-alias**=*alias*
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -171,6 +171,8 @@ type slirpFeatures struct {
 | 
			
		|||
	HasMTU                 bool
 | 
			
		||||
	HasEnableSandbox       bool
 | 
			
		||||
	HasEnableSeccomp       bool
 | 
			
		||||
	HasOutboundAddr        bool
 | 
			
		||||
	HasIPv6                bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type slirp4netnsCmdArg struct {
 | 
			
		||||
| 
						 | 
				
			
			@ -197,6 +199,8 @@ func checkSlirpFlags(path string) (*slirpFeatures, error) {
 | 
			
		|||
		HasMTU:                 strings.Contains(string(out), "--mtu"),
 | 
			
		||||
		HasEnableSandbox:       strings.Contains(string(out), "--enable-sandbox"),
 | 
			
		||||
		HasEnableSeccomp:       strings.Contains(string(out), "--enable-seccomp"),
 | 
			
		||||
		HasOutboundAddr:        strings.Contains(string(out), "--outbound-addr"),
 | 
			
		||||
		HasIPv6:                strings.Contains(string(out), "--enable-ipv6"),
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -225,21 +229,64 @@ func (r *Runtime) setupRootlessNetNS(ctr *Container) error {
 | 
			
		|||
 | 
			
		||||
	isSlirpHostForward := false
 | 
			
		||||
	disableHostLoopback := true
 | 
			
		||||
	enableIPv6 := false
 | 
			
		||||
	outboundAddr := ""
 | 
			
		||||
	outboundAddr6 := ""
 | 
			
		||||
 | 
			
		||||
	if ctr.config.NetworkOptions != nil {
 | 
			
		||||
		slirpOptions := ctr.config.NetworkOptions["slirp4netns"]
 | 
			
		||||
		for _, o := range slirpOptions {
 | 
			
		||||
			switch o {
 | 
			
		||||
			case "port_handler=slirp4netns":
 | 
			
		||||
				isSlirpHostForward = true
 | 
			
		||||
			case "port_handler=rootlesskit":
 | 
			
		||||
				isSlirpHostForward = false
 | 
			
		||||
			case "allow_host_loopback=true":
 | 
			
		||||
				disableHostLoopback = false
 | 
			
		||||
			case "allow_host_loopback=false":
 | 
			
		||||
				disableHostLoopback = true
 | 
			
		||||
			parts := strings.Split(o, "=")
 | 
			
		||||
			option, value := parts[0], parts[1]
 | 
			
		||||
 | 
			
		||||
			switch option {
 | 
			
		||||
			case "port_handler":
 | 
			
		||||
				switch value {
 | 
			
		||||
				case "slirp4netns":
 | 
			
		||||
					isSlirpHostForward = true
 | 
			
		||||
				case "rootlesskit":
 | 
			
		||||
					isSlirpHostForward = false
 | 
			
		||||
				default:
 | 
			
		||||
					return errors.Errorf("unknown port_handler for slirp4netns: %q", value)
 | 
			
		||||
				}
 | 
			
		||||
			case "allow_host_loopback":
 | 
			
		||||
				switch value {
 | 
			
		||||
				case "true":
 | 
			
		||||
					disableHostLoopback = false
 | 
			
		||||
				case "false":
 | 
			
		||||
					disableHostLoopback = true
 | 
			
		||||
				default:
 | 
			
		||||
					return errors.Errorf("invalid value of allow_host_loopback for slirp4netns: %q", value)
 | 
			
		||||
				}
 | 
			
		||||
			case "enable_ipv6":
 | 
			
		||||
				switch value {
 | 
			
		||||
				case "true":
 | 
			
		||||
					enableIPv6 = true
 | 
			
		||||
				case "false":
 | 
			
		||||
					enableIPv6 = false
 | 
			
		||||
				default:
 | 
			
		||||
					return errors.Errorf("invalid value of enable_ipv6 for slirp4netns: %q", value)
 | 
			
		||||
				}
 | 
			
		||||
			case "outbound_addr":
 | 
			
		||||
				ipv4 := net.ParseIP(value)
 | 
			
		||||
				if ipv4 == nil || ipv4.To4() == nil {
 | 
			
		||||
					_, err := net.InterfaceByName(value)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return errors.Errorf("invalid outbound_addr %q", value)
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				outboundAddr = value
 | 
			
		||||
			case "outbound_addr6":
 | 
			
		||||
				ipv6 := net.ParseIP(value)
 | 
			
		||||
				if ipv6 == nil || ipv6.To4() != nil {
 | 
			
		||||
					_, err := net.InterfaceByName(value)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return errors.Errorf("invalid outbound_addr6: %q", value)
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				outboundAddr6 = value
 | 
			
		||||
			default:
 | 
			
		||||
				return errors.Errorf("unknown option for slirp4netns: %q", o)
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -262,6 +309,30 @@ func (r *Runtime) setupRootlessNetNS(ctr *Container) error {
 | 
			
		|||
		cmdArgs = append(cmdArgs, "--enable-seccomp")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if enableIPv6 {
 | 
			
		||||
		if !slirpFeatures.HasIPv6 {
 | 
			
		||||
			return errors.Errorf("enable_ipv6 not supported")
 | 
			
		||||
		}
 | 
			
		||||
		cmdArgs = append(cmdArgs, "--enable-ipv6")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if outboundAddr != "" {
 | 
			
		||||
		if !slirpFeatures.HasOutboundAddr {
 | 
			
		||||
			return errors.Errorf("outbound_addr not supported")
 | 
			
		||||
		}
 | 
			
		||||
		cmdArgs = append(cmdArgs, fmt.Sprintf("--outbound-addr=%s", outboundAddr))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if outboundAddr6 != "" {
 | 
			
		||||
		if !slirpFeatures.HasOutboundAddr || !slirpFeatures.HasIPv6 {
 | 
			
		||||
			return errors.Errorf("outbound_addr6 not supported")
 | 
			
		||||
		}
 | 
			
		||||
		if !enableIPv6 {
 | 
			
		||||
			return errors.Errorf("enable_ipv6=true is required for outbound_addr6")
 | 
			
		||||
		}
 | 
			
		||||
		cmdArgs = append(cmdArgs, fmt.Sprintf("--outbound-addr6=%s", outboundAddr6))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var apiSocket string
 | 
			
		||||
	if havePortMapping && isSlirpHostForward {
 | 
			
		||||
		apiSocket = filepath.Join(ctr.runtime.config.Engine.TmpDir, fmt.Sprintf("%s.net", ctr.config.ID))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,11 +1,14 @@
 | 
			
		|||
package integration
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	. "github.com/containers/podman/v2/test/utils"
 | 
			
		||||
	. "github.com/onsi/ginkgo"
 | 
			
		||||
	. "github.com/onsi/gomega"
 | 
			
		||||
	"github.com/uber/jaeger-client-go/utils"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var _ = Describe("Podman run networking", func() {
 | 
			
		||||
| 
						 | 
				
			
			@ -278,6 +281,53 @@ var _ = Describe("Podman run networking", func() {
 | 
			
		|||
		Expect(session.ExitCode()).To(Equal(0))
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	It("podman run network bind to 127.0.0.1", func() {
 | 
			
		||||
		slirp4netnsHelp := SystemExec("slirp4netns", []string{"--help"})
 | 
			
		||||
		Expect(slirp4netnsHelp.ExitCode()).To(Equal(0))
 | 
			
		||||
		networkConfiguration := "slirp4netns:outbound_addr=127.0.0.1,allow_host_loopback=true"
 | 
			
		||||
 | 
			
		||||
		if strings.Contains(slirp4netnsHelp.OutputToString(), "outbound-addr") {
 | 
			
		||||
			ncListener := StartSystemExec("nc", []string{"-v", "-n", "-l", "-p", "8083"})
 | 
			
		||||
			session := podmanTest.Podman([]string{"run", "--network", networkConfiguration, "-dt", ALPINE, "nc", "-w", "2", "10.0.2.2", "8083"})
 | 
			
		||||
			session.Wait(30)
 | 
			
		||||
			ncListener.Wait(30)
 | 
			
		||||
 | 
			
		||||
			Expect(session.ExitCode()).To(Equal(0))
 | 
			
		||||
			Expect(ncListener.ExitCode()).To(Equal(0))
 | 
			
		||||
			Expect(ncListener.ErrorToString()).To(ContainSubstring("127.0.0.1"))
 | 
			
		||||
		} else {
 | 
			
		||||
			session := podmanTest.Podman([]string{"run", "--network", networkConfiguration, "-dt", ALPINE, "nc", "-w", "2", "10.0.2.2", "8083"})
 | 
			
		||||
			session.Wait(30)
 | 
			
		||||
			Expect(session.ExitCode()).ToNot(Equal(0))
 | 
			
		||||
			Expect(session.ErrorToString()).To(ContainSubstring("outbound_addr not supported"))
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	It("podman run network bind to HostIP", func() {
 | 
			
		||||
		ip, err := utils.HostIP()
 | 
			
		||||
		Expect(err).To(BeNil())
 | 
			
		||||
 | 
			
		||||
		slirp4netnsHelp := SystemExec("slirp4netns", []string{"--help"})
 | 
			
		||||
		Expect(slirp4netnsHelp.ExitCode()).To(Equal(0))
 | 
			
		||||
		networkConfiguration := fmt.Sprintf("slirp4netns:outbound_addr=%s,allow_host_loopback=true", ip.String())
 | 
			
		||||
 | 
			
		||||
		if strings.Contains(slirp4netnsHelp.OutputToString(), "outbound-addr") {
 | 
			
		||||
			ncListener := StartSystemExec("nc", []string{"-v", "-n", "-l", "-p", "8084"})
 | 
			
		||||
			session := podmanTest.Podman([]string{"run", "--network", networkConfiguration, "-dt", ALPINE, "nc", "-w", "2", "10.0.2.2", "8084"})
 | 
			
		||||
			session.Wait(30)
 | 
			
		||||
			ncListener.Wait(30)
 | 
			
		||||
 | 
			
		||||
			Expect(session.ExitCode()).To(Equal(0))
 | 
			
		||||
			Expect(ncListener.ExitCode()).To(Equal(0))
 | 
			
		||||
			Expect(ncListener.ErrorToString()).To(ContainSubstring(ip.String()))
 | 
			
		||||
		} else {
 | 
			
		||||
			session := podmanTest.Podman([]string{"run", "--network", networkConfiguration, "-dt", ALPINE, "nc", "-w", "2", "10.0.2.2", "8084"})
 | 
			
		||||
			session.Wait(30)
 | 
			
		||||
			Expect(session.ExitCode()).ToNot(Equal(0))
 | 
			
		||||
			Expect(session.ErrorToString()).To(ContainSubstring("outbound_addr not supported"))
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	It("podman run network expose ports in image metadata", func() {
 | 
			
		||||
		session := podmanTest.Podman([]string{"create", "--name", "test", "-dt", "-P", nginx})
 | 
			
		||||
		session.Wait(90)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -341,6 +341,16 @@ func SystemExec(command string, args []string) *PodmanSession {
 | 
			
		|||
	return &PodmanSession{session}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StartSystemExec is used to start exec a system command
 | 
			
		||||
func StartSystemExec(command string, args []string) *PodmanSession {
 | 
			
		||||
	c := exec.Command(command, args...)
 | 
			
		||||
	session, err := gexec.Start(c, GinkgoWriter, GinkgoWriter)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		Fail(fmt.Sprintf("unable to run command: %s %s", command, strings.Join(args, " ")))
 | 
			
		||||
	}
 | 
			
		||||
	return &PodmanSession{session}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StringInSlice determines if a string is in a string slice, returns bool
 | 
			
		||||
func StringInSlice(s string, sl []string) bool {
 | 
			
		||||
	for _, i := range sl {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue