You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
relay: one address can exhaust the shared frame budget below its own socket cap #992
#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.
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