Skip to main content

LoginLimiter

Struct LoginLimiter 

Source
pub struct LoginLimiter { /* private fields */ }
Expand description

Fixed-window failed-login counter, keyed by client address.

In-process on purpose: it protects a listener that defaults to loopback and holds a handful of accounts, and a database-backed counter would add a write to the very path being flooded.

An attempt is counted when it starts, not when it fails. begin reserves a slot under the lock and refuses once failures plus attempts still in flight reach the limit. Counting only finished failures was a check-then-act race: a burst of parallel requests from one address all passed the check before the first of them had paid its 600 000 iterations and recorded anything, so the burst bought as many guesses — and as much KDF time — as it had requests. The slot is a LoginAttempt guard, so every early return (a database error included) gives it back.

Implementations§

Source§

impl LoginLimiter

Source

pub fn new(max_attempts: u32, window_seconds: u64) -> Self

At most max_attempts failures per client address (an IPv6 address by its /64) within window_seconds.

Source

pub fn rebuilt(&self, max_attempts: u32, window_seconds: u64) -> Self

The same counters under new limits.

A configuration reload rebuilds the admin router, and with it every value AdminState derives from [admin] — which for this type would mean starting from an empty map. That is a security regression, not a cosmetic one: a reload in the middle of a brute-force attempt would clear the attacker’s backoff, and admin.login_* is exactly the sort of key an operator edits because they are being flooded.

Carrying the whole limiter across instead would be the other error, leaving login_max_attempts and login_window_seconds silently stale. So the counters move and the limits do not.

The in-flight counts do not move: their guards hold the old limiter and settle against it, so a count copied here would never be released. The cost is that an attempt straddling a reload is not counted, once.

Source

pub fn begin(&self, client: Option<IpAddr>) -> Result<LoginAttempt<'_>, u64>

Starts a login attempt from this address, or refuses it. Err carries the seconds left in the window.

Called before the password hash runs: 600 000 iterations is a denial-of-service lever, so a limited caller must not pay it — nor make the server pay it. The returned guard holds the slot until it is failed or dropped.

Source

pub fn record_success(&self, client: Option<IpAddr>)

Clears an address’s counter after a completed login, so one operator fumbling their password does not spend the window for the next.

Trait Implementations§

Source§

impl Debug for LoginLimiter

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

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<'a, T, E> AsTaggedExplicit<'a, E> for T
where T: 'a,

Source§

fn explicit(self, class: Class, tag: u32) -> TaggedParser<'a, Explicit, Self, E>

Source§

impl<'a, T, E> AsTaggedImplicit<'a, E> for T
where T: 'a,

Source§

fn implicit( self, class: Class, constructed: bool, tag: u32, ) -> TaggedParser<'a, Implicit, Self, E>

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<A, B, T> HttpServerConnExec<A, B> for T
where B: Body,

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
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 = !

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

fn try_from(value: U) -> Result<T, !>

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.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more