UnveilTech

UnveilDNS Blog

← All articles

Try UnveilDNS free

RPZ explained: Response Policy Zones without the BIND headache

Posted 2026-06-09 · 7 min read · filtering

Most people meet Response Policy Zones the hard way: a security vendor hands them a feed URL, the documentation says "load it as an RPZ", and suddenly they are reading about zone transfers, response-policy clauses, and why their resolver logged a SERVFAIL at 3 a.m. RPZ is one of the most useful ideas in DNS — a firewall you express as a zone file — but the classic implementation wraps it in enough operational ceremony that plenty of teams quietly give up and paste the domains into a hosts file instead.

That is a shame, because the concept is genuinely elegant. RPZ lets a policy author say "when anyone asks about this name, or resolves to that address, or is delegated through those nameservers — rewrite the answer." It is a standardized way to distribute and apply DNS policy, and threat-intelligence providers have leaned on it for over a decade. This article explains what RPZ actually is, the actions and triggers it supports, why feeds ship in this format, and how a modern resolver can swallow an RPZ list without forcing you to run a full BIND zone-transfer pipeline.

What RPZ actually is

A Response Policy Zone is, mechanically, an ordinary DNS zone — the same SOA, NS, and resource-record structure you would write for any domain. The twist is in interpretation: the resolver is told to treat this zone not as authoritative data to serve, but as a policy ruleset to consult before answering a query. The format was introduced by Paul Vixie and Vernon Schryver around 2010 and documented in an informational draft (commonly referenced as the "DNS RPZ" format). It has been a de facto standard ever since.

Because a policy is encoded as a zone, it inherits everything DNS already knows how to do: it can be transferred between servers (AXFR/IXFR), signed, versioned through the SOA serial, and updated incrementally. A vendor publishes a zone, your resolver pulls deltas, and policy propagates the same way DNS data propagates. That reuse is the whole appeal — and, as we will see, also the source of the operational pain.

The mental model. Think of an RPZ as a deny/allow list with a grammar. Each record is a rule: the owner name encodes what to match (the trigger), and the record data encodes what to do about it (the action). The resolver walks its policy zones in order and the first match wins.

The action types

When a query matches a rule, RPZ rewrites the response. There are five canonical actions, each expressed through a specific record value in the policy zone.

ActionEncoded asEffect on the client
NXDOMAINCNAME to the root (.)The name "does not exist" — the most common block. Clients see a clean negative answer.
NODATACNAME to a wildcard (*.)The name exists but has no records of the requested type. Useful to suppress, say, AAAA without killing the name entirely.
Passthru (allow)CNAME to rpz-passthru.Explicitly exempt the name from policy. This is how you whitelist an entry that a broader rule would otherwise catch.
Redirect (CNAME)CNAME to a real target nameResolve the query to a different name — a walled-garden page, a sinkhole, a safe alternative.
DropCNAME to rpz-drop.Discard the query with no response at all. The client times out. Useful against abusive floods you do not want to acknowledge.

A few subtleties matter in practice. A literal local-data answer (returning a specific A/AAAA record instead of a CNAME) is also possible and behaves like a redirect to an address. And ordering is significant: passthru rules are how you carve exceptions out of a blanket block, so a more-specific allow must be evaluated before the broad deny — which RPZ handles by zone precedence and longest-match semantics.

# Illustrative RPZ fragment (owner name = trigger, data = action)
malware.example.        CNAME   .             ; NXDOMAIN — block
ads.example.            CNAME   *.            ; NODATA
trusted.example.        CNAME   rpz-passthru. ; allow / whitelist
phish.example.          CNAME   safe.example. ; redirect to a notice page
flood.example.          CNAME   rpz-drop.     ; drop silently

The trigger types

Actions answer "what to do." Triggers answer "what to match against." RPZ supports four, and this is where it gets more powerful than a flat domain list. Each trigger lives in its own naming convention inside the policy zone.

TriggerMatches onTypical use
QNAMEThe queried name itselfThe bread-and-butter case. "Block bad.example and everything under it."
Response IPThe address in the answer"Block any name that resolves into this hostile netblock," even names you have never seen.
NSDNAMEThe nameservers serving the answer"Block anything delegated through this known-bad nameserver." Catches whole malicious infrastructures at once.
NSIPThe IP of the answering nameserversLike NSDNAME, but keyed on the nameserver's address rather than its name.

Vendors also distribute a client-IP dimension, letting policy depend on who is asking rather than only on what they ask. That turns a single resolver into a multi-tenant policy engine: one client subnet gets a strict zone, another gets a lenient one. The response-IP and nameserver triggers are the genuinely clever part — a plain blocklist can only react to names it already knows, whereas an IP trigger blocks a brand-new phishing domain the moment it resolves into a flagged hosting range.

QNAME blocking is reactive: you must already know the bad name. Response-IP and NSDNAME blocking are structural: you block the infrastructure, so freshly minted domains on the same hosts and nameservers are caught on first contact.

Why security vendors ship RPZ feeds

If you subscribe to commercial threat intelligence, there is a good chance at least one feed is offered as RPZ. The reasons are practical:

