Skip to content

Chains and routes by domain: each VPN keeps its own networks - #51

Merged
GarageDeveloper merged 1 commit into
mainfrom
chained-dynamic-routes
Oct 30, 2026
Merged

GarageDeveloper merged 1 commit into
mainfrom
chained-dynamic-routes

Conversation

@GarageDeveloper

Copy link
Copy Markdown
Owner

Three fixes for a VPN chained through another one that routes names by domain.

  • Routes by domain stay out of a chained VPN's networks. The chain exception now goes one way only. An address inside a VPN this one goes through is expected. An address inside a VPN that goes through this one belongs to that VPN: the host route here used to take its traffic. When a session registers its routes, the other sessions also hand over the routes by domain that fall inside its networks or on its gateway. A full tunnel connected afterwards takes none of them.
  • A refused address is retried later. When another session routes an address, it now waits with its name and expiry. It gets its route by domain once no other session carries it. This matters because macOS keeps the DNS answer cached, so the name may not be asked again.
  • A chained VPN no longer removes the other VPN's route to its gateway. If the VPN it goes through already has a host route to that gateway, the chained VPN no longer adds or removes it. macOS keeps only one copy of the route, so removing it when the chained VPN disconnected cut the first VPN's route, and the chained VPN could not reconnect.

Unit tests cover the registry rules and the waiting list. Tested by hand on macOS with an L2TP VPN and an OpenVPN chained through it, connecting and disconnecting the chained one alone.

🤖 Generated with Claude Code

Three fixes for a VPN chained through another that routes names by
domain:

- The chain exception for routes by domain goes one way only. An address
  inside a VPN this one goes through is expected; one inside a VPN that
  goes through this one is that VPN's, and a host route here took its
  traffic. When a session registers its routes, the others also hand over
  the routes by domain inside its networks or on its gateway (a full
  tunnel connected since takes none).
- An address refused, or handed over, because another session routes it
  now waits with its name and expiry, and gets its route by domain once
  no other session carries it. The system keeps the DNS answer cached, so
  the name may not be asked again.
- A VPN whose routes hold the gateway of a VPN chained through it as a
  host route: the chained VPN added the same route, which macOS keeps
  once, and deleted it when it disconnected, cutting the first VPN's
  route. The chained VPN no longer adds, nor removes, such a route.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@GarageDeveloper
GarageDeveloper merged commit b752e95 into main Oct 30, 2026
6 checks passed
@GarageDeveloper
GarageDeveloper deleted the chained-dynamic-routes branch October 30, 2026 15:30
@GarageDeveloper GarageDeveloper mentioned this pull request Oct 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant