When you query the DNS, are you sure the reply you're getting is the truth and nothing but the truth? No, you aren't:
$ dig www.google.com ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 45617 ;; flags: qr rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;www.google.com. IN A ;; ANSWER SECTION: www.google.com. 300 IN CNAME jpmens.net.
We administrators have a variety of methods by which we can lie to our users. ;-) (This, by the way, is one of the reasons why DNSSEC is so important: it will help us detect that kind of modification, but it'll also (unfortunately) disallow pranks.)
Changing DNS replies on the fly is not something we typically do maliciously -- we do it for reasons:
- provide addresses of resources which are moving targets, think Geo-location
- to protect our users from illicit or harmful content
- to temporarily work around broken DNS data provided by third-parties we can't persuade that their data is broken
- for testing purposes
Depending on whether you're interested in authoritative DNS servers or recursive servers, there are different solutions you can use to respond to DNS queries on the fly. Let me briefly mention a few:
I'll just mention these shortly, because I cover most of them in quite great detail in the book:
- SDB is BIND's Simplified Database interface, an API provided in BIND version 9.1 and above which lets an administrator extend BIND by creating a driver that is linked into BIND. Basically this allows us to create an integral bit of BIND which can provide authoritative answers from any data source. (Read much more on SDB in Chapter 8.)
- Dynamically Loadable Zones (DLZ) is an add-on for the BIND name server that
lets you store zone data in an external database. DLZ lets you add zones on-the-fly
without having to reconfigure or reload BIND. As an enhancement over SDB, DLZ allows
us to use DLZ to determine whether a zone is available (we configure SDB zones in
named.conf). I devote Chapter 9 to DLZ. You may also be interested in a very nice bit of work by Mark Goldfinch who very recently created a BDB back-end for DLZ with dlopen() called dlz-bdbhpt-dynamic.
- As an extension to DLZ, Andrew Tridgell created DLZ dlopen(), which allows DLZ
zones to be updated on the fly with dynamic DNS updates. Also based on
dlopen()is my own Lua back-end for BIND which may interest you.
- PowerDNS has a back-end in Lua, which produces responses on the fly. The documentation is a bit thin but there's plenty of information in the source code.
Many PowerDNS users utilize the Pipe back-end which is included in the distribution. Although it's primarily meant for rapid prototyping, I know lots of people who use it in production. The great advantage of the Pipe back-end is, it allows us to write program in any language we desire, and PowerDNS speaks to our program using stdin and stdout to give our program queries to which it replies. There are dozens of examples; I'll start listing some here, and gladly accept links with which I'll add: (note: I have not experimented with the majority of these -- I put them here for your inspiration)
- PyPdnsRedis, a redis-backed pipe-backend for PowerDNS by Bjarni R. Einarsson
- Autoreverse Generator to create IPv6 PTR records by Aki Tuomi. There are a few similar tools, for example: 1, 2
- PowerDNS backend using DynamoDB by Cosmin Stejerean
- Ruby library for interacting with the PowerDNS Pipe backend by John Leach
Two small favorites of mine Net::DNS and Stanford::DNSserver I write about in Chapter 15: these tools allow me to create specialized name servers in Perl. I also used Stanford::DNSserver when I talked about DNS backed by CouchDB: if you follow the links there, you'll see the result culminated as PowerDNS and a CouchDB backend. :-)
- Miek Gieben has a DNS package in Go which can be a bit of fun.
Interesting for testing-purposes is to have a recursive server intercept, maybe log or print queries and replies, and possibly also modify those (which is what happened in the example at the top of this page). Here are some beasts you can use for that.
- The PowerDNS Recursor has an embedded Lua interpreter with which it can modify resolvering behaviour using Lua scripts. (See Appendix H.)
- The Unbound recursive name server can be made to respond however way you wish basically, either by scripting in Python or by writing your own C module.
- Frank Denis created DNScrypt proxy for OpenDNS. An upcoming version of it will permit plugins which can modify responses.
- Sentry is a Python DNS proxy that allows you to inspect, block, rewrite or redirect queries.
- Peter van Dijk reminds me that Python's Twisted has a DNS server module with which we can do, ooh, lots of things. :)
- BIND RPZ, which allows you to configure your BIND resolvers to lie, doesn't really produce answers on the fly, but as RPZ zones can be dynamically updated, I'll mention it here.
- So-called local data can be injected to a running Unbound to modify its behaviour, so I'll add that as well.
This list is by no means exhaustive -- I've probably forgotten lots of tools. Tell me which and I'll gladly add them here.