Random Tech Thoughts

The title above is not random

PowerDNS Setup on Debian Lenny Using Bind or Sqlite3 Backend

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.confis 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.

Comments