Skip to content

relay: one address can exhaust the shared frame budget below its own socket cap #992

Open

Description

@chappie-daemon

#959 gives the relay a global frame-memory budget (256 MiB) and a per-IP concurrent cap (64). The two do not compose under load: one address can open 32 non-reading sockets — half its own cap — fill 8 MiB of queue on each, and exhaust the whole budget, at which point every other client's next frame is refused and its socket closed, including a newcomer's AUTH challenge.

ADR 0008 §6 states this as the shared bound's inherent blast radius, with the arithmetic: 8 MiB × 32 = 256 MiB < 64 sockets, so the budget binds long before the cap does. That is honest, and it is not a fix.

What a fix looks like

A per-address share of the budget, so no single address can consume more than budget / N regardless of how many sockets it holds, with the global bound still the outer limit. The refusal paths already exist and do not change: FrameSink accounts text.len() on admission (sink.rs:269-270), the last handle's Drop refunds, and a budget refusal closes 1013 with no text frame (ADR 0008 §5).

What it should not do

  • Not a second charge on legitimate traffic: a single client with one socket reading normally must never be refused because another address is under attack.
  • Not a change to the global number. 256 MiB is the policy, and the per-address share should be derived from it rather than replacing it.
  • Not a change to max_connections_per_ip: the cap guards a different thing (concurrent sockets, not memory), and relay: the 8 MiB frame bound is per socket and sockets are unlimited #959's ADR says so.

Before building

Measure first. The measured resident-per-queued ratio is 1.04×–2.83× (ADR 0008, "What frame memory means here"), so a per-address share expressed in accounted bytes is not an RSS guarantee either; the issue should carry the same caveat the ADR does rather than implying a memory ceiling it cannot deliver.

Activity

  1. added
    rewritenostream 4.0 Rust/LMDB rewrite
    rustRust implementation work
    factoryBuilt by the software factory
    on Oct 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    factoryBuilt by the software factoryrewritenostream 4.0 Rust/LMDB rewriterustRust implementation work

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions