Summary: Domains added to the DNS Firewall Custom Allow list return SERVFAIL (EDE 22, “No Reachable Authority: delegation .”) instead of resolving normally, even though the same domains resolve fine via external resolvers and are not falsely still matching any block rule.
Evidence:
google.com (cached) → NOERROR, instant
anthropic.com (uncached, not listed) → NOERROR, 15.4ms — proves general recursion is healthy
doubleclick.net (blocked, not allow-listed) → NXDOMAIN with synthetic localhost. SOA — proves the block mechanism works correctly
cb.sailthru.com (allow-listed) → SERVFAIL, EDE 22, 338.9ms
horizon.sailthru.com (allow-listed) → SERVFAIL, EDE 22, 286.1ms
Environment: Core Update version 2.29 Update 203, Knot Resolver / DNS Firewall with Advertising list enabled, six domains in Custom Allow list. Not using Webproxy.
Conclusion: Allow-listed domains consistently fail resolution with a delegation-authority error, while the same box resolves ordinary domains fine and correctly blocks non-allow-listed domains. Is this a bug in how Allow list interacts with kresd’s resolution policy, or a configuration problem. All test done with cleared cache after settings changed.
When you add a domain to your “custom allowed list”, a policy.PASS rule is applied to it. This bypasses the other matching policy rules, including forwarding rules to other DNS servers.
The domain is therefore resolved normally by the recursor.
Option: Unblocking a Domain Caught by DNS Firewall Ad List (RPZ) when using a captive tunnel
Custom Allow list
The DNS Firewall’s Custom Allow list applies policy.PASS, which forces full local recursion (bypassing your forwarder) for that domain. If your setup routes all traffic through a full-tunnel VPN, that VPN’s DNS-leak protection blocks the arbitrary root/TLD server queries recursion needs, causing SERVFAIL / EDE 22 “No Reachable Authority”. Works fine without a restrictive VPN; fails with one.
One fix: DNS Forwarding (Network → DNS Forwarding in the WebUI)
Why this works
Forwarding sends the query directly to one specific, known-good nameserver instead of forcing recursion — the same path ordinary (non-blocked) domains already use successfully, VPN or not. DNS Forwarding zones are evaluated ahead of the RPZ block in Knot Resolver’s policy chain, so they successfully route around the block. No IP-drift maintenance needed (unlike a static hosts override) since it resolves live, every time.
Steps
Remove the blocked domain from the Custom Allow list (DNS Firewall page) — if left in place, its policy.PASS rule fires first and the forwarding zone below never gets evaluated.
Add a DNS Forwarding zone: Network → DNS Forwarding →
Zone: the parent domain, not each subdomain — forwarding zones match the whole subtree, so one entry for sailthru.com covers cb.sailthru.com, api.sailthru.com, horizon.sailthru.com, etc.
Nameserver: a working, reachable resolver IP. Using the VPN’s own DNS server (rather than a generic public resolver) is a good choice here — it’s guaranteed reachable over the tunnel with no split-tunnel exception needed, since ordinary forwarded queries already succeed against it.
If it still fails after adding the forwarding zone
Re-check step 1 — confirm the domain isn’t still on the Allow list.
If DNSSEC validation fails (SERVFAIL with a bogus/validation-related EDE) even though the zone works via +cd (checking disabled): it usually means the target domain is legitimately unsigned (no DS record — confirm via kdig +dnssec <domain> DS, expect an NSEC3 proof-of-nonexistence, not an actual DS record), and the forwarding path isn’t returning enough proof material for Knot Resolver to independently validate the “insecure delegation” itself. Not a misconfiguration on the target’s end — disable DNSSEC for that specific zone’s forwarding entry only:
Leave DNSSEC enabled on zones that validate fine; only disable it per-zone, as needed.
The above solution is only one of multiple options. Comments on any risks are welcome.