Pool: stop wedging listener accept loops on unauthenticated Noise handshakes #45

Open
opened 2026-10-15 18:06:10 +01:00 by vnprc-agent · 0 comments
Collaborator

Move the Noise handshake off the pool's accept loops so one silent TCP connection can no longer block all new connections, and bound connection resources.

Primary goals:

  • Per-connection handshake tasks — both listeners spawn a task per accepted socket instead of awaiting the handshake inline: the miner listener (roles/pool/src/lib/mining_pool/mod.rs:545-575, Connection::new::<Message>(...).await inside the accept arm) and the mint listener (roles/pool/src/lib/mining_pool/mint_connection.rs, perform_handshake awaited inside establish_connection's accept loop).
  • Handshake timeout — wrap the responder handshake in tokio::time::timeout (SV2 Noise is initiator-speaks-first; a peer that connects and sends nothing parks the current inline await forever).
  • Connection caps — bound concurrent handshakes and total live connections per listener, rejecting beyond the cap, so fd/memory exhaustion is not reachable by connection count alone.

Current state and specifics

Today Connection::new (full Noise handshake) is .awaited before the loop returns to listener.accept(), with no timeout on either listener. A single peer that completes the TCP handshake and then goes quiet permanently blocks every new miner connection on 0.0.0.0:34254 and every reconnection of the mint on the quote-listener port — cheap, remote, infrastructure-free DoS that compounds with any natural churn (restarts, network events). Neither listener caps concurrent connections. The same inline-await pattern exists in the translator's/jd-client's listeners via shared helpers; this issue covers the pool's two listeners, which face miners and the mint directly.

Findings write-up: notes/hashpool/security-review-2026-10-15.md (finding H-2, plus M-3 for the per-connection frame-buffer allocation ceiling).

Scope

In scope: the two pool listeners named above — spawn-per-connection, handshake timeout, connection/handshake caps, and a regression test that a silent peer does not block a second connection.

Out of scope: frame-size caps in the shared noise helpers (separate follow-up), upstream SRI listener refactor, and mint-side listener changes (the mint only dials out).

Move the Noise handshake off the pool's accept loops so one silent TCP connection can no longer block all new connections, and bound connection resources. Primary goals: - **Per-connection handshake tasks** — both listeners spawn a task per accepted socket instead of awaiting the handshake inline: the miner listener (`roles/pool/src/lib/mining_pool/mod.rs:545-575`, `Connection::new::<Message>(...).await` inside the accept arm) and the mint listener (`roles/pool/src/lib/mining_pool/mint_connection.rs`, `perform_handshake` awaited inside `establish_connection`'s accept loop). - **Handshake timeout** — wrap the responder handshake in `tokio::time::timeout` (SV2 Noise is initiator-speaks-first; a peer that connects and sends nothing parks the current inline await forever). - **Connection caps** — bound concurrent handshakes and total live connections per listener, rejecting beyond the cap, so fd/memory exhaustion is not reachable by connection count alone. ### Current state and specifics Today `Connection::new` (full Noise handshake) is `.await`ed before the loop returns to `listener.accept()`, with no timeout on either listener. A single peer that completes the TCP handshake and then goes quiet permanently blocks every new miner connection on `0.0.0.0:34254` and every reconnection of the mint on the quote-listener port — cheap, remote, infrastructure-free DoS that compounds with any natural churn (restarts, network events). Neither listener caps concurrent connections. The same inline-await pattern exists in the translator's/jd-client's listeners via shared helpers; this issue covers the pool's two listeners, which face miners and the mint directly. Findings write-up: `notes/hashpool/security-review-2026-10-15.md` (finding H-2, plus M-3 for the per-connection frame-buffer allocation ceiling). ### Scope In scope: the two pool listeners named above — spawn-per-connection, handshake timeout, connection/handshake caps, and a regression test that a silent peer does not block a second connection. Out of scope: frame-size caps in the shared noise helpers (separate follow-up), upstream SRI listener refactor, and mint-side listener changes (the mint only dials out).
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
vnprc/hashpool#45
No description provided.