Translation(s): English - French


Introduction

Putting a DNS server on a network allows for the replacement of IP addresses of individual machines by a name. As a result, it's even possible to associate multiple names to the same machine to update the different available services. For example, www.example.com and pop.example.com, could both point to the primary server where the mail server and the business intranet reside, and the domain could be example.com. It's easy to remember that these two services are running on the same machine whose IP address is 192.168.0.1.

Now imagine that our network administrator decides for some reason or another to move the mail server to the machine 192.168.0.11. The only thing that has to be changed is the DNS server configuration file. You could always go and modify the host configuration for all the users, but that would be time consuming and inconvenient.

Definitions

Network Layout

We get internet access through an xxxbox (192.168.1.1), two DNS servers provided by our ISP (80.10.249.2, 80.10.246.129). In fact, these two latter servers will ever be referred to in the configuration because the xxxbox will be in charge of resolving names if the packet destination isn't known. Consequently, I consider the xxxbox like a primary server outside of our domain. The “sid” server (192.168.1.10) is connected to the xxxbox via its primary network card. It's also connected to the LAN (192.168.0.0/24) by its secondary network interface(192.168.0.1). It's on this that we are going to install the primary DNS server for our domain example.com (rfc2606) All the computers on the LAN are automatically assigned a single address by the DHCP service. The DHCP also provides the primary DNS server's address for our domain, and updates the host names for the zone example.com so they can be associated with an ip address.

Server Management

Installation

The package bind9 will be used for installation.

# apt-get install bind9 

and then if you want to also install the documentation (very useful):

# apt-get install bind9-doc

Configuration

After installation, you might want to get familiar with some of the configuration files. They are in the directory /etc/bind/

TSIG Signature

The purpose of this signature is to authenticate transactions with BIND. Thus, the DHCP server cannot update the example.com domain if it loses this key. Copy and paste an existing key

# cd /etc/bind/
# cat rndc.key
key "rndc-key" {
        algorithm hmac-md5;
        secret "QJc08cnP1xkoF4a/eSZZbw==";
};

# cp rndc.key ns-example-com_rndc-key

You can generate a new key with the following options:

dnssec-keygen -a HMAC-MD5 -b 512 -n USER ns-example-com_rndc-key
Kns-example-com_rndc-key.+157+53334

The footprint associated with the key is 53334. We get two files, one with an extension key and the other with a private extension. This substitutes the key in the file ns-example-com_rndc-key with the one in one of these two files.

# cat Kns-example-com_rndc-key.+157+53334.private
Private-key-format: v1.2
Algorithm: 157 (HMAC_MD5)
Key: LZ5m+L/HAmtc9rs9OU2RGstsg+Ud0TMXOT+C4rK7+YNUo3vNxKx/197o2Z80t6gA34AEaAf3F+hEodV4K+SWvA==
Bits: AAA=

# cat ns-example-com_rndc-key
key "ns-example-com_rndc-key" {
        algorithm hmac-md5;
        secret "LZ5m+L/HAmtc9rs9OU2RGstsg+Ud0TMXOT+C4rK7+YNUo3vNxKx/197o2Z80t6gA34AEaAf3F+hEodV4K+SWvA==";
};

The file ns-example-com_rndc-key should not be made world readable for security reasons. This should be inserted into the bind configuration by an include because the bind configuration itself is world-readable. Also, it's a good idea to delete the key and private files generated before.

File /etc/bind/named.conf

This file is the main configuration file for the DNS file.

// Managing acls
acl internals { 127.0.0.0/8; 192.168.0.0/24; };

// Load options
include "/etc/bind/named.conf.options";

// TSIG key used for the dynamic update
include "/etc/bind/ns-example-com_rndc-key";

// Configure the communication channel for Administrative BIND9 with rndc
// By default, they key is in the rndc.key file and is used by rndc and bind9
// on the localhost
controls {
        inet 127.0.0.1 port 953 allow { 127.0.0.1; };
};

// prime the server with knowledge of the root servers
zone "." {
        type hint;
        file "/etc/bind/db.root";
};

include "/etc/bind/named.conf.default-zones";
include "/etc/bind/named.conf.local";

Note : with Debian Jessie the 'zone "." {...}' part is inside the file "named.conf.default-zones". You don't need to add it in the file "named.conf".

File /etc/bind/named.conf.default-zones

Note: as of Debian 7 "Wheezy" bind9 ships with a file containing default forward, reverse, and broadcast zones.

// be authoritative for the localhost forward and reverse zones, and for
// broadcast zones as per RFC 1912
zone "localhost" {
        type master;
        file "/etc/bind/db.local";
};
zone "127.in-addr.arpa" {
        type master;
        file "/etc/bind/db.127";
};
zone "0.in-addr.arpa" {
        type master;
        file "/etc/bind/db.0";
};
zone "255.in-addr.arpa" {
        type master;
        file "/etc/bind/db.255";
};

File /etc/bind/named.conf.options

This file contains all the configuration options for the DNS server

options {
        directory "/var/cache/bind";

        // Exchange port between DNS servers
        query-source address * port *;

        // Transmit requests to 192.168.1.1 if
        // this server doesn't know how to resolve them
        forward only;
        forwarders { 192.168.1.1; };

        auth-nxdomain no;    # conform to RFC1035

        // From 9.9.5 ARM, disables interfaces scanning to prevent unwanted stop listening
        interface-interval 0;
        // Listen on local interfaces only(IPV4)
        listen-on-v6 { none; };
        listen-on { 127.0.0.1; 192.168.0.1; };

        // Do not transfer the zone information to the secondary DNS
        allow-transfer { none; };

        // Accept requests for internal network only
        allow-query { internals; };

        // Allow recursive queries to the local hosts
        allow-recursion { internals; };

        // Do not make public version of BIND
        version none;
};

The port associated with the query-source option must not in any case be frozen because it jeopardizes the DNS transactions in the case of a resolver.

M. Rash wrote an interesting article about this and how to force the source port randomly via the iptables: Mitigating DNS Cache Poisoning Attacks with iptables

To reduce the delay timeout for UDP connections, and thus highlight the randomization, which by default is 30s by tuple, simply update the parameter net.netfilter.nf_conntrack_udp_timeout

# sysctl -w net.netfilter.nf_conntrack_udp_timeout=10

to get timeout of 10s.

File /etc/bind/named.conf.local

This file contains the local DNS server configuration, and this is where you declare the zones associated with this server's domain(s).

// Manage the file logs
include "/etc/bind/named.conf.log";

// Domain Management example.com
// ------------------------------
//  - The server is defined as the master on the domain.
//  - There are no forwarders for this domain.
//  - Entries in the domain can be added dynamically
//    with the key ns-example-com_rndc-key
zone "example.com" {
        type master;
        file "/var/lib/bind/db.example.com";
        //forwarders {};
        // If we do not comment the ''forwarders'' "empty" clients of the local subnet in my case don't have access to the upstream DNS ?
        //allow-update { key ns-example-com_rndc-key; };
        allow-update { key rndc-key; };
        //confusion between the file name to import (ns-example-com_rndc-key) and the key label (rndc-key) ?
};
zone "0.168.192.in-addr.arpa" {
        type master;
        file "/var/lib/bind/db.example.com.inv";
        //see comment below (zone "example.com")
        //forwarders {};
        //allow-update { key ns-example-com_rndc-key; };
        allow-update { key rndc-key; };
};

// Consider adding the 1918 zones here, if they are not used in your
// organization
include "/etc/bind/zones.rfc1918";

NOTE: if you create a local non-FQDN and call it .local it clashes with some other packages (which?). Edit /etc/nsswitch.conf and move dns right after the files on the host line makes .local domains work.

File /etc/bind/named.conf.log

With Debian Jessie, you need to create this file in /etc/bind

logging {
        channel update_debug {
                file "/var/log/update_debug.log" versions 3 size 100k;
                severity debug;
                print-severity  yes;
                print-time      yes;
        };
        channel security_info {
                file "/var/log/security_info.log" versions 1 size 100k;
                severity info;
                print-severity  yes;
                print-time      yes;
        };
        channel bind_log {
                file "/var/log/bind.log" versions 3 size 1m;
                severity info;
                print-category  yes;
                print-severity  yes;
                print-time      yes;
        };

        category default { bind_log; };
        category lame-servers { null; };
        category update { update_debug; };
        category update-security { update_debug; };
        category security { security_info; };
};

Here we define different log methods for the different categories. The first category is, as its name indicates the default category that is usually assigned to syslog. All categories not mentioned, are similar to the default category. For a list of the different categories, see the bind9 administrator reference manual. In terms of blade-servers, it ignores all the logs associated with them. It may be necessary to create /var/log in the chroot later.

Resource Records (RR)

DNS is made up of several registrations, RR or Resource Records, defining the various domain information. The first is dedicated to name resolution, in our case, it is the file db.example.com. The second will be used for reverse name resolution, it is the file db.example.com.inv.

Files in /var/lib/bind/

$TTL    3600
@       IN      SOA     sid.example.com. root.example.com. (
                   2007010401           ; Serial
                         3600           ; Refresh [1h]
                          600           ; Retry   [10m]
                        86400           ; Expire  [1d]
                          600 )         ; Negative Cache TTL [1h]
;
@       IN      NS      sid.example.com.
@       IN      MX      10 sid.example.com.

sid     IN      A       192.168.0.1
etch    IN      A       192.168.0.2

pop     IN      CNAME   sid
www     IN      CNAME   sid
mail    IN      CNAME   sid

@       IN      SOA     sid.example.com. root.example.com. (
                   2007010401           ; Serial
                         3600           ; Refresh [1h]
                          600           ; Retry   [10m]
                        86400           ; Expire  [1d]
                          600 )         ; Negative Cache TTL [1h]
;
@       IN      NS      sid.example.com.

1       IN      PTR     sid.example.com.
2       IN      PTR     etch.example.com.

Some Explanations

In the first example, we can see the directive $TTL (Time To Live), which expresses the duration (in seconds) validity, by default, of the information contained in the RRs. Once this time expires, it is necessary to recheck the data.

Then, we have each RR specified with its type. Some examples are:

For a complete list, please refer to the iana list

The classes in the association determines the Internet class. Other classes are available (CH and HS). For more information please consult the rfc1035

/etc/resolv.conf File

search example.com

It's no more complicated than that !

Bind Chroot

Debian Wheezy and earlier

The named daemon is started using the bind user by default.

This option is found in the bind service config file /etc/default/bind9

OPTIONS="-u bind"

The bind start script /etc/init.d/bind9 reads this config file when the service is started.

Starting bind as a non root user is good practice but to run the daemon in a chroot environment we also need specify the chroot directory. This is done using the same OPTIONS variable in /etc/default/bind9.

To begin, start by stopping the bind service:

/etc/init.d/bind9 stop

Then edit /etc/default/bind9:

OPTIONS="-u bind -t /var/bind9/chroot"

If bind refuses to start with error messages like "network unreachable resolving: " followed by a host and an IPv6 address, then you might add argument "-4" to force bind to always use IPv4 instead of IPv6:

OPTIONS="-u bind -4 -t /var/bind9/chroot"

Now create the chroot directory structure:

mkdir -p /var/bind9/chroot/{etc,dev,var/cache/bind,var/run/named}

Create the required device special files and set the correct permissions:

mknod /var/bind9/chroot/dev/null c 1 3
mknod /var/bind9/chroot/dev/random c 1 8
mknod /var/bind9/chroot/dev/urandom c 1 9
chmod 660 /var/bind9/chroot/dev/{null,random,urandom}

Move the current config directory into the new chroot directory:

mv /etc/bind /var/bind9/chroot/etc

Now create a symbolic link in /etc for compatibility:

ln -s /var/bind9/chroot/etc/bind /etc/bind

If you want to use the local timezone in the chroot (e.g. for syslog):

cp /etc/localtime /var/bind9/chroot/etc/

Change the ownership on the files you've just moved over and the rest of the newly created chroot directory structure:

chown bind:bind /var/bind9/chroot/etc/bind/rndc.key
chmod 775 /var/bind9/chroot/var/{cache/bind,run/named}
chgrp bind /var/bind9/chroot/var/{cache/bind,run/named}

Edit the PIDFILE variable in /etc/init.d/bind9 to the correct path:

PIDFILE=/var/bind9/chroot/var/run/named/named.pid

Finally tell rsyslog to listen to the bind logs in the correct place:

echo "\$AddUnixListenSocket /var/bind9/chroot/dev/log" > /etc/rsyslog.d/bind-chroot.conf

Restart rsyslog and start bind:

/etc/init.d/rsyslog restart; /etc/init.d/bind9 start

Debian Jessie and later

The named daemon is started using the bind user by default.

Create the file /etc/systemd/system/bind9.service with options "-t /var/bind9/chroot":

[Unit]
Description=BIND Domain Name Server
Documentation=man:named(8)
After=network.target

[Service]
ExecStart=/usr/sbin/named -f -u bind -t /var/bind9/chroot
ExecReload=/usr/sbin/rndc reload
ExecStop=/usr/sbin/rndc stop

[Install]
WantedBy=multi-user.target

However, at least by Debian 9 stretch, one could use the package maintainer's version of the systemd unit file, and add the chroot overrides in: /etc/systemd/system/bind9.service.d/bind9.conf (or setting one's chroot dir accordingly), e.g.:

[Service]
UMask=027
ExecStart=
ExecStart=/usr/sbin/named -f -u bind -t /var/bind9/chroot

However, at least as of Debian 10 buster, it's probably better to remove such a /etc/systemd/system/bind9.service.d/bind9.conf file (as the manner in which systemd now starts bind9's named, has changed, and will typically conflict with override done as the above), and now is best to have the overrides in /etc/default/bind9, e.g.:

OPTIONS="-u bind -t /var/bind9/chroot"

and systemd will now incorporate the OPTIONS from /etc/default/bind9 and use those (as will at least also sysvinit).

Update the symlink to the unit file with:-

systemctl reenable bind9

Also advised to run:

systemctl daemon-reload

for systemd (default) systems, to pick up any changes to systemd configuration files.

Now create the chroot directory structure:

mkdir -p /var/bind9/chroot/{etc,dev,run/named,var/cache/bind}

Create the required device special files and set the correct permissions:

mknod /var/bind9/chroot/dev/null c 1 3
mknod /var/bind9/chroot/dev/random c 1 8
mknod /var/bind9/chroot/dev/urandom c 1 9
chmod 666 /var/bind9/chroot/dev/{null,random,urandom}

Move the current config directory into the new chroot directory:

mv /etc/bind /var/bind9/chroot/etc

Now create a symbolic link in /etc for compatibility:

ln -s /var/bind9/chroot/etc/bind /etc/bind

If you want to use the local timezone in the chroot (e.g. for syslog):

cp /etc/localtime /var/bind9/chroot/etc/

Change the ownership on the files you've just moved over and the rest of the newly created chroot directory structure:

chown bind:bind /var/bind9/chroot/etc/bind/rndc.key
chown bind:bind /var/bind9/chroot/run/named
chmod 775 /var/bind9/chroot/{var/cache/bind,run/named}
chgrp bind /var/bind9/chroot/{var/cache/bind,run/named}

Starting with Buster, AppArmor is enabled by default on Debian, which requires to add the following 4 lines to /etc/apparmor.d/local/usr.sbin.named:

