From d830bf8430d25f4401db8decf200e781267438e0 Mon Sep 17 00:00:00 2001 From: Paul Holzinger Date: Thu, 7 Nov 2024 16:42:45 +0100 Subject: [PATCH] libnetwork/resolvconf: filter out ipv6 link local One thing I noticed in the recent aardvark-dns bug[1] that we copy link local nameservers into the container. This makes no sense as the link local address contains a zone (interface name/index) and cannot work without it. However a container by design will have a different interface name/index so the address can never work in the normal case. Only when we do share the host netns then we should keep it. [1] https://github.com/containers/aardvark-dns/pull/537 Signed-off-by: Paul Holzinger --- libnetwork/resolvconf/resolv_test.go | 12 ++++++++++++ libnetwork/resolvconf/resolvconf.go | 15 ++++++++++----- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/libnetwork/resolvconf/resolv_test.go b/libnetwork/resolvconf/resolv_test.go index 07a975dc3..8e1dfdf80 100644 --- a/libnetwork/resolvconf/resolv_test.go +++ b/libnetwork/resolvconf/resolv_test.go @@ -122,6 +122,18 @@ func TestNew(t *testing.T) { ipv6: true, want: "nameserver 1.1.1.1\nnameserver fd::1\n", }, + { + name: "ipv6 link local must always be filtered when netns is private", + baseContent: "nameserver 1.1.1.1\nnameserver fe80::1%eth1\nnameserver fd::1\n", + ipv6: true, + want: "nameserver 1.1.1.1\nnameserver fd::1\n", + }, + { + name: "ipv6 link local must not be filtered when netns is host", + baseContent: "nameserver 1.1.1.1\nnameserver fe80::1%eth1\nnameserver fd::1\n", + hostns: true, + want: "nameserver 1.1.1.1\nnameserver fe80::1%eth1\nnameserver fd::1\n", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/libnetwork/resolvconf/resolvconf.go b/libnetwork/resolvconf/resolvconf.go index 6b844373d..97cf48cfd 100644 --- a/libnetwork/resolvconf/resolvconf.go +++ b/libnetwork/resolvconf/resolvconf.go @@ -32,11 +32,12 @@ var ( // ipLocalhost is a regex pattern for IPv4 or IPv6 loopback range. ipLocalhost = `((127\.([0-9]{1,3}\.){2}[0-9]{1,3})|(::1)$)` - localhostNSRegexp = regexp.Delayed(`(?m)^nameserver\s+` + ipLocalhost + `\s*\n*`) - nsIPv6Regexp = regexp.Delayed(`(?m)^nameserver\s+` + ipv6Address + `\s*\n*`) - nsRegexp = regexp.Delayed(`^\s*nameserver\s*((` + ipv4Address + `)|(` + ipv6Address + `))\s*$`) - searchRegexp = regexp.Delayed(`^\s*search\s*(([^\s]+\s*)*)$`) - optionsRegexp = regexp.Delayed(`^\s*options\s*(([^\s]+\s*)*)$`) + localhostNSRegexp = regexp.Delayed(`(?m)^nameserver\s+` + ipLocalhost + `\s*\n*`) + nsIPv6Regexp = regexp.Delayed(`(?m)^nameserver\s+` + ipv6Address + `\s*\n*`) + nsIPv6LinkLocalRegexp = regexp.Delayed(`(?m)^nameserver\s+` + ipv6Address + `%.*\s*\n*`) + nsRegexp = regexp.Delayed(`^\s*nameserver\s*((` + ipv4Address + `)|(` + ipv6Address + `))\s*$`) + searchRegexp = regexp.Delayed(`^\s*search\s*(([^\s]+\s*)*)$`) + optionsRegexp = regexp.Delayed(`^\s*options\s*(([^\s]+\s*)*)$`) ) // filterResolvDNS cleans up the config in resolvConf. It has two main jobs: @@ -54,6 +55,10 @@ func filterResolvDNS(resolvConf []byte, ipv6Enabled bool, netnsEnabled bool) []b // if IPv6 is not enabled, also clean out any IPv6 address nameserver if !ipv6Enabled { cleanedResolvConf = nsIPv6Regexp.ReplaceAll(cleanedResolvConf, []byte{}) + } else { + // If ipv6 is we still must remove any ipv6 link-local addresses as + // the zone will never match the interface name or index in the container. + cleanedResolvConf = nsIPv6LinkLocalRegexp.ReplaceAll(cleanedResolvConf, []byte{}) } // if the resulting resolvConf has no more nameservers defined, add appropriate // default DNS servers for IPv4 and (optionally) IPv6