Skip to main content

SecurityConfig

Struct SecurityConfig 

Source
pub struct SecurityConfig {
    pub max_concurrent_handlers: Option<u32>,
    pub per_source_rate_per_sec: Option<f64>,
    pub per_source_burst: Option<u32>,
    pub max_tracked_sources: Option<usize>,
}
Expand description

Security / rate-limiting section of the config file.

All fields are optional; defaults produce a safe configuration out of the box.

All fields are hot-reloadable on SIGHUP and via admin_v1_reload. The live ConnectionLimiter rebuilds its keyed governor rate limiter from the new quota and swaps it under an RwLock. The Arc<Semaphore> identity is preserved across cap resizes via add_permits / acquire_many_owned(...).forget() so every in-flight OwnedSemaphorePermit keeps draining into the same semaphore on Drop.

Caveats: during a shrink the live concurrency cap is >= new until enough handlers drain; under racing reloads (N→N+1→N) the post-task permit count may briefly land anywhere in [N, N+1] until the next reload reconciles. Accepted as a known trade-off: strict resize semantics would require a full handler-drain barrier.

Token-bucket state is not preserved across a reload — the keyed limiter is rebuilt from scratch. Operators tuning the per-source quota live should expect the next acquire after a reload to start with a fresh burst budget.

0 means “disable this layer”:

  • max_concurrent_handlers = 0: no global concurrency cap.
  • per_source_rate_per_sec = 0: per-source rate-limit disabled. The paired per_source_burst field is ignored — the limiter short-circuits before the keyed map is consulted.
  • max_tracked_sources = 0: rate-limit bookkeeping map is unbounded. Warning: an attacker churning source addresses can grow the map without bound in this mode — operator opt-in only.

burst > 0 is required only when paired with a positive rate. Setting rate > 0 together with burst = 0 would deny every request after the first burst-many — the resolver rejects that combination as a likely-typo. Setting rate = 0 together with any burst value is fine; burst is unused once the layer is disabled.

Fields§

§max_concurrent_handlers: Option<u32>

Maximum number of concurrently in-flight QUIC handler tasks across all deCDN-authored ALPNs. New connections beyond this limit are closed immediately with APP_ERR_RATE_LIMITED. Default: 256. 0 disables the global cap (no concurrency limit).

§per_source_rate_per_sec: Option<f64>

Refill rate for per-source rate limiting (cells per second). More generous than older per-NodeID-only schemes because a single source IP may host a legitimate fleet. Default: 100. 0.0 disables the per-source layer (the paired per_source_burst is then ignored).

The current implementation keys on the remote IpAddr. IPv6 addresses are bucketed by their /64 prefix, not the full 128-bit address. A customer-grade IPv6 allocation is typically /64 or larger, so without this prefix grouping an attacker can rotate through 2^64 distinct source addresses inside one allocation and trivially defeat the layer. IPv4 addresses are used in full.

“Per-source” rather than “per-IP” because the keying axis may extend in the future (e.g. NodeID) without renaming the field.

§per_source_burst: Option<u32>

Burst capacity for per-source limiting. Default: 200 (2× the rate, providing headroom for jitter so well-behaved peers don’t trip the limit on naturally-clumped requests). Required > 0 when per_source_rate_per_sec > 0; ignored when the layer is disabled (per_source_rate_per_sec = 0).

§max_tracked_sources: Option<usize>

Hard cap on the number of distinct sources tracked in the rate-limit state. When the live keyed map exceeds this size the limiter prunes entries whose state has refilled to a fresh baseline. Default: 4096. 0 makes the map unbounded — see the type-level docs for the operator-opt-in warning.

Trait Implementations§

Source§

impl Debug for SecurityConfig

Source§

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

Formats the value using the given formatter. Read more
Source§

impl Default for SecurityConfig

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<'de> Deserialize<'de> for SecurityConfig

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Serialize for SecurityConfig

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. 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<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> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

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> MaybeSend for T
where T: Send,

Source§

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

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<'de, T> RpcBorrow<'de> for T
where T: Deserialize<'de> + Debug + Send + Sync + Unpin,

Source§

impl<T> RpcRecv for T
where T: DeserializeOwned + Debug + Send + Sync + Unpin + 'static,

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<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

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