3. Base configuration

Now that we have a working knowledge of the Domain Name System architecture, it's time to move from theory to practice and set up our first domain name server.

This is the overall layout of the network in which our name servers will be placed. It is a very simple network, made up of:

All of our systems will belong to the "kernel-panic.it" zone and our first DNS server will be the primary master name server for that zone; it will reside in the DMZ and answer internal queries for Internet and DMZ servers' names.

3.1 The main configuration file

Bind configuration takes place in named.conf(5), which is, by default, located in /var/named/etc/. You can, however, specify an alternate path using the -c flag of the named(8) command.

The configuration syntax is rather simple: it is a series of statements enclosed in curly braces and terminated with a semi-colon. Statements contain a variable number of semi-colon terminated clauses, in keyword/value form. Supported comment styles are:

The "options" statement defines global options to be used by Bind. The "directory" clause specifies the directory against which subsequent relative paths should be resolved. The default values are retained for unspecified clauses. E.g.:

options {
    # Bind runs chrooted to "/var/named/", hence "/" actually is "/var/named/"
    directory       "/";
};

The "zone" statements tell Bind what zones it is authoritative for; for each zone, the "type" clause specifies whether the server is a master or a slave for it and the "file" clause specifies the path to the corresponding zone data file. E.g.:

zone "kernel-panic.it" {
    type            master;
    file            "master/db.kernel-panic.it";
};

The names of the zone data files are free-form, but it's highly recommended to follow a reasonable naming convention to make maintenance easier. For instance, zone data files are often called db.domain.

In order to allow for reverse name resolution, we also need to create zone data files for each network:

zone "240.16.172.in-addr.arpa" {
    type            master;
    file            "master/db.172.16.240";
};

zone "250.16.172.in-addr.arpa" {
    type            master;
    file            "master/db.172.16.250";
};

zone "3.2.1.in-addr.arpa" {
    type            master;
    file            "master/db.1.2.3";
};

The name server will also need to map the loopback address to a name. Therefore, we will have to create specific zone data files for the "localhost" zone and the 127.0.0.0/8 network:

zone "localhost" {
    type            master;
    file            "master/db.localhost";
};

zone "127.in-addr.arpa" {
    type            master;
    file            "master/db.127";
};

[RFC1912] also recommends that the "255.in-addr.arpa" and "0.in-addr.arpa" zones always be present in nameserver configurations to either provide nameservice for "special" addresses, or to help eliminate accidental queries for broadcast or local address to be sent off to the root nameservers:

zone "255.in-addr.arpa" {
    type            master;
    file            "master/db.255";
};

zone "0.in-addr.arpa" {
    type            master;
    file            "master/db.0";
};

Finally, if the name server must be able to resolve Internet names, we have to give it the list of the root name servers, which is specified using a hint zone.

zone "." {
    type            hint;
    file            "master/root.hint";
};

You can find a copy of the root.hint file in the /var/named/etc directory.

3.2 The zone data files

Zone data files contain information about the zones the server is authoritative for, and, according to our configuration, they will be placed in the /var/named/master/ directory.

Usually, the first line of a zone data file sets the default TTL for the zone, i.e. how long other DNS servers and applications are allowed to cache the record.

$TTL   3h

A zone data file may contain multiple $TTL statements: each applies to all subsequent records (that don't have an explicit TTL) until a new $TTL statement is found. You may want to tweak this value to find a good trade-off between bandwidth usage and data freshness.

The next entry in a zone data file is the SOA record, which indicates that the name server is authoritative for that zone.

@ IN SOA dns1.kernel-panic.it. danix.kernel-panic.it. (
    2007020601 ; serial
    3h         ; refresh after 3 hours
    1h         ; retry after 1 hour
    1w         ; expire after 1 week
    1h )       ; negative caching TTL of 1 hour

Let's examine it in detail. The "@" symbol represents the zone the server is authoritative for; well, to be more precise, it represents the origin of the data in the zone data file, which, by default, is the same as the zone's domain name. The origin is appended to all names in the zone data file that don't end with a trailing dot and can be modified with the $ORIGIN statement.

IN is the class of the record (Internet). SOA is the record type (Start Of Authority). "dns1.kernel-panic.it." is the name of the primary master name server for this zone and "danix.kernel-panic.it." is the mail address of the zone administrator, with the "@" replaced with a dot (therefore, the actual address would be "danix@kernel-panic.it").

Now we come to the numbers enclosed within brackets (brackets simply allow the record to span across multiple lines) (note that comments, in zone data files, start with a semicolon and finish at the end of the line). The serial number is a progressive number that must be increased whenever zone data is updated or slave name servers won't notice that data has changed (according to [RFC1912], the recommended format for the serial number is "YYYYMMDDnn", where "nn" is the revision number). The refresh value sets how often slave name servers should check that their zone data is up to date. If the master is unreachable, the retry and expire values tell slaves at what interval to attempt to connect again and after how long to stop giving out data about the zone. The last value is the time to live for negative responses from the name servers authoritative for the zone.

Next, every zone data file has one or more NS records, specifying the name servers authoritative for the zone.

kernel-panic.it.    IN NS       dns1.kernel-panic.it.
kernel-panic.it.    IN NS       dns2.kernel-panic.it.

The first field of a resource record is its name and must start on the first column; if omitted, it defaults to the previous one. Therefore, the above NS records can be shortened as:

                    IN NS       dns1.kernel-panic.it.
                    IN NS       dns2.kernel-panic.it.

The MX record allows you to specify the host that will manage mail for the domain name; this record has an extra parameter, a 16-bit integer indicating the mail exchanger's priority (the lower the number, the higher the priority).

                    IN MX    0  mail.kernel-panic.it.
                    IN MX   10  mail.provider.com.

The next record, "A", is specific to forward-mapping zone data files, since it associates domain names with their IP address.

mail                IN A        172.16.240.150
proxy               IN A        172.16.240.151
www1                IN A        172.16.240.152
www2                IN A        172.16.240.153
dns1                IN A        172.16.240.154
dns2                IN A        172.16.240.155

mickey              IN A        172.16.0.200
                    IN A        172.16.240.200
minnie              IN A        172.16.0.201
                    IN A        172.16.240.201

router              IN A        172.16.250.1
                    IN A        1.2.3.4
[...]

The CNAME record maps an alias to its canonical name; in other words, it defines a domain name pointing to another node of the domain name space.

antivirus           IN CNAME    mail
cache               IN CNAME    proxy

Ok, we're done with forward-mapping; let's have a look at the reverse-mapping zone data files. The beginning is exactly the same: you set the default TTL and insert the SOA and NS records that we've seen before. Next come the PTR records, which map addresses to host names; well, to be more precise, they map names in the in-addr.arpa domain to names in the kernel-panic.it domain. Again, the origin is automatically appended to all domain names that don't end with a trailing dot, allowing you to specify only the last octet(s) of the IP addresses.

/var/named/master/db.172.16.240
$TTL 3h

@ IN SOA dns1.kernel-panic.it. danix.kernel-panic.it. (
    2007020601 ; serial
    3h         ; refresh after 3 hours
    1h         ; retry after 1 hour
    1w         ; expire after 1 week
    1h )       ; negative caching TTL of 1 hour

                    IN NS       dns1.kernel-panic.it.
                    IN NS       dns2.kernel-panic.it.

100                 IN PTR      donald.kernel-panic.it.
101                 IN PTR      daisy.kernel-panic.it.
102                 IN PTR      fw-ext.kernel-panic.it.
150                 IN PTR      mail.kernel-panic.it.
151                 IN PTR      proxy.kernel-panic.it.
152                 IN PTR      www1.kernel-panic.it.
153                 IN PTR      www2.kernel-panic.it.
154                 IN PTR      dns1.kernel-panic.it.
155                 IN PTR      dns2.kernel-panic.it.
200                 IN PTR      mickey.kernel-panic.it.
201                 IN PTR      minnie.kernel-panic.it.
202                 IN PTR      fw-int.kernel-panic.it.

To recap, here are the complete zone data files.

3.3 Starting Bind

Running Bind is as simple as typing "named". The first time, you may want to run it with the -g flag, which runs the server in the foreground and forces all logging to stderr.

# named -g
10-Nov-2013 18:17:44.897 starting BIND 9.4.2-P2 -g
10-Nov-2013 18:17:44.907 loading configuration from '/etc/named.conf'
10-Nov-2013 18:17:44.910 listening on IPv6 interfaces, port 53
Binding privsep
[...]
10-Nov-2013 18:17:45.494 running

You will probably be warned that the name server couldn't find the file /etc/rndc.key: don't worry about this yet, we will discuss rndc(8) in a moment. In case named(8) complains about syntax errors, you can use the named-checkconf(8) and named-checkzone(8) commands to check the syntax of the Bind configuration file and the zone data files respectively.

If everything looks alright, you can test your fresh new name server with nslookup(1) or dig(1).

$ nslookup mail.kernel-panic.it 127.0.0.1
Server:         127.0.0.1
Address:        127.0.0.1#53

Name:   mail.kernel-panic.it
Address: 172.16.240.150

$

To start Bind on system boot, simply add the following line to the /etc/rc.conf.local(8) file:

/etc/rc.conf.local
named_flags=""

3.4 rndc(8)

The rndc(8) utility allows you to communicate with the name server and send it authenticated commands over a TCP connection. It reads its configuration from the rndc.conf(5) file (by default in /var/named/etc/), which has a syntax similar to named.conf(5). The following is a sample configuration file to connect to the server at localhost:

/var/named/etc/rndc.conf
options {
    default-server  localhost;
    default-port    953;
    default-key     "rndc-key";
};

server localhost {
    key             "rndc-key";
};

key "rndc-key" {
    algorithm       hmac-md5;
    secret          "jIpKqniOSfP7Nr5GTTyDkw==";
};

To make the name server accept rndc(8) connections, just add the following lines to your named.conf(5) file (adjusting the allow list as needed):

/var/named/etc/named.conf
key "rndc-key" {
    algorithm       hmac-md5;
    secret          "jIpKqniOSfP7Nr5GTTyDkw==";
};

controls {
    inet            127.0.0.1 port 953
                    allow { 127.0.0.1; }
                    keys { "rndc-key"; };
};

If you like things simple, you can generate the rndc(8) configuration file automatically, by using the rndc-confgen(8) utility. A typical usage for rndc(8) is to force Bind to reload its configuration file and zones:

# rndc -c /var/named/etc/rndc.conf reload
server reload successful

3.5 Adding a slave name server

Now that your primary master name server runs fine, you may want to set up a slave name server to allow for redundancy and load sharing. Bind configuration is quite similar:

/var/named/etc/named.conf
options {
    directory       "/";
};

zone "kernel-panic.it" {
    type            slave;
    masters         { 172.16.240.154; };
    file            "slave/bak.kernel-panic.it";
};

zone "240.16.172.in-addr.arpa" {
    type            slave;
    masters         { 172.16.240.154; };
    file            "slave/bak.172.16.240";
};

zone "250.16.172.in-addr.arpa" {
    type            slave;
    masters         { 172.16.240.154; };
    file            "slave/bak.172.16.250";
};

zone "3.2.1.in-addr.arpa" {
    type            slave;
    masters         { 172.16.240.154; };
    file            "slave/bak.1.2.3";
};

# Loopback address
zone "localhost" {
    type            master;
    file            "master/db.localhost";
};

zone "127.in-addr.arpa" {
    type            master;
    file            "master/db.127";
};

# Special zones
zone "255.in-addr.arpa" {
    type            master;
    file            "master/db.255";
};

zone "0.in-addr.arpa" {
    type            master;
    file            "master/db.0";
};

# Root zone
zone "." {
    type            hint;
    file            "master/db.cache";
};

For all the zones the slave name server is authoritative for (except for the loopback address and the "special" zones) type is now slave. We also had to add the masters clause to tell Bind the address of the primary master name server(s). The file specified in a slave zone is where Bind will store data transferred from the master; this allows Bind to have a local copy of the data in case the master name server is unreachable at startup.