|
|
@ -14,7 +14,7 @@ import (
|
|
|
|
"context"
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/godbus/dbus/v5"
|
|
|
|
"github.com/godbus/dbus/v5"
|
|
|
|
"tailscale.com/util/endian"
|
|
|
|
"tailscale.com/util/endian"
|
|
|
@ -22,11 +22,21 @@ import (
|
|
|
|
|
|
|
|
|
|
|
|
// isNMActive determines if NetworkManager is currently managing system DNS settings.
|
|
|
|
// isNMActive determines if NetworkManager is currently managing system DNS settings.
|
|
|
|
func isNMActive() bool {
|
|
|
|
func isNMActive() bool {
|
|
|
|
// This is somewhat tricky because NetworkManager supports a number
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), reconfigTimeout)
|
|
|
|
// of DNS configuration modes. In all cases, we expect it to be installed
|
|
|
|
defer cancel()
|
|
|
|
// and /etc/resolv.conf to contain a mention of NetworkManager in the comments.
|
|
|
|
|
|
|
|
_, err := exec.LookPath("NetworkManager")
|
|
|
|
conn, err := dbus.SystemBus()
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
// Probably no DBus on this system. Either way, we can't
|
|
|
|
|
|
|
|
// control NM without DBus.
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Try to ping NetworkManager's DnsManager object. If it responds,
|
|
|
|
|
|
|
|
// NM is running and we're allowed to touch it.
|
|
|
|
|
|
|
|
nm := conn.Object("org.freedesktop.NetworkManager", dbus.ObjectPath("/org/freedesktop/NetworkManager/DnsManager"))
|
|
|
|
|
|
|
|
call := nm.CallWithContext(ctx, "org.freedesktop.DBus.Peer.Ping", 0)
|
|
|
|
|
|
|
|
if call.Err != nil {
|
|
|
|
return false
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -67,8 +77,24 @@ func (m nmManager) SetDNS(config OSConfig) error {
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), reconfigTimeout)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), reconfigTimeout)
|
|
|
|
defer cancel()
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
|
|
|
|
// conn is a shared connection whose lifecycle is managed by the dbus package.
|
|
|
|
// NetworkManager only lets you set DNS settings on "active"
|
|
|
|
// We should not interfere with that by closing it.
|
|
|
|
// connections, which requires an assigned IP address. This got
|
|
|
|
|
|
|
|
// configured before the DNS manager was invoked, but it might
|
|
|
|
|
|
|
|
// take a little time for the netlink notifications to propagate
|
|
|
|
|
|
|
|
// up. So, keep retrying for the duration of the reconfigTimeout.
|
|
|
|
|
|
|
|
var err error
|
|
|
|
|
|
|
|
for ctx.Err() == nil {
|
|
|
|
|
|
|
|
err = m.trySet(ctx, config)
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
time.Sleep(10 * time.Millisecond)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (m nmManager) trySet(ctx context.Context, config OSConfig) error {
|
|
|
|
conn, err := dbus.SystemBus()
|
|
|
|
conn, err := dbus.SystemBus()
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("connecting to system bus: %w", err)
|
|
|
|
return fmt.Errorf("connecting to system bus: %w", err)
|
|
|
|