From 25ce9885a25241adda1c8dd0a83af9c63301a4cf Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 23 Apr 2021 20:57:35 -0700 Subject: [PATCH] net/dns: don't use NM+resolved for NM >=1.26.6. NetworkManager fixed the bug that forced us to use NetworkManager if it's programming systemd-resolved, and in the same release also made NetworkManager ignore DNS settings provided for unmanaged interfaces... Which breaks what we used to do. So, with versions 1.26.6 and above, we MUST NOT use NetworkManager to indirectly program systemd-resolved, but thankfully we can talk to resolved directly and get the right outcome. Fixes #1788 Signed-off-by: David Anderson --- cmd/tailscaled/depaware.txt | 1 + net/dns/manager_linux.go | 49 ++++++++++++++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/cmd/tailscaled/depaware.txt b/cmd/tailscaled/depaware.txt index e51b75dec..4f00dcd20 100644 --- a/cmd/tailscaled/depaware.txt +++ b/cmd/tailscaled/depaware.txt @@ -131,6 +131,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de tailscale.com/types/strbuilder from tailscale.com/net/packet tailscale.com/types/structs from tailscale.com/control/controlclient+ tailscale.com/types/wgkey from tailscale.com/control/controlclient+ + L tailscale.com/util/cmpver from tailscale.com/net/dns tailscale.com/util/dnsname from tailscale.com/ipn/ipnstate+ LW tailscale.com/util/endian from tailscale.com/net/netns+ L tailscale.com/util/lineread from tailscale.com/control/controlclient+ diff --git a/net/dns/manager_linux.go b/net/dns/manager_linux.go index f55b2b8cd..47ce5c1ca 100644 --- a/net/dns/manager_linux.go +++ b/net/dns/manager_linux.go @@ -16,6 +16,7 @@ import ( "github.com/godbus/dbus/v5" "tailscale.com/types/logger" + "tailscale.com/util/cmpver" ) type kv struct { @@ -64,7 +65,32 @@ func NewOSConfigurator(logf logger.Logf, interfaceName string) (ret OSConfigurat return newResolvedManager(logf) } dbg("nm-resolved", "yes") - return newNMManager(interfaceName) + + // Version of NetworkManager before 1.26.6 programmed resolved + // incorrectly, such that NM's settings would always take + // precedence over other settings set by other resolved + // clients. + // + // If we're dealing with such a version, we have to set our + // DNS settings through NM to have them take. + // + // However, versions 1.26.6 later both fixed the resolved + // programming issue _and_ started ignoring DNS settings for + // "unmanaged" interfaces - meaning NM 1.26.6 and later + // actively ignore DNS configuration we give it. So, for those + // NM versions, we can and must use resolved directly. + old, err := nmVersionOlderThan("1.26.6") + if err != nil { + // Failed to figure out NM's version, can't make a correct + // decision. + return nil, fmt.Errorf("checking NetworkManager version: %v", err) + } + if old { + dbg("nm-old", "yes") + return newNMManager(interfaceName) + } + dbg("nm-old", "no") + return newResolvedManager(logf) case "resolvconf": dbg("rc", "resolvconf") if err := resolvconfSourceIsNM(bs); err == nil { @@ -135,6 +161,27 @@ func resolvconfSourceIsNM(resolvDotConf []byte) error { return nil } +func nmVersionOlderThan(want string) (bool, error) { + conn, err := dbus.SystemBus() + if err != nil { + // DBus probably not running. + return false, err + } + + nm := conn.Object("org.freedesktop.NetworkManager", dbus.ObjectPath("/org/freedesktop/NetworkManager")) + v, err := nm.GetProperty("org.freedesktop.NetworkManager.Version") + if err != nil { + return false, err + } + + version, ok := v.Value().(string) + if !ok { + return false, fmt.Errorf("unexpected type %T for NM version", v.Value()) + } + + return cmpver.Compare(version, want) < 0, nil +} + func nmIsUsingResolved() error { conn, err := dbus.SystemBus() if err != nil {