Authenticated reachability: endpoint roaming (M2) + signed rendezvous registration (#37) #100
No reviewers
Labels
No labels
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
femboy/yip!100
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/authenticated-reachability-37-m2"
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?
Closes #37. Resolves the M2 follow-up filed in #34's review.
One milestone, two subsystems, stacked on #34 (PR #99). Both are "don't trust unauthenticated source/registration information."
M2 — authenticated endpoint roaming (data plane)
A peer's
endpointnow follows a legitimate address change (NAT rebind / mobility), gated on cryptographic authentication (WireGuard's model): endpoint moves only on a datagram that both decrypts and passes the AEAD replay window (a non-NoneEpochSet::inbound_open), and only for!relaypeers. A replayed/spoofed packet fails and cannot move it. #34's Init-path anti-hijack is untouched (the Init path never callsinbound_open).EpochSet::set_peer_addr(current/next/previous DataPlanes and any in-flightrekey.target) — egress is stamped fromDataPlane::peer_addr, notendpoint, so updatingendpointalone left return traffic targeting the dead address.deobf_ingressgained a trial-key fallback so a roamed peer's obfuscated data is found when theendpoint==srcfast-path misses.Fixes the ~120s ingress black-hole a mid-session NAT rebind otherwise caused under the obfuscation path.
#37 — signed rendezvous registration (control plane)
The registration is a
membership::Record(reusesRecord::verify— cert-vs-roots + signature +node_id-binds-cert, so squatting is closed; no new crypto). A newRegisterSignedmessage carries it;PeerInfogained an optionalrecord.--roots/--network-id) verifies before storing and drops legacy unsignedRegisterin mesh mode → the victim's real registration survives a forged-overwrite attempt. Rootless is unchanged.RegisterSignedwhen membership is configured, and verifies a returnedPeerInfo.recordand bindsrecord.node_id == nodebefore probing (Option-3 defense-in-depth). Address integrity is still backstopped by the 2b handshake-commit invariant.Testing
yipdunit + 32yip-rendezvouslib/bin tests;clippy -D warnings+fmtclean;#![forbid(unsafe_code)].run-netns-roaming.sh— a mid-session NAT rebind (obf on) recovers at 0% loss; a raw before/after check proves the egress redirect.run-netns-registration-hijack.sh— a rooted server refuses a forged registration; a rawLookup(A)probe returns A's real address before and after the attack (would flip to the attacker's address if the overwrite were accepted), and B↔A stays reachable.endpoint/peer_addrwriter) and the #37 verify-before-mutation invariant both hold.Follow-ups (non-blocking, from the final review)
reg_seqrestart residual: a client's registration counter resets to 0 on restart, so up to ~REG_TTL(~60s) of stale-rejected re-registrations until the old entry expires; a replay-capable eavesdropper can extend that within a capture window. Fix: wall-clock/TAI64N-seedreg_seq(mirrors #34's timestamp).PeerInfo: a mesh client currently probes a candidate that carries no record without verification (a malicious server could omit it to skip defense-in-depth). Backstopped by server-side verify + handshake-commit; consider requiring a record in mesh mode.tls_seenmap, never the servable directory — not the overwrite-DoS surface). Consider signing it for completeness.Stacked on #34 (#99) — merge after it. This milestone's design lives in
docs/superpowers/specs/2026-07-23-authenticated-reachability-design.md.