net/dns: always attempt to read the OS config on macOS/iOS

Also reconfigure DNS on iOS/macOS on link changes.

Signed-off-by: Maisem Ali <maisem@tailscale.com>
This commit is contained in:
Maisem Ali 2022-09-22 14:38:09 -07:00 committed by Maisem Ali
parent 539c073cf0
commit 3555a49518
2 changed files with 37 additions and 16 deletions

View File

@ -265,22 +265,40 @@ func (m *Manager) compileConfig(cfg Config) (rcfg resolver.Config, ocfg OSConfig
rcfg.Routes = routes rcfg.Routes = routes
ocfg.Nameservers = []netip.Addr{cfg.serviceIP()} ocfg.Nameservers = []netip.Addr{cfg.serviceIP()}
if m.os.SupportsSplitDNS() { var baseCfg *OSConfig // base config; non-nil if/when known
ocfg.MatchDomains = cfg.matchDomains()
} else { // Even though Apple devices can do split DNS, they don't provide a way to
// selectively answer ExtraRecords, and ignore other DNS traffic. As a
// workaround, we read the existing default resolver configuration and use
// that as the forwarder for all DNS traffic that quad-100 doesn't handle.
const isApple = runtime.GOOS == "darwin" || runtime.GOOS == "ios"
if isApple || !m.os.SupportsSplitDNS() {
// If the OS can't do native split-dns, read out the underlying // If the OS can't do native split-dns, read out the underlying
// resolver config and blend it into our config. // resolver config and blend it into our config.
bcfg, err := m.os.GetBaseConfig() cfg, err := m.os.GetBaseConfig()
if err != nil { if err == nil {
baseCfg = &cfg
} else if isApple && err == ErrGetBaseConfigNotSupported {
// This is currently (2022-10-13) expected on certain iOS and macOS
// builds.
} else {
health.SetDNSOSHealth(err) health.SetDNSOSHealth(err)
return resolver.Config{}, OSConfig{}, err return resolver.Config{}, OSConfig{}, err
} }
}
if baseCfg == nil || isApple && len(baseCfg.Nameservers) == 0 {
// If there was no base config, or if we're on Apple and the base
// config is empty, then we need to fallback to SplitDNS mode.
ocfg.MatchDomains = cfg.matchDomains()
} else {
var defaultRoutes []*dnstype.Resolver var defaultRoutes []*dnstype.Resolver
for _, ip := range bcfg.Nameservers { for _, ip := range baseCfg.Nameservers {
defaultRoutes = append(defaultRoutes, &dnstype.Resolver{Addr: ip.String()}) defaultRoutes = append(defaultRoutes, &dnstype.Resolver{Addr: ip.String()})
} }
rcfg.Routes["."] = defaultRoutes rcfg.Routes["."] = defaultRoutes
ocfg.SearchDomains = append(ocfg.SearchDomains, bcfg.SearchDomains...) ocfg.SearchDomains = append(ocfg.SearchDomains, baseCfg.SearchDomains...)
} }
return rcfg, ocfg, nil return rcfg, ocfg, nil

View File

@ -1187,15 +1187,18 @@ func (e *userspaceEngine) linkChange(changed bool, cur *interfaces.State) {
// suspend/resume or whenever NetworkManager is started, it // suspend/resume or whenever NetworkManager is started, it
// nukes all systemd-resolved configs. So reapply our DNS // nukes all systemd-resolved configs. So reapply our DNS
// config on major link change. // config on major link change.
if (runtime.GOOS == "linux" || runtime.GOOS == "android") && changed { if changed {
e.wgLock.Lock() switch runtime.GOOS {
dnsCfg := e.lastDNSConfig case "linux", "android", "ios", "darwin":
e.wgLock.Unlock() e.wgLock.Lock()
if dnsCfg != nil { dnsCfg := e.lastDNSConfig
if err := e.dns.Set(*dnsCfg); err != nil { e.wgLock.Unlock()
e.logf("wgengine: error setting DNS config after major link change: %v", err) if dnsCfg != nil {
} else { if err := e.dns.Set(*dnsCfg); err != nil {
e.logf("wgengine: set DNS config again after major link change") e.logf("wgengine: error setting DNS config after major link change: %v", err)
} else {
e.logf("wgengine: set DNS config again after major link change")
}
} }
} }
} }