mirror of
https://github.com/jmcorgan/fips.git
synced 2026-07-30 19:46:15 +00:00
node: skip Msg1 → Msg2 reply when at max_peers cap
Move the max_peers cap check in handle_msg1 forward, from the late check inside promote_connection (which fires after Msg2 has already been built and put on the wire) to an early position after identity verification but before index allocation and the Msg2 send. When the gate fires for a net-new identity, the Msg1 is silent-dropped — no response goes back to the peer, no AEAD compute or wire bytes are spent. Bypass preserved for known peers (reconnect / cross-connection): if the sender's NodeAddr is already in self.peers, or if a pending outbound connection is in flight to the same identity, the gate is skipped so legitimate maintenance traffic continues to work. The late check inside promote_connection is intentionally retained as defense-in-depth against future call sites or a disconnect racing between the early-gate decision and promotion. Wire-cost rationale: a 45 s tcpdump at saturation observed ~3.6 cap-denials/s steady-state, each previously paying the full Noise IK responder crypto + Msg2 (~104 B) on the wire before being rejected. The bigger value is cleaner peer-side semantics — the peer no longer sees a fake-completed handshake whose data frames subsequently fail decryption locally. Two new unit tests cover the cases: - handle_msg1_silent_drops_at_cap_for_new_peer drives a wire-pumped Msg1 from a fresh identity into a saturated node and asserts no Msg2 reaches the sender socket. Stash-verifies as FAIL on the pre-fix tree (Msg2 hits the wire) and PASS post-fix. - handle_msg1_admits_existing_peer_at_cap drives a Msg1 from an identity already in self.peers and asserts the gate does not evict it. This is a regression check (the no-gate tree behaves the same way here, but the test guards against an accidental future gate that breaks known-peer admit).
This commit is contained in:
@@ -72,6 +72,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
`handshake.rs:1114` is unchanged. Introduces a shared
|
||||
`Node::outbound_admission_check()` helper so the invariant is
|
||||
grep-able and unit-testable.
|
||||
- Inbound `handle_msg1` now silent-drops at `node.limits.max_peers`
|
||||
saturation *before* building/sending Msg2, instead of replying with
|
||||
Msg2 and then rejecting at `promote_connection`. Adds an early cap
|
||||
check positioned after identity verification (so the
|
||||
reconnect / cross-connection bypass for known peers still fires) and
|
||||
before index allocation + Msg2 wire send. The late cap check inside
|
||||
`promote_connection` is intentionally retained as
|
||||
defense-in-depth. Wire savings observed in a 45 s ops tcpdump at
|
||||
saturation: ~3.6 cap-denials/s × Msg2 (~104 B + AEAD compute) each.
|
||||
Bigger win is cleaner peer-side semantics — no fake-completed
|
||||
handshake whose subsequent data frames fail decryption on this side.
|
||||
- Mesh-size estimator (`compute_mesh_size`) no longer double-counts the
|
||||
parent's bloom cardinality during the transient cache window after a
|
||||
local parent-switch. Symptom: `fipsctl show status` / fipstop displayed
|
||||
|
||||
Reference in New Issue
Block a user