For those of you who know the BIND name server but don’t know about CouchDB, it is a distributed, fault-tolerant and schema-free document- oriented database accessible via REST. And for those who know CouchDB but don’t know BIND, BIND is a DNS name server, probably the DNS name server: it powers a large majority of the world’s Domain Name System.
While I was experimenting with CouchDB it occurred to me that it would make a rather sexy DNS data store, and so I started looking into using it for doing precisely that. I revised the proof of concept because I had the schema all wrong, and implemented a follow-up with a full zone in a single document – much better. Quite a bit of feedback then got me to implement a PowerDNS pipe back-end, but I wasn’t terribly pleased with it. So I implemented a BIND SDB driver, and here it is.
The Simplified Database Interface for BIND 9 is an application programmer interface (API) with which a programmer can add a back-end (called a driver in BIND SDB) to the BIND name server. BIND uses that driver to provide answers to DNS queries. BIND 9.1 introduced this simplified database interface, or SDB, to make it easy to create specialized applications.
When a zone uses SDB, BIND answers queries for the zone, not by reading information from zone master files, but instead by using the driver specified in the zone’s configuration. Standard drivers distributed with BIND SDB let you use a variety of databases and files from which to retrieve data. The current BIND 9.7.2 distribution contains drivers for bdb, dir, ldap, pgsql, sqlite, tcl, and time. For example, the demonstration timedb driver returns the date and time when you query for a txt record in a zone configured to use timedb.
A single instance of BIND can have both normal zones and zones served by SDB drivers. An SDB zone has an SDB-specific database statement in a zone clause. If this is present when BIND receives a query for such a zone, BIND calls the SDB driver to resolve the query instead of using master files as for normal zones.
Adding an SDB driver to your
named isn’t for the faint of heart. The couch-
sdb README contains some pointers, but you’ll have to dig in to the BIND
distribution to find the nitty gritty on how to do that. (What I really
recommend is my book, where I devote a whole chapter to SDB and show you
in great detail how to implement a driver.)
Upon receiving queries for zones configured to use couch-sdb, BIND invokes the couch-sdb driver which goes off and requests the zone’s document from CouchDB and uses values in that document to create answers which are stuffed back into SDB and thus sent back to the DNS client.
A zone is configured in a single document which contains objects that define replies to queries on a particular zone, and you can view an example JSON document here. Let’s look at some bits, though:
- The document’s
_idis the zone name.
- If a
serialvalue exists in the
soaobject, it must be an integer, which is used as the SOA serial. If it doesn’t exist, the first integer value of the document’s
_revis used; now that is way cool! – auto-incrementing serial! (The value called
xserialabove will be ignored.)
rnameare used, else hard-coded values.
default_ttlis just that; it is used for the NS RR and for records that don’t have their own TTL.
- If a
nsis an array of name servers. Names, of course; not addresses!
- Apropos names; unqualified names are in the zone
rris an array of RR objects. Each of these have:
- A domain
name, which must be unqualified. (I.e. use
@for the zone apex.
type. Upper or lower case.
datais the rdata for the domain. It is either a single value or an array of similar values, in which case an RRset is built.
- An optional
ttlfor this RRset.
- And do remember: Don’t put a CNAME and other data together!
- A domain
named to use the couch-sdb driver isn’t difficult. A zone
stanza defines a zone as master, and you give it a
database statement. The
first word in the statement, here it is
couch, defines the SDB driver
named will utilize. The next two parameters are specific to the couch-
sdb driver: they are the URL of the CouchDB instance and the name of
the CouchDB database respectively.
- CouchDB databases replicate over normal HTTP, allowing firewall administrators to accomodate said replication without having to open additional ports (53) for zone transfers (AXFR).
- The way I’ve implemented the
couch-sdbdriver allows you to have auto-incrementing serial numbers. The way this works is that if the zone’s document doesn’t explicitly contain a
serialfield, the document’s revision (
_rev), which is incremented automatically whenever a document changes, is used as the SOA serial.
There are of course also disadvantages. First of all, BIND SDB is rather slow to start; this isn’t a limitation of couch-sdb, but rather a design “feature” of BIND: when BIND starts up, it queries each and every zone (including those configured to use an SDB database) for the SOA and NS of the zone. This means that upon startup, CouchDB will be hit with a query for every couch-sdb configured zone. Then there is obviously the additional dependency to CouchDB: both BIND and the database back-end must be running for the name server to work. But here again, this isn’t a limitation of BIND – the same applies to whichever database-driven DNS server you want to use. The couch-sdb is currently experimental; there may be the odd memory leak in the (also experimental) CDBC library I created for this, but all in all, it appears to function rather nicely. I’m interested in reading your comments.