Expand description
The dynamic IP ban store and the auto-ban engine: ban_ip with a
duration, expiry-honoring is_banned, and the per-IP violation counters
with the threshold resolution both are fed by.
This is the Rust family’s in-memory port of the reference engine’s
dynamic ban layer (guard_core/handlers/ipban_handler.py and the
threshold helper core/checks/helpers.py:_resolve_and_apply_threshold_ban,
via the Go port’s ipban.go). Redis is out of scope: the store is
process-local, exactly what both references fall back to when Redis is
off, and the follow-up that adds Redis adopts the full distributed
semantics (shared bans, expiry refresh, legacy key migration).
§Bans
IpBanManager::ban_ip records an expiry (now + duration) and
IpBanManager::is_banned honors it: a lookup past the expiry returns
false and drops the entry. Mirroring the references’ local store, an
entry lives at most
LOCAL_CACHE_TTL_CAP_SECONDS (3600) seconds - the reference clamps
longer durations to the local cap when Redis is not configured
(clampToLocalCap, cause not configured) and the Python TTLCache
caps every local entry at the same TTL - so ban_ip with a longer
duration records the clamped expiry. The default auto_ban_duration
(3600) sits exactly at the cap, so default autobans are unaffected.
The store is an LRU capped at LOCAL_CACHE_MAX_SIZE (10 000) entries
(localCacheMaxSize / the reference maxsize=10000): inserting into a
full store silently evicts the least recently banned entry, the same
silent-overflow behavior the references log a warning for.
§Self-ban refusal
ban_ip refuses (Ok(false), no entry recorded) when the target
overlaps the loopback space (127.0.0.0/8, ::1/128) or a configured
trusted proxy - the references’ self-DoS guard, so a deployment can never
ban its own ingress and go dark on itself.
§The auto-ban engine
Detection violations are counted per IP per category in
ViolationCounters (the reference’s suspicious_request_counts). One
call, IpBanManager::register_violations, records the categories and
applies the reference threshold resolution
(_resolve_and_apply_threshold_ban, same shape as the TypeScript port’s
resolveThresholdBan):
banning disabled: no ban
for each category in the recorded order:
threat_ban_config[category] exists and
count[category] >= its threshold: ban (entry duration, reason:category)
total of all counted categories >=
auto_ban_threshold: ban (auto_ban_duration, reason)
otherwise: no banThe per-category entries win first (in the order the caller lists the
categories), the flat threshold is the fallback measured against the
total. The rate-limit stage feeds the same engine with the pseudo-category
rate_limit when enable_rate_limit_auto_ban is on, so
threat_ban_config["rate_limit"] overrides and the flat threshold backs
it up, exactly as the reference pipeline does.
§Example
use std::net::IpAddr;
use std::str::FromStr;
use guard_core_engine::ip_ban::{IpBanConfig, IpBanManager};
let manager = IpBanManager::new();
let attacker = IpAddr::from_str("192.0.2.9").unwrap();
assert!(manager.ban_ip(attacker, 60, "threshold_exceeded").unwrap());
assert!(manager.is_banned(attacker));
// Loopback is refused: banning it would self-DoS the deployment.
let loopback = IpAddr::from_str("127.0.0.1").unwrap();
assert!(!manager.ban_ip(loopback, 60, "mistake").unwrap());
assert!(!manager.is_banned(loopback));
manager.unban(attacker);
assert!(!manager.is_banned(attacker));Structs§
- BanRecord
- One recorded ban: when it expires and why it was issued. The reason is metadata for observability (the references persist it on the Redis side); the in-memory store only acts on the expiry.
- IpBan
Config - The IP-banning knobs (the reference
enable_ip_banning/auto_ban_threshold/auto_ban_duration/threat_ban_configgroup). - IpBan
Manager - The dynamic IP ban store over one shared in-memory map.
- Resolved
Ban - The ban a threshold resolution decided on: how long, under what reason, and which category crossed (none for the flat fallback).
- Threat
BanEntry - One
threat_ban_configentry: the violation count per category that triggers a ban, and how long the ban lasts. - Violation
Counters - Per-IP per-category violation counts: the reference’s
suspicious_request_counts, the store the auto-ban engine resolves thresholds against.
Enums§
- BanError
- Why
IpBanManager::ban_iprefused a ban. - IpBan
Config Error - An invalid
IpBanConfig: the config errorIpBanConfig::newfails closed with.
Constants§
- DEFAULT_
AUTO_ BAN_ DURATION - The flat auto-ban fallback duration in seconds (
auto_ban_duration, reference default: one hour). - DEFAULT_
AUTO_ BAN_ THRESHOLD - The flat auto-ban fallback threshold (
auto_ban_threshold, reference default). - LOCAL_
CACHE_ MAX_ SIZE - The local ban store’s entry cap (
localCacheMaxSize/ the referencemaxsize=10000). - LOCAL_
CACHE_ TTL_ CAP_ SECONDS - The local store’s TTL cap in seconds (
LOCAL_CACHE_TTL_CAP_SECONDSin both references): no in-memory ban outlives it. - MAX_
TRACKED_ SUSPICIOUS_ IPS - The violation counter store’s IP cap (
_MAX_TRACKED_SUSPICIOUS_IPS). - RATE_
LIMIT_ CATEGORY - The pseudo-category the rate-limit stage feeds the auto-ban engine under
(
enable_rate_limit_auto_ban).
Functions§
- resolve_
threshold_ ban - The reference threshold resolution against one IP’s current counts.
- valid_
threat_ categories - The detection categories a
threat_ban_configkey may name: every pattern-table category plus therate_limitpseudo-category (the reference’sALL_DETECTION_CATEGORIES | {'rate_limit'}).
Type Aliases§
- Clock
- The monotonic-ish wall clock, in seconds since the Unix epoch. Injectable so expiry behavior is testable without sleeping.