pub struct PublicLimiter { /* private fields */ }Expand description
Admission control for the routes that answer before a credential is checked (the invite link and the public landing page).
RateLimiter cannot do this job, and the reason is written into its
own bounds note: its map holds one entry per key it has seen, which is
safe only because its keys come from the operator’s auth file. Keyed on
something an anonymous caller chooses, an address or a header, the same
map is an unbounded allocation driven by whoever is calling, which is
the attack rather than the defence against it.
So this counter has no key at all. One number for the whole pre-auth
surface, reset each window. It bounds the node’s total pre-auth work no
matter how many callers the traffic arrives from, its memory is one
u32 decided at startup, and there is nothing a caller can supply that
makes it allocate or that buys them a second allowance.
There is deliberately no per-client ceiling, here or at the proxy (D59). Every key that would give one is either a client address, which this deployment does not handle at any layer, or something the caller chooses, which is the attack above. This type used to hold a 256-slot table hashed from the peer address; it was removed rather than left dormant, so the property is a fact about the code instead of a fact about where the node happens to be bound.
The cost is stated rather than hidden: a flood spends the node’s whole
pre-auth budget and the join page is unavailable to real invitees until
the window rolls. That is an outage and never a disclosure, because the
invite link is a bearer secret, GET never spends one, and every
failure renders one byte-identical page (D57). Whoever can see the
client can still limit per client; nothing in this deployment can.
Implementations§
Source§impl PublicLimiter
impl PublicLimiter
Sourcepub fn new(global: u32) -> Self
pub fn new(global: u32) -> Self
A limiter allowing global requests per minute across the whole
pre-auth surface.
Sourcepub fn check(&self) -> Option<u64>
pub fn check(&self) -> Option<u64>
Spends one request against the pre-auth allowance.
None admits it. Some(seconds) refuses it and is the
Retry-After to answer with: whole seconds until the window rolls,
never less than one, so a client obeying it does not spin.
Takes no argument describing the caller, which is the point: there is no caller identity to take before a credential has been checked that is not either a client address or a value the caller picked.