net/net{mon,ns},tsconst: avoid enumerating all interfaces when retrieving the default

Change-Id: I4c6a9d9ed791788fb0567154ee1dbe0f6a2c52a2
This commit is contained in:
Nick Khyl committed 2026-10-21 11:15:52 -04:00
1 parent 47743a8b9a
commit a04ab38741
4 files changed
+58 -42

No files matched your search

+44 -36
View File
@@ -15,12 +15,16 @@ import (
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg" "golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
"tailscale.com/feature/buildfeatures" "tailscale.com/feature/buildfeatures"
"tailscale.com/tsconst" "tailscale.com/tsconst"
"tailscale.com/util/mak"
"tailscale.com/util/must"
) )
const ( const (
fallbackInterfaceMetric = uint32(0) // Used if we cannot get the actual interface metric fallbackInterfaceMetric = uint32(0) // Used if we cannot get the actual interface metric
) )
var wintunInterfaceGUID = must.Get(windows.GUIDFromString(tsconst.WintunInterfaceGUID))
func init() { func init() {
likelyHomeRouterIP = likelyHomeRouterIPWindows likelyHomeRouterIP = likelyHomeRouterIPWindows
if buildfeatures.HasUseProxy { if buildfeatures.HasUseProxy {
@@ -152,45 +156,41 @@ func getInterfaces(family winipcfg.AddressFamily, flags winipcfg.GAAFlags, match
// GetWindowsDefault returns the interface that has the non-Tailscale // GetWindowsDefault returns the interface that has the non-Tailscale
// default route for the given address family. // default route for the given address family.
// //
// It returns (nil, nil) if no interface is found. // It returns (0, nil) if no interface is found.
// //
// The family must be one of AF_INET or AF_INET6. // The family must be one of AF_INET or AF_INET6.
func GetWindowsDefault(family winipcfg.AddressFamily) (*winipcfg.IPAdapterAddresses, error) { func GetWindowsDefault(family winipcfg.AddressFamily) (winipcfg.LUID, error) {
ifs, err := getInterfaces(family, winipcfg.GAAFlagIncludeAllInterfaces, func(iface *winipcfg.IPAdapterAddresses) bool { type ipInterfaceKey struct {
switch iface.IfType { winipcfg.LUID
case winipcfg.IfTypeSoftwareLoopback: winipcfg.AddressFamily
return false }
var ipInterfaces map[ipInterfaceKey]*winipcfg.MibIPInterfaceRow
getIPInterface := func(luid winipcfg.LUID, family winipcfg.AddressFamily) (*winipcfg.MibIPInterfaceRow, error) {
if ipif, ok := ipInterfaces[ipInterfaceKey{luid, family}]; ok {
return ipif, nil
} }
switch family { ipif, err := luid.IPInterface(family)
case windows.AF_INET: if err != nil {
if iface.Flags&winipcfg.IPAAFlagIpv4Enabled == 0 { return nil, err
return false
}
case windows.AF_INET6:
if iface.Flags&winipcfg.IPAAFlagIpv6Enabled == 0 {
return false
}
} }
return iface.OperStatus == winipcfg.IfOperStatusUp && notTailscaleInterface(iface) mak.Set(&ipInterfaces, ipInterfaceKey{luid, family}, ipif)
}) return ipif, nil
if err != nil {
return nil, err
} }
routes, err := winipcfg.GetIPForwardTable2(family) routes, err := winipcfg.GetIPForwardTable2(family)
if err != nil { if err != nil {
return nil, err return 0, err
} }
bestMetric := ^uint32(0) bestMetric := ^uint32(0)
var bestIface *winipcfg.IPAdapterAddresses var bestIface winipcfg.LUID
for _, route := range routes { for _, route := range routes {
if route.DestinationPrefix.PrefixLength != 0 { if route.DestinationPrefix.PrefixLength != 0 {
// Not a default route. // Not a default route.
continue continue
} }
iface := ifs[route.InterfaceLUID] ipif, err := getIPInterface(route.InterfaceLUID, family)
if iface == nil { if err != nil {
continue continue
} }
@@ -201,17 +201,21 @@ func GetWindowsDefault(family winipcfg.AddressFamily) (*winipcfg.IPAdapterAddres
// metric offset specified in the Metric member of the // metric offset specified in the Metric member of the
// MIB_IPFORWARD_ROW2 structure and the interface // MIB_IPFORWARD_ROW2 structure and the interface
// metric specified in this member for IPv4" // metric specified in this member for IPv4"
metric := route.Metric metric := route.Metric + ipif.Metric
switch family { if metric >= bestMetric {
case windows.AF_INET: continue
metric += iface.Ipv4Metric
case windows.AF_INET6:
metric += iface.Ipv6Metric
} }
if metric < bestMetric {
bestMetric = metric iface, err := route.InterfaceLUID.Interface()
bestIface = iface if err != nil || iface.OperStatus != winipcfg.IfOperStatusUp {
continue
} }
if iface.InterfaceGUID == wintunInterfaceGUID {
continue
}
bestMetric = metric
bestIface = route.InterfaceLUID
} }
return bestIface, nil return bestIface, nil
@@ -221,14 +225,18 @@ func defaultRoute() (d DefaultRouteDetails, err error) {
// We always return the IPv4 default route. // We always return the IPv4 default route.
// TODO(bradfitz): adjust API if/when anything cares. They could in theory differ, though, // TODO(bradfitz): adjust API if/when anything cares. They could in theory differ, though,
// in which case we might send traffic to the wrong interface. // in which case we might send traffic to the wrong interface.
iface, err := GetWindowsDefault(windows.AF_INET) luid, err := GetWindowsDefault(windows.AF_INET)
if err != nil { if err != nil {
return d, err return d, err
} }
if iface != nil { if luid != 0 {
d.InterfaceName = iface.FriendlyName() iface, err := luid.Interface()
if err != nil {
return d, err
}
d.InterfaceName = iface.Alias()
d.InterfaceDesc = iface.Description() d.InterfaceDesc = iface.Description()
d.InterfaceIndex = int(iface.IfIndex) d.InterfaceIndex = int(iface.InterfaceIndex)
} }
return d, nil return d, nil
} }
+9 -5
View File
@@ -19,15 +19,19 @@ import (
"tailscale.com/types/logger" "tailscale.com/types/logger"
) )
func interfaceIndex(iface *winipcfg.IPAdapterAddresses) uint32 { func interfaceIndex(luid winipcfg.LUID) (uint32, error) {
if iface == nil { if luid == 0 {
// The zero ifidx means "unspecified". If we end up passing zero // The zero ifidx means "unspecified". If we end up passing zero
// to bindSocket*(), it unsets the binding and lets the socket // to bindSocket*(), it unsets the binding and lets the socket
// behave as normal again, which is what we want if there's no // behave as normal again, which is what we want if there's no
// default route we can use. // default route we can use.
return 0 return 0, nil
} }
return iface.IfIndex iface, err := luid.Interface()
if err != nil {
return 0, err
}
return iface.InterfaceIndex, nil
} }
func defaultInterfaceIndex(family winipcfg.AddressFamily) (uint32, error) { func defaultInterfaceIndex(family winipcfg.AddressFamily) (uint32, error) {
@@ -36,7 +40,7 @@ func defaultInterfaceIndex(family winipcfg.AddressFamily) (uint32, error) {
return 0, err return 0, err
} }
return interfaceIndex(iface), nil return interfaceIndex(iface)
} }
func control(logf logger.Logf, _ *netmon.Monitor) func(network, address string, c syscall.RawConn) error { func control(logf logger.Logf, _ *netmon.Monitor) func(network, address string, c syscall.RawConn) error {
+2 -1
View File
@@ -7,11 +7,12 @@ import (
"github.com/tailscale/wireguard-go/tun" "github.com/tailscale/wireguard-go/tun"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg" "golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
"tailscale.com/tsconst"
) )
func init() { func init() {
tun.WintunTunnelType = "Tailscale" tun.WintunTunnelType = "Tailscale"
guid, err := windows.GUIDFromString("{37217669-42da-4657-a55b-0d995d328250}") guid, err := windows.GUIDFromString(tsconst.WintunInterfaceGUID)
if err != nil { if err != nil {
panic(err) panic(err)
} }
+3
View File
@@ -10,6 +10,9 @@ package tsconst
const WintunInterfaceDesc = "Tailscale Tunnel" const WintunInterfaceDesc = "Tailscale Tunnel"
const WintunInterfaceDesc0_14 = "Wintun Userspace Tunnel" const WintunInterfaceDesc0_14 = "Wintun Userspace Tunnel"
// WintunInterfaceGUID is the GUID of the Tailscale interface on Windows.
const WintunInterfaceGUID = "{37217669-42da-4657-a55b-0d995d328250}"
// TailnetLockNotTrustedMsg is the error message used by tailnet lock // TailnetLockNotTrustedMsg is the error message used by tailnet lock
// and sniffed (via substring) out of an error sent over the network. // and sniffed (via substring) out of an error sent over the network.
const TailnetLockNotTrustedMsg = "this node is not trusted by Tailnet Lock" const TailnetLockNotTrustedMsg = "this node is not trusted by Tailnet Lock"