Skip to content

fix(wg_mgr): retry the initial direct-path handshake instead of one-shot - #54

Merged
fudio101 merged 1 commit into
mainfrom
fix/retry-initial-direct-handshake
Aug 19, 2026
Merged

fix(wg_mgr): retry the initial direct-path handshake instead of one-shot#54
fudio101 merged 1 commit into
mainfrom
fix/retry-initial-direct-handshake

Conversation

@fudio101

Copy link
Copy Markdown
Collaborator

Summary

Adapted from Csontikka/microlink@5bda1783 (issue #32), with the already-fixed active-clearing bug (PR #53, this same session) kept removed — the source commit's diff still cleared peer->active right after wireguardif_connect(), which PR #53 (issues #26/#28) proved permanently blocks that peer's direct-path handshake, since active is the master session-initiation gate, not a retry throttle. Porting this verbatim would have silently reintroduced a bug fixed two PRs ago.

  • process_disco_pong() fired a one-shot direct-path handshake init gated by a single boolean latch (tried_initial_handshake): if that one init was lost or unanswered, the peer stayed permanently un-sessioned on the direct path even though further direct PONGs kept arriving. Replaced the latch with a retry timestamp (last_init_handshake_ms) so a dropped/unanswered init gets another try every 30s (INITIAL_HANDSHAKE_RETRY_MS) instead of giving up forever.

FORK_PRS.md row 13 (issue #32) marked done. Also documented that issue #36 (wake blocked sockets on stop) was investigated as part of this batch and isn't needed here: this fork's microlink_stop() (from issues #21/#22's PR #47) never frees context until ml_join_tasks() proves every worker exited, and ml_derp.c's blocking loops already call ml_shutdown_pending() on every SO_RCVTIMEO-bounded iteration to bail out cooperatively — the source commit's UAF doesn't exist in this fork's architecture, so no port planned (row left open for now).

Closes #32

Test plan

🤖 Generated with Claude Code

Adapted from Csontikka/microlink@5bda1783 (issue #32), with the
already-fixed active-clearing bug (PR #53, this same session) kept removed
-- the source commit's diff still cleared peer->active right after
wireguardif_connect(), which PR #53 (issues #26/#28) proved permanently
blocks that peer's direct-path handshake since active is the master
session-initiation gate, not a retry throttle. Porting this verbatim would
have silently reintroduced a bug fixed two PRs ago.

process_disco_pong() fired a one-shot direct-path handshake init gated by
a single boolean latch (tried_initial_handshake): if that one init was
lost or unanswered, the peer stayed permanently un-sessioned on the direct
path even though further direct PONGs kept arriving. Replaced the latch
with a retry timestamp (last_init_handshake_ms) so a dropped/unanswered
init gets another try every 30s (INITIAL_HANDSHAKE_RETRY_MS) instead of
giving up forever.

Also documented in FORK_PRS.md that issue #36 (wake blocked sockets on
stop) was investigated and isn't needed here: this fork's
microlink_stop() (from issues #21/#22's PR #47) never frees context until
ml_join_tasks() proves every worker exited, and ml_derp.c's blocking
loops already call ml_shutdown_pending() on every SO_RCVTIMEO-bounded
iteration to bail out cooperatively -- the source commit's UAF doesn't
exist in this fork's architecture.

Closes #32

Co-authored-by: Adrian.Nguyen-Qualgo <nguyen.ndt@qualgo.net>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
@fudio101
fudio101 merged commit 7e52ba3 into main Aug 19, 2026
13 checks passed
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.

Retry direct-handshake init every 30s instead of one-shot latch (mined from Csontikka/microlink)

2 participants