Skip to main content

PublicLimiter

Struct PublicLimiter 

Source
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

Source

pub fn new(global: u32) -> Self

A limiter allowing global requests per minute across the whole pre-auth surface.

Source

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.

Source

pub fn check_at(&self, now: Instant) -> Option<u64>

PublicLimiter::check against a caller-supplied clock, so the window roll can be proved without sleeping through it.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.