diff --git a/cmd/k8s-operator/depaware.txt b/cmd/k8s-operator/depaware.txt index 2ed36c3dc..9e6f24419 100644 --- a/cmd/k8s-operator/depaware.txt +++ b/cmd/k8s-operator/depaware.txt @@ -840,7 +840,7 @@ tailscale.com/cmd/k8s-operator dependencies: (generated by github.com/tailscale/ tailscale.com/net/dns/publicdns from tailscale.com/net/dns+ tailscale.com/net/dns/recursive from tailscale.com/net/dnsfallback tailscale.com/net/dns/resolvconffile from tailscale.com/cmd/k8s-operator+ - tailscale.com/net/dns/resolver from tailscale.com/net/dns + tailscale.com/net/dns/resolver from tailscale.com/net/dns+ tailscale.com/net/dnscache from tailscale.com/control/controlclient+ tailscale.com/net/dnsfallback from tailscale.com/control/controlclient+ tailscale.com/net/flowtrack from tailscale.com/net/packet+ diff --git a/cmd/tailscaled/depaware.txt b/cmd/tailscaled/depaware.txt index 7e937165b..823d639c9 100644 --- a/cmd/tailscaled/depaware.txt +++ b/cmd/tailscaled/depaware.txt @@ -318,7 +318,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de tailscale.com/net/dns/publicdns from tailscale.com/net/dns+ tailscale.com/net/dns/recursive from tailscale.com/net/dnsfallback tailscale.com/net/dns/resolvconffile from tailscale.com/net/dns+ - tailscale.com/net/dns/resolver from tailscale.com/net/dns + tailscale.com/net/dns/resolver from tailscale.com/net/dns+ tailscale.com/net/dnscache from tailscale.com/control/controlclient+ tailscale.com/net/dnsfallback from tailscale.com/cmd/tailscaled+ tailscale.com/net/flowtrack from tailscale.com/net/packet+ diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index 91a46bbcc..e8ff05b37 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -64,6 +64,7 @@ import ( "tailscale.com/logpolicy" "tailscale.com/net/captivedetection" "tailscale.com/net/dns" + "tailscale.com/net/dns/resolver" "tailscale.com/net/dnscache" "tailscale.com/net/dnsfallback" "tailscale.com/net/ipset" @@ -4908,7 +4909,6 @@ func (b *LocalBackend) authReconfig() { nm := cn.NetMap() hasPAC := b.prevIfState.HasPAC() disableSubnetsIfPAC := cn.SelfHasCap(tailcfg.NodeAttrDisableSubnetsIfPAC) - userDialUseRoutes := cn.SelfHasCap(tailcfg.NodeAttrUserDialUseRoutes) dohURL, dohURLOK := cn.exitNodeCanProxyDNS(prefs.ExitNodeID()) dcfg := cn.dnsConfigForNetmap(prefs, b.keyExpired, b.logf, version.OS()) // If the current node is an app connector, ensure the app connector machine is started @@ -4969,7 +4969,7 @@ func (b *LocalBackend) authReconfig() { } b.logf("[v1] authReconfig: ra=%v dns=%v 0x%02x: %v", prefs.RouteAll(), prefs.CorpDNS(), flags, err) - if userDialUseRoutes { + if resolver.ShouldUseRoutes(b.ControlKnobs()) { b.dialer.SetRoutes(rcfg.Routes, rcfg.LocalRoutes) } else { b.dialer.SetRoutes(nil, nil) diff --git a/net/dns/resolver/forwarder.go b/net/dns/resolver/forwarder.go index c7b9439e6..f12876905 100644 --- a/net/dns/resolver/forwarder.go +++ b/net/dns/resolver/forwarder.go @@ -17,6 +17,7 @@ import ( "net/http" "net/netip" "net/url" + "runtime" "sort" "strings" "sync" @@ -740,18 +741,37 @@ func (f *forwarder) sendUDP(ctx context.Context, fq *forwardQuery, rr resolverAn return out, nil } +var optDNSForwardUseRoutes = envknob.RegisterOptBool("TS_DNS_FORWARD_USE_ROUTES") + +// ShouldUseRoutes reports true if the DNS resolver should use the peer or system dialer +// for forwarding DNS queries to upstream nameservers via TCP, based on the destination +// address and configured routes. Currently, this requires maintaining a [bart.Table], +// resulting in a slightly higher memory usage. +// +// It reports false if the system dialer should always be used, regardless of the +// destination address. +// +// TODO(nickkhyl): Update [tsdial.Dialer] to reuse the bart.Table we create in net/tstun.Wrapper +// to avoid having two bart tables in memory, especially on iOS. Once that's done, +// we can get rid of the nodeAttr/control knob and always use UserDial for DNS. +// +// See https://github.com/tailscale/tailscale/issues/12027. +func ShouldUseRoutes(knobs *controlknobs.Knobs) bool { + switch runtime.GOOS { + case "android", "ios": + // On mobile platforms with lower memory limits (e.g., 50MB on iOS), + // this behavior is still gated by the "user-dial-routes" nodeAttr. + return knobs != nil && knobs.UserDialUseRoutes.Load() + default: + // On all other platforms, it is the default behavior, + // but it can be overridden with the "TS_DNS_FORWARD_USE_ROUTES" env var. + doNotUseRoutes := optDNSForwardUseRoutes().EqualBool(false) + return !doNotUseRoutes + } +} + func (f *forwarder) getDialerType() netx.DialFunc { - if f.controlKnobs != nil && f.controlKnobs.UserDialUseRoutes.Load() { - // It is safe to use UserDial as it dials external servers without going through Tailscale - // and closes connections on interface change in the same way as SystemDial does, - // thus preventing DNS resolution issues when switching between WiFi and cellular, - // but can also dial an internal DNS server on the Tailnet or via a subnet router. - // - // TODO(nickkhyl): Update tsdial.Dialer to reuse the bart.Table we create in net/tstun.Wrapper - // to avoid having two bart tables in memory, especially on iOS. Once that's done, - // we can get rid of the nodeAttr/control knob and always use UserDial for DNS. - // - // See https://github.com/tailscale/tailscale/issues/12027. + if ShouldUseRoutes(f.controlKnobs) { return f.dialer.UserDial } return f.dialer.SystemDial diff --git a/tsnet/depaware.txt b/tsnet/depaware.txt index f9e58a71c..4c9c6831e 100644 --- a/tsnet/depaware.txt +++ b/tsnet/depaware.txt @@ -271,7 +271,7 @@ tailscale.com/tsnet dependencies: (generated by github.com/tailscale/depaware) tailscale.com/net/dns/publicdns from tailscale.com/net/dns+ tailscale.com/net/dns/recursive from tailscale.com/net/dnsfallback tailscale.com/net/dns/resolvconffile from tailscale.com/net/dns+ - tailscale.com/net/dns/resolver from tailscale.com/net/dns + tailscale.com/net/dns/resolver from tailscale.com/net/dns+ tailscale.com/net/dnscache from tailscale.com/control/controlclient+ tailscale.com/net/dnsfallback from tailscale.com/control/controlclient+ tailscale.com/net/flowtrack from tailscale.com/net/packet+