This post appeared originally in our sysadvent series and has been moved here following the discontinuation of the sysadvent microsite

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 configuration 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 configuration

Add something like the following to BIND’s configuration, 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 configuration, 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.

Bjørn Ruberg

Senior Systems Consultant at Redpill Linpro

With long experience as both a network security consultant and system administrator, Bjørn is one of those guys we go to when we need forensics to be done on a potentially compromised system. He's also good at dealing with tailored DDoS-attacks on our customers, and always has a trick up his sleeve.

Containerized Development Environment

Do you spend days or weeks setting up your development environment just the way you like it when you get a new computer? Is your home directory a mess of dotfiles and metadata that you’re reluctant to clean up just in case they do something useful? Do you avoid trying new versions of software because of the effort to roll back software and settings if the new version doesn’t work?

Take control over your local development environment with containerization and Dev-Env-as-Code!

... [continue reading]

Ansible-runner

Published on February 27, 2024

Portable Java shell scripts with Java 21

Published on February 21, 2024