fix(zebrad): key the mempool per-peer download cap on IpAddr - #11233
fix(zebrad): key the mempool per-peer download cap on IpAddr#11233natalieesk wants to merge 1 commit into
Conversation
The mempool inbound-download manager keyed its per-peer concurrency cap (`MAX_INBOUND_CONCURRENCY_PER_PEER`) on the full `SocketAddr`. The `source` is a transient `(IP, ephemeral port)`, so two connections from the same host landed in two distinct `pending_per_peer` buckets, each with its own 5-slot budget, and a single host could exceed the intended per-host bound. `get_transient_addr` is explicitly not a permanent identifier. Re-key `pending_per_peer` on `IpAddr` at the cap check, the increment, and `release_peer_slot`, mirroring the inbound-block download path (`in_flight_ips`). Adds a regression test asserting a sixth transaction from the same IP on a different port is rejected once the IP holds `MAX_INBOUND_CONCURRENCY_PER_PEER`.
And two more auto-invalidated findings. Analyzed one file, diff |
Merge Protections🟠 1 of 1 protections blocking · waiting on 🕒 schedule
🟠 ❄️ 6.3.0 release [Scheduled Freeze]Waiting for
This freeze has no end date and must be removed manually.A freeze on the repository is scheduled for the following reason: 6.3.0 release
|
Summary
Closes #10685.
Warning
⛔ Blocked on #11229 (#10684). This PR is stacked on the
mempool_timeout_peer_slot_10684branch, notmain, and must not merge before #11229. Re-keying the per-peer cap on IP is only safe once the verification-timeout path releases the per-peer slot (fixed in #10684); without it, a single timed-out transaction would permanently lock out the sending host's IP. Merge #11229 first — GitHub then auto-retargets this PR tomainand itsCloses #10685link activates. See "Dependency" below.zebrad/src/components/mempool/downloads.rs: re-keypending_per_peerfromHashMap<SocketAddr, usize>toHashMap<IpAddr, usize>, usingsource.ip()at the cap check, the increment, andrelease_peer_slot.CHANGELOG.md: Security entry.zebrad/src/components/mempool/tests/vector.rs.Approach & Key Decisions
The per-peer download cap (
MAX_INBOUND_CONCURRENCY_PER_PEER) was keyed on the fullSocketAddr. Thesourceis the peer's transient(IP, ephemeral port)(connected_addr.get_transient_addr(), explicitly not a permanent identifier), so two connections from one host landed in two separate 5-slot buckets and a single host could exceed the intended per-host bound. The sibling inbound-block path already keys onIpAddr(in_flight_ips); this brings the mempool path in line.cancel_handlesstill stores theOption<SocketAddr>; only its.ip()is used for the map, so metrics/logging/error paths are unaffected.Dependency
This change must not ship without #10684 (#11229). The verification-timeout arm releases the per-peer slot only via #10684's fix. Without it, re-keying on IP turns that latent per-
SocketAddrslot leak (harmless, since ephemeral-port keys are never reused) into a permanent per-IP lockout: each timed-out transaction would leave a residual+1on the host's IP bucket, and afterMAX_INBOUND_CONCURRENCY_PER_PEERcumulative timeouts the host is rejected from all further mempool downloads until a downloader reset. Stacking on #11229 guarantees the timeout path releases the slot, so the map invariant (an IP's count equals its livecancel_handlesentries) holds. Once #11229 merges, this PR retargets tomain.Testing & Verification
per_peer_cap_is_keyed_on_ip_not_socket_addr(mempool/tests/vector.rs): queuesMAX_INBOUND_CONCURRENCY_PER_PEERtransactions from oneIP:port, then queues one more from the same IP, different port and asserts it is rejected withFullQueue.Ok(())(verified).cargo fmtandcargo clippy -p zebrad --lib --all-featuresare clean.Risk & Impact
Low, confined to mempool inbound-download accounting; no consensus, state-format, RPC, or config change; no DB format bump. Tightens a per-host DoS control (a host can no longer multiply its budget by opening connections from many source ports).
Changelog
Added under
### Security: the mempool per-peer download cap is now keyed on IP.AI Disclosure
Claude (Claude Code) wrote the fix and the regression test.
PR Checklist
CHANGELOG.mdupdated (Security)mainafter it merges