net/tsdial, ipn/localapi, client/local: let clients dial non-Tailscale addresses directly
Add a tsdial.Dialer.UserDialPlan method that resolves an address and reports whether the dialer would route it via Tailscale. The LocalAPI /dial handler now uses this to skip proxying for addresses that aren't Tailscale routes (e.g. localhost), returning a Dial-Self response with the resolved address so the client can dial it directly. This avoids an unnecessary round-trip through the daemon for local connections. The client's UserDial handles the new response by dialing the resolved address itself, and the server passes the pre-resolved IP:port for Tailscale dials to avoid redundant DNS lookups. Thanks to giacomo and Moyao for pointing this out! Updates tailscale/corp#39702 Change-Id: I78d640f11ccd92f43ddd505cbb0db8fee19f43a6 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
committed by
Brad Fitzpatrick
parent
649781df84
commit
0e10a3f580
@@ -515,6 +515,33 @@ func (d *Dialer) UserDial(ctx context.Context, network, addr string) (net.Conn,
|
||||
return stdDialer.DialContext(ctx, network, ipp.String())
|
||||
}
|
||||
|
||||
// UserDialPlan resolves addr and reports whether the dialer would
|
||||
// handle it via Tailscale. If viaTailscale is false, the resolved
|
||||
// address is not a Tailscale route and the caller may dial it directly.
|
||||
//
|
||||
// Warning: there is a TOCTOU race if addr contains a DNS name and the
|
||||
// caller subsequently passes the same DNS name to [Dialer.UserDial], as DNS
|
||||
// may resolve differently the second time. Callers who want to only
|
||||
// dial over Tailscale should call [Dialer.UserDial] with the returned
|
||||
// ipp.String() (an IP:port) rather than the original DNS name.
|
||||
func (d *Dialer) UserDialPlan(ctx context.Context, network, addr string) (ipp netip.AddrPort, viaTailscale bool, err error) {
|
||||
ipp, err = d.userDialResolve(ctx, network, addr)
|
||||
if err != nil {
|
||||
return netip.AddrPort{}, false, err
|
||||
}
|
||||
if d.UseNetstackForIP != nil && d.UseNetstackForIP(ipp.Addr()) {
|
||||
return ipp, true, nil
|
||||
}
|
||||
if routes := d.routes.Load(); routes != nil {
|
||||
isTailscaleRoute, _ := routes.Lookup(ipp.Addr())
|
||||
return ipp, isTailscaleRoute, nil
|
||||
}
|
||||
if version.IsMacGUIVariant() && tsaddr.IsTailscaleIP(ipp.Addr()) {
|
||||
return ipp, true, nil
|
||||
}
|
||||
return ipp, false, nil
|
||||
}
|
||||
|
||||
// dialPeerAPI connects to a Tailscale peer's peerapi over TCP.
|
||||
//
|
||||
// network must a "tcp" type, and addr must be an ip:port. Name resolution
|
||||
|
||||
Reference in New Issue
Block a user