mirror of
https://github.com/Control-D-Inc/ctrld.git
synced 2026-02-03 22:18:39 +00: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
@@ -80,16 +80,20 @@ func setDNS(iface *net.Interface, nameservers []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func resetDNS(iface *net.Interface) error {
|
||||
if r, err := dns.NewOSConfigurator(logf, iface.Name); err == nil {
|
||||
if err := r.Close(); err != nil {
|
||||
mainLog.Error().Err(err).Msg("failed to rollback DNS setting")
|
||||
return err
|
||||
func resetDNS(iface *net.Interface) (err error) {
|
||||
defer func() {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
if r.Mode() == "direct" {
|
||||
return nil
|
||||
if r, oerr := dns.NewOSConfigurator(logf, iface.Name); oerr == 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
|
||||
c, err := nclient4.New(iface.Name)
|
||||
|
||||
@@ -37,14 +37,45 @@ const reconfigTimeout = time.Second
|
||||
// Clients connect to the bus and walk that same hierarchy to invoke
|
||||
// RPCs, get/set properties, or listen for signals.
|
||||
const (
|
||||
dbusResolvedObject = "org.freedesktop.resolve1"
|
||||
dbusResolvedPath dbus.ObjectPath = "/org/freedesktop/resolve1"
|
||||
dbusResolvedInterface = "org.freedesktop.resolve1.Manager"
|
||||
dbusPath dbus.ObjectPath = "/org/freedesktop/DBus"
|
||||
dbusInterface = "org.freedesktop.DBus"
|
||||
dbusOwnerSignal = "NameOwnerChanged" // broadcast when a well-known name's owning process changes.
|
||||
dbusResolvedObject = "org.freedesktop.resolve1"
|
||||
dbusNetworkdObject = "org.freedesktop.network1"
|
||||
dbusResolvedPath dbus.ObjectPath = "/org/freedesktop/resolve1"
|
||||
dbusNetworkdPath dbus.ObjectPath = "/org/freedesktop/network1"
|
||||
dbusResolvedInterface = "org.freedesktop.resolve1.Manager"
|
||||
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 {
|
||||
Family int32
|
||||
Address []byte
|
||||
@@ -69,7 +100,9 @@ type resolvedManager struct {
|
||||
logf logger.Logf
|
||||
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) {
|
||||
@@ -89,6 +122,7 @@ func newResolvedManager(logf logger.Logf, interfaceName string) (*resolvedManage
|
||||
ifidx: iface.Index,
|
||||
|
||||
configCR: make(chan changeRequest),
|
||||
revertCh: make(chan struct{}),
|
||||
}
|
||||
|
||||
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) {
|
||||
var (
|
||||
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 := func() error {
|
||||
var err error
|
||||
@@ -151,7 +211,7 @@ func (m *resolvedManager) run(ctx context.Context) {
|
||||
return err
|
||||
}
|
||||
|
||||
rManager = conn.Object(dbusResolvedObject, dbus.ObjectPath(dbusResolvedPath))
|
||||
rManager = newManager(conn)
|
||||
|
||||
// Only receive the DBus signals we need to resync our config on
|
||||
// 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 {
|
||||
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)
|
||||
|
||||
// Reset backoff and SetNSOSHealth after successful on reconnect.
|
||||
@@ -179,13 +242,15 @@ func (m *resolvedManager) run(ctx context.Context) {
|
||||
if rManager == nil {
|
||||
return
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
// RevertLink resets all per-interface settings on systemd-resolved to defaults.
|
||||
// When ctx goes away systemd-resolved auto reverts.
|
||||
// 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)
|
||||
return
|
||||
}
|
||||
cancel()
|
||||
close(m.revertCh)
|
||||
return
|
||||
case configCR := <-m.configCR:
|
||||
// Track and update sync with latest config change.
|
||||
@@ -223,7 +288,7 @@ func (m *resolvedManager) run(ctx context.Context) {
|
||||
if len(signal.Body) != 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
|
||||
}
|
||||
newOwner, ok := signal.Body[2].(string)
|
||||
@@ -271,7 +336,7 @@ func (m *resolvedManager) setConfigOverDBus(ctx context.Context, rManager dbus.B
|
||||
}
|
||||
}
|
||||
err := rManager.CallWithContext(
|
||||
ctx, dbusResolvedInterface+".SetLinkDNS", 0,
|
||||
ctx, dbusSetLinkDNS, 0,
|
||||
m.ifidx, linkNameservers,
|
||||
).Store()
|
||||
if err != nil {
|
||||
@@ -311,14 +376,14 @@ func (m *resolvedManager) setConfigOverDBus(ctx context.Context, rManager dbus.B
|
||||
}
|
||||
|
||||
err = rManager.CallWithContext(
|
||||
ctx, dbusResolvedInterface+".SetLinkDomains", 0,
|
||||
ctx, dbusSetLinkDomains, 0,
|
||||
m.ifidx, linkDomains,
|
||||
).Store()
|
||||
if err != nil && err.Error() == "Argument list too long" { // TODO: better error match
|
||||
// Issue 3188: older systemd-resolved had argument length limits.
|
||||
// Trim out the *.arpa. entries and try again.
|
||||
err = rManager.CallWithContext(
|
||||
ctx, dbusResolvedInterface+".SetLinkDomains", 0,
|
||||
ctx, dbusSetLinkDomains, 0,
|
||||
m.ifidx, linkDomainsWithoutReverseDNS(linkDomains),
|
||||
).Store()
|
||||
}
|
||||
@@ -326,7 +391,7 @@ func (m *resolvedManager) setConfigOverDBus(ctx context.Context, rManager dbus.B
|
||||
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 {
|
||||
// on some older systems like Kubuntu 18.04.6 with systemd 237 method SetLinkDefaultRoute is absent,
|
||||
// but otherwise it's working good
|
||||
@@ -341,33 +406,37 @@ func (m *resolvedManager) setConfigOverDBus(ctx context.Context, rManager dbus.B
|
||||
// or something).
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// We don't support dnssec consistently right now, force it off to
|
||||
// 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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
if call := rManager.CallWithContext(ctx, dbusResolvedInterface+".FlushCaches", 0); call.Err != nil {
|
||||
m.logf("failed to flush resolved DNS cache: %v", call.Err)
|
||||
if rManager.Path() == dbusResolvedPath {
|
||||
if call := rManager.CallWithContext(ctx, dbusFlushCaches, 0); call.Err != nil {
|
||||
m.logf("failed to flush resolved DNS cache: %v", call.Err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *resolvedManager) Close() error {
|
||||
m.cancel() // stops the 'run' method goroutine
|
||||
<-m.revertCh
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user