Skip to main content

Module ip_ban

Module ip_ban 

Source
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 ban

The 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.
IpBanConfig
The IP-banning knobs (the reference enable_ip_banning / auto_ban_threshold / auto_ban_duration / threat_ban_config group).
IpBanManager
The dynamic IP ban store over one shared in-memory map.
ResolvedBan
The ban a threshold resolution decided on: how long, under what reason, and which category crossed (none for the flat fallback).
ThreatBanEntry
One threat_ban_config entry: the violation count per category that triggers a ban, and how long the ban lasts.
ViolationCounters
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_ip refused a ban.
IpBanConfigError
An invalid IpBanConfig: the config error IpBanConfig::new fails 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 reference maxsize=10000).
LOCAL_CACHE_TTL_CAP_SECONDS
The local store’s TTL cap in seconds (LOCAL_CACHE_TTL_CAP_SECONDS in 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_config key may name: every pattern-table category plus the rate_limit pseudo-category (the reference’s ALL_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.