Skip to main content

Module ratelimit

Module ratelimit 

Source
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 capacity addresses 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 than capacity (a /52 of 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/8 address counts as 127.0.0.1 (on Linux the whole block reaches lo, 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§

Limiter
Policy

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 ::1 is itself.