From dc61fd255477348091238d03fe15d6bf9fbc0bc0 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Tue, 11 Jul 2023 18:23:09 +0700 Subject: [PATCH] all: update handling of local config For local config, we don't want to alter what user explicitly set, and only try filling in missing value. While at it, also remove the dnsmasq port delete on openwrt, we don't need that hack anymore. --- cmd/ctrld/cli.go | 98 ++++++++++++++++++++++++++---- cmd/ctrld/prog.go | 2 +- internal/router/openwrt/openwrt.go | 5 -- 3 files changed, 87 insertions(+), 18 deletions(-) diff --git a/cmd/ctrld/cli.go b/cmd/ctrld/cli.go index e6c40f3..6876fc2 100644 --- a/cmd/ctrld/cli.go +++ b/cmd/ctrld/cli.go @@ -996,7 +996,13 @@ func selfCheckStatus(status service.Status, domain string) service.Status { lcChanged map[string]*ctrld.ListenerConfig mu sync.Mutex ) - curCfg := cfg + + if err := v.ReadInConfig(); err != nil { + mainLog.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") + } watcher, err := fsnotify.NewWatcher() if err != nil { mainLog.Error().Err(err).Msg("could not watch config change") @@ -1016,10 +1022,10 @@ func selfCheckStatus(status service.Status, domain string) service.Status { for i := 0; i < maxAttempts; i++ { mu.Lock() if lcChanged != nil { - curCfg.Listener = lcChanged + cfg.Listener = lcChanged } mu.Unlock() - lc := curCfg.FirstListener() + lc := cfg.FirstListener() m := new(dns.Msg) m.SetQuestion(domain+".", dns.TypeA) @@ -1183,16 +1189,31 @@ func shouldAllocateLoopbackIP(ipStr string) bool { return ip.IsLoopback() && ip.String() != "127.0.0.1" } +type listenerConfigCheck struct { + IP bool + Port bool +} + // updateListenerConfig updates the config for listeners if not defined, // or defined but invalid to be used, e.g: using loopback address other // than 127.0.0.1 with sytemd-resolved. func updateListenerConfig() { - for _, listener := range cfg.Listener { + lcc := make(map[string]*listenerConfigCheck) + cdMode := cdUID != "" + for n, listener := range cfg.Listener { + lcc[n] = &listenerConfigCheck{} if listener.IP == "" { listener.IP = "0.0.0.0" + lcc[n].IP = true } if listener.Port == 0 { listener.Port = 53 + lcc[n].Port = true + } + // In cd mode, we always try to pick an ip:port pair to work. + if cdMode { + lcc[n].IP = true + lcc[n].Port = true } } @@ -1229,7 +1250,10 @@ func updateListenerConfig() { for _, n := range listeners { listener := cfg.Listener[strconv.Itoa(n)] + check := lcc[strconv.Itoa(n)] oldIP := listener.IP + oldPort := listener.Port + // Check if we could listen on the current IP + Port, if not, try following thing, pick first one success: // - Try 127.0.0.1:53 // - Pick a random port until success. @@ -1243,6 +1267,8 @@ func updateListenerConfig() { // On firewalla, we don't need to check localhost, because the lo interface is excluded in dnsmasq // config, so we can always listen on localhost port 53, but no traffic could be routed there. tryLocalhost := !isLoopback(listener.IP) && router.Name() != firewalla.Name + tryAllPort53 := true + tryOldIPPort5354 := true tryPort5354 := true attempts := 0 maxAttempts := 10 @@ -1254,22 +1280,70 @@ func updateListenerConfig() { if listenOk(addr) { break } + if !check.IP && !check.Port { + mainLog.Fatal().Msgf("failed to listen on: %s", addr) + } + if tryAllPort53 { + tryAllPort53 = false + if check.IP { + listener.IP = "0.0.0.0" + } + if check.Port { + listener.Port = 53 + } + if check.IP { + mainLog.Warn().Msgf("could not listen on address: %s, trying: %s", addr, net.JoinHostPort(listener.IP, strconv.Itoa(listener.Port))) + } + continue + } if tryLocalhost { tryLocalhost = false - listener.IP = localhostIP(listener.IP) - listener.Port = 53 - mainLog.Warn().Msgf("could not listen on address: %s, trying localhost: %s", addr, net.JoinHostPort(listener.IP, strconv.Itoa(listener.Port))) + if check.IP { + listener.IP = localhostIP(listener.IP) + } + if check.Port { + listener.Port = 53 + } + if check.IP { + mainLog.Warn().Msgf("could not listen on address: %s, trying localhost: %s", addr, net.JoinHostPort(listener.IP, strconv.Itoa(listener.Port))) + } + continue + } + if tryOldIPPort5354 { + tryOldIPPort5354 = false + if check.IP { + listener.IP = oldIP + } + if check.Port { + listener.Port = 5354 + } + mainLog.Warn().Msgf("could not listen on address: %s, trying current ip with port 5354", addr) continue } if tryPort5354 { tryPort5354 = false - listener.IP = oldIP - listener.Port = 5354 - mainLog.Warn().Msgf("could not listen on address: %s, trying port 5354", addr) + if check.IP { + listener.IP = "0.0.0.0" + } + if check.Port { + listener.Port = 5354 + } + mainLog.Warn().Msgf("could not listen on address: %s, trying 0.0.0.0:5354", addr) continue } - listener.IP = randomLocalIP() - listener.Port = randomPort() + if check.IP { + listener.IP = randomLocalIP() + } else { + listener.IP = oldIP + } + if check.Port { + listener.Port = randomPort() + } else { + listener.Port = oldPort + } + if listener.IP == oldIP && listener.Port == oldPort { + mainLog.Fatal().Msgf("could not listener on: %s", net.JoinHostPort(listener.IP, strconv.Itoa(listener.Port))) + } mainLog.Warn().Msgf("could not listen on address: %s, pick a random ip+port", addr) attempts++ } diff --git a/cmd/ctrld/prog.go b/cmd/ctrld/prog.go index 83e71ae..394b4a0 100644 --- a/cmd/ctrld/prog.go +++ b/cmd/ctrld/prog.go @@ -264,7 +264,7 @@ func (p *prog) setDNS() { logger.Warn().Msgf("using %s interface IP address as DNS server", ifaceName) } } - logger.Warn().Msg("ctrld is not running on port 53, use interface %s IP as DNS server") + logger.Warn().Msgf("ctrld is not running on port 53, use interface %s IP as DNS server", ifaceName) netIface, err := net.InterfaceByName(ifaceName) if err != nil { mainLog.Fatal().Err(err).Msg("failed to get default route interface") diff --git a/internal/router/openwrt/openwrt.go b/internal/router/openwrt/openwrt.go index 1c8860d..1d8de34 100644 --- a/internal/router/openwrt/openwrt.go +++ b/internal/router/openwrt/openwrt.go @@ -49,11 +49,6 @@ func (o *Openwrt) PreRun() error { } func (o *Openwrt) Setup() error { - // Delete dnsmasq port if set. - if _, err := uci("delete", "dhcp.@dnsmasq[0].port"); err != nil && !errors.Is(err, errUCIEntryNotFound) { - return err - } - data, err := dnsmasq.ConfTmpl(dnsmasq.ConfigContentTmpl, o.cfg) if err != nil { return err