Update on May 4th, 2011: Sebastian Andrzej Siewior writes a C program that can make incremental SQL updates for sqlite based on a bind zone file. This would be useful if you are managing a large domain using sqlite.
As the number of computers in my lab grows, it’s better to use a local DNS server. I’ve done this with bind when I’m an undergraduate student, but I forget almost all about bind’s configuration. PowerDNS seems to be promising: good performance, flexible, easy to use. It has a built-in web server monitor, web based zone management tool Poweradmin. So I decide to use it this time.
Update: When troubleshooting the problem in the final note, I find that dnsmasq is more suitable for my purpose. It reads /etc/resolv.conf
and /etc/hosts
for it’s DNS configuration. I will write more about this in another article.
Installation
I am setting up the DNS server on a Debian Lenny system. PowerDNS uses backend to store zone (domain) information. A backend can be bind configuration, relational database, LDAP server etc. I’m going to show how to use the bind and sqlite3 backend. First install pownerdns and the sqlite3 backend:
sudo aptitude install pdns-server pdns-backend-sqlite3
pdns-server
combines the authoritative server (which can only lookup host in its own database) and the recursor (which send recursive DNS request to other DNS servers). (If you don’t need local DNS database and just want to use a DNS cache, pdns-recursor
can be used.)
Testing DNS server
Before going on, I want mention that we can use nslookup
to make DNS lookup to a specific server manually. (In case you don’t have this command, install bind9-host
package on Debian.)
$ nslookup[DNS server] # For example: $ nslookup example.com localhost
Without specifying DNS server, nslookup will use one in /etc/resolv.conf
.
Basic setup
The pdns configuration on Debian Lenny lives in /etc/powerdns/
.
-
pdns.conf
contains the main configuration for pdns server. It can include other configurations. -
pdns.d/pdns.local
this contains local changes we can make, such as backend configurations.
Enabling recursion
Recursion allows the server to send recursive DNS request to other DNS server. To enable this, set the recursor
in pdns.conf
to the DNS server we want to send recursive request. Then make sure that allow-recursion
are set correctly. Simply commenting out allow-recursion
allow recursion from anywhere.
Reload the configuration and use nslookup google.com localhost
to see if recursion works.
Troubleshooting
The log will be very helpful if something goes wrong. You can change loglevel
to 9 to log all the message. The default setting put log in /var/log/daemon.log
. Take a look there to see if you server starts correctly.
Using the bind backend to configure domain
If you do not know anything about zone file, please refer to other resources first. You don’t need to be a guru on zone file, but understanding what is SOA, what is A/MX record is necessary. I recommend the the zone file wikipedia article and redhat’sreference manul.
Here’s a configuration example using the setup for our lab. I put them under /etc/powerdns/bind
. The first file named.conf
is a simple bind configuration which only includes another zone file.
zone "ppi" { type master; file "/etc/powerdns/bind/ppi.zone"; allow-update { none; }; };
The second file ppi.zone
is a zone file which contains the host and ip mapping for our lab.
$ORIGIN ppi. ; start of this zone file in the name space, not necessary if included from named.conf $TTL 1h ; default expiration time of all resource records without their own TTL value @ IN SOA localhost someone.mail.com. ( ; @ is replaced with . in email address 1 ; serial number of this zone file 1d ; slave refresh (1 day) 2h ; slave retry time in case of a problem (2 hours) 4w ; slave expiration time (4 weeks) 1h ; minimum caching time in case of failed lookups (1 hour) ) IN NS ns ; ns.ppi is a nameserver for ppi IN MX 1 mail IN A 10.x.x.x ns IN A 10.x.x.x mail IN A 10.x.x.x serv1 IN A 10.x.x.x
Now let’s configure powerdns to use the bind configuration we’ve just created. Edit /etc/powerdns/pdns.d/pdns.local
to contain the following content:
launch=bind bind-config=/etc/powerdns/bind/named.conf
Reload the configuration by issuing the command /etc/init.d/pdns reload
. Now you can use nslookup
to get the IP address of “serv1.ppi”. If the lookup failed, take a look at the log.
Remember that every time you update the zone file, you need to tell pdns to reload the configuration. This is not the case if we are using a relational database backend, which I’ll cover next.
Using the sqlite3 backend to configure domain
I found the information about sqlite3 backend in PowerDNS’s documentation. I will put all the files under /etc/powerdns/sqlite
directory.
The 1st step is toset up powerdns to use the sqlite3 backend. Follow the instruction here to setup a sqlite3 database with the specified schema. Note that your database should be readable by the pdns
user, otherwise powerdns will fail to start. Edit pdns.local
to like this:
launch=gsqlite3 gsqlite3-database=/etc/powerdns/sqlite3/db.sqlite3
Now we can restart the pdns server.
Next create a domain, I found the instruction in the MySQL configuration example. (It took me some time to find it.) Use the following command to create the domain:
$ sqlite3 db.sqlite3 'insert into domains (id, name, type) values (0, 'ppi', 'NATIVE');'
Then we can use zone2sql
tool provided by PowerDNS to convert the zone file into SQL statement to insert into the records table. I’ve created a small shell script to do that:
#!/bin/bash usage() { echo "Usage: `basename $0`" } if [[ $# != 2 ]]; then usage exit 1 fi bindconf=$1 db=$2 if [[ -r $db ]]; then # create a backup first cp $db $db~ else echo "Must use an existing sqlite3 database with schema setup." fi sqlite3 $db 'delete from records' zone2sql --named-conf=$bindconf 2>/dev/null | sqlite3 $db
You can use this script to load previous zone file into the sqlite3 database. After that, you pdns server will be working again as using the bind configuration file.
Conclusion
Though both backend works, I prefer the sqlite3 backend since modification to zone configuration doesn’t require server to reload configuration. But I don’t like operate with SQL statements directly. So my choice is to change the zone file, then use the script to update the database. For a small environment like our lab, this works well.
Final note: I found that on windows, nslookup works but ping doesn’t when looking up the name like “serv1.ppi”. A little gooling take me to stackoverflow and dnsmasq FAQ (search for “looking up local names” in that FAQ). Adding a dot at the end the the name like “serv1.ppi.” works, refer to dnsmasq’s FAQ for how to configure your system to force that.