diff options
-rw-r--r-- | cmd/podman/common/util.go | 32 | ||||
-rw-r--r-- | libpod/oci_util.go | 36 | ||||
-rw-r--r-- | test/e2e/run_networking_test.go | 26 |
3 files changed, 89 insertions, 5 deletions
diff --git a/cmd/podman/common/util.go b/cmd/podman/common/util.go index a3626b4e4..0d9f3ba26 100644 --- a/cmd/podman/common/util.go +++ b/cmd/podman/common/util.go @@ -71,14 +71,44 @@ func createPortBindings(ports []string) ([]specgen.PortMapping, error) { return nil, errors.Errorf("invalid port format - protocol can only be specified once") } - splitPort := strings.Split(splitProto[0], ":") + remainder := splitProto[0] + haveV6 := false + + // Check for an IPv6 address in brackets + splitV6 := strings.Split(remainder, "]") + switch len(splitV6) { + case 1: + // Do nothing, proceed as before + case 2: + // We potentially have an IPv6 address + haveV6 = true + if !strings.HasPrefix(splitV6[0], "[") { + return nil, errors.Errorf("invalid port format - IPv6 addresses must be enclosed by []") + } + if !strings.HasPrefix(splitV6[1], ":") { + return nil, errors.Errorf("invalid port format - IPv6 address must be followed by a colon (':')") + } + ipNoPrefix := strings.TrimPrefix(splitV6[0], "[") + hostIP = &ipNoPrefix + remainder = strings.TrimPrefix(splitV6[1], ":") + default: + return nil, errors.Errorf("invalid port format - at most one IPv6 address can be specified in a --publish") + } + + splitPort := strings.Split(remainder, ":") switch len(splitPort) { case 1: + if haveV6 { + return nil, errors.Errorf("invalid port format - must provide host and destination port if specifying an IP") + } ctrPort = splitPort[0] case 2: hostPort = &(splitPort[0]) ctrPort = splitPort[1] case 3: + if haveV6 { + return nil, errors.Errorf("invalid port format - when v6 address specified, must be [ipv6]:hostPort:ctrPort") + } hostIP = &(splitPort[0]) hostPort = &(splitPort[1]) ctrPort = splitPort[2] diff --git a/libpod/oci_util.go b/libpod/oci_util.go index 53567d2d0..8b40dad81 100644 --- a/libpod/oci_util.go +++ b/libpod/oci_util.go @@ -36,14 +36,30 @@ func bindPorts(ports []ocicni.PortMapping) ([]*os.File, error) { var files []*os.File notifySCTP := false for _, i := range ports { + isV6 := net.ParseIP(i.HostIP).To4() == nil + if i.HostIP == "" { + isV6 = false + } switch i.Protocol { case "udp": - addr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", i.HostIP, i.HostPort)) + var ( + addr *net.UDPAddr + err error + ) + if isV6 { + addr, err = net.ResolveUDPAddr("udp6", fmt.Sprintf("[%s]:%d", i.HostIP, i.HostPort)) + } else { + addr, err = net.ResolveUDPAddr("udp4", fmt.Sprintf("%s:%d", i.HostIP, i.HostPort)) + } if err != nil { return nil, errors.Wrapf(err, "cannot resolve the UDP address") } - server, err := net.ListenUDP("udp", addr) + proto := "udp4" + if isV6 { + proto = "udp6" + } + server, err := net.ListenUDP(proto, addr) if err != nil { return nil, errors.Wrapf(err, "cannot listen on the UDP port") } @@ -54,12 +70,24 @@ func bindPorts(ports []ocicni.PortMapping) ([]*os.File, error) { files = append(files, f) case "tcp": - addr, err := net.ResolveTCPAddr("tcp4", fmt.Sprintf("%s:%d", i.HostIP, i.HostPort)) + var ( + addr *net.TCPAddr + err error + ) + if isV6 { + addr, err = net.ResolveTCPAddr("tcp6", fmt.Sprintf("[%s]:%d", i.HostIP, i.HostPort)) + } else { + addr, err = net.ResolveTCPAddr("tcp4", fmt.Sprintf("%s:%d", i.HostIP, i.HostPort)) + } if err != nil { return nil, errors.Wrapf(err, "cannot resolve the TCP address") } - server, err := net.ListenTCP("tcp4", addr) + proto := "tcp4" + if isV6 { + proto = "tcp6" + } + server, err := net.ListenTCP(proto, addr) if err != nil { return nil, errors.Wrapf(err, "cannot listen on the TCP port") } diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go index 9db2f5d49..4fad85f00 100644 --- a/test/e2e/run_networking_test.go +++ b/test/e2e/run_networking_test.go @@ -129,6 +129,32 @@ var _ = Describe("Podman run networking", func() { Expect(inspectOut[0].NetworkSettings.Ports[0].HostIP).To(Equal("127.0.0.1")) }) + It("podman run -p [::1]:8080:80/udp", func() { + name := "testctr" + session := podmanTest.Podman([]string{"create", "-t", "-p", "[::1]:8080:80/udp", "--name", name, ALPINE, "/bin/sh"}) + session.WaitWithDefaultTimeout() + inspectOut := podmanTest.InspectContainer(name) + Expect(len(inspectOut)).To(Equal(1)) + Expect(len(inspectOut[0].NetworkSettings.Ports)).To(Equal(1)) + Expect(inspectOut[0].NetworkSettings.Ports[0].HostPort).To(Equal(int32(8080))) + Expect(inspectOut[0].NetworkSettings.Ports[0].ContainerPort).To(Equal(int32(80))) + Expect(inspectOut[0].NetworkSettings.Ports[0].Protocol).To(Equal("udp")) + Expect(inspectOut[0].NetworkSettings.Ports[0].HostIP).To(Equal("::1")) + }) + + It("podman run -p [::1]:8080:80/tcp", func() { + name := "testctr" + session := podmanTest.Podman([]string{"create", "-t", "-p", "[::1]:8080:80/tcp", "--name", name, ALPINE, "/bin/sh"}) + session.WaitWithDefaultTimeout() + inspectOut := podmanTest.InspectContainer(name) + Expect(len(inspectOut)).To(Equal(1)) + Expect(len(inspectOut[0].NetworkSettings.Ports)).To(Equal(1)) + Expect(inspectOut[0].NetworkSettings.Ports[0].HostPort).To(Equal(int32(8080))) + Expect(inspectOut[0].NetworkSettings.Ports[0].ContainerPort).To(Equal(int32(80))) + Expect(inspectOut[0].NetworkSettings.Ports[0].Protocol).To(Equal("tcp")) + Expect(inspectOut[0].NetworkSettings.Ports[0].HostIP).To(Equal("::1")) + }) + It("podman run --expose 80 -P", func() { name := "testctr" session := podmanTest.Podman([]string{"create", "-t", "--expose", "80", "-P", "--name", name, ALPINE, "/bin/sh"}) |