# 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. To ban a netblock, add an entry with its `netblock`, `start` and `expires`. `reason`, `notes` and `cause` may be left out; 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" } ] } ``` To lift a ban, add `"lifted"` with the time you lift it, such as `"lifted": "2026-10-06T13:00:00Z"`. To keep a ban `smallwebwaf` made, set its `cause` to `admin`. To forget a ban, delete its entry. The notes: - `asn`, `as_name` and `country`: the client's, added when the lookup answers (empty when lookups are off); - what was broken: the rule id and target that matched, or the trap path, or the limit, its window and the count reached; - the client's percentage of the limit, with the setting that gave it; - the reputation sources the client is on; - `request`: the request that caused the ban: time, method, host, path with its query string, status and user agent, each text cut to 256 bytes; - `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`. With a full file, a hundred new bans a day come to about 600 MiB of writes. - `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.