aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/common/util.go32
-rw-r--r--libpod/oci_util.go36
-rw-r--r--test/e2e/run_networking_test.go26
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"})