summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/source/markdown/podman-create.1.md11
-rw-r--r--libpod/networking_linux.go91
-rw-r--r--test/e2e/run_networking_test.go50
-rw-r--r--test/utils/utils.go10
4 files changed, 149 insertions, 13 deletions
diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md
index b4456225e..d57af0a06 100644
--- a/docs/source/markdown/podman-create.1.md
+++ b/docs/source/markdown/podman-create.1.md
@@ -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*
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index 844748970..ed8f82c46 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -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))
diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go
index 87b74052a..d37b3510e 100644
--- a/test/e2e/run_networking_test.go
+++ b/test/e2e/run_networking_test.go
@@ -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)
diff --git a/test/utils/utils.go b/test/utils/utils.go
index 2c454f532..8ee702423 100644
--- a/test/utils/utils.go
+++ b/test/utils/utils.go
@@ -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 {