mirror of
https://github.com/fosrl/olm.git
synced 2026-07-19 22:31:26 +02:00
Also check network manager on linux
This commit is contained in:
@@ -16,12 +16,18 @@ import (
|
||||
|
||||
const (
|
||||
// NetworkManager D-Bus constants
|
||||
networkManagerDest = "org.freedesktop.NetworkManager"
|
||||
networkManagerDbusObjectNode = "/org/freedesktop/NetworkManager"
|
||||
networkManagerDbusDNSManagerInterface = "org.freedesktop.NetworkManager.DnsManager"
|
||||
networkManagerDbusDNSManagerObjectNode = networkManagerDbusObjectNode + "/DnsManager"
|
||||
networkManagerDbusDNSManagerModeProperty = networkManagerDbusDNSManagerInterface + ".Mode"
|
||||
networkManagerDbusVersionProperty = "org.freedesktop.NetworkManager.Version"
|
||||
networkManagerDest = "org.freedesktop.NetworkManager"
|
||||
networkManagerDbusObjectNode = "/org/freedesktop/NetworkManager"
|
||||
networkManagerDbusDNSManagerInterface = "org.freedesktop.NetworkManager.DnsManager"
|
||||
networkManagerDbusDNSManagerObjectNode = networkManagerDbusObjectNode + "/DnsManager"
|
||||
networkManagerDbusDNSManagerModeProperty = networkManagerDbusDNSManagerInterface + ".Mode"
|
||||
networkManagerDbusVersionProperty = "org.freedesktop.NetworkManager.Version"
|
||||
networkManagerDbusActiveConnsProperty = networkManagerDest + ".ActiveConnections"
|
||||
networkManagerDbusActiveInterface = "org.freedesktop.NetworkManager.Connection.Active"
|
||||
networkManagerDbusActiveIP4ConfigProperty = networkManagerDbusActiveInterface + ".Ip4Config"
|
||||
networkManagerDbusActiveIP6ConfigProperty = networkManagerDbusActiveInterface + ".Ip6Config"
|
||||
networkManagerDbusIP4ConfigInterface = "org.freedesktop.NetworkManager.IP4Config"
|
||||
networkManagerDbusIP6ConfigInterface = "org.freedesktop.NetworkManager.IP6Config"
|
||||
|
||||
// NetworkManager dispatcher script path
|
||||
networkManagerDispatcherDir = "/etc/NetworkManager/dispatcher.d"
|
||||
@@ -301,6 +307,89 @@ func GetNetworkManagerDNSMode() (string, error) {
|
||||
return mode, nil
|
||||
}
|
||||
|
||||
// GetNetworkManagerNameservers returns the DNS servers NetworkManager has
|
||||
// computed for every active connection, read live via D-Bus from each
|
||||
// connection's IP4Config/IP6Config NameserverData property.
|
||||
//
|
||||
// Unlike reading /etc/resolv.conf, this reflects NetworkManager's own view of
|
||||
// DNS regardless of its DnsManager.Mode: in "dnsmasq" or "unbound" mode
|
||||
// /etc/resolv.conf only contains a loopback stub address pointing at
|
||||
// NetworkManager's local resolver, not the real upstream servers, and even in
|
||||
// "default" mode this stays live and unaffected if something else (such as
|
||||
// olm's own override) has since overwritten /etc/resolv.conf directly instead
|
||||
// of going through NetworkManager.
|
||||
func GetNetworkManagerNameservers() ([]netip.Addr, error) {
|
||||
conn, err := dbus.SystemBus()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("connect to system bus: %w", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
nm := conn.Object(networkManagerDest, networkManagerDbusObjectNode)
|
||||
|
||||
activeVariant, err := nm.GetProperty(networkManagerDbusActiveConnsProperty)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get active connections: %w", err)
|
||||
}
|
||||
activePaths, ok := activeVariant.Value().([]dbus.ObjectPath)
|
||||
if !ok {
|
||||
return nil, errors.New("ActiveConnections is not a list of object paths")
|
||||
}
|
||||
|
||||
ipConfigSources := []struct {
|
||||
activeProperty string
|
||||
configIface string
|
||||
}{
|
||||
{networkManagerDbusActiveIP4ConfigProperty, networkManagerDbusIP4ConfigInterface},
|
||||
{networkManagerDbusActiveIP6ConfigProperty, networkManagerDbusIP6ConfigInterface},
|
||||
}
|
||||
|
||||
seen := make(map[netip.Addr]bool)
|
||||
var servers []netip.Addr
|
||||
for _, activePath := range activePaths {
|
||||
active := conn.Object(networkManagerDest, activePath)
|
||||
for _, src := range ipConfigSources {
|
||||
cfgVariant, err := active.GetProperty(src.activeProperty)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
cfgPath, ok := cfgVariant.Value().(dbus.ObjectPath)
|
||||
if !ok || cfgPath == "" || cfgPath == "/" {
|
||||
continue
|
||||
}
|
||||
|
||||
nsVariant, err := conn.Object(networkManagerDest, cfgPath).GetProperty(src.configIface + ".NameserverData")
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
entries, ok := nsVariant.Value().([]map[string]dbus.Variant)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
for _, entry := range entries {
|
||||
addrVariant, ok := entry["address"]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
addrStr, ok := addrVariant.Value().(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
addr, err := netip.ParseAddr(addrStr)
|
||||
if err != nil || addr.IsLoopback() || addr.IsLinkLocalUnicast() {
|
||||
continue
|
||||
}
|
||||
if !seen[addr] {
|
||||
seen[addr] = true
|
||||
servers = append(servers, addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return servers, nil
|
||||
}
|
||||
|
||||
// GetNetworkManagerVersion returns the version of NetworkManager
|
||||
func GetNetworkManagerVersion() (string, error) {
|
||||
conn, err := dbus.SystemBus()
|
||||
|
||||
@@ -8,6 +8,8 @@ import (
|
||||
"net/netip"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
platform "github.com/fosrl/olm/dns/platform"
|
||||
)
|
||||
|
||||
// readSystemDNS returns the current system DNS servers in "host:53" format.
|
||||
@@ -16,9 +18,18 @@ import (
|
||||
// 1. /run/systemd/resolve/resolv.conf — maintained by systemd-resolved with
|
||||
// the real per-link DNS servers; updated on every DHCP change and never
|
||||
// touched by olm's D-Bus DNS override.
|
||||
// 2. /etc/resolv.conf.olm.backup — written by olm before it overrides
|
||||
// /etc/resolv.conf on non-systemd systems.
|
||||
// 3. /etc/resolv.conf — plain fallback.
|
||||
// 2. NetworkManager, queried live over D-Bus — NetworkManager's own view of
|
||||
// each active connection's DNS servers, independent of what is currently
|
||||
// written to /etc/resolv.conf. This covers NetworkManager's "dnsmasq" and
|
||||
// "unbound" DNS modes, where /etc/resolv.conf only contains a loopback
|
||||
// stub address, and stays accurate even if olm's own override has
|
||||
// directly overwritten /etc/resolv.conf, without going stale the way a
|
||||
// one-time backup snapshot would if the real DNS changes mid-override
|
||||
// (e.g. the user switches WiFi networks).
|
||||
// 3. /etc/resolv.conf.olm.backup — written by olm before it overrides
|
||||
// /etc/resolv.conf on non-systemd systems, for when NetworkManager isn't
|
||||
// in use at all.
|
||||
// 4. /etc/resolv.conf — plain fallback.
|
||||
//
|
||||
// Loopback and link-local addresses (e.g. 127.0.0.53, ::1) are excluded
|
||||
// because they are stub resolver addresses, not real upstream servers.
|
||||
@@ -28,6 +39,10 @@ func readSystemDNS() []string {
|
||||
return servers
|
||||
}
|
||||
|
||||
if servers := readNetworkManagerDNS(); len(servers) > 0 {
|
||||
return servers
|
||||
}
|
||||
|
||||
// If olm has already overridden /etc/resolv.conf the backup holds the
|
||||
// original pre-override DNS servers.
|
||||
if _, err := os.Stat("/etc/resolv.conf.olm.backup"); err == nil {
|
||||
@@ -39,6 +54,22 @@ func readSystemDNS() []string {
|
||||
return parseResolvConf("/etc/resolv.conf")
|
||||
}
|
||||
|
||||
// readNetworkManagerDNS returns the DNS servers NetworkManager reports over
|
||||
// D-Bus for its active connections, in "host:53" format. Returns nil if
|
||||
// NetworkManager isn't running or reports nothing usable.
|
||||
func readNetworkManagerDNS() []string {
|
||||
addrs, err := platform.GetNetworkManagerNameservers()
|
||||
if err != nil || len(addrs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
result := make([]string, 0, len(addrs))
|
||||
for _, addr := range addrs {
|
||||
result = append(result, addrToHostPort(addr))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// parseResolvConf reads nameserver lines from a resolv.conf-style file,
|
||||
// skipping loopback and link-local addresses.
|
||||
func parseResolvConf(path string) []string {
|
||||
|
||||
Reference in New Issue
Block a user