Expand description
Failure-based rate limiting per client address (kernel spec §3.2, §4.1): a few free failures within a window, then an exponentially growing lockout.
- Every attempt counts as a failure the moment it is made
(
attempt), under the same lock as the lockout check, so a burst of parallel requests cannot get more guesses in than the policy allows. Only a success (succeeded) takes it back, and clears the address. - The key is the network, not the socket address: an IPv4-mapped IPv6 address counts as its IPv4 address, and IPv6 addresses count per /64, the block one subscriber usually holds.
- The window runs from the end of the last lockout, so waiting out a lockout does not reset the count; the next wrong attempt doubles it.
- Bounded, and a live entry is never evicted (amendment 2026-10-01).
At most
capacityaddresses are tracked. Past it, forgotten entries are pruned first; if the table is still full of live ones, the new address’s attempt is instead counted against one shared “overflow” entry with its own budget and lockout, rather than evicting an unrelated address’s real count. An earlier version evicted the oldest not-locked-out entry (then the oldest of all) to make room — but an attacker holding more addresses thancapacity(a/52of IPv6 is 4097 distinct/64s) could rotate through them so that no single address ever accumulated enough failures to lock out, turning the per-address budget into a throughput limit only. Sharing one overflow budget instead means a flood from more addresses than the table holds locks itself out together and slows pairing for everyone until that shared window or lockout passes (or the collector restarts) — a deliberate trade-off, not a bug: a single generous per-address budget should not be defeatable by rotating addresses. - In memory only: a collector restart clears every count and lockout, including the shared overflow entry. Each tracked address still has its own separate budget; only addresses past capacity share the overflow entry’s.
- Loopback is one address with its own entry (3b decision 9). Every
127.0.0.0/8address counts as127.0.0.1(on Linux the whole block reacheslo, so per-address entries would give a local process millions of budgets), and loopback always gets its own entry, past capacity too:hennery up’s own host and an unconfigured reverse proxy on the same machine are never pushed into the shared overflow budget by a flood from elsewhere. It is not exempt: its budget is the same as anyone’s.
Callers pass now, so the policy is testable without sleeping.
Structs§
Constants§
- DEFAULT_
CAPACITY - Addresses tracked by default.
Functions§
- key
- What a client address is counted as: its IPv4 address (also when it
arrives IPv4-mapped), or its IPv6 /64. Every IPv4 loopback address is
127.0.0.1, and::1is itself.