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