Add IPv6 nameserver to the internal DNS's upstreams.
When configuring the internal DNS resolver - rather than keep IPv6 nameservers read from the host's resolv.conf in the container's resolv.conf, treat them like IPv4 addresses and use them as upstream resolvers. For IPv6 nameservers, if there's a zone identifier in the address or the container itself doesn't have IPv6 support, mark the upstream addresses for use in the host's network namespace. Signed-off-by: Rob Murray <rob.murray@docker.com>
This commit is contained in:
parent
137a9d6a4c
commit
4e8d9a4522
11 changed files with 78 additions and 83 deletions
|
@ -237,7 +237,7 @@ func (rc *ResolvConf) TransformForLegacyNw(ipv6 bool) {
|
||||||
// use in a network sandbox that has an internal DNS resolver.
|
// use in a network sandbox that has an internal DNS resolver.
|
||||||
// - Add internalNS as a nameserver.
|
// - Add internalNS as a nameserver.
|
||||||
// - Remove other nameservers, stashing them as ExtNameServers for the
|
// - Remove other nameservers, stashing them as ExtNameServers for the
|
||||||
// internal resolver to use. (Apart from IPv6 nameservers, if keepIPv6.)
|
// internal resolver to use.
|
||||||
// - Mark ExtNameServers that must be used in the host namespace.
|
// - Mark ExtNameServers that must be used in the host namespace.
|
||||||
// - If no ExtNameServer addresses are found, use the defaults.
|
// - If no ExtNameServer addresses are found, use the defaults.
|
||||||
// - Return an error if an "ndots" option inherited from the host's config, or
|
// - Return an error if an "ndots" option inherited from the host's config, or
|
||||||
|
@ -246,7 +246,7 @@ func (rc *ResolvConf) TransformForLegacyNw(ipv6 bool) {
|
||||||
// option includes a ':', and an option with a matching prefix exists, it
|
// option includes a ':', and an option with a matching prefix exists, it
|
||||||
// is not modified.
|
// is not modified.
|
||||||
func (rc *ResolvConf) TransformForIntNS(
|
func (rc *ResolvConf) TransformForIntNS(
|
||||||
keepIPv6 bool,
|
ipv6 bool,
|
||||||
internalNS netip.Addr,
|
internalNS netip.Addr,
|
||||||
reqdOptions []string,
|
reqdOptions []string,
|
||||||
) ([]ExtDNSEntry, error) {
|
) ([]ExtDNSEntry, error) {
|
||||||
|
@ -256,30 +256,16 @@ func (rc *ResolvConf) TransformForIntNS(
|
||||||
// internal nameserver.
|
// internal nameserver.
|
||||||
rc.md.ExtNameServers = nil
|
rc.md.ExtNameServers = nil
|
||||||
for _, addr := range rc.nameServers {
|
for _, addr := range rc.nameServers {
|
||||||
// The internal resolver only uses IPv4 addresses so, keep IPv6 nameservers in
|
// Extract this NS. Mark addresses that did not come from an override, but will
|
||||||
// the container's file if keepIPv6, else drop them.
|
// definitely not work in the container's namespace as 'HostLoopback'. Upstream
|
||||||
if addr.Is6() {
|
// requests for these servers will be made in the host's network namespace. (So,
|
||||||
if keepIPv6 {
|
// '--dns 127.0.0.53' means use a nameserver listening on the container's
|
||||||
newNSs = append(newNSs, addr)
|
// loopback interface. But, if the host's resolv.conf contains 'nameserver
|
||||||
}
|
// 127.0.0.53', the host's resolver will be used.)
|
||||||
} else {
|
rc.md.ExtNameServers = append(rc.md.ExtNameServers, ExtDNSEntry{
|
||||||
// Extract this NS. Mark loopback addresses that did not come from an override as
|
Addr: addr,
|
||||||
// 'HostLoopback'. Upstream requests for these servers will be made in the host's
|
HostLoopback: !rc.md.NSOverride && (addr.IsLoopback() || (addr.Is6() && !ipv6) || addr.Zone() != ""),
|
||||||
// network namespace. (So, '--dns 127.0.0.53' means use a nameserver listening on
|
})
|
||||||
// the container's loopback interface. But, if the host's resolv.conf contains
|
|
||||||
// 'nameserver 127.0.0.53', the host's resolver will be used.)
|
|
||||||
//
|
|
||||||
// TODO(robmry) - why only loopback addresses?
|
|
||||||
// Addresses from the host's resolv.conf must be usable in the host's namespace,
|
|
||||||
// and a lookup from the container's namespace is more expensive? And, for
|
|
||||||
// example, if the host has a nameserver with an IPv6 LL address with a zone-id,
|
|
||||||
// it won't work from the container's namespace (now, while the address is left in
|
|
||||||
// the container's resolv.conf, or in future for the internal resolver).
|
|
||||||
rc.md.ExtNameServers = append(rc.md.ExtNameServers, ExtDNSEntry{
|
|
||||||
Addr: addr,
|
|
||||||
HostLoopback: addr.IsLoopback() && !rc.md.NSOverride,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
rc.nameServers = newNSs
|
rc.nameServers = newNSs
|
||||||
|
|
||||||
|
@ -287,7 +273,7 @@ func (rc *ResolvConf) TransformForIntNS(
|
||||||
// internal resolver, use the defaults as ext nameservers.
|
// internal resolver, use the defaults as ext nameservers.
|
||||||
if len(rc.md.ExtNameServers) == 0 && len(rc.nameServers) == 1 {
|
if len(rc.md.ExtNameServers) == 0 && len(rc.nameServers) == 1 {
|
||||||
log.G(context.TODO()).Info("No non-localhost DNS nameservers are left in resolv.conf. Using default external servers")
|
log.G(context.TODO()).Info("No non-localhost DNS nameservers are left in resolv.conf. Using default external servers")
|
||||||
for _, addr := range defaultNSAddrs(keepIPv6) {
|
for _, addr := range defaultNSAddrs(ipv6) {
|
||||||
rc.md.ExtNameServers = append(rc.md.ExtNameServers, ExtDNSEntry{Addr: addr})
|
rc.md.ExtNameServers = append(rc.md.ExtNameServers, ExtDNSEntry{Addr: addr})
|
||||||
}
|
}
|
||||||
rc.md.UsedDefaultNS = true
|
rc.md.UsedDefaultNS = true
|
||||||
|
|
|
@ -351,16 +351,22 @@ func TestRCTransformForIntNS(t *testing.T) {
|
||||||
expExtServers: []ExtDNSEntry{mke("10.0.0.1", false)},
|
expExtServers: []ExtDNSEntry{mke("10.0.0.1", false)},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "IPv4 and IPv6, ipv6 enabled",
|
name: "IPv4 and IPv6, ipv6 enabled",
|
||||||
input: "nameserver 10.0.0.1\nnameserver fdb6:b8fe:b528::1",
|
input: "nameserver 10.0.0.1\nnameserver fdb6:b8fe:b528::1",
|
||||||
ipv6: true,
|
ipv6: true,
|
||||||
expExtServers: []ExtDNSEntry{mke("10.0.0.1", false)},
|
expExtServers: []ExtDNSEntry{
|
||||||
|
mke("10.0.0.1", false),
|
||||||
|
mke("fdb6:b8fe:b528::1", false),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "IPv4 and IPv6, ipv6 disabled",
|
name: "IPv4 and IPv6, ipv6 disabled",
|
||||||
input: "nameserver 10.0.0.1\nnameserver fdb6:b8fe:b528::1",
|
input: "nameserver 10.0.0.1\nnameserver fdb6:b8fe:b528::1",
|
||||||
ipv6: false,
|
ipv6: false,
|
||||||
expExtServers: []ExtDNSEntry{mke("10.0.0.1", false)},
|
expExtServers: []ExtDNSEntry{
|
||||||
|
mke("10.0.0.1", false),
|
||||||
|
mke("fdb6:b8fe:b528::1", true),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "IPv4 localhost",
|
name: "IPv4 localhost",
|
||||||
|
@ -384,37 +390,46 @@ func TestRCTransformForIntNS(t *testing.T) {
|
||||||
expExtServers: []ExtDNSEntry{mke("127.0.0.53", true)},
|
expExtServers: []ExtDNSEntry{mke("127.0.0.53", true)},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "IPv6 addr, IPv6 enabled",
|
name: "IPv6 addr, IPv6 enabled",
|
||||||
input: "nameserver fd14:6e0e:f855::1",
|
input: "nameserver fd14:6e0e:f855::1",
|
||||||
|
ipv6: true,
|
||||||
|
expExtServers: []ExtDNSEntry{mke("fd14:6e0e:f855::1", false)},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "IPv4 and IPv6 localhost, IPv6 disabled",
|
||||||
|
input: "nameserver 127.0.0.53\nnameserver ::1",
|
||||||
|
ipv6: false,
|
||||||
|
expExtServers: []ExtDNSEntry{
|
||||||
|
mke("127.0.0.53", true),
|
||||||
|
mke("::1", true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "IPv4 and IPv6 localhost, ipv6 enabled",
|
||||||
|
input: "nameserver 127.0.0.53\nnameserver ::1",
|
||||||
ipv6: true,
|
ipv6: true,
|
||||||
// Note that there are no ext servers in this case, the internal resolver
|
expExtServers: []ExtDNSEntry{
|
||||||
// will only look up container names. The default nameservers aren't added
|
mke("127.0.0.53", true),
|
||||||
// because the host's IPv6 nameserver remains in the container's resolv.conf,
|
mke("::1", true),
|
||||||
// (because only IPv4 ext servers are currently allowed).
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "IPv4 and IPv6 localhost, IPv6 disabled",
|
name: "IPv4 localhost, IPv6 private, IPv6 enabled",
|
||||||
input: "nameserver 127.0.0.53\nnameserver ::1",
|
input: "nameserver 127.0.0.53\nnameserver fd3e:2d1a:1f5a::1",
|
||||||
ipv6: false,
|
ipv6: true,
|
||||||
expExtServers: []ExtDNSEntry{mke("127.0.0.53", true)},
|
expExtServers: []ExtDNSEntry{
|
||||||
|
mke("127.0.0.53", true),
|
||||||
|
mke("fd3e:2d1a:1f5a::1", false),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "IPv4 and IPv6 localhost, ipv6 enabled",
|
name: "IPv4 localhost, IPv6 private, IPv6 disabled",
|
||||||
input: "nameserver 127.0.0.53\nnameserver ::1",
|
input: "nameserver 127.0.0.53\nnameserver fd3e:2d1a:1f5a::1",
|
||||||
ipv6: true,
|
ipv6: false,
|
||||||
expExtServers: []ExtDNSEntry{mke("127.0.0.53", true)},
|
expExtServers: []ExtDNSEntry{
|
||||||
},
|
mke("127.0.0.53", true),
|
||||||
{
|
mke("fd3e:2d1a:1f5a::1", true),
|
||||||
name: "IPv4 localhost, IPv6 private, IPv6 enabled",
|
},
|
||||||
input: "nameserver 127.0.0.53\nnameserver fd3e:2d1a:1f5a::1",
|
|
||||||
ipv6: true,
|
|
||||||
expExtServers: []ExtDNSEntry{mke("127.0.0.53", true)},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "IPv4 localhost, IPv6 private, IPv6 disabled",
|
|
||||||
input: "nameserver 127.0.0.53\nnameserver fd3e:2d1a:1f5a::1",
|
|
||||||
ipv6: false,
|
|
||||||
expExtServers: []ExtDNSEntry{mke("127.0.0.53", true)},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "No host nameserver, no iv6",
|
name: "No host nameserver, no iv6",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
nameserver 127.0.0.11
|
nameserver 127.0.0.11
|
||||||
|
|
||||||
# Based on host file: '/etc/resolv.conf' (internal resolver)
|
# Based on host file: '/etc/resolv.conf' (internal resolver)
|
||||||
# ExtServers: [10.0.0.1]
|
# ExtServers: [10.0.0.1 host(fdb6:b8fe:b528::1)]
|
||||||
# Overrides: []
|
# Overrides: []
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
nameserver 127.0.0.11
|
nameserver 127.0.0.11
|
||||||
nameserver fdb6:b8fe:b528::1
|
|
||||||
|
|
||||||
# Based on host file: '/etc/resolv.conf' (internal resolver)
|
# Based on host file: '/etc/resolv.conf' (internal resolver)
|
||||||
# ExtServers: [10.0.0.1]
|
# ExtServers: [10.0.0.1 fdb6:b8fe:b528::1]
|
||||||
# Overrides: []
|
# Overrides: []
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
nameserver 127.0.0.11
|
nameserver 127.0.0.11
|
||||||
|
|
||||||
# Based on host file: '/etc/resolv.conf' (internal resolver)
|
# Based on host file: '/etc/resolv.conf' (internal resolver)
|
||||||
# ExtServers: [host(127.0.0.53)]
|
# ExtServers: [host(127.0.0.53) host(::1)]
|
||||||
# Overrides: []
|
# Overrides: []
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
nameserver 127.0.0.11
|
nameserver 127.0.0.11
|
||||||
nameserver ::1
|
|
||||||
|
|
||||||
# Based on host file: '/etc/resolv.conf' (internal resolver)
|
# Based on host file: '/etc/resolv.conf' (internal resolver)
|
||||||
# ExtServers: [host(127.0.0.53)]
|
# ExtServers: [host(127.0.0.53) host(::1)]
|
||||||
# Overrides: []
|
# Overrides: []
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
nameserver 127.0.0.11
|
nameserver 127.0.0.11
|
||||||
|
|
||||||
# Based on host file: '/etc/resolv.conf' (internal resolver)
|
# Based on host file: '/etc/resolv.conf' (internal resolver)
|
||||||
# ExtServers: [host(127.0.0.53)]
|
# ExtServers: [host(127.0.0.53) host(fd3e:2d1a:1f5a::1)]
|
||||||
# Overrides: []
|
# Overrides: []
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
nameserver 127.0.0.11
|
nameserver 127.0.0.11
|
||||||
nameserver fd3e:2d1a:1f5a::1
|
|
||||||
|
|
||||||
# Based on host file: '/etc/resolv.conf' (internal resolver)
|
# Based on host file: '/etc/resolv.conf' (internal resolver)
|
||||||
# ExtServers: [host(127.0.0.53)]
|
# ExtServers: [host(127.0.0.53) fd3e:2d1a:1f5a::1]
|
||||||
# Overrides: []
|
# Overrides: []
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
nameserver 127.0.0.11
|
nameserver 127.0.0.11
|
||||||
nameserver fd14:6e0e:f855::1
|
|
||||||
|
|
||||||
# Based on host file: '/etc/resolv.conf' (internal resolver)
|
# Based on host file: '/etc/resolv.conf' (internal resolver)
|
||||||
|
# ExtServers: [fd14:6e0e:f855::1]
|
||||||
# Overrides: []
|
# Overrides: []
|
||||||
|
|
|
@ -1838,7 +1838,7 @@ func TestResolvConf(t *testing.T) {
|
||||||
makeNet: makeTestIPv6Network,
|
makeNet: makeTestIPv6Network,
|
||||||
delNet: true,
|
delNet: true,
|
||||||
originResolvConf: "search pommesfrites.fr\nnameserver 12.34.56.78\nnameserver 2001:4860:4860::8888\n",
|
originResolvConf: "search pommesfrites.fr\nnameserver 12.34.56.78\nnameserver 2001:4860:4860::8888\n",
|
||||||
expResolvConf: "nameserver 127.0.0.11\nnameserver 2001:4860:4860::8888\nsearch pommesfrites.fr\noptions ndots:0",
|
expResolvConf: "nameserver 127.0.0.11\nsearch pommesfrites.fr\noptions ndots:0",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "host network",
|
name: "host network",
|
||||||
|
|
|
@ -327,20 +327,17 @@ func (sb *Sandbox) rebuildDNS() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for IPv6 endpoints in this sandbox. If there are any, IPv6 nameservers
|
// Check for IPv6 endpoints in this sandbox. If there are any, and the container has
|
||||||
// will be left in the container's 'resolv.conf'.
|
// IPv6 enabled, upstream requests from the internal DNS resolver can be made from
|
||||||
// TODO(robmry) - preserving old behaviour, but ...
|
// the container's namespace.
|
||||||
// IPv6 nameservers should be treated like IPv4 ones, and used as upstream
|
// TODO(robmry) - this can only check networks connected when the resolver is set up,
|
||||||
// servers for the internal resolver (if it has IPv6 connectivity). This
|
// the configuration won't be updated if the container gets an IPv6 address later.
|
||||||
// doesn't need to depend on whether there are currently any IPv6 endpoints.
|
|
||||||
// Removing IPv6 nameservers from the container's resolv.conf will avoid the
|
|
||||||
// problem that musl-libc's resolver tries all nameservers in parallel, so an
|
|
||||||
// external IPv6 resolver can return NXDOMAIN before the internal resolver
|
|
||||||
// returns the address of a container.
|
|
||||||
ipv6 := false
|
ipv6 := false
|
||||||
for _, ep := range sb.endpoints {
|
for _, ep := range sb.endpoints {
|
||||||
if ep.network.enableIPv6 {
|
if ep.network.enableIPv6 {
|
||||||
ipv6 = true
|
if en, ok := sb.ipv6Enabled(); ok {
|
||||||
|
ipv6 = en
|
||||||
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue