Project sponsored by
Project hosted on

This driver allows you to use Berkeley DB as a database for storage of DNS data. It has been tested on Windows 2K and Redhat Linux 8.0. The driver should build properly on any UN*X system that BIND & Berkeley DB support. Be sure to specify --with-dlz-bdb when running configure so that the Berkeley DB driver is built with BIND. By default, DLZ and its drivers are not built. When you specify a DLZ driver, the DLZ core is automatically built too.

BE SURE TO READ THE SPECIAL BUILD INSTRUCTIONS FOR THIS DRIVER THAT ARE DETAILED LATER IN THIS DOCUMENT!

The Berkeley DB driver was built to be as flexible as possible, but it is not as flexible as the PostgreSQL, MySQL or file system drivers because of how Berkeley DB works.

Below is a sample of a proper dlz_bdb_driver configuration. This configuration segment would be contained in BIND's config (named.conf) file. It is explained more below. When you are setting up your own Berkeley DB driver be sure to pass the following parameters to BIND "-g -d 1". The first "-g" tells BIND to write all log messages to stdout instead of a log file. The second parameter "-d 1" sets BIND's debug level to 1. The Berkely DB driver will output additional information when the debug level is set to at least 1. This can be very helpful while you are setting up the driver. The additional information will be output only when BIND is trying to answer DNS queries, not when BIND loads. Run a few sample DNS queries in order to see the output.

    dlz "bdb zone" {
       database "bdb /dns-root dnsdata.db";
    };

The first line: dlz "bdb zone" {

This line tells BIND we want to use a DLZ driver. The word "dlz" is a new BIND keyword added by the DLZ patch. The next section "bdb zone" is the label for this configuration segment. It is used in any error messages BIND displays while parsing its config file. The last piece "{" starts the DLZ configuration section in BIND's config file.

The second line: database "bdb /dns-root dnsdata.db";

This line is indented just to make it easier to read the configuration file. The keyword "database" is the only parameter that can be specified in a DLZ configuration segment. It is required. The double quote (") begins the command line that is passed to the DLZ driver--in this case, the Berkeley DB driver. The command line could be broken over many lines but is not necessary here. The next piece is the word "bdb". This is the official name of the DLZ Berkeley DB driver. We are telling BIND that we want to use the Berkeley DB driver. The word "bdb" is located at argv[0]. I.E. This is the command line array passed to the driver, and the driver name must always be at argv[0]; it is not optional.

Next is "/dns-root". It should NOT have a "/" at the end. This is the directory path where the Berkeley DB environment is stored. The Berkeley DB driver operates in "concurrent data store" (CDS) mode, not in the old style "DBM" mode, and thus requires a Berkeley DB environment. For more information about "concurrent data store" operation of the Berkeley DB, see the documentation provided with that software package.

Basically, CDS allows the database to be "read" by one or more applications simultaneously, and also allows the database to be updated or "written" to simultaneously by another application. Only one application may make updates to the database at a time. The Berkeley DB takes care of all synchronization and locking. Because of this, it may appear that multiple applications are writing to the database simultaneously, but that is not the case. One application will make its updates, and then the other application will. Depending upon how the application is written, the updates from the two programs may actually be inter-weaved. One program makes an update, then the second, then the first again, etc. In order for the Berkeley DB to handle locking properly, all applications which access the database must use the same environement and use the correct Berkeley API's to access the database environment BEFORE attempting to perform any database operations. The Berkeley DB driver, and the supplied utility (dlzbdb) both make use of the Berkeley environment properly. Look at the source code of both to see how to properly access the Berkeley envionment and database.

The next item "dnsdata.db" is the path and name of the database file to store the dns data in. This "path" is relative to the environment path. So, using the configuration as we have it here will create a file called "dnsdata.db" in the path "/dns-root" for a full path of "/dns-root/dnsdata.db". You can also use absolute paths for the database file path and name if you don't want the database file stored in the same folder as, or relative to the Berkeley DB environment. I highly recommend that you place the database file in the same folder as the database environment just for ease of administration.

The last characters on the command line are "; These characters complete and close the command line and are part of BIND's standard configuration file syntax.

Third line: };

This closes the DLZ configuration section in BIND's config file. It is part of BIND's standard configuration file syntax.

How the Berkeley DB driver works:

The Berkeley database file actually has 4 "databases" in it. Berkeley DB and "DBM" / "NDBM" / "GDBM" style databases are only simple key = value databases. That is to say that each database can only store a key, and the corresponding value for that key. In order to perform more complex query operations using multiple keys you need to use multiple key = value databases and combine them together in some way. This is easiest with the Berkeley DB as it provides API's to do this, so we don't have to do it all manually (We still do a lot of it manually). The four databases in the database file are:

dns_data | The DNS data. The key is meaningless. It is only used as a means to identify this particular data record. The key is used to lookup this particular data record by other index databases.
dns_zone | The zone index for the DNS data. The key is a zone name, the value is a "dns_data" key. Multiple matching keys (zone names) are allowed. This database is used to narrow results to a particular zone. Usually used in combination with "dns_host".
dns_host | The host index for the DNS data. The key is a hose name, the value is a "dns_data" key. Multiple matching keys (host names) are allowed. This database is used to narrow results to a particular host. Usually used in combination with "dns_zone".

dns_client

The lookup database for zone transfers. This databases keys are zone names, and the values are IP addresses. Multiple matching keys are allowed. Multiple matching IP addresses are allowed. Only one unique zone & IP address are allowed. I.E You may have:

key | value
--- | ---
example.com | 127.0.0.1
example.com | 192.168.0.1
example2.com | 127.0.0.1
example2.com | 192.168.0.1
example.com | 127.0.0.1 // not allowed!

All the above would be allowed except the last line because a key "example.com" already has a value "127.0.0.1".

Data in the "dns_data" value field must be specified in the following order. Only a single space " " must be between each field, and records of DNS type TXT should include any necessary quoting. Any un-needed fields should be ignored.

Order | Name | Data Type | Description
--- | --- | --- | ---
1 | zone | string | DNS zone
2 | host | string | DNS host name
3 | type | string | DNS data type
4 | ttl | string (num) | Time to live (string must convert to number)
5 | mx_priority | string (num) | MX Priority (only for MX DNS types)
6 | data | string | IP address / Host name / Full domain name
7 | primary_ns | string | Primary name server SOA record (SOA ONLY)

8 | resp_person | string | Responsible person SOA record (SOA ONLY)
9 | serial | string (num) | Serial # for SOA record (SOA ONLY)
10 | refresh | string (num) | Refresh timefor SOA record (SOA ONLY)
11 | retry | string (num) | Retry time for SOA record (SOA ONLY)
12 | expire | string (num) | Expire time for SOA record (SOA ONLY)
13 | minimum | string (num) | Minimum time for SOA record (SOA ONLY)

Like most other DLZ drivers, the Berkeley DB supports wildcard hostnames using "*" as the wild card, and the character "@" is used as the hostname at the zone apex.

Some examples:

    example.com @ SOA 10 ns1.example.com. root.example.com. 2 2800 7200 604800 86400
    example.com www A 10 192.168.0.1
    example.com mail A 10 192.168.0.2
    example.com backup A 10 192.168.0.3
    example.com @ MX 10 20 mail
    example.com @ MX 10 40 backup
    example.com www MX 10 20 mail
    example.com www MX 10 40 backup
    example.com ns1 A 10 192.168.0.4
    example.com ns2 A 10 192.168.0.5
    example.com @ NS 10 ns1.example.com.
    example.com @ NS 10 ns2.example.com.
    example.com @ TXT 10 "This is some sample text.  Notice it is inside of quotes"
    example.com @ TXT 10 "The quotes are required by BIND so that it returns the"
    example.com @ TXT 10 "string as a single entry.  Otherwise it will return each"
    example.com @ TXT 10 "word as a entry instead of the entire string."
    example.com @ TXT 10 "This text is actually 8 separate text records.  It was"
    example.com @ TXT 10 "broken up this way to be easier to read.  You may"
    example.com @ TXT 10 "specify long text entries if you want. i.e. this could"
    example.com @ TXT 10 "have all been one entry if we wanted to do that."
    example.com * A 10 192.168.0.6

Using the dlzbdb utility:

The dlzbdb utility was developed to enable immediate use of the Berkeley DB driver and serve as an example of how to interact with the database. The utility provides only basic operations.

For help at anytime, execute dlzbdb without any command line arguements. The program will display a simple help message showing how to use it.

First you must create a database. The dlzbdb utility can create a database and add records at the same time.

For example:

    dlzbdb -n -a "d example.com www A 10 192.168.0.1" /dns-root dnsdata.db

This command will create a new database and environment if they did not exist. If a database and environment already exist, they will not be created or overwritten. The new record will simply be added to the existing database.

The "-n" option can be used to re-create Berkeley DB environment files if they are missing after performing a Berkeley DB recover operation. If the environment files are gone and the database file is intact, the environment files will be recreated, and no data in the database will have been lost.

The "a" option indicates that we wish to add a new record to the database. The data is contained within the quotes. The first letter "d" inicates that this is DNS data. The rest of the data inside the quotes is the data to be added to the database. Notice it follows the format listed above. The dlzbdb utility is a bit more forgiving in that if there are extra spaces between the fields, it will automatically remove them. To insert text records with quotes, you will need to escape the quotes in the data record by proceeding each quote with a "\" character.

For example:

    dlzbdb -a "d example.com www TXT 10 \"this is escaped\"" /dns-root dnsdata.db

The dlzbdb utility will automatically create the key for the "dns_data" database, and add required zone and host entries to the other databases as well.

In order for zone transfers to be performed, a client must be authorized to do zone transfers. This is accomplished by adding an entry to the "dns_client" database. To do this:

    dlzbdb -a "c example.com 192.168.0.1" /dns-root dnsdata.db

This command is very similar to the previous ones. The difference is that instead of a "d" we have a "c" as the first character. This lets dlzbdb know we want to add a client to the zone transfer list. After the "c" character is "example.com"--this is the zone. Following that is "192.168.0.1". This is the IP address of a machine that we will allow to perform zone transfers.

In all the commands shown thus far, the last two parameters are "/dns-root" and "dnsdata.db". The first parameter is the location of the Berkeley DB environment. The last is the relative path & name of the database file. These two parameters are required for any operation with dlzbdb and should always be the last two parameters, in that order.

dlzbdb can also perform "bulk" loads of data. To do that, create a file where each line is one "command". Each command should look exactly as the commands we have listed above. The file may also include c, c++ and shell comments; comments are ignored.

Example file:

    d example.com @ SOA 10 ns1.example.com. root.example.com. 2 2800 7200 604800 86400
    d example.com www A 10 192.168.0.1
    d example.com mail A 10 192.168.0.2
    d example.com backup A 10 192.168.0.3
    d example.com @ MX 10 20 mail
    d example.com @ MX 10 40 backup
    d example.com www MX 10 20 mail
    d example.com www MX 10 40 backup
    // This is an example comment.  It is ignored.
    // these are our name servers
    d example.com ns1 A 10 192.168.0.4
    d example.com ns2 A 10 192.168.0.5
    d example.com @ NS 10 ns1.example.com.
    d example.com @ NS 10 ns2.example.com.
    d example.com @ TXT 10 "This is some sample text."
    d example.com * A 10 192.168.0.6
    c example.com 192.168.0.4   // allow zone transfers to our public DNS servers
    c example.com 192.128.0.5

The Berkeley DB does not allow the use of transactions when operating in CDS mode. So it is not possible to "rollback" the load if an error occurs on one line. Instead, the dlzbdb utility will display an error message indicating any line which could not be loaded. You should then copy that line and any others that failed to load to a new file, repair the errors and load the new file. This is not the best solution, but it is the only one that works.

The dlzbdb utility also has the ability to list entries in the database and delete entries from the database. Execute dlzbdb with no parameters to display the help. Those operations should be self explanatory.

BERKELEY DB DRIVER BUILD INSTRUCTIONS:

Sleepycat, the makers of Berkeley DB, changed the api between versions 4.0.X of and 4.1.X. The dlz driver was developed to use the newest version of the driver available at the time (4.1.25 when this driver released). The version of Berkeley DB shipped with most Linux and other UN*X compatible distributions uses the older style of the Berkeley DB API. To build this driver you must download and install a new version of Berkeley DB. Follow the instructions included with the Berkeley DB software to build it for your platform.

On Redhat, Berkeley DB will build and install, but does not install over the original Berkeley DB that shipped with redhat. I expect the same thing will happen with other distributions. In order to build this driver properly, you will need to specify the path to the Berkeley DB that you just built & installed. This is done by specifying the path (as shown below) when running configure: (Path used here was for Redhat after Berkeley DB build & install)

    ./configure --with-dlz-bdb=/usr/local/BerkeleyDB.4.1

BIND will now build properly, but when you try to execute named using the BDB driver, or use dlzbdb, you will get an error about not finding the library libdb-4.1.so. This is because the library is not in your "lib" path. The easiest way to fix this is to create a link in your lib path that points to where the Berkeley install script put the libdb-4.1.so file. For Redhat this is:

    ln /usr/local/BerkeleyDB.4.1/lib/libdb-4.1.so /usr/lib/libdb-4.1.so

This will create a hard link. If /usr/local and /usr/lib are not on the same file system, create a symbolic link instead.

    ln -s /usr/local/BerkeleyDB.4.1/lib/libdb-4.1.so /usr/lib/libdb-4.1.so

Lastly run ldconfig to reconfigure the dynamic linker run-time bindings.

Now everything should work fine.