2b: path-switch re-initiation can half-open a session (needs rekey/anti-replay) #36

Closed
opened 2026-07-06 18:18:45 +00:00 by vxfemboy · 0 comments
vxfemboy commented 2026-07-06 18:18:45 +00:00 (Migrated from github.com)

Context

Whole-branch review of milestone 2b (rendezvous/NAT traversal, branch feat/rendezvous-2b). Availability edge case, no security impact. Rooted in the deferred no-rekey/no-anti-replay limitation (#34, #9).

Problem

Every path switch in PeerManager (Direct→Punch re-target, Punch(C1)→Punch(C2), Punch→Relay, Direct→Relay) calls begin_handshake, which runs start_initiator and draws a fresh Noise ephemeral. If the remote peer already admitted the abandoned attempt and is now Established, it cannot rebuild (no rekey/anti-replay) and only replays its cached HandshakeResp keyed to the old ephemeral. Our read_response then fails, reverts us to Idle, and we re-escalate — indefinitely.

Scenario: A and B rendezvous-only, both punch; glare tiebreak makes B the responder-adopter → B Established. B→A HandshakeResp is lost/delayed through A's full PUNCH_MS (~5s) window. A escalates to relay (clears endpoint, fix-pass-2). A's relay Inits reach B; B (Established) replays its direct cached_resp over the relay; A never completes. B believes it is connected and black-holes A-bound TUN traffic into a dead session; A buffers B-bound traffic in pending_tun. No recovery until process restart.

Severity: Important, low probability (needs ~5s sustained asymmetric loss right at the punch boundary). Strictly worse than 2a's clean 90s give-up (silent bidirectional black hole with B falsely "up").

Fix direction

Needs a re-handshake that can supersede a stale session on the responder side — i.e. the anti-replay/rekey work in #34 / #9 (a newer authenticated Init replaces the old session). Until then, this is a known limitation of the escalation path introduced in 2b.

## Context Whole-branch review of milestone 2b (rendezvous/NAT traversal, branch feat/rendezvous-2b). Availability edge case, no security impact. Rooted in the deferred no-rekey/no-anti-replay limitation (#34, #9). ## Problem Every path switch in `PeerManager` (Direct→Punch re-target, Punch(C1)→Punch(C2), Punch→Relay, Direct→Relay) calls `begin_handshake`, which runs `start_initiator` and draws a **fresh Noise ephemeral**. If the *remote* peer already admitted the abandoned attempt and is now `Established`, it cannot rebuild (no rekey/anti-replay) and only replays its cached `HandshakeResp` keyed to the *old* ephemeral. Our `read_response` then fails, reverts us to Idle, and we re-escalate — indefinitely. **Scenario:** A and B rendezvous-only, both punch; glare tiebreak makes B the responder-adopter → B `Established`. B→A `HandshakeResp` is lost/delayed through A's full `PUNCH_MS` (~5s) window. A escalates to relay (clears endpoint, fix-pass-2). A's relay Inits reach B; B (Established) replays its *direct* cached_resp over the relay; A never completes. B believes it is connected and black-holes A-bound TUN traffic into a dead session; A buffers B-bound traffic in `pending_tun`. No recovery until process restart. **Severity:** Important, low probability (needs ~5s sustained asymmetric loss right at the punch boundary). Strictly worse than 2a's clean 90s give-up (silent bidirectional black hole with B falsely "up"). ## Fix direction Needs a re-handshake that can supersede a stale session on the responder side — i.e. the anti-replay/rekey work in #34 / #9 (a newer authenticated Init replaces the old session). Until then, this is a known limitation of the escalation path introduced in 2b.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
femboy/yip#36
No description provided.