/var/bind9/chroot/etc/bind/** r,
/var/bind9/chroot/var/** rw,
/var/bind9/chroot/dev/** rw,
/var/bind9/chroot/run/** rw,
/var/bind9/chroot/usr/** r,

Without that change, bind would terminate immediately on startup with error message "open: /etc/bind/named.conf: permission denied". To make these AppArmor changes effective:

systemctl reload apparmor

Also, additionally for Debian 10 Buster, /usr/share/dns is also needed under the chroot.

Finally tell rsyslog to listen to the bind logs in the correct place:

echo "\$AddUnixListenSocket /var/bind9/chroot/dev/log" > /etc/rsyslog.d/bind-chroot.conf

Restart rsyslog and start bind:

systemctl restart rsyslog
systemctl restart bind9

Also, alternative chroot approach to copying many files, etc., and more compatible for interacting utilities, etc. outside of chroot. One can relocate some directory(/ies), create some directories/files as/where needed, and use bind mounts, e.g.: included in /etc/fstab:

/dev/null /var/lib/named/dev/null none bind 0 0
/dev/random /var/lib/named/dev/random none bind 0 0
/run/named /var/lib/named/run/named none bind 0 0
/usr/share/dns /var/lib/named/usr/share/dns none bind 0 0

and we then also have:

$ ls -ld /etc/bind
lrwxrwxrwx 1 root root 25 Mar 15  2014 /etc/bind -> ../var/lib/named/etc/bind
$

in fact it's possible to set up a configuration that not only works within chroot, but also works without using chroot - only changing how bind9/named is invoked, and nothing else, and between symbolic links and bind mounts, utilities outside the chroot will also interact with bind fine, "as if" it were outside the chroot - as they find the needed bind components logically in the same place, even though most are physically within the chroot stucture (and some, via bind mounts, are outside of the chroot and equally accessible inside and outside the chroot).

Debian Bookworm

Additionally to the description for Debian Jessie, proper systemd and journald support will require additional steps, because systemd never gets a "successfully started" feedback from bind9 and will mark the service as failed.

You will need to extend /etc/systemd/system/bind9.service.d/bind9.conf by

ExecStartPre=/usr/bin/mount --bind /run/systemd/journal/socket /var/bind9/chroot/run/systemd/journal/socket
ExecStartPre=/usr/bin/mount --bind /run/systemd/journal/stdout /var/bind9/chroot/run/systemd/journal/stdout
ExecStartPre=/usr/bin/mount --bind /run/systemd/notify /var/bind9/chroot/run/systemd/notify
ExecStopPost=/usr/bin/umount /var/bind9/chroot/run/systemd/journal/socket /var/bind9/chroot/run/systemd/journal/stdout /var/bind9/chroot/run/systemd/notify

or do the same via /etc/fstab.

You will need to create these directories

/var/bind9/chroot/run/systemd
/var/bind9/chroot/run/systemd/journal

and you will need to create these empty files

/var/bind9/chroot/run/systemd/journal/socket
/var/bind9/chroot/run/systemd/journal/stdout
/var/bind9/chroot/run/systemd/notify

The files may created with touch. Permissions can be strict or loose and ownership does not matter as these files will be bind-mounted and inherit their permissions and ownership.

Finally, bind9 should startup after issuing

systemctl daemon-reload
systemctl restart bind9

Client Manage

As I mentioned at the beginning, the assignment of IP addresses on the LAN is performed by the DHCP server. Thus, to set our DNS server to different clients, it is necessary to add the DHCP configuration file the following two lines:

option domain-name "example.com"

option domain-name-server sid.example.com

It must be added to the file (I think) the areas for which DHCP should automatically perform updates.

Syntax (everything after "=>" is my comments) :

zone [name.of.the.zone.] {

}

Examples de [name.of.the.zone.] (with the "." at the end) :

- example.com. : for the direct zone of this article,

- 0.168.192.in-addr.arpa. : for the inverse zone of this article.

For more information on the implementation of dynamic update of DNS records through DHCP is here

Testing tools

Links and Resources

BIND 9 Documentation

BIND9 documentation:
If one has the bind9-doc package installed:
/usr/share/doc/bind9-doc/arm/
/usr/share/doc/bind9-doc/arm/Bv9ARM.html
or from ISC.org (upstream):
An Overview of BIND 9 Documentation (be sure to use corresponding version, and realize there may be some Debian differences).

DNSSEC

see: DNSSEC Howto for BIND 9.9+


CategorySoftware CategoryNetwork