Skip to content

add a handshake timeout on the stream Accept path#62

Merged
pzverkov merged 1 commit into
mainfrom
harden/stream-handshake-timeout
Jun 1, 2026
Merged

add a handshake timeout on the stream Accept path#62
pzverkov merged 1 commit into
mainfrom
harden/stream-handshake-timeout

Conversation

@pzverkov

@pzverkov pzverkov commented Jun 1, 2026

Copy link
Copy Markdown
Member

What

Listener.performHandshake called ResponderHandshake with no deadline, so a peer that connected and then stalled mid-handshake pinned a goroutine + session indefinitely (slow-loris). The handshake-rate limiter throttles new attempts but does nothing for an in-flight stall. The datagram transport already times out; the stream path did not.

Change

  • Add HandshakeTimeout to TransportConfig, default 30s (the CH-KEM handshake is sub-millisecond, so the bound only catches the abusive case; operators in hostile environments can lower it).
  • performHandshake sets the connection deadline before ResponderHandshake and clears it on success, so the established transport's own per-op deadlines take over.
  • Responder/Accept path only - a hung Dial is the client's own problem. Deadline only, no wire change.

Verification

  • New TestResponderHandshakeTimeout: a peer that connects and sends nothing gets torn down within the timeout instead of hanging.
  • Existing end-to-end Listen/Dial round-trips (now with the 30s default active) pass under -race; full suite green.

Listener.performHandshake called ResponderHandshake with no deadline, so a peer that connected and stalled mid-handshake pinned a goroutine and a session indefinitely - a slow-loris vector. The handshake-rate limiter throttles new attempts but does nothing for an in-flight stall; the datagram transport already times out, the stream path did not.

Add HandshakeTimeout to TransportConfig (default 30s; the CH-KEM handshake is sub-millisecond, so the bound only catches the abusive case). performHandshake sets the connection deadline before ResponderHandshake and clears it on success, so the established transport's own per-op deadlines take over. Responder/Accept path only - a hung Dial is the client's own problem.

Test: a peer that connects and sends nothing, the responder tears it down within the timeout instead of hanging.
@pzverkov pzverkov self-assigned this Jun 1, 2026
@pzverkov pzverkov merged commit 1eace88 into main Jun 1, 2026
13 checks passed
@pzverkov pzverkov deleted the harden/stream-handshake-timeout branch June 1, 2026 18:18
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.

1 participant