use saved static nameservers stored for the default router interface when doing nameserver discovery

fix bad logger usages

patch darwin interface name

patch darwin interface name, debugging

make resetDNS check for static config on startup, optionally restoring static confiration as needed

fix netmon logging
This commit is contained in:
Alex
2025-02-18 15:30:02 -05:00
committed by Cuong Manh Le
parent c45f863ed8
commit eff5ff580b
8 changed files with 260 additions and 25 deletions

View File

@@ -418,7 +418,8 @@ func run(appCallback *AppCallback, stopCh chan struct{}) {
if err := p.router.Cleanup(); err != nil {
mainLog.Load().Error().Err(err).Msg("could not cleanup router")
}
p.resetDNS()
// restore static DNS settings or DHCP
p.resetDNS(false, true)
})
}
}
@@ -1030,7 +1031,8 @@ func uninstall(p *prog, s service.Service) {
mainLog.Load().Warn().Err(err).Msg("post uninstallation failed, please check system/service log for details error")
return
}
p.resetDNS()
// restore static DNS settings or DHCP
p.resetDNS(false, true)
// if present restore the original DNS settings
if netIface, err := netInterface(p.runningIface); err == nil {
@@ -1779,12 +1781,14 @@ func resetDnsNoLog(p *prog) {
if verbose < 3 {
lvl := zerolog.GlobalLevel()
zerolog.SetGlobalLevel(zerolog.Disabled)
p.resetDNS()
// This is startup so interface settings may have changed
p.resetDNS(true, true)
zerolog.SetGlobalLevel(lvl)
return
}
// For debugging purpose, still emit log.
p.resetDNS()
// This is startup so interface settings may have changed
p.resetDNS(true, true)
}
// resetDnsTask returns a task which perform reset DNS operation.
@@ -1806,10 +1810,10 @@ func resetDnsTask(p *prog, s service.Service, isCtrldInstalled bool, ir *ifaceRe
}
p.runningIface = iface
if isCtrldInstalled {
mainLog.Load().Debug().Msg("restore system DNS settings")
if status, _ := s.Status(); status == service.StatusRunning {
mainLog.Load().Fatal().Msg("reset DNS while ctrld still running is not safe")
}
mainLog.Load().Debug().Msg("Start resetDNS")
resetDnsNoLog(p)
}
iface = oldIface
@@ -1868,8 +1872,8 @@ func uninstallInvalidCdUID(p *prog, logger zerolog.Logger, doStop bool) bool {
logger.Warn().Err(err).Msg("failed to create new service")
return false
}
p.resetDNS()
// restore static DNS settings or DHCP
p.resetDNS(false, true)
tasks := []task{{s.Uninstall, true, "Uninstall"}}
if doTasks(tasks) {

View File

@@ -355,7 +355,7 @@ NOTE: running "ctrld start" without any arguments will start already installed c
}, false, "Save current DNS"},
{func() error {
return ConfigureWindowsServiceFailureActions(ctrldServiceName)
}, false, "Configure Windows service failure actions"},
}, false, "Configure service failure actions"},
{s.Start, true, "Start"},
{noticeWritingControlDConfig, false, "Notice writing ControlD config"},
}
@@ -608,7 +608,8 @@ func initStopCmd() *cobra.Command {
}
if doTasks([]task{{s.Stop, true, "Stop"}}) {
p.router.Cleanup()
p.resetDNS()
// restore static DNS settings or DHCP
p.resetDNS(false, true)
// restore DNS settings
if netIface, err := netInterface(p.runningIface); err == nil {
@@ -714,7 +715,8 @@ func initRestartCmd() *cobra.Command {
{s.Stop, true, "Stop"},
{func() error {
p.router.Cleanup()
p.resetDNS()
// restore static DNS settings or DHCP
p.resetDNS(false, true)
return nil
}, false, "Cleanup"},
{func() error {
@@ -994,13 +996,13 @@ NOTE: Uninstalling will set DNS to values provided by DHCP.`,
if os.IsNotExist(err) {
continue
}
mainLog.Load().Warn().Err(err).Msg("failed to remove file")
mainLog.Load().Warn().Err(err).Msgf("failed to remove file: %s", file)
} else {
mainLog.Load().Debug().Msgf("file removed: %s", file)
}
}
if err := selfDeleteExe(); err != nil {
mainLog.Load().Warn().Err(err).Msg("failed to remove file")
mainLog.Load().Warn().Err(err).Msg("failed to delete ctrld binary")
} else {
if !supportedSelfDelete {
mainLog.Load().Debug().Msgf("file removed: %s", bin)
@@ -1266,7 +1268,8 @@ func initUpgradeCmd() *cobra.Command {
{s.Stop, true, "Stop"},
{func() error {
p.router.Cleanup()
p.resetDNS()
// restore static DNS settings or DHCP
p.resetDNS(false, true)
return nil
}, false, "Cleanup"},
{func() error {

View File

@@ -20,7 +20,6 @@ import (
"golang.org/x/sync/errgroup"
"tailscale.com/net/netmon"
"tailscale.com/net/tsaddr"
"tailscale.com/types/logger"
"github.com/Control-D-Inc/ctrld"
"github.com/Control-D-Inc/ctrld/internal/controld"
@@ -1179,7 +1178,10 @@ func FlushDNSCache() error {
// monitorNetworkChanges starts monitoring for network interface changes
func (p *prog) monitorNetworkChanges(ctx context.Context) error {
mon, err := netmon.New(logger.WithPrefix(mainLog.Load().Printf, "netmon: "))
mon, err := netmon.New(func(format string, args ...any) {
// Always fetch the latest logger (and inject the prefix)
mainLog.Load().Printf("netmon: "+format, args...)
})
if err != nil {
return fmt.Errorf("creating network monitor: %w", err)
}
@@ -1457,7 +1459,10 @@ func (p *prog) handleRecovery(reason RecoveryReason) {
// Immediately remove our DNS settings from the interface.
// set recoveryRunning to true to prevent watchdogs from putting the listener back on the interface
p.recoveryRunning.Store(true)
p.resetDNS()
// we do not want to restore any static DNS settings
// we must try to get the DHCP values, any static DNS settings
// will be appended to nameservers from the saved interface values
p.resetDNS(false, false)
// For an OS failure, reinitialize OS resolver nameservers immediately.
if reason == RecoveryReasonOSFailure {

View File

@@ -268,7 +268,7 @@ func (p *prog) preRun() {
if runtime.GOOS == "darwin" {
p.onStopped = append(p.onStopped, func() {
if !service.Interactive() {
p.resetDNS()
p.resetDNS(false, true)
}
})
}
@@ -276,7 +276,7 @@ func (p *prog) preRun() {
func (p *prog) postRun() {
if !service.Interactive() {
p.resetDNS()
p.resetDNS(false, true)
ns := ctrld.InitializeOsResolver(false)
mainLog.Load().Debug().Msgf("initialized OS resolver with nameservers: %v", ns)
p.setDNS()
@@ -809,7 +809,13 @@ func (p *prog) dnsWatchdog(iface *net.Interface, nameservers []string, allIfaces
}
}
func (p *prog) resetDNS() {
// resetDNS performs a DNS reset on the running interface.
// The parameter isStart indicates whether this is being called as part of a start (or restart)
// command. When true, we check if the current static DNS configuration already differs from the
// service listener (127.0.0.1). If so, we assume that an admin has manually changed the interface's
// static DNS settings and we do not override them using the potentially out-of-date saved file.
// Otherwise, we restore the saved configuration (if any) or reset to DHCP.
func (p *prog) resetDNS(isStart bool, restoreStatic bool) {
if p.runningIface == "" {
mainLog.Load().Debug().Msg("no running interface, skipping resetDNS")
return
@@ -822,17 +828,47 @@ func (p *prog) resetDNS() {
logger.Error().Err(err).Msg("could not get interface")
return
}
if err := restoreNetworkManager(); err != nil {
logger.Error().Err(err).Msg("could not restore NetworkManager")
return
}
logger.Debug().Msg("Restoring DNS for interface")
if err := resetDNS(netIface); err != nil {
logger.Error().Err(err).Msgf("could not reset DNS")
return
// If starting, check the current static DNS configuration.
if isStart {
current, err := currentStaticDNS(netIface)
if err != nil {
logger.Warn().Err(err).Msg("unable to obtain current static DNS configuration; proceeding to restore saved config")
} else if len(current) > 0 {
// If any static DNS value is not our own listener, assume an admin override.
hasManualConfig := false
for _, ns := range current {
if ns != "127.0.0.1" {
hasManualConfig = true
break
}
}
if hasManualConfig {
logger.Debug().Msgf("Detected manual DNS configuration on interface %q: %v; not overriding with saved configuration", netIface.Name, current)
return
}
}
}
// Default logic: if there is a saved static DNS configuration, restore it.
saved := savedStaticNameservers(netIface)
if len(saved) > 0 && restoreStatic {
logger.Debug().Msgf("Restoring interface %q from saved static config: %v", netIface.Name, saved)
if err := setDNS(netIface, saved); err != nil {
logger.Error().Err(err).Msgf("failed to restore static DNS config on interface %q", netIface.Name)
return
}
} else {
logger.Debug().Msgf("No saved static DNS config for interface %q; resetting to DHCP", netIface.Name)
if err := resetDNS(netIface); err != nil {
logger.Error().Err(err).Msgf("failed to reset DNS to DHCP on interface %q", netIface.Name)
return
}
}
logger.Debug().Msg("Restoring DNS successfully")
if allIfaces {
withEachPhysicalInterfaces(netIface.Name, "reset DNS", resetDnsIgnoreUnusableInterface)
}