Repository navigation
feat: several tunnels at once - #12
Merged
dennisklein merged 6 commits intoOct 11, 2026
Merged
dennisklein merged 6 commits into
dennisklein merged 6 commits into
Conversation
dennisklein
force-pushed
the
claude/project-thread-kmxtqs-multi
branch
from
October 11, 2026 12:21
843dc3b to
bea5536
Compare
dennisklein
force-pushed
the
claude/project-thread-kmxtqs-multi
branch
from
October 11, 2026 12:27
bea5536 to
c5bd8ac
Compare
dennisklein
force-pushed
the
claude/project-thread-kmxtqs-multi
branch
3 times, most recently
from
October 11, 2026 12:40
30de84f to
b721e4a
Compare
dennisklein
force-pushed
the
claude/project-thread-kmxtqs-multi
branch
2 times, most recently
from
October 11, 2026 12:56
e342781 to
4a86ac1
Compare
dennisklein
force-pushed
the
claude/project-thread-kmxtqs-multi
branch
from
October 11, 2026 13:04
4a86ac1 to
b714f82
Compare
dennisklein
force-pushed
the
claude/project-thread-kmxtqs-multi
branch
2 times, most recently
from
October 11, 2026 13:18
15b51f1 to
efab1e7
Compare
dennisklein
force-pushed
the
claude/project-thread-kmxtqs-multi
branch
from
October 11, 2026 13:36
efab1e7 to
0943e6e
Compare
dennisklein
force-pushed
the
claude/project-thread-kmxtqs-multi
branch
2 times, most recently
from
October 11, 2026 13:42
417f0ec to
f50798e
Compare
dennisklein
force-pushed
the
claude/project-thread-kmxtqs-multi
branch
from
October 11, 2026 13:54
f50798e to
7942504
Compare
dennisklein
force-pushed
the
claude/project-thread-kmxtqs-multi
branch
2 times, most recently
from
October 11, 2026 14:11
2693c3b to
8ddcfd9
Compare
dennisklein
force-pushed
the
claude/project-thread-kmxtqs-multi
branch
from
October 11, 2026 14:12
8ddcfd9 to
5931504
Compare
dennisklein
force-pushed
the
claude/project-thread-kmxtqs-multi
branch
5 times, most recently
from
October 11, 2026 15:36
5d8a2f2 to
baa558f
Compare
dennisklein
marked this pull request as ready for review
October 11, 2026 16:07
dennisklein
force-pushed
the
claude/project-thread-kmxtqs-multi
branch
from
October 11, 2026 19:52
baa558f to
86e20b5
Compare
- Set supports-multiple-connections in the .name file; the shim passes NM's per-activation bus name to a new D-Bus activated dispatcher - The dispatcher picks the lowest free of 8 slots, writes the bus name to /run/nm-sshuttle/N/bus-name and starts nm-sshuttle@N.service - Name the link, the guard table, the tunnel unit, the spec file, the pinned ssh config and the tproxy mark, table and rule after the slot - An instance under a per-activation name serves one activation and then exits; it sends READY=1 once it owns the name, and releases the name first when NetworkManager goes away - Count only the listeners in the tunnel unit's own cgroup in the health check - Add cleanup --slot N and --all; --all also removes what a single-tunnel version left, and the dispatcher runs it after an upgrade - Keep nmss0 to nmss7 unmanaged; the packages restart the dispatcher on update and end every tunnel on removal
- At Connect, once the first hop is known and before anything is created, check the profile against the other active ones under a lock and write its claim to /run/nm-sshuttle/N/claim.json - Refuse it when the networks left after exclude overlap, when both use dns=all, when both list the same DNS domain, or when the first hops would run in a loop; the reason names the other profile - Check the loop again when a roam changes the first hop - Release the claim on STOPPED and in cleanup --slot after a kill - Run the same checks in nm-sshuttle check, and mark active profiles in list
- Report the activated VPN connections from the NetworkManager watcher - In a gap, a VPN that has just become activated may be the tunnel this one's ssh runs over; try at once instead of waiting out the backoff
- sshuttle 1.3 keeps listening after its ssh exits, so its rules and listener look healthy while nothing carries the connections - the health check now looks for an ssh process in the tunnel unit's cgroup and drops the tunnel when none is left - a cgroup it cannot read counts as healthy, as before
- Take the link, guard, units and bus name from the newest running plugin instance; "nothing left" now means nothing in any slot - Expect one instance per activation in M2-09, M2-10 and M2-11, and a bus name of its own from NetworkManager in M2-02 - Let the lab DNS server answer another zone, for a second network with its own DNS server, web server and sshd inside 10.99.0.0/24 - MT-01: two tunnels at once, a reconnect of one, a refused overlap, a kill and an NM restart; MT-02: the lab over corp; MT-03: start-up time
- Mark the design as implemented and record what differs from it - Note the per-slot names in the design's architecture and add the work to the roadmap - Add a section on several VPNs at once to the user guide and lift the one-tunnel limit
dennisklein
force-pushed
the
claude/project-thread-kmxtqs-multi
branch
from
October 11, 2026 19:56
86e20b5 to
7f3efae
Compare
This was referenced Oct 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by Dennis · project thread
Before: one nm-sshuttle VPN at a time. Every name the plugin used was fixed (
nmss0, the guard table, the tunnel unit, the bus name), so a second profile could not be switched on next to the first.After: up to 8 nm-sshuttle VPNs can be on together, each with its own toggle, reconnects, guard, DNS link and tunnel. A profile that would fight an active one (overlapping networks, both
dns=all, a shared DNS domain, or a loop of jump hosts) is refused, and the journal andnm-sshuttle checkname the other profile. One tunnel's ssh can run over another's, and it comes back at once after the other's gap.It implements docs/later/multiple-tunnels.md and is stacked on #11 (tproxy), so its base is that branch. Merge #11 first.
How: the
.namefile setssupports-multiple-connections=true, so NM passes a bus name per activation. The shim hands it to a new D-Bus activated dispatcher. The dispatcher picks the lowest free of 8 slots, writes the name to/run/nm-sshuttle/N/bus-nameand startsnm-sshuttle@N.service. That instance owns the name and sendsREADY=1. It serves one activation and then exits. Everything it creates carries the slot:nmssN,nm-sshuttle-guard-N,nm-sshuttle-tunnel@N.service, the spec file, the pinned ssh config/run/nm-sshuttle-ssh/ssh_config-N, and the tproxy mark, table and rule. At Connect, before it creates anything, it checks its claim against the other slots' claims under a lock. The health check counts only listeners in its own tunnel unit's cgroup.cleanuptakes--slot Nor--all;--allalso removes the single-tunnel names after an upgrade.listmarks active profiles.Found by the VM runs and fixed here:
send_destination_prefixrule, so the policy names the dispatcher outright. NM does pass--bus-nameonce multiple connections are on.fix: reconnect when sshuttle outlives its ssh): in about one MT-02 run in three, corp's gap ended the lab's ssh, but the lab's sshuttle kept listening and the plugin saw nothing wrong. The health check now wants ansshprocess in the tunnel unit and reconnects without one. Unit tests cover it; the VM runs since have not hit the case, so the VM has not yet seen it fire.Results:
Profile keys: none change. The GNOME editor needs nothing for this PR.
🤖 Generated with Claude Code