I am the head of the Dents project, a group of programmers working on
building a GPL'd server for the Internet's DNS protocol. Dents is still
very much a work in progress, and so I'm not going to talk about all
of its features and how everyone should be using it. We hope to do a
general release Real Soon Now, and at that time I hope return and tout
all of great reasons to start using Dents.
Today, I'm going to talk about one teensy part of Dents, our driver
module system, and about one driver module in particular, one I've
recently written, which I thought certain readers may have an interest in.
First, a little background. named, the DNS server which is part of the
BIND distribution, is the dominant name server today. Most DNS servers,
with the notable exception of Dents, are derived, in whole or in part,
from named. named forces you to store your DNS data in a zone file,
a flat text format for representing DNS data. There are external
modifications to named which allow alternative approaches, but they are
not integrated into the main named source code base.
Lots of people would like to store their DNS data in a relational
database, e.g., or perhaps serve dynamic data via DNS. This is very hard
to do with named, because it stores all DNS data in a single, monolithic
tree (or hash table, I forget.) The notion of a single tree storing
all data is so ingrained in the named source code that it is very hard
to modify it to support using alternative methods.
By contrast, Dents treats DNS zones in a similar way to that in which
Linux or any other modern unix supports file systems; they are "mounted"
using a driver. These drivers take the form of shared object files which
Dents loads at run-time. The mechanism is similar to the way in which
the GTK+ widget set does themes. (I looked a lot at the GTK+ module
code when writing the first version of the Dents driver module system.)
Like GTK+, we have the capability of loading new drivers while we are
running, not just at start time. Indeed, we hope that our CORBA-based
control facility which is presently under development will allow us to
load zones into a running server without having to restart that server.
That's a discussion for another day, however.
The upside of all of this is, that if you can write code that will take
in a DNS question and spit out a DNS answer, then you use that code
to generate DNS data. This is a really big change in how DNS works.
Remember when CGI was born and the web went from a gopher-knock-off to
a wonderful expanse of dynamic content? We hope to unleash a similar
storm of creativity in the DNS space.
The Dents driver module system is several months old at this point, and
it works really well. All DNS functionality in Dents is done using these
driver modules; even our recursion functionality is separated from the
main server into a separate driver module. We have drivers that support
zone files (mod_stddb), drivers which serve data out of a relational
database (mod_mysql_eza), and drivers which don't store any DNS data
at all and instead generate answers algorithmically based on the query
(mod_frl).
This is really great, and we're all very excited about it. The main
problem with this approach is that you have to be able to program in C
(or some binary-compatible language) in order to write a Dents driver.
This really bugged me, because I much prefer programming in perl or
shell to programming in C. I know lots of people who are fine perl
or shell or python programmers who might not be able to program in C.
I really wanted for these people to be able to create dynamic DNS data,
the same way that CGI allows people to create dynamic web content. So,
I wrote a driver to make it possible, and it's this driver that this
article is all about.
mod_msg_tgl is a Dents driver which spawns off external programs (called
driver processes, or dprocs) and answers DNS queries by passing messages
back and forth with those driver processes. This communication is
done with pipes; the driver processes find their stdin originating from
Dents and their stdout terminating to Dents. The message format that
they use to communicate back and forth is a very simple, line-oriented
text protocol.
Here is an example of what a conversation between mod_msg_tgl and a
driver process. Say that a Dents server is configured to serve the domain
"test.dents.org" using mod_msg_tgl, which in turn would use the script
/usr/local/bin/dns_server.sh to serve the data. You would configure
the server by putting the following line into your named.boot file:
Then say you query the server for www.test.dents.org, like this:
Well, in this case, the server, via mod_msg_tgl, would send a message
to the driver process that looks like this:
Let's look at what all of that means:
So, the driver process sees this, does whatever he wants to do, and then
returns a message consisting of two lines:
Just to reinforce the simplicity of what's going on here, let's replay
all of that. First, what the client sees:
And the exchange on the server side that made this happen:
If this seems simple, that's because it is supposed to be! Let's take a look at
an actual application of this technology, clock.sh. This script responds to DNS
queries with the present time. First, the script:
We tell Dents to use this script with mod_msg_tgl by including the following line
in our named.boot:
We start Dents:
And then we query away:
"But Todd", I can hear you ask, "I want to serve glue records and poison
DNS caches and serve out all of my Hesiod data. Can I do that with
mod_msg_tgl?" The answer is that yes, you can do all of this and more.
Just because, out of the box, mod_msg_tgl is designed to be easy to use,
that doesn't mean that it isn't also a powerful DNS engine!
The Answer message format is simple. Perhaps too simple, you DNS studs
out there may be saying. "Say that I want to specify a different ttl for
my answer, or place it in a DNS section other than the Answer section?
Can I do that?" The answer is, of course you can!
Your standard "A" message can be followed by a sequence of
"key=value"-style optional settings. If you want to have your
clock program issue resource records with a ttl of 0 instead of
the default ttl, then instead of saying this:
you can say this:
Options which are presently supported are:
The mod_msg_tgl documentation explains all of this in detail.
As you may have noticed, our example script detected if the operation
code was "ZL" and, if so, responded with an "SOA" message. "ZL" stands
for "Zone Load", and driver processes can respond either with an error
message (op code of "E"), or with an SOA message. The server caches
this setting for the SOA and uses it in all future queries. A driver
process may update that SOA any time he feels like it, assuming that
it's his turn to talk. The server will use the default ttl and all
other settings from the SOA in the serving of that zone.
My above description of how the "ZL" exchange works left out a little
detail; before answering with "SOA", the driver process can specify a
series of settings which he would like for that zone. (You could also
specify settings before returning an error, but that wouldn't accomplish
anything.)
Here's what such an exchange would look like:
These are presently the only two supported options:
The extended query format results the driver process receiving a message
like the following:
I'll be brief on what all of this means; here's the summary from the
documentation:
As you can see, you get all sorts of neat stuff to play with. Want to
give the client his own IP back as an answer to all queries? Now you can.
(Remember about caching servers, though, before you go playing jokes
based on this on your friends.)
Why would anyone want such a thing? Well, I personally am using
mod_msg_tgl right now in order to prototype a Dents driver in perl before
implementing it in C. This new driver uses the awesome Berkeley DB v2
to store DNS data in a key-value database. You should be able safely
to update the database externally, using BDB's transaction support,
and have your changes take effect immediately in DNS. This, in turn,
should make all sorts of cool DNS tricks with dynamic data possible.
Sure, I could write this from day one in C, but if I change my mind about
how I want the data laid out, as I've already done once and may do again,
then it's really a pain to rewrite all of that code. Since I'm doing
the prototype in perl, however, I just tie the database to a hash, and
all is right with the world; changing how I have the database laid out
is a snap. When I am happy with how it all looks, then I'll take the
perl code, convert it to C and make a full Dents driver out of it.
mod_msg_tgl is still a work in progress; there are several improvements which
I would like to make:
While Dents is not yet a suitable general-purpose DNS server, we are
making rapid progress; at this point we are mostly fixing bugs before
unleashing our creation on the world; named will serve just fine in
the interim. However, mod_msg_tgl is technology which is working fairly
well and which has no analogue available today. For people who have need
to do innovative things with DNS, I encourage you to take a look at it
and see if it meets your needs. You can find out more about mod_msg_tgl
and Dents in general below in our (
Resources) section.
1. Introduction
2. The Dents driver module system
3. mod_msg_tgl
mod-primary test.dents.org mod_msg_tgl /usr/local/bin/dns_server.sh
host -t a www.test.dents.org.
>>> 2 Q www.test.dents.org. A
<<< 2 A www.test.dents.org. A 59.138.101.147
<<< 2 F
$ host -t a www.test.dents.org.
www.test.dents.org has address 59.138.101.147
>>> 2 Q www.test.dents.org. A
<<< 2 A www.test.dents.org. A 59.138.101.147
<<< 2 F
#!/bin/sh
# clock.sh : an sh script for use with mod_msg_tgl to serve the time
# c 1999, Todd Lewis <tlewis@mindspring.net>
# licensed under the terms of v2 of the GPL
while read a b c d
do
if [ $b = "ZL" ]
then
echo "$A SOA $c `uname -n` root.localhost 100 3600 900 3600 3600"
elif [ $b = "Q" ]
then
echo "$a A $foo[3] TXT The_time_is_`date +%H:%M:%S`"
echo "$a F"
else
echo "$a E 4"
fi
done
mod-primary time.dents.org. mod_msg_tgl /usr/local/bin/clock.sh
dents -c named.boot
reflections% dig @localhost www.time.dents.org. -p 1053
; <<>> DiG 8.1 <<>> @localhost www.time.dents.org. -p
; (1 server found)
;; res options: init recurs defnam dnsrch
;; got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUERY SECTION:
;; www.time.dents.org, type = A, class = IN
;; ANSWER SECTION:
www.time.dents.org. 1H IN TXT "The_time_is_23:21:36"
;; Total query time: 39 msec
;; FROM: reflections.mindspring.com to SERVER: localhost 127.0.0.1
;; WHEN: Tue Oct 5 23:21:36 1999
;; MSG SIZE sent: 36 rcvd: 69
4. Advanced Features
4.1 Optional Answer Arguments
<<< 2 A www.time.dents.org. A 59.138.101.147
<<< 2 A www.time.dents.org. A 59.138.101.147 ttl=0
4.2 SOA Support
4.3 Extended Query Support
>>> 1 ZL time.dents.org.
<<< 1 O time.dents.org. EXTENDEDQ
<<< 1 SOA time.dents.org. reflections.mindspring.com root.localhost 100 3600 900 3600 3600
>>> 3 EQ www.time.dents.org. TXT IN 10 127.0.0.1 2000 0 1
FORMAT: <seq#> EQ <name> <qtype> <qclass> <id> <client-ip> <client-port> <opcode> <recursion-desired>
5. The Good, The Bad, The Ugly
5.1 What mod_msg_tgl is good for
5.2 What mod_msg_tgl is bad for
5.3 Future Directions
6. Conclusion
7. Resources