From 320cc8fa2191b1d04bcc54fd605db2d6d683405f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 15 Jun 2021 16:39:21 -0700 Subject: [PATCH] net/dns: verify that systemd-resolved is actually in charge. It's possible to install a configuration that passes our current checks for systemd-resolved, without actually pointing to systemd-resolved. In that case, we end up programming DNS in resolved, but that config never applies to any name resolution requests on the system. This is quite a far-out edge case, but there's a simple additional check we can do: if the header comment names systemd-resolved, there should be a single nameserver in resolv.conf pointing to 127.0.0.53. If not, the configuration should be treated as an unmanaged resolv.conf. Fixes #2136. Signed-off-by: David Anderson --- net/dns/manager_linux.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/net/dns/manager_linux.go b/net/dns/manager_linux.go index 94c211c40..eaba491fd 100644 --- a/net/dns/manager_linux.go +++ b/net/dns/manager_linux.go @@ -14,6 +14,7 @@ import ( "time" "github.com/godbus/dbus/v5" + "inet.af/netaddr" "tailscale.com/types/logger" "tailscale.com/util/cmpver" ) @@ -50,6 +51,15 @@ func NewOSConfigurator(logf logger.Logf, interfaceName string) (ret OSConfigurat switch resolvOwner(bs) { case "systemd-resolved": dbg("rc", "resolved") + // Some systems, for reasons known only to them, have a + // resolv.conf that has the word "systemd-resolved" in its + // header, but doesn't actually point to resolved. We mustn't + // try to program resolved in that case. + // https://github.com/tailscale/tailscale/issues/2136 + if err := resolvedIsActuallyResolver(); err != nil { + dbg("resolved", "not-in-use") + return newDirectManager() + } if err := dbusPing("org.freedesktop.resolve1", "/org/freedesktop/resolve1"); err != nil { dbg("resolved", "no") return newDirectManager() @@ -184,6 +194,17 @@ func nmIsUsingResolved() error { return nil } +func resolvedIsActuallyResolver() error { + cfg, err := readResolvConf() + if err != nil { + return err + } + if len(cfg.Nameservers) != 1 || cfg.Nameservers[0] != netaddr.IPv4(127, 0, 0, 53) { + return errors.New("resolv.conf doesn't point to systemd-resolved") + } + return nil +} + func dbusPing(name, objectPath string) error { ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel()