# State files The five JSON files in `SWWAF_STATE_DIR`, and what each holds. "Persistent state" in [`SPEC.md`](../SPEC.md) says how they are written, read and edited. Each has a top-level `version` of 1. ## `bans.json` Active and past bans: every ban an admin made, and up to `SWWAF_MAX_BANS` of those `smallwebwaf` made. Per entry: - `netblock`, `start` and `expires` (`null` for a permanent ban); - `cause`: `attack`, `limit`, `admin` or `crowdsec`; - `reason`: a short reason; - `lifted`: when an admin lifted it, if one did; - `notes`: the notes below. An entry an admin adds needs `netblock`, `start` and `expires`; `reason`, `notes` and `cause` may be left out, and the cause is then `admin`: ```json { "version": 1, "bans": [ { "netblock": "203.0.113.0/24", "start": "2026-10-06T12:00:00Z", "expires": null, "reason": "probes for logins" } ] } ``` "Bans" in [`SPEC.md`](../SPEC.md) says how an edit lifts, keeps or forgets a ban. The notes: - `asn`, `as_name` and `country`: the client's, added when the lookup answers (empty when lookups are off); - for a broken limit, `kind` (`requests`, `bytes` or `refusals`), `limit`, `window` and `count`: what the limit was on, the limit, its window and the count reached; - `limit_percent` and `limit_percent_setting`: the client's percentage of that limit and the setting that gave it, when a setting lowered it; - for a clear sign of attack, `rule_id` and `target`, or `trap_path`; - `reputation`: the sources the client was on, each with its `source` and, for AbuseIPDB, its `score`; - `request`: the request that caused the ban, each text cut to 256 bytes: - `time`, `method` and `host`; - `path`, with its query string; - `status` and `user_agent`; - `requests` and `refused`: the netblock's requests since it was first seen, and how many this ban has refused so far, kept up to date while the ban lasts; - `earlier_bans`: how many earlier bans the netblock had, by cause. ## `clients.json` Per client, one per line: its minute, hour and day counters, and its history since it was first seen: - the first and last time seen; - the AS number, AS name and country last looked up, and when; - total requests, and how many were forwarded and how many refused; - bytes in each direction; - responses by status class; - offences by kind: `limit`, `attack`, `rule_blocked`, `waf_blocked` and `token_refused`. ## `lookups.json` GeoJS answers, one per line: - `client`; - `asn`, `as_name` and `country`; - `answered`: when GeoJS answered; - `used`: when the answer was last used. ## `reputation.json` - the last good copy of each list fetched from a URL, with when it was last tried; - each DNS blocklist verdict still in use; - AbuseIPDB's scores, and the checks spent today. ## `alerts.json` - the anomaly counters; - the alert cooldowns: for each event and netblock, source, file or anomaly scope, when it was last sent and the count of repeats held back since; - the alerts sent and held back in the current hour; - the alerts waiting for each destination. ## Sizes - `clients.json`: about 1 KiB per client, about 20 MiB at the default `SWWAF_MAX_TRACKED_CLIENTS`. Written every 15 minutes, that is under 2 GiB of disk writes a day. - `bans.json`: about 1.2 KiB per ban, at most about 2.5 KiB, so about 6 MiB at the default `SWWAF_MAX_BANS`. Written every 15 minutes, a full file comes to about 600 MiB of writes a day, and a hundred new bans a day add about 600 MiB more. - `lookups.json`: about 150 bytes per answer, under 1.5 GiB of writes a day when full. - `reputation.json` and `alerts.json`: usually a few MiB or less.