diff --git a/cmd/ctrld/cli.go b/cmd/ctrld/cli.go index 8484677..0774f0b 100644 --- a/cmd/ctrld/cli.go +++ b/cmd/ctrld/cli.go @@ -147,7 +147,7 @@ func initCLI() { } if daemon && runtime.GOOS == "windows" { - mainLog.Fatal().Msg("Cannot run in daemon mode. Please install a Windows service.") + mainLog.Load().Fatal().Msg("Cannot run in daemon mode. Please install a Windows service.") } if !daemon { @@ -156,10 +156,10 @@ func initCLI() { go func() { s, err := newService(p, svcConfig) if err != nil { - mainLog.Fatal().Err(err).Msg("failed create new service") + mainLog.Load().Fatal().Err(err).Msg("failed create new service") } if err := s.Run(); err != nil { - mainLog.Error().Err(err).Msg("failed to start service") + mainLog.Load().Error().Err(err).Msg("failed to start service") } }() } @@ -170,7 +170,7 @@ func initCLI() { readBase64Config(configBase64) processNoConfigFlags(noConfigStart) if err := v.Unmarshal(&cfg); err != nil { - mainLog.Fatal().Msgf("failed to unmarshal config: %v", err) + mainLog.Load().Fatal().Msgf("failed to unmarshal config: %v", err) } processLogAndCacheFlags() @@ -179,18 +179,18 @@ func initCLI() { // so it's able to log information in processCDFlags. initLogging() - mainLog.Info().Msgf("starting ctrld %s", curVersion()) - mainLog.Info().Msgf("os: %s", osVersion()) + mainLog.Load().Info().Msgf("starting ctrld %s", curVersion()) + mainLog.Load().Info().Msgf("os: %s", osVersion()) // Wait for network up. if !ctrldnet.Up() { - mainLog.Fatal().Msg("network is not up yet") + mainLog.Load().Fatal().Msg("network is not up yet") } p.router = router.New(&cfg, cdUID != "") cs, err := newControlServer(filepath.Join(homedir, ctrldControlUnixSock)) if err != nil { - mainLog.Warn().Err(err).Msg("could not create control server") + mainLog.Load().Warn().Err(err).Msg("could not create control server") } p.cs = cs @@ -198,7 +198,7 @@ func initCLI() { // time for validating server certificate. Some routers need NTP synchronization // to set the current time, so this check must happen before processCDFlags. if err := p.router.PreRun(); err != nil { - mainLog.Fatal().Err(err).Msg("failed to perform router pre-run check") + mainLog.Load().Fatal().Err(err).Msg("failed to perform router pre-run check") } oldLogPath := cfg.Service.LogPath @@ -213,19 +213,20 @@ func initCLI() { } if err := writeConfigFile(); err != nil { - mainLog.Fatal().Err(err).Msg("failed to write config file") + mainLog.Load().Fatal().Err(err).Msg("failed to write config file") } else { - mainLog.Info().Msg("writing config file to: " + defaultConfigFile) + mainLog.Load().Info().Msg("writing config file to: " + defaultConfigFile) } if newLogPath := cfg.Service.LogPath; newLogPath != "" && oldLogPath != newLogPath { // After processCDFlags, log config may change, so reset mainLog and re-init logging. - mainLog = zerolog.New(io.Discard) + l := zerolog.New(io.Discard) + mainLog.Store(&l) // Copy logs written so far to new log file if possible. if buf, err := os.ReadFile(oldLogPath); err == nil { if err := os.WriteFile(newLogPath, buf, os.FileMode(0o600)); err != nil { - mainLog.Warn().Err(err).Msg("could not copy old log file") + mainLog.Load().Warn().Err(err).Msg("could not copy old log file") } } initLoggingWithBackup(false) @@ -237,22 +238,22 @@ func initCLI() { if daemon { exe, err := os.Executable() if err != nil { - mainLog.Error().Err(err).Msg("failed to find the binary") + mainLog.Load().Error().Err(err).Msg("failed to find the binary") os.Exit(1) } curDir, err := os.Getwd() if err != nil { - mainLog.Error().Err(err).Msg("failed to get current working directory") + mainLog.Load().Error().Err(err).Msg("failed to get current working directory") os.Exit(1) } // If running as daemon, re-run the command in background, with daemon off. cmd := exec.Command(exe, append(os.Args[1:], "-d=false")...) cmd.Dir = curDir if err := cmd.Start(); err != nil { - mainLog.Error().Err(err).Msg("failed to start process as daemon") + mainLog.Load().Error().Err(err).Msg("failed to start process as daemon") os.Exit(1) } - mainLog.Info().Int("pid", cmd.Process.Pid).Msg("DNS proxy started") + mainLog.Load().Info().Int("pid", cmd.Process.Pid).Msg("DNS proxy started") os.Exit(0) } @@ -260,7 +261,7 @@ func initCLI() { for _, lc := range p.cfg.Listener { if shouldAllocateLoopbackIP(lc.IP) { if err := allocateIP(lc.IP); err != nil { - mainLog.Error().Err(err).Msgf("could not allocate IP: %s", lc.IP) + mainLog.Load().Error().Err(err).Msgf("could not allocate IP: %s", lc.IP) } } } @@ -269,7 +270,7 @@ func initCLI() { for _, lc := range p.cfg.Listener { if shouldAllocateLoopbackIP(lc.IP) { if err := deAllocateIP(lc.IP); err != nil { - mainLog.Error().Err(err).Msgf("could not de-allocate IP: %s", lc.IP) + mainLog.Load().Error().Err(err).Msgf("could not de-allocate IP: %s", lc.IP) } } } @@ -279,15 +280,15 @@ func initCLI() { rootCertPool = cp } p.onStarted = append(p.onStarted, func() { - mainLog.Debug().Msg("router setup") + mainLog.Load().Debug().Msg("router setup") if err := p.router.Setup(); err != nil { - mainLog.Error().Err(err).Msg("could not configure router") + mainLog.Load().Error().Err(err).Msg("could not configure router") } }) p.onStopped = append(p.onStopped, func() { - mainLog.Debug().Msg("router cleanup") + mainLog.Load().Debug().Msg("router cleanup") if err := p.router.Cleanup(); err != nil { - mainLog.Error().Err(err).Msg("could not cleanup router") + mainLog.Load().Error().Err(err).Msg("could not cleanup router") } p.resetDNS() }) @@ -342,7 +343,7 @@ func initCLI() { cfg: &cfg, } if err := p.router.ConfigureService(sc); err != nil { - mainLog.Fatal().Err(err).Msg("failed to configure service on router") + mainLog.Load().Fatal().Err(err).Msg("failed to configure service on router") } // No config path, generating config in HOME directory. @@ -386,7 +387,7 @@ func initCLI() { tryReadingConfig(writeDefaultConfig) if err := v.Unmarshal(&cfg); err != nil { - mainLog.Fatal().Msgf("failed to unmarshal config: %v", err) + mainLog.Load().Fatal().Msgf("failed to unmarshal config: %v", err) } initLogging() @@ -400,12 +401,12 @@ func initCLI() { s, err := newService(p, sc) if err != nil { - mainLog.Error().Msg(err.Error()) + mainLog.Load().Error().Msg(err.Error()) return } if router.Name() != "" { - mainLog.Debug().Msg("cleaning up router before installing") + mainLog.Load().Debug().Msg("cleaning up router before installing") _ = p.router.Cleanup() } @@ -417,12 +418,12 @@ func initCLI() { } if doTasks(tasks) { if err := p.router.Install(sc); err != nil { - mainLog.Warn().Err(err).Msg("post installation failed, please check system/service log for details error") + mainLog.Load().Warn().Err(err).Msg("post installation failed, please check system/service log for details error") return } status, err := s.Status() if err != nil { - mainLog.Warn().Err(err).Msg("could not get service status") + mainLog.Load().Warn().Err(err).Msg("could not get service status") return } @@ -430,15 +431,15 @@ func initCLI() { status = selfCheckStatus(status, domain) switch status { case service.StatusRunning: - mainLog.Notice().Msg("Service started") + mainLog.Load().Notice().Msg("Service started") default: marker := bytes.Repeat([]byte("="), 32) - mainLog.Error().Msg("ctrld service may not have started due to an error or misconfiguration, service log:") - _, _ = mainLog.Write(marker) + mainLog.Load().Error().Msg("ctrld service may not have started due to an error or misconfiguration, service log:") + _, _ = mainLog.Load().Write(marker) for msg := range runCmdLogCh { - _, _ = mainLog.Write([]byte(msg)) + _, _ = mainLog.Load().Write([]byte(msg)) } - _, _ = mainLog.Write(marker) + _, _ = mainLog.Load().Write(marker) uninstall(p, s) os.Exit(1) } @@ -473,7 +474,7 @@ func initCLI() { Run: func(cmd *cobra.Command, _ []string) { exe, err := os.Executable() if err != nil { - mainLog.Fatal().Msgf("could not find executable path: %v", err) + mainLog.Load().Fatal().Msgf("could not find executable path: %v", err) os.Exit(1) } flags := make([]string, 0) @@ -487,7 +488,7 @@ func initCLI() { command.Stderr = os.Stderr command.Stdin = os.Stdin if err := command.Run(); err != nil { - mainLog.Fatal().Msg(err.Error()) + mainLog.Load().Fatal().Msg(err.Error()) } }, } @@ -509,14 +510,14 @@ func initCLI() { p := &prog{router: router.New(&cfg, cdUID != "")} s, err := newService(p, svcConfig) if err != nil { - mainLog.Error().Msg(err.Error()) + mainLog.Load().Error().Msg(err.Error()) return } initLogging() if doTasks([]task{{s.Stop, true}}) { p.router.Cleanup() p.resetDNS() - mainLog.Notice().Msg("Service stopped") + mainLog.Load().Notice().Msg("Service stopped") } }, } @@ -533,12 +534,12 @@ func initCLI() { Run: func(cmd *cobra.Command, args []string) { s, err := newService(&prog{}, svcConfig) if err != nil { - mainLog.Error().Msg(err.Error()) + mainLog.Load().Error().Msg(err.Error()) return } initLogging() if doTasks([]task{{s.Restart, true}}) { - mainLog.Notice().Msg("Service restarted") + mainLog.Load().Notice().Msg("Service restarted") } }, } @@ -553,23 +554,23 @@ func initCLI() { Run: func(cmd *cobra.Command, args []string) { s, err := newService(&prog{}, svcConfig) if err != nil { - mainLog.Error().Msg(err.Error()) + mainLog.Load().Error().Msg(err.Error()) return } status, err := s.Status() if err != nil { - mainLog.Error().Msg(err.Error()) + mainLog.Load().Error().Msg(err.Error()) os.Exit(1) } switch status { case service.StatusUnknown: - mainLog.Notice().Msg("Unknown status") + mainLog.Load().Notice().Msg("Unknown status") os.Exit(2) case service.StatusRunning: - mainLog.Notice().Msg("Service is running") + mainLog.Load().Notice().Msg("Service is running") os.Exit(0) case service.StatusStopped: - mainLog.Notice().Msg("Service is stopped") + mainLog.Load().Notice().Msg("Service is stopped") os.Exit(1) } }, @@ -599,7 +600,7 @@ NOTE: Uninstalling will set DNS to values provided by DHCP.`, p := &prog{router: router.New(&cfg, cdUID != "")} s, err := newService(p, svcConfig) if err != nil { - mainLog.Error().Msg(err.Error()) + mainLog.Load().Error().Msg(err.Error()) return } if iface == "" { @@ -639,7 +640,7 @@ NOTE: Uninstalling will set DNS to values provided by DHCP.`, println() }) if err != nil { - mainLog.Error().Msg(err.Error()) + mainLog.Load().Error().Msg(err.Error()) } }, } @@ -767,18 +768,18 @@ NOTE: Uninstalling will set DNS to values provided by DHCP.`, Run: func(cmd *cobra.Command, args []string) { dir, err := userHomeDir() if err != nil { - mainLog.Fatal().Err(err).Msg("failed to find ctrld home dir") + mainLog.Load().Fatal().Err(err).Msg("failed to find ctrld home dir") } cc := newControlClient(filepath.Join(dir, ctrldControlUnixSock)) resp, err := cc.post(listClientsPath, nil) if err != nil { - mainLog.Fatal().Err(err).Msg("failed to get clients list") + mainLog.Load().Fatal().Err(err).Msg("failed to get clients list") } defer resp.Body.Close() var clients []*clientinfo.Client if err := json.NewDecoder(resp.Body).Decode(&clients); err != nil { - mainLog.Fatal().Err(err).Msg("failed to decode clients list result") + mainLog.Load().Fatal().Err(err).Msg("failed to decode clients list result") } map2Slice := func(m map[string]struct{}) []string { s := make([]string, 0, len(m)) @@ -847,7 +848,7 @@ func readConfigFile(writeDefaultConfig bool) bool { // If err == nil, there's a config supplied via `--config`, no default config written. err := v.ReadInConfig() if err == nil { - mainLog.Info().Msg("loading config file from: " + v.ConfigFileUsed()) + mainLog.Load().Info().Msg("loading config file from: " + v.ConfigFileUsed()) defaultConfigFile = v.ConfigFileUsed() return true } @@ -859,16 +860,16 @@ func readConfigFile(writeDefaultConfig bool) bool { // If error is viper.ConfigFileNotFoundError, write default config. if _, ok := err.(viper.ConfigFileNotFoundError); ok { if err := v.Unmarshal(&cfg); err != nil { - mainLog.Fatal().Msgf("failed to unmarshal default config: %v", err) + mainLog.Load().Fatal().Msgf("failed to unmarshal default config: %v", err) } if err := writeConfigFile(); err != nil { - mainLog.Fatal().Msgf("failed to write default config file: %v", err) + mainLog.Load().Fatal().Msgf("failed to write default config file: %v", err) } else { fp, err := filepath.Abs(defaultConfigFile) if err != nil { - mainLog.Fatal().Msgf("failed to get default config file path: %v", err) + mainLog.Load().Fatal().Msgf("failed to get default config file path: %v", err) } - mainLog.Info().Msg("writing default config file to: " + fp) + mainLog.Load().Info().Msg("writing default config file to: " + fp) } defaultConfigWritten = true return false @@ -879,13 +880,13 @@ func readConfigFile(writeDefaultConfig bool) bool { var i any if err, ok := toml.NewDecoder(f).Decode(&i).(*toml.DecodeError); ok { row, col := err.Position() - mainLog.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. - mainLog.Fatal().Msgf("failed to decode config file: %v", err) + mainLog.Load().Fatal().Msgf("failed to decode config file: %v", err) return false } @@ -895,7 +896,7 @@ func readBase64Config(configBase64 string) { } configStr, err := base64.StdEncoding.DecodeString(configBase64) if err != nil { - mainLog.Fatal().Msgf("invalid base64 config: %v", err) + mainLog.Load().Fatal().Msgf("invalid base64 config: %v", err) } // readBase64Config is called when: @@ -907,7 +908,7 @@ func readBase64Config(configBase64 string) { v = viper.NewWithOptions(viper.KeyDelimiter("::")) v.SetConfigType("toml") if err := v.ReadConfig(bytes.NewReader(configStr)); err != nil { - mainLog.Fatal().Msgf("failed to read base64 config: %v", err) + mainLog.Load().Fatal().Msgf("failed to read base64 config: %v", err) } } @@ -916,7 +917,7 @@ func processNoConfigFlags(noConfigStart bool) { return } if listenAddress == "" || primaryUpstream == "" { - mainLog.Fatal().Msg(`"listen" and "primary_upstream" flags must be set in no config mode`) + mainLog.Load().Fatal().Msg(`"listen" and "primary_upstream" flags must be set in no config mode`) } processListenFlag() @@ -952,7 +953,7 @@ func processNoConfigFlags(noConfigStart bool) { } func processCDFlags() { - logger := mainLog.With().Str("mode", "cd").Logger() + logger := mainLog.Load().With().Str("mode", "cd").Logger() logger.Info().Msgf("fetching Controld D configuration from API: %s", cdUID) resolverConfig, err := controld.FetchResolverConfig(cdUID, rootCmd.Version, cdDev) if uer, ok := err.(*controld.UtilityErrorResponse); ok && uer.ErrorField.Code == controld.InvalidConfigCode { @@ -993,7 +994,7 @@ func processCDFlags() { logger.Info().Msg("using defined custom config of Control-D resolver") readBase64Config(resolverConfig.Ctrld.CustomConfig) if err := v.Unmarshal(&cfg); err != nil { - mainLog.Fatal().Msgf("failed to unmarshal config: %v", err) + mainLog.Load().Fatal().Msgf("failed to unmarshal config: %v", err) } } else { cfg.Network = make(map[string]*ctrld.NetworkConfig) @@ -1034,11 +1035,11 @@ func processListenFlag() { } host, portStr, err := net.SplitHostPort(listenAddress) if err != nil { - mainLog.Fatal().Msgf("invalid listener address: %v", err) + mainLog.Load().Fatal().Msgf("invalid listener address: %v", err) } port, err := strconv.Atoi(portStr) if err != nil { - mainLog.Fatal().Msgf("invalid port number: %v", err) + mainLog.Load().Fatal().Msgf("invalid port number: %v", err) } lc := &ctrld.ListenerConfig{ IP: host, @@ -1094,7 +1095,7 @@ func defaultIfaceName() string { if oi := osinfo.New(); strings.Contains(oi.String(), "Microsoft") { return "lo" } - mainLog.Fatal().Err(err).Msg("failed to get default route interface") + mainLog.Load().Fatal().Err(err).Msg("failed to get default route interface") } return dri } @@ -1106,7 +1107,7 @@ func selfCheckStatus(status service.Status, domain string) service.Status { } dir, err := userHomeDir() if err != nil { - mainLog.Error().Err(err).Msg("failed to check ctrld listener status: could not get home directory") + mainLog.Load().Error().Err(err).Msg("failed to check ctrld listener status: could not get home directory") return service.StatusUnknown } @@ -1115,7 +1116,7 @@ func selfCheckStatus(status service.Status, domain string) service.Status { ctx := context.Background() maxAttempts := 20 - mainLog.Debug().Msg("waiting for ctrld listener to be ready") + mainLog.Load().Debug().Msg("waiting for ctrld listener to be ready") cc := newControlClient(filepath.Join(dir, ctrldControlUnixSock)) // The socket control server may not start yet, so attempt to ping @@ -1129,17 +1130,17 @@ func selfCheckStatus(status service.Status, domain string) service.Status { } resp, err := cc.post(startedPath, nil) if err != nil { - mainLog.Error().Err(err).Msg("failed to connect to control server") + mainLog.Load().Error().Err(err).Msg("failed to connect to control server") return service.StatusUnknown } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - mainLog.Error().Msg("ctrld listener is not ready") + mainLog.Load().Error().Msg("ctrld listener is not ready") return service.StatusUnknown } - mainLog.Debug().Msg("ctrld listener is ready") - mainLog.Debug().Msg("performing self-check") + mainLog.Load().Debug().Msg("ctrld listener is ready") + mainLog.Load().Debug().Msg("performing self-check") bo = backoff.NewBackoff("self-check", logf, 10*time.Second) bo.LogLongerThan = 500 * time.Millisecond c := new(dns.Client) @@ -1149,14 +1150,14 @@ func selfCheckStatus(status service.Status, domain string) service.Status { ) if err := v.ReadInConfig(); err != nil { - mainLog.Fatal().Err(err).Msg("failed to read new config") + mainLog.Load().Fatal().Err(err).Msg("failed to read new config") } if err := v.Unmarshal(&cfg); err != nil { - mainLog.Fatal().Err(err).Msg("failed to update new config") + mainLog.Load().Fatal().Err(err).Msg("failed to update new config") } watcher, err := fsnotify.NewWatcher() if err != nil { - mainLog.Error().Err(err).Msg("could not watch config change") + mainLog.Load().Error().Err(err).Msg("could not watch config change") return service.StatusUnknown } defer watcher.Close() @@ -1165,7 +1166,7 @@ func selfCheckStatus(status service.Status, domain string) service.Status { mu.Lock() defer mu.Unlock() if err := v.UnmarshalKey("listener", &lcChanged); err != nil { - mainLog.Error().Msgf("failed to unmarshal listener config: %v", err) + mainLog.Load().Error().Msgf("failed to unmarshal listener config: %v", err) return } }) @@ -1187,27 +1188,27 @@ func selfCheckStatus(status service.Status, domain string) service.Status { m.RecursionDesired = true r, _, err := c.ExchangeContext(ctx, m, net.JoinHostPort(lc.IP, strconv.Itoa(lc.Port))) if r != nil && r.Rcode == dns.RcodeSuccess && len(r.Answer) > 0 { - mainLog.Debug().Msgf("self-check against %q succeeded", domain) + mainLog.Load().Debug().Msgf("self-check against %q succeeded", domain) return status } lastAnswer = r lastErr = err bo.BackOff(ctx, fmt.Errorf("ExchangeContext: %w", err)) } - mainLog.Debug().Msgf("self-check against %q failed", domain) + mainLog.Load().Debug().Msgf("self-check against %q failed", domain) lc := cfg.FirstListener() addr := net.JoinHostPort(lc.IP, strconv.Itoa(lc.Port)) marker := strings.Repeat("=", 32) - mainLog.Debug().Msg(marker) - mainLog.Debug().Msgf("listener address : %s", addr) - mainLog.Debug().Msgf("last error : %v", lastErr) + mainLog.Load().Debug().Msg(marker) + mainLog.Load().Debug().Msgf("listener address : %s", addr) + mainLog.Load().Debug().Msgf("last error : %v", lastErr) if lastAnswer != nil { - mainLog.Debug().Msgf("last answer from ctrld :") - mainLog.Debug().Msg(marker) + mainLog.Load().Debug().Msgf("last answer from ctrld :") + mainLog.Load().Debug().Msg(marker) for _, s := range strings.Split(lastAnswer.String(), "\n") { - mainLog.Debug().Msgf("%s", s) + mainLog.Load().Debug().Msgf("%s", s) } - mainLog.Debug().Msg(marker) + mainLog.Load().Debug().Msg(marker) } return service.StatusUnknown } @@ -1260,7 +1261,7 @@ func readConfig(writeDefaultConfig bool) { dir, err := userHomeDir() if err != nil { - mainLog.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 { ctrld.SetConfigNameWithPath(v, config.name, dir) @@ -1279,20 +1280,20 @@ func uninstall(p *prog, s service.Service) { initLogging() if doTasks(tasks) { if err := p.router.ConfigureService(svcConfig); err != nil { - mainLog.Fatal().Err(err).Msg("could not configure service") + mainLog.Load().Fatal().Err(err).Msg("could not configure service") } if err := p.router.Uninstall(svcConfig); err != nil { - mainLog.Warn().Err(err).Msg("post uninstallation failed, please check system/service log for details error") + mainLog.Load().Warn().Err(err).Msg("post uninstallation failed, please check system/service log for details error") return } p.resetDNS() if router.Name() != "" { - mainLog.Debug().Msg("Router cleanup") + mainLog.Load().Debug().Msg("Router cleanup") } // Stop already did router.Cleanup and report any error if happens, // ignoring error here to prevent false positive. _ = p.router.Cleanup() - mainLog.Notice().Msg("Service uninstalled") + mainLog.Load().Notice().Msg("Service uninstalled") return } } @@ -1305,7 +1306,7 @@ func validateConfig(cfg *ctrld.Config) { var ve validator.ValidationErrors if errors.As(err, &ve) { for _, fe := range ve { - mainLog.Error().Msgf("invalid config: %s: %s", fe.Namespace(), fieldErrorMsg(fe)) + mainLog.Load().Error().Msgf("invalid config: %s: %s", fe.Namespace(), fieldErrorMsg(fe)) } } os.Exit(1) @@ -1472,14 +1473,14 @@ func updateListenerConfig() { maxAttempts := 10 for { if attempts == maxAttempts { - logMsg(mainLog.Fatal(), n, "could not find available listen ip and port") + logMsg(mainLog.Load().Fatal(), n, "could not find available listen ip and port") } addr := net.JoinHostPort(listener.IP, strconv.Itoa(listener.Port)) if listenOk(addr) { break } if !check.IP && !check.Port { - logMsg(mainLog.Fatal(), n, "failed to listen on: %s", addr) + logMsg(mainLog.Load().Fatal(), n, "failed to listen on: %s", addr) } if tryAllPort53 { tryAllPort53 = false @@ -1490,7 +1491,7 @@ func updateListenerConfig() { listener.Port = 53 } if check.IP { - logMsg(mainLog.Warn(), n, "could not listen on address: %s, trying: %s", addr, net.JoinHostPort(listener.IP, strconv.Itoa(listener.Port))) + logMsg(mainLog.Load().Warn(), n, "could not listen on address: %s, trying: %s", addr, net.JoinHostPort(listener.IP, strconv.Itoa(listener.Port))) } continue } @@ -1503,7 +1504,7 @@ func updateListenerConfig() { listener.Port = 53 } if check.IP { - logMsg(mainLog.Warn(), n, "could not listen on address: %s, trying localhost: %s", addr, net.JoinHostPort(listener.IP, strconv.Itoa(listener.Port))) + logMsg(mainLog.Load().Warn(), n, "could not listen on address: %s, trying localhost: %s", addr, net.JoinHostPort(listener.IP, strconv.Itoa(listener.Port))) } continue } @@ -1515,7 +1516,7 @@ func updateListenerConfig() { if check.Port { listener.Port = 5354 } - logMsg(mainLog.Warn(), n, "could not listen on address: %s, trying current ip with port 5354", addr) + logMsg(mainLog.Load().Warn(), n, "could not listen on address: %s, trying current ip with port 5354", addr) continue } if tryPort5354 { @@ -1526,7 +1527,7 @@ func updateListenerConfig() { if check.Port { listener.Port = 5354 } - logMsg(mainLog.Warn(), n, "could not listen on address: %s, trying 0.0.0.0:5354", addr) + logMsg(mainLog.Load().Warn(), n, "could not listen on address: %s, trying 0.0.0.0:5354", addr) continue } if check.IP && !isZeroIP { // for "0.0.0.0" or "::", we only need to try new port. @@ -1540,9 +1541,9 @@ func updateListenerConfig() { listener.Port = oldPort } if listener.IP == oldIP && listener.Port == oldPort { - logMsg(mainLog.Fatal(), n, "could not listener on: %s", net.JoinHostPort(listener.IP, strconv.Itoa(listener.Port))) + logMsg(mainLog.Load().Fatal(), n, "could not listener on: %s", net.JoinHostPort(listener.IP, strconv.Itoa(listener.Port))) } - logMsg(mainLog.Warn(), n, "could not listen on address: %s, pick a random ip+port", addr) + logMsg(mainLog.Load().Warn(), n, "could not listen on address: %s, pick a random ip+port", addr) attempts++ } } @@ -1555,7 +1556,7 @@ func updateListenerConfig() { // ip address, other than "127.0.0.1", so trying to listen on default route interface // address instead. if ip := net.ParseIP(listener.IP); ip != nil && ip.IsLoopback() && ip.String() != "127.0.0.1" { - logMsg(mainLog.Warn(), n, "using loopback interface do not work with systemd-resolved") + logMsg(mainLog.Load().Warn(), n, "using loopback interface do not work with systemd-resolved") found := false if netIface, _ := net.InterfaceByName(defaultIfaceName()); netIface != nil { addrs, _ := netIface.Addrs() @@ -1565,14 +1566,14 @@ func updateListenerConfig() { if listenOk(addr) { found = true listener.IP = netIP.IP.String() - logMsg(mainLog.Warn(), n, "use %s as listener address", listener.IP) + logMsg(mainLog.Load().Warn(), n, "use %s as listener address", listener.IP) break } } } } if !found { - logMsg(mainLog.Fatal(), n, "could not use %q as DNS nameserver with systemd resolved", listener.IP) + logMsg(mainLog.Load().Fatal(), n, "could not use %q as DNS nameserver with systemd resolved", listener.IP) } } } diff --git a/cmd/ctrld/dns_proxy.go b/cmd/ctrld/dns_proxy.go index ba0c3be..81a373e 100644 --- a/cmd/ctrld/dns_proxy.go +++ b/cmd/ctrld/dns_proxy.go @@ -44,7 +44,7 @@ func (p *prog) serveDNS(listenerNum string) error { listenerConfig := p.cfg.Listener[listenerNum] // make sure ip is allocated if allocErr := p.allocateIP(listenerConfig.IP); allocErr != nil { - mainLog.Error().Err(allocErr).Str("ip", listenerConfig.IP).Msg("serveUDP: failed to allocate listen ip") + mainLog.Load().Error().Err(allocErr).Str("ip", listenerConfig.IP).Msg("serveUDP: failed to allocate listen ip") return allocErr } var failoverRcodes []int @@ -64,7 +64,7 @@ func (p *prog) serveDNS(listenerNum string) error { fmtSrcToDest := fmtRemoteToLocal(listenerNum, remoteAddr.String(), w.LocalAddr().String()) t := time.Now() ctx := context.WithValue(context.Background(), ctrld.ReqIdCtxKey{}, reqId) - ctrld.Log(ctx, mainLog.Debug(), "%s received query: %s %s", fmtSrcToDest, dns.TypeToString[q.Qtype], domain) + ctrld.Log(ctx, mainLog.Load().Debug(), "%s received query: %s %s", fmtSrcToDest, dns.TypeToString[q.Qtype], domain) upstreams, matched := p.upstreamFor(ctx, listenerNum, listenerConfig, remoteAddr, domain) var answer *dns.Msg if !matched && listenerConfig.Restricted { @@ -73,10 +73,10 @@ func (p *prog) serveDNS(listenerNum string) error { } else { answer = p.proxy(ctx, upstreams, failoverRcodes, m, ci) rtt := time.Since(t) - ctrld.Log(ctx, mainLog.Debug(), "received response of %d bytes in %s", answer.Len(), rtt) + ctrld.Log(ctx, mainLog.Load().Debug(), "received response of %d bytes in %s", answer.Len(), rtt) } if err := w.WriteMsg(answer); err != nil { - ctrld.Log(ctx, mainLog.Error().Err(err), "serveUDP: failed to send DNS response to client") + ctrld.Log(ctx, mainLog.Load().Error().Err(err), "serveUDP: failed to send DNS response to client") } }) @@ -93,7 +93,7 @@ func (p *prog) serveDNS(listenerNum string) error { case err := <-errCh: // Local ipv6 listener should not terminate ctrld. // It's a workaround for a quirk on Windows. - mainLog.Warn().Err(err).Msg("local ipv6 listener failed") + mainLog.Load().Warn().Err(err).Msg("local ipv6 listener failed") } return nil }) @@ -113,7 +113,7 @@ func (p *prog) serveDNS(listenerNum string) error { case err := <-errCh: // RFC1918 listener should not terminate ctrld. // It's a workaround for a quirk on system with systemd-resolved. - mainLog.Warn().Err(err).Msgf("could not listen on %s: %s", proto, listenAddr) + mainLog.Load().Warn().Err(err).Msgf("could not listen on %s: %s", proto, listenAddr) } }() } @@ -157,13 +157,13 @@ func (p *prog) upstreamFor(ctx context.Context, defaultUpstreamNum string, lc *c defer func() { if !matched && lc.Restricted { - ctrld.Log(ctx, mainLog.Info(), "query refused, %s does not match any network policy", addr.String()) + ctrld.Log(ctx, mainLog.Load().Info(), "query refused, %s does not match any network policy", addr.String()) return } if matched { - ctrld.Log(ctx, mainLog.Info(), "%s, %s, %s -> %v", matchedPolicy, matchedNetwork, matchedRule, upstreams) + ctrld.Log(ctx, mainLog.Load().Info(), "%s, %s, %s -> %v", matchedPolicy, matchedNetwork, matchedRule, upstreams) } else { - ctrld.Log(ctx, mainLog.Info(), "no explicit policy matched, using default routing -> %v", upstreams) + ctrld.Log(ctx, mainLog.Load().Info(), "no explicit policy matched, using default routing -> %v", upstreams) } }() @@ -246,7 +246,7 @@ func (p *prog) proxy(ctx context.Context, upstreams []string, failoverRcodes []i answer.SetRcode(msg, answer.Rcode) now := time.Now() if cachedValue.Expire.After(now) { - ctrld.Log(ctx, mainLog.Debug(), "hit cached response") + ctrld.Log(ctx, mainLog.Load().Debug(), "hit cached response") setCachedAnswerTTL(answer, now, cachedValue.Expire) return answer } @@ -254,10 +254,10 @@ func (p *prog) proxy(ctx context.Context, upstreams []string, failoverRcodes []i } } resolve1 := func(n int, upstreamConfig *ctrld.UpstreamConfig, msg *dns.Msg) (*dns.Msg, error) { - ctrld.Log(ctx, mainLog.Debug(), "sending query to %s: %s", upstreams[n], upstreamConfig.Name) + ctrld.Log(ctx, mainLog.Load().Debug(), "sending query to %s: %s", upstreams[n], upstreamConfig.Name) dnsResolver, err := ctrld.NewResolver(upstreamConfig) if err != nil { - ctrld.Log(ctx, mainLog.Error().Err(err), "failed to create resolver") + ctrld.Log(ctx, mainLog.Load().Error().Err(err), "failed to create resolver") return nil, err } resolveCtx, cancel := context.WithCancel(ctx) @@ -271,12 +271,12 @@ func (p *prog) proxy(ctx context.Context, upstreams []string, failoverRcodes []i } resolve := func(n int, upstreamConfig *ctrld.UpstreamConfig, msg *dns.Msg) *dns.Msg { if upstreamConfig.UpstreamSendClientInfo() && ci != nil { - ctrld.Log(ctx, mainLog.Debug(), "including client info with the request") + ctrld.Log(ctx, mainLog.Load().Debug(), "including client info with the request") ctx = context.WithValue(ctx, ctrld.ClientInfoCtxKey{}, ci) } answer, err := resolve1(n, upstreamConfig, msg) if err != nil { - ctrld.Log(ctx, mainLog.Error().Err(err), "failed to resolve query") + ctrld.Log(ctx, mainLog.Load().Error().Err(err), "failed to resolve query") return nil } return answer @@ -288,7 +288,7 @@ func (p *prog) proxy(ctx context.Context, upstreams []string, failoverRcodes []i answer := resolve(n, upstreamConfig, msg) if answer == nil { if serveStaleCache && staleAnswer != nil { - ctrld.Log(ctx, mainLog.Debug(), "serving stale cached response") + ctrld.Log(ctx, mainLog.Load().Debug(), "serving stale cached response") now := time.Now() setCachedAnswerTTL(staleAnswer, now, now.Add(staleTTL)) return staleAnswer @@ -296,7 +296,7 @@ func (p *prog) proxy(ctx context.Context, upstreams []string, failoverRcodes []i continue } if answer.Rcode != dns.RcodeSuccess && len(upstreamConfigs) > 1 && containRcode(failoverRcodes, answer.Rcode) { - ctrld.Log(ctx, mainLog.Debug(), "failover rcode matched, process to next upstream") + ctrld.Log(ctx, mainLog.Load().Debug(), "failover rcode matched, process to next upstream") continue } @@ -312,11 +312,11 @@ func (p *prog) proxy(ctx context.Context, upstreams []string, failoverRcodes []i } setCachedAnswerTTL(answer, now, expired) p.cache.Add(dnscache.NewKey(msg, upstreams[n]), dnscache.NewValue(answer, expired)) - ctrld.Log(ctx, mainLog.Debug(), "add cached response") + ctrld.Log(ctx, mainLog.Load().Debug(), "add cached response") } return answer } - ctrld.Log(ctx, mainLog.Error(), "all upstreams failed") + ctrld.Log(ctx, mainLog.Load().Error(), "all upstreams failed") answer := new(dns.Msg) answer.SetRcode(msg, dns.RcodeServerFailure) return answer @@ -490,7 +490,7 @@ func runDNSServer(addr, network string, handler dns.Handler) (*dns.Server, <-cha defer close(errCh) if err := s.ListenAndServe(); err != nil { waitLock.Unlock() - mainLog.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 } }() diff --git a/cmd/ctrld/main.go b/cmd/ctrld/main.go index 2573f6e..75e7d2b 100644 --- a/cmd/ctrld/main.go +++ b/cmd/ctrld/main.go @@ -4,6 +4,7 @@ import ( "io" "os" "path/filepath" + "sync/atomic" "time" "github.com/kardianos/service" @@ -31,15 +32,20 @@ var ( iface string ifaceStartStop string - mainLog = zerolog.New(io.Discard) + mainLog atomic.Pointer[zerolog.Logger] consoleWriter zerolog.ConsoleWriter ) +func init() { + l := zerolog.New(io.Discard) + mainLog.Store(&l) +} + func main() { ctrld.InitConfig(v, "ctrld") initCLI() if err := rootCmd.Execute(); err != nil { - mainLog.Error().Msg(err.Error()) + mainLog.Load().Error().Msg(err.Error()) os.Exit(1) } } @@ -63,7 +69,8 @@ func initConsoleLogging() { w.TimeFormat = time.StampMilli }) multi := zerolog.MultiLevelWriter(consoleWriter) - mainLog = mainLog.Output(multi).With().Timestamp().Logger() + l := mainLog.Load().Output(multi).With().Timestamp().Logger() + mainLog.Store(&l) switch { case silent: zerolog.SetGlobalLevel(zerolog.NoLevel) @@ -92,7 +99,7 @@ func initLoggingWithBackup(doBackup bool) { if logFilePath := normalizeLogFilePath(cfg.Service.LogPath); logFilePath != "" { // Create parent directory if necessary. if err := os.MkdirAll(filepath.Dir(logFilePath), 0750); err != nil { - mainLog.Error().Msgf("failed to create log path: %v", err) + mainLog.Load().Error().Msgf("failed to create log path: %v", err) os.Exit(1) } @@ -101,7 +108,7 @@ func initLoggingWithBackup(doBackup bool) { if doBackup { // Backup old log file with .1 suffix. if err := os.Rename(logFilePath, logFilePath+".1"); err != nil && !os.IsNotExist(err) { - mainLog.Error().Msgf("could not backup old log file: %v", err) + mainLog.Load().Error().Msgf("could not backup old log file: %v", err) } else { // Backup was created, set flags for truncating old log file. flags = os.O_CREATE | os.O_RDWR @@ -109,16 +116,17 @@ func initLoggingWithBackup(doBackup bool) { } logFile, err := os.OpenFile(logFilePath, flags, os.FileMode(0o600)) if err != nil { - mainLog.Error().Msgf("failed to create log file: %v", err) + mainLog.Load().Error().Msgf("failed to create log file: %v", err) os.Exit(1) } writers = append(writers, logFile) } writers = append(writers, consoleWriter) multi := zerolog.MultiLevelWriter(writers...) - mainLog = mainLog.Output(multi).With().Timestamp().Logger() + l := mainLog.Load().Output(multi).With().Timestamp().Logger() + mainLog.Store(&l) // TODO: find a better way. - ctrld.ProxyLog = mainLog + ctrld.ProxyLogger.Store(&l) zerolog.SetGlobalLevel(zerolog.NoticeLevel) logLevel := cfg.Service.LogLevel @@ -136,7 +144,7 @@ func initLoggingWithBackup(doBackup bool) { } level, err := zerolog.ParseLevel(logLevel) if err != nil { - mainLog.Warn().Err(err).Msg("could not set log level") + mainLog.Load().Warn().Err(err).Msg("could not set log level") return } zerolog.SetGlobalLevel(level) diff --git a/cmd/ctrld/main_test.go b/cmd/ctrld/main_test.go index 2a2e079..9654fb6 100644 --- a/cmd/ctrld/main_test.go +++ b/cmd/ctrld/main_test.go @@ -11,6 +11,7 @@ import ( var logOutput strings.Builder func TestMain(m *testing.M) { - mainLog = zerolog.New(&logOutput) + l := zerolog.New(&logOutput) + mainLog.Store(&l) os.Exit(m.Run()) } diff --git a/cmd/ctrld/net_darwin.go b/cmd/ctrld/net_darwin.go index 0939c85..f0f7e5a 100644 --- a/cmd/ctrld/net_darwin.go +++ b/cmd/ctrld/net_darwin.go @@ -17,7 +17,7 @@ func patchNetIfaceName(iface *net.Interface) error { if name := networkServiceName(iface.Name, bytes.NewReader(b)); name != "" { iface.Name = name - mainLog.Debug().Str("network_service", name).Msg("found network service name for interface") + mainLog.Load().Debug().Str("network_service", name).Msg("found network service name for interface") } return nil } diff --git a/cmd/ctrld/netlink_linux.go b/cmd/ctrld/netlink_linux.go index 86eb45b..7657fc3 100644 --- a/cmd/ctrld/netlink_linux.go +++ b/cmd/ctrld/netlink_linux.go @@ -10,7 +10,7 @@ func (p *prog) watchLinkState() { done := make(chan struct{}) defer close(done) if err := netlink.LinkSubscribe(ch, done); err != nil { - mainLog.Warn().Err(err).Msg("could not subscribe link") + mainLog.Load().Warn().Err(err).Msg("could not subscribe link") return } for lu := range ch { @@ -18,7 +18,7 @@ func (p *prog) watchLinkState() { continue } if lu.Change&unix.IFF_UP != 0 { - mainLog.Debug().Msgf("link state changed, re-bootstrapping") + mainLog.Load().Debug().Msgf("link state changed, re-bootstrapping") for _, uc := range p.cfg.Upstream { uc.ReBootstrap() } diff --git a/cmd/ctrld/network_manager_linux.go b/cmd/ctrld/network_manager_linux.go index fe00f3a..799c2dc 100644 --- a/cmd/ctrld/network_manager_linux.go +++ b/cmd/ctrld/network_manager_linux.go @@ -24,37 +24,37 @@ var networkManagerCtrldConfFile = filepath.Join(nmConfDir, nmCtrldConfFilename) func setupNetworkManager() error { if content, _ := os.ReadFile(nmCtrldConfContent); string(content) == nmCtrldConfContent { - mainLog.Debug().Msg("NetworkManager already setup, nothing to do") + mainLog.Load().Debug().Msg("NetworkManager already setup, nothing to do") return nil } err := os.WriteFile(networkManagerCtrldConfFile, []byte(nmCtrldConfContent), os.FileMode(0644)) if os.IsNotExist(err) { - mainLog.Debug().Msg("NetworkManager is not available") + mainLog.Load().Debug().Msg("NetworkManager is not available") return nil } if err != nil { - mainLog.Debug().Err(err).Msg("could not write NetworkManager ctrld config file") + mainLog.Load().Debug().Err(err).Msg("could not write NetworkManager ctrld config file") return err } reloadNetworkManager() - mainLog.Debug().Msg("setup NetworkManager done") + mainLog.Load().Debug().Msg("setup NetworkManager done") return nil } func restoreNetworkManager() error { err := os.Remove(networkManagerCtrldConfFile) if os.IsNotExist(err) { - mainLog.Debug().Msg("NetworkManager is not available") + mainLog.Load().Debug().Msg("NetworkManager is not available") return nil } if err != nil { - mainLog.Debug().Err(err).Msg("could not remove NetworkManager ctrld config file") + mainLog.Load().Debug().Err(err).Msg("could not remove NetworkManager ctrld config file") return err } reloadNetworkManager() - mainLog.Debug().Msg("restore NetworkManager done") + mainLog.Load().Debug().Msg("restore NetworkManager done") return nil } @@ -63,14 +63,14 @@ func reloadNetworkManager() { defer cancel() conn, err := dbus.NewSystemConnectionContext(ctx) if err != nil { - mainLog.Error().Err(err).Msg("could not create new system connection") + mainLog.Load().Error().Err(err).Msg("could not create new system connection") return } defer conn.Close() waitCh := make(chan string) if _, err := conn.ReloadUnitContext(ctx, nmSystemdUnitName, "ignore-dependencies", waitCh); err != nil { - mainLog.Debug().Err(err).Msg("could not reload NetworkManager") + mainLog.Load().Debug().Err(err).Msg("could not reload NetworkManager") } <-waitCh } diff --git a/cmd/ctrld/os_darwin.go b/cmd/ctrld/os_darwin.go index 04bc66b..ac872d8 100644 --- a/cmd/ctrld/os_darwin.go +++ b/cmd/ctrld/os_darwin.go @@ -12,7 +12,7 @@ import ( func allocateIP(ip string) error { cmd := exec.Command("ifconfig", "lo0", "alias", ip, "up") if err := cmd.Run(); err != nil { - mainLog.Error().Err(err).Msg("allocateIP failed") + mainLog.Load().Error().Err(err).Msg("allocateIP failed") return err } return nil @@ -21,7 +21,7 @@ func allocateIP(ip string) error { func deAllocateIP(ip string) error { cmd := exec.Command("ifconfig", "lo0", "-alias", ip) if err := cmd.Run(); err != nil { - mainLog.Error().Err(err).Msg("deAllocateIP failed") + mainLog.Load().Error().Err(err).Msg("deAllocateIP failed") return err } return nil @@ -36,7 +36,7 @@ func setDNS(iface *net.Interface, nameservers []string) error { args = append(args, nameservers...) if err := exec.Command(cmd, args...).Run(); err != nil { - mainLog.Error().Err(err).Msgf("setDNS failed, ips = %q", nameservers) + mainLog.Load().Error().Err(err).Msgf("setDNS failed, ips = %q", nameservers) return err } return nil @@ -48,7 +48,7 @@ func resetDNS(iface *net.Interface) error { args := []string{"-setdnsservers", iface.Name, "empty"} if err := exec.Command(cmd, args...).Run(); err != nil { - mainLog.Error().Err(err).Msgf("resetDNS failed") + mainLog.Load().Error().Err(err).Msgf("resetDNS failed") return err } return nil diff --git a/cmd/ctrld/os_freebsd.go b/cmd/ctrld/os_freebsd.go index da1a05a..5a1fa36 100644 --- a/cmd/ctrld/os_freebsd.go +++ b/cmd/ctrld/os_freebsd.go @@ -14,7 +14,7 @@ import ( func allocateIP(ip string) error { cmd := exec.Command("ifconfig", "lo0", ip, "alias") if err := cmd.Run(); err != nil { - mainLog.Error().Err(err).Msg("allocateIP failed") + mainLog.Load().Error().Err(err).Msg("allocateIP failed") return err } return nil @@ -23,7 +23,7 @@ func allocateIP(ip string) error { func deAllocateIP(ip string) error { cmd := exec.Command("ifconfig", "lo0", ip, "-alias") if err := cmd.Run(); err != nil { - mainLog.Error().Err(err).Msg("deAllocateIP failed") + mainLog.Load().Error().Err(err).Msg("deAllocateIP failed") return err } return nil @@ -33,7 +33,7 @@ func deAllocateIP(ip string) error { func setDNS(iface *net.Interface, nameservers []string) error { r, err := dns.NewOSConfigurator(logf, iface.Name) if err != nil { - mainLog.Error().Err(err).Msg("failed to create DNS OS configurator") + mainLog.Load().Error().Err(err).Msg("failed to create DNS OS configurator") return err } @@ -43,7 +43,7 @@ func setDNS(iface *net.Interface, nameservers []string) error { } if err := r.SetDNS(dns.OSConfig{Nameservers: ns}); err != nil { - mainLog.Error().Err(err).Msg("failed to set DNS") + mainLog.Load().Error().Err(err).Msg("failed to set DNS") return err } return nil @@ -52,12 +52,12 @@ func setDNS(iface *net.Interface, nameservers []string) error { func resetDNS(iface *net.Interface) error { r, err := dns.NewOSConfigurator(logf, iface.Name) if err != nil { - mainLog.Error().Err(err).Msg("failed to create DNS OS configurator") + mainLog.Load().Error().Err(err).Msg("failed to create DNS OS configurator") return err } if err := r.Close(); err != nil { - mainLog.Error().Err(err).Msg("failed to rollback DNS setting") + mainLog.Load().Error().Err(err).Msg("failed to rollback DNS setting") return err } return nil diff --git a/cmd/ctrld/os_linux.go b/cmd/ctrld/os_linux.go index 570cabc..e26e396 100644 --- a/cmd/ctrld/os_linux.go +++ b/cmd/ctrld/os_linux.go @@ -29,7 +29,7 @@ import ( func allocateIP(ip string) error { cmd := exec.Command("ip", "a", "add", ip+"/24", "dev", "lo") if out, err := cmd.CombinedOutput(); err != nil { - mainLog.Error().Err(err).Msgf("allocateIP failed: %s", string(out)) + mainLog.Load().Error().Err(err).Msgf("allocateIP failed: %s", string(out)) return err } return nil @@ -38,7 +38,7 @@ func allocateIP(ip string) error { func deAllocateIP(ip string) error { cmd := exec.Command("ip", "a", "del", ip+"/24", "dev", "lo") if err := cmd.Run(); err != nil { - mainLog.Error().Err(err).Msg("deAllocateIP failed") + mainLog.Load().Error().Err(err).Msg("deAllocateIP failed") return err } return nil @@ -50,7 +50,7 @@ const maxSetDNSAttempts = 5 func setDNS(iface *net.Interface, nameservers []string) error { r, err := dns.NewOSConfigurator(logf, iface.Name) if err != nil { - mainLog.Error().Err(err).Msg("failed to create DNS OS configurator") + mainLog.Load().Error().Err(err).Msg("failed to create DNS OS configurator") return err } @@ -69,7 +69,7 @@ func setDNS(iface *net.Interface, nameservers []string) error { if err := r.SetDNS(osConfig); err != nil { if strings.Contains(err.Error(), "Rejected send message") && strings.Contains(err.Error(), "org.freedesktop.network1.Manager") { - mainLog.Warn().Msg("Interfaces are managed by systemd-networkd, switch to systemd-resolve for setting DNS") + mainLog.Load().Warn().Msg("Interfaces are managed by systemd-networkd, switch to systemd-resolve for setting DNS") trySystemdResolve = true break } @@ -100,7 +100,7 @@ func setDNS(iface *net.Interface, nameservers []string) error { time.Sleep(time.Second) } } - mainLog.Debug().Msg("DNS was not set for some reason") + mainLog.Load().Debug().Msg("DNS was not set for some reason") return nil } @@ -116,7 +116,7 @@ func resetDNS(iface *net.Interface) (err error) { if r, oerr := dns.NewOSConfigurator(logf, iface.Name); oerr == nil { _ = r.SetDNS(dns.OSConfig{}) if err := r.Close(); err != nil { - mainLog.Error().Err(err).Msg("failed to rollback DNS setting") + mainLog.Load().Error().Err(err).Msg("failed to rollback DNS setting") return } err = nil @@ -148,13 +148,13 @@ func resetDNS(iface *net.Interface) (err error) { c := client6.NewClient() conversation, err := c.Exchange(iface.Name) if err != nil && !errAddrInUse(err) { - mainLog.Debug().Err(err).Msg("could not exchange DHCPv6") + mainLog.Load().Debug().Err(err).Msg("could not exchange DHCPv6") } for _, packet := range conversation { if packet.Type() == dhcpv6.MessageTypeReply { msg, err := packet.GetInnerMessage() if err != nil { - mainLog.Debug().Err(err).Msg("could not get inner DHCPv6 message") + mainLog.Load().Debug().Err(err).Msg("could not get inner DHCPv6 message") return nil } nameservers := msg.Options.DNS() diff --git a/cmd/ctrld/os_windows.go b/cmd/ctrld/os_windows.go index 8858027..f96e224 100644 --- a/cmd/ctrld/os_windows.go +++ b/cmd/ctrld/os_windows.go @@ -30,12 +30,12 @@ func setDNS(iface *net.Interface, nameservers []string) error { func resetDNS(iface *net.Interface) error { if ctrldnet.SupportsIPv6ListenLocal() { if output, err := netsh("interface", "ipv6", "set", "dnsserver", strconv.Itoa(iface.Index), "dhcp"); err != nil { - mainLog.Warn().Err(err).Msgf("failed to reset ipv6 DNS: %s", string(output)) + mainLog.Load().Warn().Err(err).Msgf("failed to reset ipv6 DNS: %s", string(output)) } } output, err := netsh("interface", "ipv4", "set", "dnsserver", strconv.Itoa(iface.Index), "dhcp") if err != nil { - mainLog.Error().Err(err).Msgf("failed to reset ipv4 DNS: %s", string(output)) + mainLog.Load().Error().Err(err).Msgf("failed to reset ipv4 DNS: %s", string(output)) return err } return nil @@ -49,7 +49,7 @@ func setPrimaryDNS(iface *net.Interface, dns string) error { idx := strconv.Itoa(iface.Index) output, err := netsh("interface", ipVer, "set", "dnsserver", idx, "static", dns) if err != nil { - mainLog.Error().Err(err).Msgf("failed to set primary DNS: %s", string(output)) + mainLog.Load().Error().Err(err).Msgf("failed to set primary DNS: %s", string(output)) return err } if ipVer == "ipv4" && ctrldnet.SupportsIPv6ListenLocal() { @@ -67,7 +67,7 @@ func addSecondaryDNS(iface *net.Interface, dns string) error { } output, err := netsh("interface", ipVer, "add", "dns", strconv.Itoa(iface.Index), dns, "index=2") if err != nil { - mainLog.Warn().Err(err).Msgf("failed to add secondary DNS: %s", string(output)) + mainLog.Load().Warn().Err(err).Msgf("failed to add secondary DNS: %s", string(output)) } return nil } @@ -79,12 +79,12 @@ func netsh(args ...string) ([]byte, error) { func currentDNS(iface *net.Interface) []string { luid, err := winipcfg.LUIDFromIndex(uint32(iface.Index)) if err != nil { - mainLog.Error().Err(err).Msg("failed to get interface LUID") + mainLog.Load().Error().Err(err).Msg("failed to get interface LUID") return nil } nameservers, err := luid.DNS() if err != nil { - mainLog.Error().Err(err).Msg("failed to get interface DNS") + mainLog.Load().Error().Err(err).Msg("failed to get interface DNS") return nil } ns := make([]string, 0, len(nameservers)) diff --git a/cmd/ctrld/prog.go b/cmd/ctrld/prog.go index dce7c03..4aff917 100644 --- a/cmd/ctrld/prog.go +++ b/cmd/ctrld/prog.go @@ -26,7 +26,7 @@ const ( ) var logf = func(format string, args ...any) { - mainLog.Debug().Msgf(format, args...) + mainLog.Load().Debug().Msgf(format, args...) } var svcConfig = &service.Config{ @@ -72,7 +72,7 @@ func (p *prog) run() { if p.cfg.Service.CacheEnable { cacher, err := dnscache.NewLRUCache(p.cfg.Service.CacheSize) if err != nil { - mainLog.Error().Err(err).Msg("failed to create cacher, caching is disabled") + mainLog.Load().Error().Err(err).Msg("failed to create cacher, caching is disabled") } else { p.cache = cacher } @@ -93,7 +93,7 @@ func (p *prog) run() { for _, cidr := range nc.Cidrs { _, ipNet, err := net.ParseCIDR(cidr) if err != nil { - mainLog.Error().Err(err).Str("network", nc.Name).Str("cidr", cidr).Msg("invalid cidr") + mainLog.Load().Error().Err(err).Str("network", nc.Name).Str("cidr", cidr).Msg("invalid cidr") continue } nc.IPNets = append(nc.IPNets, ipNet) @@ -104,9 +104,9 @@ func (p *prog) run() { uc.Init() if uc.BootstrapIP == "" { uc.SetupBootstrapIP() - mainLog.Info().Msgf("bootstrap IPs for upstream.%s: %q", n, uc.BootstrapIPs()) + mainLog.Load().Info().Msgf("bootstrap IPs for upstream.%s: %q", n, uc.BootstrapIPs()) } else { - mainLog.Info().Str("bootstrap_ip", uc.BootstrapIP).Msgf("using bootstrap IP for upstream.%s", n) + mainLog.Load().Info().Str("bootstrap_ip", uc.BootstrapIP).Msgf("using bootstrap IP for upstream.%s", n) } uc.SetCertPool(rootCertPool) go uc.Ping() @@ -114,7 +114,7 @@ func (p *prog) run() { p.ciTable = clientinfo.NewTable(&cfg, defaultRouteIP()) if leaseFile := p.cfg.Service.DHCPLeaseFile; leaseFile != "" { - mainLog.Debug().Msgf("watching custom lease file: %s", leaseFile) + mainLog.Load().Debug().Msgf("watching custom lease file: %s", leaseFile) format := ctrld.LeaseFileFormat(p.cfg.Service.DHCPLeaseFileFormat) p.ciTable.AddLeaseFile(leaseFile, format) } @@ -132,12 +132,12 @@ func (p *prog) run() { listenerConfig := p.cfg.Listener[listenerNum] upstreamConfig := p.cfg.Upstream[listenerNum] if upstreamConfig == nil { - mainLog.Warn().Msgf("no default upstream for: [listener.%s]", listenerNum) + mainLog.Load().Warn().Msgf("no default upstream for: [listener.%s]", listenerNum) } addr := net.JoinHostPort(listenerConfig.IP, strconv.Itoa(listenerConfig.Port)) - mainLog.Info().Msgf("starting DNS server on listener.%s: %s", listenerNum, addr) + mainLog.Load().Info().Msgf("starting DNS server on listener.%s: %s", listenerNum, addr) if err := p.serveDNS(listenerNum); err != nil { - mainLog.Fatal().Err(err).Msgf("unable to start dns proxy on listener.%s", listenerNum) + mainLog.Load().Fatal().Err(err).Msgf("unable to start dns proxy on listener.%s", listenerNum) } }(listenerNum) } @@ -159,17 +159,17 @@ func (p *prog) run() { if p.cs != nil { p.registerControlServerHandler() if err := p.cs.start(); err != nil { - mainLog.Warn().Err(err).Msg("could not start control server") + mainLog.Load().Warn().Err(err).Msg("could not start control server") } } wg.Wait() } func (p *prog) Stop(s service.Service) error { - mainLog.Info().Msg("Service stopped") + mainLog.Load().Info().Msg("Service stopped") close(p.stopCh) if err := p.deAllocateIP(); err != nil { - mainLog.Error().Err(err).Msg("de-allocate ip failed") + mainLog.Load().Error().Err(err).Msg("de-allocate ip failed") return err } return nil @@ -212,7 +212,7 @@ func (p *prog) setDNS() { if lc == nil { return } - logger := mainLog.With().Str("iface", iface).Logger() + logger := mainLog.Load().With().Str("iface", iface).Logger() netIface, err := netInterface(iface) if err != nil { logger.Error().Err(err).Msg("could not get interface") @@ -257,7 +257,7 @@ func (p *prog) resetDNS() { if iface == "auto" { iface = defaultIfaceName() } - logger := mainLog.With().Str("iface", iface).Logger() + logger := mainLog.Load().With().Str("iface", iface).Logger() netIface, err := netInterface(iface) if err != nil { logger.Error().Err(err).Msg("could not get interface") @@ -291,19 +291,19 @@ func randomPort() int { func runLogServer(sockPath string) net.Conn { addr, err := net.ResolveUnixAddr("unix", sockPath) if err != nil { - mainLog.Warn().Err(err).Msg("invalid log sock path") + mainLog.Load().Warn().Err(err).Msg("invalid log sock path") return nil } ln, err := net.ListenUnix("unix", addr) if err != nil { - mainLog.Warn().Err(err).Msg("could not listen log socket") + mainLog.Load().Warn().Err(err).Msg("could not listen log socket") return nil } defer ln.Close() server, err := ln.Accept() if err != nil { - mainLog.Warn().Err(err).Msg("could not accept connection") + mainLog.Load().Warn().Err(err).Msg("could not accept connection") return nil } return server diff --git a/cmd/ctrld/service.go b/cmd/ctrld/service.go index 5f6eeb2..dfec02e 100644 --- a/cmd/ctrld/service.go +++ b/cmd/ctrld/service.go @@ -105,7 +105,7 @@ func doTasks(tasks []task) bool { for _, task := range tasks { if err := task.f(); err != nil { if task.abortOnError { - mainLog.Error().Msg(errors.Join(prevErr, err).Error()) + mainLog.Load().Error().Msg(errors.Join(prevErr, err).Error()) return false } prevErr = err @@ -117,11 +117,11 @@ func doTasks(tasks []task) bool { func checkHasElevatedPrivilege() { ok, err := hasElevatedPrivilege() if err != nil { - mainLog.Error().Msgf("could not detect user privilege: %v", err) + mainLog.Load().Error().Msgf("could not detect user privilege: %v", err) return } if !ok { - mainLog.Error().Msg("Please relaunch process with admin/root privilege.") + mainLog.Load().Error().Msg("Please relaunch process with admin/root privilege.") os.Exit(1) } } diff --git a/config.go b/config.go index ff803c5..0019e00 100644 --- a/config.go +++ b/config.go @@ -330,7 +330,7 @@ func (uc *UpstreamConfig) setupBootstrapIP(withBootstrapDNS bool) { if len(uc.bootstrapIPs) > 0 { break } - ProxyLog.Warn().Msg("could not resolve bootstrap IPs, retrying...") + ProxyLogger.Load().Warn().Msg("could not resolve bootstrap IPs, retrying...") b.BackOff(context.Background(), errors.New("no bootstrap IPs")) } for _, ip := range uc.bootstrapIPs { @@ -340,7 +340,7 @@ func (uc *UpstreamConfig) setupBootstrapIP(withBootstrapDNS bool) { uc.bootstrapIPs4 = append(uc.bootstrapIPs4, ip) } } - ProxyLog.Debug().Msgf("bootstrap IPs: %v", uc.bootstrapIPs) + ProxyLogger.Load().Debug().Msgf("bootstrap IPs: %v", uc.bootstrapIPs) } // ReBootstrap re-setup the bootstrap IP and the transport. @@ -351,7 +351,7 @@ func (uc *UpstreamConfig) ReBootstrap() { return } _, _, _ = uc.g.Do("ReBootstrap", func() (any, error) { - ProxyLog.Debug().Msg("re-bootstrapping upstream ip") + ProxyLogger.Load().Debug().Msg("re-bootstrapping upstream ip") uc.rebootstrap.Store(true) return true, nil }) @@ -405,7 +405,7 @@ func (uc *UpstreamConfig) newDOHTransport(addrs []string) *http.Transport { if uc.BootstrapIP != "" { dialer := net.Dialer{Timeout: dialerTimeout, KeepAlive: dialerTimeout} addr := net.JoinHostPort(uc.BootstrapIP, port) - Log(ctx, ProxyLog.Debug(), "sending doh request to: %s", addr) + Log(ctx, ProxyLogger.Load().Debug(), "sending doh request to: %s", addr) return dialer.DialContext(ctx, network, addr) } pd := &ctrldnet.ParallelDialer{} @@ -419,7 +419,7 @@ func (uc *UpstreamConfig) newDOHTransport(addrs []string) *http.Transport { if err != nil { return nil, err } - Log(ctx, ProxyLog.Debug(), "sending doh request to: %s", conn.RemoteAddr()) + Log(ctx, ProxyLogger.Load().Debug(), "sending doh request to: %s", conn.RemoteAddr()) return conn, nil } runtime.SetFinalizer(transport, func(transport *http.Transport) { diff --git a/config_quic.go b/config_quic.go index 32d338e..e953c72 100644 --- a/config_quic.go +++ b/config_quic.go @@ -48,7 +48,7 @@ func (uc *UpstreamConfig) newDOH3Transport(addrs []string) http.RoundTripper { // if we have a bootstrap ip set, use it to avoid DNS lookup if uc.BootstrapIP != "" { addr = net.JoinHostPort(uc.BootstrapIP, port) - ProxyLog.Debug().Msgf("sending doh3 request to: %s", addr) + ProxyLogger.Load().Debug().Msgf("sending doh3 request to: %s", addr) udpConn, err := net.ListenUDP("udp", nil) if err != nil { return nil, err @@ -68,7 +68,7 @@ func (uc *UpstreamConfig) newDOH3Transport(addrs []string) http.RoundTripper { if err != nil { return nil, err } - ProxyLog.Debug().Msgf("sending doh3 request to: %s", conn.RemoteAddr()) + ProxyLogger.Load().Debug().Msgf("sending doh3 request to: %s", conn.RemoteAddr()) return conn, err } return rt diff --git a/doh.go b/doh.go index f861f2f..5886881 100644 --- a/doh.go +++ b/doh.go @@ -110,5 +110,5 @@ func addHeader(ctx context.Context, req *http.Request, sendClientInfo bool) { } } } - Log(ctx, ProxyLog.Debug().Interface("header", req.Header), "sending request header") + Log(ctx, ProxyLogger.Load().Debug().Interface("header", req.Header), "sending request header") } diff --git a/internal/clientinfo/client_info.go b/internal/clientinfo/client_info.go index 55fe0b1..f923883 100644 --- a/internal/clientinfo/client_info.go +++ b/internal/clientinfo/client_info.go @@ -105,7 +105,7 @@ func (t *Table) Init() { if t.discoverDHCP() || t.discoverARP() { t.merlin = &merlinDiscover{} if err := t.merlin.refresh(); err != nil { - ctrld.ProxyLog.Error().Err(err).Msg("could not init Merlin discover") + ctrld.ProxyLogger.Load().Error().Err(err).Msg("could not init Merlin discover") } else { t.hostnameResolvers = append(t.hostnameResolvers, t.merlin) t.refreshers = append(t.refreshers, t.merlin) @@ -113,9 +113,9 @@ func (t *Table) Init() { } if t.discoverDHCP() { t.dhcp = &dhcp{selfIP: t.selfIP} - ctrld.ProxyLog.Debug().Msg("start dhcp discovery") + ctrld.ProxyLogger.Load().Debug().Msg("start dhcp discovery") if err := t.dhcp.init(); err != nil { - ctrld.ProxyLog.Error().Err(err).Msg("could not init DHCP discover") + ctrld.ProxyLogger.Load().Error().Err(err).Msg("could not init DHCP discover") } else { t.ipResolvers = append(t.ipResolvers, t.dhcp) t.macResolvers = append(t.macResolvers, t.dhcp) @@ -125,9 +125,9 @@ func (t *Table) Init() { } if t.discoverARP() { t.arp = &arpDiscover{} - ctrld.ProxyLog.Debug().Msg("start arp discovery") + ctrld.ProxyLogger.Load().Debug().Msg("start arp discovery") if err := t.arp.refresh(); err != nil { - ctrld.ProxyLog.Error().Err(err).Msg("could not init ARP discover") + ctrld.ProxyLogger.Load().Error().Err(err).Msg("could not init ARP discover") } else { t.ipResolvers = append(t.ipResolvers, t.arp) t.macResolvers = append(t.macResolvers, t.arp) @@ -136,9 +136,9 @@ func (t *Table) Init() { } if t.discoverPTR() { t.ptr = &ptrDiscover{resolver: ctrld.NewPrivateResolver()} - ctrld.ProxyLog.Debug().Msg("start ptr discovery") + ctrld.ProxyLogger.Load().Debug().Msg("start ptr discovery") if err := t.ptr.refresh(); err != nil { - ctrld.ProxyLog.Error().Err(err).Msg("could not init PTR discover") + ctrld.ProxyLogger.Load().Error().Err(err).Msg("could not init PTR discover") } else { t.hostnameResolvers = append(t.hostnameResolvers, t.ptr) t.refreshers = append(t.refreshers, t.ptr) @@ -146,9 +146,9 @@ func (t *Table) Init() { } if t.discoverMDNS() { t.mdns = &mdns{} - ctrld.ProxyLog.Debug().Msg("start mdns discovery") + ctrld.ProxyLogger.Load().Debug().Msg("start mdns discovery") if err := t.mdns.init(t.quitCh); err != nil { - ctrld.ProxyLog.Error().Err(err).Msg("could not init mDNS discover") + ctrld.ProxyLogger.Load().Error().Err(err).Msg("could not init mDNS discover") } else { t.hostnameResolvers = append(t.hostnameResolvers, t.mdns) } diff --git a/internal/clientinfo/dhcp.go b/internal/clientinfo/dhcp.go index ad423bd..a91bdb9 100644 --- a/internal/clientinfo/dhcp.go +++ b/internal/clientinfo/dhcp.go @@ -56,14 +56,14 @@ func (d *dhcp) watchChanges() { if event.Has(fsnotify.Write) { format := clientInfoFiles[event.Name] if err := d.readLeaseFile(event.Name, format); err != nil && !os.IsNotExist(err) { - ctrld.ProxyLog.Err(err).Str("file", event.Name).Msg("leases file changed but failed to update client info") + ctrld.ProxyLogger.Load().Err(err).Str("file", event.Name).Msg("leases file changed but failed to update client info") } } case err, ok := <-d.watcher.Errors: if !ok { return } - ctrld.ProxyLog.Err(err).Msg("could not watch client info file") + ctrld.ProxyLogger.Load().Err(err).Msg("could not watch client info file") } } @@ -167,7 +167,7 @@ func (d *dhcp) dnsmasqReadClientInfoReader(reader io.Reader) error { } ip := normalizeIP(string(fields[2])) if net.ParseIP(ip) == nil { - ctrld.ProxyLog.Warn().Msgf("invalid ip address entry: %q", ip) + ctrld.ProxyLogger.Load().Warn().Msgf("invalid ip address entry: %q", ip) ip = "" } @@ -219,7 +219,7 @@ func (d *dhcp) iscDHCPReadClientInfoReader(reader io.Reader) error { case "lease": ip = normalizeIP(strings.ToLower(fields[1])) if net.ParseIP(ip) == nil { - ctrld.ProxyLog.Warn().Msgf("invalid ip address entry: %q", ip) + ctrld.ProxyLogger.Load().Warn().Msgf("invalid ip address entry: %q", ip) ip = "" } case "hardware": @@ -242,7 +242,7 @@ func (d *dhcp) iscDHCPReadClientInfoReader(reader io.Reader) error { func (d *dhcp) addSelf() { hostname, err := os.Hostname() if err != nil { - ctrld.ProxyLog.Err(err).Msg("could not get hostname") + ctrld.ProxyLogger.Load().Err(err).Msg("could not get hostname") return } hostname = normalizeHostname(hostname) diff --git a/internal/clientinfo/mdns.go b/internal/clientinfo/mdns.go index 59ef7eb..1e99fe6 100644 --- a/internal/clientinfo/mdns.go +++ b/internal/clientinfo/mdns.go @@ -83,11 +83,11 @@ func (m *mdns) probeLoop(conns []*net.UDPConn, remoteAddr net.Addr, quitCh chan for { err := m.probe(conns, remoteAddr) if isErrNetUnreachableOrInvalid(err) { - ctrld.ProxyLog.Warn().Msgf("stop probing %q: network unreachable or invalid", remoteAddr) + ctrld.ProxyLogger.Load().Warn().Msgf("stop probing %q: network unreachable or invalid", remoteAddr) break } if err != nil { - ctrld.ProxyLog.Warn().Err(err).Msg("error while probing mdns") + ctrld.ProxyLogger.Load().Warn().Err(err).Msg("error while probing mdns") bo.BackOff(context.Background(), errors.New("mdns probe backoff")) } select { @@ -113,7 +113,7 @@ func (m *mdns) readLoop(conn *net.UDPConn) { if err, ok := err.(*net.OpError); ok && (err.Timeout() || err.Temporary()) { continue } - ctrld.ProxyLog.Debug().Err(err).Msg("mdns readLoop error") + ctrld.ProxyLogger.Load().Debug().Err(err).Msg("mdns readLoop error") return } @@ -133,11 +133,11 @@ func (m *mdns) readLoop(conn *net.UDPConn) { if ip != "" && name != "" { name = normalizeHostname(name) if val, loaded := m.name.LoadOrStore(ip, name); !loaded { - ctrld.ProxyLog.Debug().Msgf("found hostname: %q, ip: %q via mdns", name, ip) + ctrld.ProxyLogger.Load().Debug().Msgf("found hostname: %q, ip: %q via mdns", name, ip) } else { old := val.(string) if old != name { - ctrld.ProxyLog.Debug().Msgf("update hostname: %q, ip: %q, old: %q via mdns", name, ip, old) + ctrld.ProxyLogger.Load().Debug().Msgf("update hostname: %q, ip: %q, old: %q via mdns", name, ip, old) m.name.Store(ip, name) } } diff --git a/internal/clientinfo/merlin.go b/internal/clientinfo/merlin.go index 71c570c..8a39398 100644 --- a/internal/clientinfo/merlin.go +++ b/internal/clientinfo/merlin.go @@ -25,7 +25,7 @@ func (m *merlinDiscover) refresh() error { if err != nil { return err } - ctrld.ProxyLog.Debug().Msg("reading Merlin custom client list") + ctrld.ProxyLogger.Load().Debug().Msg("reading Merlin custom client list") m.parseMerlinCustomClientList(out) return nil } diff --git a/internal/clientinfo/ptr_lookup.go b/internal/clientinfo/ptr_lookup.go index 0de3f1a..29526fa 100644 --- a/internal/clientinfo/ptr_lookup.go +++ b/internal/clientinfo/ptr_lookup.go @@ -46,13 +46,13 @@ func (p *ptrDiscover) lookupHostname(ip string) string { msg := new(dns.Msg) addr, err := dns.ReverseAddr(ip) if err != nil { - ctrld.ProxyLog.Error().Err(err).Msg("invalid ip address") + ctrld.ProxyLogger.Load().Error().Err(err).Msg("invalid ip address") return "" } msg.SetQuestion(addr, dns.TypePTR) ans, err := p.resolver.Resolve(ctx, msg) if err != nil { - ctrld.ProxyLog.Error().Err(err).Msg("could not lookup IP") + ctrld.ProxyLogger.Load().Error().Err(err).Msg("could not lookup IP") return "" } for _, rr := range ans.Answer { diff --git a/internal/controld/config.go b/internal/controld/config.go index 6bc5544..852aa8a 100644 --- a/internal/controld/config.go +++ b/internal/controld/config.go @@ -80,10 +80,10 @@ func FetchResolverConfig(uid, version string, cdDev bool) (*ResolverConfig, erro } ips := ctrld.LookupIP(apiDomain) if len(ips) == 0 { - ctrld.ProxyLog.Warn().Msgf("No IPs found for %s, connecting to %s", apiDomain, addr) + ctrld.ProxyLogger.Load().Warn().Msgf("No IPs found for %s, connecting to %s", apiDomain, addr) return ctrldnet.Dialer.DialContext(ctx, network, addr) } - ctrld.ProxyLog.Debug().Msgf("API IPs: %v", ips) + ctrld.ProxyLogger.Load().Debug().Msgf("API IPs: %v", ips) _, port, _ := net.SplitHostPort(addr) addrs := make([]string, len(ips)) for i := range ips { diff --git a/log.go b/log.go index a4689b3..c521163 100644 --- a/log.go +++ b/log.go @@ -4,14 +4,24 @@ import ( "context" "fmt" "io" + "sync/atomic" "github.com/rs/zerolog" ) +func init() { + l := zerolog.New(io.Discard) + ProxyLogger.Store(&l) +} + // ProxyLog emits the log record for proxy operations. // The caller should set it only once. +// DEPRECATED: use ProxyLogger instead. var ProxyLog = zerolog.New(io.Discard) +// ProxyLogger emits the log record for proxy operations. +var ProxyLogger atomic.Pointer[zerolog.Logger] + // ReqIdCtxKey is the context.Context key for a request id. type ReqIdCtxKey struct{} diff --git a/resolver.go b/resolver.go index 2bee2d8..297d796 100644 --- a/resolver.go +++ b/resolver.go @@ -156,7 +156,7 @@ func lookupIP(domain string, timeout int, withBootstrapDNS bool) (ips []string) if withBootstrapDNS { resolver.nameservers = append([]string{net.JoinHostPort(bootstrapDNS, "53")}, resolver.nameservers...) } - ProxyLog.Debug().Msgf("resolving %q using bootstrap DNS %q", domain, resolver.nameservers) + ProxyLogger.Load().Debug().Msgf("resolving %q using bootstrap DNS %q", domain, resolver.nameservers) timeoutMs := 2000 if timeout > 0 && timeout < timeoutMs { timeoutMs = timeout @@ -199,15 +199,15 @@ func lookupIP(domain string, timeout int, withBootstrapDNS bool) (ips []string) r, err := resolver.Resolve(ctx, m) if err != nil { - ProxyLog.Error().Err(err).Msgf("could not lookup %q record for domain %q", dns.TypeToString[dnsType], domain) + ProxyLogger.Load().Error().Err(err).Msgf("could not lookup %q record for domain %q", dns.TypeToString[dnsType], domain) return } if r.Rcode != dns.RcodeSuccess { - ProxyLog.Error().Msgf("could not resolve domain %q, return code: %s", domain, dns.RcodeToString[r.Rcode]) + ProxyLogger.Load().Error().Msgf("could not resolve domain %q, return code: %s", domain, dns.RcodeToString[r.Rcode]) return } if len(r.Answer) == 0 { - ProxyLog.Error().Msg("no answer from OS resolver") + ProxyLogger.Load().Error().Msg("no answer from OS resolver") return } target := targetDomain(r.Answer)