[Pdns-users] Recursor 5.4.0: RPZ matches on '.' root query, breaks DNSSEC validation (Indeterminate instead of Bogus)
Chris Brough
hello at chrisbrough.uk
Sun Apr 19 21:48:09 UTC 2026
Hi all,
I'm running into behaviour I can't explain and I'd appreciate a second pair of eyes before I assume it's a bug. I could easily be doing something obvious and wrong.
Setup
* PowerDNS Recursor 5.4.0 in Docker (image: powerdns/pdns-recursor-54:latest)
* Host: Debian 13 VM (UmbrelOS - using the Portainer app to manage Docker), Docker host network mode
* Full recursion, no forwarders
* `dnssec.validation: validate`, built-in root trust anchor
* Root zone loaded via `zonetocaches` from Internic (ZONEMD validated Secure at startup)
* 7 RPZ zones loaded via `rpzPrimary` from IPFire DBL (xfr.dbl.ipfire.org) — ads, gambling, malware, phishing, piracy, smart-tv, violence. Open AXFR, no TSIG.
* `extended_resolution_errors: true`, per-RPZ `extendedErrorCode: 15` and `extendedErrorExtra` set
Full YAML config and docker-compose.yml available on request.
Symptom
DNSSEC-bogus domains return NOERROR with data instead of SERVFAIL:
$ dig @<host_ip> dnssec-failed.org +dnssec
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 18515
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; ANSWER SECTION:
dnssec-failed.org. 218 IN A 96.99.227.255
dnssec-failed.org. 218 IN RRSIG A 13 2 300 ...
Confirmed validation mode is actually loaded:
$ rec_control get-parameter dnssec
dnssec:
validation: validate
disabled_algorithms:
- '1'
- '3'
- '5'
- '6'
- '7'
- '12'
log_bogus: true
Query log shows `validationState="Indeterminate"` for the query, not Bogus.
Root cause (as far as I can tell)
A rec_control trace-regex 'dnssec-failed.org' trace shows validation tries to fetch the root DNSKEY and hits the first RPZ in the config list:
.|DNSKEY:: RPZ Hit; PolicyName=ads.rpz.ipfire.org; Trigger=.; Hit=; Type=QName; Kind=Local Data
.: Retrieved 0 DNSKeys, state is Indeterminate
org: Updating validation state with cache content for org to Indeterminate
dnssec-failed.org: Updating validation state with cache content for dnssec-failed.org to Indeterminate
dnssec-failed.org: Validation status is Indeterminate
Confirming this from a client:
$ dig @<host_ip> . NS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 14776
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
; EDE: 15 (Blocked): (Blocked: advertising)
;; QUESTION SECTION:
;. IN NS
Zero-answer NOERROR on `. NS`, tagged by the first RPZ. This is not specific to the ads list — I tested by removing ads.rpz.ipfire.org from config, and whichever RPZ moved into first position then shows the same behaviour on root queries. So every IPFire RPZ I'm loading exhibits this, which makes me think it's something about the way they're structured or the way PDNS loads/evaluates them, rather than a specific zone being poisoned.
What dump-rpz shows:
$ rec_control dump-rpz ads.rpz.ipfire.org /tmp/ads.txt
$ head -5 /tmp/ads.txt
ads.rpz.ipfire.org. IN SOA primary.dbl.ipfire.org. hostmaster.ipfire.org. 1776630606 3600 600 3600000 60
stbg.stanbicbank.co.zw.ads.rpz.ipfire.org. 60 IN CNAME .
stats.zpl.zone.ads.rpz.ipfire.org. 60 IN CNAME .
*.a.userscript.zone.ads.rpz.ipfire.org. 60 IN CNAME .
a.userscript.zone.ads.rpz.ipfire.org. 60 IN CNAME .
Apex has only SOA (NS stripped). Nothing in the dumped zone should produce a `.` QName trigger as far as I can read it — but the trace clearly shows one matching, with `Hit=` empty.
The IPFire source zone at xfr.dbl.ipfire.org contains at its apex: SOA, NS, and an `_info IN TXT` record one label below the apex. Nothing else unusual that I can see.
RPZ config (abbreviated)
recursor:
rpzs:
- name: ads.rpz.ipfire.org
addresses: [ 'xfr.dbl.ipfire.org:53' ]
policyName: ads.rpz.ipfire.org
extendedErrorCode: 15
extendedErrorExtra: 'Blocked: advertising'
- name: gambling.rpz.ipfire.org
addresses: [ 'xfr.dbl.ipfire.org:53' ]
policyName: gambling.rpz.ipfire.org
extendedErrorCode: 15
extendedErrorExtra: 'Blocked: gambling'
# ... 5 more in same pattern
system_resolver_ttl: 300
extended_resolution_errors: true
No `defpol` is set on any zone.
Am I configuring these RPZs wrong in a way that causes `.` to match as a QName trigger? I can't find anything in docs or the RFC that would point there.
Happy to provide the full YAML, full trace log, full zone dump, or anything else useful. I didn't attach them here to keep the email readable.
Thanks,
Chris
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.powerdns.com/pipermail/pdns-users/attachments/20260419/96d1d810/attachment.htm>
More information about the Pdns-users
mailing list