Every cache of answers from an outside service has its own file in `SWW_CACHE_DIR` (default `/var/cache/sww`): `lookups.json` (GeoJS), `lists.json` (lists fetched by URL, CrowdSec's decisions included), `dnsbl.json`, `abuseipdb-scores.json` and `routewatch.json` (at most 100,000 answers, each kept an hour). `reputation.json` is gone; the AbuseIPDB checks spent today stay in `SWW_STATE_DIR` as `abuseipdb-checks-spent.json`, since losing them would spend the daily budget twice.
A cache file never stops the start: one that does not parse is set aside as `<name>.bad` with a `file_error` alert. An unwritable `SWW_CACHE_DIR` stops the start. The `run` script creates the cache directory and gives it to `sww`. The cache directory needs no volume and can be left out of backups.
Model: opus-5-5
Zones in SWWAF_DNSBL_ZONES are asked about each client in the background,
through SWWAF_DNSBL_RESOLVER or the host's resolver; no request waits.
Verdicts last SWWAF_REPUTATION_CACHE_TTL, kept in reputation.json.
SWWAF_REPUTATION_ACTION (limit:25) denies, limits or logs a listed
client; each zone listing it raises reputation_hit. A failed query gives
no verdict, raises source_failure, and pauses the zone a minute. A
zone's key, its first label under dq.spamhaus.net, is masked everywhere
but reputation.json. Zones compare without regard to case.
Judgement call: answers in 127.255.255.0/24 or outside 127.0.0.0/8 are failures.
Judgement call: the minute's pause after a failure; at most 1,000 queries at once.
Judgement call: one zone given with two keys stops the start as listed twice.
Rule suppressed: paralleltest on the DNSBL tests (Go's resolver shares state across synctest bubbles), funlen on the test of every logged setting.
Model: opus-5-5