Now and again, there is a need to override certain DNS lookups. For individual systems you could make changes in the hosts file, but this does not scale well and is easily forgotten. Establishing the override through DNS, one could either use split-view DNS or the old-school strategy of creating a stub zone for that exact hostname (or domain, if you were lucky), but this does not scale very well either and is, let’s admit it, rather ugly.

That said, overriding DNS could in itself be considered ugly. But there are some cases where it’s very useful:

  • blackholing malicious sites/domains prior to or during an attack
  • redirecting requests for certain sites to a local resource (e.g. for developers making a new version of a live site, and need to test with the real site’s hostname)
  • blocking devices that “call home”, e.g. smart TVs, toasters and refrigerators
  • denying access to ad servers or tracking servers
  • accessing servers when you and the server are both on the inside of a NATed firewall/router

But how?

Starting with BIND 9.8.1, it’s possible to maintain such overrides in one single zone, removing the hassle of establishing BIND config for every domain or hostname you need to block or redirect. This is called Response Policy Zone, and takes the form of one single zone in which all addresses to override can be added. RPZ may be configured on a caching-only server as well as a full-blown authoritative BIND DNS server.

Create your RPZ

Create a zone file where you have your other zone files, e.g. /etc/bind/db.rpz on a Debian system and someplace under /var/named/ on a RHEL system. Add the sites you want to override, note that the left hand side records have no trailing dots.

$TTL 600
@            IN    SOA  localhost. root.localhost.  (
                          2015112501   ; serial
                          1h           ; refresh
                          30m          ; retry
                          1w           ; expiry
                          30m)         ; minimum
                   IN     NS    your.primary.DNS.
                   IN     NS    your.secondary.DNS.


; Redirect this site to our internal web server for testing
www.example.com           CNAME   internal-webserver.example.net.

; Ads from this network is particularly intrusive
ad.example.com            A       127.0.0.1

; Malware site, we must prevent compromised clients
; from contacting it.
evil.h4xx0r.example.com   A       127.0.0.1

Add the RPZ file to BIND’s config

Add something like the following to BIND’s config, obviously modifying the settings according to your own requirements:

zone "rpz" {
  type master;
  file "db.rpz";
  notify yes;
  also-notify { ip.of.your.secondary.DNS; };
  allow-transfer { ip.of.your.secondary.DNS; };
};

Tell BIND of its magic

Lastly, instruct BIND that the rpz zone is a special zone:

options {
  [ your other options here ]
  response-policy { zone "rpz"; };
}

You might also want to explicitly log requests that reach the RPZ. In your BIND config, locate (or create) a logging section, adding something like the following:

logging {
  channel rpz-queries {
    file "/var/log/bind/rpz.log" versions 10 size 500k;
    severity info;
  };
  category rpz {
    rpz-queries;
  };
};

The log file will show which clients tried to request a zone that exists in the RPZ. If your RPZ includes known malicious sites, identifying infected or compromised hosts on your network suddenly becomes much easier by tailing this log. This is how a DNS request that is picked up by the RPZ might look:

client 172.16.0.1#32846 (evil.h4xx0r.example.com):
rpz QNAME Local-Data rewrite evil.h4xx0r.example.com via
evil.h4xx0r.example.com.rpz

Testing

Now it’s time to test your setup. A regular DNS lookup is the simplest approach.

$ dig +short evil.h4xx0r.example.com
127.0.0.1

Now try opening the same address in your browser. You should see an “unable to connect” or “connection refused” message.

Note: If your network has users with local web servers installed on their workstations, you might want to choose another “sink hole” than 127.0.0.1, or your overridden host names will be redirected to everyone’s own device.

Populating an RPZ

In addition to domains or host name that that need to be overridden for local reasons, the RPZ could be populated from external sources under various terms and/or pricing. A somewhat updated list exists at https://dnsrpz.info/.

Supporting software

RPZ functionality is currently supported in the BIND DNS server (and products based on BIND) and in Knot. Similar behaviour, although not in the form of a zone, may be configured in other software such as dnsmasq and unbound.