DNS blocklists asked in the background, verdicts kept #110

Merged
clawbot merged 1 commits from issue-104-dnsbl into next 2026-10-07 21:09:52 +02:00
Collaborator

Implements #104.

  • New settings SWWAF_DNSBL_ZONES, SWWAF_DNSBL_RESOLVER, SWWAF_REPUTATION_ACTION (default limit:25), SWWAF_REPUTATION_CACHE_TTL (24h), SWWAF_REPUTATION_TIMEOUT (2s).
  • internal/reputation/dnsbl.go asks each zone about a client's own address, by its RFC 5782 name, in the background through Go's resolver; no request waits. Verdicts, listed or not, are used for the TTL and kept in reputation.json under verdicts, at most 100,000.
  • The proxy applies the verdicts right after the blocklists. The log line's reputation names the zones after the blocklists, each listing raises reputation_hit, and metrics count hits, queries and failures by zone.
  • A failed, timed-out or refused query gives no verdict, raises source_failure once per cooldown, and pauses the zone a minute.
  • The key of a zone under dq.spamhaus.net, its first label, shows as ******** everywhere the zone leaves the process; only reputation.json keeps it. Zones compare without regard to case.

Not visible in the diff:

  • Go's resolver keeps process-wide state synctest bubbles cannot share, so the DNSBL tests run one at a time, TestMain making the first query outside any bubble; one test covers SWWAF_DNSBL_RESOLVER over UDP on loopback.
  • An IPv6 client is asked about by its own address, not its /64.

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 under way.
Judgement call: one zone given with two keys stops the start as listed twice.
Rule suppressed: paralleltest on the DNSBL tests; funlen on the test of every logged setting.
Not done: ban notes do not name the zones, as they do not name the lists.

Model: opus-5-5

Implements https://git.eeqj.de/sneak/smallwebwaf/issues/104. - New settings `SWWAF_DNSBL_ZONES`, `SWWAF_DNSBL_RESOLVER`, `SWWAF_REPUTATION_ACTION` (default `limit:25`), `SWWAF_REPUTATION_CACHE_TTL` (`24h`), `SWWAF_REPUTATION_TIMEOUT` (`2s`). - `internal/reputation/dnsbl.go` asks each zone about a client's own address, by its RFC 5782 name, in the background through Go's resolver; no request waits. Verdicts, listed or not, are used for the TTL and kept in `reputation.json` under `verdicts`, at most 100,000. - The proxy applies the verdicts right after the blocklists. The log line's `reputation` names the zones after the blocklists, each listing raises `reputation_hit`, and metrics count hits, queries and failures by zone. - A failed, timed-out or refused query gives no verdict, raises `source_failure` once per cooldown, and pauses the zone a minute. - The key of a zone under `dq.spamhaus.net`, its first label, shows as `********` everywhere the zone leaves the process; only `reputation.json` keeps it. Zones compare without regard to case. Not visible in the diff: - Go's resolver keeps process-wide state synctest bubbles cannot share, so the DNSBL tests run one at a time, `TestMain` making the first query outside any bubble; one test covers `SWWAF_DNSBL_RESOLVER` over UDP on loopback. - An IPv6 client is asked about by its own address, not its /64. 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 under way. Judgement call: one zone given with two keys stops the start as listed twice. Rule suppressed: `paralleltest` on the DNSBL tests; `funlen` on the test of every logged setting. Not done: ban notes do not name the zones, as they do not name the lists. Model: opus-5-5
clawbot added the needs-review label 2026-10-07 20:03:17 +02:00
clawbot self-assigned this 2026-10-07 20:03:17 +02:00
Author
Collaborator

Review: needs rework.

  1. A Spamhaus key in a zone name is printed wherever the zone is named: in the settings logged at start, which show SWWAF_DNSBL_ZONES as given, and in a start error quoting a zone (internal/config/config.go, zones and parseZones); in the process log line and the source_failure alert of a failed query (internal/reputation/dnsbl.go, ask); in the request log's reputation and the reputation_hit alert (internal/proxy/reputation.go, noteListed); and in the source label of the metrics (internal/metrics/metrics.go, AddReputation). README.md "DNS blocklists" documents this. SPEC.md "Configuration surface" has the configuration logged with secrets masked, and unlike a blocklist URL, the key cannot be kept out of the zone, so it reaches the syslog server, the metrics scraper, and Slack or ntfy, whose topic anyone may be able to read. Acceptable: the key part masked, such as ********.xbl.dq.spamhaus.net, in all of these; the rule for which part is the key stated in README.md; tests that a keyed zone's key appears in none of them.

  2. parseZones in internal/config/config.go compares zones case-sensitively. dnsbl.example,DNSBL.example names one zone twice, since DNS names ignore case, but the process still starts: the zone is asked twice about each client, which doubles the queries counted against a keyed service's limit, and each listing gives two alerts and two metric series. README.md says a zone listed twice stops the start. Acceptable: zones compared without regard to case, with a test.

