add: WireGuard legs in the double hop #214
Loading…
Reference in a new issue
No description provided.
Delete branch "change/wireguard-doublehop-176"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Stage 3 of #176 - the payoff. Either leg of a double hop may now be OpenVPN or WireGuard, in any combination.
How:
openvpn()to thework()level, protocol-neutral: an OpenVPN leg still connects on its own thread and is waited for; a WireGuard leg's bring-up is synchronous (no process, no wait). Either way the chain is routed before the main leg launches, through the samehop_routesmodel from #211.link_upgrows the chain's policy knobs: a hop leg takes no default (it only carries the main leg, steered into it by the chain route), a chained main leg gets no endpoint pin (the chain route into the hop device owns its endpoint - a pin would yank the outer packets back onto the physical link), and an MTU cap sizes the inner tunnel to what fits through the outer one: 1340 for WG-over-WG, 1420 (the WG default, no-op) over an OpenVPN hop.tunnel_terminated_hopitself.TUNNEL_SECONDARYsplits intoTUNNEL_HOP/TUNNEL_BYPASS- one flag couldn't say hop-yes-bypass-no, which is WireGuard's state now. The gui hop button and bypass picker gate on their own tables; WG bypass remains refused at construction.Verification: suite 533 passed - new coverage for the WG-hop flow (pin precedes launch, chain route, no wait, failure aborts before the main leg), chained-main policy (def1 without pin, MTU capping both directions), role/table pinning, and the service's hop-protocol lifecycle.
Live matrix before merge (all four combos, egress + teardown):
Closes #176.
🤖 Generated with Claude Code
First live matrix round diagnosed from the log - both failures had one root each, fixed in
39495d8:WG hop (combos 2/4):
link_up's pre-clean ran a fulllink_down, which reads the conf just written and deletes that endpoint's proto-111 route - the tunnel thread's pre-launch pin. The log shows it exactly: run D pinned 149.102.227.1, the main leg connected fine through the chain ("Successfully connected to node-us-216" at 13:09:33), and then the def1 pair landed and looped the hop's outer packets into the main tunnel. Connected on screen, black hole underneath. Pre-clean is device-only now; a test pins the invariant.Empty external IP (combo 3): a WireGuard bring-up is silent success - the handshake only fires on first traffic - and the gui monitor's ip check was itself the first traffic, racing the handshake it depended on with a 1s timeout.
wg()now nudges a packet through and waits for the handshake before reporting established; a timeout is a proper failed attempt. This also un-lies the WG-hop case above, which reported "Successfully connected" over a dead chain.Suite 537. Ready for matrix round 2 - all four combos again; combo 1 unaffected by either fix.
Matrix round 2 passed live (2026-08-30): all four combos connect and pass traffic, external IP shows, teardown clean. WG→WG's first bring-up is a touch slower by design - two lazy handshakes stack (the hop's only initiates when the main leg's handshake traffic hits it) plus the nudge-and-poll; well inside the 10s gate. Verified done.