diff --git a/net/netmon/state.go b/net/netmon/state.go index 27e3524e8..e97c43325 100644 --- a/net/netmon/state.go +++ b/net/netmon/state.go @@ -9,6 +9,7 @@ import ( "net" "net/http" "net/netip" + "path" "runtime" "slices" "sort" @@ -28,6 +29,14 @@ import ( // same interface and subnet. var forceAllIPv6Endpoints = envknob.RegisterBool("TS_DEBUG_FORCE_ALL_IPV6_ENDPOINTS") +// avoidInterfaces is a debug/power-user knob to exclude specific interfaces from consideration +// when gathering endpoints. +var avoidInterfaces = envknob.RegisterString("TS_AVOID_INTERFACES") + +// Likewise, onlyInterfaces can be set to specify the _only_ interfaces Tailscale is allowed to +// consider when gathering endpoints. +var onlyInterfaces = envknob.RegisterString("TS_ONLY_INTERFACES") + // LoginEndpointForProxyDetermination is the URL used for testing // which HTTP proxy the system should use. var LoginEndpointForProxyDetermination = "https://controlplane.tailscale.com/" @@ -35,6 +44,20 @@ var LoginEndpointForProxyDetermination = "https://controlplane.tailscale.com/" func isUp(nif *net.Interface) bool { return nif.Flags&net.FlagUp != 0 } func isLoopback(nif *net.Interface) bool { return nif.Flags&net.FlagLoopback != 0 } +func matchInterfaceName(name string, patterns string) bool { + patternsList := strings.Split(patterns, ",") + for _, pattern := range patternsList { + pattern = strings.TrimSpace(pattern) + if pattern == "" { + continue + } + if matched, _ := path.Match(pattern, name); matched { + return true + } + } + return false +} + func isProblematicInterface(nif *net.Interface) bool { name := nif.Name // Don't try to send disco/etc packets over zerotier; they effectively @@ -47,6 +70,17 @@ func isProblematicInterface(nif *net.Interface) bool { return false } +func isAllowedInterface(nif *net.Interface) bool { + name := nif.Name + if onlyInterfaces() != "" && !matchInterfaceName(name, onlyInterfaces()) { + return false + } + if avoidInterfaces() != "" && matchInterfaceName(name, avoidInterfaces()) { + return false + } + return true +} + // LocalAddresses returns the machine's IP addresses, separated by // whether they're loopback addresses. If there are no regular addresses // it will return any IPv4 linklocal or IPv6 unique local addresses because we @@ -66,6 +100,10 @@ func LocalAddresses() (regular, loopback []netip.Addr, err error) { // send Tailscale traffic over. continue } + if !isAllowedInterface(stdIf) { + // Skip interfaces that the user does not want to use with Tailscale. + continue + } ifcIsLoopback := isLoopback(stdIf) addrs, err := iface.Addrs()