net/dns: simplify split DNS compile path
Cache the OS split-DNS capability while compiling DNS config and return directly for split-capable platforms that do not need the Apple base-config workaround. This removes the base-config sentinel pointer and keeps the iOS and sandboxed macOS fallback path explicit. Updates #1338 Change-Id: I836417c8fa775b35d3be9bc80cf6841d30cec222 Signed-off-by: Maisem Ali <maisem@bold.dev>
This commit is contained in:
committed by
Brad Fitzpatrick
parent
10672a63f4
commit
9013b6ec1b
+46
-46
@@ -378,10 +378,11 @@ func (m *Manager) compileConfig(cfg Config) (rcfg resolver.Config, ocfg OSConfig
|
||||
// workaround.
|
||||
isWindows := m.goos == "windows"
|
||||
isIOS := m.goos == "ios"
|
||||
supportsSplitDNS := m.os.SupportsSplitDNS()
|
||||
// Sandboxed macOS builds use NetworkExtension DNS settings, not
|
||||
// tailscaled's /etc/resolver configurator, so keep the Apple workaround.
|
||||
appleSplitDNSWorkaround := isIOS || (m.goos == "darwin" && isSandboxedMacOS())
|
||||
if m.os.SupportsSplitDNS() && !isWindows && !appleSplitDNSWorkaround {
|
||||
if supportsSplitDNS && !isWindows && !appleSplitDNSWorkaround {
|
||||
if srs := toIPsOnly(cfg.singleResolverSet()); len(srs) > 0 {
|
||||
// Split DNS configuration requested, where all split domains
|
||||
// go to the same resolvers. We can let the OS do it.
|
||||
@@ -397,63 +398,62 @@ func (m *Manager) compileConfig(cfg Config) (rcfg resolver.Config, ocfg OSConfig
|
||||
rcfg.Routes = routes
|
||||
ocfg.Nameservers = cfg.serviceIPs(m.knobs)
|
||||
|
||||
var baseCfg *OSConfig // base config; non-nil if/when known
|
||||
if supportsSplitDNS && !appleSplitDNSWorkaround {
|
||||
ocfg.MatchDomains = cfg.matchDomains()
|
||||
return rcfg, ocfg, nil
|
||||
}
|
||||
|
||||
// Even though iOS 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.
|
||||
if appleSplitDNSWorkaround || !m.os.SupportsSplitDNS() {
|
||||
// If the OS can't do native split-dns, read out the underlying
|
||||
// resolver config and blend it into our config. On apple platforms, [OSConfigurator.GetBaseConfig]
|
||||
// has a tendency to temporarily fail if called immediately following
|
||||
// an interface change. These failures should be retried if/when the OS
|
||||
// indicates that the DNS configuration has changed via [RecompileDNSConfig].
|
||||
cfg, err := m.os.GetBaseConfig()
|
||||
if err == nil {
|
||||
baseCfg = &cfg
|
||||
} else if (isIOS || isNoopManager(m.os)) && err == ErrGetBaseConfigNotSupported {
|
||||
//
|
||||
// If the OS can't do native split-DNS, read out the underlying resolver
|
||||
// config and blend it into our config. On iOS, [OSConfigurator.GetBaseConfig]
|
||||
// has a tendency to temporarily fail if called immediately following an
|
||||
// interface change. These failures should be retried if/when the OS indicates
|
||||
// that the DNS configuration has changed via [RecompileDNSConfig].
|
||||
base, err := m.os.GetBaseConfig()
|
||||
if err != nil {
|
||||
if (isIOS || isNoopManager(m.os)) && err == ErrGetBaseConfigNotSupported {
|
||||
// Expected when using noopManager (userspace networking) or on
|
||||
// certain iOS builds. Continue without base config.
|
||||
} else {
|
||||
m.health.SetUnhealthy(osConfigurationReadWarnable, health.Args{health.ArgError: err.Error()})
|
||||
return resolver.Config{}, OSConfig{}, err
|
||||
m.health.SetHealthy(osConfigurationReadWarnable)
|
||||
ocfg.MatchDomains = cfg.matchDomains()
|
||||
return rcfg, ocfg, nil
|
||||
}
|
||||
m.health.SetHealthy(osConfigurationReadWarnable)
|
||||
m.health.SetUnhealthy(osConfigurationReadWarnable, health.Args{health.ArgError: err.Error()})
|
||||
return resolver.Config{}, OSConfig{}, err
|
||||
}
|
||||
m.health.SetHealthy(osConfigurationReadWarnable)
|
||||
|
||||
if baseCfg == nil {
|
||||
// If there was no base config, then we need to fallback to SplitDNS mode.
|
||||
ocfg.MatchDomains = cfg.matchDomains()
|
||||
} else {
|
||||
// On iOS only (for now), check if all route names point to resources inside the tailnet.
|
||||
// If so, we can set those names as MatchDomains to enable a split DNS configuration
|
||||
// which will help preserve battery life.
|
||||
// Because on iOS MatchDomains must equal SearchDomains, we cannot do this when
|
||||
// we have any Routes outside the tailnet. Otherwise when app connectors are enabled,
|
||||
// a query for 'work-laptop' might lead to search domain expansion, resolving
|
||||
// as 'work-laptop.aws.com' for example.
|
||||
if m.goos == "ios" && rcfg.RoutesRequireNoCustomResolvers() {
|
||||
if !m.disableSplitDNSOptimization() {
|
||||
for r := range rcfg.Routes {
|
||||
ocfg.MatchDomains = append(ocfg.MatchDomains, r)
|
||||
}
|
||||
} else {
|
||||
m.logf("iOS split DNS is disabled by nodeattr")
|
||||
// On iOS only (for now), check if all route names point to resources inside the tailnet.
|
||||
// If so, we can set those names as MatchDomains to enable a split DNS configuration
|
||||
// which will help preserve battery life.
|
||||
// Because on iOS MatchDomains must equal SearchDomains, we cannot do this when
|
||||
// we have any Routes outside the tailnet. Otherwise when app connectors are enabled,
|
||||
// a query for 'work-laptop' might lead to search domain expansion, resolving
|
||||
// as 'work-laptop.aws.com' for example.
|
||||
if isIOS && rcfg.RoutesRequireNoCustomResolvers() {
|
||||
if !m.disableSplitDNSOptimization() {
|
||||
for r := range rcfg.Routes {
|
||||
ocfg.MatchDomains = append(ocfg.MatchDomains, r)
|
||||
}
|
||||
} else {
|
||||
m.logf("iOS split DNS is disabled by nodeattr")
|
||||
}
|
||||
var defaultRoutes []*dnstype.Resolver
|
||||
for _, ip := range baseCfg.Nameservers {
|
||||
defaultRoutes = append(defaultRoutes, &dnstype.Resolver{Addr: ip.String()})
|
||||
}
|
||||
rcfg.Routes["."] = defaultRoutes
|
||||
// Append base config search domains, but only if not already present.
|
||||
// This prevents duplicates when GetBaseConfig() reads back domains that
|
||||
// Tailscale itself previously wrote to resolv.conf.
|
||||
for _, domain := range baseCfg.SearchDomains {
|
||||
if !slices.Contains(ocfg.SearchDomains, domain) {
|
||||
ocfg.SearchDomains = append(ocfg.SearchDomains, domain)
|
||||
}
|
||||
}
|
||||
var defaultRoutes []*dnstype.Resolver
|
||||
for _, ip := range base.Nameservers {
|
||||
defaultRoutes = append(defaultRoutes, &dnstype.Resolver{Addr: ip.String()})
|
||||
}
|
||||
rcfg.Routes["."] = defaultRoutes
|
||||
// Append base config search domains, but only if not already present.
|
||||
// This prevents duplicates when GetBaseConfig() reads back domains that
|
||||
// Tailscale itself previously wrote to resolv.conf.
|
||||
for _, domain := range base.SearchDomains {
|
||||
if !slices.Contains(ocfg.SearchDomains, domain) {
|
||||
ocfg.SearchDomains = append(ocfg.SearchDomains, domain)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user