No fallback nameservers for internal resolver

The internal resolver now uses any namesever found in the host's
/etc/resolv.conf as an external nameserver, and it's accessed
from the host's network namespace.

Before this change, when no external nameservers were found (so
the host had no entries in /etc/resolv.conf) Google's DNS servers
were used as fallbacks, always accessed from the container's
network namespace. If a container's initial set of endpoints had
IPv6 enabled, the IPv6 nameservers were included.

Now we have IPv6-only networks, a similar exception would be
needed for Google's IPv4 nameservers... don't include them if
there are no IPv4 endpoints.

However, only the initial set of endpoints was considered. As
networks are connected/disconnected, IPv4 or IPv6 connectivity
may be lost.

Unlike nameservers read from the host's /etc/resolv.conf, there
is no way to tell which fallback nameservers (v4/v6) might work
from the host's namespace. So, using the host's namespace isn't
a good solution.

Since we want to get away from using fallback nameservers anyway,
this change removes them.

If a host has no /etc/resolv.conf entries, but a container does
need to use DNS, it'll need to be configured with servers via
'--dns'.

Signed-off-by: Rob Murray <rob.murray@docker.com>
This commit is contained in:
Rob Murray
2024-07-30 18:57:06 +01:00
parent d29767431c
commit 925b484a40
12 changed files with 5 additions and 136 deletions

View File

