With OpenDNS now needing one to be on the pro package to have filtering turned on, being on a tight budget, we are in need of free DNS filtering.

After reading this link on how to block domains with bind, I collected SquidGuard blacklists and concatenated domains in the categories i needed into one big list. I then fed it to this python script generating a file containing about 2 million zones.

named-checkconf parses it just fine, but reloading named takes almost 10 minutes, then it wont resolve anything, and the server slows down to a crawl. Removing the include results in named working properly again.

Whats the proper way to set up BIND9 to work as a DNS firewall efficiently? If it's possible to also block any domain that resolves to specific IP addresses that would solve the whole problem.

I'm running bind as non-authoritative, just a caching server.


That's out of date for current technology. In the BIND world, Response Policy Zones (RPZ) are synonymous with DNS firewalls these days.

A RPZ zone is a normal DNS zone, but is used to define policy actions by the server. The zone "suffix" does not matter, as this is not a real DNS domain. It's simply a zone file that contains a list of specially formatted instructions.

options {
          ...
          response-policy { zone "whatever.anytld";} };
};

The left hand side of the record defines the matching rule, with the record type and right hand side defining the action to take. Note the absence of a trailing dot on the left hand side of the following examples.

$ORIGIN whatever.anytld.

; destination IP rewrite
baddomain1.example.com       A     198.51.100.1
*.baddomain1.example.com     A     198.51.100.1

; send them to an existing A record
baddomain2.example.com       CNAME mywebserver.example.org.
*.baddoman2.example.com      CNAME mywebserver.example.org.

; NXDOMAIN it
baddomain3.example.com       CNAME .
*.baddomain3.example.com     CNAME .

; reply with NODATA
baddomain4.example.com       CNAME *.
*.baddomain4.example.com     CNAME *.

And so on. You can do quite a bit with this, including more heavy handed measures that risk impacting innocent shared hosting sites: blocking nameservers by name, blocking nameservers by IP, performing actions on the IP address of a returned record instead of the name, etc.

There's a lot that RPZ will do, and this isn't meant to serve as exhaustive documentation. Recommended reading include the Chapter 6 of the BIND ARM (bottom of this answer) for your version of BIND, and Chapter 9 of the online Zytrax book.

Cliff notes from my personal experience to save you time:

  • Use zone transfers to move your RPZ zones around withIXFR. Enable ixfr-from-differences on your master to facilitate this. Use key based zone transfers if using BIND 9.9 or later to protect against NOTIFY based DoS attempts.
  • Only let administrative IPs query the RPZ zone.
  • Don't use more than one RPZ file unless you're running BIND 9.10. There were performance issues with multiple zones until that version.
  • RPZ can't be used to stop the NS record based attacks that became popularized in 2014, as by default RPZ is designed to attempt authoritative lookups and not "betray" your record hijacking to an upstream nameserver source.
    • qname-wait-recurse no was added in BIND 9.10 and may allow you to use RPZ for this purpose. I've been meaning to lab it out.
    • Even if qname-wait-recurse no works, there is still a need for a record type that can be used to offline attack domains without extra configuration. I've spoken to Paul Vixie about this and we may see it in a future version of the RPZ format spec.
  • NXDOMAIN and NODATA actions will betray the name of your RPZ zone in the AUTHORITY section of the reply. Assume that people will learn its name.

BIND ARM Chapter 6 links:

  • BIND 9.10
  • BIND 9.9
  • BIND 9.8 (caution: BIND 9.8 reaches EOL in 9/2014)