This commit is contained in:
2026-02-19 10:07:43 +00:00
parent 007438e372
commit 6e637ecf77
1763 changed files with 60820 additions and 279516 deletions

View File

@@ -36,11 +36,11 @@ func dnsMapFromNetworkMap(nm *netmap.NetworkMap) dnsMap {
suffix := nm.MagicDNSSuffix()
have4 := false
addrs := nm.GetAddresses()
if nm.Name != "" && addrs.Len() > 0 {
if name := nm.SelfName(); name != "" && addrs.Len() > 0 {
ip := addrs.At(0).Addr()
ret[canonMapKey(nm.Name)] = ip
if dnsname.HasSuffix(nm.Name, suffix) {
ret[canonMapKey(dnsname.TrimSuffix(nm.Name, suffix))] = ip
ret[canonMapKey(name)] = ip
if dnsname.HasSuffix(name, suffix) {
ret[canonMapKey(dnsname.TrimSuffix(name, suffix))] = ip
}
for _, p := range addrs.All() {
if p.Addr().Is4() {

View File

@@ -19,14 +19,19 @@ import (
"time"
"github.com/gaissmai/bart"
"tailscale.com/feature"
"tailscale.com/feature/buildfeatures"
"tailscale.com/net/dnscache"
"tailscale.com/net/netknob"
"tailscale.com/net/netmon"
"tailscale.com/net/netns"
"tailscale.com/net/netx"
"tailscale.com/net/tsaddr"
"tailscale.com/syncs"
"tailscale.com/types/logger"
"tailscale.com/types/netmap"
"tailscale.com/util/clientmetric"
"tailscale.com/util/eventbus"
"tailscale.com/util/mak"
"tailscale.com/util/testenv"
"tailscale.com/version"
@@ -43,6 +48,13 @@ func NewDialer(netMon *netmon.Monitor) *Dialer {
return d
}
// NewFromFuncForDebug is like NewDialer but takes a netx.DialFunc
// and no netMon. It's meant exclusively for the "tailscale debug ts2021"
// debug command, and perhaps tests.
func NewFromFuncForDebug(logf logger.Logf, dial netx.DialFunc) *Dialer {
return &Dialer{sysDialForTest: dial, Logf: logf}
}
// Dialer dials out of tailscaled, while taking care of details while
// handling the dozens of edge cases depending on the server mode
// (TUN, netstack), the OS network sandboxing style (macOS/iOS
@@ -71,10 +83,11 @@ type Dialer struct {
netnsDialerOnce sync.Once
netnsDialer netns.Dialer
sysDialForTest netx.DialFunc // or nil
routes atomic.Pointer[bart.Table[bool]] // or nil if UserDial should not use routes. `true` indicates routes that point into the Tailscale interface
mu sync.Mutex
mu syncs.Mutex
closed bool
dns dnsMap
tunName string // tun device name
@@ -84,6 +97,9 @@ type Dialer struct {
dnsCache *dnscache.MessageCache // nil until first non-empty SetExitDNSDoH
nextSysConnID int
activeSysConns map[int]net.Conn // active connections not yet closed
bus *eventbus.Bus // only used for comparison with already set bus.
eventClient *eventbus.Client
eventBusSubs eventbus.Monitor
}
// sysConn wraps a net.Conn that was created using d.SystemDial.
@@ -123,6 +139,9 @@ func (d *Dialer) TUNName() string {
//
// For example, "http://100.68.82.120:47830/dns-query".
func (d *Dialer) SetExitDNSDoH(doh string) {
if !buildfeatures.HasUseExitNode {
return
}
d.mu.Lock()
defer d.mu.Unlock()
if d.exitDNSDoHBase == doh {
@@ -149,12 +168,16 @@ func (d *Dialer) SetRoutes(routes, localRoutes []netip.Prefix) {
for _, r := range localRoutes {
rt.Insert(r, false)
}
d.logf("tsdial: bart table size: %d", rt.Size())
}
d.routes.Store(rt)
}
func (d *Dialer) Close() error {
if d.eventClient != nil {
d.eventBusSubs.Close()
}
d.mu.Lock()
defer d.mu.Unlock()
d.closed = true
@@ -183,6 +206,14 @@ func (d *Dialer) SetNetMon(netMon *netmon.Monitor) {
d.netMonUnregister = nil
}
d.netMon = netMon
// Having multiple watchers could lead to problems,
// so remove the eventClient if it exists.
// This should really not happen, but better checking for it than not.
// TODO(cmol): Should this just be a panic?
if d.eventClient != nil {
d.eventBusSubs.Close()
d.eventClient = nil
}
d.netMonUnregister = d.netMon.RegisterChangeCallback(d.linkChanged)
}
@@ -194,6 +225,38 @@ func (d *Dialer) NetMon() *netmon.Monitor {
return d.netMon
}
func (d *Dialer) SetBus(bus *eventbus.Bus) {
d.mu.Lock()
defer d.mu.Unlock()
if d.bus == bus {
return
} else if d.bus != nil {
panic("different eventbus has already been set")
}
// Having multiple watchers could lead to problems,
// so unregister the callback if it exists.
if d.netMonUnregister != nil {
d.netMonUnregister()
}
d.bus = bus
d.eventClient = bus.Client("tsdial.Dialer")
d.eventBusSubs = d.eventClient.Monitor(d.linkChangeWatcher(d.eventClient))
}
func (d *Dialer) linkChangeWatcher(ec *eventbus.Client) func(*eventbus.Client) {
linkChangeSub := eventbus.Subscribe[netmon.ChangeDelta](ec)
return func(ec *eventbus.Client) {
for {
select {
case <-ec.Done():
return
case cd := <-linkChangeSub.Events():
d.linkChanged(&cd)
}
}
}
}
var (
metricLinkChangeConnClosed = clientmetric.NewCounter("tsdial_linkchange_closes")
metricChangeDeltaNoDefaultRoute = clientmetric.NewCounter("tsdial_changedelta_no_default_route")
@@ -201,7 +264,7 @@ var (
func (d *Dialer) linkChanged(delta *netmon.ChangeDelta) {
// Track how often we see ChangeDeltas with no DefaultRouteInterface.
if delta.New.DefaultRouteInterface == "" {
if delta.DefaultRouteInterface == "" {
metricChangeDeltaNoDefaultRoute.Add(1)
}
@@ -231,22 +294,23 @@ func changeAffectsConn(delta *netmon.ChangeDelta, conn net.Conn) bool {
}
lip, rip := la.AddrPort().Addr(), ra.AddrPort().Addr()
if delta.Old == nil {
if delta.IsInitialState {
return false
}
if delta.Old.DefaultRouteInterface != delta.New.DefaultRouteInterface ||
delta.Old.HTTPProxy != delta.New.HTTPProxy {
if delta.DefaultInterfaceChanged ||
delta.HasPACOrProxyConfigChanged {
return true
}
// In a few cases, we don't have a new DefaultRouteInterface (e.g. on
// Android; see tailscale/corp#19124); if so, pessimistically assume
// Android and macOS/iOS; see tailscale/corp#19124); if so, pessimistically assume
// that all connections are affected.
if delta.New.DefaultRouteInterface == "" {
if delta.DefaultRouteInterface == "" && runtime.GOOS != "plan9" {
return true
}
if !delta.New.HasIP(lip) && delta.Old.HasIP(lip) {
if delta.InterfaceIPDisappeared(lip) {
// Our interface with this source IP went away.
return true
}
@@ -319,7 +383,7 @@ func (d *Dialer) userDialResolve(ctx context.Context, network, addr string) (net
}
var r net.Resolver
if exitDNSDoH != "" && runtime.GOOS != "windows" { // Windows: https://github.com/golang/go/issues/33097
if buildfeatures.HasUseExitNode && buildfeatures.HasPeerAPIClient && exitDNSDoH != "" {
r.PreferGo = true
r.Dial = func(ctx context.Context, network, address string) (net.Conn, error) {
return &dohConn{
@@ -361,13 +425,20 @@ func (d *Dialer) logf(format string, args ...any) {
}
}
// SetSystemDialerForTest sets an alternate function to use for SystemDial
// instead of netns.Dialer. This is intended for use with nettest.MemoryNetwork.
func (d *Dialer) SetSystemDialerForTest(fn netx.DialFunc) {
testenv.AssertInTest()
d.sysDialForTest = fn
}
// SystemDial connects to the provided network address without going over
// Tailscale. It prefers going over the default interface and closes existing
// connections if the default interface changes. It is used to connect to
// Control and (in the future, as of 2022-04-27) DERPs..
func (d *Dialer) SystemDial(ctx context.Context, network, addr string) (net.Conn, error) {
d.mu.Lock()
if d.netMon == nil {
if d.netMon == nil && d.sysDialForTest == nil {
d.mu.Unlock()
if testenv.InTest() {
panic("SystemDial requires a netmon.Monitor; call SetNetMon first")
@@ -380,10 +451,16 @@ func (d *Dialer) SystemDial(ctx context.Context, network, addr string) (net.Conn
return nil, net.ErrClosed
}
d.netnsDialerOnce.Do(func() {
d.netnsDialer = netns.NewDialer(d.logf, d.netMon)
})
c, err := d.netnsDialer.DialContext(ctx, network, addr)
var c net.Conn
var err error
if d.sysDialForTest != nil {
c, err = d.sysDialForTest(ctx, network, addr)
} else {
d.netnsDialerOnce.Do(func() {
d.netnsDialer = netns.NewDialer(d.logf, d.netMon)
})
c, err = d.netnsDialer.DialContext(ctx, network, addr)
}
if err != nil {
return nil, err
}
@@ -443,6 +520,9 @@ func (d *Dialer) UserDial(ctx context.Context, network, addr string) (net.Conn,
// network must a "tcp" type, and addr must be an ip:port. Name resolution
// is not supported.
func (d *Dialer) dialPeerAPI(ctx context.Context, network, addr string) (net.Conn, error) {
if !buildfeatures.HasPeerAPIClient {
return nil, feature.ErrUnavailable
}
switch network {
case "tcp", "tcp6", "tcp4":
default:
@@ -485,6 +565,9 @@ func (d *Dialer) getPeerDialer() *net.Dialer {
// The returned Client must not be mutated; it's owned by the Dialer
// and shared by callers.
func (d *Dialer) PeerAPIHTTPClient() *http.Client {
if !buildfeatures.HasPeerAPIClient {
panic("unreachable")
}
d.peerClientOnce.Do(func() {
t := http.DefaultTransport.(*http.Transport).Clone()
t.Dial = nil