So RPZ became the lingua franca for "here is some DNS policy, apply it." The problem was never the feed. It was the machinery you needed to consume it.

The operational tax in classic BIND

The traditional way to use RPZ is to configure a response-policy statement and either host the zone locally or pull it via zone transfer from the provider. That works, and on a well-run BIND it works well. But it drags in a surprising amount of operational surface:

  1. Zone-transfer plumbing. You configure AXFR/IXFR from the feed's primaries, manage TSIG keys, open the right ports, and hope the provider's transfer endpoint is reachable from your resolver. A blocked transfer means stale or missing policy.
  2. Reloads and rebuilds. Depending on configuration, applying or reordering policy zones can mean a config reload. On a busy resolver that is a moment of risk, and a malformed zone can take down resolution rather than just one rule.
  3. Ordering and precedence debugging. With multiple policy zones, working out why a name was (or was not) rewritten means reasoning about zone order, longest-match, and passthru exceptions across several files.
  4. DNSSEC interaction. Rewriting an answer is, by definition, forging it. RPZ and DNSSEC validation have well-known tensions; a rewritten name can fail validation downstream unless you handle the break deliberately.
  5. Format lock-in. If your resolver is not BIND-family, native RPZ support ranges from partial to absent — yet the feed you bought only ships RPZ.
The honest summary. RPZ the format is excellent. RPZ operated as live zone transfers feeding a reload-sensitive resolver is what gives it the reputation as a headache. The two are separable.

A modern alternative: ingest, convert, apply

You do not actually need a zone-transfer pipeline to benefit from an RPZ feed. The information in an RPZ list is just rules — owner name plus action — and those map cleanly onto the block and redirect primitives any decent filtering resolver already has. So instead of teaching the resolver to be an RPZ secondary, you teach an ingestion layer to read the RPZ list and translate it into the resolver's native rule format.

That is the approach UnveilDNS takes. You point it at an RPZ source; it fetches the list (validating that the source is reachable and not pointing at private infrastructure), detects the format, converts each rule, and registers the result as a normal blocklist. No response-policy clause, no TSIG, no transfer ports. The list is refreshed on a schedule, and only when the converted output actually changes does the filter engine reload — so a feed that publishes a new serial every few minutes does not translate into a reconfiguration storm on a high-traffic resolver.

Mapping RPZ rules to block/redirect rules

The translation is mostly mechanical. Each RPZ action has a natural equivalent in a name-based rule grammar:

RPZ ruleMeaningEquivalent native rule
name CNAME .NXDOMAIN blockBlock name (return "does not exist")
name CNAME *.NODATABlock name (no data for the type)
name CNAME target.RedirectRewrite nametarget
name A 0.0.0.0Sinkhole to a null addressBlock name
name CNAME rpz-passthru.Allow / whitelistAllow exception for name

QNAME triggers convert one-to-one. The redirect case becomes a DNS rewrite to the named target. Passthru becomes an allow exception. The two triggers that do not survive a static conversion are response-IP and NSDNAME/NSIP, because those can only be evaluated at resolution time against a live answer — a converted blocklist is name-keyed by nature. In practice most distributed RPZ feeds are overwhelmingly QNAME rules, so conversion captures the vast majority of the policy; the infrastructure-level triggers are better served by a resolver's own threat-intelligence and detection layers (response-IP reputation, fast-flux and DGA heuristics) than by importing them from a third-party zone.

# Before (RPZ)            ->  After (native rule, conceptual)
bad.example.   CNAME .         block: bad.example
go.example.    CNAME safe.example.  rewrite: go.example -> safe.example
ok.example.    CNAME rpz-passthru.  allow:  ok.example

RPZ feed vs a plain blocklist: when each wins

Once you can consume both, the question becomes which to reach for. They are not interchangeable.

Choose…When…
An RPZ feedYou are paying for curated threat intelligence that ships in RPZ; you want vendor-managed redirects/sinkholes and passthru exceptions baked in; or you need the infrastructure-level triggers (and run a resolver that evaluates them live).
A plain blocklistYou are aggregating community or open lists that are already simple domain or hosts files; you want one flat, auditable list of names; or you only need "block these and don't pretend they redirect anywhere."

The deciding factor is usually who authors the policy. RPZ shines when a provider expresses nuanced intent — block here, sinkhole there, exempt this — and you want that intent applied faithfully. A plain blocklist shines when you are the policy author and a list of names is all the expressiveness you need. The good news is that with format conversion in front of the resolver, you no longer have to choose your tooling based on which format your feed happens to use. You choose based on the policy you actually want, and let the ingestion layer normalize the rest.

RPZ's reputation as a BIND headache is really a reputation for one specific deployment model. The format itself — a DNS firewall expressed as a zone — is worth keeping. Consume the rules, drop the zone-transfer ceremony, and RPZ becomes just another well-structured input to a filtering resolver that already knows how to block, redirect, and allow.

Use RPZ feeds, skip the pain

UnveilDNS ingests RPZ-format lists and converts them for you — no zone-file surgery.

Deploy UnveilDNS free