Update
This commit is contained in:
111
vendor/tailscale.com/net/tsdial/tsdial.go
generated
vendored
111
vendor/tailscale.com/net/tsdial/tsdial.go
generated
vendored
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user