ipn/ipnlocal,net/dns/resolver: use the user dialer and routes for DNS forwarding by default, except on iOS and Android

In this PR, we make the "user-dial-routes" behavior default on all platforms except for iOS and Android.
It can be disabled by setting the TS_DNS_FORWARD_USE_ROUTES envknob to 0 or false.

Updates #12027
Updates #13837

Signed-off-by: Nick Khyl <nickk@tailscale.com>
This commit is contained in:
Nick Khyl 2025-05-09 10:25:28 -05:00 committed by Nick Khyl
parent 3177e50b14
commit a9be049c19
5 changed files with 36 additions and 16 deletions

View File

@ -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/publicdns from tailscale.com/net/dns+
tailscale.com/net/dns/recursive from tailscale.com/net/dnsfallback 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/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/dnscache from tailscale.com/control/controlclient+
tailscale.com/net/dnsfallback from tailscale.com/control/controlclient+ tailscale.com/net/dnsfallback from tailscale.com/control/controlclient+
tailscale.com/net/flowtrack from tailscale.com/net/packet+ tailscale.com/net/flowtrack from tailscale.com/net/packet+

View File

@ -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/publicdns from tailscale.com/net/dns+
tailscale.com/net/dns/recursive from tailscale.com/net/dnsfallback tailscale.com/net/dns/recursive from tailscale.com/net/dnsfallback
tailscale.com/net/dns/resolvconffile from tailscale.com/net/dns+ 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/dnscache from tailscale.com/control/controlclient+
tailscale.com/net/dnsfallback from tailscale.com/cmd/tailscaled+ tailscale.com/net/dnsfallback from tailscale.com/cmd/tailscaled+
tailscale.com/net/flowtrack from tailscale.com/net/packet+ tailscale.com/net/flowtrack from tailscale.com/net/packet+

View File

@ -64,6 +64,7 @@ import (
"tailscale.com/logpolicy" "tailscale.com/logpolicy"
"tailscale.com/net/captivedetection" "tailscale.com/net/captivedetection"
"tailscale.com/net/dns" "tailscale.com/net/dns"
"tailscale.com/net/dns/resolver"
"tailscale.com/net/dnscache" "tailscale.com/net/dnscache"
"tailscale.com/net/dnsfallback" "tailscale.com/net/dnsfallback"
"tailscale.com/net/ipset" "tailscale.com/net/ipset"
@ -4908,7 +4909,6 @@ func (b *LocalBackend) authReconfig() {
nm := cn.NetMap() nm := cn.NetMap()
hasPAC := b.prevIfState.HasPAC() hasPAC := b.prevIfState.HasPAC()
disableSubnetsIfPAC := cn.SelfHasCap(tailcfg.NodeAttrDisableSubnetsIfPAC) disableSubnetsIfPAC := cn.SelfHasCap(tailcfg.NodeAttrDisableSubnetsIfPAC)
userDialUseRoutes := cn.SelfHasCap(tailcfg.NodeAttrUserDialUseRoutes)
dohURL, dohURLOK := cn.exitNodeCanProxyDNS(prefs.ExitNodeID()) dohURL, dohURLOK := cn.exitNodeCanProxyDNS(prefs.ExitNodeID())
dcfg := cn.dnsConfigForNetmap(prefs, b.keyExpired, b.logf, version.OS()) 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 // 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) 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) b.dialer.SetRoutes(rcfg.Routes, rcfg.LocalRoutes)
} else { } else {
b.dialer.SetRoutes(nil, nil) b.dialer.SetRoutes(nil, nil)

View File

@ -17,6 +17,7 @@ import (
"net/http" "net/http"
"net/netip" "net/netip"
"net/url" "net/url"
"runtime"
"sort" "sort"
"strings" "strings"
"sync" "sync"
@ -740,18 +741,37 @@ func (f *forwarder) sendUDP(ctx context.Context, fq *forwardQuery, rr resolverAn
return out, nil return out, nil
} }
func (f *forwarder) getDialerType() netx.DialFunc { var optDNSForwardUseRoutes = envknob.RegisterOptBool("TS_DNS_FORWARD_USE_ROUTES")
if f.controlKnobs != nil && f.controlKnobs.UserDialUseRoutes.Load() {
// It is safe to use UserDial as it dials external servers without going through Tailscale // ShouldUseRoutes reports true if the DNS resolver should use the peer or system dialer
// and closes connections on interface change in the same way as SystemDial does, // for forwarding DNS queries to upstream nameservers via TCP, based on the destination
// thus preventing DNS resolution issues when switching between WiFi and cellular, // address and configured routes. Currently, this requires maintaining a [bart.Table],
// but can also dial an internal DNS server on the Tailnet or via a subnet router. // resulting in a slightly higher memory usage.
// //
// TODO(nickkhyl): Update tsdial.Dialer to reuse the bart.Table we create in net/tstun.Wrapper // 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, // 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. // we can get rid of the nodeAttr/control knob and always use UserDial for DNS.
// //
// See https://github.com/tailscale/tailscale/issues/12027. // 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 ShouldUseRoutes(f.controlKnobs) {
return f.dialer.UserDial return f.dialer.UserDial
} }
return f.dialer.SystemDial return f.dialer.SystemDial

View File

@ -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/publicdns from tailscale.com/net/dns+
tailscale.com/net/dns/recursive from tailscale.com/net/dnsfallback tailscale.com/net/dns/recursive from tailscale.com/net/dnsfallback
tailscale.com/net/dns/resolvconffile from tailscale.com/net/dns+ 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/dnscache from tailscale.com/control/controlclient+
tailscale.com/net/dnsfallback from tailscale.com/control/controlclient+ tailscale.com/net/dnsfallback from tailscale.com/control/controlclient+
tailscale.com/net/flowtrack from tailscale.com/net/packet+ tailscale.com/net/flowtrack from tailscale.com/net/packet+