@@ -245,7 +245,6 @@ func (rc *ResolvConf) TransformForLegacyNw(ipv6 bool) {
// option includes a ':', and an option with a matching prefix exists, it
// is not modified.
func (rc *ResolvConf) TransformForIntNS(
ipv6 bool,
internalNS netip.Addr,
reqdOptions []string,
) ([]ExtDNSEntry, error) {
@@ -265,16 +264,6 @@ func (rc *ResolvConf) TransformForIntNS(
// The transformed config only lists the internal nameserver.
rc.nameServers = []netip.Addr{internalNS}
// If there are no external nameservers, and the only nameserver left is the
// internal resolver, use the defaults as ext nameservers.
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")
for _, addr := range defaultNSAddrs(ipv6) {
rc.md.ExtNameServers = append(rc.md.ExtNameServers, ExtDNSEntry{Addr: addr})
}
rc.md.UsedDefaultNS = true
}
// For each option required by the nameserver, add it if not already present. If
// the option is already present, don't override it. Apart from ndots - if the
// ndots value is invalid and an ndots option is required, replace the existing

View File

@@ -340,7 +340,6 @@ func TestRCTransformForIntNS(t *testing.T) {
name string
input string
intNameServer string
ipv6 bool
overrideNS []string
overrideOptions []string
reqdOptions []string
@@ -355,16 +354,6 @@ func TestRCTransformForIntNS(t *testing.T) {
{
name: "IPv4 and IPv6, ipv6 enabled",
input: "nameserver 10.0.0.1\nnameserver fdb6:b8fe:b528::1",
ipv6: true,
expExtServers: []ExtDNSEntry{
mke("10.0.0.1", true),
mke("fdb6:b8fe:b528::1", true),
},
},
{
name: "IPv4 and IPv6, ipv6 disabled",
input: "nameserver 10.0.0.1\nnameserver fdb6:b8fe:b528::1",
ipv6: false,
expExtServers: []ExtDNSEntry{
mke("10.0.0.1", true),
mke("fdb6:b8fe:b528::1", true),
@@ -373,7 +362,6 @@ func TestRCTransformForIntNS(t *testing.T) {
{
name: "IPv4 localhost",
input: "nameserver 127.0.0.53",
ipv6: false,
expExtServers: []ExtDNSEntry{mke("127.0.0.53", true)},
},
{
@@ -381,78 +369,22 @@ func TestRCTransformForIntNS(t *testing.T) {
// loopback interface, not the host's.
name: "IPv4 localhost override",
input: "nameserver 10.0.0.1",
ipv6: false,
overrideNS: []string{"127.0.0.53"},
expExtServers: []ExtDNSEntry{mke("127.0.0.53", false)},
},
{
name: "IPv4 localhost, ipv6 enabled",
input: "nameserver 127.0.0.53",
ipv6: true,
expExtServers: []ExtDNSEntry{mke("127.0.0.53", true)},
},
{
name: "IPv6 addr, IPv6 enabled",
name: "IPv6 only",
input: "nameserver fd14:6e0e:f855::1",
ipv6: true,
expExtServers: []ExtDNSEntry{mke("fd14:6e0e:f855::1", true)},
},
{
name: "IPv4 and IPv6 localhost, IPv6 disabled",
name: "IPv4 and IPv6 localhost",
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,
expExtServers: []ExtDNSEntry{
mke("127.0.0.53", true),
mke("::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),
mke("fd3e:2d1a:1f5a::1", 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),
mke("fd3e:2d1a:1f5a::1", true),
},
},
{
name: "No host nameserver, no iv6",
input: "",
ipv6: false,
expExtServers: []ExtDNSEntry{
mke("8.8.8.8", false),
mke("8.8.4.4", false),
},
},
{
name: "No host nameserver, iv6",
input: "",
ipv6: true,
expExtServers: []ExtDNSEntry{
mke("8.8.8.8", false),
mke("8.8.4.4", false),
mke("2001:4860:4860::8888", false),
mke("2001:4860:4860::8844", false),
},
},
{
name: "ndots present and required",
input: "nameserver 127.0.0.53\noptions ndots:1",
@@ -496,7 +428,7 @@ func TestRCTransformForIntNS(t *testing.T) {
rc.OverrideOptions(tc.overrideOptions)
}
intNS := netip.MustParseAddr(tc.intNameServer)
extNameServers, err := rc.TransformForIntNS(tc.ipv6, intNS, tc.reqdOptions)
extNameServers, err := rc.TransformForIntNS(intNS, tc.reqdOptions)
if tc.expErr != "" {
assert.Check(t, is.ErrorContains(err, tc.expErr))
return
@@ -559,7 +491,7 @@ func TestRCTransformForIntNSInvalidNdots(t *testing.T) {
content := "nameserver 8.8.8.8\n" + tc.options
rc, err := Parse(bytes.NewBuffer([]byte(content)), "/etc/resolv.conf")
assert.NilError(t, err)
_, err = rc.TransformForIntNS(false, netip.MustParseAddr("127.0.0.11"), tc.reqdOptions)
_, err = rc.TransformForIntNS(netip.MustParseAddr("127.0.0.11"), tc.reqdOptions)
assert.NilError(t, err)
val, found := rc.Option("ndots")

View File

@@ -1,5 +0,0 @@
nameserver 127.0.0.11
# Based on host file: '/etc/resolv.conf' (internal resolver)
# ExtServers: [host(10.0.0.1) host(fdb6:b8fe:b528::1)]
# Overrides: []

View File

@@ -1,5 +0,0 @@
nameserver 127.0.0.11
# Based on host file: '/etc/resolv.conf' (internal resolver)
# ExtServers: [host(127.0.0.53) host(::1)]
# Overrides: []

View File

@@ -1,5 +0,0 @@
nameserver 127.0.0.11
# Based on host file: '/etc/resolv.conf' (internal resolver)
# ExtServers: [host(127.0.0.53) host(fd3e:2d1a:1f5a::1)]
# Overrides: []

View File

@@ -1,5 +0,0 @@
nameserver 127.0.0.11
# Based on host file: '/etc/resolv.conf' (internal resolver)
# ExtServers: [host(127.0.0.53) host(fd3e:2d1a:1f5a::1)]
# Overrides: []

View File

@@ -1,5 +0,0 @@
nameserver 127.0.0.11
# Based on host file: '/etc/resolv.conf' (internal resolver)
# ExtServers: [host(127.0.0.53)]
# Overrides: []

View File

@@ -1,6 +0,0 @@
nameserver 127.0.0.11
# Based on host file: '/etc/resolv.conf' (internal resolver)
# Used default nameservers.
# ExtServers: [8.8.8.8 8.8.4.4 2001:4860:4860::8888 2001:4860:4860::8844]
# Overrides: []

View File

@@ -1,6 +0,0 @@
nameserver 127.0.0.11
# Based on host file: '/etc/resolv.conf' (internal resolver)
# Used default nameservers.
# ExtServers: [8.8.8.8 8.8.4.4]
# Overrides: []

View File

@@ -336,21 +336,6 @@ func (sb *Sandbox) rebuildDNS() error {
return err
}
// Check for IPv6 endpoints in this sandbox. If there are any, and the container has
// IPv6 enabled, upstream requests from the internal DNS resolver can be made from
// the container's namespace.
// TODO(robmry) - this can only check networks connected when the resolver is set up,
// the configuration won't be updated if the container gets an IPv6 address later.
ipv6 := false
for _, ep := range sb.endpoints {
if ep.network.enableIPv6 {
if en, ok := sb.ipv6Enabled(); ok {
ipv6 = en
}
break
}
}
intNS := sb.resolver.NameServer()
if !intNS.IsValid() {
return fmt.Errorf("no listen-address for internal resolver")
@@ -360,7 +345,7 @@ func (sb *Sandbox) rebuildDNS() error {
_, sb.ndotsSet = rc.Option("ndots")
// Swap nameservers for the internal one, and make sure the required options are set.
var extNameServers []resolvconf.ExtDNSEntry
extNameServers, err = rc.TransformForIntNS(ipv6, intNS, sb.resolver.ResolverOptions())
extNameServers, err = rc.TransformForIntNS(intNS, sb.resolver.ResolverOptions())
if err != nil {
return err
}