Skip to content

What's New — v2.0 to v2.22.0 ​

The feature changelog for the 2.x line. For the complete feature map see Everything OpenShield-XDP Does.

v2.22.0 — ASN policies, per-destination geo/ASN, Bedrock churn fix, lifecycle + webhook hardening ​

  • ASN policy layer (new ASN tab, key A) — global ASN whitelist/blacklist with always / attack-only enforcement, backed by a kernel source classifier (GeoLite2 ASN dataset, ~510k prefixes, loaded lazily on first policy). Socket (asn_global_*), API (POST/DELETE /control/asn), and geoip.asn_enabled opt-in — off costs nothing.
  • Per-destination geo/ASN policies — every attached IP can carry its own country/ASN block-or-allow policy plus per-destination ASN overrides, with always/attack-only enforcement. Only traffic destined to that IP sees the second layer — other tenants are untouched, and a destination allow can never rescue a global deny. Visible in the DstIP Analyzer as geo_asn_policy; managed from the ASN tab, the socket, or /control/geoasn/* and /control/asn/dst.
  • Bedrock/UDP random-block fix — during a flood, the LRU churn evicts a legit player's ip_stats entry; their next packet looked brand-new and the new-source gate temp-banned them. The new-source gate and the CT blind-ACK/RST gates now exempt protected_map members (userspace socket-truth presence) — long-lived MC Java/Bedrock/SFTP sessions survive full flood matrices (rig-proven, 100% UDP delivery).
  • Faster geo country changes — the country prefix index is built once per dataset revision and cached (memory + on-disk), jobs serialize, and country toggles apply in well under 2s. Also fixed: allow-mode installing blocking prefixes, attack-only mode leaking exact-source bans, and geo prefixes overwriting manual bans.
  • Ban map 10M default / 50M max — maps.ban_max default raised 4M→10M (validated ceiling 50M), and IPv6 sizing is now independent via maps.ban_max_v6 (pre-v2.22 a non-default ban_max silently resized the IPv6 map too).
  • Webhook reliability — every accepted attack-start now gets exactly one terminal message (false-alarm and sub-floor endings included), updates coalesce per event, terminal events are never evicted from the bounded queue, Discord Retry-After is honored, daily-report retries stay anchored to their original window, and delivery failures surface in the snapshot + /metrics/alerter (coalesced / terminal_lost / attack_end_followup_failed counters).
  • Lifecycle hardening — the loader can no longer be SIGKILLed out of a graceful stop by slow feeds/webhooks (fetcher requests are now context-cancelled; CLI stop budget 3s→5s per phase; systemd KillSignal=SIGINT + TimeoutStopSec=15s), signals register before attach, license hard-fail shuts down through the orderly path (bans persist), and attack-mode log suppression no longer hides WARN/ERROR.
  • Per-port/protocol blackholes — openshield blackhole port add <ip> <port|range> --proto tcp|udp|both [--seconds N] (plus socket + /control/blackhole/port*): drop traffic to one destination on a port or port range, temporary or permanent, alongside the whole-IP blackhole.
  • Spaceflare.org rebrand — display text moved from XDP.Network to Spaceflare.org; license/update/trust infrastructure is unchanged.
  • Installer fixes — Balanced is now the actual default profile (the wizard recommended it but pre-selected Strict), "Save & Apply" renamed to what it really does, existing configuration is preserved on reconfigure, and child-process failures propagate instead of pretending success.

Build 2 — Geo/ASN gate preservation hotfix ​

An ASN or geo rule added through the ASN tab/API appeared active (asn_db: yes) yet traffic from the listed AS kept passing: every full config rewrite (reload, license refresh, runtime config update) rebuilt the kernel config from YAML and zeroed the runtime-owned Geo/ASN presence bytes, silently disarming the stage while the UI still reported it ready. The gates are now preserved across rewrites; regression tests at both the helper and live UpdateConfig seams.

Build 3 — attack targets scoped to your networks + embed hardening ​

  • "Random subnets" in Top Targeted IPs explained: on forwarding deployments (XDP on OVH with VXLAN to colo, routed upstreams) dst_stats sees every destination crossing the wire — including other networks on the same fabric being flooded. Attack records now classify each target with a scope from the attached-IP registry (pool / manual / auto / transit), and end-of-attack alerts split the list into "Top Targeted IPs (your networks)" and "Other destinations seen (learned/transit)". Declare your allocations (openshield ips add / pool add) so the split is meaningful; with nothing declared, the legacy flat list renders unchanged.
  • Attack-update embeds can no longer render "Attack #0" or an epoch "57 years ago" next-update, regardless of upstream path.

Build 10 — Peer tab + ASN peer trust ​

  • New TUI Peer tab (key P) — the admin surface for peering trust: two sections, IP/Subnet peers and ASN peers, with add/remove, live asn-db/asn-license status hints, and the same functionality over the socket (peer_list, peer_add, peer_remove, peer_asn_add, peer_asn_remove) and the HTTP API (GET /metrics/peers, POST/DELETE /control/peers, POST/DELETE /control/peers/asn).
  • ASN peer whitelist (tunnels.asns) — every prefix of a whitelisted ASN gets the same full-bypass treatment as an explicit tunnels.peers entry: never scored, never banned, never capped. "Peering with AS64999" is now one line instead of listing hundreds of prefixes. Requires the ASN license tier and the source-ASN dataset, which builds lazily on first use — the tab shows asn-db: yes once the bypass is live. Rig-proven isolated from the exact-peer path (a source with only ASN trust survives the same flood that bans an untrusted source).

Build 9 — false-positive fixes for verified-legit sources (non-tunnel deployments) ​

The same "connections reset / latency / blacklisted for no reason" family also hit plain (non-tunnel) deployments. Two general mechanisms, both rig-verified:

  • The attack-mode per-IP hard cap (attack_per_ip_pps, default 1000, ON by default) had no protected-source exemption — during any attack declaration a verified-legit heavy source (NAT gateway, CDN peer, busy upstream) got hard-dropped, throttling every user behind it. The cap exists for rotating spoofed floods, which can never mint protected_map membership. Protected sources are now exempt, same rule as the v2.17.2 CT blind gates.
  • Restart blindness: every load/restart/update left established local TCP connections unknown to the fresh maps for up to 10s, so the CT blind-ACK/RST gates dropped their mid-transfer ACKs. The protected-set sweep now runs at startup — the socket-truth leg (/proc/net/tcp ESTABLISHED) is provable at t=0.

Kernel change shipped through the full gate: verifier checks (bpftool + all-features Go gate) plus all nine release rigs and rig-ct-evict PASS.

Build 8 — tunnels.peers: XDP stops killing your VXLAN/colo tunnel ​

The problem (rig-reproduced): with XDP on a border host that fronts encapsulated traffic (the classic "OVH bare metal + VXLAN to colocated servers" layout), every tunneled tenant aggregates onto the single tunnel peer source IP. At real rates the per-IP thresholds scored that peer and the kernel banned it — one temp ban reset every tunneled connection for the ban duration. Symptoms reported by a customer: all connections timing out/reset with XDP loaded, rising in-app latency, an upstream peer blacklisted "for no reason". NIC tuning changed nothing because the drops happen at XDP before the stack.

The fix: declare your tunnel endpoints once —

yaml
tunnels:
  peers: ["203.0.113.10"]   # your colo router / tunnel endpoint IPs or CIDRs

Peers bypass all per-IP scoring and bans (independent of whitelist.enabled, hot-applies via openshield reload or config set tunnels.peers). This is explicit trust: XDP can't see inside the encap, so per-IP outer-header checks are meaningless for a peer — you either trust it or cap the whole tunnel. On older builds the same effect is openshield whitelist add <peer-ip>.

Also fixed along the way: the kernel treats a whitelist bloom-filter miss as authoritative, and the bloom set didn't include the peers — their bypass silently died with bloom_filter_enabled on (the default). New regression rig: scripts/rig-vxlan-repro.sh proves both the aggregate ban and the fix end-to-end.

Builds 4–5 — cockpit redesign (TUI + Discord embeds) ​

  • New dashboard — status strip, attack banner, bento grid (Traffic with in-card chart, Defense with drop-path bars, Protocol + Activity with live top attacking countries and an all-countries popup).
  • Status page bento — License / Registry / Egress / Edge / Flowspec cards fill the previously empty right half.
  • Config tab readability — numbered bullets, colored values (true/false/numbers), grey descriptions, clear range column.
  • Access tab search (/) — find an IP across blacklist/whitelist and remove it in place; Geo+ASN tabs gain a policy-overview container; IPs and DstIP tabs merged into one Network tab.
  • Discord embeds: sectioned layouts, per-family colors, attack-numbered footers.

Build 6 — Flowspec shutdown + persistence fixes ​

  • Manager.Stop() no longer hangs up to 2 minutes in the initial BGP peer wait (systemd would SIGKILL at 15s); the wait is cancelled on shutdown and the first reconcile is skipped when stopping.
  • Flowspec whitelist/blacklist persistence is now crash-safe (atomic temp+rename write) and no longer silently disabled when audit_log_path is cleared.

Build 7 — deep-audit batch (14 verified defects) ​

A full six-subsystem engineering audit; every finding was verified first-hand before fixing.

  • Attack-update embeds shipped zeroed content — the queue dropped the event details for coalescible events, so the lazily built embed showed all zeros (this was the real root cause behind the build-1 "Attack #0" report; earlier hardening only masked the title). Fixed at the source, with a regression test.
  • Terminal alert accounting — attack start/end and panic alerts are now counted in terminal_lost at every drop point (requeue exhaustion, closed queue), panic alerts get the same requeue budget, and in-flight webhook HTTP honors shutdown cancellation instead of risking a SIGKILL mid-delivery. During attacks, per-IP ban embeds collapse into one 30-second digest instead of one embed per event type every 5s.
  • Runtime map-resize no longer kills telemetry — the event ring reader and XDP tracer are re-created against the new maps after a maps.* resize (previously they kept reading destroyed maps and all ring-driven events silently stopped until restart).
  • Per-destination ASN overrides actually enforce — asn_dst_add rules were dead when the destination had no country/ASN descriptor (the kernel gate byte never armed). One-line gate fix + test.
  • Pinned bans survive restarts as pinned — the ban-state file's dedup kept the LRU copy of a heavy/repeat ban, silently demoting it to the flood-evictable tier on every graceful restart. The pinned copy now wins, and bans.json is written atomically.
  • Config saves no longer delete Flowspec — SaveAnnotated never emitted the flowspec: section, so any runtime config set/whitelist persist wiped the operator's BGP Flowspec configuration (peers, passwords) from disk. The full section is now emitted, guarded by a round-trip test plus a reflection test asserting every top-level config section appears in saves.
  • Flowspec can't null-route legitimate clients — auto_mode: all pushed upstream discard rules for unbanned top-pps sources (including protected high-rate clients); auto-rules now require a live kernel ban, matching the edge syncer.
  • Edge (OVH) mitigation honors the whitelist and no longer pushes feed/auto-fetch bans to the provider; last_error clears on recovery.
  • Blocklist fetcher hardening — feed entries no longer clobber live attack/manual bans (lookup-before-write), single-IP feed lines go through the same protected-range self-DoS guard as CIDRs, and never_block now covers CIDR overlaps in both directions.
  • Updater health check is real — a build used to be declared healthy ~2s after restart, long before the license check (15s) and XDP attach could fail, so auto-rollback effectively never fired. The service must now stay active through the full license+attach window or the previous build is restored.
  • Installer — systemd always runs the full-featured openshield-loader binary (the CLI load path lacks Flowspec), and the generated config (license key, webhook URL, metrics key) is root-only from the start.
  • Smaller fixes: latent Flowspec self-deadlock on a future runtime toggle, bulk-ban jobs now respect shutdown, attack history capped at 1024 records, kernelVersion() no longer panics on an empty osrelease, socket blackhole_add rejects negative seconds.

v2.20.0 — burst-tolerant rate limiting ​

  • Burst allowance for every per-IP rate threshold (dynamic.burst_allowance_sec, default 3s) — pps, bps, tcp, udp, icmp and syn thresholds now run on window-granular token buckets instead of hard per-second windows: a threshold-sized bucket refills every second and over-threshold traffic drains it. Bursts up to N seconds of threshold are absorbed with zero suspicion — Minecraft chunk downloads, login waves, NAT'd player groups, backup/SFTP pushes — while sustained floods empty the bucket and score exactly as before. 0 restores legacy per-window scoring.
  • Per-minute burst grace (dynamic.burst_max_per_min, default 4) — bucket-empty windows only start scoring once a source passes this many empties per rolling minute, so repeat-but-occasional bursts (world downloads every few minutes) stay free too; sustained floods still accrue score every window past the grace.
  • Everything hot-applies (openshield reload, TUI, /control/config).
  • New rig: rig-burst-test (short burst absorbed → sustained banned at the allowance → legacy mode bans instantly) — the release gate is now 9 rigs.
  • "What's new" setup flow — when a release adds a config value that needs your decision, it now asks instead of silently defaulting: a prompt on interactive loads, openshield setup anytime, and the same pending list over the API (GET /metrics/setup, POST /control/setup/answer) so the xdp.network dashboard can pop the question too. Unanswered questions run their safe default and never block the firewall; answers are hot-applied and recorded on the box.
  • openshield autoload — keep the firewall running, always: boot start via the loader service, a 30s watchdog that restarts the loader when the process dies or XDP detaches while the loader lives (a bare NIC alone never trips systemd's Restart), and a config-change fuse — any edit to openshield.yaml (manual or live) disarms autoload automatically so a bad config can never restart-loop your box. Re-arm after review with openshield autoload.
  • Access search — openshield whitelist check <ip> / openshield blacklist check <ip> answer "is this IP listed, where, and why" instantly (whitelist, pinned/LRU bans with reason + expiry, subnet bans incl. geo). TUI Access tab: / filters the list live by IP or note.
  • Human-readable ban reasons — blacklist list now prints auto_fetch, ttl_anomaly, conn_rate_exceeded, … instead of raw codes.
  • openshield stats waits for the loader — up to 90s with a live countdown instead of an instant "cannot connect" while the loader is still starting or restarting.
  • RHEL/Alma fixes (from 2.19.3 respins): install continues with a warning on RHEL 9-family 5.14 kernels, and the CLI now links into /usr/sbin so openshield is found in sudo-entered root shells.

v2.19.3 — CONTAINED state, analyzer blackhole popup, safer NIC tuning ​

  • CONTAINED badge — attack state is arrival-based by design (banned sources still blasting the NIC keep attack time accruing), but a red UNDER ATTACK banner while every packet is being dropped reads as a false alarm. When an attack is active and ≥85% of arriving traffic is being dropped (EMA-smoothed), the TUI shows an amber [~~] CONTAINED badge instead — flood still arriving, fully mitigated. The classifier, caps, attack records and webhook reports are untouched. API: snapshot.attack.contained.
  • DstIP Analyzer: blackhole popup (key b) — blackhole the analyzed destination right from the analyzer: Permanent / 5m / 10m / 1h / 6h / Custom (single-unit 30s–30d or compounds like 1h30m). The Status panel now also shows the blackhole's remaining time (blackhole_remaining_sec in the API; -1 = indefinite).
  • NIC tuning split into safe vs hardware tiers — queue-count (ethtool -L) and ring-buffer (ethtool -G) changes fully reset the NIC and can hang some driver/firmware combos hard enough to need IPMI. They now sit behind dynamic.nic_tuning_hardware (default off) and the wizard offers them only via a separate, explicitly-warned confirm. The safe tier (coalescing, IRQ spread, qdisc, txqueuelen, LRO) never resets the device.
  • RHEL-family polish: the CLI now also links into /usr/sbin, so openshield is found even in root shells entered via sudo su (sudo's secure_path on RHEL/Alma excludes /usr/local/bin).
  • Analyzer long ranges (from 2.19.2): /metrics/dstip?ip=&range=1h|24h answers from a box-side minute-resolution history — 24h of per-tenant history at ~12 MB RAM, no external storage.

v2.19.0 — per-port connection caps, geo enforce modes, DstIP Analyzer ​

  • Per-port new-connection cap (dynamic.port_syn_pps) — the existing per-IP connection limit now has its per-PORT twin: cap new TCP connections/sec per destination port (always-on, CAS-windowed, fail-open, same exemptions as the port cap). One flooded service port stops eating the box's connection budget while every other port runs untouched.
  • Geo enforce mode (geoip.enforce_mode) — always keeps classic geo-blocking; attack enforces your country list only while an attack is declared. For hosts with legitimate users in high-risk regions you only cut off during a flood. Hot-applies, no reload.
  • New TUI tab: DstIP Analyzer (key I) — enter any destination IP and watch it live: current pps/bps/drops, 1m/5m/15m peak+avg windows, a pps+drops chart, and that IP's attack history with targeted/global verdicts and an ongoing-attack badge. Built for dedi operators watching tenant IPs. Note: per-destination drop figures are estimated from the destination's share of inbound traffic (exact for targeted floods, proportional for spread ones).
  • API: GET /metrics/dstips (tracked destinations overview) and GET /metrics/dstip?ip=<addr> (the full analysis payload the Analyzer shows). Both new config knobs are runtime-safe — settable via /control/config and openshield reload, documented in the API reference.
  • Fix: dynamic.new_source_limit: 0 (feature off) was briefly rejected by validation in 2.18.1 — accepted again (0 = off, house convention).

v2.18.1 — adversarial-audit hardening: the bans that always enforce ​

A full-tree adversarial audit (11 auditors, every finding cross-verified against the code before fixing — two rejected as wrong/overstated).

  • Manual bans always enforce. On a fresh install the kernel's ban fast-path (bans_empty) was only cleared by feed/geo bans — a manual blacklist entry silently did nothing while the CLI reported success. Every userspace insert now clears it, and the ban sweep self-heals.
  • Failed map-resize can no longer leave you bare. A live map resize that failed used to unpins everything, error quietly, and report success with nothing attached. It now restores the previous sizes and reports the failure honestly.
  • The rotating-flood cap actually caps. attack_per_ip_pps sat behind a 1-in-256 sampling gate, evaluating ~0.3% of a flood; sources sending under 256 packets per window were never capped. The cap now evaluates the live per-window count for every packet.
  • SYNPROXY correctness: payload-carrying final handshake ACKs now validate (some clients were deadlocked), and IPv6 events carry real addresses instead of 0.0.0.0.
  • IPv6 hardening: ICMPv6 (NDP) is no longer dropped by the private-range filter, extension-header chains beyond 4 headers are handled or rejected instead of evading every L4 check, and the v6 bogon list covers the documentation + v4-compat ranges.
  • Established-mark exemption gets a 60s freshness bound — the peacetime scoring exemption can no longer be held forever by two crafted packets (documented v2.17.2 residual, now bounded).
  • Rate-cap engine races closed: per-port cap rollover is CAS-elected (no more all-core spinlock on a flooded port), protocol-cap rollover is single-winner, and the first packet on a new port is evaluated.
  • TC egress safety: clsact is only removed when truly empty (foreign filters are safe), orphaned filters on renamed interfaces are cleaned, and debug logs print the right address.
  • Operator-facing: CIDRs can be added from the TUI Access tab (was 100% broken), /metrics/access and the TUI say when lists are capped, credentials are masked in the config tab, and /metrics answers fast even after million-ban mitigations (build 3).
  • Housekeeping: dead code and dead config keys removed, edge sync covers IPv6, socket-truth scans halved, bulk-ban note writes are batched, baseline imports fully validated, rigs run clean on fresh CI machines, and release builds pin their BPF feature set instead of trusting the build host's kernel.

v2.18.0 — hot reload over HTTP, synproxy self-probe, TC egress (opt-in) ​

  • Hot reload is now an API call. POST /control/reload on the metrics endpoint re-reads /etc/openshield/openshield.yaml, validates it, and applies every runtime-safe setting (123 fields today) through the same path as openshield reload — no restart, no re-attach, dashboards can drive it. The response reports how many settings were applied. Read-only fields (interface, map sizes) still require a real reload, as before. Off unless metrics.control_enabled: true, same as the rest of the control API.
  • SYNPROXY probes itself at load. On kernels where XDP_TX delivery is broken (observed on 7.0-RC: cookie replies silently vanish — a total TCP blackout with synproxy on), the loader now attaches the live program to a throwaway veth pair and demands a real cookie SYN-ACK within 400 ms. If the probe fails, synproxy is force-disabled for that session with a loud error instead of blackholing your TCP. No config needed; healthy kernels see zero behavior change.
  • TC egress per-IP protection (opt-in, egress: config). The XDP firewall is RX-only by design; v2.18 adds its outbound twin: a small, separate BPF policer on the interface's clsact egress hook that caps OUTBOUND packets/sec and bytes/sec per SOURCE IP (plus optional UDP / ICMP / SYN sub-caps and exemption list). On a dedicated host it stops one compromised tenant VM from flooding out and getting the whole box null-routed; on a single VPS it blunts amplification participation. Off by default; every knob hot-applies at runtime; enabling runs an outbound connectivity self-check through the very hook it attached and force-disables itself if it would break connectivity. Never touches foreign qdiscs/filters, and crash leftovers clean themselves up. openshield egress status, GET /metrics/egress, and a four-scenario rig (inert under cap / cap enforcement / per-IP isolation / exemption) back it.
  • Release discipline: customer zips are now mechanically gated on the live rigs (flood matrix, blackhole, interference, hot-reload, egress) passing on the exact tree being packaged, and every release is dogfooded through openshield update on our own field boxes before we call it shipped.

v2.17.4 — audit follow-up fixes ​

A regression-hunt pass over the v2.17.2/2.17.3 changes; every item confirmed before fixing.

  • Fragmented UDP packets were dropped at parse (large DNSSEC/NFS/game datagrams, with drop_fragments off) — a v2.17.2 regression, fixed.
  • The per-port cap's overflow backstop now actually exists (loader pre-creates it); the carpet-bomb disarm is closed for real.
  • Auto-update no longer retry-loops a failing build (persisted latch; each attempt used to restart the firewall twice every 90s), survives systemd-less environments, and can't corrupt itself when two updates run at once.
  • Blackhole exemptions now see tenant VMs/containers — proof comes from the conntrack table too, not just the host's own socket table.
  • Plus: tail-fragment validation, blacklist-clear vs bulk-ban race, notes pruning, big-endian hosts, and a protected-set expiry edge right after boot.

v2.17.3 — realistic preset values + blend fix ​

Field-reported: a game-hosting wizard run (Minecraft + game server + Docker + download server, Gaming/Balanced) produced ceilings no legit client could ever reach — 560 SYN/s per IP, 3500 new connections/s per IP, a 10k pps attack floor.

  • Attack-surface knobs no longer blend by maximum. Rate ceilings merge by union (a mixed box must fit every workload's legit traffic — correct), but the same rule also governed the knobs whose height is the attack surface: per-IP SYN/connection limits, new-source limit, attack-declaration floors, attack per-IP cap, panic breaker. One 0.5-weighted "download server" vote pulled all of them to CDN-edge levels on a game box. They now blend by weighted average, so the dominant workload sets the box's character.
  • Per-IP bases retuned to measured reality across all categories: SYN 150–250 (was up to 500), per-IP PPS 800–2500 (Gaming 2000), UDP 350–1800, conn-rate ~2× SYN, ICMP ≤100.
  • Example: the reported selection now generates SYN 170/IP (was 560), conn-rate 450 (was 3500), attack floor 5.1k pps (was 10k), attack per-IP cap 1466 (was 3000).

Note: existing installs keep their saved config — the retune applies to new wizard runs / profile applications.

v2.17.2 — deep-audit hardening release ​

A multi-area audit (packet parse, maps/races, limiters, daemon, config/presets, lifecycle, security); every finding was code-traced or rig-reproduced before fixing.

  • Packet payload accounting now trusts the IP layer, not the frame — last-hop NIC padding and L2 trailers no longer count as TCP/UDP payload. Closes the empty-ACK established-mark mint on physical NICs, a SYNPROXY cookie-gate skip for the canonical flood SYN shape, and L7 evasion via forged UDP lengths.
  • Exemption sets anchor on real socket state (/proc/net/tcp) — the kernel's established mark was mintable in two crafted packets (rig-proven); protected sources and blackhole exemptions now require a real connection in the host's socket table.
  • Early-spike baselines clamp learning to 2×/window (ramp poisoning killed); the per-port cap can no longer be disarmed by port-spray squatting; legit fragmented TCP no longer dies as bogus-null-flags; v4-mapped IPv6 bogons actually filtered.
  • Auto-update works under systemd now — it runs as a detached process (the in-daemon path was dead on arrival and self-killed its own rollback).
  • Runtime config edits can no longer clobber hand edits, persist license-gutted values, force a full map rebuild on every reload, or brick the next start; runtime bloom enable actually works; clear-blacklist clears the pinned (manual) tier; registry stops per-second disk writes; star decay reaches the kernel repeat-offender ladder.
  • uninstall fully detaches (and only ours); install --update backs up + health-checks; tcpdump orphans reaped; state/logs no longer world-readable; API keys/webhook URLs redacted from logs; feed CIDR injection guards (no 0.0.0.0/0 self-DoS); unload works with a broken config.

v2.17.1 — peacetime fairness: "games fine, websites dead" fix ​

Field report: on a box hosting both games and websites, websites stopped loading for new visitors while existing players kept playing; unloading the firewall cured it. Two kernel-side causes, both found and rig-proven:

  • New-source temp-bans no longer fire in peacetime. The rotating-source flood defense used to temp-ban any source arriving while >100 new IPs/s were showing up — with no attack required. A busy website draws that organically, so real visitors ate 30-second bans while established players (never "new") were untouched. The ban now engages only after an attack declaration, or on an extreme spike (>8× the limit — rotating spoofed floods run orders of magnitude hotter than popularity). Verified on the rig: a 60-new-IPs/s visitor surge gets zero bans; a 100k+/s rotating flood still triggers ~1M bans.
  • Idle legit connections survive flow-table churn. The per-flow table is an LRU; on a busy server it recycles, and a recycled connection's next packet after an idle stretch (HTTP keep-alive, game lobbies) looked "blind" to connection tracking and was dropped. The per-source established mark (only mintable by real payload after an observed handshake) now extends that freshness window to 5 minutes. Blind ACK/RST floods can't mint the mark and still drop. Verified: an established connection lives through 1.5M churn inserts plus an idle past the CT timeout.

Both fixes are in the packet path; no config changes needed.

v2.17.0 — attached-IP registry & per-tenant blackhole ​

Built for dedicated hosts carrying many tenant VPSes.

  • Attached IPs — the firewall now learns which destination IPs are yours: wire-observed destinations auto-attach (with noise filtered out), local interface addresses are swept in, and you can add single IPs or whole subnet pools by hand. Every entry carries a last-seen timestamp; auto-detected entries idle for registry.inactive_days (default 14) clean themselves out. Browse and manage from openshield ips or the TUI's new IPs tab. Attaching never changes how traffic is handled — it's knowledge, not policy. See Attached IPs.
  • Blackhole — drop everything destined to one tenant IP at the earliest point in the pipeline, until you say otherwise or a timer runs out. Established players (real TCP handshakes) keep playing; they get a 10-minute grace window when they disconnect, and they still face every other check — exemption is from the blackhole only. Your whitelist is evaluated first, so you never lock yourself out. openshield blackhole add/remove/list, or toggle per IP in the TUI. See Blackhole.
  • Auto-blackhole (opt-in) — set a per-IP pps/bps magnitude and the firewall blackholes an attached IP that crosses it, extends while the attack persists, and lifts when it's over. Registry-gated so it can never touch an address you don't manage; every engage/lift posts an alert with the numbers.
  • New metrics for all of it: attached counts by origin, reaped total, active blackholes with remaining time, blackhole-dropped packets, live exemption count, auto-blackhole events.
  • Junk "attack" alerts are gone — an event that ends with zero bans and ~zero dropped traffic was a legitimate surge, not an attack: it no longer pages the attack-ended webhook (or lands in history) at all; its rate is fed to the baseline learner silently, so it won't even declare next time. The end embed also no longer glues a "mitigation" label onto no-ban endings, no longer shows an empty Forensics field, and renders sub-second durations as "<1s".
  • Under the hood: config fields can no longer drift between the YAML writer, the TUI metadata and the docs (CI-enforced), a C↔Go struct-layout gate guards the kernel/userspace ABI, and the updater understands same-version hotfix builds.

v2.16.3 — carpet-bomb floods answered, protection that holds under churn ​

Found by our 23-class automated flood matrix (every flood class run against live simulated players); every fix verified on the rig before shipping.

  • Carpet-bomb floods can no longer rotate past the caps — a flood that spreads across thousands of destination ports defeated every per-port defense. New aggregate per-protocol caps close it: dynamic.attack_udp_pps (default 100k/s) watches UDP as a whole, and both it and dynamic.attack_icmp_pps now engage on attack state or on an early spike over 8× the learned normal rate for that protocol — inside the first window of the burst. Protected (known-good) sources are exempt, as always.
  • Short ICMP bursts no longer outrun mitigation — the aggregate ICMP cap previously waited for the userspace attack declaration; it now has the same kernel-side early trigger, so seconds-long rotating ICMP floods are capped immediately.
  • Legit clients stay protected for the whole fight — the known-good source set now freezes during any engagement: existing members keep their proof fresh, new admits need an established TCP connection, and nothing expires until 90 seconds of sustained peace. Mid-flood map churn can no longer evict your real players, and flood sources can't mint themselves "protected" status mid-attack.
  • Testing infrastructure: the flood matrix (23 attack classes including every common amplification shape and game-shaped floods) now asserts that Minecraft Java/Bedrock, CS2 and SFTP traffic profiles survive every single class.
  • Auto-update fixed for single-activation licenses — the update download gate re-validated your key under a synthetic identity, which needed a spare activation seat; keys with exactly one seat were refused with invalid license. The updater now presents the machine identity it already owns.

v2.16.1 — blacklist action un-gated from forensics ​

  • Fixed: on a server with forensics collection off (or halted by the disk guard), the attacks-tab blacklist action had no ips_involved.txt to read and failed with a bare stat error — zero IPs banned. The involved-IP list is now written at every attack end regardless of the forensics gate, and the block-pattern action tells you plainly when an attack has no fingerprint (payload patterns need pcap data).

v2.16.0 — auto-updates, burst-proofing, disk guardrails ​

  • Signed auto-update channel — openshield update downloads and installs the latest release for you; licensed installs can also update unattended (updates.auto, default on). The release metadata is Ed25519-signed by the license server, the download is license-gated and short-lived, the zip is hash-verified before anything is touched, and the previous version is restored automatically if the new one fails to start. An update badge in the TUI top bar tells you when a newer release exists.
  • Jumbo-packet floods can no longer sneak under the pps cap — the per-port cap and its early spike trigger now watch bytes too (dynamic.attack_port_bps), so a slow-pps flood of 1400-byte packets is throttled just the same.
  • Rotating ICMP floods answered — new attack-mode aggregate ICMP cap (dynamic.attack_icmp_pps, default 1000/s) while an attack is declared. Normal ping/PMTUD traffic is tens per second and unaffected.
  • Your SSH session survives the flood — dynamic.port_cap_exempt_ports (default [22]) keeps management ports out of the per-port cap forever, even when the flood aims at them.
  • Players are protected from the first packet of a burst — the firewall now maintains its known-good source set continuously instead of snapshotting at attack start (the snapshot provably arrived after flood churn had erased the evidence). Real clients on capped ports no longer share the throttled pool at all.
  • It learns from its false alarms — an "attack" that ends with zero bans and zero dropped packets was a legitimate surge; the baseline now gets a bounded credit to learn that rate instead of re-alerting the same busy hour every day.
  • The firewall can never fill your disk again — forensics are capped at 15% of the hosting filesystem regardless of the configured limit, and collection halts outright under 512MB free (resumes when space returns).
  • 4GB-tuned defaults — minimum recommended RAM moves from 2GB to 4GB; default ban map 4M entries, per-IP stats 262k, whitelist 50k. The installer warns on smaller hosts and tells you what to trim.
  • CI now runs a live flood regression on every push: the firewall is loaded on a virtual link and must stop real floods while simulated players survive.

v2.15.2 — learned detection can be switched off ​

  • New dynamic.baseline_enabled master switch (default on, applies live — no reload). Turn it off and every learned detection layer goes quiet: baseline learning, seasonal thresholds, the changepoint onset detector and behavior clustering. Attacks then declare purely on your static numbers — attack_min_pps/attack_min_bps, or the explicit attack_pps_threshold/attack_bps_threshold overrides when set. Per-IP rate limiting, suspicion scoring, bans and the attack-mode caps are static mechanisms and keep working unchanged. For servers with spiky-but-legitimate traffic that prefer fixed thresholds.

v2.15.1 — burst-flood bypass fix ​

  • Short distributed floods can no longer outrun mitigation. Every aggregate defense (the per-port cap, per-IP attack cap) used to wait for the userspace attack declaration — a burst of a few seconds could end before it arrived. The per-port cap now also engages on a kernel-side early spike trigger: a destination port running over your attack_port_pps cap and over 8× its own learned normal rate is throttled immediately — inside the first window of the burst — while players with established connections stay exempt as before. The learned baseline only updates from calm windows, so the flood itself can't train it upward mid-attack.
  • Attack-type labels are re-verified at attack end against the aggregate protocol mix — a fast first-second guess can no longer leave an ACK_FLOOD label on what became a UDP flood (or MIXED on a single-protocol flood).
  • Fixed Family: <nil> appearing in alert embeds when no fingerprint family was identified.

v2.15.0 — self-managing SYN cookies, richer attack reports ​

  • SYNPROXY companion rules, managed for you (opt-in) — the installer now offers to auto-manage the 3 netfilter rules the SYN-cookie mode needs: it verifies iptables is present (offers to install it), then live-probes the rules on your interface before you commit — if your server can't do it, you see the exact reason and choose to skip or stop. At runtime the rules appear when an attack engages the cookie path and are removed when it clears; only OpenShield's own tagged rules are ever touched. Enable via installer or dynamic.synproxy_companion_auto.
  • Attack-end alerts, now in two focused messages — message 1 stays the operational summary (timeline, mitigation, traffic table, graph, forensics bundle). The new message 2, "Sources & Targets", shows which of your IPs were attacked (broadcast-looking .255/.0 entries filtered out), the targeted ports (mix when many), top attacking countries, and the offender list as a .txt grouped by ban reason.
  • Honest attachments — an embed only ever says "attached as .txt" when the file really is attached; if it can't be, the top rows are inlined instead. Applies to both attack-end and ban-batch alerts. Also fixed: attack-end alerts could silently omit the country breakdown — they now say when GeoIP is off.
  • Ban reasons with teeth — banned-source events now carry the actual kernel ban reason (pps_exceeded, syn_pps_exceeded, …), which is what powers the reason-grouped offender list above.
  • Daily/weekly/monthly reports redesigned — a headline summary up top, the period's top 5 attacks (peak rate × type × duration), a mitigation breakdown showing which protection paths dropped what, SYN-cookie challenge/validation stats, a period-over-period attack delta, and attacker/user country lists that never overflow Discord's limits.
  • Optional anonymized attack fingerprints (default OFF; the installer asks once) — after an attack you can share its shape (type, rates, duration, port classes, source count — never a single IP) to help improve the detection patterns everyone auto-fetches. telemetry.attack_share.
  • xdp_mode: offload now fails with a clear explanation instead of an obscure driver error (no NIC can offload this program — use native or auto).
  • Hot-patchable stage modules (freplace) are correctly wired to the split pipeline stages.
  • Full CI gating on every push: build, format/vet, the entire test suite, both kernel-verifier gates, and release-package smoke tests.

v2.14.0 — SYN cookies, IPv6 parity, pinned bans ​

  • XDP SYN cookies (dynamic.synproxy_mode: off / adaptive / always) — during SYN floods the firewall answers SYNs itself with cookie challenges; spoofed floods never reach your services while real clients connect normally. adaptive engages only above synproxy_threshold or during an active attack, so peacetime handshakes are never touched. One-time setup note: the loader prints the two sysctl/iptables companion lines if your kernel needs them.
  • Faster, future-proof engine layout — the packet pipeline now runs as chained stages, which removes the "program too large" class of load failures on stricter kernels for good and leaves headroom for more detections.
  • IPv6 parity — connection tracking, per-target traffic stats, and the API-endpoint guard now work on IPv6 the same as IPv4. Also fixes a bug where manually added IPv6 whitelist/ban entries could silently not match.
  • Pinned bans — manual blacklist entries and heavy repeat-offender bans now live in a dedicated tier that flood churn can never evict; the TUI bans tab marks them with a PIN tag.
  • UDP response-window watch (on by default) — sustained spoofed-looking "responses" from service ports (DNS/NTP-style amplification) lose their fast-pass exemption and get scored like any other attacker. Verified zero false positives on real DNS/NTP traffic.
  • Per-port rate caps no longer undercount under multi-core floods.
  • Five new auto-fetch L7 signatures (WS-Discovery, STUN, CoAP, mDNS, NTP mode-6) — 10 curated reflection-flood patterns total.
  • Attack forensics: SYN fingerprint lines now include the sender's stack class (Linux-like / Windows-like / network-device), and suppressed junk attacks can no longer reappear in history ("duplicate attacks" fix).
  • Edge mitigation: new edge: config section (your existing ovh: config keeps working unchanged); every selected IP now gets its edge firewall enabled, not just the first.
  • Reliability: openshield reload no longer overwrites hand-edited config or times out on unchanged map sizes; Ctrl+C during the load prompts no longer leaves the firewall half-attached; openshield unload fails loudly instead of orphaning a running loader; license re-checks can no longer leave the interface unprotected after a transient failure.
  • Optional per-customer watermarking on release packages, and scripts/bench.sh for one-command performance runs.

v2.13.1 — license enforcement hardening ​

  • The license check's feature switch now lives inside the loaded firewall program itself (frozen at load) instead of a settings area that admin-level tools could edit — tampering with it no longer has any effect.
  • Shipped program package no longer carries source-level debug info.
  • License tier changes apply live with zero protection gap and no loss of learned state.

v2.13.6 — live visibility + L7 pattern feeds ​

  • Top bar shows the version; Packets panel adds the current interval's pass/drop %; Mitigation panel adds "IPs live: X pass / Y blocked". New /metrics fields: live_pass_rate, live_drop_rate, live_ips_passed, live_ips_blocked.
  • Auto-fetch L7 attack patterns (opt-in: auto_fetch.patterns_enabled + pattern_urls) — curated reflection-flood signatures (DNS amp, NTP monlist, SSDP, CLDAP, memcached-UDP) load into free L7 slots and update on the fetch interval. Chosen to never fire on game/enterprise/CDN/bulk traffic.

v2.13.5 — live map sizing ​

  • maps.ban_max, maps.ip_stats_max, maps.whitelist_max are now real, live settings (TUI config tab / control API). Changes apply immediately with a state-preserving reload — active bans survive the resize.

v2.13.4 — self-healing config values ​

  • A config value written by an older version could fail validation and block every openshield reload permanently. Config load now repairs out-of-range values automatically and persists the fix on the next save.

v2.13.3 — bans tab upgrade ​

  • Search (/) by IP or ban reason, row scrolling (j/k/arrows, g/G), and instant unban — select a row, press u, confirm.

v2.13.2 — older-kernel compatibility fix ​

  • Fixes an install failure on kernels before 6.9 ("BPF program is too large"): the newest analysis features are intensive for older kernel verifiers, so the release now ships two program builds — full on 6.9+, a lighter (fully protection-equivalent) build on 5.15–6.8 — and picks automatically at load.

v2.13.1 — license enforcement hardening ​

  • One-click network optimization in the installer, detection-first — it probes your NIC and only applies what's missing: queue count matched to your vCPUs, larger RX/TX ring buffers for flood bursts, IRQ spread (skipped when irqbalance manages it), txqueuelen, fq_codel queueing, LRO off. You see the exact change list before saying yes.
  • Safe on every host type — unsupported items are skipped per-item, so VPSes (virtio), dedicated boxes, and multi-tenant hosts all get exactly what their hardware supports and nothing breaks.
  • New doctor check reports pending optimizations; the TUI nic_tuning toggle applies the same smart set.

v2.12.1 — false-attack flapping fix ​

  • Quiet servers no longer flap — the new changepoint detector could declare attacks below your configured attack_min_pps/attack_min_bps floors, producing hundreds of 1-2s phantom attacks a day on low-traffic boxes. It now respects the floors.
  • Junk-record guard — an "attack" whose traffic never crossed your own floors is suppressed entirely (no history entry, no webhook, no forensics) and counted in the log. Detector noise can never spam your attack history again.

v2.12.0 — connection-state tracking, season-aware detection, per-tenant visibility 🆕 ​

Kernel & protection:

  • Connection-state tracking — the firewall now follows every connection individually: replies to your own outbound connections (apt, curl, updates) are recognized precisely instead of heuristically, and blind ACK/RST floods are judged against the actual state of each connection. No configuration needed.
  • Flood-proof offender records — repeat offenders can no longer wash out their history during a flood; ban history lives in flood-proof storage, so the escalating 1-day / 7-day tiers engage reliably even against million-source rotating floods.
  • Small-packet floods now escalate to long bans — the heavy-evidence bar was unreachable for 64-byte-packet floods; extreme packet rate alone now qualifies for the escalating ban tiers.
  • Established connections during attacks — peacetime behavior is unchanged (proven connections are never banned); while an attack is actively declared, a once-connected source pushing flood-grade rates now accrues suspicion gradually instead of being fully exempt.
  • Rotating-source floods without slowdown — per-source counting is now lock-free, so million-source rotating floods are handled with no core slowdown.

Detection intelligence:

  • Poison-resistant baselines — the 30-day baseline history is now merged with robust statistics (median + deviation), so a slow multi-day traffic ramp can't train the baseline upward. Tunable via dynamic.baseline_mad_k (default 3.5). Baseline guide
  • Season-aware thresholds — the firewall learns your hour-of-day pattern and automatically relaxes the trigger band during predictably busy hours. Needs ~7 days to warm up per hour, and only ever relaxes — never tightens.
  • Faster attack onset — a changepoint detector declares sharp onsets 1–2 seconds earlier than the spike trigger alone.
  • Smarter attack classification — spoof-distribution, FIN-heavy, payload-shape (randomized vs structured) and port-share hints now refine the attack subtype in reports and forensics; forensics bundles show per-source TCP stack consistency.
  • Per-tenant visibility on dedicated hosts — every hosted IP gets a normal / elevated / under_attack state in the TUI targets panel, attack reports, and GET /metrics/targets. Auto-detected: activates only on multi-IP dedicated hosts — single-IP VPS installs are never treated as dedicated. New knob tenant.mode (auto / on / off). Metrics API

Ops:

  • Ban-storage pressure protection — if ban storage approaches full, OpenShield warns you (dashboard + webhook), reaps expired entries immediately, and as a last resort reclaims blocklist-feed entries (they re-fetch automatically). Attack-driven bans are never pressure-deleted.
  • openshield doctor — one-command environment health check: kernel, BTF, XDP attach, NIC driver, config, forensics disk, and license. --json output for support tickets. CLI reference
  • Generic JSON webhook — set alerter.generic_webhook_url and every event also posts a JSON envelope ({product, version, event, host, timestamp, data}) to your endpoint — same pacing and rate-limit handling as Discord; embeds and attachments stay Discord-only. Alerter docs

v2.11.0 — OVH edge-mitigation module ​

  • Drop attacks at OVH's edge — optional module (installer opt-in, marked NEW): banned attacker IPs are pushed to OVH's network firewall (VAC) so flood traffic never reaches your NIC.
  • Guided setup — API region → app credentials → one browser authorization → service auto-detection (the service routing this machine's main IPv4 is pre-marked) → pick the service's IPs to protect. Back navigation on every step.
  • Two push modes — confirmed (verified-heavy / repeat offenders only, near-zero false positives) or all (every detected attacker). Blocklist-feed bans are never pushed.
  • OVH limits respected — 20 rule slots per IP (worst offenders first), token-bucket API pacing with 429 backoff, all configurable. Runtime toggle in live settings; status on GET /metrics/ovh.

v2.10.0 — forensics disk guard ​

  • Custom forensics directory (forensics.dir) and a disk cap (forensics.max_size_mb, default 30 GB) with automatic oldest-first cleanup of completed attack bundles (cleanup_percent, default 50) — whole bundles only, never half a forensics dir.
  • Disk-pressure halt/resume — if a live capture alone exceeds the cap, collection pauses (pcap stops, future attacks skip forensics) and auto-resumes when space recovers. A manual forensics.collect: false is never overridden; the toggle is in live settings (TUI config tab / control API) and persisted.
  • GET /metrics/forensics — dir, size vs cap, collecting/halted state, cleanup counters.

v2.9.1 — target-list hygiene ​

  • Multicast/broadcast destinations no longer appear in Top Targeted IPs / /metrics/targets.

v2.9.0 — targeted-IP visibility ​

  • Which VPS IP is being attacked — per-destination-IP counters at wire speed; the TUI dashboard gets a Top Targeted IPs panel (live pps/bps/share), attack-end webhook reports get a Top Targeted IPs field, and the metrics API gains GET /metrics/targets. Built for dedicated hosts with routed/bridged VMs. Deployment models

v2.8.3 — audit hardening pass ​

  • Security: TCP doff<5 rejected (a doff=0 ACK could mint the established-connection mark without a real session); null-flag and Xmas scans now actually reach the flag validator; baseline anchor u64 wrap on busy links fixed; blind RSTs enforce the freshness window; API guard no longer drops multi-MSS request bodies or locks out IPv6 in allowlist-only mode.
  • Correctness: IPv6 amp check honors extension headers; L7 runtime-promoted rules (slots 1-15) were silently inert; TUI ban countdown clock-domain mix; fetcher apply errors swallowed; config-reload RMW race; panic recovery reverting runtime edits; spike_recovery_time/baseline_update_interval validation (flap/panic paths).
  • Performance: ban sweep loses ~400k syscalls/5s on feed-loaded hosts; bounded top-N map iterators; rate-limited new-source events with an exact kernel counter; async capped attacks.json persistence; no snapshot marshal with zero clients.

v2.8.2 — new-source metric fix ​

  • New Src/s was stuck at 0 — the userspace reader queried the single-entry new-source map with a per-CPU slice lookup, which always failed silently. The kernel now keeps a monotonic total alongside the 1s windowed count; the displayed rate is exact at any poll interval. The new-source temp-ban rule itself was verified firing live (400–540k new src/s during a rotating-spoof flood).

v2.8.1 — repeat-offender hardening, all-port coverage ​

  • Repeat-offender hardening — bans backed by verified heavy evidence (both PPS and BPS ≥ 3× threshold, no established TCP session) accrue a separate heavy-hit count: 2nd verified heavy ban = 1 day, 3rd+ = 7 days (static.repeat_ban_duration_2/3). Bulk transfers can never collect heavy marks; borderline crossers keep the normal ladder.
  • All-port protection — ct_server_port_max default 65535: services on high ports (>30000) are fully covered; outbound connections (apt/curl) still work via the SYN-ACK bootstrap.
  • Scoring determinism fix — an odd bpf_ktime low bit was decoded as a spurious window reset on ~half of all packets; sampling and scoring are now exact.
  • Heavy-evidence measurement fix — fast floods banned on 256-packet samples now have their true arrival rate extrapolated, so hardening actually engages on real floods.
  • Port-cap starvation fix — attack-capped sources accrue suspicion before the cap drop (previously throttled forever, never banned).
  • Ban-expiry clock fix — bans on hosts that suspend (laptops, suspended/migrated VMs) were reaped as instantly-expired; userspace now reads the same CLOCK_MONOTONIC as the kernel.

v2.8.0 — smarter classification, XDP trace, API guard, fixed TUI chrome ​

  • Multi-signal classifier — new types (ACK_FLOOD, SYNACK_REFLECTION, FRAG_FLOOD, CARPET_BOMB, PORT_SCAN), UDP_AMPLIFICATION revived with subtypes (dns/ntp/ssdp/…), driven by new kernel counters (TCP flags, fragments, 12-slot reflector source-port histogram). Research-backed rules (FastNetMon, CICDDoS2019, Kitsune).
  • XDP decision trace — every attack's forensics dir now has xdp-trace.log: each verdict with ns-accurate timestamps, sampled 1/64 per CPU, zero peacetime cost.
  • API port guard — basic L7 for the metrics/control port: TCP-only + HTTP-method payloads + its own allowlist (metrics.whitelist), synced live.
  • TUI fixed chrome — status/nav pinned top, keybind footer pinned bottom, every screen scrolls in a bounded viewport with scrollbars.
  • Behavior engine: port fan-out scan detection. Baseline: anomalous days auto-flagged. Whitelisted bulk traffic no longer declares attacks.

v2.7.0 — full management API + player protection hardened ​

  • Management API — new read endpoints (/metrics/baseline, /metrics/geo, /metrics/alerter, /metrics/autofetch, /metrics/access, /metrics/schedule) and a control_enabled-gated control API: config get/set, whitelist/blacklist, geo toggle, baseline export/import/delete-day, autofetch, schedule, block-pattern, attack bulk-ban jobs. Everything the TUI does, over HTTP. API reference
  • Player protection, flood-tested — the protected-source snapshot now fills in ~0.5s via batch map ops (plain iteration finished after the attack) and protects only proven pre-attack sources (established or first-seen ≥15s before declaration) — verified live: players flat through a rotating flood.

v2.6.0 — adaptive granularity, live NIC-tuning toggle, baseline day summaries ​

  • attack_poll_divisor (default 4): polling jumps to 250ms during attacks only — zero peacetime CPU cost; poll_interval accepts fractional seconds.
  • NIC tuning toggle (T in the TUI) applies/reverts instantly, with the jitter tradeoff explained in the confirmation.
  • Baseline history rows show TCP/UDP splits and ▲/▼ deviation markers vs your median day.

v2.5.x — UDP player protection, geo UX, webhook health, jitter fix ​

  • v2.5.0 — protected-source snapshot map (Bedrock/UDP players survive floods), geo tab live job progress, webhook delivery panel in the Status tab, keybind pills + segmented status bar.
  • v2.5.1 — NIC tuning became opt-in (nic_tuning, default off): the coalescing it applied was the dedicated-host jitter source.

v2.4.x — baseline memory (ML tab), smart preset blending, honest reports ​

  • 30-day baseline memory — daily snapshots merged recency-weighted with the live EMA; one weird day can't tilt detection. TUI ML tab (m): learning state, live vs merged, thresholds, full history. Guide
  • Delete-a-day reconfiguration — a poisoned day (attack bypassed detection) can be deleted; the baseline reconfigures instantly. D resets today's live baseline for same-day bypasses.
  • Baseline import/export — move trained baselines between servers.
  • Smart multi-profile blending — multiple workload selections merge by semantics, not averages: rate ceilings = union of legit needs, scoring = strictest, FP-prone detections only where all agree.
  • Preset retune — Balanced actually bans sustained 2× abuse; Hosting/Performance/Database bypass classes closed.
  • Honest attack reports — median-based recovery (3s spikes no longer linger for minutes), real attacker IP counts (no more 100k phantom IPs), geo breakdown only from elevated intervals, Mbps/Kbps formatting.
  • Alert pipeline overhaul — attack-end reports can't be lost, lifecycle alerts get queue priority, Discord 429 handling, embedded banner.
  • Behavior engine race fixed; attack_start_mono preservation (the MC disconnect bug).

v2.3.3 — Boot autostart & crash-immunity ​

  • openshield load -always — one flag enables auto-load on every boot via the systemd unit. Self-heals a missing unit file from the pristine copy in /opt/openshield/lib, and verifies the enable actually took.
  • Admin IP protection, guaranteed — the loader binary (what systemd runs at boot) now also auto-whitelists your SSH source IP; the persisted entry is re-applied on every boot before the first packet is judged.
  • Hardened systemd unit — waits for network-online.target (no more racing the interface at boot), and StartLimitIntervalSec=0 means a crash loop never puts the firewall into a permanent failed state.
  • Silent-crash immunity baked into every binary — on some kernels/hypervisors the Go runtime's async preemption killed the loader instantly with no output. All binaries now self-apply the documented workaround (GODEBUG=asyncpreemptoff=1) via a transparent re-exec, so manual runs are as safe as the systemd unit.

v2.3.2 — CLI help system & TUI bugfix sweep ​

  • Per-command help pages — openshield help <command> / --help anywhere, driven by one registry so overall and per-command help can never drift.
  • 18 TUI fixes — geo-tab crash on empty search, never-block input digit handling, traffic screen wraps below 140 columns, typed config_update replies (live config edits no longer look lost), confirm dialogs honor Ctrl+C, uptime-based health badges, narrow-terminal layout, scrollable help overlay, complete keybind docs, input validation, and more.

v2.3.1 — Self-traffic exclusion & startup warmup ​

  • Your own downloads no longer fake attacks — replies to the server's outbound connections (GeoIP updates, blocklist fetches, apt) are excluded from attack-detection and baseline-learning rates. Root-caused: the global counters ran before every exemption. How it works
  • attack_warmup_sec (default 20) — no attack declaration in the first seconds after loader start; per-IP mitigation unaffected.

v2.3.0 — Smarter feeds, bigger maps ​

  • Auto-fetch vps / dedicated modes — dedicated mode skips known cloud/hosting provider ranges (Cloudflare, AWS, GCP live lists + offline fallback) so customer nodes on a dedicated box are never feed-banned.
  • List hygiene — whitelabel (never-block) syncing with the whitelist, blacklist↔whitelist conflict resolution.
  • 2M-entry ban maps (IPv4) — million-IP botnets fit with headroom (~1 GB).

v2.2.x — Geo blocking & alert quality ​

  • Geo country blocking — one keypress blocks a country; ranges resolve from MaxMind GeoLite2 into permanent subnet bans, with persisted records and one-keypress unblock. Geo analytics (top attacking countries with flags, IPs, PPS, Gbps, share %) in attack-end reports and daily/weekly/monthly reports.
  • Ban notes — optional notes on every ban; geo blocks use them for surgical unblocking.
  • Alert cadence rework — growing-interval progress updates, guaranteed end-of-attack delivery with the full report, oversized-forensics fallback message.
  • Port-cap player protection — established and pre-attack sources exempt from the per-port attack cap.

v2.1.x — Metrics, obfuscation, rotation-proof caps ​

  • Metrics HTTP API — optional endpoint with everything the TUI shows; API key (yours or auto-generated), rate limits, allowlist.
  • Obfuscated prebuilt releases — garble-built binaries, zero source in the production zip; dual packaging (bin + src).
  • Attack per-port aggregate cap — the rotation-proof answer to spoofed floods.
  • New-source temp bans — replaces drop-only handling of source bursts.
  • Forensics config evidence — every attack bundle includes the config (with change timestamps) active during it.
  • Runtime config edits persist — TUI/live edits write through to the YAML.

v2.0.0 — The SFTP fix ​

  • Established-connection exemption (A2) — proven TCP connections (handshake + real data) are exempt from rate scoring. Bulk transfers — SFTP uploads, backups, replication — never get banned again. The full story
  • Per-port threshold overrides (C) — custom PPS/BPS limits for specific ports or port ranges, replacing both normal and attack-mode thresholds on those ports only.