Skip to content

Mitigation Overview

When an IP's suspicion score reaches the effective threshold, OpenShield automatically bans it. Multiple escalation mechanisms tighten response for repeat offenders and subnet-level attacks. The Bloom filter accelerates whitelist lookups, and freplace hot-patching enables live updates to mitigation stages without reloading the XDP program.

Ban types

TypeMechanismDuration
Single-IPInserted when suspicion_score ≥ effective_thresholdban_duration * star_multiplier (default 1 hour)
LPM subnetCIDR-level via longest-prefix-match triesubnet_ban_duration (default 2 hours)
Auto /24 escalationAfter N single-IP bans per /24ban_duration * 2
Auto /64 escalationAfter N single-IP bans per /64 (IPv6)ban_duration * 2
Star (repeat)6 offense levels, multipliers ×1–×32ban_duration * star_multiplier

Ban reason codes

CodeTriggerDescription
1BAN_REASON_PPSPackets/s exceeded
2BAN_REASON_BPSBytes/s exceeded
3BAN_REASON_TCP_PPSTCP packets/s exceeded
4BAN_REASON_UDP_PPSUDP packets/s exceeded
5BAN_REASON_ICMP_PPSICMP packets/s exceeded
6BAN_REASON_SYN_PPSSYN packets/s exceeded
7BAN_REASON_NEW_SOURCENew source flood
8BAN_REASON_BOGUS_TCPBogus TCP flags
9BAN_REASON_CONN_RATEConnection rate limit
10BAN_REASON_TTL_ANOMALYTTL anomaly
11BAN_REASON_PKT_ANOMALYPacket size anomaly
12BAN_REASON_ENTROPYEntropy spoofing
13BAN_REASON_SYN_FINSYN/FIN ratio

The primary reason is determined by highest-weighted violation: SYN > ICMP > UDP > TCP > BPS > PPS.

Star system: repeat offender escalation

Six star levels with geometric duration multipliers:

Star levelban_countDuration multiplierEffective ban
0 (first)0×11 hour
11×22 hours
22×44 hours
33×88 hours
44×1616 hours
5 (max)5+×3232 hours

Star decay

Stars decay by 1 level after a configurable clean period:

star_decay_seconds = 3600 per star level

Example: A star-3 (×8) IP that stays clean for 3 × 3600 = 10,800 seconds (3 hours) decays to star-2 (×4), then continues decaying hourly. The userspace ban manager handles star decay on its 5-second poll cycle.

Panic circuit breaker

A per-CPU probabilistic drop that activates when packet rate exceeds panic_pps_rate on any CPU:

c
// Per-CPU panic bucket (PERCPU_ARRAY, no contention)
if (pb->last_second != this_sec) {
    pb->pkt_count = 0;           // Reset window
    pb->last_second = this_sec;
}
pb->pkt_count++;
if (pb->pkt_count > cfg->panic_pps_rate) {
    // Probabilistic drop at panic_drop_ratio %
    if (cfg->panic_drop_ratio >= 100 ||
        (pb->pkt_count % 100) < cfg->panic_drop_ratio) {
        return XDP_DROP;
    }
}
Config fieldDefaultDescription
panic_pps_rate200,000Per-CPU PPS trigger (0 = disabled)
panic_drop_ratio80Percentage of packets to drop in panic mode
panic_global_pps_threshold5,000,000Global PPS threshold for coordinated panic (userspace-managed)
panic_coordination_enabledtrueEnable cross-CPU panic coordination

The panic breaker runs before any per-IP checks (stage 3 in the pipeline). It acts as a last-resort bulkhead: when the CPU is overwhelmed, drop packets probabilistically rather than trying to track per-IP state (which would add overhead during overload).

Panic breaker drops indiscriminately

Panic drops are not tracked per-IP. Legitimate traffic is dropped alongside attack traffic. Use only as a fail-safe — tune per-IP rate thresholds first. Set panic_pps_rate: 0 to disable.

freplace hot-patching

Five mitigation stages support runtime replacement via BPF freplace (kernel ≥ 5.11, CONFIG_DEBUG_INFO_BTF=y):

Stagefreplace targetCan replace
Ban checkSEC("freplace/stage_ban_check")Single-IP + subnet ban logic, event emission
Rate limitSEC("freplace/stage_rate_limit")Threshold scoring or token bucket algorithm
Connection trackingSEC("freplace/stage_conn_track")Blind SYN-ACK/RST detection
UDP amplificationSEC("freplace/stage_amp_check")Amplification detection rules
L7 filterSEC("freplace/stage_l7_filter")L7 signature matching

An example ban check replacement at ebpf/modules/ban_check_freplace.c adds per-hit ringbuf event emission. To deploy a replacement:

  1. Compile with make -C ebpf/modules
  2. Attach via FreplaceManager.AttachFreplace("stage_ban_check", "path/to/ban_check.o")

The main XDP program is never unloaded — freplace swaps the subprogram pointer atomically via bpf_link.

Whitelist

Per-IP flags with granular bypass:

FlagValueEffect
WL_FULL_BYPASS0x0000Skip all checks, immediate XDP_PASS
WL_SKIP_BAN0x0001Skip ban + subnet ban lookup
WL_SKIP_RATE0x0002Skip rate threshold checks
WL_SKIP_VALIDATION0x0004Skip L3/L4 validation (private/bogon/bogus TCP)

A Bloom filter (3 hashes, 150K u64 entries, ~1% FPR) is checked before the HASH whitelist lookup. If the Bloom filter says "definitely not present", the more expensive HASH lookup is skipped entirely, saving ~60–100ns per packet.

The whitelist_empty config flag skips ALL whitelist lookups when the map has 0 entries. Updated automatically after every config change.

Empty-map fast path

When 0 whitelist entries exist, the whitelist lookup is skipped entirely. Same for bans (bans_empty flag). Updated automatically after every config change.

Ban System · Rate Limiting · Whitelist · Detection Engine