Tuesday, August 24, 2010

DNS Sinkholes... That Work

One idea that's been ramping up in the last few months is the DNS sinkhole. Essentially you configure your local client facing resolves to always return an IP address of your choice for a list of "known bad" domains. The list of domains will usually come from some trusted source, and the IP returned will either be a completely non-functional one (like a 127 address), or one that points at your local honeypot server. Assuming that you've got a good list of malicious domains, it can be a great way to block viruses and other malware without having to touch any of your clients.

The only problem, though, is that most of the examples I've found... well, kinda suck. They're either limited in scope, less efficient than they should be, or just don't work. So rather than complaining about them all individually, here's the set up that Works For Me®.

First, you need a minimal zone file. All of the malicious zones will get served out of this zone file, so you are restricted to records that will be common to all. This example uses 127.1.1.1 for the target IP address, substitute your own if you want to send the traffic somewhere else.

$TTL    600
@                       1D IN SOA       localhost root (
                                        42              ; serial
                                        3H              ; refresh
                                        15M             ; retry
                                        1W              ; expiry
                                        1D )            ; minimum

        IN  NS  localhost.
        IN  A 127.1.1.1
*       IN  A 127.1.1.1
  • The SOA and NS records are both just set to 'localhost', avoiding hitting any real records, but still resolving.
  • Pick any serial you like - it should never change, only the list of zones pointing at it.
  • The first 127.1.1.1 record causes BIND to return a record for the zone itself. For example, if you pointed "badstuff.com" at this zone file, it would allow any queries for badstuff.com to return 127.1.1.1.
  • The second 127.1.1.1 record handles anything within badstuff.com - www.badstuff.com, download.badstuff.com, etc. You need both records to get full coverage.

Take that zone file, and stuff a copy of it on all of your servers. Here, rather than bothering to set up the usual master/slave relationship, I just made all of my servers master - much simpler, since none of the usual benefits of master/slave configurations apply.

Once it's in place, create a config block in your named.conf (or included file) for each zone that you want to filter (getting the list of zones is outside of the scope of this post):

zone "badstuff.com" {
    type master;
    notify no;
    file "Malware.zone";
};

This will cause your server to start answering all queries for badstuff.com and anything under it out of the file Malware.zone instead of issuing a recursive query for it. Make sure you include the 'notify no;' line - that will prevent your servers from trying to flood each other with useless notifies.

Here are a few other links you should follow if you're serious about doing real DNS sinkholes.