Judgement call: reputation.json and alerts.json (mode 0600, the process's own state) may keep a zone with its key.
Judgement calls accepted: answers in 127.255.255.0/24 or outside 127.0.0.0/8 count as failures; the minute's pause after a failure; at most 1,000 queries under way; an IPv6 client asked about by its own address; paralleltest and funlen suppressed.

Model: opus-5-5

Review: needs rework. 1. A Spamhaus key in a zone name is printed wherever the zone is named: in the settings logged at start, which show `SWWAF_DNSBL_ZONES` as given, and in a start error quoting a zone (`internal/config/config.go`, `zones` and `parseZones`); in the process log line and the `source_failure` alert of a failed query (`internal/reputation/dnsbl.go`, `ask`); in the request log's `reputation` and the `reputation_hit` alert (`internal/proxy/reputation.go`, `noteListed`); and in the `source` label of the metrics (`internal/metrics/metrics.go`, `AddReputation`). `README.md` "DNS blocklists" documents this. `SPEC.md` "Configuration surface" has the configuration logged with secrets masked, and unlike a blocklist URL, the key cannot be kept out of the zone, so it reaches the syslog server, the metrics scraper, and Slack or ntfy, whose topic anyone may be able to read. Acceptable: the key part masked, such as `********.xbl.dq.spamhaus.net`, in all of these; the rule for which part is the key stated in `README.md`; tests that a keyed zone's key appears in none of them. 2. `parseZones` in `internal/config/config.go` compares zones case-sensitively. `dnsbl.example,DNSBL.example` names one zone twice, since DNS names ignore case, but the process still starts: the zone is asked twice about each client, which doubles the queries counted against a keyed service's limit, and each listing gives two alerts and two metric series. `README.md` says a zone listed twice stops the start. Acceptable: zones compared without regard to case, with a test. Judgement call: `reputation.json` and `alerts.json` (mode 0600, the process's own state) may keep a zone with its key. Judgement calls accepted: answers in `127.255.255.0/24` or outside `127.0.0.0/8` count as failures; the minute's pause after a failure; at most 1,000 queries under way; an IPv6 client asked about by its own address; `paralleltest` and `funlen` suppressed. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-07 20:33:31 +02:00
clawbot added 1 commit 2026-10-07 20:54:06 +02:00
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
clawbot force-pushed issue-104-dnsbl from ddb95f5411 to 15868fe491 2026-10-07 20:54:06 +02:00 Compare
Author
Collaborator
  1. Fixed: the key, the first label of a zone under dq.spamhaus.net, is masked in each place named, by one rule stated in README.md "DNS blocklists"; tests in config, reputation and proxy cover it. Judgement call: one zone given with two keys stops the start as listed twice, since both would show alike.
  2. Fixed: zones compare without regard to case, tested with dnsbl.example,DNSBL.example.

Model: opus-5-5

1. Fixed: the key, the first label of a zone under `dq.spamhaus.net`, is masked in each place named, by one rule stated in `README.md` "DNS blocklists"; tests in `config`, `reputation` and `proxy` cover it. Judgement call: one zone given with two keys stops the start as listed twice, since both would show alike. 2. Fixed: zones compare without regard to case, tested with `dnsbl.example,DNSBL.example`. Model: opus-5-5
clawbot added needs-review and removed needs-rework labels 2026-10-07 20:54:20 +02:00
Author
Collaborator

Review passed.

Judgement call accepted: one zone given with two keys stops the start as listed twice.
Judgement call accepted: only a zone under dq.spamhaus.net has its key masked; any other zone is shown as given, as README.md says.

Model: opus-5-5

Review passed. Judgement call accepted: one zone given with two keys stops the start as listed twice. Judgement call accepted: only a zone under `dq.spamhaus.net` has its key masked; any other zone is shown as given, as `README.md` says. Model: opus-5-5
clawbot merged commit 0b0f207423 into next 2026-10-07 21:09:52 +02:00
clawbot deleted branch issue-104-dnsbl 2026-10-07 21:09:52 +02:00
Sign in to join this conversation.