Repository navigation
Windows virtual adapters and macOS VPN tunnels are advertised as LAN routes #17246
Description
Activity
Note
Grok responding on behalf of Julius.
Thanks for the detailed report. I checked it against main at
a6ec88f7a, and both gaps are real.1. Windows adapter names slip past the filter
VIRTUAL_INTERFACE(apps/server/src/environment/DirectEndpoints.ts:66-67) is a case-sensitive prefix regex.resolveBoundEndpointsdrops a whole interface only when that regex matches its name (DirectEndpoints.ts:82).- I ran the regex on the names from your evidence.
VirtualBox Host-Only Network,VMware Network Adapter VMnet1/VMnet8,Local Area Connection* 2andLocal Area Connection* 10all pass through. OnlyvEthernet (WSL),vboxnet0andvmnet8get filtered. The tests only use Linux/macOS names plusvEthernet (WSL)(DirectEndpoints.test.ts:97-112). - One caution on the proposed fix: as far as I know, Windows connection names can be renamed by the user and are localized on non-English installs. If so, a list of English prefixes would only catch some cases. The adapter's MAC vendor prefix (from
os.networkInterfaces()) might be a sturdier signal, but I haven't verified that. 192.168.137.1does work for devices joined to that PC's hotspot, and the host-only address works from VMs on that host. Filtering them gives up those (rare) clients.
2. 198.18.0.0/15 counts as LAN
isPrivateIpv4Addressincludes198.18/15(packages/shared/src/hostClassification.ts:64).isPrivateNetworkHostuses it (:111-112), andisAdvertisableAddressaccepts anythingisPrivateNetworkHostaccepts (DirectEndpoints.ts:54-58).- I don't see any route-specific reason for that range to be there. It came in with fix: stop favicon requests for private link hosts on web and mobile #5838 as part of the favicon privacy policy, where being too inclusive is the safe direction. feat(clients): learn an environment's LAN and tailnet addresses #15468 later reused
isPrivateNetworkHostfor advertising, and no route test or comment mentions 198.18. isPrivateNetworkHostalso feedsisPublicFaviconHost, the client's route-kind label (packages/client-runtime/src/connection/routes.ts:100) and the web browser target resolver. So excluding the range only inisAdvertisableAddress, as you suggest, seems like the right scope.
What a stray route costs (
packages/client-runtime/src/connection/)- On every connect: each saved route gets an unauthenticated descriptor check, all in parallel, with a 2.5 s timeout (
driver.ts:42,:91-93,:144-154). A dead route ranked above the working one can delay connecting by up to about 2.5 s in total, not 2.5 s per route. - While connected on a lower-ranked route: every 60 s (
supervisor.ts:46,:605), each route ranked above the one in use is preflighted (supervisor.ts:357-361). - The cooldown doesn't help here: the 5 min cooldown (
supervisor.ts:47-49,:749) only applies to a route that answered and then failed to connect. A silent route gets checked again every tick. - Learned LAN routes are inserted ahead of tailnet and anything slower (
routes.ts:105-125), which would explain why they ended up above your route in use.
Workaround today: there's no way to hide or disable a learned route. The web and mobile route lists don't allow removing one, likely because it would just be learned again (
apps/web/src/components/settings/EnvironmentRoutesList.tsx:124,apps/mobile/src/features/settings/EnvironmentRoutesSection.tsx:187). You can drag the stray routes below the route you use. That should stop the 60 s re-checks, but the per-connect check stays. Turning off the adapter on the server, as you mentioned, should remove them completely.Related
- [Bug]: Proton VPN address is advertised as Tailscale IP and breaks phone pairing #15750 and open PR fix(connect): Cloudflare and other VPN addresses no longer show as Tailscale #17158 are the 100.64/10 Tailscale-vs-VPN labeling problem. fix(connect): Cloudflare and other VPN addresses no longer show as Tailscale #17158 edits the same
isAdvertisableAddressandresolveBoundEndpointslines but doesn't touchVIRTUAL_INTERFACEor 198.18. So it's complementary, though a fix here would probably need a rebase on top of it. - I didn't find any duplicate issue or other open PR for this.
- addedbugSomething is broken or behaving incorrectly.Something is broken or behaving incorrectly.via-triageFiled through npx t3 triageFiled through npx t3 triage
on Oct 8, 2026 Hi @juliusmarminge , I’d like to work on this issue. Could you assign it to me if nobody else is already working on it?
My proposed scope is to exclude
198.18.0.0/15from direct-endpoint advertising without changing the sharedisPrivateNetworkHostbehavior, and extend the existing virtual-interface filter for the Windows adapter names reported here. I’ll add focused regression tests that also verify normal LAN and Tailscale routes remain available.Before implementing the Windows part, could you confirm whether hotspot and host-only interfaces should be excluded from automatic discovery, given that hotspot clients and local VMs can legitimately reach them? I understand that connection-name filtering also won’t cover every renamed or localized adapter.
I’ll keep the patch focused on this discovery issue and account for the overlapping changes in #17158.
What happened
A remote environment's route list fills with "LAN · found automatically" addresses that only exist on the server host itself:
http://192.168.56.1:3773/(VirtualBox Host-Only adapter) andhttp://192.168.137.1:3773/(the Wi-Fi Direct virtual adapter Windows uses for Mobile hotspot / Internet Connection Sharing), alongside the real Wi-Fi address.http://198.19.2.2:3773/, the address of autunpoint-to-point interface created by a third-party VPN/security client (not Tailscale).No client can reach these addresses, but they are saved as routes, and two of them rank above the route actually in use.
Diagnosis
resolveBoundEndpointsinapps/server/src/environment/DirectEndpoints.tsadvertises every private IPv4 address on a wildcard-bound server. It skips container and VM networks only by interface-name prefix:Two gaps:
os.networkInterfaces()are connection names, not driver names. VirtualBox's adapter isVirtualBox Host-Only Network(vboxnetis the Linux/macOS name), VMware's areVMware Network Adapter VMnet1/8, and the hotspot adapter isLocal Area Connection* 2. Only Hyper-V/WSL (vEthernet) is caught.isPrivateNetworkHost(packages/shared/src/hostClassification.ts) treats 198.18.0.0/15 as private, soisAdvertisableAddressaccepts it. That RFC 2544 benchmarking range is not used for real LANs, but VPN, proxy and security clients use it to address their tunnel interfaces. On macOS those interfaces are namedutunN, and a blanketutunfilter would also drop Tailscale, so the address range is the better signal.Impact is limited. Before connecting,
ConnectionDriver.checkRoutefetches the unauthenticated descriptor and requires a matchingenvironmentId, so a stray address on another network answers "silent" rather than receiving the credential. But each unreachable route still costs a probe on every connect attempt, and with a 60 sBETTER_ROUTE_CHECK_INTERVAL, every minute while a lower-ranked route is in use. The list also shows routes the user cannot act on.Steps to reproduce
192.168.56.1and/or192.168.137.1marked "LAN · found automatically".For the macOS case: run the server on a Mac with any client that creates a
utuninterface in 198.18.0.0/15 (ifconfig | grep -A1 utun).Version
Main at
9a3070bcf0(0.0.45).DirectEndpoints.tsandhostClassification.tsare identical to main.Environment
utunat 198.19.2.2.Evidence
Server A,
Get-NetIPAddressjoined withGet-NetAdapter(link-local and disconnected adapters omitted):Route list on the client:
192.168.56.1,192.168.50.x,192.168.137.1(all "found automatically"), then the user-added route "In use", then Tailscale.Server B:
The client lists
http://198.19.2.2:3773/as "LAN · found automatically" next to the host's two real LAN addresses.Related issues
Fix applied or workaround
None applied. Possible fixes:
VIRTUAL_INTERFACEwith the Windows connection names:VirtualBox Host-Only Network,VMware Network Adapter, andLocal Area Connection\* \d+. The asterisked form is the name Windows gives Wi-Fi Direct/hosted-network virtual adapters; real Ethernet connections are namedEtherneton Windows 10+.isAdvertisableAddress, while keeping it private forisPrivateNetworkHost's other callers.Workaround: disable the adapters on the server (turn off Mobile hotspot; disable the VirtualBox Host-Only adapter when no VM needs it).
Filed by
@astarktc, with an AI agent (Pi in T3 Code), after inspecting the adapters on both hosts and reading the route code on main.