From 30320ec9c7622f4863651981d8e3de22639fa66d Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Thu, 1 Aug 2024 23:32:41 +0700 Subject: [PATCH] cmd/cli: fix issue with editing /etc/resolv.conf directly on Darwin On Darwin, modifying /etc/resolv.conf directly does not change interface network settings. Thus the networksetup command uses to set DNS does not do anything. To fix this, after setting DNS using networksetup, re-check the content of /etc/resolv.conf file to see if the nameservers are what we expected. Otherwise, re-generate the file with proper nameservers. --- cmd/cli/prog.go | 2 ++ cmd/cli/resolvconf_darwin.go | 31 ++++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/cmd/cli/prog.go b/cmd/cli/prog.go index 54ade0d..c112ada 100644 --- a/cmd/cli/prog.go +++ b/cmd/cli/prog.go @@ -651,6 +651,8 @@ func (p *prog) dnsWatchdog(iface *net.Interface, nameservers []string, allIfaces if dnsChanged(i, ns) { if err := setDnsIgnoreUnusableInterface(i, nameservers); err != nil { mainLog.Load().Error().Err(err).Str("iface", i.Name).Msgf("could not re-apply DNS settings") + } else { + mainLog.Load().Debug().Msgf("re-applying DNS for interface %q successfully", i.Name) } } return nil diff --git a/cmd/cli/resolvconf_darwin.go b/cmd/cli/resolvconf_darwin.go index 7e26f41..eb70eed 100644 --- a/cmd/cli/resolvconf_darwin.go +++ b/cmd/cli/resolvconf_darwin.go @@ -3,15 +3,44 @@ package cli import ( "net" "net/netip" + "os" + "slices" + + "github.com/Control-D-Inc/ctrld/internal/dns/resolvconffile" ) +const resolvConfPath = "/etc/resolv.conf" + // setResolvConf sets the content of resolv.conf file using the given nameservers list. func setResolvConf(iface *net.Interface, ns []netip.Addr) error { servers := make([]string, len(ns)) for i := range ns { servers[i] = ns[i].String() } - return setDNS(iface, servers) + if err := setDNS(iface, servers); err != nil { + return err + } + slices.Sort(servers) + curNs := currentDNS(iface) + slices.Sort(curNs) + if !slices.Equal(curNs, servers) { + c, err := resolvconffile.ParseFile(resolvConfPath) + if err != nil { + return err + } + c.Nameservers = ns + f, err := os.Create(resolvConfPath) + if err != nil { + return err + } + defer f.Close() + + if err := c.Write(f); err != nil { + return err + } + return f.Close() + } + return nil } // shouldWatchResolvconf reports whether ctrld should watch changes to resolv.conf file with given OS configurator.