fix(desktop,web): advertise all usable network interfaces as selectable endpoints - #5165
fix(desktop,web): advertise all usable network interfaces as selectable endpoints#5165William-BnCRocks wants to merge 3 commits into
Conversation
…le endpoints Network access previously advertised only the first non-internal IPv4 that os.networkInterfaces() enumerated, which on multi-homed machines (VPN + LAN) is often an address other devices cannot reach. Advertise one selectable endpoint per usable interface instead, re-resolved from live interfaces on each read, and give each endpoint a distinct default preference key so any interface can be chosen as the default. Fixes pingdotgg#2031
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…keys Two configured HTTPS endpoints both labeled "Custom HTTPS" produced identical default-preference keys, so a stored default always resolved back to the first one. Include the endpoint host in the fallback key, matching the desktop-lan and tailscale-ip key shapes.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit be40876. Configure here.
ApprovabilityVerdict: Needs human review This PR introduces new user-facing functionality by allowing users to select from all usable network interfaces instead of just one. Changes to endpoint discovery, deduplication logic, and dynamic interface re-resolution represent meaningful runtime behavior changes that warrant human review. You can customize Macroscope's approvability policy. Learn more. |
…ale endpoint provider Both enumeration sites now use the same isIpv4Family helper, so a tailnet address reported with a numeric family resolves as its tailscale-ip entry and dedupes instead of surfacing as a generic LAN endpoint.

What Changed
Settings → Connections → Network access advertised a single "Local network" endpoint: the first non-internal IPv4 that
os.networkInterfaces()happened to enumerate. On multi-homed machines (VPN + LAN) the VPN adapter often wins, and the addresses other devices can actually reach are never shown or selectable.Now every usable IPv4 interface is advertised as its own selectable endpoint:
resolveLanAdvertisedHost→resolveLanAdvertisedHosts: enumerates all non-internal, non-loopback, non-link-local IPv4 addresses with their interface names, deduped. Regular LAN/VPN addresses order ahead of Tailscale CGNAT addresses, so a real NIC wins the default while Tailnet-only machines keep working.desktop-lan:endpoint per address, labeled with the interface name — "Local network (en0)" — when more than one would show;isDefaultstays on the first.getAdvertisedEndpointsread, so a VPN connecting or dropping after launch is reflected on the settings UI's normal refresh. The backend already binds0.0.0.0in network-accessible mode, so any currently-present address is reachable.endpointDefaultPreferenceKeynow embedshost:portfordesktop-lan:/tailscale-ip:endpoints so each interface can individually be set as default. Previously all LAN endpoints collapsed to one key, so with several rows every one would have matched the stored default. A stored legacy key matches nothing and falls back to theisDefaultendpoint — no migration needed.family: 4fromos.networkInterfaces(), matching the existing normalizations instartupAccess.ts:41andDesktopBackendConfiguration.ts:348.The wire contract is unchanged:
DesktopServerExposureState.advertisedHost/endpointUrlstill carry the first host,T3CODE_DESKTOP_LAN_HOSTstill overrides to a single host, and "no usable address → fall back to local-only" behaves identically. Only the advertised-endpoints list grew.Verification: 5 new desktop tests (per-interface enumeration/labels/default, numeric family, tailnet dedupe with default transfer, cross-interface address dedupe, live interface changes) and 3 new web tests for the preference keys; full desktop suite 411 passing, web unit suite passing, typecheck and
vp checkclean.Why
Fixes #2031. On hosts with several interfaces (VPN/WireGuard + LAN), the auto-picked address is frequently one other devices can't reach, so the "Reachable at" note and copied pairing URLs need hand-editing. #2031 proposed a manual hostname override (#2086, closed as superseded by the endpoint catalog); the catalog can instead offer all interfaces directly, which keeps the copy/pairing flows working with zero typing and lets the user pick a different default per machine.
UI Changes
Before/after screenshots coming before this leaves draft: the Network access row previously listed one "Local network" entry; it now lists one entry per interface with the interface name, each selectable as default.
Checklist
Note
Advertise all usable network interfaces as selectable LAN endpoints
isIpv4Familyhelper in DesktopNetworkInterfaces.ts to normalize Node's numeric4family value alongside the string'IPv4', fixing Tailscale IP discovery when Node uses numeric families.httpBaseUrl, transferring the default marker to the surviving Tailscale entry when a LAN endpoint is dropped.desktop-lanandtailscale-ipendpoints, so each address gets a distinct stored default.Macroscope summarized 2ec4b61.
Note
Medium Risk
Changes how LAN endpoints are discovered and how default pairing URLs are chosen, but exposure state and bind behavior stay compatible and the PR adds broad tests plus an intentional one-time preference fallback.
Overview
Multi-homed machines (VPN + LAN) previously surfaced only the first enumerated IPv4 as Local network, so pairing URLs often pointed at an unreachable address (#2031).
Desktop now enumerates every usable non-internal IPv4 via
resolveLanAdvertisedHosts, emits onedesktop-lan:endpoint per address (labels like Local network (en0) when several NICs qualify), and re-readsos.networkInterfaces()on eachgetAdvertisedEndpointsso VPN connect/disconnect updates the list without a relaunch. Tailscale CGNAT addresses are ordered after regular LAN IPs for the default host; duplicate URLs drop the plain LAN row and moveisDefaultto the Tailscale entry.isIpv4Familyaccepts numericfamily: 4from Node.Web moves pairing helpers into
ConnectionsSettings.logicand makesendpointDefaultPreferenceKeyhost-specific for LAN and Tailscale IP rows so each interface can be stored as default. Legacy keys likedesktop-core:lan:httpno longer match and fall back to theisDefaultendpoint once.Reviewed by Cursor Bugbot for commit 2ec4b61. Bugbot is set up for automated code reviews on this repo. Configure here.