diff --git a/net/dns/manager_darwin.go b/net/dns/manager_darwin.go index 7e4d40320..ccfafaa45 100644 --- a/net/dns/manager_darwin.go +++ b/net/dns/manager_darwin.go @@ -10,6 +10,8 @@ import ( "go4.org/mem" "tailscale.com/control/controlknobs" "tailscale.com/health" + "tailscale.com/net/dns/resolvconffile" + "tailscale.com/net/tsaddr" "tailscale.com/types/logger" "tailscale.com/util/mak" ) @@ -83,8 +85,36 @@ func (c *darwinConfigurator) SetDNS(cfg OSConfig) error { return c.removeResolverFiles(func(domain string) bool { return !keep[domain] }) } +// GetBaseConfig returns the current OS DNS configuration, extracting it from /etc/resolv.conf. +// We should really be using the SystemConfiguration framework to get this information, as this +// is not a stable public API, and is provided mostly as a compatibility effort with Unix +// tools. Apple might break this in the future. But honestly, parsing the output of `scutil --dns` +// is *even more* likely to break in the future. func (c *darwinConfigurator) GetBaseConfig() (OSConfig, error) { - return OSConfig{}, ErrGetBaseConfigNotSupported + cfg := OSConfig{} + + resolvConf, err := resolvconffile.ParseFile("/etc/resolv.conf") + if err != nil { + c.logf("failed to parse /etc/resolv.conf: %v", err) + return cfg, ErrGetBaseConfigNotSupported + } + + for _, ns := range resolvConf.Nameservers { + if ns == tsaddr.TailscaleServiceIP() || ns == tsaddr.TailscaleServiceIPv6() { + // If we find Quad100 in /etc/resolv.conf, we should ignore it + c.logf("ignoring 100.100.100.100 resolver IP found in /etc/resolv.conf") + continue + } + cfg.Nameservers = append(cfg.Nameservers, ns) + } + cfg.SearchDomains = resolvConf.SearchDomains + + if len(cfg.Nameservers) == 0 { + // Log a warning in case we couldn't find any nameservers in /etc/resolv.conf. + c.logf("no nameservers found in /etc/resolv.conf, DNS resolution might fail") + } + + return cfg, nil } const macResolverFileHeader = "# Added by tailscaled\n"