net/{netns, netmon}: use LastKnownDefaultInterface if set and check for utun (#16873)

fixes tailscale/corp#31299

Fixes two issues:
getInterfaceIndex would occasionally race with netmon's state, returning
the cached default interface index after it had be changed by NWNetworkMonitor.
This had the potential to cause connections to bind to the prior default.  The fix
here is to preferentially use the interface index provided by NWNetworkMonitor
preferentially.

When no interfaces are available, macOS will set the tunnel as the default
interface when an exit node is enabled, potentially causing getInterfaceIndex
to return utun's index.  We now guard against this when taking the
defaultIdx path.

Signed-off-by: Jonathan Nobels <jonathan@tailscale.com>
This commit is contained in:
Jonathan Nobels
2025-08-15 16:04:23 -04:00
committed by GitHub
parent 9c39296ab5
commit 6006bc92b5
3 changed files with 125 additions and 46 deletions

View File

@@ -112,3 +112,25 @@ func TestFetchRoutingTable(t *testing.T) {
}
}
}
func TestUpdateLastKnownDefaultRouteInterface(t *testing.T) {
// Pick some interface on the machine
interfaces, err := netInterfaces()
if err != nil || len(interfaces) == 0 {
t.Fatalf("netInterfaces() error: %v", err)
}
// Set it as our last known default route interface
ifName := interfaces[0].Name
UpdateLastKnownDefaultRouteInterface(ifName)
// And make sure we can get it back
route, err := OSDefaultRoute()
if err != nil {
t.Fatalf("OSDefaultRoute() error: %v", err)
}
want, got := ifName, route.InterfaceName
if want != got {
t.Errorf("OSDefaultRoute() = %q, want %q", got, want)
}
}