diff --git a/api/swagger.yaml b/api/swagger.yaml index 93c6f82598..4664b3fca6 100644 --- a/api/swagger.yaml +++ b/api/swagger.yaml @@ -182,6 +182,10 @@ definitions: type: "string" format: "ip-address" description: "Host IP address that the container's port is mapped to" + x-go-type: + type: Addr + import: + package: net/netip PrivatePort: type: "integer" format: "uint16" @@ -1081,6 +1085,11 @@ definitions: description: "A list of DNS servers for the container to use." items: type: "string" + format: "ip-address" + x-go-type: + type: Addr + import: + package: net/netip DnsOptions: type: "array" description: "A list of DNS options." @@ -1645,6 +1654,10 @@ definitions: description: "Host IP address that the container's port is mapped to." type: "string" example: "127.0.0.1" + x-go-type: + type: Addr + import: + package: net/netip HostPort: description: "Host port number that the container's port is mapped to." type: "string" diff --git a/api/types/container/hostconfig.go b/api/types/container/hostconfig.go index f167d80599..6df9d1d63c 100644 --- a/api/types/container/hostconfig.go +++ b/api/types/container/hostconfig.go @@ -3,6 +3,7 @@ package container import ( "errors" "fmt" + "net/netip" "strings" "github.com/docker/go-units" @@ -432,7 +433,7 @@ type HostConfig struct { CapAdd []string // List of kernel capabilities to add to the container CapDrop []string // List of kernel capabilities to remove from the container CgroupnsMode CgroupnsMode // Cgroup namespace mode to use for the container - DNS []string `json:"Dns"` // List of DNS server to lookup + DNS []netip.Addr `json:"Dns"` // List of DNS server to lookup DNSOptions []string `json:"DnsOptions"` // List of DNSOption to look for DNSSearch []string `json:"DnsSearch"` // List of DNSSearch to look for ExtraHosts []string // List of extra hosts diff --git a/api/types/container/network.go b/api/types/container/network.go index b22329033a..17e90ed746 100644 --- a/api/types/container/network.go +++ b/api/types/container/network.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "iter" + "net/netip" "strconv" "strings" "unique" @@ -148,7 +149,7 @@ type PortSet = map[Port]struct{} // PortBinding represents a binding between a Host IP address and a Host Port. type PortBinding struct { // HostIP is the host IP Address - HostIP string `json:"HostIp"` + HostIP netip.Addr `json:"HostIp"` // HostPort is the host port number HostPort string `json:"HostPort"` } diff --git a/api/types/container/port_summary.go b/api/types/container/port_summary.go index 3956224dcc..68148eece4 100644 --- a/api/types/container/port_summary.go +++ b/api/types/container/port_summary.go @@ -5,6 +5,10 @@ package container // This file was generated by the swagger tool. // Editing this file might prove futile when you re-run the swagger generate command +import ( + "net/netip" +) + // PortSummary Describes a port-mapping between the container and the host. // // Example: {"PrivatePort":8080,"PublicPort":80,"Type":"tcp"} @@ -13,7 +17,7 @@ package container type PortSummary struct { // Host IP address that the container's port is mapped to - IP string `json:"IP,omitempty"` + IP netip.Addr `json:"IP,omitempty"` // Port on the container // Required: true diff --git a/daemon/builder/dockerfile/dispatchers.go b/daemon/builder/dockerfile/dispatchers.go index c383aad764..c4f820c30f 100644 --- a/daemon/builder/dockerfile/dispatchers.go +++ b/daemon/builder/dockerfile/dispatchers.go @@ -25,6 +25,7 @@ import ( "github.com/moby/moby/api/types/jsonstream" "github.com/moby/moby/v2/daemon/builder" "github.com/moby/moby/v2/daemon/internal/image" + "github.com/moby/moby/v2/daemon/internal/netiputil" "github.com/moby/moby/v2/errdefs" "github.com/moby/sys/signal" ocispec "github.com/opencontainers/image-spec/specs-go/v1" @@ -591,8 +592,9 @@ func parsePortSpec(rawPort string) ([]container.PortMap, error) { } ip = rawIP } - if ip != "" && net.ParseIP(ip) == nil { - return nil, errors.New("invalid IP address: " + ip) + addr, err := netiputil.MaybeParseAddr(ip) + if err != nil { + return nil, fmt.Errorf("invalid IP address: %w", err) } pr, err := container.ParsePortRange(containerPort) @@ -637,7 +639,7 @@ func parsePortSpec(rawPort string) ([]container.PortMap, error) { } } ports = append(ports, container.PortMap{ - container.MustParsePort(fmt.Sprintf("%d/%s", startPort+i, proto)): []container.PortBinding{{HostIP: ip, HostPort: hPort}}, + container.MustParsePort(fmt.Sprintf("%d/%s", startPort+i, proto)): []container.PortBinding{{HostIP: addr, HostPort: hPort}}, }) } return ports, nil diff --git a/daemon/builder/dockerfile/dispatchers_test.go b/daemon/builder/dockerfile/dispatchers_test.go index 985f859395..10fe109024 100644 --- a/daemon/builder/dockerfile/dispatchers_test.go +++ b/daemon/builder/dockerfile/dispatchers_test.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "fmt" + "net/netip" "reflect" "runtime" "strings" @@ -662,7 +663,7 @@ func TestParsePortSpecs(t *testing.T) { t.Fatalf("%s should have exactly one binding", portSpec) } - if bindings[0].HostIP != "" { + if bindings[0].HostIP.IsValid() { t.Fatalf("HostIP should not be set for %s", portSpec) } @@ -695,7 +696,7 @@ func TestParsePortSpecs(t *testing.T) { t.Fatalf("%s should have exactly one binding", portSpec) } - if bindings[0].HostIP != "" { + if bindings[0].HostIP.IsValid() { t.Fatalf("HostIP should not be set for %s", portSpec) } @@ -728,7 +729,7 @@ func TestParsePortSpecs(t *testing.T) { t.Fatalf("%s should have exactly one binding", portSpec) } - if bindings[0].HostIP != "0.0.0.0" { + if bindings[0].HostIP != netip.IPv4Unspecified() { t.Fatalf("HostIP is not 0.0.0.0 for %s", portSpec) } @@ -787,7 +788,7 @@ func TestParsePortSpecFull(t *testing.T) { { container.MustParsePort("3333/tcp"): []container.PortBinding{ { - HostIP: "0.0.0.0", + HostIP: netip.IPv4Unspecified(), HostPort: "1234", }, }, @@ -795,7 +796,7 @@ func TestParsePortSpecFull(t *testing.T) { { container.MustParsePort("3334/tcp"): []container.PortBinding{ { - HostIP: "0.0.0.0", + HostIP: netip.IPv4Unspecified(), HostPort: "1235", }, }, @@ -822,7 +823,7 @@ func TestPartPortSpecIPV6(t *testing.T) { { container.MustParsePort("333/tcp"): []container.PortBinding{ { - HostIP: "2001:4860:0:2001::68", + HostIP: netip.MustParseAddr("2001:4860:0:2001::68"), HostPort: "", }, }, @@ -836,7 +837,7 @@ func TestPartPortSpecIPV6(t *testing.T) { { container.MustParsePort("80/tcp"): []container.PortBinding{ { - HostIP: "::1", + HostIP: netip.IPv6Loopback(), HostPort: "80", }, }, @@ -850,7 +851,7 @@ func TestPartPortSpecIPV6(t *testing.T) { { container.MustParsePort("333/tcp"): []container.PortBinding{ { - HostIP: "2001:4860:0:2001::68", + HostIP: netip.MustParseAddr("2001:4860:0:2001::68"), HostPort: "", }, }, @@ -864,7 +865,7 @@ func TestPartPortSpecIPV6(t *testing.T) { { container.MustParsePort("80/tcp"): []container.PortBinding{ { - HostIP: "::1", + HostIP: netip.IPv6Loopback(), HostPort: "80", }, }, @@ -878,7 +879,7 @@ func TestPartPortSpecIPV6(t *testing.T) { { container.MustParsePort("80/tcp"): []container.PortBinding{ { - HostIP: "::", + HostIP: netip.IPv6Unspecified(), HostPort: "", }, }, @@ -929,7 +930,7 @@ func TestParsePortSpecsWithRange(t *testing.T) { t.Fatalf("%s should have exactly one binding", portSpec) } - if bindings[0].HostIP != "" { + if bindings[0].HostIP.IsValid() { t.Fatalf("HostIP should not be set for %s", portSpec) } @@ -961,7 +962,7 @@ func TestParsePortSpecsWithRange(t *testing.T) { t.Fatalf("%s should have exactly one binding", portSpec) } - if bindings[0].HostIP != "" { + if bindings[0].HostIP.IsValid() { t.Fatalf("HostIP should not be set for %s", portSpec) } @@ -989,7 +990,7 @@ func TestParsePortSpecsWithRange(t *testing.T) { for portSpec, bindings := range bindingMap { _, port := splitProtoPort(portSpec.String()) - if len(bindings) != 1 || bindings[0].HostIP != "0.0.0.0" || bindings[0].HostPort != port { + if len(bindings) != 1 || bindings[0].HostIP != netip.IPv4Unspecified() || bindings[0].HostPort != port { t.Fatalf("Expect single binding to port %s but found %s", port, bindings) } } @@ -1031,7 +1032,7 @@ func TestParseNetworkOptsPrivateOnly(t *testing.T) { if s.HostPort != "" { t.Errorf("Expected \"\" got %s", s.HostPort) } - if s.HostIP != "192.168.1.100" { + if s.HostIP != netip.MustParseAddr("192.168.1.100") { t.Errorf("Expected 192.168.1.100 got %s", s.HostIP) } } @@ -1067,7 +1068,7 @@ func TestParseNetworkOptsPublic(t *testing.T) { if s.HostPort != "8080" { t.Errorf("Expected 8080 got %s", s.HostPort) } - if s.HostIP != "192.168.1.100" { + if s.HostIP != netip.MustParseAddr("192.168.1.100") { t.Errorf("Expected 192.168.1.100 got %s", s.HostIP) } } @@ -1133,7 +1134,7 @@ func TestParseNetworkOptsUdp(t *testing.T) { if s.HostPort != "" { t.Errorf("Expected \"\" got %s", s.HostPort) } - if s.HostIP != "192.168.1.100" { + if s.HostIP != netip.MustParseAddr("192.168.1.100") { t.Errorf("Expected 192.168.1.100 got %s", s.HostIP) } } @@ -1169,7 +1170,7 @@ func TestParseNetworkOptsSctp(t *testing.T) { if s.HostPort != "" { t.Errorf("Expected \"\" got %s", s.HostPort) } - if s.HostIP != "192.168.1.100" { + if s.HostIP != netip.MustParseAddr("192.168.1.100") { t.Errorf("Expected 192.168.1.100 got %s", s.HostIP) } } diff --git a/daemon/cluster/executor/container/container.go b/daemon/cluster/executor/container/container.go index 10e4d5d14a..8553a460f0 100644 --- a/daemon/cluster/executor/container/container.go +++ b/daemon/cluster/executor/container/container.go @@ -24,6 +24,7 @@ import ( clustertypes "github.com/moby/moby/v2/daemon/cluster/provider" "github.com/moby/moby/v2/daemon/internal/netiputil" "github.com/moby/moby/v2/daemon/libnetwork/scope" + "github.com/moby/moby/v2/internal/sliceutil" "github.com/moby/swarmkit/v2/agent/exec" "github.com/moby/swarmkit/v2/api" "github.com/moby/swarmkit/v2/api/genericresource" @@ -433,7 +434,7 @@ func (c *containerConfig) hostConfig(deps exec.VolumeGetter) *container.HostConf } if c.spec().DNSConfig != nil { - hc.DNS = c.spec().DNSConfig.Nameservers + hc.DNS = sliceutil.Map(c.spec().DNSConfig.Nameservers, func(ns string) netip.Addr { a, _ := netip.ParseAddr(ns); return a }) hc.DNSSearch = c.spec().DNSConfig.Search hc.DNSOptions = c.spec().DNSConfig.Options } diff --git a/daemon/container/container.go b/daemon/container/container.go index a5b3f6a6da..d564c5f6f2 100644 --- a/daemon/container/container.go +++ b/daemon/container/container.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "io" + "net/netip" "os" "path/filepath" "runtime" @@ -618,7 +619,7 @@ func (container *Container) InitDNSHostConfig() { container.Lock() defer container.Unlock() if container.HostConfig.DNS == nil { - container.HostConfig.DNS = make([]string, 0) + container.HostConfig.DNS = make([]netip.Addr, 0) } if container.HostConfig.DNSSearch == nil { diff --git a/daemon/container_operations.go b/daemon/container_operations.go index a544ea1f4c..bc007bcb37 100644 --- a/daemon/container_operations.go +++ b/daemon/container_operations.go @@ -37,18 +37,6 @@ import ( const errSetupNetworking = "failed to set up container networking" -func toNetIP(ips []string) ([]netip.Addr, error) { - var dnsAddrs []netip.Addr - for _, ns := range ips { - addr, err := netip.ParseAddr(ns) - if err != nil { - return nil, fmt.Errorf("bad nameserver address %s: %w", ns, err) - } - dnsAddrs = append(dnsAddrs, addr) - } - return dnsAddrs, nil -} - func buildSandboxOptions(cfg *config.Config, ctr *container.Container) ([]libnetwork.SandboxOption, error) { var sboxOptions []libnetwork.SandboxOption sboxOptions = append(sboxOptions, libnetwork.OptionHostname(ctr.Config.Hostname), libnetwork.OptionDomainname(ctr.Config.Domainname)) @@ -70,11 +58,7 @@ func buildSandboxOptions(cfg *config.Config, ctr *container.Container) ([]libnet sboxOptions = append(sboxOptions, platformOpts...) if len(ctr.HostConfig.DNS) > 0 { - dnsAddrs, err := toNetIP(ctr.HostConfig.DNS) - if err != nil { - return nil, err - } - sboxOptions = append(sboxOptions, libnetwork.OptionDNS(dnsAddrs)) + sboxOptions = append(sboxOptions, libnetwork.OptionDNS(ctr.HostConfig.DNS)) } else if len(cfg.DNS) > 0 { sboxOptions = append(sboxOptions, libnetwork.OptionDNS(cfg.DNS)) } @@ -150,7 +134,7 @@ func buildSandboxOptions(cfg *config.Config, ctr *container.Container) ([]libnet publishedPorts = append(publishedPorts, types.PortBinding{ Proto: protocol, Port: port.Num(), - HostIP: net.ParseIP(binding.HostIP), + HostIP: binding.HostIP.AsSlice(), HostPort: portRange.Start(), HostPortEnd: portRange.End(), }) diff --git a/daemon/network.go b/daemon/network.go index 8bef13a5d5..5ffca1e8cc 100644 --- a/daemon/network.go +++ b/daemon/network.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "maps" "net" "net/netip" "sort" @@ -35,6 +36,7 @@ import ( "github.com/moby/moby/v2/daemon/server/backend" "github.com/moby/moby/v2/errdefs" "github.com/moby/moby/v2/internal/iterutil" + "github.com/moby/moby/v2/internal/sliceutil" "github.com/moby/moby/v2/pkg/plugingetter" "go.opentelemetry.io/otel/baggage" ) @@ -975,14 +977,14 @@ func buildCreateEndpointOptions(c *container.Container, n *libnetwork.Network, e // we're dealing with DNS config both here and in buildSandboxOptions. Following DNS options are only honored by // Windows netdrivers, whereas DNS options in buildSandboxOptions are only honored by Linux netdrivers. if !n.Internal() { + var nameservers []netip.Addr if len(c.HostConfig.DNS) > 0 { - createOptions = append(createOptions, libnetwork.CreateOptionDNS(c.HostConfig.DNS)) + nameservers = c.HostConfig.DNS } else if len(daemonDNS) > 0 { - dns := make([]string, len(daemonDNS)) - for i, a := range daemonDNS { - dns[i] = a.String() - } - createOptions = append(createOptions, libnetwork.CreateOptionDNS(dns)) + nameservers = daemonDNS + } + if len(nameservers) > 0 { + createOptions = append(createOptions, libnetwork.CreateOptionDNS(sliceutil.Map(nameservers, (netip.Addr).String))) } } @@ -1040,7 +1042,7 @@ func buildPortsRelatedCreateEndpointOptions(c *container.Container, n *libnetwor publishedPorts = append(publishedPorts, lntypes.PortBinding{ Proto: protocol, Port: p.Num(), - HostIP: net.ParseIP(binding.HostIP), + HostIP: binding.HostIP.AsSlice(), HostPort: portRange.Start(), HostPortEnd: portRange.End(), }) @@ -1113,7 +1115,8 @@ func getEndpointPortMapInfo(pm containertypes.PortMap, ep *libnetwork.Endpoint) if pp.HostPort > 0 { hp = strconv.Itoa(int(pp.HostPort)) } - natBndg := containertypes.PortBinding{HostIP: pp.HostIP.String(), HostPort: hp} + natBndg := containertypes.PortBinding{HostPort: hp} + natBndg.HostIP, _ = netip.AddrFromSlice(pp.HostIP) pm[natPort] = append(pm[natPort], natBndg) } } diff --git a/integration-cli/docker_api_containers_test.go b/integration-cli/docker_api_containers_test.go index 6cddb65e27..242818ce85 100644 --- a/integration-cli/docker_api_containers_test.go +++ b/integration-cli/docker_api_containers_test.go @@ -507,7 +507,6 @@ func (s *DockerAPISuite) TestContainerAPIBadPort(c *testing.T) { PortBindings: container.PortMap{ container.MustParsePort("8080/tcp"): []container.PortBinding{ { - HostIP: "", HostPort: "aa80", }, }, diff --git a/integration/internal/container/ops.go b/integration/internal/container/ops.go index e584829aeb..3a49791765 100644 --- a/integration/internal/container/ops.go +++ b/integration/internal/container/ops.go @@ -58,9 +58,9 @@ func WithNetworkMode(mode string) func(*TestContainerConfig) { } // WithDNS sets external DNS servers for the container -func WithDNS(dns []string) func(*TestContainerConfig) { +func WithDNS(dns []netip.Addr) func(*TestContainerConfig) { return func(c *TestContainerConfig) { - c.HostConfig.DNS = append([]string(nil), dns...) + c.HostConfig.DNS = append([]netip.Addr(nil), dns...) } } diff --git a/integration/network/bridge/bridge_linux_test.go b/integration/network/bridge/bridge_linux_test.go index 90ba9d3024..48a571c0b3 100644 --- a/integration/network/bridge/bridge_linux_test.go +++ b/integration/network/bridge/bridge_linux_test.go @@ -10,6 +10,7 @@ import ( "testing" "time" + "github.com/google/go-cmp/cmp/cmpopts" containertypes "github.com/moby/moby/api/types/container" networktypes "github.com/moby/moby/api/types/network" "github.com/moby/moby/api/types/versions" @@ -570,11 +571,11 @@ func TestAllPortMappingsAreReturned(t *testing.T) { inspect := ctr.Inspect(ctx, t, apiClient, ctrID) assert.DeepEqual(t, inspect.NetworkSettings.Ports, containertypes.PortMap{ containertypes.MustParsePort("80/tcp"): []containertypes.PortBinding{ - {HostIP: "0.0.0.0", HostPort: "8000"}, - {HostIP: "::", HostPort: "8000"}, + {HostIP: netip.IPv4Unspecified(), HostPort: "8000"}, + {HostIP: netip.IPv6Unspecified(), HostPort: "8000"}, }, containertypes.MustParsePort("81/tcp"): nil, - }) + }, cmpopts.EquateComparable(netip.Addr{})) } // TestFirewalldReloadNoZombies checks that when firewalld is reloaded, rules @@ -983,8 +984,8 @@ func TestEmptyPortBindingsBC(t *testing.T) { expWarnings := make([]string, 0) mappings, warnings := createInspect(t, "1.51", []containertypes.PortBinding{}) - assert.DeepEqual(t, expMappings, mappings) - assert.DeepEqual(t, expWarnings, warnings) + assert.DeepEqual(t, expMappings, mappings, cmpopts.EquateComparable(netip.Addr{})) + assert.DeepEqual(t, expWarnings, warnings, cmpopts.EquateComparable(netip.Addr{})) }) t.Run("backfilling on API 1.52, with a warning", func(t *testing.T) { @@ -996,8 +997,8 @@ func TestEmptyPortBindingsBC(t *testing.T) { } mappings, warnings := createInspect(t, "1.52", []containertypes.PortBinding{}) - assert.DeepEqual(t, expMappings, mappings) - assert.DeepEqual(t, expWarnings, warnings) + assert.DeepEqual(t, expMappings, mappings, cmpopts.EquateComparable(netip.Addr{})) + assert.DeepEqual(t, expWarnings, warnings, cmpopts.EquateComparable(netip.Addr{})) }) t.Run("no backfilling on API 1.53", func(t *testing.T) { @@ -1005,8 +1006,8 @@ func TestEmptyPortBindingsBC(t *testing.T) { expWarnings := make([]string, 0) mappings, warnings := createInspect(t, "1.53", []containertypes.PortBinding{}) - assert.DeepEqual(t, expMappings, mappings) - assert.DeepEqual(t, expWarnings, warnings) + assert.DeepEqual(t, expMappings, mappings, cmpopts.EquateComparable(netip.Addr{})) + assert.DeepEqual(t, expWarnings, warnings, cmpopts.EquateComparable(netip.Addr{})) }) for _, apiVersion := range []string{"1.51", "1.52", "1.53"} { @@ -1017,8 +1018,8 @@ func TestEmptyPortBindingsBC(t *testing.T) { expWarnings := make([]string, 0) mappings, warnings := createInspect(t, apiVersion, []containertypes.PortBinding{{HostPort: "8080"}}) - assert.DeepEqual(t, expMappings, mappings) - assert.DeepEqual(t, expWarnings, warnings) + assert.DeepEqual(t, expMappings, mappings, cmpopts.EquateComparable(netip.Addr{})) + assert.DeepEqual(t, expWarnings, warnings, cmpopts.EquateComparable(netip.Addr{})) }) } } @@ -1061,7 +1062,7 @@ func TestPortBindingBackfillingForOlderContainers(t *testing.T) { expMappings := containertypes.PortMap{containertypes.MustParsePort("80/tcp"): { {}, // An empty PortBinding is backfilled }} - assert.DeepEqual(t, expMappings, inspect.HostConfig.PortBindings) + assert.DeepEqual(t, expMappings, inspect.HostConfig.PortBindings, cmpopts.EquateComparable(netip.Addr{})) } func TestBridgeIPAMStatus(t *testing.T) { diff --git a/integration/network/bridge/iptablesdoc/iptablesdoc_linux_test.go b/integration/network/bridge/iptablesdoc/iptablesdoc_linux_test.go index 3aeff2645d..304c0434c2 100644 --- a/integration/network/bridge/iptablesdoc/iptablesdoc_linux_test.go +++ b/integration/network/bridge/iptablesdoc/iptablesdoc_linux_test.go @@ -179,7 +179,7 @@ var index = []section{ containers: []ctrDesc{ { name: "c1", - portMappings: containertypes.PortMap{containertypes.MustParsePort("80/tcp"): {{HostIP: "127.0.0.1", HostPort: "8080"}}}, + portMappings: containertypes.PortMap{containertypes.MustParsePort("80/tcp"): {{HostIP: netip.MustParseAddr("127.0.0.1"), HostPort: "8080"}}}, }, }, }}, diff --git a/integration/network/bridge/nftablesdoc/nftablesdoc_linux_test.go b/integration/network/bridge/nftablesdoc/nftablesdoc_linux_test.go index fc249aa8d3..7be4e353fc 100644 --- a/integration/network/bridge/nftablesdoc/nftablesdoc_linux_test.go +++ b/integration/network/bridge/nftablesdoc/nftablesdoc_linux_test.go @@ -178,7 +178,7 @@ var index = []section{ containers: []ctrDesc{ { name: "c1", - portMappings: containertypes.PortMap{containertypes.MustParsePort("80/tcp"): {{HostIP: "127.0.0.1", HostPort: "8080"}}}, + portMappings: containertypes.PortMap{containertypes.MustParsePort("80/tcp"): {{HostIP: netip.MustParseAddr("127.0.0.1"), HostPort: "8080"}}}, }, }, }}, diff --git a/integration/network/dns_test.go b/integration/network/dns_test.go index 33f3deb208..9c2aecc985 100644 --- a/integration/network/dns_test.go +++ b/integration/network/dns_test.go @@ -1,11 +1,13 @@ package network import ( + "net/netip" "testing" "github.com/moby/moby/client" "github.com/moby/moby/v2/integration/internal/container" "github.com/moby/moby/v2/integration/internal/network" + "github.com/moby/moby/v2/internal/sliceutil" "github.com/moby/moby/v2/internal/testutil" "github.com/moby/moby/v2/internal/testutil/daemon" "gotest.tools/v3/assert" @@ -80,7 +82,7 @@ func TestIntDNSAsExtDNS(t *testing.T) { res := container.RunAttach(ctx, t, c, container.WithNetworkMode(netName), - container.WithDNS(tc.extServers), + container.WithDNS(sliceutil.Map(tc.extServers, netip.MustParseAddr)), container.WithCmd("nslookup", "docker.com"), ) defer c.ContainerRemove(ctx, res.ContainerID, client.ContainerRemoveOptions{Force: true}) diff --git a/integration/network/overlay/overlay_test.go b/integration/network/overlay/overlay_test.go index f363ad1f28..823dfc898d 100644 --- a/integration/network/overlay/overlay_test.go +++ b/integration/network/overlay/overlay_test.go @@ -95,7 +95,7 @@ func TestHostPortMappings(t *testing.T) { var addrs []string for _, port := range ctrs[0].Ports { - addrs = append(addrs, fmt.Sprintf("%s:%d/%s", net.JoinHostPort(port.IP, strconv.Itoa(int(port.PublicPort))), port.PrivatePort, port.Type)) + addrs = append(addrs, fmt.Sprintf("%s:%d/%s", net.JoinHostPort(port.IP.String(), strconv.Itoa(int(port.PublicPort))), port.PrivatePort, port.Type)) } assert.Check(t, len(addrs) >= 1 && len(addrs) <= 2) diff --git a/integration/networking/nat_windows_test.go b/integration/networking/nat_windows_test.go index 2668132a50..0d0a3865b1 100644 --- a/integration/networking/nat_windows_test.go +++ b/integration/networking/nat_windows_test.go @@ -3,6 +3,7 @@ package networking import ( "context" "net" + "net/netip" "testing" "time" @@ -97,7 +98,7 @@ func TestFlakyPortMappedHairpinWindows(t *testing.T) { serverId := container.Run(ctx, t, c, container.WithNetworkMode(serverNetName), container.WithExposedPorts("80"), - container.WithPortMap(containertypes.PortMap{containertypes.MustParsePort("80"): {{HostIP: "0.0.0.0"}}}), + container.WithPortMap(containertypes.PortMap{containertypes.MustParsePort("80"): {{HostIP: netip.IPv4Unspecified()}}}), container.WithCmd("httpd", "-f"), ) defer c.ContainerRemove(ctx, serverId, client.ContainerRemoveOptions{Force: true}) diff --git a/integration/networking/port_mapping_linux_test.go b/integration/networking/port_mapping_linux_test.go index 25c34729f1..b9f2312791 100644 --- a/integration/networking/port_mapping_linux_test.go +++ b/integration/networking/port_mapping_linux_test.go @@ -15,6 +15,7 @@ import ( "testing" "time" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/moby/moby/api/pkg/stdcopy" containertypes "github.com/moby/moby/api/types/container" networktypes "github.com/moby/moby/api/types/network" @@ -74,8 +75,8 @@ func TestDisableNAT(t *testing.T) { name: "defaults", expPortMap: containertypes.PortMap{ containertypes.MustParsePort("80/tcp"): []containertypes.PortBinding{ - {HostIP: "0.0.0.0", HostPort: "8080"}, - {HostIP: "::", HostPort: "8080"}, + {HostIP: netip.MustParseAddr("0.0.0.0"), HostPort: "8080"}, + {HostIP: netip.MustParseAddr("::"), HostPort: "8080"}, }, }, }, @@ -85,8 +86,8 @@ func TestDisableNAT(t *testing.T) { gwMode6: "routed", expPortMap: containertypes.PortMap{ containertypes.MustParsePort("80/tcp"): []containertypes.PortBinding{ - {HostIP: "0.0.0.0", HostPort: "8080"}, - {HostIP: "::", HostPort: ""}, + {HostIP: netip.MustParseAddr("0.0.0.0"), HostPort: "8080"}, + {HostIP: netip.MustParseAddr("::"), HostPort: ""}, }, }, }, @@ -96,8 +97,8 @@ func TestDisableNAT(t *testing.T) { gwMode6: "nat", expPortMap: containertypes.PortMap{ containertypes.MustParsePort("80/tcp"): []containertypes.PortBinding{ - {HostIP: "::", HostPort: "8080"}, - {HostIP: "0.0.0.0", HostPort: ""}, + {HostIP: netip.MustParseAddr("::"), HostPort: "8080"}, + {HostIP: netip.MustParseAddr("0.0.0.0"), HostPort: ""}, }, }, }, @@ -129,7 +130,7 @@ func TestDisableNAT(t *testing.T) { defer c.ContainerRemove(ctx, id, client.ContainerRemoveOptions{Force: true}) inspect := container.Inspect(ctx, t, c, id) - assert.Check(t, is.DeepEqual(inspect.NetworkSettings.Ports, tc.expPortMap)) + assert.Check(t, is.DeepEqual(inspect.NetworkSettings.Ports, tc.expPortMap, cmpopts.EquateComparable(netip.Addr{}))) }) } } @@ -162,7 +163,7 @@ func TestPortMappedHairpinTCP(t *testing.T) { serverId := container.Run(ctx, t, c, container.WithNetworkMode(serverNetName), container.WithExposedPorts("80"), - container.WithPortMap(containertypes.PortMap{containertypes.MustParsePort("80"): {{HostIP: "0.0.0.0"}}}), + container.WithPortMap(containertypes.PortMap{containertypes.MustParsePort("80"): {{HostIP: netip.MustParseAddr("0.0.0.0")}}}), container.WithCmd("httpd", "-f"), ) defer c.ContainerRemove(ctx, serverId, client.ContainerRemoveOptions{Force: true}) @@ -209,7 +210,7 @@ func TestPortMappedHairpinUDP(t *testing.T) { serverId := container.Run(ctx, t, c, container.WithNetworkMode(serverNetName), container.WithExposedPorts("54/udp"), - container.WithPortMap(containertypes.PortMap{containertypes.MustParsePort("54/udp"): {{HostIP: "0.0.0.0"}}}), + container.WithPortMap(containertypes.PortMap{containertypes.MustParsePort("54/udp"): {{HostIP: netip.MustParseAddr("0.0.0.0")}}}), container.WithCmd("/bin/sh", "-c", "echo 'foobar.internal 192.168.155.23' | dnsd -c - -p 54"), ) defer c.ContainerRemove(ctx, serverId, client.ContainerRemoveOptions{Force: true}) @@ -251,7 +252,7 @@ func TestProxy4To6(t *testing.T) { serverId := container.Run(ctx, t, c, container.WithNetworkMode(netName), container.WithExposedPorts("80"), - container.WithPortMap(containertypes.PortMap{containertypes.MustParsePort("80"): {{HostIP: "::1"}}}), + container.WithPortMap(containertypes.PortMap{containertypes.MustParsePort("80"): {{HostIP: netip.MustParseAddr("::1")}}}), container.WithCmd("httpd", "-f"), ) defer c.ContainerRemove(ctx, serverId, client.ContainerRemoveOptions{Force: true}) @@ -553,7 +554,7 @@ func TestAccessPublishedPortFromCtr(t *testing.T) { serverId := container.Run(ctx, t, c, container.WithNetworkMode(netName), container.WithExposedPorts("80"), - container.WithPortMap(containertypes.PortMap{containertypes.MustParsePort("80/tcp"): {{HostIP: "0.0.0.0"}}}), + container.WithPortMap(containertypes.PortMap{containertypes.MustParsePort("80/tcp"): {{HostIP: netip.MustParseAddr("0.0.0.0")}}}), container.WithCmd("httpd", "-f"), ) defer c.ContainerRemove(ctx, serverId, client.ContainerRemoveOptions{Force: true}) @@ -1426,7 +1427,7 @@ func TestAccessPortPublishedOnLoopbackAddress(t *testing.T) { container.WithExposedPorts("5000/udp"), // This port is mapped on 127.0.0.2, so it should not be remotely accessible. container.WithPortMap(containertypes.PortMap{ - containertypes.MustParsePort("5000/udp"): {{HostIP: loIP, HostPort: hostPort}}, + containertypes.MustParsePort("5000/udp"): {{HostIP: netip.MustParseAddr(loIP), HostPort: hostPort}}, }), container.WithNetworkMode(bridgeName)) defer c.ContainerRemove(ctx, serverID, client.ContainerRemoveOptions{Force: true}) @@ -1539,7 +1540,7 @@ func TestSkipRawRules(t *testing.T) { ctrId := container.Run(ctx, t, c, container.WithExposedPorts("80/tcp"), container.WithPortMap(containertypes.PortMap{containertypes.MustParsePort("80/tcp"): { - {HostIP: "127.0.0.1", HostPort: "8080"}, + {HostIP: netip.MustParseAddr("127.0.0.1"), HostPort: "8080"}, {HostPort: "8081"}, }}), ) @@ -1573,7 +1574,7 @@ func TestMixAnyWithSpecificHostAddrs(t *testing.T) { container.WithPortMap(containertypes.PortMap{ containertypes.MustParsePort("81/" + proto): {{}}, containertypes.MustParsePort("82/" + proto): {{}}, - containertypes.MustParsePort("80/" + proto): {{HostIP: "127.0.0.1"}}, + containertypes.MustParsePort("80/" + proto): {{HostIP: netip.MustParseAddr("127.0.0.1")}}, }), ) defer c.ContainerRemove(ctx, ctrId, client.ContainerRemoveOptions{Force: true}) diff --git a/integration/networking/resolvconf_test.go b/integration/networking/resolvconf_test.go index 0b468d2237..c7181faf18 100644 --- a/integration/networking/resolvconf_test.go +++ b/integration/networking/resolvconf_test.go @@ -2,6 +2,7 @@ package networking import ( "context" + "net/netip" "os" "path" "strings" @@ -180,7 +181,7 @@ func TestInternalNetworkLocalDNS(t *testing.T) { // Query the internal network's DNS server (via the daemon's internal DNS server). res := container.RunAttach(ctx, t, c, container.WithNetworkMode(intNetName), - container.WithDNS([]string{serverIP.String()}), + container.WithDNS([]netip.Addr{serverIP}), container.WithCmd("nslookup", "-type=A", "foo.example"), ) defer c.ContainerRemove(ctx, res.ContainerID, client.ContainerRemoveOptions{Force: true}) diff --git a/vendor/github.com/moby/moby/api/types/container/hostconfig.go b/vendor/github.com/moby/moby/api/types/container/hostconfig.go index f167d80599..6df9d1d63c 100644 --- a/vendor/github.com/moby/moby/api/types/container/hostconfig.go +++ b/vendor/github.com/moby/moby/api/types/container/hostconfig.go @@ -3,6 +3,7 @@ package container import ( "errors" "fmt" + "net/netip" "strings" "github.com/docker/go-units" @@ -432,7 +433,7 @@ type HostConfig struct { CapAdd []string // List of kernel capabilities to add to the container CapDrop []string // List of kernel capabilities to remove from the container CgroupnsMode CgroupnsMode // Cgroup namespace mode to use for the container - DNS []string `json:"Dns"` // List of DNS server to lookup + DNS []netip.Addr `json:"Dns"` // List of DNS server to lookup DNSOptions []string `json:"DnsOptions"` // List of DNSOption to look for DNSSearch []string `json:"DnsSearch"` // List of DNSSearch to look for ExtraHosts []string // List of extra hosts diff --git a/vendor/github.com/moby/moby/api/types/container/network.go b/vendor/github.com/moby/moby/api/types/container/network.go index b22329033a..17e90ed746 100644 --- a/vendor/github.com/moby/moby/api/types/container/network.go +++ b/vendor/github.com/moby/moby/api/types/container/network.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "iter" + "net/netip" "strconv" "strings" "unique" @@ -148,7 +149,7 @@ type PortSet = map[Port]struct{} // PortBinding represents a binding between a Host IP address and a Host Port. type PortBinding struct { // HostIP is the host IP Address - HostIP string `json:"HostIp"` + HostIP netip.Addr `json:"HostIp"` // HostPort is the host port number HostPort string `json:"HostPort"` } diff --git a/vendor/github.com/moby/moby/api/types/container/port_summary.go b/vendor/github.com/moby/moby/api/types/container/port_summary.go index 3956224dcc..68148eece4 100644 --- a/vendor/github.com/moby/moby/api/types/container/port_summary.go +++ b/vendor/github.com/moby/moby/api/types/container/port_summary.go @@ -5,6 +5,10 @@ package container // This file was generated by the swagger tool. // Editing this file might prove futile when you re-run the swagger generate command +import ( + "net/netip" +) + // PortSummary Describes a port-mapping between the container and the host. // // Example: {"PrivatePort":8080,"PublicPort":80,"Type":"tcp"} @@ -13,7 +17,7 @@ package container type PortSummary struct { // Host IP address that the container's port is mapped to - IP string `json:"IP,omitempty"` + IP netip.Addr `json:"IP,omitempty"` // Port on the container // Required: true