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

@@ -21,6 +21,7 @@ import (
"tailscale.com/net/netmon"
"tailscale.com/net/tsaddr"
"tailscale.com/types/logger"
"tailscale.com/version"
)
func control(logf logger.Logf, netMon *netmon.Monitor) func(network, address string, c syscall.RawConn) error {
@@ -33,18 +34,14 @@ var bindToInterfaceByRouteEnv = envknob.RegisterBool("TS_BIND_TO_INTERFACE_BY_RO
var errInterfaceStateInvalid = errors.New("interface state invalid")
// controlLogf marks c as necessary to dial in a separate network namespace.
//
// It's intentionally the same signature as net.Dialer.Control
// and net.ListenConfig.Control.
// controlLogf binds c to a particular interface as necessary to dial the
// provided (network, address).
func controlLogf(logf logger.Logf, netMon *netmon.Monitor, network, address string, c syscall.RawConn) error {
if isLocalhost(address) {
// Don't bind to an interface for localhost connections.
if disableBindConnToInterface.Load() || (version.IsMacGUIVariant() && disableBindConnToInterfaceAppleExt.Load()) {
return nil
}
if disableBindConnToInterface.Load() {
logf("netns_darwin: binding connection to interfaces disabled")
if isLocalhost(address) {
return nil
}
@@ -78,10 +75,38 @@ func getInterfaceIndex(logf logger.Logf, netMon *netmon.Monitor, address string)
return -1, errInterfaceStateInvalid
}
if iface, ok := state.Interface[state.DefaultRouteInterface]; ok {
return iface.Index, nil
// Netmon's cached view of the default inteface
cachedIdx, ok := state.Interface[state.DefaultRouteInterface]
// OSes view (if available) of the default interface
osIf, osIferr := netmon.OSDefaultRoute()
idx := -1
errOut := errInterfaceStateInvalid
// Preferentially choose the OS's view of the default if index. Due to the way darwin sets the delegated
// interface on tunnel creation only, it is possible for netmon to have a stale view of the default and
// netmon's view is often temporarily wrong during network transitions, or for us to not have the
// the the oses view of the defaultIf yet.
if osIferr == nil {
idx = osIf.InterfaceIndex
errOut = nil
} else if ok {
idx = cachedIdx.Index
errOut = nil
}
return -1, errInterfaceStateInvalid
if osIferr == nil && ok && (osIf.InterfaceIndex != cachedIdx.Index) {
logf("netns: [unexpected] os default if %q (%d) != netmon cached if %q (%d)", osIf.InterfaceName, osIf.InterfaceIndex, cachedIdx.Name, cachedIdx.Index)
}
// Sanity check to make sure we didn't pick the tailscale interface
if tsif, err2 := tailscaleInterface(); tsif != nil && err2 == nil && errOut == nil {
if tsif.Index == idx {
idx = -1
errOut = errInterfaceStateInvalid
}
}
return idx, errOut
}
useRoute := bindToInterfaceByRoute.Load() || bindToInterfaceByRouteEnv()
@@ -100,7 +125,7 @@ func getInterfaceIndex(logf logger.Logf, netMon *netmon.Monitor, address string)
idx, err := interfaceIndexFor(addr, true /* canRecurse */)
if err != nil {
logf("netns: error in interfaceIndexFor: %v", err)
logf("netns: error getting interface index for %q: %v", address, err)
return defaultIdx()
}
@@ -108,10 +133,13 @@ func getInterfaceIndex(logf logger.Logf, netMon *netmon.Monitor, address string)
// if so, we fall back to binding from the default.
tsif, err2 := tailscaleInterface()
if err2 == nil && tsif != nil && tsif.Index == idx {
logf("[unexpected] netns: interfaceIndexFor returned Tailscale interface")
// note: with an exit node enabled, this is almost always true. defaultIdx() is the
// right thing to do here.
return defaultIdx()
}
logf("netns: completed success interfaceIndexFor(%s) = %d", address, idx)
return idx, err
}