mirror of
https://github.com/Control-D-Inc/ctrld.git
synced 2026-07-04 01:07:49 +02:00
cmd/ctrld,internal/dns: support systemd-networkd dbus
For interface managed by systemd-networkd, systemd-resolved can not reset DNS. To fix this, attempting to check before the run loop and set the suitable manager for the system. Updates #55
This commit is contained in:
committed by
Cuong Manh Le
parent
e385547461
commit
997ec342e0
+12
-8
@@ -80,16 +80,20 @@ func setDNS(iface *net.Interface, nameservers []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func resetDNS(iface *net.Interface) error {
|
func resetDNS(iface *net.Interface) (err error) {
|
||||||
if r, err := dns.NewOSConfigurator(logf, iface.Name); err == nil {
|
defer func() {
|
||||||
if err := r.Close(); err != nil {
|
if err == nil {
|
||||||
mainLog.Error().Err(err).Msg("failed to rollback DNS setting")
|
return
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
if r.Mode() == "direct" {
|
if r, oerr := dns.NewOSConfigurator(logf, iface.Name); oerr == nil {
|
||||||
return nil
|
_ = r.SetDNS(dns.OSConfig{})
|
||||||
|
if err := r.Close(); err != nil {
|
||||||
|
mainLog.Error().Err(err).Msg("failed to rollback DNS setting")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = nil
|
||||||
}
|
}
|
||||||
}
|
}()
|
||||||
|
|
||||||
var ns []string
|
var ns []string
|
||||||
c, err := nclient4.New(iface.Name)
|
c, err := nclient4.New(iface.Name)
|
||||||
|
|||||||
+90
-21
@@ -37,14 +37,45 @@ const reconfigTimeout = time.Second
|
|||||||
// Clients connect to the bus and walk that same hierarchy to invoke
|
// Clients connect to the bus and walk that same hierarchy to invoke
|
||||||
// RPCs, get/set properties, or listen for signals.
|
// RPCs, get/set properties, or listen for signals.
|
||||||
const (
|
const (
|
||||||
dbusResolvedObject = "org.freedesktop.resolve1"
|
dbusResolvedObject = "org.freedesktop.resolve1"
|
||||||
dbusResolvedPath dbus.ObjectPath = "/org/freedesktop/resolve1"
|
dbusNetworkdObject = "org.freedesktop.network1"
|
||||||
dbusResolvedInterface = "org.freedesktop.resolve1.Manager"
|
dbusResolvedPath dbus.ObjectPath = "/org/freedesktop/resolve1"
|
||||||
dbusPath dbus.ObjectPath = "/org/freedesktop/DBus"
|
dbusNetworkdPath dbus.ObjectPath = "/org/freedesktop/network1"
|
||||||
dbusInterface = "org.freedesktop.DBus"
|
dbusResolvedInterface = "org.freedesktop.resolve1.Manager"
|
||||||
dbusOwnerSignal = "NameOwnerChanged" // broadcast when a well-known name's owning process changes.
|
dbusNetworkdInterface = "org.freedesktop.network1.Manager"
|
||||||
|
dbusPath dbus.ObjectPath = "/org/freedesktop/DBus"
|
||||||
|
dbusInterface = "org.freedesktop.DBus"
|
||||||
|
dbusOwnerSignal = "NameOwnerChanged" // broadcast when a well-known name's owning process changes.
|
||||||
|
dbusResolvedErrorLinkBusy = "org.freedesktop.resolve1.LinkBusy"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
dbusSetLinkDNS string
|
||||||
|
dbusSetLinkDomains string
|
||||||
|
dbusSetLinkDefaultRoute string
|
||||||
|
dbusSetLinkLLMNR string
|
||||||
|
dbusSetLinkMulticastDNS string
|
||||||
|
dbusSetLinkDNSSEC string
|
||||||
|
dbusSetLinkDNSOverTLS string
|
||||||
|
dbusFlushCaches string
|
||||||
|
dbusRevertLink string
|
||||||
|
)
|
||||||
|
|
||||||
|
func setDbusMethods(dbusInterface string) {
|
||||||
|
dbusSetLinkDNS = dbusInterface + ".SetLinkDNS"
|
||||||
|
dbusSetLinkDomains = dbusInterface + ".SetLinkDomains"
|
||||||
|
dbusSetLinkDefaultRoute = dbusInterface + ".SetLinkDefaultRoute"
|
||||||
|
dbusSetLinkLLMNR = dbusInterface + ".SetLinkLLMNR"
|
||||||
|
dbusSetLinkMulticastDNS = dbusInterface + ".SetLinkMulticastDNS"
|
||||||
|
dbusSetLinkDNSSEC = dbusInterface + ".SetLinkDNSSEC"
|
||||||
|
dbusSetLinkDNSOverTLS = dbusInterface + ".SetLinkDNSOverTLS"
|
||||||
|
dbusFlushCaches = dbusInterface + ".FlushCaches"
|
||||||
|
dbusRevertLink = dbusInterface + ".RevertLink"
|
||||||
|
if dbusInterface == dbusNetworkdInterface {
|
||||||
|
dbusRevertLink = dbusInterface + ".RevertLinkDNS"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type resolvedLinkNameserver struct {
|
type resolvedLinkNameserver struct {
|
||||||
Family int32
|
Family int32
|
||||||
Address []byte
|
Address []byte
|
||||||
@@ -69,7 +100,9 @@ type resolvedManager struct {
|
|||||||
logf logger.Logf
|
logf logger.Logf
|
||||||
ifidx int
|
ifidx int
|
||||||
|
|
||||||
configCR chan changeRequest // tracks OSConfigs changes and error responses
|
configCR chan changeRequest // tracks OSConfigs changes and error responses
|
||||||
|
revertCh chan struct{}
|
||||||
|
newManager func(conn *dbus.Conn) dbus.BusObject
|
||||||
}
|
}
|
||||||
|
|
||||||
func newResolvedManager(logf logger.Logf, interfaceName string) (*resolvedManager, error) {
|
func newResolvedManager(logf logger.Logf, interfaceName string) (*resolvedManager, error) {
|
||||||
@@ -89,6 +122,7 @@ func newResolvedManager(logf logger.Logf, interfaceName string) (*resolvedManage
|
|||||||
ifidx: iface.Index,
|
ifidx: iface.Index,
|
||||||
|
|
||||||
configCR: make(chan changeRequest),
|
configCR: make(chan changeRequest),
|
||||||
|
revertCh: make(chan struct{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
go mgr.run(ctx)
|
go mgr.run(ctx)
|
||||||
@@ -117,6 +151,16 @@ func (m *resolvedManager) SetDNS(config OSConfig) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newResolvedObject(conn *dbus.Conn) dbus.BusObject {
|
||||||
|
setDbusMethods(dbusResolvedInterface)
|
||||||
|
return conn.Object(dbusResolvedObject, dbusResolvedPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newNetworkdObject(conn *dbus.Conn) dbus.BusObject {
|
||||||
|
setDbusMethods(dbusNetworkdInterface)
|
||||||
|
return conn.Object(dbusNetworkdObject, dbusNetworkdPath)
|
||||||
|
}
|
||||||
|
|
||||||
func (m *resolvedManager) run(ctx context.Context) {
|
func (m *resolvedManager) run(ctx context.Context) {
|
||||||
var (
|
var (
|
||||||
conn *dbus.Conn
|
conn *dbus.Conn
|
||||||
@@ -131,6 +175,22 @@ func (m *resolvedManager) run(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
newManager := newResolvedObject
|
||||||
|
func() {
|
||||||
|
conn, err := dbus.SystemBus()
|
||||||
|
if err != nil {
|
||||||
|
m.logf("dbus connection error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rManager = newManager(conn)
|
||||||
|
if call := rManager.CallWithContext(ctx, dbusRevertLink, 0, m.ifidx); call.Err != nil {
|
||||||
|
if dbusErr, ok := call.Err.(dbus.Error); ok && dbusErr.Name == dbusResolvedErrorLinkBusy {
|
||||||
|
m.logf("[v1] Using %s as manager", dbusNetworkdObject)
|
||||||
|
newManager = newNetworkdObject
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
// Reconnect the systemBus if disconnected.
|
// Reconnect the systemBus if disconnected.
|
||||||
reconnect := func() error {
|
reconnect := func() error {
|
||||||
var err error
|
var err error
|
||||||
@@ -151,7 +211,7 @@ func (m *resolvedManager) run(ctx context.Context) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
rManager = conn.Object(dbusResolvedObject, dbus.ObjectPath(dbusResolvedPath))
|
rManager = newManager(conn)
|
||||||
|
|
||||||
// Only receive the DBus signals we need to resync our config on
|
// Only receive the DBus signals we need to resync our config on
|
||||||
// resolved restart. Failure to set filters isn't a fatal error,
|
// resolved restart. Failure to set filters isn't a fatal error,
|
||||||
@@ -160,6 +220,9 @@ func (m *resolvedManager) run(ctx context.Context) {
|
|||||||
if err = conn.AddMatchSignal(dbus.WithMatchObjectPath(dbusPath), dbus.WithMatchInterface(dbusInterface), dbus.WithMatchMember(dbusOwnerSignal), dbus.WithMatchArg(0, dbusResolvedObject)); err != nil {
|
if err = conn.AddMatchSignal(dbus.WithMatchObjectPath(dbusPath), dbus.WithMatchInterface(dbusInterface), dbus.WithMatchMember(dbusOwnerSignal), dbus.WithMatchArg(0, dbusResolvedObject)); err != nil {
|
||||||
m.logf("[v1] Setting DBus signal filter failed: %v", err)
|
m.logf("[v1] Setting DBus signal filter failed: %v", err)
|
||||||
}
|
}
|
||||||
|
if err = conn.AddMatchSignal(dbus.WithMatchObjectPath(dbusPath), dbus.WithMatchInterface(dbusInterface), dbus.WithMatchMember(dbusOwnerSignal), dbus.WithMatchArg(0, dbusNetworkdObject)); err != nil {
|
||||||
|
m.logf("[v1] Setting DBus signal filter failed: %v", err)
|
||||||
|
}
|
||||||
conn.Signal(signals)
|
conn.Signal(signals)
|
||||||
|
|
||||||
// Reset backoff and SetNSOSHealth after successful on reconnect.
|
// Reset backoff and SetNSOSHealth after successful on reconnect.
|
||||||
@@ -179,13 +242,15 @@ func (m *resolvedManager) run(ctx context.Context) {
|
|||||||
if rManager == nil {
|
if rManager == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
// RevertLink resets all per-interface settings on systemd-resolved to defaults.
|
// RevertLink resets all per-interface settings on systemd-resolved to defaults.
|
||||||
// When ctx goes away systemd-resolved auto reverts.
|
// When ctx goes away systemd-resolved auto reverts.
|
||||||
// Keeping for potential use in future refactor.
|
// Keeping for potential use in future refactor.
|
||||||
if call := rManager.CallWithContext(ctx, dbusResolvedInterface+".RevertLink", 0, m.ifidx); call.Err != nil {
|
if call := rManager.CallWithContext(ctx, dbusRevertLink, 0, m.ifidx); call.Err != nil {
|
||||||
m.logf("[v1] RevertLink: %v", call.Err)
|
m.logf("[v1] RevertLink: %v", call.Err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
cancel()
|
||||||
|
close(m.revertCh)
|
||||||
return
|
return
|
||||||
case configCR := <-m.configCR:
|
case configCR := <-m.configCR:
|
||||||
// Track and update sync with latest config change.
|
// Track and update sync with latest config change.
|
||||||
@@ -223,7 +288,7 @@ func (m *resolvedManager) run(ctx context.Context) {
|
|||||||
if len(signal.Body) != 3 {
|
if len(signal.Body) != 3 {
|
||||||
m.logf("[unexpected] DBus NameOwnerChanged len(Body) = %d, want 3")
|
m.logf("[unexpected] DBus NameOwnerChanged len(Body) = %d, want 3")
|
||||||
}
|
}
|
||||||
if name, ok := signal.Body[0].(string); !ok || name != dbusResolvedObject {
|
if name, ok := signal.Body[0].(string); !ok || (name != dbusResolvedObject && name != dbusNetworkdObject) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
newOwner, ok := signal.Body[2].(string)
|
newOwner, ok := signal.Body[2].(string)
|
||||||
@@ -271,7 +336,7 @@ func (m *resolvedManager) setConfigOverDBus(ctx context.Context, rManager dbus.B
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
err := rManager.CallWithContext(
|
err := rManager.CallWithContext(
|
||||||
ctx, dbusResolvedInterface+".SetLinkDNS", 0,
|
ctx, dbusSetLinkDNS, 0,
|
||||||
m.ifidx, linkNameservers,
|
m.ifidx, linkNameservers,
|
||||||
).Store()
|
).Store()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -311,14 +376,14 @@ func (m *resolvedManager) setConfigOverDBus(ctx context.Context, rManager dbus.B
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = rManager.CallWithContext(
|
err = rManager.CallWithContext(
|
||||||
ctx, dbusResolvedInterface+".SetLinkDomains", 0,
|
ctx, dbusSetLinkDomains, 0,
|
||||||
m.ifidx, linkDomains,
|
m.ifidx, linkDomains,
|
||||||
).Store()
|
).Store()
|
||||||
if err != nil && err.Error() == "Argument list too long" { // TODO: better error match
|
if err != nil && err.Error() == "Argument list too long" { // TODO: better error match
|
||||||
// Issue 3188: older systemd-resolved had argument length limits.
|
// Issue 3188: older systemd-resolved had argument length limits.
|
||||||
// Trim out the *.arpa. entries and try again.
|
// Trim out the *.arpa. entries and try again.
|
||||||
err = rManager.CallWithContext(
|
err = rManager.CallWithContext(
|
||||||
ctx, dbusResolvedInterface+".SetLinkDomains", 0,
|
ctx, dbusSetLinkDomains, 0,
|
||||||
m.ifidx, linkDomainsWithoutReverseDNS(linkDomains),
|
m.ifidx, linkDomainsWithoutReverseDNS(linkDomains),
|
||||||
).Store()
|
).Store()
|
||||||
}
|
}
|
||||||
@@ -326,7 +391,7 @@ func (m *resolvedManager) setConfigOverDBus(ctx context.Context, rManager dbus.B
|
|||||||
return fmt.Errorf("setLinkDomains: %w", err)
|
return fmt.Errorf("setLinkDomains: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if call := rManager.CallWithContext(ctx, dbusResolvedInterface+".SetLinkDefaultRoute", 0, m.ifidx, len(config.MatchDomains) == 0); call.Err != nil {
|
if call := rManager.CallWithContext(ctx, dbusSetLinkDefaultRoute, 0, m.ifidx, len(config.MatchDomains) == 0); call.Err != nil {
|
||||||
if dbusErr, ok := call.Err.(dbus.Error); ok && dbusErr.Name == dbus.ErrMsgUnknownMethod.Name {
|
if dbusErr, ok := call.Err.(dbus.Error); ok && dbusErr.Name == dbus.ErrMsgUnknownMethod.Name {
|
||||||
// on some older systems like Kubuntu 18.04.6 with systemd 237 method SetLinkDefaultRoute is absent,
|
// on some older systems like Kubuntu 18.04.6 with systemd 237 method SetLinkDefaultRoute is absent,
|
||||||
// but otherwise it's working good
|
// but otherwise it's working good
|
||||||
@@ -341,33 +406,37 @@ func (m *resolvedManager) setConfigOverDBus(ctx context.Context, rManager dbus.B
|
|||||||
// or something).
|
// or something).
|
||||||
|
|
||||||
// Disable LLMNR, we don't do multicast.
|
// Disable LLMNR, we don't do multicast.
|
||||||
if call := rManager.CallWithContext(ctx, dbusResolvedInterface+".SetLinkLLMNR", 0, m.ifidx, "no"); call.Err != nil {
|
if call := rManager.CallWithContext(ctx, dbusSetLinkLLMNR, 0, m.ifidx, "no"); call.Err != nil {
|
||||||
m.logf("[v1] failed to disable LLMNR: %v", call.Err)
|
m.logf("[v1] failed to disable LLMNR: %v", call.Err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable mdns.
|
// Disable mdns.
|
||||||
if call := rManager.CallWithContext(ctx, dbusResolvedInterface+".SetLinkMulticastDNS", 0, m.ifidx, "no"); call.Err != nil {
|
if call := rManager.CallWithContext(ctx, dbusSetLinkMulticastDNS, 0, m.ifidx, "no"); call.Err != nil {
|
||||||
m.logf("[v1] failed to disable mdns: %v", call.Err)
|
m.logf("[v1] failed to disable mdns: %v", call.Err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't support dnssec consistently right now, force it off to
|
// We don't support dnssec consistently right now, force it off to
|
||||||
// avoid partial failures when we split DNS internally.
|
// avoid partial failures when we split DNS internally.
|
||||||
if call := rManager.CallWithContext(ctx, dbusResolvedInterface+".SetLinkDNSSEC", 0, m.ifidx, "no"); call.Err != nil {
|
if call := rManager.CallWithContext(ctx, dbusSetLinkDNSSEC, 0, m.ifidx, "no"); call.Err != nil {
|
||||||
m.logf("[v1] failed to disable DNSSEC: %v", call.Err)
|
m.logf("[v1] failed to disable DNSSEC: %v", call.Err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if call := rManager.CallWithContext(ctx, dbusResolvedInterface+".SetLinkDNSOverTLS", 0, m.ifidx, "no"); call.Err != nil {
|
if call := rManager.CallWithContext(ctx, dbusSetLinkDNSOverTLS, 0, m.ifidx, "no"); call.Err != nil {
|
||||||
m.logf("[v1] failed to disable DoT: %v", call.Err)
|
m.logf("[v1] failed to disable DoT: %v", call.Err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if call := rManager.CallWithContext(ctx, dbusResolvedInterface+".FlushCaches", 0); call.Err != nil {
|
if rManager.Path() == dbusResolvedPath {
|
||||||
m.logf("failed to flush resolved DNS cache: %v", call.Err)
|
if call := rManager.CallWithContext(ctx, dbusFlushCaches, 0); call.Err != nil {
|
||||||
|
m.logf("failed to flush resolved DNS cache: %v", call.Err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *resolvedManager) Close() error {
|
func (m *resolvedManager) Close() error {
|
||||||
m.cancel() // stops the 'run' method goroutine
|
m.cancel() // stops the 'run' method goroutine
|
||||||
|
<-m.revertCh
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user