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 <danderson@tailscale.com>
pull/1791/head
David Anderson 3 years ago
parent 31f81b782e
commit 25ce9885a2

@ -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+

@ -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 {

Loading…
Cancel
Save