@ -391,20 +391,8 @@ func (f *forwarder) getKnownDoHClientForProvider(urlBase string) (c *http.Client
if err != nil {
return nil , false
}
// NOTE: use f.dialer.SystemDial so we close connections on a link
// change; on mobile devices when switching between WiFi and cellular,
// we need to ensure we don't retain a connection on the old interface
// or we can block DNS resolution.
//
// NOTE: if we ever support arbitrary user-defined DoH providers, this
// isn't sufficient; we'd need a dialer that dial a DoH server on the
// internet, without going through Tailscale (as SystemDial does), but
// also can dial a node on the tailnet (e.g. a PiHole).
//
// As of the time of writing (2024-02-11), this isn't a problem because
// we only support a restricted set of public DoH providers that aren't
// on a user's tailnet.
dialer := dnscache . Dialer ( f . dialer . SystemDial , & dnscache . Resolver {
dialer := dnscache . Dialer ( f . getDialerType ( ) , & dnscache . Resolver {
SingleHost : dohURL . Hostname ( ) ,
SingleHostStaticResult : allIPs ,
Logf : f . logf ,
@ -699,6 +687,23 @@ func (f *forwarder) sendUDP(ctx context.Context, fq *forwardQuery, rr resolverAn
return out , nil
}
func ( f * forwarder ) getDialerType ( ) dnscache . DialContextFunc {
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.
return f . dialer . UserDial
}
return f . dialer . SystemDial
}
func ( f * forwarder ) sendTCP ( ctx context . Context , fq * forwardQuery , rr resolverAndDelay ) ( ret [ ] byte , err error ) {
ipp , ok := rr . name . IPPort ( )
if ! ok {
@ -717,7 +722,7 @@ func (f *forwarder) sendTCP(ctx context.Context, fq *forwardQuery, rr resolverAn
ctx , cancel := context . WithTimeout ( ctx , tcpQueryTimeout )
defer cancel ( )
conn , err := f . dialer . SystemDial ( ctx , tcpFam , ipp . String ( ) )
conn , err := f . getDialerType ( ) ( ctx , tcpFam , ipp . String ( ) )
if err != nil {
return nil , err
}