From 5365f08ae2f3b2a311f95aa82caebcd8116a7a01 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Fri, 1 Aug 2025 18:27:42 +0200 Subject: [PATCH] daemon/config: make DNSConfig.DNS a netip.Addr Modernize the field and allow using it as-is in some places, or convert it to a string (which won't produce an error down the line). Signed-off-by: Sebastiaan van Stijn --- daemon/command/config.go | 2 +- daemon/config/config.go | 2 +- daemon/config/config_test.go | 6 +++--- daemon/container_operations.go | 25 ++++++++++++++++-------- daemon/internal/builder-next/executor.go | 4 ++-- daemon/libnetwork/sandbox.go | 3 ++- daemon/libnetwork/sandbox_dns_unix.go | 10 +--------- daemon/libnetwork/sandbox_options.go | 4 +++- daemon/network.go | 9 +++++++-- 9 files changed, 37 insertions(+), 28 deletions(-) diff --git a/daemon/command/config.go b/daemon/command/config.go index d32f965b7d..ee1be2d041 100644 --- a/daemon/command/config.go +++ b/daemon/command/config.go @@ -45,7 +45,7 @@ func installCommonConfigFlags(conf *config.Config, flags *pflag.FlagSet) { _ = flags.MarkHidden("network-diagnostic-port") flags.BoolVar(&conf.RawLogs, "raw-logs", false, "Full timestamps without ANSI coloring") - flags.IPSliceVar(&conf.DNS, "dns", conf.DNS, "DNS server to use") + flags.Var(dopts.NewNamedIPListOptsRef("dns", &conf.DNS), "dns", "DNS server to use") flags.Var(opts.NewNamedListOptsRef("dns-opts", &conf.DNSOptions, nil), "dns-opt", "DNS options to use") flags.Var(opts.NewListOptsRef(&conf.DNSSearch, opts.ValidateDNSSearch), "dns-search", "DNS search domains to use") flags.Var(dopts.NewNamedIPListOptsRef("host-gateway-ips", &conf.HostGatewayIPs), "host-gateway-ip", "IP addresses that the special 'host-gateway' string in --add-host resolves to. Defaults to the IP addresses of the default bridge") diff --git a/daemon/config/config.go b/daemon/config/config.go index cfb372dfb9..fd0d376b02 100644 --- a/daemon/config/config.go +++ b/daemon/config/config.go @@ -170,7 +170,7 @@ type TLSOptions struct { // DNSConfig defines the DNS configurations. type DNSConfig struct { - DNS []net.IP `json:"dns,omitempty"` + DNS []netip.Addr `json:"dns,omitempty"` DNSOptions []string `json:"dns-opts,omitempty"` DNSSearch []string `json:"dns-search,omitempty"` HostGatewayIP net.IP `json:"host-gateway-ip,omitempty"` // Deprecated: this single-IP is migrated to HostGatewayIPs diff --git a/daemon/config/config_test.go b/daemon/config/config_test.go index 7b2f999da6..bed80d803f 100644 --- a/daemon/config/config_test.go +++ b/daemon/config/config_test.go @@ -658,12 +658,12 @@ func TestConfigInvalidDNS(t *testing.T) { { doc: "single DNS, invalid IP-address", input: `{"dns": ["1.1.1.1o"]}`, - expectedErr: `invalid IP address: 1.1.1.1o`, + expectedErr: `ParseAddr("1.1.1.1o"): unexpected character (at "o")`, }, { doc: "multiple DNS, invalid IP-address", input: `{"dns": ["2.2.2.2", "1.1.1.1o"]}`, - expectedErr: `invalid IP address: 1.1.1.1o`, + expectedErr: `ParseAddr("1.1.1.1o"): unexpected character (at "o")`, }, } @@ -671,7 +671,7 @@ func TestConfigInvalidDNS(t *testing.T) { t.Run(tc.doc, func(t *testing.T) { var cfg Config err := json.Unmarshal([]byte(tc.input), &cfg) - assert.Check(t, is.Error(err, tc.expectedErr)) + assert.Check(t, is.Error(err, tc.expectedErr), "type: %T", err) }) } } diff --git a/daemon/container_operations.go b/daemon/container_operations.go index cf51847f2a..cdacca91cc 100644 --- a/daemon/container_operations.go +++ b/daemon/container_operations.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "net" + "net/netip" "os" "runtime" "strings" @@ -36,12 +37,16 @@ import ( const errSetupNetworking = "failed to set up container networking" -func ipAddresses(ips []net.IP) []string { - var addrs []string - for _, ip := range ips { - addrs = append(addrs, ip.String()) +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 addrs + return dnsAddrs, nil } func buildSandboxOptions(cfg *config.Config, ctr *container.Container) ([]libnetwork.SandboxOption, error) { @@ -62,9 +67,13 @@ func buildSandboxOptions(cfg *config.Config, ctr *container.Container) ([]libnet } if len(ctr.HostConfig.DNS) > 0 { - sboxOptions = append(sboxOptions, libnetwork.OptionDNS(ctr.HostConfig.DNS)) + dnsAddrs, err := toNetIP(ctr.HostConfig.DNS) + if err != nil { + return nil, err + } + sboxOptions = append(sboxOptions, libnetwork.OptionDNS(dnsAddrs)) } else if len(cfg.DNS) > 0 { - sboxOptions = append(sboxOptions, libnetwork.OptionDNS(ipAddresses(cfg.DNS))) + sboxOptions = append(sboxOptions, libnetwork.OptionDNS(cfg.DNS)) } if len(ctr.HostConfig.DNSSearch) > 0 { sboxOptions = append(sboxOptions, libnetwork.OptionDNSSearch(ctr.HostConfig.DNSSearch)) @@ -711,7 +720,7 @@ func (daemon *Daemon) connectToNetwork(ctx context.Context, cfg *config.Config, return err } - createOptions, err := buildCreateEndpointOptions(ctr, n, endpointConfig, sb, ipAddresses(cfg.DNS)) + createOptions, err := buildCreateEndpointOptions(ctr, n, endpointConfig, sb, cfg.DNS) if err != nil { return err } diff --git a/daemon/internal/builder-next/executor.go b/daemon/internal/builder-next/executor.go index d15e2761ea..d12c3be89c 100644 --- a/daemon/internal/builder-next/executor.go +++ b/daemon/internal/builder-next/executor.go @@ -2,7 +2,7 @@ package buildkit import ( "context" - "net" + "net/netip" "os" "path/filepath" "sync" @@ -110,7 +110,7 @@ func getDNSConfig(cfg config.DNSConfig) *oci.DNSConfig { return nil } -func ipAddresses(ips []net.IP) []string { +func ipAddresses(ips []netip.Addr) []string { var addrs []string for _, ip := range ips { addrs = append(addrs, ip.String()) diff --git a/daemon/libnetwork/sandbox.go b/daemon/libnetwork/sandbox.go index bd57127caa..b59a32924a 100644 --- a/daemon/libnetwork/sandbox.go +++ b/daemon/libnetwork/sandbox.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "net" + "net/netip" "slices" "sort" "strings" @@ -80,7 +81,7 @@ type resolvConfPathConfig struct { resolvConfPath string originResolvConfPath string resolvConfHashFile string - dnsList []string + dnsList []netip.Addr dnsSearchList []string dnsOptionsList []string } diff --git a/daemon/libnetwork/sandbox_dns_unix.go b/daemon/libnetwork/sandbox_dns_unix.go index 75092a320f..2c5aad9954 100644 --- a/daemon/libnetwork/sandbox_dns_unix.go +++ b/daemon/libnetwork/sandbox_dns_unix.go @@ -254,15 +254,7 @@ func (sb *Sandbox) loadResolvConf(path string) (*resolvconf.ResolvConf, error) { # This file can be edited; Docker Engine will not make further changes once it # has been modified.`) if len(sb.config.dnsList) > 0 { - var dnsAddrs []netip.Addr - for _, ns := range sb.config.dnsList { - addr, err := netip.ParseAddr(ns) - if err != nil { - return nil, errors.Wrapf(err, "bad nameserver address %s", ns) - } - dnsAddrs = append(dnsAddrs, addr) - } - rc.OverrideNameServers(dnsAddrs) + rc.OverrideNameServers(sb.config.dnsList) } if len(sb.config.dnsSearchList) > 0 { rc.OverrideSearch(sb.config.dnsSearchList) diff --git a/daemon/libnetwork/sandbox_options.go b/daemon/libnetwork/sandbox_options.go index a56a232369..ea6e972872 100644 --- a/daemon/libnetwork/sandbox_options.go +++ b/daemon/libnetwork/sandbox_options.go @@ -1,6 +1,8 @@ package libnetwork import ( + "net/netip" + "github.com/moby/moby/v2/daemon/libnetwork/netlabel" "github.com/moby/moby/v2/daemon/libnetwork/osl" "github.com/moby/moby/v2/daemon/libnetwork/types" @@ -64,7 +66,7 @@ func OptionOriginResolvConfPath(path string) SandboxOption { // OptionDNS function returns an option setter for dns entry option to // be passed to container Create method. -func OptionDNS(dns []string) SandboxOption { +func OptionDNS(dns []netip.Addr) SandboxOption { return func(sb *Sandbox) { sb.config.dnsList = dns } diff --git a/daemon/network.go b/daemon/network.go index 7650185723..3487e86326 100644 --- a/daemon/network.go +++ b/daemon/network.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "net" + "net/netip" "sort" "strconv" "strings" @@ -831,7 +832,7 @@ func (daemon *Daemon) clearAttachableNetworks() { } // buildCreateEndpointOptions builds endpoint options from a given network. -func buildCreateEndpointOptions(c *container.Container, n *libnetwork.Network, epConfig *network.EndpointSettings, sb *libnetwork.Sandbox, daemonDNS []string) ([]libnetwork.EndpointOption, error) { +func buildCreateEndpointOptions(c *container.Container, n *libnetwork.Network, epConfig *network.EndpointSettings, sb *libnetwork.Sandbox, daemonDNS []netip.Addr) ([]libnetwork.EndpointOption, error) { var createOptions []libnetwork.EndpointOption genericOptions := make(options.Generic) @@ -914,7 +915,11 @@ func buildCreateEndpointOptions(c *container.Container, n *libnetwork.Network, e if len(c.HostConfig.DNS) > 0 { createOptions = append(createOptions, libnetwork.CreateOptionDNS(c.HostConfig.DNS)) } else if len(daemonDNS) > 0 { - createOptions = append(createOptions, libnetwork.CreateOptionDNS(daemonDNS)) + dns := make([]string, len(daemonDNS)) + for i, a := range daemonDNS { + dns[i] = a.String() + } + createOptions = append(createOptions, libnetwork.CreateOptionDNS(dns)) } }