feat: capitalize all log messages for better readability

Capitalize the first letter of all log messages throughout the codebase
to improve readability and consistency in logging output.

Key improvements:
- All log messages now start with capital letters
- Consistent formatting across all logging statements
- Improved readability for debugging and monitoring
- Enhanced user experience with better formatted messages

Files updated:
- CLI commands and service management
- Internal client information discovery
- Network operations and configuration
- DNS resolver and proxy operations
- Platform-specific implementations

This completes the final phase of the logging improvement project,
ensuring all log messages follow consistent capitalization standards
for better readability and professional appearance.
This commit is contained in:
Cuong Manh Le
2025-09-04 15:46:37 +07:00
committed by Cuong Manh Le
parent 166b7f38fc
commit d3b01dc7e8
45 changed files with 391 additions and 389 deletions
+4 -4
View File
@@ -16,11 +16,11 @@ import (
func addExtraSplitDnsRule(cfg *ctrld.Config) bool { func addExtraSplitDnsRule(cfg *ctrld.Config) bool {
domain, err := getActiveDirectoryDomain() domain, err := getActiveDirectoryDomain()
if err != nil { if err != nil {
mainLog.Load().Debug().Msgf("unable to get active directory domain: %v", err) mainLog.Load().Debug().Msgf("Unable to get active directory domain: %v", err)
return false return false
} }
if domain == "" { if domain == "" {
mainLog.Load().Debug().Msg("no active directory domain found") mainLog.Load().Debug().Msg("No active directory domain found")
return false return false
} }
// Network rules are lowercase during toml config marshaling, // Network rules are lowercase during toml config marshaling,
@@ -40,11 +40,11 @@ func addSplitDnsRule(cfg *ctrld.Config, domain string) bool {
} }
for _, rule := range lc.Policy.Rules { for _, rule := range lc.Policy.Rules {
if _, ok := rule[domain]; ok { if _, ok := rule[domain]; ok {
mainLog.Load().Debug().Msgf("split-rule %q already existed for listener.%s", domain, n) mainLog.Load().Debug().Msgf("Split-rule %q already existed for listener.%s", domain, n)
return false return false
} }
} }
mainLog.Load().Debug().Msgf("adding split-rule %q for listener.%s", domain, n) mainLog.Load().Debug().Msgf("Adding split-rule %q for listener.%s", domain, n)
lc.Policy.Rules = append(lc.Policy.Rules, ctrld.Rule{domain: []string{}}) lc.Policy.Rules = append(lc.Policy.Rules, ctrld.Rule{domain: []string{}})
} }
return true return true
+68 -67
View File
@@ -241,11 +241,11 @@ func run(appCallback *AppCallback, stopCh chan struct{}) {
p.logConn = lc p.logConn = lc
} else { } else {
if !errors.Is(err, os.ErrNotExist) { if !errors.Is(err, os.ErrNotExist) {
p.Warn().Err(err).Msg("unable to create log ipc connection") p.Warn().Err(err).Msg("Unable to create log ipc connection")
} }
} }
} else { } else {
p.Warn().Err(err).Msgf("unable to resolve socket address: %s", sockPath) p.Warn().Err(err).Msgf("Unable to resolve socket address: %s", sockPath)
} }
notifyExitToLogServer := func() { notifyExitToLogServer := func() {
if p.logConn != nil { if p.logConn != nil {
@@ -265,10 +265,10 @@ func run(appCallback *AppCallback, stopCh chan struct{}) {
svcConfig := svcCmd.createServiceConfig() svcConfig := svcCmd.createServiceConfig()
s, err := svcCmd.newService(p, svcConfig) s, err := svcCmd.newService(p, svcConfig)
if err != nil { if err != nil {
p.Fatal().Err(err).Msg("failed create new service") p.Fatal().Err(err).Msg("Failed to create new service")
} }
if err := s.Run(); err != nil { if err := s.Run(); err != nil {
p.Error().Err(err).Msg("failed to start service") p.Error().Err(err).Msg("Failed to start service")
} }
}() }()
} }
@@ -276,7 +276,7 @@ func run(appCallback *AppCallback, stopCh chan struct{}) {
tryReadingConfig(writeDefaultConfig) tryReadingConfig(writeDefaultConfig)
if err := readBase64Config(configBase64); err != nil { if err := readBase64Config(configBase64); err != nil {
p.Fatal().Err(err).Msg("failed to read base64 config") p.Fatal().Err(err).Msg("Failed to read base64 config")
} }
processNoConfigFlags(noConfigStart) processNoConfigFlags(noConfigStart)
@@ -285,7 +285,7 @@ func run(appCallback *AppCallback, stopCh chan struct{}) {
p.mu.Lock() p.mu.Lock()
if err := v.Unmarshal(&cfg); err != nil { if err := v.Unmarshal(&cfg); err != nil {
notifyExitToLogServer() notifyExitToLogServer()
p.Fatal().Msgf("failed to unmarshal config: %v", err) p.Fatal().Msgf("Failed to unmarshal config: %v", err)
} }
p.mu.Unlock() p.mu.Unlock()
@@ -295,18 +295,18 @@ func run(appCallback *AppCallback, stopCh chan struct{}) {
// so it's able to log information in processCDFlags. // so it's able to log information in processCDFlags.
p.initLogging(true) p.initLogging(true)
p.Info().Msgf("starting ctrld %s", curVersion()) p.Info().Msgf("Starting ctrld %s", curVersion())
p.Info().Msgf("os: %s", osVersion()) p.Info().Msgf("OS: %s", osVersion())
// Wait for network up. // Wait for network up.
if !ctrldnet.Up() { if !ctrldnet.Up() {
notifyExitToLogServer() notifyExitToLogServer()
p.Fatal().Msg("network is not up yet") p.Fatal().Msg("Network is not up yet")
} }
cs, err := newControlServer(filepath.Join(sockDir, ControlSocketName())) cs, err := newControlServer(filepath.Join(sockDir, ControlSocketName()))
if err != nil { if err != nil {
p.Warn().Err(err).Msg("could not create control server") p.Warn().Err(err).Msg("Could not create control server")
} }
p.cs = cs p.cs = cs
@@ -329,7 +329,7 @@ func run(appCallback *AppCallback, stopCh chan struct{}) {
_ = uninstallInvalidCdUID(p, cdLogger, false) _ = uninstallInvalidCdUID(p, cdLogger, false)
} }
notifyExitToLogServer() notifyExitToLogServer()
cdLogger.Fatal().Err(err).Msg("failed to fetch resolver config") cdLogger.Fatal().Err(err).Msg("Failed to fetch resolver config")
} else { } else {
p.mu.Lock() p.mu.Lock()
p.rc = rc p.rc = rc
@@ -346,9 +346,9 @@ func run(appCallback *AppCallback, stopCh chan struct{}) {
if updated { if updated {
if err := writeConfigFile(&cfg); err != nil { if err := writeConfigFile(&cfg); err != nil {
notifyExitToLogServer() notifyExitToLogServer()
p.Fatal().Err(err).Msg("failed to write config file") p.Fatal().Err(err).Msg("Failed to write config file")
} else { } else {
p.Info().Msg("writing config file to: " + defaultConfigFile) p.Info().Msg("Writing config file to: " + defaultConfigFile)
} }
} }
@@ -360,7 +360,7 @@ func run(appCallback *AppCallback, stopCh chan struct{}) {
// Copy logs written so far to new log file if possible. // Copy logs written so far to new log file if possible.
if buf, err := os.ReadFile(oldLogPath); err == nil { if buf, err := os.ReadFile(oldLogPath); err == nil {
if err := os.WriteFile(newLogPath, buf, os.FileMode(0o600)); err != nil { if err := os.WriteFile(newLogPath, buf, os.FileMode(0o600)); err != nil {
p.Warn().Err(err).Msg("could not copy old log file") p.Warn().Err(err).Msg("Could not copy old log file")
} }
} }
initLoggingWithBackup(false) initLoggingWithBackup(false)
@@ -376,13 +376,13 @@ func run(appCallback *AppCallback, stopCh chan struct{}) {
if daemon { if daemon {
exe, err := os.Executable() exe, err := os.Executable()
if err != nil { if err != nil {
p.Error().Err(err).Msg("failed to find the binary") p.Error().Err(err).Msg("Failed to find the binary")
notifyExitToLogServer() notifyExitToLogServer()
os.Exit(1) os.Exit(1)
} }
curDir, err := os.Getwd() curDir, err := os.Getwd()
if err != nil { if err != nil {
p.Error().Err(err).Msg("failed to get current working directory") p.Error().Err(err).Msg("Failed to get current working directory")
notifyExitToLogServer() notifyExitToLogServer()
os.Exit(1) os.Exit(1)
} }
@@ -390,7 +390,7 @@ func run(appCallback *AppCallback, stopCh chan struct{}) {
cmd := exec.Command(exe, append(os.Args[1:], "-d=false")...) cmd := exec.Command(exe, append(os.Args[1:], "-d=false")...)
cmd.Dir = curDir cmd.Dir = curDir
if err := cmd.Start(); err != nil { if err := cmd.Start(); err != nil {
p.Error().Err(err).Msg("failed to start process as daemon") p.Error().Err(err).Msg("Failed to start process as daemon")
notifyExitToLogServer() notifyExitToLogServer()
os.Exit(1) os.Exit(1)
} }
@@ -402,7 +402,7 @@ func run(appCallback *AppCallback, stopCh chan struct{}) {
for _, lc := range p.cfg.Listener { for _, lc := range p.cfg.Listener {
if shouldAllocateLoopbackIP(lc.IP) { if shouldAllocateLoopbackIP(lc.IP) {
if err := allocateIP(lc.IP); err != nil { if err := allocateIP(lc.IP); err != nil {
p.Error().Err(err).Msgf("could not allocate IP: %s", lc.IP) p.Error().Err(err).Msgf("Could not allocate ip: %s", lc.IP)
} }
} }
} }
@@ -413,7 +413,7 @@ func run(appCallback *AppCallback, stopCh chan struct{}) {
for _, lc := range p.cfg.Listener { for _, lc := range p.cfg.Listener {
if shouldAllocateLoopbackIP(lc.IP) { if shouldAllocateLoopbackIP(lc.IP) {
if err := deAllocateIP(lc.IP); err != nil { if err := deAllocateIP(lc.IP); err != nil {
p.Error().Err(err).Msgf("could not de-allocate IP: %s", lc.IP) p.Error().Err(err).Msgf("Could not de-allocate ip: %s", lc.IP)
} }
} }
} }
@@ -426,9 +426,9 @@ func run(appCallback *AppCallback, stopCh chan struct{}) {
file := ctrld.SavedStaticDnsSettingsFilePath(i) file := ctrld.SavedStaticDnsSettingsFilePath(i)
if _, err := os.Stat(file); err == nil { if _, err := os.Stat(file); err == nil {
if err := restoreDNS(i); err != nil { if err := restoreDNS(i); err != nil {
p.Error().Err(err).Msgf("Could not restore static DNS on interface %s", i.Name) p.Error().Err(err).Msgf("Could not restore static dns on interface %s", i.Name)
} else { } else {
p.Debug().Msgf("Restored static DNS on interface %s successfully", i.Name) p.Debug().Msgf("Restored static dns on interface %s successfully", i.Name)
} }
} }
return nil return nil
@@ -488,7 +488,7 @@ func readConfigFile(writeDefaultConfig, notice bool) bool {
if notice { if notice {
mainLog.Load().Notice().Msg("Reading config: " + v.ConfigFileUsed()) mainLog.Load().Notice().Msg("Reading config: " + v.ConfigFileUsed())
} }
mainLog.Load().Info().Msg("loading config file from: " + v.ConfigFileUsed()) mainLog.Load().Info().Msg("Loading config file from: " + v.ConfigFileUsed())
defaultConfigFile = v.ConfigFileUsed() defaultConfigFile = v.ConfigFileUsed()
return true return true
} }
@@ -500,21 +500,21 @@ func readConfigFile(writeDefaultConfig, notice bool) bool {
// If error is viper.ConfigFileNotFoundError, write default config. // If error is viper.ConfigFileNotFoundError, write default config.
if errors.As(err, &viper.ConfigFileNotFoundError{}) { if errors.As(err, &viper.ConfigFileNotFoundError{}) {
if err := v.Unmarshal(&cfg); err != nil { if err := v.Unmarshal(&cfg); err != nil {
mainLog.Load().Fatal().Msgf("failed to unmarshal default config: %v", err) mainLog.Load().Fatal().Msgf("Failed to unmarshal default config: %v", err)
} }
_, _ = tryUpdateListenerConfig(&cfg, func() {}, true) _, _ = tryUpdateListenerConfig(&cfg, func() {}, true)
addExtraSplitDnsRule(&cfg) addExtraSplitDnsRule(&cfg)
if err := writeConfigFile(&cfg); err != nil { if err := writeConfigFile(&cfg); err != nil {
mainLog.Load().Fatal().Msgf("failed to write default config file: %v", err) mainLog.Load().Fatal().Msgf("Failed to write default config file: %v", err)
} else { } else {
fp, err := filepath.Abs(defaultConfigFile) fp, err := filepath.Abs(defaultConfigFile)
if err != nil { if err != nil {
mainLog.Load().Fatal().Msgf("failed to get default config file path: %v", err) mainLog.Load().Fatal().Msgf("Failed to get default config file path: %v", err)
} }
if cdUID == "" && nextdns == "" { if cdUID == "" && nextdns == "" {
mainLog.Load().Notice().Msg("Generating controld default config: " + fp) mainLog.Load().Notice().Msg("Generating controld default config: " + fp)
} }
mainLog.Load().Info().Msg("writing default config file to: " + fp) mainLog.Load().Info().Msg("Writing default config file to: " + fp)
} }
return false return false
} }
@@ -523,12 +523,12 @@ func readConfigFile(writeDefaultConfig, notice bool) bool {
if errors.As(err, &viper.ConfigParseError{}) { if errors.As(err, &viper.ConfigParseError{}) {
if de := decoderErrorFromTomlFile(v.ConfigFileUsed()); de != nil { if de := decoderErrorFromTomlFile(v.ConfigFileUsed()); de != nil {
row, col := de.Position() row, col := de.Position()
mainLog.Load().Fatal().Msgf("failed to decode config file at line: %d, column: %d, error: %v", row, col, err) mainLog.Load().Fatal().Msgf("Failed to decode config file at line: %d, column: %d, error: %v", row, col, err)
} }
} }
// Otherwise, report fatal error and exit. // Otherwise, report fatal error and exit.
mainLog.Load().Fatal().Msgf("failed to decode config file: %v", err) mainLog.Load().Fatal().Msgf("Failed to decode config file: %v", err)
return false return false
} }
@@ -653,7 +653,7 @@ func deactivationPinSet() bool {
// processCDFlags processes Control D related flags // processCDFlags processes Control D related flags
func processCDFlags(cfg *ctrld.Config) (*controld.ResolverConfig, error) { func processCDFlags(cfg *ctrld.Config) (*controld.ResolverConfig, error) {
logger := mainLog.Load().With().Str("mode", "cd") logger := mainLog.Load().With().Str("mode", "cd")
logger.Info().Msgf("fetching Controld D configuration from API: %s", cdUID) logger.Info().Msgf("Fetching Controld D configuration from API: %s", cdUID)
bo := backoff.NewBackoff("processCDFlags", logf, 30*time.Second) bo := backoff.NewBackoff("processCDFlags", logf, 30*time.Second)
bo.LogLongerThan = 30 * time.Second bo.LogLongerThan = 30 * time.Second
ctx := ctrld.LoggerCtx(context.Background(), logger) ctx := ctrld.LoggerCtx(context.Background(), logger)
@@ -665,7 +665,7 @@ func processCDFlags(cfg *ctrld.Config) (*controld.ResolverConfig, error) {
for { for {
if errUrlNetworkError(err) { if errUrlNetworkError(err) {
bo.BackOff(ctx, err) bo.BackOff(ctx, err)
logger.Warn().Msg("could not fetch resolver using bootstrap DNS, retrying...") logger.Warn().Msg("Could not fetch resolver using bootstrap DNS, retrying...")
resolverConfig, err = controld.FetchResolverConfig(ctx, cdUID, appVersion, cdDev) resolverConfig, err = controld.FetchResolverConfig(ctx, cdUID, appVersion, cdDev)
continue continue
} }
@@ -675,23 +675,23 @@ func processCDFlags(cfg *ctrld.Config) (*controld.ResolverConfig, error) {
if isMobile() { if isMobile() {
return nil, err return nil, err
} }
logger.Warn().Err(err).Msg("could not fetch resolver config") logger.Warn().Err(err).Msg("Could not fetch resolver config")
return nil, err return nil, err
} }
if resolverConfig.DeactivationPin != nil { if resolverConfig.DeactivationPin != nil {
logger.Debug().Msg("saving deactivation pin") logger.Debug().Msg("Saving deactivation pin")
cdDeactivationPin.Store(*resolverConfig.DeactivationPin) cdDeactivationPin.Store(*resolverConfig.DeactivationPin)
} }
logger.Info().Msg("generating ctrld config from Control-D configuration") logger.Info().Msg("Generating ctrld config from Control-D configuration")
// Reset config to ensure clean state before applying Control-D settings // Reset config to ensure clean state before applying Control-D settings
// This prevents mixing of old configuration with new Control-D settings // This prevents mixing of old configuration with new Control-D settings
*cfg = ctrld.Config{} *cfg = ctrld.Config{}
// Fetch config, unmarshal to cfg. // Fetch config, unmarshal to cfg.
if resolverConfig.Ctrld.CustomConfig != "" { if resolverConfig.Ctrld.CustomConfig != "" {
logger.Info().Msg("using defined custom config of Control-D resolver") logger.Info().Msg("Using defined custom config of Control-D resolver")
var cfgErr error var cfgErr error
if cfgErr = validateCdRemoteConfig(resolverConfig, cfg); cfgErr == nil { if cfgErr = validateCdRemoteConfig(resolverConfig, cfg); cfgErr == nil {
setListenerDefaultValue(cfg) setListenerDefaultValue(cfg)
@@ -700,13 +700,13 @@ func processCDFlags(cfg *ctrld.Config) (*controld.ResolverConfig, error) {
return resolverConfig, nil return resolverConfig, nil
} }
} }
mainLog.Load().Warn().Err(err).Msg("disregarding invalid custom config") mainLog.Load().Warn().Err(err).Msg("Disregarding invalid custom config")
} }
bootstrapIP := func(endpoint string) string { bootstrapIP := func(endpoint string) string {
u, err := url.Parse(endpoint) u, err := url.Parse(endpoint)
if err != nil { if err != nil {
logger.Warn().Err(err).Msgf("no bootstrap IP for invalid endpoint: %s", endpoint) logger.Warn().Err(err).Msgf("No bootstrap ip for invalid endpoint: %s", endpoint)
return "" return ""
} }
switch { switch {
@@ -796,11 +796,11 @@ func processListenFlag() {
host, portStr, err := net.SplitHostPort(listenAddress) host, portStr, err := net.SplitHostPort(listenAddress)
if err != nil { if err != nil {
mainLog.Load().Fatal().Msgf("invalid listener address: %v", err) mainLog.Load().Fatal().Msgf("Invalid listener address: %v", err)
} }
port, err := strconv.Atoi(portStr) port, err := strconv.Atoi(portStr)
if err != nil { if err != nil {
mainLog.Load().Fatal().Msgf("invalid port number: %v", err) mainLog.Load().Fatal().Msgf("Invalid port number: %v", err)
} }
lc := &ctrld.ListenerConfig{ lc := &ctrld.ListenerConfig{
IP: host, IP: host,
@@ -870,7 +870,7 @@ func defaultIfaceName() string {
if runtime.GOOS == "linux" { if runtime.GOOS == "linux" {
return "lo" return "lo"
} }
mainLog.Load().Debug().Err(err).Msg("no default route interface found") mainLog.Load().Debug().Err(err).Msg("No default route interface found")
return "" return ""
} }
return dri return dri
@@ -889,7 +889,7 @@ func defaultIfaceName() string {
func selfCheckStatus(ctx context.Context, s service.Service, sockDir string) (bool, service.Status, error) { func selfCheckStatus(ctx context.Context, s service.Service, sockDir string) (bool, service.Status, error) {
status, err := s.Status() status, err := s.Status()
if err != nil { if err != nil {
mainLog.Load().Warn().Err(err).Msg("could not get service status") mainLog.Load().Warn().Err(err).Msg("Could not get service status")
return false, service.StatusUnknown, err return false, service.StatusUnknown, err
} }
// If ctrld is not running, do nothing, just return the status as-is. // If ctrld is not running, do nothing, just return the status as-is.
@@ -901,7 +901,7 @@ func selfCheckStatus(ctx context.Context, s service.Service, sockDir string) (bo
return true, status, nil return true, status, nil
} }
mainLog.Load().Debug().Msg("waiting for ctrld listener to be ready") mainLog.Load().Debug().Msg("Waiting for ctrld listener to be ready")
cc := newSocketControlClient(ctx, s, sockDir) cc := newSocketControlClient(ctx, s, sockDir)
if cc == nil { if cc == nil {
return false, status, errors.New("could not connect to control server") return false, status, errors.New("could not connect to control server")
@@ -914,13 +914,13 @@ func selfCheckStatus(ctx context.Context, s service.Service, sockDir string) (bo
v.SetConfigFile(defaultConfigFile) v.SetConfigFile(defaultConfigFile)
} }
if err := v.ReadInConfig(); err != nil { if err := v.ReadInConfig(); err != nil {
mainLog.Load().Error().Err(err).Msgf("failed to re-read configuration file: %s", v.ConfigFileUsed()) mainLog.Load().Error().Err(err).Msgf("Failed to re-read configuration file: %s", v.ConfigFileUsed())
return false, status, err return false, status, err
} }
cfg = ctrld.Config{} cfg = ctrld.Config{}
if err := v.Unmarshal(&cfg); err != nil { if err := v.Unmarshal(&cfg); err != nil {
mainLog.Load().Error().Err(err).Msg("failed to update new config") mainLog.Load().Error().Err(err).Msg("Failed to update new config")
return false, status, err return false, status, err
} }
@@ -930,12 +930,12 @@ func selfCheckStatus(ctx context.Context, s service.Service, sockDir string) (bo
return true, status, nil return true, status, nil
} }
mainLog.Load().Debug().Msg("ctrld listener is ready") mainLog.Load().Debug().Msg("Ctrld listener is ready")
lc := cfg.FirstListener() lc := cfg.FirstListener()
addr := net.JoinHostPort(lc.IP, strconv.Itoa(lc.Port)) addr := net.JoinHostPort(lc.IP, strconv.Itoa(lc.Port))
mainLog.Load().Debug().Msgf("performing listener test, sending queries to %s", addr) mainLog.Load().Debug().Msgf("Performing listener test, sending queries to %s", addr)
if err := selfCheckResolveDomain(context.TODO(), addr, "internal", selfCheckInternalTestDomain); err != nil { if err := selfCheckResolveDomain(context.TODO(), addr, "internal", selfCheckInternalTestDomain); err != nil {
return false, status, err return false, status, err
@@ -985,20 +985,21 @@ func selfCheckResolveDomain(ctx context.Context, addr, scope string, domain stri
lastErr = exErr lastErr = exErr
bo.BackOff(ctx, fmt.Errorf("ExchangeContext: %w", exErr)) bo.BackOff(ctx, fmt.Errorf("ExchangeContext: %w", exErr))
} }
mainLog.Load().Debug().Msgf("self-check against %q failed", domain) mainLog.Load().Debug().Msgf("Self-check against %q failed", domain)
loggerCtx := ctrld.LoggerCtx(ctx, mainLog.Load()) loggerCtx := ctrld.LoggerCtx(ctx, mainLog.Load())
// Ping all upstreams to provide better error message to users. // Ping all upstreams to provide better error message to users.
for name, uc := range cfg.Upstream { for name, uc := range cfg.Upstream {
if err := uc.ErrorPing(loggerCtx); err != nil { if err := uc.ErrorPing(loggerCtx); err != nil {
mainLog.Load().Err(err).Msgf("failed to connect to upstream.%s, endpoint: %s", name, uc.Endpoint) mainLog.Load().Err(err).Msgf("Failed to connect to upstream.%s, endpoint: %s", name, uc.Endpoint)
} }
} }
marker := strings.Repeat("=", 32) marker := strings.Repeat("=", 32)
mainLog.Load().Debug().Msg(marker) mainLog.Load().Debug().Msg(marker)
mainLog.Load().Debug().Msgf("listener address : %s", addr)
mainLog.Load().Debug().Msgf("last error : %v", lastErr) mainLog.Load().Debug().Msgf("Listener address : %s", addr)
mainLog.Load().Debug().Msgf("Last error : %v", lastErr)
if lastAnswer != nil { if lastAnswer != nil {
mainLog.Load().Debug().Msgf("last answer from ctrld :") mainLog.Load().Debug().Msgf("Last answer from ctrld :")
mainLog.Load().Debug().Msg(marker) mainLog.Load().Debug().Msg(marker)
for _, s := range strings.Split(lastAnswer.String(), "\n") { for _, s := range strings.Split(lastAnswer.String(), "\n") {
mainLog.Load().Debug().Msgf("%s", s) mainLog.Load().Debug().Msgf("%s", s)
@@ -1069,7 +1070,7 @@ func readConfigWithNotice(writeDefaultConfig, notice bool) {
dir, err := userHomeDir() dir, err := userHomeDir()
if err != nil { if err != nil {
mainLog.Load().Fatal().Msgf("failed to get user home dir: %v", err) mainLog.Load().Fatal().Msgf("Failed to get user home dir: %v", err)
} }
for _, config := range configs { for _, config := range configs {
ctrld.SetConfigNameWithPath(v, config.name, dir) ctrld.SetConfigNameWithPath(v, config.name, dir)
@@ -1099,12 +1100,12 @@ func uninstall(p *prog, s service.Service) {
file := ctrld.SavedStaticDnsSettingsFilePath(i) file := ctrld.SavedStaticDnsSettingsFilePath(i)
if _, err := os.Stat(file); err == nil { if _, err := os.Stat(file); err == nil {
if err := restoreDNS(i); err != nil { if err := restoreDNS(i); err != nil {
mainLog.Load().Error().Err(err).Msgf("Could not restore static DNS on interface %s", i.Name) mainLog.Load().Error().Err(err).Msgf("Could not restore static dns on interface %s", i.Name)
} else { } else {
mainLog.Load().Debug().Msgf("Restored static DNS on interface %s successfully", i.Name) mainLog.Load().Debug().Msgf("Restored static dns on interface %s successfully", i.Name)
err = os.Remove(file) err = os.Remove(file)
if err != nil { if err != nil {
mainLog.Load().Debug().Err(err).Msgf("Could not remove saved static DNS file for interface %s", i.Name) mainLog.Load().Debug().Err(err).Msgf("Could not remove saved static dns file for interface %s", i.Name)
} }
} }
} }
@@ -1123,7 +1124,7 @@ func validateConfig(cfg *ctrld.Config) error {
var ve validator.ValidationErrors var ve validator.ValidationErrors
if errors.As(err, &ve) { if errors.As(err, &ve) {
for _, fe := range ve { for _, fe := range ve {
mainLog.Load().Error().Msgf("invalid config: %s: %s", fe.Namespace(), fieldErrorMsg(fe)) mainLog.Load().Error().Msgf("Invalid config: %s: %s", fe.Namespace(), fieldErrorMsg(fe))
} }
} }
mainLog.Load().Error().Err(err).Msg("Configuration validation failed") mainLog.Load().Error().Err(err).Msg("Configuration validation failed")
@@ -1492,14 +1493,14 @@ func cdUIDFromProvToken() string {
} }
// Validate custom hostname if provided. // Validate custom hostname if provided.
if customHostname != "" && !validHostname(customHostname) { if customHostname != "" && !validHostname(customHostname) {
mainLog.Load().Fatal().Msgf("invalid custom hostname: %q", customHostname) mainLog.Load().Fatal().Msgf("Invalid custom hostname: %q", customHostname)
} }
req := &controld.UtilityOrgRequest{ProvToken: cdOrg, Hostname: customHostname} req := &controld.UtilityOrgRequest{ProvToken: cdOrg, Hostname: customHostname}
// Process provision token if provided. // Process provision token if provided.
loggerCtx := ctrld.LoggerCtx(context.Background(), mainLog.Load()) loggerCtx := ctrld.LoggerCtx(context.Background(), mainLog.Load())
resolverConfig, err := controld.FetchResolverUID(loggerCtx, req, appVersion, cdDev) resolverConfig, err := controld.FetchResolverUID(loggerCtx, req, appVersion, cdDev)
if err != nil { if err != nil {
mainLog.Load().Fatal().Err(err).Msgf("failed to fetch resolver uid with provision token: %s", cdOrg) mainLog.Load().Fatal().Err(err).Msgf("Failed to fetch resolver uid with provision token: %s", cdOrg)
} }
return resolverConfig.UID return resolverConfig.UID
} }
@@ -1619,7 +1620,7 @@ func validateCdUpstreamProtocol() {
switch cdUpstreamProto { switch cdUpstreamProto {
case ctrld.ResolverTypeDOH, ctrld.ResolverTypeDOH3: case ctrld.ResolverTypeDOH, ctrld.ResolverTypeDOH3:
default: default:
mainLog.Load().Fatal().Msg(`flag "--protocol" must be "doh" or "doh3"`) mainLog.Load().Fatal().Msg(`Flag "--protocol" must be "doh" or "doh3"`)
} }
} }
@@ -1686,7 +1687,7 @@ func checkDeactivationPin(s service.Service, stopCh chan struct{}) error {
mainLog.Load().Debug().Msg("Checking deactivation pin") mainLog.Load().Debug().Msg("Checking deactivation pin")
dir, err := socketDir() dir, err := socketDir()
if err != nil { if err != nil {
mainLog.Load().Err(err).Msg("could not check deactivation pin") mainLog.Load().Err(err).Msg("Could not check deactivation pin")
return err return err
} }
mainLog.Load().Debug().Msg("Creating control client") mainLog.Load().Debug().Msg("Creating control client")
@@ -1751,7 +1752,7 @@ func curCdUID() string {
if s, _, _ := svcCmd.initializeServiceManager(); s != nil { if s, _, _ := svcCmd.initializeServiceManager(); s != nil {
// Configure Windows service failure actions // Configure Windows service failure actions
if err := ConfigureWindowsServiceFailureActions(ctrldServiceName); err != nil { if err := ConfigureWindowsServiceFailureActions(ctrldServiceName); err != nil {
mainLog.Load().Debug().Err(err).Msgf("failed to configure Windows service %s failure actions", ctrldServiceName) mainLog.Load().Debug().Err(err).Msgf("Failed to configure windows service %s failure actions", ctrldServiceName)
} }
if dir, _ := socketDir(); dir != "" { if dir, _ := socketDir(); dir != "" {
cc := newSocketControlClient(context.TODO(), s, dir) cc := newSocketControlClient(context.TODO(), s, dir)
@@ -1830,7 +1831,7 @@ func doValidateCdRemoteConfig(cdUID string, fatal bool) error {
if !fatal { if !fatal {
logger = mainLog.Load().Warn() logger = mainLog.Load().Warn()
} }
logger.Err(err).Err(err).Msgf("failed to fetch resolver uid: %s", cdUID) logger.Err(err).Err(err).Msgf("Failed to fetch resolver uid: %s", cdUID)
if !fatal { if !fatal {
return err return err
} }
@@ -1859,22 +1860,22 @@ func doValidateCdRemoteConfig(cdUID string, fatal bool) error {
if we := os.WriteFile(tmpConfFile, configStr, 0600); we == nil { if we := os.WriteFile(tmpConfFile, configStr, 0600); we == nil {
if de := decoderErrorFromTomlFile(tmpConfFile); de != nil { if de := decoderErrorFromTomlFile(tmpConfFile); de != nil {
row, col := de.Position() row, col := de.Position()
mainLog.Load().Error().Msgf("failed to parse custom config at line: %d, column: %d, error: %s", row, col, de.Error()) mainLog.Load().Error().Msgf("Failed to parse custom config at line: %d, column: %d, error: %s", row, col, de.Error())
errorLogged = true errorLogged = true
} }
_ = os.Remove(tmpConfFile) _ = os.Remove(tmpConfFile)
} }
// If we could not log details error, emit what we have already got. // If we could not log details error, emit what we have already got.
if !errorLogged { if !errorLogged {
mainLog.Load().Error().Msgf("failed to parse custom config: %v", cfgErr) mainLog.Load().Error().Msgf("Failed to parse custom config: %v", cfgErr)
} }
} }
} else { } else {
mainLog.Load().Error().Msgf("failed to unmarshal custom config: %v", err) mainLog.Load().Error().Msgf("Failed to unmarshal custom config: %v", err)
} }
} }
if cfgErr != nil { if cfgErr != nil {
mainLog.Load().Warn().Msg("disregarding invalid custom config") mainLog.Load().Warn().Msg("Disregarding invalid custom config")
} }
v = oldV v = oldV
return nil return nil
@@ -1885,7 +1886,7 @@ func uninstallInvalidCdUID(p *prog, logger *ctrld.Logger, doStop bool) bool {
svcCmd := NewServiceCommand() svcCmd := NewServiceCommand()
s, _, err := svcCmd.initializeServiceManager() s, _, err := svcCmd.initializeServiceManager()
if err != nil { if err != nil {
logger.Warn().Err(err).Msg("failed to create new service") logger.Warn().Err(err).Msg("Failed to create new service")
return false return false
} }
// restore static DNS settings or DHCP // restore static DNS settings or DHCP
@@ -1893,7 +1894,7 @@ func uninstallInvalidCdUID(p *prog, logger *ctrld.Logger, doStop bool) bool {
tasks := []task{{s.Uninstall, true, "Uninstall"}} tasks := []task{{s.Uninstall, true, "Uninstall"}}
if doTasks(tasks) { if doTasks(tasks) {
logger.Info().Msg("uninstalled service") logger.Info().Msg("Uninstalled service")
if doStop { if doStop {
_ = s.Stop() _ = s.Stop()
} }
+2 -2
View File
@@ -46,11 +46,11 @@ func (cc *ClientsCommand) ListClients(cmd *cobra.Command, args []string) error {
status, err := s.Status() status, err := s.Status()
if errors.Is(err, service.ErrNotInstalled) { if errors.Is(err, service.ErrNotInstalled) {
mainLog.Load().Warn().Msg("service not installed") mainLog.Load().Warn().Msg("Service not installed")
return nil return nil
} }
if status == service.StatusStopped { if status == service.StatusStopped {
mainLog.Load().Warn().Msg("service is not running") mainLog.Load().Warn().Msg("Service is not running")
return nil return nil
} }
+1 -1
View File
@@ -37,7 +37,7 @@ func (ic *InterfacesCommand) ListInterfaces(cmd *cobra.Command, args []string) e
} }
nss, err := currentStaticDNS(i) nss, err := currentStaticDNS(i)
if err != nil { if err != nil {
mainLog.Load().Warn().Err(err).Msg("failed to get DNS") mainLog.Load().Warn().Err(err).Msg("Failed to get DNS")
} }
if len(nss) == 0 { if len(nss) == 0 {
nss = currentDNS(i) nss = currentDNS(i)
+8 -8
View File
@@ -33,7 +33,7 @@ func NewLogCommand() (*LogCommand, error) {
// warnRuntimeLoggingNotEnabled logs a warning about runtime logging not being enabled // warnRuntimeLoggingNotEnabled logs a warning about runtime logging not being enabled
func (lc *LogCommand) warnRuntimeLoggingNotEnabled() { func (lc *LogCommand) warnRuntimeLoggingNotEnabled() {
mainLog.Load().Warn().Msg("runtime debug logging is not enabled") mainLog.Load().Warn().Msg("Runtime debug logging is not enabled")
mainLog.Load().Warn().Msg(`ctrld may be running without "--cd" flag or logging is already enabled`) mainLog.Load().Warn().Msg(`ctrld may be running without "--cd" flag or logging is already enabled`)
} }
@@ -47,11 +47,11 @@ func (lc *LogCommand) SendLogs(cmd *cobra.Command, args []string) error {
status, err := s.Status() status, err := s.Status()
if errors.Is(err, service.ErrNotInstalled) { if errors.Is(err, service.ErrNotInstalled) {
mainLog.Load().Warn().Msg("service not installed") mainLog.Load().Warn().Msg("Service not installed")
return nil return nil
} }
if status == service.StatusStopped { if status == service.StatusStopped {
mainLog.Load().Warn().Msg("service is not running") mainLog.Load().Warn().Msg("Service is not running")
return nil return nil
} }
@@ -63,7 +63,7 @@ func (lc *LogCommand) SendLogs(cmd *cobra.Command, args []string) error {
switch resp.StatusCode { switch resp.StatusCode {
case http.StatusServiceUnavailable: case http.StatusServiceUnavailable:
mainLog.Load().Warn().Msg("runtime logs could only be sent once per minute") mainLog.Load().Warn().Msg("Runtime logs could only be sent once per minute")
return nil return nil
case http.StatusMovedPermanently: case http.StatusMovedPermanently:
lc.warnRuntimeLoggingNotEnabled() lc.warnRuntimeLoggingNotEnabled()
@@ -93,11 +93,11 @@ func (lc *LogCommand) ViewLogs(cmd *cobra.Command, args []string) error {
status, err := s.Status() status, err := s.Status()
if errors.Is(err, service.ErrNotInstalled) { if errors.Is(err, service.ErrNotInstalled) {
mainLog.Load().Warn().Msg("service not installed") mainLog.Load().Warn().Msg("Service not installed")
return nil return nil
} }
if status == service.StatusStopped { if status == service.StatusStopped {
mainLog.Load().Warn().Msg("service is not running") mainLog.Load().Warn().Msg("Service is not running")
return nil return nil
} }
@@ -112,10 +112,10 @@ func (lc *LogCommand) ViewLogs(cmd *cobra.Command, args []string) error {
lc.warnRuntimeLoggingNotEnabled() lc.warnRuntimeLoggingNotEnabled()
return nil return nil
case http.StatusBadRequest: case http.StatusBadRequest:
mainLog.Load().Warn().Msg("runtime debugs log is not available") mainLog.Load().Warn().Msg("Runtime debug logs are not available")
buf, err := io.ReadAll(resp.Body) buf, err := io.ReadAll(resp.Body)
if err != nil { if err != nil {
mainLog.Load().Fatal().Err(err).Msg("failed to read response body") mainLog.Load().Fatal().Err(err).Msg("Failed to read response body")
} }
mainLog.Load().Warn().Msgf("ctrld process response:\n\n%s\n", string(buf)) mainLog.Load().Warn().Msgf("ctrld process response:\n\n%s\n", string(buf))
return nil return nil
+8 -8
View File
@@ -42,7 +42,7 @@ func (uc *UpgradeCommand) Upgrade(cmd *cobra.Command, args []string) error {
bin, err := os.Executable() bin, err := os.Executable()
if err != nil { if err != nil {
mainLog.Load().Fatal().Err(err).Msg("failed to get current ctrld binary path") mainLog.Load().Fatal().Err(err).Msg("Failed to get current ctrld binary path")
} }
readConfig(false) readConfig(false)
@@ -75,7 +75,7 @@ func (uc *UpgradeCommand) Upgrade(cmd *cobra.Command, args []string) error {
switch channel { switch channel {
case upgradeChannelProd, upgradeChannelDev: // ok case upgradeChannelProd, upgradeChannelDev: // ok
default: default:
mainLog.Load().Fatal().Msgf("uprade argument must be either %q or %q", upgradeChannelProd, upgradeChannelDev) mainLog.Load().Fatal().Msgf("Upgrade argument must be either %q or %q", upgradeChannelProd, upgradeChannelDev)
} }
baseUrl = upgradeChannel[channel] baseUrl = upgradeChannel[channel]
} }
@@ -85,20 +85,20 @@ func (uc *UpgradeCommand) Upgrade(cmd *cobra.Command, args []string) error {
resp, err := getWithRetry(dlUrl, downloadServerIp) resp, err := getWithRetry(dlUrl, downloadServerIp)
if err != nil { if err != nil {
mainLog.Load().Fatal().Err(err).Msg("failed to download binary") mainLog.Load().Fatal().Err(err).Msg("Failed to download binary")
} }
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
mainLog.Load().Fatal().Msgf("could not download binary: %s", http.StatusText(resp.StatusCode)) mainLog.Load().Fatal().Msgf("Could not download binary: %s", http.StatusText(resp.StatusCode))
} }
mainLog.Load().Debug().Msg("Updating current binary") mainLog.Load().Debug().Msg("Updating current binary")
if err := selfupdate.Apply(resp.Body, selfupdate.Options{OldSavePath: oldBin}); err != nil { if err := selfupdate.Apply(resp.Body, selfupdate.Options{OldSavePath: oldBin}); err != nil {
if rerr := selfupdate.RollbackError(err); rerr != nil { if rerr := selfupdate.RollbackError(err); rerr != nil {
mainLog.Load().Error().Err(rerr).Msg("could not rollback old binary") mainLog.Load().Error().Err(rerr).Msg("Could not rollback old binary")
} }
mainLog.Load().Fatal().Err(err).Msg("failed to update current binary") mainLog.Load().Fatal().Err(err).Msg("Failed to update current binary")
} }
doRestart := func() bool { doRestart := func() bool {
@@ -154,10 +154,10 @@ func (uc *UpgradeCommand) Upgrade(cmd *cobra.Command, args []string) error {
mainLog.Load().Warn().Msgf("Upgrade failed, restoring previous binary: %s", oldBin) mainLog.Load().Warn().Msgf("Upgrade failed, restoring previous binary: %s", oldBin)
if err := os.Remove(bin); err != nil { if err := os.Remove(bin); err != nil {
mainLog.Load().Fatal().Err(err).Msg("failed to remove new binary") mainLog.Load().Fatal().Err(err).Msg("Failed to remove new binary")
} }
if err := os.Rename(oldBin, bin); err != nil { if err := os.Rename(oldBin, bin); err != nil {
mainLog.Load().Fatal().Err(err).Msg("failed to restore old binary") mainLog.Load().Fatal().Err(err).Msg("Failed to restore old binary")
} }
if doRestart() { if doRestart() {
mainLog.Load().Notice().Msg("Restored previous binary successfully") mainLog.Load().Notice().Msg("Restored previous binary successfully")
+19 -19
View File
@@ -81,18 +81,18 @@ func (s *controlServer) register(pattern string, handler http.Handler) {
func (p *prog) registerControlServerHandler() { func (p *prog) registerControlServerHandler() {
p.cs.register(listClientsPath, http.HandlerFunc(func(w http.ResponseWriter, request *http.Request) { p.cs.register(listClientsPath, http.HandlerFunc(func(w http.ResponseWriter, request *http.Request) {
p.Debug().Msg("handling list clients request") p.Debug().Msg("Handling list clients request")
clients := p.ciTable.ListClients() clients := p.ciTable.ListClients()
p.Debug().Int("client_count", len(clients)).Msg("retrieved clients list") p.Debug().Int("client_count", len(clients)).Msg("Retrieved clients list")
sort.Slice(clients, func(i, j int) bool { sort.Slice(clients, func(i, j int) bool {
return clients[i].IP.Less(clients[j].IP) return clients[i].IP.Less(clients[j].IP)
}) })
p.Debug().Msg("sorted clients by IP address") p.Debug().Msg("Sorted clients by IP address")
if p.metricsQueryStats.Load() { if p.metricsQueryStats.Load() {
p.Debug().Msg("metrics query stats enabled, collecting query counts") p.Debug().Msg("Metrics query stats enabled, collecting query counts")
for idx, client := range clients { for idx, client := range clients {
p.Debug(). p.Debug().
@@ -100,7 +100,7 @@ func (p *prog) registerControlServerHandler() {
Str("ip", client.IP.String()). Str("ip", client.IP.String()).
Str("mac", client.Mac). Str("mac", client.Mac).
Str("hostname", client.Hostname). Str("hostname", client.Hostname).
Msg("processing client metrics") Msg("Processing client metrics")
client.IncludeQueryCount = true client.IncludeQueryCount = true
dm := &dto.Metric{} dm := &dto.Metric{}
@@ -108,7 +108,7 @@ func (p *prog) registerControlServerHandler() {
if statsClientQueriesCount.MetricVec == nil { if statsClientQueriesCount.MetricVec == nil {
p.Debug(). p.Debug().
Str("client_ip", client.IP.String()). Str("client_ip", client.IP.String()).
Msg("skipping metrics collection: MetricVec is nil") Msg("Skipping metrics collection: MetricVec is nil")
continue continue
} }
@@ -123,7 +123,7 @@ func (p *prog) registerControlServerHandler() {
Str("client_ip", client.IP.String()). Str("client_ip", client.IP.String()).
Str("mac", client.Mac). Str("mac", client.Mac).
Str("hostname", client.Hostname). Str("hostname", client.Hostname).
Msg("failed to get metrics for client") Msg("Failed to get metrics for client")
continue continue
} }
@@ -132,30 +132,30 @@ func (p *prog) registerControlServerHandler() {
p.Debug(). p.Debug().
Str("client_ip", client.IP.String()). Str("client_ip", client.IP.String()).
Int64("query_count", client.QueryCount). Int64("query_count", client.QueryCount).
Msg("successfully collected query count") Msg("Successfully collected query count")
} else if err != nil { } else if err != nil {
p.Debug(). p.Debug().
Err(err). Err(err).
Str("client_ip", client.IP.String()). Str("client_ip", client.IP.String()).
Msg("failed to write metric") Msg("Failed to write metric")
} }
} }
} else { } else {
p.Debug().Msg("metrics query stats disabled, skipping query counts") p.Debug().Msg("Metrics query stats disabled, skipping query counts")
} }
if err := json.NewEncoder(w).Encode(&clients); err != nil { if err := json.NewEncoder(w).Encode(&clients); err != nil {
p.Error(). p.Error().
Err(err). Err(err).
Int("client_count", len(clients)). Int("client_count", len(clients)).
Msg("failed to encode clients response") Msg("Failed to encode clients response")
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
p.Debug(). p.Debug().
Int("client_count", len(clients)). Int("client_count", len(clients)).
Msg("successfully sent clients list response") Msg("Successfully sent clients list response")
})) }))
p.cs.register(startedPath, http.HandlerFunc(func(w http.ResponseWriter, request *http.Request) { p.cs.register(startedPath, http.HandlerFunc(func(w http.ResponseWriter, request *http.Request) {
select { select {
@@ -177,14 +177,14 @@ func (p *prog) registerControlServerHandler() {
oldSvc := p.cfg.Service oldSvc := p.cfg.Service
p.mu.Unlock() p.mu.Unlock()
if err := p.sendReloadSignal(); err != nil { if err := p.sendReloadSignal(); err != nil {
p.Error().Err(err).Msg("could not send reload signal") p.Error().Err(err).Msg("Could not send reload signal")
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
select { select {
case <-p.reloadDoneCh: case <-p.reloadDoneCh:
case <-time.After(5 * time.Second): case <-time.After(5 * time.Second):
http.Error(w, "timeout waiting for ctrld reload", http.StatusInternalServerError) http.Error(w, "Timeout waiting for ctrld reload", http.StatusInternalServerError)
return return
} }
@@ -227,7 +227,7 @@ func (p *prog) registerControlServerHandler() {
cdDeactivationPin.Store(defaultDeactivationPin) cdDeactivationPin.Store(defaultDeactivationPin)
} }
} else { } else {
p.Warn().Err(err).Msg("could not re-fetch deactivation pin code") p.Warn().Err(err).Msg("Could not re-fetch deactivation pin code")
} }
// If pin code not set, allowing deactivation. // If pin code not set, allowing deactivation.
@@ -239,7 +239,7 @@ func (p *prog) registerControlServerHandler() {
var req deactivationRequest var req deactivationRequest
if err := json.NewDecoder(request.Body).Decode(&req); err != nil { if err := json.NewDecoder(request.Body).Decode(&req); err != nil {
w.WriteHeader(http.StatusPreconditionFailed) w.WriteHeader(http.StatusPreconditionFailed)
p.Error().Err(err).Msg("invalid deactivation request") p.Error().Err(err).Msg("Invalid deactivation request")
return return
} }
@@ -322,15 +322,15 @@ func (p *prog) registerControlServerHandler() {
UID: cdUID, UID: cdUID,
Data: r.r, Data: r.r,
} }
p.Debug().Msg("sending log file to ControlD server") p.Debug().Msg("Sending log file to ControlD server")
resp := logSentResponse{Size: r.size} resp := logSentResponse{Size: r.size}
loggerCtx := ctrld.LoggerCtx(context.Background(), p.logger.Load()) loggerCtx := ctrld.LoggerCtx(context.Background(), p.logger.Load())
if err := controld.SendLogs(loggerCtx, req, cdDev); err != nil { if err := controld.SendLogs(loggerCtx, req, cdDev); err != nil {
p.Error().Msgf("could not send log file to ControlD server: %v", err) p.Error().Msgf("Could not send log file to ControlD server: %v", err)
resp.Error = err.Error() resp.Error = err.Error()
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
} else { } else {
p.Debug().Msg("sending log file successfully") p.Debug().Msg("Sending log file successfully")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
if err := json.NewEncoder(w).Encode(&resp); err != nil { if err := json.NewEncoder(w).Encode(&resp); err != nil {
+20 -20
View File
@@ -105,7 +105,7 @@ func (p *prog) serveDNS(ctx context.Context, listenerNum string) error {
listenerConfig := p.cfg.Listener[listenerNum] listenerConfig := p.cfg.Listener[listenerNum]
if allocErr := p.allocateIP(listenerConfig.IP); allocErr != nil { if allocErr := p.allocateIP(listenerConfig.IP); allocErr != nil {
p.Error().Err(allocErr).Str("ip", listenerConfig.IP).Msg("serveUDP: failed to allocate listen ip") p.Error().Err(allocErr).Str("ip", listenerConfig.IP).Msg("serveUDP: Failed to allocate listen IP")
return allocErr return allocErr
} }
@@ -136,7 +136,7 @@ func (p *prog) startListeners(ctx context.Context, cfg *ctrld.ListenerConfig, ha
case <-p.stopCh: case <-p.stopCh:
case <-gctx.Done(): case <-gctx.Done():
case err := <-errCh: case err := <-errCh:
p.Warn().Err(err).Msg("local ipv6 listener failed") p.Warn().Err(err).Msg("Local IPv6 listener failed")
} }
return nil return nil
}) })
@@ -154,7 +154,7 @@ func (p *prog) startListeners(ctx context.Context, cfg *ctrld.ListenerConfig, ha
case <-p.stopCh: case <-p.stopCh:
case <-gctx.Done(): case <-gctx.Done():
case err := <-errCh: case err := <-errCh:
p.Warn().Err(err).Msgf("could not listen on %s: %s", proto, listenAddr) p.Warn().Err(err).Msgf("Could not listen on %s: %s", proto, listenAddr)
} }
}() }()
} }
@@ -476,8 +476,8 @@ func (p *prog) proxyPrivatePtrLookup(ctx context.Context, msg *dns.Msg) *dns.Msg
}, },
Ptr: dns.Fqdn(name), Ptr: dns.Fqdn(name),
}} }}
ctrld.Log(ctx, p.Info(), "private PTR lookup, using client info table") ctrld.Log(ctx, p.Info(), "Private PTR lookup, using client info table")
ctrld.Log(ctx, p.Debug(), "client info: %v", ctrld.ClientInfo{ ctrld.Log(ctx, p.Debug(), "Client info: %v", ctrld.ClientInfo{
Mac: p.ciTable.LookupMac(ip.String()), Mac: p.ciTable.LookupMac(ip.String()),
IP: ip.String(), IP: ip.String(),
Hostname: name, Hostname: name,
@@ -525,8 +525,8 @@ func (p *prog) proxyLanHostnameQuery(ctx context.Context, msg *dns.Msg) *dns.Msg
AAAA: ip.AsSlice(), AAAA: ip.AsSlice(),
}} }}
} }
ctrld.Log(ctx, p.Info(), "lan hostname lookup, using client info table") ctrld.Log(ctx, p.Info(), "Lan hostname lookup, using client info table")
ctrld.Log(ctx, p.Debug(), "client info: %v", ctrld.ClientInfo{ ctrld.Log(ctx, p.Debug(), "Client info: %v", ctrld.ClientInfo{
Mac: p.ciTable.LookupMac(ip.String()), Mac: p.ciTable.LookupMac(ip.String()),
IP: ip.String(), IP: ip.String(),
Hostname: hostname, Hostname: hostname,
@@ -560,7 +560,7 @@ func (p *prog) handleSpecialQueryTypes(ctx *context.Context, req *proxyRequest,
} }
*upstreams, *upstreamConfigs = p.upstreamsAndUpstreamConfigForPtr(*upstreams, *upstreamConfigs) *upstreams, *upstreamConfigs = p.upstreamsAndUpstreamConfigForPtr(*upstreams, *upstreamConfigs)
*ctx = ctrld.LanQueryCtx(*ctx) *ctx = ctrld.LanQueryCtx(*ctx)
ctrld.Log(*ctx, p.Debug(), "private PTR lookup, using upstreams: %v", *upstreams) ctrld.Log(*ctx, p.Debug(), "Private PTR lookup, using upstreams: %v", *upstreams)
return nil return nil
case isLanHostnameQuery(req.msg): case isLanHostnameQuery(req.msg):
req.isLanOrPtrQuery = true req.isLanOrPtrQuery = true
@@ -570,10 +570,10 @@ func (p *prog) handleSpecialQueryTypes(ctx *context.Context, req *proxyRequest,
*upstreams = []string{upstreamOS} *upstreams = []string{upstreamOS}
*upstreamConfigs = []*ctrld.UpstreamConfig{osUpstreamConfig} *upstreamConfigs = []*ctrld.UpstreamConfig{osUpstreamConfig}
*ctx = ctrld.LanQueryCtx(*ctx) *ctx = ctrld.LanQueryCtx(*ctx)
ctrld.Log(*ctx, p.Debug(), "lan hostname lookup, using upstreams: %v", *upstreams) ctrld.Log(*ctx, p.Debug(), "Lan hostname lookup, using upstreams: %v", *upstreams)
return nil return nil
default: default:
ctrld.Log(*ctx, p.Debug(), "no explicit policy matched, using default routing -> %v", *upstreams) ctrld.Log(*ctx, p.Debug(), "No explicit policy matched, using default routing -> %v", *upstreams)
return nil return nil
} }
} }
@@ -1093,7 +1093,7 @@ func runDNSServer(addr, network string, handler dns.Handler) (*dns.Server, <-cha
defer close(errCh) defer close(errCh)
if err := s.ListenAndServe(); err != nil { if err := s.ListenAndServe(); err != nil {
s.NotifyStartedFunc() s.NotifyStartedFunc()
mainLog.Load().Error().Err(err).Msgf("could not listen and serve on: %s", s.Addr) mainLog.Load().Error().Err(err).Msgf("Could not listen and serve on: %s", s.Addr)
errCh <- err errCh <- err
} }
}() }()
@@ -1195,11 +1195,11 @@ func (p *prog) doSelfUninstall(pr *proxyResponse) {
p.checkingSelfUninstall = true p.checkingSelfUninstall = true
loggerCtx := ctrld.LoggerCtx(context.Background(), p.logger.Load()) loggerCtx := ctrld.LoggerCtx(context.Background(), p.logger.Load())
_, err := controld.FetchResolverConfig(loggerCtx, cdUID, appVersion, cdDev) _, err := controld.FetchResolverConfig(loggerCtx, cdUID, appVersion, cdDev)
logger.Debug().Msg("maximum number of refused queries reached, checking device status") logger.Debug().Msg("Maximum number of refused queries reached, checking device status")
selfUninstallCheck(err, p, logger) selfUninstallCheck(err, p, logger)
if err != nil { if err != nil {
logger.Warn().Err(err).Msg("could not fetch resolver config") logger.Warn().Err(err).Msg("Could not fetch resolver config")
} }
// Cool-of period to prevent abusing the API. // Cool-of period to prevent abusing the API.
go p.selfUninstallCoolOfPeriod() go p.selfUninstallCoolOfPeriod()
@@ -1263,7 +1263,7 @@ func (p *prog) queryFromSelf(ip string) bool {
netIP := netip.MustParseAddr(ip) netIP := netip.MustParseAddr(ip)
regularIPs, loopbackIPs, err := netmon.LocalAddresses() regularIPs, loopbackIPs, err := netmon.LocalAddresses()
if err != nil { if err != nil {
p.Warn().Err(err).Msg("could not get local addresses") p.Warn().Err(err).Msg("Could not get local addresses")
return false return false
} }
for _, localIP := range slices.Concat(regularIPs, loopbackIPs) { for _, localIP := range slices.Concat(regularIPs, loopbackIPs) {
@@ -1384,7 +1384,7 @@ func isWanClient(na net.Addr) bool {
// resolveInternalDomainTestQuery resolves internal test domain query, returning the answer to the caller. // resolveInternalDomainTestQuery resolves internal test domain query, returning the answer to the caller.
func resolveInternalDomainTestQuery(ctx context.Context, domain string, m *dns.Msg) *dns.Msg { func resolveInternalDomainTestQuery(ctx context.Context, domain string, m *dns.Msg) *dns.Msg {
logger := ctrld.LoggerFromCtx(ctx) logger := ctrld.LoggerFromCtx(ctx)
ctrld.Log(ctx, logger.Debug(), "internal domain test query") ctrld.Log(ctx, logger.Debug(), "Internal domain test query")
q := m.Question[0] q := m.Question[0]
answer := new(dns.Msg) answer := new(dns.Msg)
@@ -1521,18 +1521,18 @@ func (p *prog) monitorNetworkChanges(ctx context.Context) error {
// Ensure that selfIP is an IPv4 address. // Ensure that selfIP is an IPv4 address.
// If defaultRouteIP mistakenly returns an IPv6 (such as a ULA), clear it // If defaultRouteIP mistakenly returns an IPv6 (such as a ULA), clear it
if ip := net.ParseIP(selfIP); ip != nil && ip.To4() == nil { if ip := net.ParseIP(selfIP); ip != nil && ip.To4() == nil {
p.Debug().Msgf("defaultRouteIP returned a non-IPv4 address: %s, ignoring it", selfIP) p.Debug().Msgf("DefaultRouteIP returned a non-ipv4 address: %s, ignoring it", selfIP)
selfIP = "" selfIP = ""
} }
var ipv6 string var ipv6 string
if delta.New.DefaultRouteInterface != "" { if delta.New.DefaultRouteInterface != "" {
p.Debug().Msgf("default route interface: %s, IPs: %v", delta.New.DefaultRouteInterface, delta.New.InterfaceIPs[delta.New.DefaultRouteInterface]) p.Debug().Msgf("Default route interface: %s, ips: %v", delta.New.DefaultRouteInterface, delta.New.InterfaceIPs[delta.New.DefaultRouteInterface])
for _, ip := range delta.New.InterfaceIPs[delta.New.DefaultRouteInterface] { for _, ip := range delta.New.InterfaceIPs[delta.New.DefaultRouteInterface] {
ipAddr, _ := netip.ParsePrefix(ip.String()) ipAddr, _ := netip.ParsePrefix(ip.String())
addr := ipAddr.Addr() addr := ipAddr.Addr()
if selfIP == "" && addr.Is4() { if selfIP == "" && addr.Is4() {
p.Debug().Msgf("checking IP: %s", addr.String()) p.Debug().Msgf("Checking ip: %s", addr.String())
if !addr.IsLoopback() && !addr.IsLinkLocalUnicast() { if !addr.IsLoopback() && !addr.IsLinkLocalUnicast() {
selfIP = addr.String() selfIP = addr.String()
} }
@@ -1543,12 +1543,12 @@ func (p *prog) monitorNetworkChanges(ctx context.Context) error {
} }
} else { } else {
// If no default route interface is set yet, use the changed IPs // If no default route interface is set yet, use the changed IPs
p.Debug().Msgf("no default route interface found, using changed IPs: %v", changeIPs) p.Debug().Msgf("No default route interface found, using changed ips: %v", changeIPs)
for _, ip := range changeIPs { for _, ip := range changeIPs {
ipAddr, _ := netip.ParsePrefix(ip.String()) ipAddr, _ := netip.ParsePrefix(ip.String())
addr := ipAddr.Addr() addr := ipAddr.Addr()
if selfIP == "" && addr.Is4() { if selfIP == "" && addr.Is4() {
p.Debug().Msgf("checking IP: %s", addr.String()) p.Debug().Msgf("Checking ip: %s", addr.String())
if !addr.IsLoopback() && !addr.IsLinkLocalUnicast() { if !addr.IsLoopback() && !addr.IsLinkLocalUnicast() {
selfIP = addr.String() selfIP = addr.String()
} }
+2 -2
View File
@@ -83,8 +83,8 @@ func doWithRetry(req *http.Request, maxRetries int, ip string) (*http.Response,
return resp, nil return resp, nil
} }
if ipReq != nil { if ipReq != nil {
mainLog.Load().Warn().Err(err).Msgf("dial to %q failed", req.Host) mainLog.Load().Warn().Err(err).Msgf("Dial to %q failed", req.Host)
mainLog.Load().Warn().Msgf("fallback to direct IP to download prod version: %q", ip) mainLog.Load().Warn().Msgf("Fallback to direct ip to download prod version: %q", ip)
resp, err = client.Do(ipReq) resp, err = client.Do(ipReq)
if err == nil { if err == nil {
return resp, nil return resp, nil
+6 -6
View File
@@ -20,19 +20,19 @@ import (
const ( const (
// logWriterSize is the default buffer size for log writers // logWriterSize is the default buffer size for log writers
// This provides sufficient space for runtime logs without excessive memory usage // This provides sufficient space for runtime logs without excessive memory usage
logWriterSize = 1024 * 1024 * 5 // 5 MB logWriterSize = 1024 * 1024 * 5 // 5 MB
// logWriterSmallSize is used for memory-constrained environments // logWriterSmallSize is used for memory-constrained environments
// This reduces memory footprint while still maintaining log functionality // This reduces memory footprint while still maintaining log functionality
logWriterSmallSize = 1024 * 1024 * 1 // 1 MB logWriterSmallSize = 1024 * 1024 * 1 // 1 MB
// logWriterInitialSize is the initial buffer allocation // logWriterInitialSize is the initial buffer allocation
// This provides immediate space for early log entries // This provides immediate space for early log entries
logWriterInitialSize = 32 * 1024 // 32 KB logWriterInitialSize = 32 * 1024 // 32 KB
// logWriterSentInterval controls how often logs are sent to external systems // logWriterSentInterval controls how often logs are sent to external systems
// This balances real-time logging with system performance // This balances real-time logging with system performance
logWriterSentInterval = time.Minute logWriterSentInterval = time.Minute
// logWriterInitEndMarker marks the end of initialization logs // logWriterInitEndMarker marks the end of initialization logs
// This helps separate startup logs from runtime logs // This helps separate startup logs from runtime logs
@@ -40,7 +40,7 @@ const (
// logWriterLogEndMarker marks the end of log sections // logWriterLogEndMarker marks the end of log sections
// This provides clear boundaries for log parsing and analysis // This provides clear boundaries for log parsing and analysis
logWriterLogEndMarker = "\n\n=== LOG_END ===\n\n" logWriterLogEndMarker = "\n\n=== LOG_END ===\n\n"
) )
// Custom level encoders that handle NOTICE level // Custom level encoders that handle NOTICE level
@@ -169,7 +169,7 @@ func (p *prog) initInternalLogging(externalCores []zapcore.Core) {
return return
} }
p.initInternalLogWriterOnce.Do(func() { p.initInternalLogWriterOnce.Do(func() {
p.Notice().Msg("internal logging enabled") p.Notice().Msg("Internal logging enabled")
p.internalLogWriter = newLogWriter() p.internalLogWriter = newLogWriter()
p.internalLogSent = time.Now().Add(-logWriterSentInterval) p.internalLogSent = time.Now().Add(-logWriterSentInterval)
p.internalWarnLogWriter = newSmallLogWriter() p.internalWarnLogWriter = newSmallLogWriter()
+5 -5
View File
@@ -84,7 +84,7 @@ func (p *prog) detectLoop(msg *dns.Msg) {
// //
// See: https://thekelleys.org.uk/dnsmasq/docs/dnsmasq-man.html // See: https://thekelleys.org.uk/dnsmasq/docs/dnsmasq-man.html
func (p *prog) checkDnsLoop() { func (p *prog) checkDnsLoop() {
p.Debug().Msg("start checking DNS loop") p.Debug().Msg("Start checking DNS loop")
upstream := make(map[string]*ctrld.UpstreamConfig) upstream := make(map[string]*ctrld.UpstreamConfig)
p.loopMu.Lock() p.loopMu.Lock()
for n, uc := range p.cfg.Upstream { for n, uc := range p.cfg.Upstream {
@@ -93,7 +93,7 @@ func (p *prog) checkDnsLoop() {
} }
// Do not send test query to external upstream. // Do not send test query to external upstream.
if !canBeLocalUpstream(uc.Domain) { if !canBeLocalUpstream(uc.Domain) {
p.Debug().Msgf("skipping external: upstream.%s", n) p.Debug().Msgf("Skipping external: upstream.%s", n)
continue continue
} }
uid := uc.UID() uid := uc.UID()
@@ -112,14 +112,14 @@ func (p *prog) checkDnsLoop() {
} }
resolver, err := ctrld.NewResolver(loggerCtx, uc) resolver, err := ctrld.NewResolver(loggerCtx, uc)
if err != nil { if err != nil {
p.Warn().Err(err).Msgf("could not perform loop check for upstream: %q, endpoint: %q", uc.Name, uc.Endpoint) p.Warn().Err(err).Msgf("Could not perform loop check for upstream: %q, endpoint: %q", uc.Name, uc.Endpoint)
continue continue
} }
if _, err := resolver.Resolve(context.Background(), msg); err != nil { if _, err := resolver.Resolve(context.Background(), msg); err != nil {
p.Warn().Err(err).Msgf("could not send DNS loop check query for upstream: %q, endpoint: %q", uc.Name, uc.Endpoint) p.Warn().Err(err).Msgf("Could not send DNS loop check query for upstream: %q, endpoint: %q", uc.Name, uc.Endpoint)
} }
} }
p.Debug().Msg("end checking DNS loop") p.Debug().Msg("End checking DNS loop")
} }
// checkDnsLoopTicker performs p.checkDnsLoop every minute. // checkDnsLoopTicker performs p.checkDnsLoop every minute.
+3 -3
View File
@@ -136,7 +136,7 @@ func initLoggingWithBackup(doBackup bool) []zapcore.Core {
// Create parent directory if necessary. // Create parent directory if necessary.
// This ensures log files can be created even if the directory doesn't exist // This ensures log files can be created even if the directory doesn't exist
if err := os.MkdirAll(filepath.Dir(logFilePath), 0750); err != nil { if err := os.MkdirAll(filepath.Dir(logFilePath), 0750); err != nil {
mainLog.Load().Error().Msgf("failed to create log path: %v", err) mainLog.Load().Error().Msgf("Failed to create log path: %v", err)
os.Exit(1) os.Exit(1)
} }
@@ -147,7 +147,7 @@ func initLoggingWithBackup(doBackup bool) []zapcore.Core {
// Backup old log file with .1 suffix. // Backup old log file with .1 suffix.
// This prevents log file corruption during rotation // This prevents log file corruption during rotation
if err := os.Rename(logFilePath, logFilePath+oldLogSuffix); err != nil && !os.IsNotExist(err) { if err := os.Rename(logFilePath, logFilePath+oldLogSuffix); err != nil && !os.IsNotExist(err) {
mainLog.Load().Error().Msgf("could not backup old log file: %v", err) mainLog.Load().Error().Msgf("Could not backup old log file: %v", err)
} else { } else {
// Backup was created, set flags for truncating old log file. // Backup was created, set flags for truncating old log file.
// This ensures a clean start for the new log file // This ensures a clean start for the new log file
@@ -156,7 +156,7 @@ func initLoggingWithBackup(doBackup bool) []zapcore.Core {
} }
logFile, err := openLogFile(logFilePath, flags) logFile, err := openLogFile(logFilePath, flags)
if err != nil { if err != nil {
mainLog.Load().Error().Msgf("failed to create log file: %v", err) mainLog.Load().Error().Msgf("Failed to create log file: %v", err)
os.Exit(1) os.Exit(1)
} }
writers = append(writers, logFile) writers = append(writers, logFile)
+4 -4
View File
@@ -122,7 +122,7 @@ func (p *prog) runMetricsServer(ctx context.Context, reloadCh chan struct{}) {
addr := p.cfg.Service.MetricsListener addr := p.cfg.Service.MetricsListener
ms, err := newMetricsServer(addr, reg) ms, err := newMetricsServer(addr, reg)
if err != nil { if err != nil {
mainLog.Load().Warn().Err(err).Msg("could not create new metrics server") mainLog.Load().Warn().Err(err).Msg("Could not create new metrics server")
return return
} }
// Only start listener address if defined. // Only start listener address if defined.
@@ -137,9 +137,9 @@ func (p *prog) runMetricsServer(ctx context.Context, reloadCh chan struct{}) {
statsVersion.WithLabelValues(commit, runtime.Version(), curVersion()).Inc() statsVersion.WithLabelValues(commit, runtime.Version(), curVersion()).Inc()
reg.MustRegister(statsTimeStart) reg.MustRegister(statsTimeStart)
statsTimeStart.Set(float64(time.Now().Unix())) statsTimeStart.Set(float64(time.Now().Unix()))
mainLog.Load().Debug().Msgf("starting metrics server on: %s", addr) mainLog.Load().Debug().Msgf("Starting metrics server on: %s", addr)
if err := ms.start(); err != nil { if err := ms.start(); err != nil {
mainLog.Load().Warn().Err(err).Msg("could not start metrics server") mainLog.Load().Warn().Err(err).Msg("Could not start metrics server")
return return
} }
} }
@@ -151,7 +151,7 @@ func (p *prog) runMetricsServer(ctx context.Context, reloadCh chan struct{}) {
} }
if err := ms.stop(); err != nil { if err := ms.stop(); err != nil {
mainLog.Load().Warn().Err(err).Msg("could not stop metrics server") mainLog.Load().Warn().Err(err).Msg("Could not stop metrics server")
return return
} }
} }
+1 -1
View File
@@ -55,7 +55,7 @@ func virtualInterfaces(ctx context.Context) map[string]struct{} {
s := make(map[string]struct{}) s := make(map[string]struct{})
entries, err := os.ReadDir("/sys/devices/virtual/net") entries, err := os.ReadDir("/sys/devices/virtual/net")
if err != nil { if err != nil {
logger.Error().Err(err).Msg("failed to read /sys/devices/virtual/net") logger.Error().Err(err).Msg("Failed to read /sys/devices/virtual/net")
return nil return nil
} }
for _, entry := range entries { for _, entry := range entries {
+2 -2
View File
@@ -14,7 +14,7 @@ func (p *prog) watchLinkState(ctx context.Context) {
done := make(chan struct{}) done := make(chan struct{})
defer close(done) defer close(done)
if err := netlink.LinkSubscribe(ch, done); err != nil { if err := netlink.LinkSubscribe(ch, done); err != nil {
p.Warn().Err(err).Msg("could not subscribe link") p.Warn().Err(err).Msg("Could not subscribe link")
return return
} }
for { for {
@@ -26,7 +26,7 @@ func (p *prog) watchLinkState(ctx context.Context) {
continue continue
} }
if lu.Change&unix.IFF_UP != 0 { if lu.Change&unix.IFF_UP != 0 {
p.Debug().Msgf("link state changed, re-bootstrapping") p.Debug().Msgf("Link state changed, re-bootstrapping")
for _, uc := range p.cfg.Upstream { for _, uc := range p.cfg.Upstream {
uc.ReBootstrap(ctrld.LoggerCtx(ctx, p.logger.Load())) uc.ReBootstrap(ctrld.LoggerCtx(ctx, p.logger.Load()))
} }
+6 -6
View File
@@ -43,12 +43,12 @@ func (p *prog) setupNetworkManager() error {
return nil return nil
} }
if err != nil { if err != nil {
p.Debug().Err(err).Msg("could not write NetworkManager ctrld config file") p.Debug().Err(err).Msg("Could not write NetworkManager ctrld config file")
return err return err
} }
p.reloadNetworkManager() p.reloadNetworkManager()
p.Debug().Msg("setup NetworkManager done") p.Debug().Msg("Setup NetworkManager done")
return nil return nil
} }
@@ -62,12 +62,12 @@ func (p *prog) restoreNetworkManager() error {
return nil return nil
} }
if err != nil { if err != nil {
p.Debug().Err(err).Msg("could not remove NetworkManager ctrld config file") p.Debug().Err(err).Msg("Could not remove NetworkManager ctrld config file")
return err return err
} }
p.reloadNetworkManager() p.reloadNetworkManager()
p.Debug().Msg("restore NetworkManager done") p.Debug().Msg("Restore NetworkManager done")
return nil return nil
} }
@@ -76,14 +76,14 @@ func (p *prog) reloadNetworkManager() {
defer cancel() defer cancel()
conn, err := dbus.NewSystemConnectionContext(ctx) conn, err := dbus.NewSystemConnectionContext(ctx)
if err != nil { if err != nil {
p.Error().Err(err).Msg("could not create new system connection") p.Error().Err(err).Msg("Could not create new system connection")
return return
} }
defer conn.Close() defer conn.Close()
waitCh := make(chan string) waitCh := make(chan string)
if _, err := conn.ReloadUnitContext(ctx, nmSystemdUnitName, "ignore-dependencies", waitCh); err != nil { if _, err := conn.ReloadUnitContext(ctx, nmSystemdUnitName, "ignore-dependencies", waitCh); err != nil {
p.Debug().Err(err).Msg("could not reload NetworkManager") p.Debug().Err(err).Msg("Could not reload NetworkManager")
return return
} }
<-waitCh <-waitCh
+1 -1
View File
@@ -13,7 +13,7 @@ func generateNextDNSConfig(uid string) {
if uid == "" { if uid == "" {
return return
} }
mainLog.Load().Info().Msg("generating ctrld config for NextDNS resolver") mainLog.Load().Info().Msg("Generating ctrld config for NextDNS resolver")
cfg = ctrld.Config{ cfg = ctrld.Config{
Listener: map[string]*ctrld.ListenerConfig{ Listener: map[string]*ctrld.ListenerConfig{
"0": { "0": {
+2 -2
View File
@@ -17,7 +17,7 @@ func allocateIP(ip string) error {
mainLog.Load().Debug().Str("ip", ip).Msg("Allocating IP address") mainLog.Load().Debug().Str("ip", ip).Msg("Allocating IP address")
cmd := exec.Command("ifconfig", "lo0", "alias", ip, "up") cmd := exec.Command("ifconfig", "lo0", "alias", ip, "up")
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
mainLog.Load().Error().Err(err).Msg("allocateIP failed") mainLog.Load().Error().Err(err).Msg("AllocateIP failed")
return err return err
} }
mainLog.Load().Debug().Str("ip", ip).Msg("IP address allocated successfully") mainLog.Load().Debug().Str("ip", ip).Msg("IP address allocated successfully")
@@ -29,7 +29,7 @@ func deAllocateIP(ip string) error {
mainLog.Load().Debug().Str("ip", ip).Msg("Deallocating IP address") mainLog.Load().Debug().Str("ip", ip).Msg("Deallocating IP address")
cmd := exec.Command("ifconfig", "lo0", "-alias", ip) cmd := exec.Command("ifconfig", "lo0", "-alias", ip)
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
mainLog.Load().Error().Err(err).Msg("deAllocateIP failed") mainLog.Load().Error().Err(err).Msg("DeAllocateIP failed")
return err return err
} }
mainLog.Load().Debug().Str("ip", ip).Msg("IP address deallocated successfully") mainLog.Load().Debug().Str("ip", ip).Msg("IP address deallocated successfully")
+5 -5
View File
@@ -49,7 +49,7 @@ func setDNS(iface *net.Interface, nameservers []string) error {
r, err := dns.NewOSConfigurator(logf, &health.Tracker{}, &controlknobs.Knobs{}, iface.Name) r, err := dns.NewOSConfigurator(logf, &health.Tracker{}, &controlknobs.Knobs{}, iface.Name)
if err != nil { if err != nil {
mainLog.Load().Error().Err(err).Msg("failed to create DNS OS configurator") mainLog.Load().Error().Err(err).Msg("Failed to create DNS OS configurator")
return err return err
} }
@@ -65,11 +65,11 @@ func setDNS(iface *net.Interface, nameservers []string) error {
if sds, err := searchDomains(); err == nil { if sds, err := searchDomains(); err == nil {
osConfig.SearchDomains = sds osConfig.SearchDomains = sds
} else { } else {
mainLog.Load().Debug().Err(err).Msg("failed to get search domains list") mainLog.Load().Debug().Err(err).Msg("Failed to get search domains list")
} }
if err := r.SetDNS(osConfig); err != nil { if err := r.SetDNS(osConfig); err != nil {
mainLog.Load().Error().Err(err).Msg("failed to set DNS") mainLog.Load().Error().Err(err).Msg("Failed to set DNS")
return err return err
} }
@@ -88,12 +88,12 @@ func resetDNS(iface *net.Interface) error {
r, err := dns.NewOSConfigurator(logf, &health.Tracker{}, &controlknobs.Knobs{}, iface.Name) r, err := dns.NewOSConfigurator(logf, &health.Tracker{}, &controlknobs.Knobs{}, iface.Name)
if err != nil { if err != nil {
mainLog.Load().Error().Err(err).Msg("failed to create DNS OS configurator") mainLog.Load().Error().Err(err).Msg("Failed to create DNS OS configurator")
return err return err
} }
if err := r.Close(); err != nil { if err := r.Close(); err != nil {
mainLog.Load().Error().Err(err).Msg("failed to rollback DNS setting") mainLog.Load().Error().Err(err).Msg("Failed to rollback DNS setting")
return err return err
} }
+8 -8
View File
@@ -36,7 +36,7 @@ func allocateIP(ip string) error {
mainLog.Load().Debug().Str("ip", ip).Msg("Allocating IP address") mainLog.Load().Debug().Str("ip", ip).Msg("Allocating IP address")
cmd := exec.Command("ip", "a", "add", ip+"/24", "dev", "lo") cmd := exec.Command("ip", "a", "add", ip+"/24", "dev", "lo")
if out, err := cmd.CombinedOutput(); err != nil { if out, err := cmd.CombinedOutput(); err != nil {
mainLog.Load().Error().Err(err).Msgf("allocateIP failed: %s", string(out)) mainLog.Load().Error().Err(err).Msgf("AllocateIP failed: %s", string(out))
return err return err
} }
mainLog.Load().Debug().Str("ip", ip).Msg("IP address allocated successfully") mainLog.Load().Debug().Str("ip", ip).Msg("IP address allocated successfully")
@@ -47,7 +47,7 @@ func deAllocateIP(ip string) error {
mainLog.Load().Debug().Str("ip", ip).Msg("Deallocating IP address") mainLog.Load().Debug().Str("ip", ip).Msg("Deallocating IP address")
cmd := exec.Command("ip", "a", "del", ip+"/24", "dev", "lo") cmd := exec.Command("ip", "a", "del", ip+"/24", "dev", "lo")
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
mainLog.Load().Error().Err(err).Msg("deAllocateIP failed") mainLog.Load().Error().Err(err).Msg("DeAllocateIP failed")
return err return err
} }
mainLog.Load().Debug().Str("ip", ip).Msg("IP address deallocated successfully") mainLog.Load().Debug().Str("ip", ip).Msg("IP address deallocated successfully")
@@ -66,7 +66,7 @@ func setDNS(iface *net.Interface, nameservers []string) error {
r, err := dns.NewOSConfigurator(logf, &health.Tracker{}, &controlknobs.Knobs{}, iface.Name) r, err := dns.NewOSConfigurator(logf, &health.Tracker{}, &controlknobs.Knobs{}, iface.Name)
if err != nil { if err != nil {
mainLog.Load().Error().Err(err).Msg("failed to create DNS OS configurator") mainLog.Load().Error().Err(err).Msg("Failed to create dns os configurator")
return err return err
} }
@@ -82,7 +82,7 @@ func setDNS(iface *net.Interface, nameservers []string) error {
if sds, err := searchDomains(); err == nil { if sds, err := searchDomains(); err == nil {
osConfig.SearchDomains = sds osConfig.SearchDomains = sds
} else { } else {
mainLog.Load().Debug().Err(err).Msg("failed to get search domains list") mainLog.Load().Debug().Err(err).Msg("Failed to get search domains list")
} }
trySystemdResolve := false trySystemdResolve := false
if err := r.SetDNS(osConfig); err != nil { if err := r.SetDNS(osConfig); err != nil {
@@ -149,7 +149,7 @@ func resetDNS(iface *net.Interface) (err error) {
if r, oerr := dns.NewOSConfigurator(logf, &health.Tracker{}, &controlknobs.Knobs{}, iface.Name); oerr == nil { if r, oerr := dns.NewOSConfigurator(logf, &health.Tracker{}, &controlknobs.Knobs{}, iface.Name); oerr == nil {
_ = r.SetDNS(dns.OSConfig{}) _ = r.SetDNS(dns.OSConfig{})
if err := r.Close(); err != nil { if err := r.Close(); err != nil {
mainLog.Load().Error().Err(err).Msg("failed to rollback DNS setting") mainLog.Load().Error().Err(err).Msg("Failed to rollback dns setting")
return return
} }
err = nil err = nil
@@ -177,18 +177,18 @@ func resetDNS(iface *net.Interface) (err error) {
} }
// TODO(cuonglm): handle DHCPv6 properly. // TODO(cuonglm): handle DHCPv6 properly.
mainLog.Load().Debug().Msg("checking for IPv6 availability") mainLog.Load().Debug().Msg("Checking for ipv6 availability")
if ctrldnet.IPv6Available(ctx) { if ctrldnet.IPv6Available(ctx) {
c := client6.NewClient() c := client6.NewClient()
conversation, err := c.Exchange(iface.Name) conversation, err := c.Exchange(iface.Name)
if err != nil && !errAddrInUse(err) { if err != nil && !errAddrInUse(err) {
mainLog.Load().Debug().Err(err).Msg("could not exchange DHCPv6") mainLog.Load().Debug().Err(err).Msg("Could not exchange dhcpv6")
} }
for _, packet := range conversation { for _, packet := range conversation {
if packet.Type() == dhcpv6.MessageTypeReply { if packet.Type() == dhcpv6.MessageTypeReply {
msg, err := packet.GetInnerMessage() msg, err := packet.GetInnerMessage()
if err != nil { if err != nil {
mainLog.Load().Debug().Err(err).Msg("could not get inner DHCPv6 message") mainLog.Load().Debug().Err(err).Msg("Could not get inner dhcpv6 message")
return nil return nil
} }
nameservers := msg.Options.DNS() nameservers := msg.Options.DNS()
+10 -10
View File
@@ -111,24 +111,24 @@ func restoreDNS(iface *net.Interface) (err error) {
} }
if len(v4ns) > 0 { if len(v4ns) > 0 {
mainLog.Load().Debug().Msgf("restoring IPv4 static DNS for interface %q: %v", iface.Name, v4ns) mainLog.Load().Debug().Msgf("Restoring IPv4 static DNS for interface %q: %v", iface.Name, v4ns)
if err := setDNS(iface, v4ns); err != nil { if err := setDNS(iface, v4ns); err != nil {
return fmt.Errorf("restoreDNS (IPv4): %w", err) return fmt.Errorf("restoreDNS (IPv4): %w", err)
} }
} else { } else {
mainLog.Load().Debug().Msgf("restoring IPv4 DHCP for interface %q", iface.Name) mainLog.Load().Debug().Msgf("Restoring IPv4 DHCP for interface %q", iface.Name)
if err := luid.SetDNS(windows.AF_INET, nil, nil); err != nil { if err := luid.SetDNS(windows.AF_INET, nil, nil); err != nil {
return fmt.Errorf("restoreDNS (IPv4 clear): %w", err) return fmt.Errorf("restoreDNS (IPv4 clear): %w", err)
} }
} }
if len(v6ns) > 0 { if len(v6ns) > 0 {
mainLog.Load().Debug().Msgf("restoring IPv6 static DNS for interface %q: %v", iface.Name, v6ns) mainLog.Load().Debug().Msgf("Restoring IPv6 static DNS for interface %q: %v", iface.Name, v6ns)
if err := setDNS(iface, v6ns); err != nil { if err := setDNS(iface, v6ns); err != nil {
return fmt.Errorf("restoreDNS (IPv6): %w", err) return fmt.Errorf("restoreDNS (IPv6): %w", err)
} }
} else { } else {
mainLog.Load().Debug().Msgf("restoring IPv6 DHCP for interface %q", iface.Name) mainLog.Load().Debug().Msgf("Restoring IPv6 DHCP for interface %q", iface.Name)
if err := luid.SetDNS(windows.AF_INET6, nil, nil); err != nil { if err := luid.SetDNS(windows.AF_INET6, nil, nil); err != nil {
return fmt.Errorf("restoreDNS (IPv6 clear): %w", err) return fmt.Errorf("restoreDNS (IPv6 clear): %w", err)
} }
@@ -141,12 +141,12 @@ func restoreDNS(iface *net.Interface) (err error) {
func currentDNS(iface *net.Interface) []string { func currentDNS(iface *net.Interface) []string {
luid, err := winipcfg.LUIDFromIndex(uint32(iface.Index)) luid, err := winipcfg.LUIDFromIndex(uint32(iface.Index))
if err != nil { if err != nil {
mainLog.Load().Error().Err(err).Msg("failed to get interface LUID") mainLog.Load().Error().Err(err).Msg("Failed to get interface LUID")
return nil return nil
} }
nameservers, err := luid.DNS() nameservers, err := luid.DNS()
if err != nil { if err != nil {
mainLog.Load().Error().Err(err).Msg("failed to get interface DNS") mainLog.Load().Error().Err(err).Msg("Failed to get interface DNS")
return nil return nil
} }
ns := make([]string, 0, len(nameservers)) ns := make([]string, 0, len(nameservers))
@@ -174,7 +174,7 @@ func currentStaticDNS(iface *net.Interface) ([]string, error) {
interfaceKeyPath := path + guid.String() interfaceKeyPath := path + guid.String()
k, err := registry.OpenKey(registry.LOCAL_MACHINE, interfaceKeyPath, registry.QUERY_VALUE) k, err := registry.OpenKey(registry.LOCAL_MACHINE, interfaceKeyPath, registry.QUERY_VALUE)
if err != nil { if err != nil {
mainLog.Load().Debug().Err(err).Msgf("failed to open registry key %q for interface %q; trying next key", interfaceKeyPath, iface.Name) mainLog.Load().Debug().Err(err).Msgf("Failed to open registry key %q for interface %q; trying next key", interfaceKeyPath, iface.Name)
continue continue
} }
func() { func() {
@@ -182,11 +182,11 @@ func currentStaticDNS(iface *net.Interface) ([]string, error) {
for _, keyName := range []string{"NameServer", "ProfileNameServer"} { for _, keyName := range []string{"NameServer", "ProfileNameServer"} {
value, _, err := k.GetStringValue(keyName) value, _, err := k.GetStringValue(keyName)
if err != nil && !errors.Is(err, registry.ErrNotExist) { if err != nil && !errors.Is(err, registry.ErrNotExist) {
mainLog.Load().Debug().Err(err).Msgf("error reading %s registry key", keyName) mainLog.Load().Debug().Err(err).Msgf("Error reading %s registry key", keyName)
continue continue
} }
if len(value) > 0 { if len(value) > 0 {
mainLog.Load().Debug().Msgf("found static DNS for interface %q: %s", iface.Name, value) mainLog.Load().Debug().Msgf("Found static DNS for interface %q: %s", iface.Name, value)
parsed := parseDNSServers(value) parsed := parseDNSServers(value)
for _, pns := range parsed { for _, pns := range parsed {
if !slices.Contains(ns, pns) { if !slices.Contains(ns, pns) {
@@ -198,7 +198,7 @@ func currentStaticDNS(iface *net.Interface) ([]string, error) {
}() }()
} }
if len(ns) == 0 { if len(ns) == 0 {
mainLog.Load().Debug().Msgf("no static DNS values found for interface %q", iface.Name) mainLog.Load().Debug().Msgf("No static DNS values found for interface %q", iface.Name)
} }
return ns, nil return ns, nil
} }
+88 -88
View File
@@ -165,9 +165,9 @@ func (p *prog) runWait() {
var newCfg *ctrld.Config var newCfg *ctrld.Config
select { select {
case sig := <-reloadSigCh: case sig := <-reloadSigCh:
p.Notice().Msgf("got signal: %s, reloading...", sig.String()) p.Notice().Msgf("Got signal: %s, reloading...", sig.String())
case <-p.reloadCh: case <-p.reloadCh:
p.Notice().Msg("reloading...") p.Notice().Msg("Reloading...")
case apiCfg := <-p.apiReloadCh: case apiCfg := <-p.apiReloadCh:
newCfg = apiCfg newCfg = apiCfg
case <-p.stopCh: case <-p.stopCh:
@@ -190,18 +190,18 @@ func (p *prog) runWait() {
} }
v.SetConfigFile(confFile) v.SetConfigFile(confFile)
if err := v.ReadInConfig(); err != nil { if err := v.ReadInConfig(); err != nil {
p.Error().Err(err).Msg("could not read new config") p.Error().Err(err).Msg("Could not read new config")
waitOldRunDone() waitOldRunDone()
continue continue
} }
if err := v.Unmarshal(&newCfg); err != nil { if err := v.Unmarshal(&newCfg); err != nil {
p.Error().Err(err).Msg("could not unmarshal new config") p.Error().Err(err).Msg("Could not unmarshal new config")
waitOldRunDone() waitOldRunDone()
continue continue
} }
if cdUID != "" { if cdUID != "" {
if rc, err := processCDFlags(newCfg); err != nil { if rc, err := processCDFlags(newCfg); err != nil {
p.Error().Err(err).Msg("could not fetch ControlD config") p.Error().Err(err).Msg("Could not fetch controld config")
waitOldRunDone() waitOldRunDone()
continue continue
} else { } else {
@@ -231,29 +231,29 @@ func (p *prog) runWait() {
} }
} }
if err := validateConfig(newCfg); err != nil { if err := validateConfig(newCfg); err != nil {
p.Error().Err(err).Msg("invalid config") p.Error().Err(err).Msg("Invalid config")
continue continue
} }
addExtraSplitDnsRule(newCfg) addExtraSplitDnsRule(newCfg)
if err := writeConfigFile(newCfg); err != nil { if err := writeConfigFile(newCfg); err != nil {
p.Error().Err(err).Msg("could not write new config") p.Error().Err(err).Msg("Could not write new config")
} }
// This needs to be done here, otherwise, the DNS handler may observe an invalid // This needs to be done here, otherwise, the DNS handler may observe an invalid
// upstream config because its initialization function have not been called yet. // upstream config because its initialization function have not been called yet.
p.Debug().Msg("setup upstream with new config") p.Debug().Msg("Setup upstream with new config")
p.setupUpstream(newCfg) p.setupUpstream(newCfg)
p.mu.Lock() p.mu.Lock()
*p.cfg = *newCfg *p.cfg = *newCfg
p.mu.Unlock() p.mu.Unlock()
p.Notice().Msg("reloading config successfully") p.Notice().Msg("Reloading config successfully")
select { select {
case p.reloadDoneCh <- struct{}{}: case p.reloadDoneCh <- struct{}{}:
p.Debug().Msg("reload done signal sent") p.Debug().Msg("Reload done signal sent")
default: default:
} }
} }
@@ -272,7 +272,7 @@ func (p *prog) postRun() {
if !service.Interactive() { if !service.Interactive() {
p.resetDNS(false, false) p.resetDNS(false, false)
ns := ctrld.InitializeOsResolver(ctrld.LoggerCtx(context.Background(), p.logger.Load()), false) ns := ctrld.InitializeOsResolver(ctrld.LoggerCtx(context.Background(), p.logger.Load()), false)
p.Debug().Msgf("initialized OS resolver with nameservers: %v", ns) p.Debug().Msgf("Initialized os resolver with nameservers: %v", ns)
p.setDNS() p.setDNS()
p.csSetDnsDone <- struct{}{} p.csSetDnsDone <- struct{}{}
close(p.csSetDnsDone) close(p.csSetDnsDone)
@@ -290,7 +290,7 @@ func (p *prog) apiConfigReload() {
defer ticker.Stop() defer ticker.Stop()
logger := p.logger.Load().With().Str("mode", "api-reload") logger := p.logger.Load().With().Str("mode", "api-reload")
logger.Debug().Msg("starting custom config reload timer") logger.Debug().Msg("Starting custom config reload timer")
lastUpdated := time.Now().Unix() lastUpdated := time.Now().Unix()
curVerStr := curVersion() curVerStr := curVersion()
curVer, err := semver.NewVersion(curVerStr) curVer, err := semver.NewVersion(curVerStr)
@@ -300,7 +300,7 @@ func (p *prog) apiConfigReload() {
if err != nil { if err != nil {
l = l.Err(err) l = l.Err(err)
} }
l.Msgf("current version is not stable, skipping self-upgrade: %s", curVerStr) l.Msgf("Current version is not stable, skipping self-upgrade: %s", curVerStr)
} }
doReloadApiConfig := func(forced bool, logger *ctrld.Logger) { doReloadApiConfig := func(forced bool, logger *ctrld.Logger) {
@@ -308,7 +308,7 @@ func (p *prog) apiConfigReload() {
resolverConfig, err := controld.FetchResolverConfig(loggerCtx, cdUID, appVersion, cdDev) resolverConfig, err := controld.FetchResolverConfig(loggerCtx, cdUID, appVersion, cdDev)
selfUninstallCheck(err, p, logger) selfUninstallCheck(err, p, logger)
if err != nil { if err != nil {
logger.Warn().Err(err).Msg("could not fetch resolver config") logger.Warn().Err(err).Msg("Could not fetch resolver config")
return return
} }
@@ -322,9 +322,9 @@ func (p *prog) apiConfigReload() {
curDeactivationPin := cdDeactivationPin.Load() curDeactivationPin := cdDeactivationPin.Load()
switch { switch {
case curDeactivationPin != defaultDeactivationPin: case curDeactivationPin != defaultDeactivationPin:
logger.Debug().Msg("saving deactivation pin") logger.Debug().Msg("Saving deactivation pin")
case curDeactivationPin != newDeactivationPin: case curDeactivationPin != newDeactivationPin:
logger.Debug().Msg("update deactivation pin") logger.Debug().Msg("Update deactivation pin")
} }
cdDeactivationPin.Store(newDeactivationPin) cdDeactivationPin.Store(newDeactivationPin)
} else { } else {
@@ -347,7 +347,7 @@ func (p *prog) apiConfigReload() {
} }
if noCustomConfig && !noExcludeListChanged { if noCustomConfig && !noExcludeListChanged {
logger.Debug().Msg("exclude list changes detected, reloading...") logger.Debug().Msg("Exclude list changes detected, reloading...")
p.apiReloadCh <- nil p.apiReloadCh <- nil
return return
} }
@@ -362,16 +362,16 @@ func (p *prog) apiConfigReload() {
cfgErr = validateConfig(cfg) cfgErr = validateConfig(cfg)
} }
if cfgErr != nil { if cfgErr != nil {
logger.Warn().Err(err).Msg("skipping invalid custom config") logger.Warn().Err(err).Msg("Skipping invalid custom config")
if _, err := controld.UpdateCustomLastFailed(loggerCtx, cdUID, appVersion, cdDev, true); err != nil { if _, err := controld.UpdateCustomLastFailed(loggerCtx, cdUID, appVersion, cdDev, true); err != nil {
logger.Error().Err(err).Msg("could not mark custom last update failed") logger.Error().Err(err).Msg("Could not mark custom last update failed")
} }
return return
} }
logger.Debug().Msg("custom config changes detected, reloading...") logger.Debug().Msg("Custom config changes detected, reloading...")
p.apiReloadCh <- cfg p.apiReloadCh <- cfg
} else { } else {
logger.Debug().Msg("custom config does not change") logger.Debug().Msg("Custom config does not change")
} }
} }
for { for {
@@ -396,14 +396,14 @@ func (p *prog) setupUpstream(cfg *ctrld.Config) {
sdns := uc.Type == ctrld.ResolverTypeSDNS sdns := uc.Type == ctrld.ResolverTypeSDNS
uc.Init(loggerCtx) uc.Init(loggerCtx)
if sdns { if sdns {
p.Debug().Msgf("initialized DNS Stamps with endpoint: %s, type: %s", uc.Endpoint, uc.Type) p.Debug().Msgf("Initialized dns stamps with endpoint: %s, type: %s", uc.Endpoint, uc.Type)
} }
isControlDUpstream = isControlDUpstream || uc.IsControlD() isControlDUpstream = isControlDUpstream || uc.IsControlD()
if uc.BootstrapIP == "" { if uc.BootstrapIP == "" {
uc.SetupBootstrapIP(ctrld.LoggerCtx(context.Background(), p.logger.Load())) uc.SetupBootstrapIP(ctrld.LoggerCtx(context.Background(), p.logger.Load()))
p.Info().Msgf("bootstrap IPs for upstream.%s: %q", n, uc.BootstrapIPs()) p.Info().Msgf("Bootstrap ips for upstream.%s: %q", n, uc.BootstrapIPs())
} else { } else {
p.Info().Str("bootstrap_ip", uc.BootstrapIP).Msgf("using bootstrap IP for upstream.%s", n) p.Info().Str("bootstrap_ip", uc.BootstrapIP).Msgf("Using bootstrap ip for upstream.%s", n)
} }
uc.SetCertPool(rootCertPool) uc.SetCertPool(rootCertPool)
go uc.Ping(loggerCtx) go uc.Ping(loggerCtx)
@@ -444,9 +444,9 @@ func (p *prog) run(reload bool, reloadCh chan struct{}) {
p.csSetDnsDone = make(chan struct{}, 1) p.csSetDnsDone = make(chan struct{}, 1)
p.registerControlServerHandler() p.registerControlServerHandler()
if err := p.cs.start(); err != nil { if err := p.cs.start(); err != nil {
p.Warn().Err(err).Msg("could not start control server") p.Warn().Err(err).Msg("Could not start control server")
} }
p.Debug().Msgf("control server started: %s", p.cs.addr) p.Debug().Msgf("Control server started: %s", p.cs.addr)
} }
} }
p.onStartedDone = make(chan struct{}) p.onStartedDone = make(chan struct{})
@@ -458,7 +458,7 @@ func (p *prog) run(reload bool, reloadCh chan struct{}) {
if p.cfg.Service.CacheEnable { if p.cfg.Service.CacheEnable {
cacher, err := dnscache.NewLRUCache(p.cfg.Service.CacheSize) cacher, err := dnscache.NewLRUCache(p.cfg.Service.CacheSize)
if err != nil { if err != nil {
p.Error().Err(err).Msg("failed to create cacher, caching is disabled") p.Error().Err(err).Msg("Failed to create cacher, caching is disabled")
} else { } else {
p.cache = cacher p.cache = cacher
p.cacheFlushDomainsMap = make(map[string]struct{}, 256) p.cacheFlushDomainsMap = make(map[string]struct{}, 256)
@@ -475,7 +475,7 @@ func (p *prog) run(reload bool, reloadCh chan struct{}) {
for _, cidr := range nc.Cidrs { for _, cidr := range nc.Cidrs {
_, ipNet, err := net.ParseCIDR(cidr) _, ipNet, err := net.ParseCIDR(cidr)
if err != nil { if err != nil {
p.Error().Err(err).Str("network", nc.Name).Str("cidr", cidr).Msg("invalid cidr") p.Error().Err(err).Str("network", nc.Name).Str("cidr", cidr).Msg("Invalid cidr")
continue continue
} }
nc.IPNets = append(nc.IPNets, ipNet) nc.IPNets = append(nc.IPNets, ipNet)
@@ -528,17 +528,17 @@ func (p *prog) run(reload bool, reloadCh chan struct{}) {
listenerConfig := p.cfg.Listener[listenerNum] listenerConfig := p.cfg.Listener[listenerNum]
upstreamConfig := p.cfg.Upstream[listenerNum] upstreamConfig := p.cfg.Upstream[listenerNum]
if upstreamConfig == nil { if upstreamConfig == nil {
p.Warn().Msgf("no default upstream for: [listener.%s]", listenerNum) p.Warn().Msgf("No default upstream for: [listener.%s]", listenerNum)
} }
addr := net.JoinHostPort(listenerConfig.IP, strconv.Itoa(listenerConfig.Port)) addr := net.JoinHostPort(listenerConfig.IP, strconv.Itoa(listenerConfig.Port))
p.Info().Msgf("starting DNS server on listener.%s: %s", listenerNum, addr) p.Info().Msgf("Starting dns server on listener.%s: %s", listenerNum, addr)
// serveCtx uses Background() context so listeners survive between reloads. // serveCtx uses Background() context so listeners survive between reloads.
// Changes to listeners config require a service restart, not just reload. // Changes to listeners config require a service restart, not just reload.
serveCtx := context.Background() serveCtx := context.Background()
if err := p.serveDNS(serveCtx, listenerNum); err != nil { if err := p.serveDNS(serveCtx, listenerNum); err != nil {
p.Fatal().Err(err).Msgf("unable to start dns proxy on listener.%s", listenerNum) p.Fatal().Err(err).Msgf("Unable to start dns proxy on listener.%s", listenerNum)
} }
p.Debug().Msgf("end of serveDNS listener.%s: %s", listenerNum, addr) p.Debug().Msgf("End of serveDNS listener.%s: %s", listenerNum, addr)
}(listenerNum) }(listenerNum)
} }
go func() { go func() {
@@ -599,7 +599,7 @@ func (p *prog) setupClientInfoDiscover() {
selfIP := p.defaultRouteIP() selfIP := p.defaultRouteIP()
p.ciTable = clientinfo.NewTable(&cfg, selfIP, cdUID, p.ptrNameservers, p.logger.Load()) p.ciTable = clientinfo.NewTable(&cfg, selfIP, cdUID, p.ptrNameservers, p.logger.Load())
if leaseFile := p.cfg.Service.DHCPLeaseFile; leaseFile != "" { if leaseFile := p.cfg.Service.DHCPLeaseFile; leaseFile != "" {
p.Debug().Msgf("watching custom lease file: %s", leaseFile) p.Debug().Msgf("Watching custom lease file: %s", leaseFile)
format := ctrld.LeaseFileFormat(p.cfg.Service.DHCPLeaseFileFormat) format := ctrld.LeaseFileFormat(p.cfg.Service.DHCPLeaseFileFormat)
p.ciTable.AddLeaseFile(leaseFile, format) p.ciTable.AddLeaseFile(leaseFile, format)
} }
@@ -618,16 +618,16 @@ func (p *prog) metricsEnabled() bool {
func (p *prog) Stop(_ service.Service) error { func (p *prog) Stop(_ service.Service) error {
p.stopDnsWatchers() p.stopDnsWatchers()
p.Debug().Msg("dns watchers stopped") p.Debug().Msg("Dns watchers stopped")
for _, f := range p.onStopped { for _, f := range p.onStopped {
f() f()
} }
p.Debug().Msg("finish running onStopped functions") p.Debug().Msg("Finish running onStopped functions")
defer func() { defer func() {
p.Info().Msg("Service stopped") p.Info().Msg("Service stopped")
}() }()
if err := p.deAllocateIP(); err != nil { if err := p.deAllocateIP(); err != nil {
p.Error().Err(err).Msg("de-allocate ip failed") p.Error().Err(err).Msg("De-allocate ip failed")
return err return err
} }
if deactivationPinSet() { if deactivationPinSet() {
@@ -639,16 +639,16 @@ func (p *prog) Stop(_ service.Service) error {
// No valid pin code was checked, that mean we are stopping // No valid pin code was checked, that mean we are stopping
// because of OS signal sent directly from someone else. // because of OS signal sent directly from someone else.
// In this case, restarting ctrld service by ourselves. // In this case, restarting ctrld service by ourselves.
p.Debug().Msgf("receiving stopping signal without valid pin code") p.Debug().Msgf("Receiving stopping signal without valid pin code")
p.Debug().Msgf("self restarting ctrld service") p.Debug().Msgf("Self restarting ctrld service")
if exe, err := os.Executable(); err == nil { if exe, err := os.Executable(); err == nil {
cmd := exec.Command(exe, "restart") cmd := exec.Command(exe, "restart")
cmd.SysProcAttr = sysProcAttrForDetachedChildProcess() cmd.SysProcAttr = sysProcAttrForDetachedChildProcess()
if err := cmd.Start(); err != nil { if err := cmd.Start(); err != nil {
p.Error().Err(err).Msg("failed to run self restart command") p.Error().Err(err).Msg("Failed to run self restart command")
} }
} else { } else {
p.Error().Err(err).Msg("failed to self restart ctrld service") p.Error().Err(err).Msg("Failed to self restart ctrld service")
} }
os.Exit(deactivationPinInvalidExitCode) os.Exit(deactivationPinInvalidExitCode)
} }
@@ -780,29 +780,29 @@ func (p *prog) setDnsForRunningIface(nameservers []string) (runningIface *net.In
if newIface != p.runningIface { if newIface != p.runningIface {
p.runningIface = newIface p.runningIface = newIface
logger = p.logger.Load().With().Str("iface", p.runningIface) logger = p.logger.Load().With().Str("iface", p.runningIface)
logger.Info().Msg("switched to new interface") logger.Info().Msg("Switched to new interface")
continue continue
} }
logger.Warn().Err(err).Int("attempt", attempt).Msg("could not get interface, retrying...") logger.Warn().Err(err).Int("attempt", attempt).Msg("Could not get interface, retrying...")
time.Sleep(retryDelay) time.Sleep(retryDelay)
continue continue
} }
logger.Error().Err(err).Msg("could not get interface after all attempts") logger.Error().Err(err).Msg("Could not get interface after all attempts")
return return
} }
if err := p.setupNetworkManager(); err != nil { if err := p.setupNetworkManager(); err != nil {
logger.Error().Err(err).Msg("could not patch NetworkManager") logger.Error().Err(err).Msg("Could not patch networkmanager")
return return
} }
runningIface = netIface runningIface = netIface
logger.Debug().Msg("setting DNS for interface") logger.Debug().Msg("Setting dns for interface")
if err := setDNS(netIface, nameservers); err != nil { if err := setDNS(netIface, nameservers); err != nil {
logger.Error().Err(err).Msgf("could not set DNS for interface") logger.Error().Err(err).Msgf("Could not set dns for interface")
return return
} }
logger.Debug().Msg("setting DNS successfully") logger.Debug().Msg("Setting dns successfully")
return return
} }
@@ -831,7 +831,7 @@ func (p *prog) dnsWatchdog(iface *net.Interface, nameservers []string) {
return return
} }
p.Debug().Msg("start DNS settings watchdog") p.Debug().Msg("Start dns settings watchdog")
ns := nameservers ns := nameservers
slices.Sort(ns) slices.Sort(ns)
@@ -842,7 +842,7 @@ func (p *prog) dnsWatchdog(iface *net.Interface, nameservers []string) {
case <-p.dnsWatcherStopCh: case <-p.dnsWatcherStopCh:
return return
case <-p.stopCh: case <-p.stopCh:
p.Debug().Msg("stop dns watchdog") p.Debug().Msg("Stop dns watchdog")
return return
case <-ticker.C: case <-ticker.C:
if p.recoveryRunning.Load() { if p.recoveryRunning.Load() {
@@ -854,7 +854,7 @@ func (p *prog) dnsWatchdog(iface *net.Interface, nameservers []string) {
// currentStaticDNS is an OS-dependent helper that returns the current static DNS. // currentStaticDNS is an OS-dependent helper that returns the current static DNS.
staticDNS, err := currentStaticDNS(iface) staticDNS, err := currentStaticDNS(iface)
if err != nil { if err != nil {
p.Debug().Err(err).Msgf("failed to get static DNS for interface %s", iface.Name) p.Debug().Err(err).Msgf("Failed to get static DNS for interface %s", iface.Name)
} else if len(staticDNS) > 0 { } else if len(staticDNS) > 0 {
//filter out loopback addresses //filter out loopback addresses
staticDNS = slices.DeleteFunc(staticDNS, func(s string) bool { staticDNS = slices.DeleteFunc(staticDNS, func(s string) bool {
@@ -864,12 +864,12 @@ func (p *prog) dnsWatchdog(iface *net.Interface, nameservers []string) {
if len(staticDNS) > 0 && len(ctrld.SavedStaticNameservers(iface)) == 0 { if len(staticDNS) > 0 && len(ctrld.SavedStaticNameservers(iface)) == 0 {
// Save these static DNS values so that they can be restored later. // Save these static DNS values so that they can be restored later.
if err := saveCurrentStaticDNS(iface); err != nil { if err := saveCurrentStaticDNS(iface); err != nil {
p.Debug().Err(err).Msgf("failed to save static DNS for interface %s", iface.Name) p.Debug().Err(err).Msgf("Failed to save static DNS for interface %s", iface.Name)
} }
} }
} }
if err := setDNS(iface, ns); err != nil { if err := setDNS(iface, ns); err != nil {
p.Error().Err(err).Str("iface", iface.Name).Msgf("could not re-apply DNS settings") p.Error().Err(err).Str("iface", iface.Name).Msgf("Could not re-apply DNS settings")
} }
} }
if p.requiredMultiNICsConfig { if p.requiredMultiNICsConfig {
@@ -884,7 +884,7 @@ func (p *prog) dnsWatchdog(iface *net.Interface, nameservers []string) {
// currentStaticDNS is an OS-dependent helper that returns the current static DNS. // currentStaticDNS is an OS-dependent helper that returns the current static DNS.
staticDNS, err := currentStaticDNS(i) staticDNS, err := currentStaticDNS(i)
if err != nil { if err != nil {
p.Debug().Err(err).Msgf("failed to get static DNS for interface %s", i.Name) p.Debug().Err(err).Msgf("Failed to get static DNS for interface %s", i.Name)
} else if len(staticDNS) > 0 { } else if len(staticDNS) > 0 {
//filter out loopback addresses //filter out loopback addresses
staticDNS = slices.DeleteFunc(staticDNS, func(s string) bool { staticDNS = slices.DeleteFunc(staticDNS, func(s string) bool {
@@ -894,15 +894,15 @@ func (p *prog) dnsWatchdog(iface *net.Interface, nameservers []string) {
if len(staticDNS) > 0 && len(ctrld.SavedStaticNameservers(i)) == 0 { if len(staticDNS) > 0 && len(ctrld.SavedStaticNameservers(i)) == 0 {
// Save these static DNS values so that they can be restored later. // Save these static DNS values so that they can be restored later.
if err := saveCurrentStaticDNS(i); err != nil { if err := saveCurrentStaticDNS(i); err != nil {
p.Debug().Err(err).Msgf("failed to save static DNS for interface %s", i.Name) p.Debug().Err(err).Msgf("Failed to save static DNS for interface %s", i.Name)
} }
} }
} }
if err := setDnsIgnoreUnusableInterface(i, nameservers); err != nil { if err := setDnsIgnoreUnusableInterface(i, nameservers); err != nil {
p.Error().Err(err).Str("iface", i.Name).Msgf("could not re-apply DNS settings") p.Error().Err(err).Str("iface", i.Name).Msgf("Could not re-apply DNS settings")
} else { } else {
p.Debug().Msgf("re-applying DNS for interface %q successfully", i.Name) p.Debug().Msgf("Re-applying DNS for interface %q successfully", i.Name)
} }
} }
return nil return nil
@@ -932,18 +932,18 @@ func (p *prog) resetDNS(isStart bool, restoreStatic bool) {
// Otherwise, we restore the saved configuration (if any) or reset to DHCP. // Otherwise, we restore the saved configuration (if any) or reset to DHCP.
func (p *prog) resetDNSForRunningIface(isStart bool, restoreStatic bool) (runningIface *net.Interface) { func (p *prog) resetDNSForRunningIface(isStart bool, restoreStatic bool) (runningIface *net.Interface) {
if p.runningIface == "" { if p.runningIface == "" {
p.Debug().Msg("no running interface, skipping resetDNS") p.Debug().Msg("No running interface, skipping resetDNS")
return return
} }
logger := p.logger.Load().With().Str("iface", p.runningIface) logger := p.logger.Load().With().Str("iface", p.runningIface)
netIface, err := netInterface(p.runningIface) netIface, err := netInterface(p.runningIface)
if err != nil { if err != nil {
logger.Error().Err(err).Msg("could not get interface") logger.Error().Err(err).Msg("Could not get interface")
return return
} }
runningIface = netIface runningIface = netIface
if err := p.restoreNetworkManager(); err != nil { if err := p.restoreNetworkManager(); err != nil {
logger.Error().Err(err).Msg("could not restore NetworkManager") logger.Error().Err(err).Msg("Could not restore NetworkManager")
return return
} }
@@ -951,7 +951,7 @@ func (p *prog) resetDNSForRunningIface(isStart bool, restoreStatic bool) (runnin
if isStart { if isStart {
current, err := currentStaticDNS(netIface) current, err := currentStaticDNS(netIface)
if err != nil { if err != nil {
logger.Warn().Err(err).Msg("unable to obtain current static DNS configuration; proceeding to restore saved config") logger.Warn().Err(err).Msg("Unable to obtain current static DNS configuration; proceeding to restore saved config")
} else if len(current) > 0 { } else if len(current) > 0 {
// If any static DNS value is not our own listener, assume an admin override. // If any static DNS value is not our own listener, assume an admin override.
hasManualConfig := false hasManualConfig := false
@@ -973,13 +973,13 @@ func (p *prog) resetDNSForRunningIface(isStart bool, restoreStatic bool) (runnin
if len(saved) > 0 && restoreStatic { if len(saved) > 0 && restoreStatic {
logger.Debug().Msgf("Restoring interface %q from saved static config: %v", netIface.Name, saved) logger.Debug().Msgf("Restoring interface %q from saved static config: %v", netIface.Name, saved)
if err := setDNS(netIface, saved); err != nil { if err := setDNS(netIface, saved); err != nil {
logger.Error().Err(err).Msgf("failed to restore static DNS config on interface %q", netIface.Name) logger.Error().Err(err).Msgf("Failed to restore static DNS config on interface %q", netIface.Name)
return return
} }
} else { } else {
logger.Debug().Msgf("No saved static DNS config for interface %q; resetting to DHCP", netIface.Name) logger.Debug().Msgf("No saved static DNS config for interface %q; resetting to DHCP", netIface.Name)
if err := resetDNS(netIface); err != nil { if err := resetDNS(netIface); err != nil {
logger.Error().Err(err).Msgf("failed to reset DNS to DHCP on interface %q", netIface.Name) logger.Error().Err(err).Msgf("Failed to reset DNS to DHCP on interface %q", netIface.Name)
return return
} }
} }
@@ -990,11 +990,11 @@ func (p *prog) logInterfacesState() {
withEachPhysicalInterfaces("", "", func(i *net.Interface) error { withEachPhysicalInterfaces("", "", func(i *net.Interface) error {
addrs, err := i.Addrs() addrs, err := i.Addrs()
if err != nil { if err != nil {
p.Warn().Str("interface", i.Name).Err(err).Msg("failed to get addresses") p.Warn().Str("interface", i.Name).Err(err).Msg("Failed to get addresses")
} }
nss, err := currentStaticDNS(i) nss, err := currentStaticDNS(i)
if err != nil { if err != nil {
p.Warn().Str("interface", i.Name).Err(err).Msg("failed to get DNS") p.Warn().Str("interface", i.Name).Err(err).Msg("Failed to get DNS")
} }
if len(nss) == 0 { if len(nss) == 0 {
nss = currentDNS(i) nss = currentDNS(i)
@@ -1063,7 +1063,7 @@ func (p *prog) findWorkingInterface() string {
// Get all interfaces // Get all interfaces
ifaces, err := net.Interfaces() ifaces, err := net.Interfaces()
if err != nil { if err != nil {
p.Error().Err(err).Msg("failed to list network interfaces") p.Error().Err(err).Msg("Failed to list network interfaces")
return currentIface // Return current interface as fallback return currentIface // Return current interface as fallback
} }
@@ -1132,7 +1132,7 @@ func (p *prog) findWorkingInterface() string {
// 3. Fall back to current interface if nothing else works // 3. Fall back to current interface if nothing else works
p.Warn(). p.Warn().
Str("current_iface", currentIface). Str("current_iface", currentIface).
Msg("no working physical interface found, keeping current") Msg("No working physical interface found, keeping current")
return currentIface return currentIface
} }
@@ -1152,19 +1152,19 @@ func randomPort() int {
func runLogServer(sockPath string) net.Conn { func runLogServer(sockPath string) net.Conn {
addr, err := net.ResolveUnixAddr("unix", sockPath) addr, err := net.ResolveUnixAddr("unix", sockPath)
if err != nil { if err != nil {
mainLog.Load().Warn().Err(err).Msg("invalid log sock path") mainLog.Load().Warn().Err(err).Msg("Invalid log sock path")
return nil return nil
} }
ln, err := net.ListenUnix("unix", addr) ln, err := net.ListenUnix("unix", addr)
if err != nil { if err != nil {
mainLog.Load().Warn().Err(err).Msg("could not listen log socket") mainLog.Load().Warn().Err(err).Msg("Could not listen log socket")
return nil return nil
} }
defer ln.Close() defer ln.Close()
server, err := ln.Accept() server, err := ln.Accept()
if err != nil { if err != nil {
mainLog.Load().Warn().Err(err).Msg("could not accept connection") mainLog.Load().Warn().Err(err).Msg("Could not accept connection")
return nil return nil
} }
return server return server
@@ -1261,9 +1261,9 @@ func (p *prog) defaultRouteIP() string {
if err != nil { if err != nil {
return "" return ""
} }
p.Debug().Str("iface", drNetIface.Name).Msg("checking default route interface") p.Debug().Str("iface", drNetIface.Name).Msg("Checking default route interface")
if ip := ifaceFirstPrivateIP(drNetIface); ip != "" { if ip := ifaceFirstPrivateIP(drNetIface); ip != "" {
p.Debug().Str("ip", ip).Msg("found ip with default route interface") p.Debug().Str("ip", ip).Msg("Found ip with default route interface")
return ip return ip
} }
@@ -1288,7 +1288,7 @@ func (p *prog) defaultRouteIP() string {
}) })
if len(addrs) == 0 { if len(addrs) == 0 {
p.Warn().Msg("no default route IP found") p.Warn().Msg("No default route IP found")
return "" return ""
} }
sort.Slice(addrs, func(i, j int) bool { sort.Slice(addrs, func(i, j int) bool {
@@ -1296,7 +1296,7 @@ func (p *prog) defaultRouteIP() string {
}) })
ip := addrs[0].String() ip := addrs[0].String()
p.Debug().Str("ip", ip).Msg("found LAN interface IP") p.Debug().Str("ip", ip).Msg("Found LAN interface IP")
return ip return ip
} }
@@ -1324,7 +1324,7 @@ func withEachPhysicalInterfaces(excludeIfaceName, contextStr string, f func(i *n
} }
netIface := i.Interface netIface := i.Interface
if patched, err := patchNetIfaceName(netIface); err != nil { if patched, err := patchNetIfaceName(netIface); err != nil {
mainLog.Load().Debug().Err(err).Msg("failed to patch net interface name") mainLog.Load().Debug().Err(err).Msg("Failed to patch net interface name")
return return
} else if !patched { } else if !patched {
// The interface is not functional, skipping. // The interface is not functional, skipping.
@@ -1361,7 +1361,7 @@ var errSaveCurrentStaticDNSNotSupported = errors.New("saving current DNS is not
// Only works on Windows and Mac. // Only works on Windows and Mac.
func saveCurrentStaticDNS(iface *net.Interface) error { func saveCurrentStaticDNS(iface *net.Interface) error {
if iface == nil { if iface == nil {
mainLog.Load().Debug().Msg("could not save current static DNS settings for nil interface") mainLog.Load().Debug().Msg("Could not save current static DNS settings for nil interface")
return nil return nil
} }
switch runtime.GOOS { switch runtime.GOOS {
@@ -1372,11 +1372,11 @@ func saveCurrentStaticDNS(iface *net.Interface) error {
file := ctrld.SavedStaticDnsSettingsFilePath(iface) file := ctrld.SavedStaticDnsSettingsFilePath(iface)
ns, err := currentStaticDNS(iface) ns, err := currentStaticDNS(iface)
if err != nil { if err != nil {
mainLog.Load().Warn().Err(err).Msgf("could not get current static DNS settings for %q", iface.Name) mainLog.Load().Warn().Err(err).Msgf("Could not get current static DNS settings for %q", iface.Name)
return err return err
} }
if len(ns) == 0 { if len(ns) == 0 {
mainLog.Load().Debug().Msgf("no static DNS settings for %q, removing old static DNS settings file", iface.Name) mainLog.Load().Debug().Msgf("No static DNS settings for %q, removing old static DNS settings file", iface.Name)
_ = os.Remove(file) // removing old static DNS settings _ = os.Remove(file) // removing old static DNS settings
return nil return nil
} }
@@ -1391,15 +1391,15 @@ func saveCurrentStaticDNS(iface *net.Interface) error {
return nil return nil
} }
if err := os.Remove(file); err != nil && !errors.Is(err, fs.ErrNotExist) { if err := os.Remove(file); err != nil && !errors.Is(err, fs.ErrNotExist) {
mainLog.Load().Warn().Err(err).Msgf("could not remove old static DNS settings file: %s", file) mainLog.Load().Warn().Err(err).Msgf("Could not remove old static DNS settings file: %s", file)
} }
nss := strings.Join(ns, ",") nss := strings.Join(ns, ",")
mainLog.Load().Debug().Msgf("DNS settings for %q is static: %v, saving ...", iface.Name, nss) mainLog.Load().Debug().Msgf("DNS settings for %q is static: %v, saving ...", iface.Name, nss)
if err := os.WriteFile(file, []byte(nss), 0600); err != nil { if err := os.WriteFile(file, []byte(nss), 0600); err != nil {
mainLog.Load().Err(err).Msgf("could not save DNS settings for iface: %s", iface.Name) mainLog.Load().Err(err).Msgf("Could not save DNS settings for iface: %s", iface.Name)
return err return err
} }
mainLog.Load().Debug().Msgf("save DNS settings for interface %q successfully", iface.Name) mainLog.Load().Debug().Msgf("Save DNS settings for interface %q successfully", iface.Name)
return nil return nil
} }
@@ -1414,7 +1414,7 @@ func (p *prog) dnsChanged(iface *net.Interface, nameservers []string) bool {
curNameservers, _ := currentStaticDNS(iface) curNameservers, _ := currentStaticDNS(iface)
slices.Sort(curNameservers) slices.Sort(curNameservers)
if !slices.Equal(curNameservers, nameservers) { if !slices.Equal(curNameservers, nameservers) {
p.Debug().Msgf("interface %q current DNS settings: %v, expected: %v", iface.Name, curNameservers, nameservers) p.Debug().Msgf("Interface %q current DNS settings: %v, expected: %v", iface.Name, curNameservers, nameservers)
return true return true
} }
return false return false
@@ -1438,7 +1438,7 @@ func selfUninstallCheck(uninstallErr error, p *prog, logger *ctrld.Logger) {
// Returns true if upgrade is allowed, false otherwise. // Returns true if upgrade is allowed, false otherwise.
func shouldUpgrade(vt string, cv *semver.Version, logger *ctrld.Logger) bool { func shouldUpgrade(vt string, cv *semver.Version, logger *ctrld.Logger) bool {
if vt == "" { if vt == "" {
logger.Debug().Msg("no version target set, skipped checking self-upgrade") logger.Debug().Msg("No version target set, skipped checking self-upgrade")
return false return false
} }
vts := vt vts := vt
@@ -1447,7 +1447,7 @@ func shouldUpgrade(vt string, cv *semver.Version, logger *ctrld.Logger) bool {
} }
targetVer, err := semver.NewVersion(vts) targetVer, err := semver.NewVersion(vts)
if err != nil { if err != nil {
logger.Warn().Err(err).Msgf("invalid target version, skipped self-upgrade: %s", vt) logger.Warn().Err(err).Msgf("Invalid target version, skipped self-upgrade: %s", vt)
return false return false
} }
@@ -1456,7 +1456,7 @@ func shouldUpgrade(vt string, cv *semver.Version, logger *ctrld.Logger) bool {
logger.Warn(). logger.Warn().
Str("target", vt). Str("target", vt).
Str("current", cv.String()). Str("current", cv.String()).
Msgf("major version upgrade not allowed (target: %d, current: %d), skipped self-upgrade", targetVer.Major(), cv.Major()) Msgf("Major version upgrade not allowed (target: %d, current: %d), skipped self-upgrade", targetVer.Major(), cv.Major())
return false return false
} }
@@ -1464,7 +1464,7 @@ func shouldUpgrade(vt string, cv *semver.Version, logger *ctrld.Logger) bool {
logger.Debug(). logger.Debug().
Str("target", vt). Str("target", vt).
Str("current", cv.String()). Str("current", cv.String()).
Msgf("target version is not greater than current one, skipped self-upgrade") Msgf("Target version is not greater than current one, skipped self-upgrade")
return false return false
} }
@@ -1476,16 +1476,16 @@ func shouldUpgrade(vt string, cv *semver.Version, logger *ctrld.Logger) bool {
func performUpgrade(vt string, logger *ctrld.Logger) bool { func performUpgrade(vt string, logger *ctrld.Logger) bool {
exe, err := os.Executable() exe, err := os.Executable()
if err != nil { if err != nil {
logger.Error().Err(err).Msg("failed to get executable path, skipped self-upgrade") logger.Error().Err(err).Msg("Failed to get executable path, skipped self-upgrade")
return false return false
} }
cmd := exec.Command(exe, "upgrade", "prod", "-vv") cmd := exec.Command(exe, "upgrade", "prod", "-vv")
cmd.SysProcAttr = sysProcAttrForDetachedChildProcess() cmd.SysProcAttr = sysProcAttrForDetachedChildProcess()
if err := cmd.Start(); err != nil { if err := cmd.Start(); err != nil {
logger.Error().Err(err).Msg("failed to start self-upgrade") logger.Error().Err(err).Msg("Failed to start self-upgrade")
return false return false
} }
mainLog.Load().Debug().Msgf("self-upgrade triggered, version target: %s", vt) logger.Debug().Msgf("Self-upgrade triggered, version target: %s", vt)
return true return true
} }
+9 -9
View File
@@ -28,10 +28,10 @@ func (p *prog) watchResolvConf(iface *net.Interface, ns []netip.Addr, setDnsFn f
if rp, _ := filepath.EvalSymlinks(resolvConfPath); rp != "" { if rp, _ := filepath.EvalSymlinks(resolvConfPath); rp != "" {
resolvConfPath = rp resolvConfPath = rp
} }
p.Debug().Msgf("start watching %s file", resolvConfPath) p.Debug().Msgf("Start watching %s file", resolvConfPath)
watcher, err := fsnotify.NewWatcher() watcher, err := fsnotify.NewWatcher()
if err != nil { if err != nil {
p.Warn().Err(err).Msg("could not create watcher for /etc/resolv.conf") p.Warn().Err(err).Msg("Could not create watcher for /etc/resolv.conf")
return return
} }
defer watcher.Close() defer watcher.Close()
@@ -41,7 +41,7 @@ func (p *prog) watchResolvConf(iface *net.Interface, ns []netip.Addr, setDnsFn f
// This is necessary because some systems don't properly notify on file changes // This is necessary because some systems don't properly notify on file changes
watchDir := filepath.Dir(resolvConfPath) watchDir := filepath.Dir(resolvConfPath)
if err := watcher.Add(watchDir); err != nil { if err := watcher.Add(watchDir); err != nil {
p.Warn().Err(err).Msgf("could not add %s to watcher list", watchDir) p.Warn().Err(err).Msgf("Could not add %s to watcher list", watchDir)
return return
} }
@@ -50,7 +50,7 @@ func (p *prog) watchResolvConf(iface *net.Interface, ns []netip.Addr, setDnsFn f
case <-p.dnsWatcherStopCh: case <-p.dnsWatcherStopCh:
return return
case <-p.stopCh: case <-p.stopCh:
p.Debug().Msgf("stopping watcher for %s", resolvConfPath) p.Debug().Msgf("Stopping watcher for %s", resolvConfPath)
return return
case event, ok := <-watcher.Events: case event, ok := <-watcher.Events:
if p.recoveryRunning.Load() { if p.recoveryRunning.Load() {
@@ -79,7 +79,7 @@ func (p *prog) watchResolvConf(iface *net.Interface, ns []netip.Addr, setDnsFn f
for retry := 0; retry < maxRetries; retry++ { for retry := 0; retry < maxRetries; retry++ {
foundNS, err = p.parseResolvConfNameservers(resolvConfPath) foundNS, err = p.parseResolvConfNameservers(resolvConfPath)
if err != nil { if err != nil {
p.Error().Err(err).Msg("failed to read resolv.conf content") p.Error().Err(err).Msg("Failed to read resolv.conf content")
break break
} }
@@ -128,16 +128,16 @@ func (p *prog) watchResolvConf(iface *net.Interface, ns []netip.Addr, setDnsFn f
// Only revert if the nameservers don't match // Only revert if the nameservers don't match
if !matches { if !matches {
if err := watcher.Remove(watchDir); err != nil { if err := watcher.Remove(watchDir); err != nil {
p.Error().Err(err).Msg("failed to pause watcher") p.Error().Err(err).Msg("Failed to pause watcher")
continue continue
} }
if err := setDnsFn(iface, ns); err != nil { if err := setDnsFn(iface, ns); err != nil {
p.Error().Err(err).Msg("failed to revert /etc/resolv.conf changes") p.Error().Err(err).Msg("Failed to revert /etc/resolv.conf changes")
} }
if err := watcher.Add(watchDir); err != nil { if err := watcher.Add(watchDir); err != nil {
p.Error().Err(err).Msg("failed to continue running watcher") p.Error().Err(err).Msg("Failed to continue running watcher")
return return
} }
} }
@@ -147,7 +147,7 @@ func (p *prog) watchResolvConf(iface *net.Interface, ns []netip.Addr, setDnsFn f
if !ok { if !ok {
return return
} }
p.Error().Err(err).Msg("could not get event for /etc/resolv.conf") p.Error().Err(err).Msg("Could not get event for /etc/resolv.conf")
} }
} }
} }
+1 -1
View File
@@ -27,7 +27,7 @@ func (p *prog) setResolvConf(iface *net.Interface, ns []netip.Addr) error {
if sds, err := searchDomains(); err == nil { if sds, err := searchDomains(); err == nil {
oc.SearchDomains = sds oc.SearchDomains = sds
} else { } else {
p.Debug().Err(err).Msg("failed to get search domains list when reverting resolv.conf file") p.Debug().Err(err).Msg("Failed to get search domains list when reverting resolv.conf file")
} }
return r.SetDNS(oc) return r.SetDNS(oc)
} }
+1 -1
View File
@@ -33,7 +33,7 @@ func searchDomains() ([]dnsname.FQDN, error) {
for a := aa.FirstDNSSuffix; a != nil; a = a.Next { for a := aa.FirstDNSSuffix; a != nil; a = a.Next {
d, err := dnsname.ToFQDN(a.String()) d, err := dnsname.ToFQDN(a.String())
if err != nil { if err != nil {
mainLog.Load().Debug().Err(err).Msgf("failed to parse domain: %s", a.String()) mainLog.Load().Debug().Err(err).Msgf("Failed to parse domain: %s", a.String())
continue continue
} }
sds = append(sds, d) sds = append(sds, d)
+1 -1
View File
@@ -11,7 +11,7 @@ import (
// selfUninstall performs self-uninstallation on non-Unix platforms // selfUninstall performs self-uninstallation on non-Unix platforms
func selfUninstall(p *prog, logger *ctrld.Logger) { func selfUninstall(p *prog, logger *ctrld.Logger) {
if uninstallInvalidCdUID(p, logger, false) { if uninstallInvalidCdUID(p, logger, false) {
logger.Warn().Msgf("service was uninstalled because device %q does not exist", cdUID) logger.Warn().Msgf("Service was uninstalled because device %q does not exist", cdUID)
os.Exit(0) os.Exit(0)
} }
} }
+4 -4
View File
@@ -20,7 +20,7 @@ func selfUninstall(p *prog, logger *ctrld.Logger) {
bin, err := os.Executable() bin, err := os.Executable()
if err != nil { if err != nil {
logger.Fatal().Err(err).Msg("could not determine executable") logger.Fatal().Err(err).Msg("Could not determine executable")
} }
args := []string{"uninstall"} args := []string{"uninstall"}
if deactivationPinSet() { if deactivationPinSet() {
@@ -29,11 +29,11 @@ func selfUninstall(p *prog, logger *ctrld.Logger) {
cmd := exec.Command(bin, args...) cmd := exec.Command(bin, args...)
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
if err := cmd.Start(); err != nil { if err := cmd.Start(); err != nil {
logger.Fatal().Err(err).Msg("could not start self uninstall command") logger.Fatal().Err(err).Msg("Could not start self uninstall command")
} }
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
logger.Warn().Msgf("service was uninstalled because device %q does not exist", cdUID) logger.Warn().Msgf("Service was uninstalled because device %q does not exist", cdUID)
_ = cmd.Wait() _ = cmd.Wait()
os.Exit(0) os.Exit(0)
} }
@@ -41,7 +41,7 @@ func selfUninstall(p *prog, logger *ctrld.Logger) {
// selfUninstallLinux performs self-uninstallation on Linux platforms // selfUninstallLinux performs self-uninstallation on Linux platforms
func selfUninstallLinux(p *prog, logger *ctrld.Logger) { func selfUninstallLinux(p *prog, logger *ctrld.Logger) {
if uninstallInvalidCdUID(p, logger, true) { if uninstallInvalidCdUID(p, logger, true) {
logger.Warn().Msgf("service was uninstalled because device %q does not exist", cdUID) logger.Warn().Msgf("Service was uninstalled because device %q does not exist", cdUID)
os.Exit(0) os.Exit(0)
} }
} }
+5 -5
View File
@@ -115,7 +115,7 @@ func (s *systemd) Start() error {
if out, err := exec.Command("systemctl", "daemon-reload").CombinedOutput(); err != nil { if out, err := exec.Command("systemctl", "daemon-reload").CombinedOutput(); err != nil {
return fmt.Errorf("systemctl daemon-reload failed: %w\n%s", err, string(out)) return fmt.Errorf("systemctl daemon-reload failed: %w\n%s", err, string(out))
} }
mainLog.Load().Debug().Msg("set KillMode=process successfully") mainLog.Load().Debug().Msg("Set KillMode=process successfully")
} }
return s.Service.Start() return s.Service.Start()
} }
@@ -125,7 +125,7 @@ func (s *systemd) Start() error {
func ensureSystemdKillMode(r io.Reader) (opts []*unit.UnitOption, change bool) { func ensureSystemdKillMode(r io.Reader) (opts []*unit.UnitOption, change bool) {
opts, err := unit.DeserializeOptions(r) opts, err := unit.DeserializeOptions(r)
if err != nil { if err != nil {
mainLog.Load().Error().Err(err).Msg("failed to deserialize options") mainLog.Load().Error().Err(err).Msg("Failed to deserialize options")
return return
} }
change = true change = true
@@ -185,13 +185,13 @@ func doTasks(tasks []task) bool {
mainLog.Load().Debug().Msgf("Running task %s", task.Name) mainLog.Load().Debug().Msgf("Running task %s", task.Name)
if err := task.f(); err != nil { if err := task.f(); err != nil {
if task.abortOnError { if task.abortOnError {
mainLog.Load().Error().Msgf("error running task %s: %v", task.Name, err) mainLog.Load().Error().Msgf("Error running task %s: %v", task.Name, err)
return false return false
} }
// if this is darwin stop command, dont print debug // if this is darwin stop command, dont print debug
// since launchctl complains on every start // since launchctl complains on every start
if runtime.GOOS != "darwin" || task.Name != "Stop" { if runtime.GOOS != "darwin" || task.Name != "Stop" {
mainLog.Load().Debug().Msgf("error running task %s: %v", task.Name, err) mainLog.Load().Debug().Msgf("Error running task %s: %v", task.Name, err)
} }
} }
} }
@@ -202,7 +202,7 @@ func doTasks(tasks []task) bool {
func checkHasElevatedPrivilege() { func checkHasElevatedPrivilege() {
ok, err := hasElevatedPrivilege() ok, err := hasElevatedPrivilege()
if err != nil { if err != nil {
mainLog.Load().Error().Msgf("could not detect user privilege: %v", err) mainLog.Load().Error().Msgf("Could not detect user privilege: %v", err)
return return
} }
if !ok { if !ok {
+4 -4
View File
@@ -57,7 +57,7 @@ func (um *upstreamMonitor) increaseFailureCount(upstream string) {
defer um.mu.Unlock() defer um.mu.Unlock()
if um.recovered[upstream] { if um.recovered[upstream] {
um.logger.Load().Debug().Msgf("upstream %q is recovered, skipping failure count increase", upstream) um.logger.Load().Debug().Msgf("Upstream %q is recovered, skipping failure count increase", upstream)
return return
} }
@@ -65,7 +65,7 @@ func (um *upstreamMonitor) increaseFailureCount(upstream string) {
failedCount := um.failureReq[upstream] failedCount := um.failureReq[upstream]
// Log the updated failure count. // Log the updated failure count.
um.logger.Load().Debug().Msgf("upstream %q failure count updated to %d", upstream, failedCount) um.logger.Load().Debug().Msgf("Upstream %q failure count updated to %d", upstream, failedCount)
// If this is the first failure and no timer is running, start a 10-second timer. // If this is the first failure and no timer is running, start a 10-second timer.
if failedCount == 1 && !um.failureTimerActive[upstream] { if failedCount == 1 && !um.failureTimerActive[upstream] {
@@ -78,7 +78,7 @@ func (um *upstreamMonitor) increaseFailureCount(upstream string) {
// and the upstream is not in a recovered state, mark it as down. // and the upstream is not in a recovered state, mark it as down.
if um.failureReq[upstream] > 0 && !um.recovered[upstream] { if um.failureReq[upstream] > 0 && !um.recovered[upstream] {
um.down[upstream] = true um.down[upstream] = true
um.logger.Load().Warn().Msgf("upstream %q marked as down after 10 seconds (failure count: %d)", upstream, um.failureReq[upstream]) um.logger.Load().Warn().Msgf("Upstream %q marked as down after 10 seconds (failure count: %d)", upstream, um.failureReq[upstream])
} }
// Reset the timer flag so that a new timer can be spawned if needed. // Reset the timer flag so that a new timer can be spawned if needed.
um.failureTimerActive[upstream] = false um.failureTimerActive[upstream] = false
@@ -88,7 +88,7 @@ func (um *upstreamMonitor) increaseFailureCount(upstream string) {
// If the failure count quickly reaches the threshold, mark the upstream as down immediately. // If the failure count quickly reaches the threshold, mark the upstream as down immediately.
if failedCount >= maxFailureRequest { if failedCount >= maxFailureRequest {
um.down[upstream] = true um.down[upstream] = true
um.logger.Load().Warn().Msgf("upstream %q marked as down immediately (failure count: %d)", upstream, failedCount) um.logger.Load().Warn().Msgf("Upstream %q marked as down immediately (failure count: %d)", upstream, failedCount)
} }
} }
+12 -11
View File
@@ -114,8 +114,9 @@ func SetConfigNameWithPath(v *viper.Viper, name, configPath string) {
// InitConfig initializes default config values for given *viper.Viper instance. // InitConfig initializes default config values for given *viper.Viper instance.
func InitConfig(v *viper.Viper, name string) { func InitConfig(v *viper.Viper, name string) {
logger := LoggerFromCtx(context.Background()) ctx := context.Background()
Log(context.Background(), logger.Debug(), "Config initialization started") logger := LoggerFromCtx(ctx)
Log(ctx, logger.Debug(), "Config initialization started")
v.SetDefault("listener", map[string]*ListenerConfig{ v.SetDefault("listener", map[string]*ListenerConfig{
"0": { "0": {
@@ -156,7 +157,7 @@ func InitConfig(v *viper.Viper, name string) {
}, },
}) })
Log(context.Background(), logger.Debug(), "Config initialization completed") Log(ctx, logger.Debug(), "Config initialization completed")
} }
// Config represents ctrld supported configuration. // Config represents ctrld supported configuration.
@@ -333,7 +334,7 @@ type Rule map[string][]string
func (uc *UpstreamConfig) Init(ctx context.Context) { func (uc *UpstreamConfig) Init(ctx context.Context) {
logger := LoggerFromCtx(ctx) logger := LoggerFromCtx(ctx)
if err := uc.initDnsStamps(); err != nil { if err := uc.initDnsStamps(); err != nil {
logger.Fatal().Err(err).Msg("invalid DNS Stamps") logger.Fatal().Err(err).Msg("Invalid dns stamps")
} }
uc.initDoHScheme() uc.initDoHScheme()
uc.uid = upstreamUID(ctx) uc.uid = upstreamUID(ctx)
@@ -469,7 +470,7 @@ func (uc *UpstreamConfig) SetupBootstrapIP(ctx context.Context) {
uc.bootstrapIPs = uc.bootstrapIPs[:n] uc.bootstrapIPs = uc.bootstrapIPs[:n]
if len(uc.bootstrapIPs) == 0 { if len(uc.bootstrapIPs) == 0 {
uc.bootstrapIPs = bootstrapIPsFromControlDDomain(uc.Domain) uc.bootstrapIPs = bootstrapIPsFromControlDDomain(uc.Domain)
logger.Warn().Msgf("No record found for %q, lookup from direct IP table", uc.Domain) logger.Warn().Msgf("No record found for %q, lookup from direct ip table", uc.Domain)
} }
} }
if len(uc.bootstrapIPs) == 0 { if len(uc.bootstrapIPs) == 0 {
@@ -480,7 +481,7 @@ func (uc *UpstreamConfig) SetupBootstrapIP(ctx context.Context) {
if len(uc.bootstrapIPs) > 0 { if len(uc.bootstrapIPs) > 0 {
break break
} }
logger.Warn().Msg("Could not resolve bootstrap IPs, retrying...") logger.Warn().Msg("Could not resolve bootstrap ips, retrying...")
b.BackOff(context.Background(), errors.New("no bootstrap IPs")) b.BackOff(context.Background(), errors.New("no bootstrap IPs"))
} }
for _, ip := range uc.bootstrapIPs { for _, ip := range uc.bootstrapIPs {
@@ -490,7 +491,7 @@ func (uc *UpstreamConfig) SetupBootstrapIP(ctx context.Context) {
uc.bootstrapIPs4 = append(uc.bootstrapIPs4, ip) uc.bootstrapIPs4 = append(uc.bootstrapIPs4, ip)
} }
} }
logger.Debug().Msgf("Bootstrap IPs: %v", uc.bootstrapIPs) logger.Debug().Msgf("Bootstrap ips: %v", uc.bootstrapIPs)
Log(ctx, logger.Debug(), "Bootstrap IP setup completed for upstream: %s", uc.Name) Log(ctx, logger.Debug(), "Bootstrap IP setup completed for upstream: %s", uc.Name)
} }
@@ -566,7 +567,7 @@ func (uc *UpstreamConfig) newDOHTransport(ctx context.Context, addrs []string) *
if uc.BootstrapIP != "" { if uc.BootstrapIP != "" {
dialer := net.Dialer{Timeout: dialerTimeout, KeepAlive: dialerTimeout} dialer := net.Dialer{Timeout: dialerTimeout, KeepAlive: dialerTimeout}
addr := net.JoinHostPort(uc.BootstrapIP, port) addr := net.JoinHostPort(uc.BootstrapIP, port)
Log(ctx, logger.Debug(), "sending doh request to: %s", addr) Log(ctx, logger.Debug(), "Sending doh request to: %s", addr)
return dialer.DialContext(ctx, network, addr) return dialer.DialContext(ctx, network, addr)
} }
pd := &ctrldnet.ParallelDialer{} pd := &ctrldnet.ParallelDialer{}
@@ -580,7 +581,7 @@ func (uc *UpstreamConfig) newDOHTransport(ctx context.Context, addrs []string) *
if err != nil { if err != nil {
return nil, err return nil, err
} }
Log(ctx, logger.Debug(), "sending doh request to: %s", conn.RemoteAddr()) Log(ctx, logger.Debug(), "Sending doh request to: %s", conn.RemoteAddr())
return conn, nil return conn, nil
} }
runtime.SetFinalizer(transport, func(transport *http.Transport) { runtime.SetFinalizer(transport, func(transport *http.Transport) {
@@ -593,7 +594,7 @@ func (uc *UpstreamConfig) newDOHTransport(ctx context.Context, addrs []string) *
func (uc *UpstreamConfig) Ping(ctx context.Context) { func (uc *UpstreamConfig) Ping(ctx context.Context) {
if err := uc.ping(ctx); err != nil { if err := uc.ping(ctx); err != nil {
logger := LoggerFromCtx(ctx) logger := LoggerFromCtx(ctx)
logger.Debug().Err(err).Msgf("upstream ping failed: %s", uc.Endpoint) logger.Debug().Err(err).Msgf("Upstream ping failed: %s", uc.Endpoint)
_ = uc.FallbackToDirectIP(ctx) _ = uc.FallbackToDirectIP(ctx)
} }
} }
@@ -973,7 +974,7 @@ func upstreamUID(ctx context.Context) string {
b := make([]byte, 4) b := make([]byte, 4)
for { for {
if _, err := crand.Read(b); err != nil { if _, err := crand.Read(b); err != nil {
logger.Warn().Err(err).Msg("could not generate uid for upstream, retrying...") logger.Warn().Err(err).Msg("Could not generate uid for upstream, retrying...")
continue continue
} }
return hex.EncodeToString(b) return hex.EncodeToString(b)
+2 -2
View File
@@ -42,7 +42,7 @@ func (uc *UpstreamConfig) newDOH3Transport(ctx context.Context, addrs []string)
// if we have a bootstrap ip set, use it to avoid DNS lookup // if we have a bootstrap ip set, use it to avoid DNS lookup
if uc.BootstrapIP != "" { if uc.BootstrapIP != "" {
addr = net.JoinHostPort(uc.BootstrapIP, port) addr = net.JoinHostPort(uc.BootstrapIP, port)
Log(ctx, logger.Debug(), "sending doh3 request to: %s", addr) Log(ctx, logger.Debug(), "Sending doh3 request to: %s", addr)
udpConn, err := net.ListenUDP("udp", nil) udpConn, err := net.ListenUDP("udp", nil)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -62,7 +62,7 @@ func (uc *UpstreamConfig) newDOH3Transport(ctx context.Context, addrs []string)
if err != nil { if err != nil {
return nil, err return nil, err
} }
Log(ctx, logger.Debug(), "sending doh3 request to: %s", conn.RemoteAddr()) Log(ctx, logger.Debug(), "Sending doh3 request to: %s", conn.RemoteAddr())
return conn, err return conn, err
} }
runtime.SetFinalizer(rt, func(rt *http3.Transport) { runtime.SetFinalizer(rt, func(rt *http3.Transport) {
+14 -14
View File
@@ -196,14 +196,14 @@ func (t *Table) initSelfDiscover() {
func (t *Table) init() { func (t *Table) init() {
// Custom client ID presents, use it as the only source. // Custom client ID presents, use it as the only source.
if _, clientID := controld.ParseRawUID(t.cdUID); clientID != "" { if _, clientID := controld.ParseRawUID(t.cdUID); clientID != "" {
t.logger.Debug().Msg("start self discovery with custom client id") t.logger.Debug().Msg("Start self discovery with custom client id")
t.initSelfDiscover() t.initSelfDiscover()
return return
} }
// If we are running on platforms that should only do self discover, use it as the only source, too. // If we are running on platforms that should only do self discover, use it as the only source, too.
if ctrld.SelfDiscover() { if ctrld.SelfDiscover() {
t.logger.Debug().Msg("start self discovery on desktop platforms") t.logger.Debug().Msg("Start self discovery on desktop platforms")
t.initSelfDiscover() t.initSelfDiscover()
return return
} }
@@ -211,9 +211,9 @@ func (t *Table) init() {
// Hosts file mapping. // Hosts file mapping.
if t.discoverHosts() { if t.discoverHosts() {
t.hf = &hostsFile{logger: t.logger} t.hf = &hostsFile{logger: t.logger}
t.logger.Debug().Msg("start hosts file discovery") t.logger.Debug().Msg("Start hosts file discovery")
if err := t.hf.init(); err != nil { if err := t.hf.init(); err != nil {
t.logger.Error().Err(err).Msg("could not init hosts file discover") t.logger.Error().Err(err).Msg("Could not init hosts file discover")
} else { } else {
t.hostnameResolvers = append(t.hostnameResolvers, t.hf) t.hostnameResolvers = append(t.hostnameResolvers, t.hf)
t.refreshers = append(t.refreshers, t.hf) t.refreshers = append(t.refreshers, t.hf)
@@ -223,9 +223,9 @@ func (t *Table) init() {
// DHCP lease files. // DHCP lease files.
if t.discoverDHCP() { if t.discoverDHCP() {
t.dhcp = &dhcp{selfIP: t.selfIP, logger: t.logger} t.dhcp = &dhcp{selfIP: t.selfIP, logger: t.logger}
t.logger.Debug().Msg("start dhcp discovery") t.logger.Debug().Msg("Start dhcp discovery")
if err := t.dhcp.init(); err != nil { if err := t.dhcp.init(); err != nil {
t.logger.Error().Err(err).Msg("could not init DHCP discover") t.logger.Error().Err(err).Msg("Could not init dhcp discover")
} else { } else {
t.ipResolvers = append(t.ipResolvers, t.dhcp) t.ipResolvers = append(t.ipResolvers, t.dhcp)
t.macResolvers = append(t.macResolvers, t.dhcp) t.macResolvers = append(t.macResolvers, t.dhcp)
@@ -237,7 +237,7 @@ func (t *Table) init() {
if t.discoverARP() { if t.discoverARP() {
t.arp = &arpDiscover{} t.arp = &arpDiscover{}
t.ndp = &ndpDiscover{logger: t.logger} t.ndp = &ndpDiscover{logger: t.logger}
t.logger.Debug().Msg("start arp discovery") t.logger.Debug().Msg("Start arp discovery")
discovers := map[string]interface { discovers := map[string]interface {
refresher refresher
IpResolver IpResolver
@@ -249,7 +249,7 @@ func (t *Table) init() {
for protocol, discover := range discovers { for protocol, discover := range discovers {
if err := discover.refresh(); err != nil { if err := discover.refresh(); err != nil {
t.logger.Error().Err(err).Msgf("could not init %s discover", protocol) t.logger.Error().Err(err).Msgf("Could not init %s discover", protocol)
} else { } else {
t.ipResolvers = append(t.ipResolvers, discover) t.ipResolvers = append(t.ipResolvers, discover)
t.macResolvers = append(t.macResolvers, discover) t.macResolvers = append(t.macResolvers, discover)
@@ -282,18 +282,18 @@ func (t *Table) init() {
if _, portErr := strconv.Atoi(port); portErr == nil && port != "0" && net.ParseIP(host) != nil { if _, portErr := strconv.Atoi(port); portErr == nil && port != "0" && net.ParseIP(host) != nil {
nss = append(nss, net.JoinHostPort(host, port)) nss = append(nss, net.JoinHostPort(host, port))
} else { } else {
t.logger.Warn().Msgf("ignoring invalid nameserver for ptr discover: %q", ns) t.logger.Warn().Msgf("Ignoring invalid nameserver for ptr discover: %q", ns)
} }
} }
if len(nss) > 0 { if len(nss) > 0 {
t.ptr.resolver = ctrld.NewResolverWithNameserver(nss) t.ptr.resolver = ctrld.NewResolverWithNameserver(nss)
t.logger.Debug().Msgf("using nameservers %v for ptr discovery", nss) t.logger.Debug().Msgf("Using nameservers %v for ptr discovery", nss)
} }
} }
t.logger.Debug().Msg("start ptr discovery") t.logger.Debug().Msg("Start ptr discovery")
if err := t.ptr.refresh(); err != nil { if err := t.ptr.refresh(); err != nil {
t.logger.Error().Err(err).Msg("could not init PTR discover") t.logger.Error().Err(err).Msg("Could not init ptr discover")
} else { } else {
t.hostnameResolvers = append(t.hostnameResolvers, t.ptr) t.hostnameResolvers = append(t.hostnameResolvers, t.ptr)
t.refreshers = append(t.refreshers, t.ptr) t.refreshers = append(t.refreshers, t.ptr)
@@ -302,9 +302,9 @@ func (t *Table) init() {
// mdns. // mdns.
if t.discoverMDNS() { if t.discoverMDNS() {
t.mdns = &mdns{logger: t.logger} t.mdns = &mdns{logger: t.logger}
t.logger.Debug().Msg("start mdns discovery") t.logger.Debug().Msg("Start mdns discovery")
if err := t.mdns.init(t.quitCh); err != nil { if err := t.mdns.init(t.quitCh); err != nil {
t.logger.Error().Err(err).Msg("could not init mDNS discover") t.logger.Error().Err(err).Msg("Could not init mdns discover")
} else { } else {
t.hostnameResolvers = append(t.hostnameResolvers, t.mdns) t.hostnameResolvers = append(t.hostnameResolvers, t.mdns)
} }
+7 -7
View File
@@ -55,7 +55,7 @@ func (d *dhcp) watchChanges() {
if event.Has(fsnotify.Create) { if event.Has(fsnotify.Create) {
if format, ok := clientInfoFiles[event.Name]; ok { if format, ok := clientInfoFiles[event.Name]; ok {
if err := d.addLeaseFile(event.Name, format); err != nil { if err := d.addLeaseFile(event.Name, format); err != nil {
d.logger.Err(err).Str("file", event.Name).Msg("could not add lease file") d.logger.Err(err).Str("file", event.Name).Msg("Could not add lease file")
} }
} }
continue continue
@@ -63,14 +63,14 @@ func (d *dhcp) watchChanges() {
if event.Has(fsnotify.Write) || event.Has(fsnotify.Rename) || event.Has(fsnotify.Chmod) || event.Has(fsnotify.Remove) { if event.Has(fsnotify.Write) || event.Has(fsnotify.Rename) || event.Has(fsnotify.Chmod) || event.Has(fsnotify.Remove) {
format := clientInfoFiles[event.Name] format := clientInfoFiles[event.Name]
if err := d.readLeaseFile(event.Name, format); err != nil && !os.IsNotExist(err) { if err := d.readLeaseFile(event.Name, format); err != nil && !os.IsNotExist(err) {
d.logger.Err(err).Str("file", event.Name).Msg("leases file changed but failed to update client info") d.logger.Err(err).Str("file", event.Name).Msg("Leases file changed but failed to update client info")
} }
} }
case err, ok := <-d.watcher.Errors: case err, ok := <-d.watcher.Errors:
if !ok { if !ok {
return return
} }
d.logger.Err(err).Msg("could not watch client info file") d.logger.Err(err).Msg("Could not watch client info file")
} }
} }
@@ -216,7 +216,7 @@ func (d *dhcp) dnsmasqReadClientInfoReader(reader io.Reader) error {
} }
ip := normalizeIP(string(fields[2])) ip := normalizeIP(string(fields[2]))
if net.ParseIP(ip) == nil { if net.ParseIP(ip) == nil {
d.logger.Warn().Msgf("invalid ip address entry: %q", ip) d.logger.Warn().Msgf("Invalid ip address entry: %q", ip)
ip = "" ip = ""
} }
@@ -271,7 +271,7 @@ func (d *dhcp) iscDHCPReadClientInfoReader(reader io.Reader) error {
// DHCP lease files may contain mixed-case IP addresses // DHCP lease files may contain mixed-case IP addresses
ip = normalizeIP(strings.ToLower(fields[1])) ip = normalizeIP(strings.ToLower(fields[1]))
if net.ParseIP(ip) == nil { if net.ParseIP(ip) == nil {
d.logger.Warn().Msgf("invalid ip address entry: %q", ip) d.logger.Warn().Msgf("Invalid ip address entry: %q", ip)
ip = "" ip = ""
} }
case "hardware": case "hardware":
@@ -328,7 +328,7 @@ func (d *dhcp) keaDhcp4ReadClientInfoReader(r io.Reader) error {
} }
ip := normalizeIP(record[0]) ip := normalizeIP(record[0])
if net.ParseIP(ip) == nil { if net.ParseIP(ip) == nil {
d.logger.Warn().Msgf("invalid ip address entry: %q", ip) d.logger.Warn().Msgf("Invalid ip address entry: %q", ip)
ip = "" ip = ""
} }
@@ -350,7 +350,7 @@ func (d *dhcp) keaDhcp4ReadClientInfoReader(r io.Reader) error {
func (d *dhcp) addSelf() { func (d *dhcp) addSelf() {
hostname, err := os.Hostname() hostname, err := os.Hostname()
if err != nil { if err != nil {
d.logger.Err(err).Msg("could not get hostname") d.logger.Err(err).Msg("Could not get hostname")
return return
} }
hostname = normalizeHostname(hostname) hostname = normalizeHostname(hostname)
+3 -3
View File
@@ -56,7 +56,7 @@ func (hf *hostsFile) refresh() error {
// override hosts file with host_entries.conf content if present. // override hosts file with host_entries.conf content if present.
hem, err := parseHostEntriesConf(hostEntriesConfPath) hem, err := parseHostEntriesConf(hostEntriesConfPath)
if err != nil && !os.IsNotExist(err) { if err != nil && !os.IsNotExist(err) {
hf.logger.Debug().Err(err).Msg("could not read host_entries.conf file") hf.logger.Debug().Err(err).Msg("Could not read host_entries.conf file")
} }
for k, v := range hem { for k, v := range hem {
hf.m[k] = v hf.m[k] = v
@@ -78,14 +78,14 @@ func (hf *hostsFile) watchChanges() {
} }
if event.Has(fsnotify.Write) || event.Has(fsnotify.Rename) || event.Has(fsnotify.Chmod) || event.Has(fsnotify.Remove) { if event.Has(fsnotify.Write) || event.Has(fsnotify.Rename) || event.Has(fsnotify.Chmod) || event.Has(fsnotify.Remove) {
if err := hf.refresh(); err != nil && !os.IsNotExist(err) { if err := hf.refresh(); err != nil && !os.IsNotExist(err) {
hf.logger.Err(err).Msg("hosts file changed but failed to update client info") hf.logger.Err(err).Msg("Hosts file changed but Failed to update client info")
} }
} }
case err, ok := <-hf.watcher.Errors: case err, ok := <-hf.watcher.Errors:
if !ok { if !ok {
return return
} }
hf.logger.Err(err).Msg("could not watch client info file") hf.logger.Err(err).Msg("Could not watch client info file")
} }
} }
+10 -10
View File
@@ -94,9 +94,9 @@ func (m *mdns) init(quitCh chan struct{}) error {
} }
// Check if IPv6 is available once and use the result for the rest of the function. // Check if IPv6 is available once and use the result for the rest of the function.
m.logger.Debug().Msgf("checking for IPv6 availability in mdns init") m.logger.Debug().Msgf("Checking for ipv6 availability in mdns init")
ipv6 := ctrldnet.IPv6Available(context.Background()) ipv6 := ctrldnet.IPv6Available(context.Background())
m.logger.Debug().Msgf("IPv6 is %v in mdns init", ipv6) m.logger.Debug().Msgf("ipv6 is %v in mdns init", ipv6)
v4ConnList := make([]*net.UDPConn, 0, len(ifaces)) v4ConnList := make([]*net.UDPConn, 0, len(ifaces))
v6ConnList := make([]*net.UDPConn, 0, len(ifaces)) v6ConnList := make([]*net.UDPConn, 0, len(ifaces))
@@ -130,11 +130,11 @@ func (m *mdns) probeLoop(conns []*net.UDPConn, remoteAddr net.Addr, quitCh chan
for { for {
err := m.probe(conns, remoteAddr) err := m.probe(conns, remoteAddr)
if shouldStopProbing(err) { if shouldStopProbing(err) {
m.logger.Warn().Msgf("stop probing %q: %v", remoteAddr, err) m.logger.Warn().Msgf("Stop probing %q: %v", remoteAddr, err)
break break
} }
if err != nil { if err != nil {
m.logger.Warn().Err(err).Msg("error while probing mdns") m.logger.Warn().Err(err).Msg("Error while probing mdns")
bo.BackOff(context.Background(), errors.New("mdns probe backoff")) bo.BackOff(context.Background(), errors.New("mdns probe backoff"))
continue continue
} }
@@ -162,7 +162,7 @@ func (m *mdns) readLoop(conn *net.UDPConn) {
if errors.Is(err, net.ErrClosed) { if errors.Is(err, net.ErrClosed) {
return return
} }
m.logger.Debug().Err(err).Msg("mdns readLoop error") m.logger.Debug().Err(err).Msg("Mdns readLoop error")
return return
} }
@@ -185,11 +185,11 @@ func (m *mdns) readLoop(conn *net.UDPConn) {
if ip != "" && name != "" { if ip != "" && name != "" {
name = normalizeHostname(name) name = normalizeHostname(name)
if val, loaded := m.name.LoadOrStore(ip, name); !loaded { if val, loaded := m.name.LoadOrStore(ip, name); !loaded {
m.logger.Debug().Msgf("found hostname: %q, ip: %q via mdns", name, ip) m.logger.Debug().Msgf("Found hostname: %q, ip: %q via mdns", name, ip)
} else { } else {
old := val.(string) old := val.(string)
if old != name { if old != name {
m.logger.Debug().Msgf("update hostname: %q, ip: %q, old: %q via mdns", name, ip, old) m.logger.Debug().Msgf("Update hostname: %q, ip: %q, old: %q via mdns", name, ip, old)
m.name.Store(ip, name) m.name.Store(ip, name)
} }
} }
@@ -230,7 +230,7 @@ func (m *mdns) probe(conns []*net.UDPConn, remoteAddr net.Addr) error {
// getDataFromAvahiDaemonCache reads entries from avahi-daemon cache to update mdns data. // getDataFromAvahiDaemonCache reads entries from avahi-daemon cache to update mdns data.
func (m *mdns) getDataFromAvahiDaemonCache() { func (m *mdns) getDataFromAvahiDaemonCache() {
if _, err := exec.LookPath("avahi-browse"); err != nil { if _, err := exec.LookPath("avahi-browse"); err != nil {
m.logger.Debug().Err(err).Msg("could not find avahi-browse binary, skipping.") m.logger.Debug().Err(err).Msg("Could not find avahi-browse binary, skipping.")
return return
} }
// Run avahi-browse to discover services from cache: // Run avahi-browse to discover services from cache:
@@ -240,7 +240,7 @@ func (m *mdns) getDataFromAvahiDaemonCache() {
// - "-c" -> read from cache. // - "-c" -> read from cache.
out, err := exec.Command("avahi-browse", "-a", "-r", "-p", "-c").Output() out, err := exec.Command("avahi-browse", "-a", "-r", "-p", "-c").Output()
if err != nil { if err != nil {
m.logger.Debug().Err(err).Msg("could not browse services from avahi cache") m.logger.Debug().Err(err).Msg("Could not browse services from avahi cache")
return return
} }
m.storeDataFromAvahiBrowseOutput(bytes.NewReader(out)) m.storeDataFromAvahiBrowseOutput(bytes.NewReader(out))
@@ -260,7 +260,7 @@ func (m *mdns) storeDataFromAvahiBrowseOutput(r io.Reader) {
name := normalizeHostname(fields[6]) name := normalizeHostname(fields[6])
// Only using cache value if we don't have existed one. // Only using cache value if we don't have existed one.
if _, loaded := m.name.LoadOrStore(ip, name); !loaded { if _, loaded := m.name.LoadOrStore(ip, name); !loaded {
m.logger.Debug().Msgf("found hostname: %q, ip: %q via avahi cache", name, ip) m.logger.Debug().Msgf("Found hostname: %q, ip: %q via avahi cache", name, ip)
} }
} }
} }
+4 -4
View File
@@ -98,7 +98,7 @@ func (nd *ndpDiscover) saveInfo(ip, mac string) {
func (nd *ndpDiscover) listen(ctx context.Context) { func (nd *ndpDiscover) listen(ctx context.Context) {
ifis, err := allInterfacesWithV6LinkLocal() ifis, err := allInterfacesWithV6LinkLocal()
if err != nil { if err != nil {
nd.logger.Debug().Err(err).Msg("failed to find valid ipv6 interfaces") nd.logger.Debug().Err(err).Msg("Failed to find valid ipv6 interfaces")
return return
} }
for _, ifi := range ifis { for _, ifi := range ifis {
@@ -111,11 +111,11 @@ func (nd *ndpDiscover) listen(ctx context.Context) {
func (nd *ndpDiscover) listenOnInterface(ctx context.Context, ifi *net.Interface) { func (nd *ndpDiscover) listenOnInterface(ctx context.Context, ifi *net.Interface) {
c, ip, err := ndp.Listen(ifi, ndp.Unspecified) c, ip, err := ndp.Listen(ifi, ndp.Unspecified)
if err != nil { if err != nil {
nd.logger.Debug().Err(err).Msg("ndp listen failed") nd.logger.Debug().Err(err).Msg("Ndp listen failed")
return return
} }
defer c.Close() defer c.Close()
nd.logger.Debug().Msgf("listening ndp on: %s", ip.String()) nd.logger.Debug().Msgf("Listening ndp on: %s", ip.String())
for { for {
select { select {
case <-ctx.Done(): case <-ctx.Done():
@@ -129,7 +129,7 @@ func (nd *ndpDiscover) listenOnInterface(ctx context.Context, ifi *net.Interface
if errors.As(readErr, &opErr) && (opErr.Timeout() || opErr.Temporary()) { if errors.As(readErr, &opErr) && (opErr.Timeout() || opErr.Temporary()) {
continue continue
} }
nd.logger.Debug().Err(readErr).Msg("ndp read loop error") nd.logger.Debug().Err(readErr).Msg("Ndp read loop error")
return return
} }
+4 -4
View File
@@ -11,7 +11,7 @@ import (
func (nd *ndpDiscover) scan() { func (nd *ndpDiscover) scan() {
neighs, err := netlink.NeighList(0, netlink.FAMILY_V6) neighs, err := netlink.NeighList(0, netlink.FAMILY_V6)
if err != nil { if err != nil {
nd.logger.Warn().Err(err).Msg("could not get neigh list") nd.logger.Warn().Err(err).Msg("Could not get neighbor list")
return return
} }
@@ -32,7 +32,7 @@ func (nd *ndpDiscover) subscribe(ctx context.Context) {
done := make(chan struct{}) done := make(chan struct{})
defer close(done) defer close(done)
if err := netlink.NeighSubscribe(ch, done); err != nil { if err := netlink.NeighSubscribe(ch, done); err != nil {
nd.logger.Err(err).Msg("could not perform neighbor subscribing") nd.logger.Err(err).Msg("Could not perform neighbor subscribing")
return return
} }
for { for {
@@ -45,7 +45,7 @@ func (nd *ndpDiscover) subscribe(ctx context.Context) {
} }
ip := normalizeIP(nu.IP.String()) ip := normalizeIP(nu.IP.String())
if nu.Type == unix.RTM_DELNEIGH { if nu.Type == unix.RTM_DELNEIGH {
nd.logger.Debug().Msgf("removing NDP neighbor: %s", ip) nd.logger.Debug().Msgf("Removing ndp neighbor: %s", ip)
nd.mac.Delete(ip) nd.mac.Delete(ip)
continue continue
} }
@@ -54,7 +54,7 @@ func (nd *ndpDiscover) subscribe(ctx context.Context) {
case netlink.NUD_REACHABLE: case netlink.NUD_REACHABLE:
nd.saveInfo(ip, mac) nd.saveInfo(ip, mac)
case netlink.NUD_FAILED: case netlink.NUD_FAILED:
nd.logger.Debug().Msgf("removing NDP neighbor with failed state: %s", ip) nd.logger.Debug().Msgf("Removing ndp neighbor with failed state: %s", ip)
nd.mac.Delete(ip) nd.mac.Delete(ip)
} }
} }
+2 -2
View File
@@ -15,14 +15,14 @@ func (nd *ndpDiscover) scan() {
case "windows": case "windows":
data, err := exec.Command("netsh", "interface", "ipv6", "show", "neighbors").Output() data, err := exec.Command("netsh", "interface", "ipv6", "show", "neighbors").Output()
if err != nil { if err != nil {
nd.logger.Warn().Err(err).Msg("could not query ndp table") nd.logger.Warn().Err(err).Msg("Could not query ndp table")
return return
} }
nd.scanWindows(bytes.NewReader(data)) nd.scanWindows(bytes.NewReader(data))
default: default:
data, err := exec.Command("ndp", "-an").Output() data, err := exec.Command("ndp", "-an").Output()
if err != nil { if err != nil {
nd.logger.Warn().Err(err).Msg("could not query ndp table") nd.logger.Warn().Err(err).Msg("Could not query ndp table")
return return
} }
nd.scanUnix(bytes.NewReader(data)) nd.scanUnix(bytes.NewReader(data))
+2 -2
View File
@@ -74,14 +74,14 @@ func (p *ptrDiscover) lookupHostname(ip string) string {
msg := new(dns.Msg) msg := new(dns.Msg)
addr, err := dns.ReverseAddr(ip) addr, err := dns.ReverseAddr(ip)
if err != nil { if err != nil {
p.logger.Info().Str("discovery", "ptr").Err(err).Msg("invalid ip address") p.logger.Info().Str("discovery", "ptr").Err(err).Msg("Invalid ip address")
return "" return ""
} }
msg.SetQuestion(addr, dns.TypePTR) msg.SetQuestion(addr, dns.TypePTR)
ans, err := p.resolver.Resolve(ctx, msg) ans, err := p.resolver.Resolve(ctx, msg)
if err != nil { if err != nil {
if p.serverDown.CompareAndSwap(false, true) { if p.serverDown.CompareAndSwap(false, true) {
p.logger.Info().Str("discovery", "ptr").Err(err).Msg("could not perform PTR lookup") p.logger.Info().Str("discovery", "ptr").Err(err).Msg("Could not perform ptr lookup")
go p.checkServer() go p.checkServer()
} }
return "" return ""
+2 -2
View File
@@ -287,7 +287,7 @@ func apiTransport(loggerCtx context.Context, cdDev bool) *http.Transport {
ips := ctrld.LookupIP(loggerCtx, apiDomain) ips := ctrld.LookupIP(loggerCtx, apiDomain)
if len(ips) == 0 { if len(ips) == 0 {
logger := ctrld.LoggerFromCtx(loggerCtx) logger := ctrld.LoggerFromCtx(loggerCtx)
logger.Warn().Msgf("No IPs found for %s, use direct IPs: %v", apiDomain, apiIPs) logger.Warn().Msgf("No ips found for %s, use direct ips: %v", apiDomain, apiIPs)
ips = apiIPs ips = apiIPs
} }
@@ -348,7 +348,7 @@ func doWithFallback(ctx context.Context, client *http.Client, req *http.Request,
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
logger := ctrld.LoggerFromCtx(ctx) logger := ctrld.LoggerFromCtx(ctx)
logger.Warn().Err(err).Msgf("failed to send request, fallback to direct IP: %s", apiIp) logger.Warn().Err(err).Msgf("Failed to send request, fallback to direct ip: %s", apiIp)
ipReq := req.Clone(req.Context()) ipReq := req.Clone(req.Context())
ipReq.Host = apiIp ipReq.Host = apiIp
ipReq.URL.Host = apiIp ipReq.URL.Host = apiIp
+4 -4
View File
@@ -180,16 +180,16 @@ func (d *ParallelDialer) DialContext(ctx context.Context, network string, addrs
for _, addr := range addrs { for _, addr := range addrs {
go func(addr string) { go func(addr string) {
defer wg.Done() defer wg.Done()
logger.Debug("dialing to", zap.String("address", addr)) logger.Debug("Dialing to", zap.String("address", addr))
conn, err := d.Dialer.DialContext(ctx, network, addr) conn, err := d.Dialer.DialContext(ctx, network, addr)
if err != nil { if err != nil {
logger.Debug("failed to dial", zap.String("address", addr), zap.Error(err)) logger.Debug("Failed to dial", zap.String("address", addr), zap.Error(err))
} }
select { select {
case ch <- &parallelDialerResult{conn: conn, err: err}: case ch <- &parallelDialerResult{conn: conn, err: err}:
case <-done: case <-done:
if conn != nil { if conn != nil {
logger.Debug("connection closed", zap.String("remote_address", conn.RemoteAddr().String())) logger.Debug("Connection closed", zap.String("remote_address", conn.RemoteAddr().String()))
conn.Close() conn.Close()
} }
} }
@@ -200,7 +200,7 @@ func (d *ParallelDialer) DialContext(ctx context.Context, network string, addrs
for res := range ch { for res := range ch {
if res.err == nil { if res.err == nil {
cancel() cancel()
logger.Debug("connected to", zap.String("remote_address", res.conn.RemoteAddr().String())) logger.Debug("Connected to", zap.String("remote_address", res.conn.RemoteAddr().String()))
return res.conn, res.err return res.conn, res.err
} }
errs = append(errs, res.err) errs = append(errs, res.err)
+3 -3
View File
@@ -41,7 +41,7 @@ func getDNSFromScutil(ctx context.Context) []string {
cmd := exec.Command("scutil", "--dns") cmd := exec.Command("scutil", "--dns")
output, err := cmd.Output() output, err := cmd.Output()
if err != nil { if err != nil {
Log(context.Background(), logger.Error(), "failed to execute scutil --dns (attempt %d/%d): %v", attempt+1, maxRetries, err) Log(context.Background(), logger.Error(), "Failed to execute scutil --dns (attempt %d/%d): %v", attempt+1, maxRetries, err)
continue continue
} }
@@ -75,7 +75,7 @@ func getDNSFromScutil(ctx context.Context) []string {
} }
if err := scanner.Err(); err != nil { if err := scanner.Err(); err != nil {
Log(context.Background(), logger.Error(), "error scanning scutil output (attempt %d/%d): %v", attempt+1, maxRetries, err) Log(context.Background(), logger.Error(), "Error scanning scutil output (attempt %d/%d): %v", attempt+1, maxRetries, err)
continue continue
} }
@@ -172,7 +172,7 @@ func getAllDHCPNameservers(ctx context.Context) []string {
// if we have static DNS servers saved for the current default route, we should add them to the list // if we have static DNS servers saved for the current default route, we should add them to the list
drIfaceName, err := netmon.DefaultRouteInterface() drIfaceName, err := netmon.DefaultRouteInterface()
Log(context.Background(), logger.Debug(), "checking for static DNS servers for default route interface: %s", drIfaceName) Log(context.Background(), logger.Debug(), "Checking for static DNS servers for default route interface: %s", drIfaceName)
if err != nil { if err != nil {
Log(context.Background(), logger.Debug(), Log(context.Background(), logger.Debug(),
"Failed to get default route interface: %v", err) "Failed to get default route interface: %v", err)
+8 -8
View File
@@ -281,7 +281,7 @@ func getDNSServers(ctx context.Context) ([]string, error) {
logger.Debug().Msgf("Failed to get interface by name %s: %v", drIfaceName, err) logger.Debug().Msgf("Failed to get interface by name %s: %v", drIfaceName, err)
} else { } else {
staticNs, file := SavedStaticNameserversAndPath(drIface) staticNs, file := SavedStaticNameserversAndPath(drIface)
logger.Debug().Msgf("static dns servers from %s: %v", file, staticNs) logger.Debug().Msgf("Static dns servers from %s: %v", file, staticNs)
if len(staticNs) > 0 { if len(staticNs) > 0 {
logger.Debug().Msgf("Adding static DNS servers from %s: %v", drIfaceName, staticNs) logger.Debug().Msgf("Adding static DNS servers from %s: %v", drIfaceName, staticNs)
ns = append(ns, staticNs...) ns = append(ns, staticNs...)
@@ -392,20 +392,20 @@ func ValidInterfaces(ctx context.Context) map[string]struct{} {
defer instances.Close() defer instances.Close()
} }
if err != nil { if err != nil {
logger.Warn().Msgf("failed to get wmi network adapter: %v", err) logger.Warn().Msgf("Failed to get wmi network adapter: %v", err)
return nil return nil
} }
var adapters []string var adapters []string
for _, i := range instances { for _, i := range instances {
adapter, err := netadapter.NewNetworkAdapter(i) adapter, err := netadapter.NewNetworkAdapter(i)
if err != nil { if err != nil {
logger.Warn().Msgf("failed to get network adapter: %v", err) logger.Warn().Msgf("Failed to get network adapter: %v", err)
continue continue
} }
name, err := adapter.GetPropertyName() name, err := adapter.GetPropertyName()
if err != nil { if err != nil {
logger.Warn().Msgf("failed to get interface name: %v", err) logger.Warn().Msgf("Failed to get interface name: %v", err)
continue continue
} }
@@ -415,11 +415,11 @@ func ValidInterfaces(ctx context.Context) map[string]struct{} {
// if this is a physical adapter or FALSE if this is not a physical adapter." // if this is a physical adapter or FALSE if this is not a physical adapter."
physical, err := adapter.GetPropertyConnectorPresent() physical, err := adapter.GetPropertyConnectorPresent()
if err != nil { if err != nil {
logger.Debug().Msgf("failed to get network adapter connector present property: %v", err) logger.Debug().Msgf("Failed to get network adapter connector present property: %v", err)
continue continue
} }
if !physical { if !physical {
logger.Debug().Msgf("skipping non-physical adapter: %s", name) logger.Debug().Msgf("Skipping non-physical adapter: %s", name)
continue continue
} }
@@ -427,11 +427,11 @@ func ValidInterfaces(ctx context.Context) map[string]struct{} {
// because some interfaces are not physical but have a connector. // because some interfaces are not physical but have a connector.
hardware, err := adapter.GetPropertyHardwareInterface() hardware, err := adapter.GetPropertyHardwareInterface()
if err != nil { if err != nil {
logger.Debug().Msgf("failed to get network adapter hardware interface property: %v", err) logger.Debug().Msgf("Failed to get network adapter hardware interface property: %v", err)
continue continue
} }
if !hardware { if !hardware {
logger.Debug().Msgf("skipping non-hardware interface: %s", name) logger.Debug().Msgf("Skipping non-hardware interface: %s", name)
continue continue
} }
+4 -4
View File
@@ -20,7 +20,7 @@ var (
func HasIPv6(ctx context.Context) bool { func HasIPv6(ctx context.Context) bool {
hasIPv6Once.Do(func() { hasIPv6Once.Do(func() {
logger := LoggerFromCtx(ctx) logger := LoggerFromCtx(ctx)
logger.Debug().Msg("checking for IPv6 availability once") logger.Debug().Msg("Checking for ipv6 availability once")
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel() defer cancel()
val := ctrldnet.IPv6Available(ctx) val := ctrldnet.IPv6Available(ctx)
@@ -28,7 +28,7 @@ func HasIPv6(ctx context.Context) bool {
logger.Debug().Msgf("ipv6 availability: %v", val) logger.Debug().Msgf("ipv6 availability: %v", val)
mon, err := netmon.New(func(format string, args ...any) {}) mon, err := netmon.New(func(format string, args ...any) {})
if err != nil { if err != nil {
logger.Debug().Err(err).Msg("failed to monitor IPv6 state") logger.Debug().Err(err).Msg("Failed to monitor ipv6 state")
return return
} }
mon.RegisterChangeCallback(func(delta *netmon.ChangeDelta) { mon.RegisterChangeCallback(func(delta *netmon.ChangeDelta) {
@@ -37,7 +37,7 @@ func HasIPv6(ctx context.Context) bool {
if old != cur { if old != cur {
logger.Warn().Msgf("ipv6 availability changed, old: %v, new: %v", old, cur) logger.Warn().Msgf("ipv6 availability changed, old: %v, new: %v", old, cur)
} else { } else {
logger.Debug().Msg("ipv6 availability does not changed") logger.Debug().Msg("ipv6 availability does not Changed")
} }
ipv6Available.Store(cur) ipv6Available.Store(cur)
}) })
@@ -50,6 +50,6 @@ func HasIPv6(ctx context.Context) bool {
func DisableIPv6(ctx context.Context) { func DisableIPv6(ctx context.Context) {
if ipv6Available.CompareAndSwap(true, false) { if ipv6Available.CompareAndSwap(true, false) {
logger := LoggerFromCtx(ctx) logger := LoggerFromCtx(ctx)
logger.Debug().Msg("turned off IPv6 availability") logger.Debug().Msg("Turned off ipv6 availability")
} }
} }
+12 -12
View File
@@ -427,7 +427,7 @@ func (o *osResolver) resolve(ctx context.Context, msg *dns.Msg) (*dns.Msg, error
switch { switch {
case res.lan: case res.lan:
// Always prefer LAN responses immediately // Always prefer LAN responses immediately
Log(ctx, logger.Debug(), "using LAN answer from: %s", res.server) Log(ctx, logger.Debug(), "Using LAN answer from: %s", res.server)
cancel() cancel()
logAnswer(res.server) logAnswer(res.server)
return res.answer, nil return res.answer, nil
@@ -437,7 +437,7 @@ func (o *osResolver) resolve(ctx context.Context, msg *dns.Msg) (*dns.Msg, error
// if there are no LAN nameservers, we should not wait // if there are no LAN nameservers, we should not wait
// just use the first response // just use the first response
if len(nss) == 0 { if len(nss) == 0 {
Log(ctx, logger.Debug(), "using public answer from: %s", res.server) Log(ctx, logger.Debug(), "Using public answer from: %s", res.server)
cancel() cancel()
logAnswer(res.server) logAnswer(res.server)
return res.answer, nil return res.answer, nil
@@ -448,12 +448,12 @@ func (o *osResolver) resolve(ctx context.Context, msg *dns.Msg) (*dns.Msg, error
}) })
} }
case res.answer != nil: case res.answer != nil:
Log(ctx, logger.Debug(), "got non-success answer from: %s with code: %d", Log(ctx, logger.Debug(), "Got non-success answer from: %s with code: %d",
res.server, res.answer.Rcode) res.server, res.answer.Rcode)
// When there are no LAN nameservers, we should not wait // When there are no LAN nameservers, we should not wait
// for other nameservers to respond. // for other nameservers to respond.
if len(nss) == 0 { if len(nss) == 0 {
Log(ctx, logger.Debug(), "no lan nameservers using public non success answer") Log(ctx, logger.Debug(), "No lan nameservers using public non success answer")
cancel() cancel()
logAnswer(res.server) logAnswer(res.server)
return res.answer, nil return res.answer, nil
@@ -466,17 +466,17 @@ func (o *osResolver) resolve(ctx context.Context, msg *dns.Msg) (*dns.Msg, error
if len(publicResponses) > 0 { if len(publicResponses) > 0 {
resp := publicResponses[0] resp := publicResponses[0]
Log(ctx, logger.Debug(), "using public answer from: %s", resp.server) Log(ctx, logger.Debug(), "Using public answer from: %s", resp.server)
logAnswer(resp.server) logAnswer(resp.server)
return resp.answer, nil return resp.answer, nil
} }
if controldSuccessAnswer != nil { if controldSuccessAnswer != nil {
Log(ctx, logger.Debug(), "using ControlD answer from: %s", controldPublicDnsWithPort) Log(ctx, logger.Debug(), "Using ControlD answer from: %s", controldPublicDnsWithPort)
logAnswer(controldPublicDnsWithPort) logAnswer(controldPublicDnsWithPort)
return controldSuccessAnswer, nil return controldSuccessAnswer, nil
} }
if nonSuccessAnswer != nil { if nonSuccessAnswer != nil {
Log(ctx, logger.Debug(), "using non-success answer from: %s", nonSuccessServer) Log(ctx, logger.Debug(), "Using non-success answer from: %s", nonSuccessServer)
logAnswer(nonSuccessServer) logAnswer(nonSuccessServer)
return nonSuccessAnswer, nil return nonSuccessAnswer, nil
} }
@@ -563,12 +563,12 @@ func lookupIP(ctx context.Context, domain string, timeout int, bootstrapDNS []st
} }
logger := LoggerFromCtx(ctx) logger := LoggerFromCtx(ctx)
if bootstrapDNS == nil { if bootstrapDNS == nil {
logger.Debug().Msgf("empty bootstrap DNS") logger.Debug().Msgf("Empty bootstrap dns")
return nil return nil
} }
resolver := newResolverWithNameserver(bootstrapDNS) resolver := newResolverWithNameserver(bootstrapDNS)
logger.Debug().Msgf("resolving %q using bootstrap DNS %q", domain, bootstrapDNS) logger.Debug().Msgf("Resolving %q using bootstrap dns %q", domain, bootstrapDNS)
timeoutMs := 2000 timeoutMs := 2000
if timeout > 0 && timeout < timeoutMs { if timeout > 0 && timeout < timeoutMs {
@@ -612,15 +612,15 @@ func lookupIP(ctx context.Context, domain string, timeout int, bootstrapDNS []st
r, err := resolver.Resolve(ctx, m) r, err := resolver.Resolve(ctx, m)
if err != nil { if err != nil {
logger.Error().Err(err).Msgf("could not lookup %q record for domain %q", dns.TypeToString[dnsType], domain) logger.Error().Err(err).Msgf("Could not lookup %q record for domain %q", dns.TypeToString[dnsType], domain)
return return
} }
if r.Rcode != dns.RcodeSuccess { if r.Rcode != dns.RcodeSuccess {
logger.Error().Msgf("could not resolve domain %q, return code: %s", domain, dns.RcodeToString[r.Rcode]) logger.Error().Msgf("Could not resolve domain %q, return code: %s", domain, dns.RcodeToString[r.Rcode])
return return
} }
if len(r.Answer) == 0 { if len(r.Answer) == 0 {
logger.Error().Msg("no answer from OS resolver") logger.Error().Msg("No answer from os resolver")
return return
} }
target := targetDomain(r.Answer) target := targetDomain(r.Answer)