31. Install BIND

by Double Bastion - Updated March 8, 2022

As mentioned before, you can use the DNS services offered by your registrar or by your hosting provider, because this will allow you to avoid installing and maintaining your own BIND servers.

However, if neither your registrar or your hosting provider offer free DNS services and you don’t want to use Hurricane Electric’s free DNS services, or if you insist on having full control over your DNS servers, then you can install and maintain BIND on two (or more) of your servers, as we’ll describe below.

In order to install BIND, you must have at least two servers, each with its own IP and preferably in different geographic locations: one will host the master DNS server and the other will host the slave DNS server. Of course, you can have two, three and even more slave DNS servers, if you want, for redundancy purposes, but one master and one slave server is the minimum. All the slave DNS servers will be configured like the one we’ll present below, so if you know how to install a master and a slave BIND server, you will know how to configure a master and two slaves, three slaves, etc.

The following operations have to be performed both on the master and the slave server:

apt-get update
apt-get dist-upgrade
apt-get install bind9 bind9utils bind9-doc dnsutils

Check version number:

named -v
BIND 9.16.22-Debian (Extended Support Version) <id:59bfaba>

Check if it’s running:

systemctl status named

● bind9.service - BIND Domain Name Server
   Loaded: loaded (/lib/systemd/system/bind9.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2020-09-30 16:18:23 EDT; 4min 9s ago
     Docs: man:named(8)
 Main PID: 29965 (named)
    Tasks: 4 (limit: 3569)
   Memory: 14.1M
   CGroup: /system.slice/bind9.service
           └─29965 /usr/sbin/named -u bind

Enable auto-start at boot time:

systemctl enable named

The BIND server runs as the bind user, created during installation, and listens on port 53 over TCP and UDP, so, open port 53 with ufw by running:

ufw allow 53

You can see the port on which BIND listens with:

netstat -lnptu | grep named

The BIND daemon is called named. There is an important binary called rndc (remote name daemon controller). The rndc binary is used to reload, stop and control different aspects of the BIND daemon. Communication is done over TCP port 953 internally, so you don’t have to open port 953 to the public.

You can check the status of the BIND server by running:

rndc status

The result will look similar to this:

version: BIND 9.16.22-Debian (Extended Support Version) <id:59bfaba>
running on mail.example.com: Linux x86_64 5.10.0-10-amd64 #1 SMP Debian 5.10.84-1 (2021-12-08)
boot time: Thu, 23 Dec 2021 20:04:30 GMT
last configured: Thu, 23 Dec 2021 20:04:30 GMT
configuration file: /etc/bind/named.conf
CPUs found: 1
worker threads: 1
UDP listeners per interface: 1
number of zones: 102 (97 automatic)
debug level: 0
xfers running: 0
xfers deferred: 0
soa queries in progress: 0
query logging is OFF
recursive clients: 0/900/1000
tcp clients: 0/150
TCP high-water: 0
server is up and running

When it is installed, BIND provides recursive search for localhost and the local network. Since you are setting up an authoritative DNS server, you have to disable recursion. Make a copy of the original /etc/bind/named.conf.options file:

cp /etc/bind/named.conf.options /etc/bind/named.conf.options_orig

Open the /etc/bind/named.conf.options file for editing:

nano /etc/bind/named.conf.options

Add the following lines in the options clause, right before the closing bracket:

 // hide version number from clients for security reasons.
 version "not available";

 // disable recursion on authoritative DNS server.
 recursion no;

 // enable the query log
 querylog yes;

 // disallow zone transfer
 allow-transfer { none; };

 // limit response rate to prevent DDOS attacks
 rate-limit {
   responses-per-second 10;
 };

In the same file, also check if you have the following line, which enables IPv6:

listen-on-v6 { any; };

The rate-limit {} clause limits the number of queries a server can send to BIND, in order to prevent DDOS attacks.

Restart BIND:

systemctl restart named

By default BIND logs data to /var/log/syslog . This is done in the absence of the logging {} clause in /etc/bind/named.conf . The logging {} clause can be used to configure BIND to write log data to a specific file, as explained further down below, in order to be able to use Fail2ban to block offending IPs.

31.1. Configure automatic BIND restart

When encountering an inconsistent state, BIND stops. This is an intentional process termination implemented for security reasons. Since BIND provides a service that is so important, it’s recommended to implement a method to restart it automatically once it exits for any reason. To do this, you need to edit the service file /lib/systemd/system/named.service in a way that will preserve the modifications during future updates. Thus run the command:

systemctl edit named.service

In the new open file, right below these two lines:

### Editing /etc/systemd/system/named.service.d/override.conf
### Anything between here and the comment below will become the new contents of the file

add the following lines:

[Service]
Restart=always

The systemctl edit named.service command will create the /etc/systemd/system/named.service.d directory and will place the override.conf file inside it. In this way, the directives contained in the override.conf file will override those in the /lib/systemd/system/named.service file.

Next run:

systemctl daemon-reload
systemctl restart named

From now on, if you run systemctl status named, you will see something like this:

● named.service - BIND Domain Name Server
     Loaded: loaded (/lib/systemd/system/named.service; enabled; vendor preset: enabled)
    Drop-In: /etc/systemd/system/named.service.d
             └─override.conf

All the configurations presented above have to be applied both on the master and the slave server. The configurations that follow have to be applied only on the specified server: master or slave.

31.2. Configure the master DNS server

The master DNS server is the server where the master copy of the zone file is stored. Changes of the DNS records are made on this server. A domain can have one or multiple DNS zones. Each DNS zone has a zone file which contains all the DNS records for that zone. In this case we’ll use a single DNS zone to manage all the DNS records for a domain name.

The /etc/bind/named.conf.default-zones file defines the root zone and localhost zone.

To add a zone for a domain name, let’s say example.com, edit the /etc/bind/named.conf.local file:

nano /etc/bind/named.conf.local

Add the following lines to the bottom of this file:

zone "example.com" {
      type master;
      file "/etc/bind/db.example.com";
      notify yes;
      allow-transfer { 1.2.3.4; };
};

Replace example.com with the domain for which you create the DNS records and 1.2.3.4 with the IP address of the slave DNS server. If you have multiple slave DNS servers, write their IPs folowed by a semicolon and space, one after the other, like this:

allow-transfer { 1.2.3.4; 12.12.12.12; 23.23.23.23; };

In the configuration from above, you created a new zone with the zone clause and you specified that this is the master zone. The zone file is /etc/bind/db.example.com, where you will add the DNS records. Zone transfer will only be allowed to the slave DNS server.

Please note that you’ll have to add a configuration block similar to the one presented above, for every domain that you want to add to BIND. The zone blocks should be added one below the other, like this:

zone "example.com" {
      type master;
      file "/etc/bind/db.example.com";
      notify yes;
      allow-transfer { 1.2.3.4; };
};

zone "secondsite.net" {
      type master;
      file "/etc/bind/db.secondsite.net";
      notify yes;
      allow-transfer { 1.2.3.4; };
};

Instead of creating a zone file from scratch, you can use a zone template file. Copy the content of db.empty to a new file:

cp /etc/bind/db.empty /etc/bind/db.example.com

There are 3 types of entries that a zone file can contain:

  • Comments: they start with a semicolon (;).
  • Directives: they start with a dollar sign ($).
  • Resource Records: DNS records. In general, a zone file consists of the following types of DNS records:
  • The SOA (Start of Authority) record: defines the key characteristics of a zone. It’s the first DNS record in the zone file and is mandatory.
  • NS (Name Server) record: specifies which servers are used to store DNS records and answer DNS queries for a domain name. There must be at least two NS records in a zone file.
  • MX (Mail Exchanger) record: specifies which hosts are responsible for email delivery for a domain name.
  • A (Address) record: Converts DNS names into IPv4 addresses.
  • AAAA (Quad A) record: Converts DNS names into IPv6 addresses.
  • CNAME record (Canonical Name): It’s used to create aliases for DNS names.
  • TXT record: SPF, DKIM, DMARC, etc.

Next, open the new zone file:

nano /etc/bind/db.example.com

Edit this file to make it look like this:

; Zone file for example.com

$TTL    86400  ; default TTL for this zone (1 day)
$ORIGIN example.com. ; base domain name

; Start of Authority record

@       IN      SOA     ns1.example.com. hostmaster.example.com. (
                     2020100282         ; Serial. You must update it when this file is changed.The format is: yyyymmddxx, where xx is 01 for the first change on that day, 02 for the second >
                          21600         ; Refresh
                           7200         ; Retry
                        2419200         ; Expire
                          86400 )       ; Negative Cache TTL

; Name servers for this domain
@       IN      NS      ns1.example.com.
@       IN      NS      ns2.example.com.

; A records
ns1     IN      A       123.123.123.123
ns2     IN      A       1.2.3.4
@       IN      A       123.123.123.123
www     IN      A       123.123.123.123


; AAAA records
ns1     IN      AAAA    2000:2000:2000:2000::ec12
ns2     IN      AAAA    1000:1000:1000:1000::da43
@       IN      AAAA    2000:2000:2000:2000::ec12
www     IN      AAAA    2000:2000:2000:2000::ec12


; Mail servers for this domain
@       IN      MX      mail.example.com.

; CNAME records

; TXT records (SPF, DKIM, DMARC, etc.)

where 123.123.123.123 is the public IPv4 address of the master server and 1.2.3.4 is the public IPv4 address of the slave server. Similary, 2000:2000:2000:2000::ec12 is the public IPv6 address of the master server and 1000:1000:1000:1000::da43 is the public IPv6 address of the slave server.

Below is a description of the parameters used:

  • The $TTL parameter defines the default Time to Live value for the zone, which is the time a DNS record can be cached on a DNS resolver. Time is specified in seconds. This directive is obligatory.
  • The $ORIGIN parameter defines the base domain.
  • Domain names must end with a dot (.), which is the root domain. The typical format of a fully qualified domain name (FQDN) is with a dot at the end.
  • The @ symbol references the base domain; it functions like a placeholder for the base domain.
  • IN is the DNS class. It stands for Internet. There are other DNS classes, but they are rarely used.

The first record of a zone file should be the SOA (Start of Authority) record. This record contains the following data:

  • The primary DNS server (ns1.example.com).
  • Email address of the zone administrator. The RFC 2142 standard recommends that the email address should be hostmaster@example.com. In the zone file, this email address takes the form: hostmaster.example.com. because the @ sign has special meaning in a zone file.
  • Zone serial number. The serial number is a way in which the slave DNS server can track changes to the zone. The serial number has the format: yyyymmddxx, where yyyy is the four-digit year number, mm is the month, dd is the day, and xx records the number of changes on that day (xx is 01 for the first change on that day, 02 for the second change, 03 for the third change, etc.) You have to update the serial number each time you make changes to the zone file (if this is not done automatically, as we’ll explain later).
  • Refresh value. When the refresh time is reached, the slave DNS server tries to read the SOA record from the master DNS server. If it notices that the serial number is higher, it initiates a zone transfer.
  • Retry value. Defines the retry interval (in seconds) if the slave DNS server fails to connect to the master DNS server.
  • Expiry. If the slave DNS server has been failing to connect to the master DNS server for this interval of time, the slave will stop responding to DNS queries for this zone.
  • Negative cache TTL. Defines the “time to leave” value of DNS responses for non-existent DNS names.

TXT records can be enclosed in double quotes. DKIM records have to be enclosed with round brackets.

You can check if there are syntax errors in the main configuration file by running:

named-checkconf

If you have more than one slave server, you will need to add records similar to the ones for ns2, for each additional slave server (ns3, ns4, etc.)

You can check the syntax of a zone file by running:

named-checkzone example.com /etc/bind/db.example.com

If there are no errors, restart BIND:

systemctl restart named

If you host the following domains: example.com, secondsite.net, thirdsite.info, fourthsite.org, fifthsite.us, each domain’s zone file will mention the following name servers, respectively:

ns1.example.com
ns2.example.com

ns1.secondsite.net
ns2.secondsite.net

ns1.thirdsite.info
ns2.thirdsite.info

ns1.fourthsite.org
ns2.fourthsite.org

ns1.fifthsite.us
ns2.fifthsite.us

31.3. Configure the slave DNS server

Next, you’ll have to configure the slave DNS server.

Edit the /etc/bind/named.conf.local file:

nano /etc/bind/named.conf.local

Add the following lines inside this file:

zone "example.com" {
        type slave;
        file "db.example.com";
        allow-notify { 123.123.123.123; };
        masters { 123.123.123.123; };
};

Replace 123.123.123.123 with the IP address of the master DNS server, and example.com with the domain name you are configuring. Add a block similar to the one from above for every domain configured on the master server.

Y
ou can check if there are syntax errors with:

named-checkconf

If there are no errors restart BIND:

systemctl restart named

After BIND is restarted, a zone tranfer will start immediately. During a zone transfer, the slave DNS server will synchronize its DNS records with those on the master server.

31.4. Reverse Zone

A reverse zone contains a PTR record that maps an IP address to a domain name. In general, you will have to add a reverse DNS record, in order to make spam filters accept the emails coming from your mail server. This type of record cannot be added to a domain, in your BIND server’s configuration. This record has to be added on the administration panel/dashboard of your hosting account, or, if the administration panel/dashboard doesn’t offer this option, you should ask your hosting company to add the reverse DNS record for you, in a support ticket.

31.5. Create glue records and change Name Servers records with the registrar of your domains

Next, log in to your domain registrar’s website and create glue records, so that the IP addresses of your name servers become known on the Internet. The glue records are A and AAAA records for ns1.somedomain.com and ns2.somedomain.com, like the following:

A Record      ns1.somedomain.com       123.123.123.123

A Record      ns2.somedomain.com       1.2.3.4

AAAA Record   ns1.somedomain.com       2000:2000:2000:2000::ec12

AAAA Record   ns2.somedomain.com       1000:1000:1000:1000::da43

where somedomain.com is the domain you are configuring, 123.123.123.123 is the IPv4 of the master server, 1.2.3.4 is the IPv4 of the slave server, 2000:2000:2000:2000::ec12 is the IPv6 of the master server and 1000:1000:1000:1000::da43 is the IPv6 of the slave server.

Please note that somedomain.com stands for any domain on your server, including the main domain, which we have called example.com in the previous chapters.

Then, change the Name Servers records for your domain, in the appropriate section of your domain registrar’s website. Thus, the Name Servers for the somedomain.com domain, should be set to:

ns1.somedomain.com
ns2.somedomain.com

Repeat the steps from above for every domain configured in BIND, so that each domain has the proper glue records and Name Servers set up with the registrar of that domain.

After the Name Servers records and glue records have propagated, your DNS servers will respond to the DNS queries for the configured domain.

31.5.1. Setting up glue records in a namecheap.com account

Each registrar offers a different web interface. For namecheap.com, the steps that you have to follow in order to set up your own glue records for the somedomain.com domain are the following:

– log in to your namecheap.com account.

– click on the ‘MANAGE’ button next to the domain that you want to configure.

– on the ‘Domain’ tab, in the ‘NAMESERVERS’ section, click on the dropdown list and choose ‘Namecheap BasicDNS’, then click on the tick sign (on the right, before the cancel sign) to save this setting.

– click on the ‘Advanced DNS’ tab on the upper bar.

– you can delete the following two records (by clicking on the delete sign), because you won’t need them:

'CNAME Record www parkingpage.namecheap.com 30 min'
'URL Redirect Record @ http://www.somedomain.com/ Unmasked'

– click on the ‘ADD NEW RECORD’ button and add two A records and two AAAA records for the name servers, like the following:

A Record        ns1.somedomain.com   123.123.123.123   Automatic
A Record        ns2.somedomain.com   1.2.3.4   Automatic
AAAA Record     ns1.somedomain.com   2000:2000:2000:2000::ec12   Automatic
AAAA Record     ns2.somedomain.com   1000:1000:1000:1000::da43  Automatic

where somedomain.com is the domain you are configuring, 123.123.123.123 is the IPv4 of the master server, 1.2.3.4 is the IPv4 of the slave server, 2000:2000:2000:2000::ec12 is the IPv6 of the master server and 1000:1000:1000:1000::da43 is the IPv6 of the slave server.

Obviously, if you have more than one slave server, you’ll have to add more similar A and AAAA records.

– scroll down to the ‘PERSONAL DNS SERVER’ section. In the ‘Find Nameservers’ dropdown list make sure it’s ‘Standard Nameservers’ selected, then click on the ‘ADD NAMESERVER’ link; in the new window, click on ‘Nameserver’, enter manually the subdomain that the name server will have, in our example this will be ns1, so enter manually ns1, press Enter, then in the ‘IP Address’ field enter the IPv4 address of ns1.somedomain.com, then click on ‘DONE’. Next, click again on the ‘ADD NAMESERVER’ button and do the same for ns2.somedomain.com. Don’t forget that ns2 has a different IPv4 address than ns1. Don’t repeat the process for the IPv6 addresses.

– next, click on the ‘Domain’ tab again, in the ‘NAMESERVERS’ section select ‘Custom DNS’ from the drop-down list, then in the text fields from below enter:

ns1.somedomain.com
ns2.somedomain.com

then click on the tick sign to save the records.

– the records will propagate and become functional in a few minutes or in a few hours.

If you want to check if the data is synchronized between the master and the slave server, run the following command on each server:

dig @123.123.123.123 somedomain.com. soa +norec

where 123.123.123.123 is the IPv4 address of the other server.

You can find the BIND9 referece manual here: https://bind9.readthedocs.io/en/latest/ .

31.6. Configure DNSSEC

An attacker can tamper with the DNS responses and send the clients to a malicious website having the legitimate domain name in the address bar. To prevent this, the DNSSEC (Domain Name System Security Extensions) was designed. DNSSEC is a set of extensions to DNS, which offers cryptographic authentication of DNS responses. It signs all the DNS resource records (A, AAAA, MX, etc.) of a zone using the Resource Public Key Infrastructure (RPKI), so that DNSSEC enabled DNS resolvers can verify the authenticity of a DNS reply using the public DNSKEY record.

DNSSEC requires the following resource records (RRs) in the zone file, to function:

  • DNSKEY – it specifies the public key which resolvers use to decrypt the encrypted DNS response and verify its authenticity.
  • RRSIG – it contains the signature for a DNSSEC-secured record set.
  • DS – Delegation signer – the record used to identify the DNSSEC signing key of a delegated zone.

31.6.1. Master server configuration for DNSSEC

To configure the master server, first open the /etc/bind/named.conf.options file:

nano /etc/bind/named.conf.options

Right above listen-on-v6 {any; }; add the following lines in the options configuration block:

dnssec-enable yes;
dnssec-validation yes;
dnssec-lookaside auto;

// conform to RFC1035
auth-nxdomain no;

Please note that the dnssec-validation has to be changed from auto to yes.

Next, navigate to /etc/bind:

cd /etc/bind

Create a Zone Signing Key (ZSK) for each domain, using the following command:

dnssec-keygen -a NSEC3RSASHA1 -b 2048 -n ZONE somedomain.com

Then create a Key Signing Key (KSK) for each domain by running:

dnssec-keygen -f KSK -a NSEC3RSASHA1 -b 4096 -n ZONE somedomain.com

These commands will create one pair of ZSK keys (private/public) and one pair of KSK keys (private/public) for each domain.

Next, add the following two lines at the bottom of the zone file db.somedomain.com :

$INCLUDE Ksomedomain.com.+007+23232.key
$INCLUDE Ksomedomain.com.+007+54545.key

Replace the names of the two public key files for somedomain.com with the actual names of your files.

Repeat the above step for each domain name configured with BIND, by including the two public key files for a domain, at the bottom of that respective domain’s zone file.

Then sign each zone using the following command:

dnssec-signzone -A -3 $(od  -vN 8 -An -tx1 /dev/urandom | tr -d " \n" ; echo) -N INCREMENT -o somedomain.com -t db.somedomain.com

The output of the command from above will look similar to this:

Verifying the zone using the following algorithms: NSEC3RSASHA1.
Zone fully signed:
Algorithm: NSEC3RSASHA1: KSKs: 1 active, 0 stand-by, 0 revoked
                         ZSKs: 1 active, 0 stand-by, 0 revoked
db.example.com.signed
Signatures generated:                       17
Signatures retained:                         0
Signatures dropped:                          0
Signatures successfully verified:            0
Signatures unsuccessfully verified:          0
Signing time in seconds:                 0.032
Signatures per second:                 519.845
Runtime in seconds:                      0.041

This command:

od -vN 8 -An -tx1 /dev/urandom | tr -d " \n" ; echo

generates a string of 16 random hexadecimal characters, that is included as a salt, in the dnssec-signzone command.

Signing the zone creates a new file called db.somedomain.com.signed, which contains the RRSIG records for each DNS record.

Use the dnssec-signzone command from above to sign the zone for each zone configured with BIND.

Next, you have to instruct BIND to load this “signed” zones:

nano /etc/bind/named.conf.local

Change the file option inside the zone section for somedomain.com, by replacing db.somedomain.com with db.somedomain.com.signed. The zone section for somedomain.com should look like this:

zone "somedomain.com" {
      type master;
      file "/etc/bind/db.somedomain.com.signed";
      notify yes;
      allow-transfer { 1.2.3.4; };
};

where 1.2.3.4 is the IPv4 of the slave DNS server. Do similar changes for all the other zones.

Next restart BIND:

systemctl restart named

You can check the DNSKEY record using the dig command:

dig DNSKEY somedomain.com. @localhost +multiline

The output should look similar to this:

;; ANSWER SECTION:
example.com.         86400 IN DNSKEY 256 3 7 (
                     ...
                     ) ; ZSK; alg = NSEC3RSASHA1; key id = 68356

example.com.         86400 IN DNSKEY 257 3 7 (
                     ...
                     ) ; KSK; alg = NSEC3RSASHA1; key id = 29461

You can also check the RRSIG records by running:

dig A somedomain.com. @localhost +noadditional +dnssec +multiline

31.6.2. Slave server configuration for DNSSEC

On the slave server edit the /etc/bind/named.conf.options file:

nano /etc/bind/named.conf.options

In the options configuration block, right above listen-on-v6 { any; }; add the following lines:

dnssec-enable yes;
dnssec-validation yes;
dnssec-lookaside auto;

// conform to RFC1035
auth-nxdomain no;

Also edit the /etc/bind/named.conf.local file:

nano /etc/bind/named.conf.local

Change the name of the zone file from db.somedomain.com to db.somedomain.com.signed. The zone section for somedomain.com should look like this:

zone "somedomain.com" {
        type slave;
        file "db.somedomain.com.signed";
        allow-notify { 123.123.123.123; };
        masters { 123.123.123.123; };
};

where 123.123.123.123 is the IPv4 of the master server. Do the same for every zone.

Restart BIND:

systemctl restart named

31.7. Configure the DS records with your domain name registrar

When running the dnssec-signzone command, apart from the db.somedomain.com.signed file, a file named dsset-somedomain.com. was also created. This file contains the DS record that has to be added in your domain names registrar’s account. Each registrar has a different web interface. We’ll describe how to add the DS record in a namecheap.com account and you should be able to adapt the instructions to other registrars.

31.7.1. Setting up DS records in a namecheap.com account

Log in to your namecheap.com account. Click on ‘Domain List’ on the left panel, click on the ‘MANAGE’ button next to the domain you want to configure, then click on the ‘Advanced DNS’ tab on the upper bar; next, in the ‘DNSSEC’ section toggle the Status switch to On, then add below a DS record, like this:

Key Tag       Algorithm                    Digest Type           Digest
58465         7 RSASHA1-NSEC3-SHA1         2 SHA-256             BD3A3BD829934F86BCB434A16E297D6E0E26B84A57EFA284B370ECDA4AF6FC36

where the number in the ‘Key Tag’ column is the first number that appears right after ‘IN DS’, on the first line of the /etc/bind/dsset-somedomain.com. file. Please note that the digest string, as you copy it from the /etc/bind/dsset-somedomain.com. file, contains a space. When you enter it in the ‘Digest’ field you have to remove the space, otherwise the record can’t be saved.

After you save the above record, you’ll have to wait about one hour for the settings to take effect. Then, to check your DNSSEC settings, you can use an online service like: http://dnssec-debugger.verisignlabs.com .

You have to add a DS record for each domain configured in BIND.

31.8. Editing zone records

The operations in this chapter will be performed only on the master server.

Each time you modify a zone file, you have to sign it again, for the DNSSEC to work. It’s best to use a script to automatically sign a zone after you modify it. Create a script:

nano /etc/bind/signzone.sh

Enter the following content inside this file:

#!/bin/bash

ZONE=$1
ZONEFILE=$2
cd /etc/bind
SERIAL=`/usr/sbin/named-checkzone $ZONE $ZONEFILE | egrep -ho '[0-9]{10}'`
sed -i 's/'$SERIAL'/'$(($SERIAL+1))'/' $ZONEFILE
/usr/sbin/dnssec-signzone -A -3 $(od  -vN 8 -An -tx1 /dev/urandom | tr -d " \n" ; echo) -o $1 -t $2
systemctl reload named

Make the script executable:

chmod 700 /etc/bind/signzone.sh

When you want to change DNS settings for somedomain.com, you must edit the db.somedomain.com file and not the db.somedomain.com.signed file. After editing the file just run the script by passing the domain name and the zone file name as parameters as follows:

/etc/bind/signzone.sh somedomain.com db.somedomain.com

The result of successful signing for the somedomain.com domain will look similar to this:

Verifying the zone using the following algorithms: NSEC3RSASHA1.
Zone fully signed:
Algorithm: NSEC3RSASHA1: KSKs: 1 active, 0 stand-by, 0 revoked
                         ZSKs: 1 active, 0 stand-by, 0 revoked
db.example.com.signed
Signatures generated:                       22
Signatures retained:                         0
Signatures dropped:                          0
Signatures successfully verified:            0
Signatures unsuccessfully verified:          0
Signing time in seconds:                 0.058
Signatures per second:                 378.572
Runtime in seconds:                      0.077

If a zone can’t be signed because of wrong configurations, etc., the signing command will produce no output for that respective zone, so, the successful signing result block from above will be absent for zones that cannot be signed.

To prevent potential hackers to find the salt that was used to sign the zones, you have to change the salt regularly by resigning the zones. Each time the zones are resigned with the command presented above, a new salt is generated and used. To automate the periodic signing process you have to write a new script and set up a cron job that will run the script every 3 days. First, create the script:

nano /etc/bind/signallzones.sh

Enter the following content inside this file:

#!/bin/bash

# If you want to add a new domain to the DNSSEC zone signing process, just add the domain at the end of the "domains" array from below.
# If you want the signing process result to be sent to a different email address, just change the email address at the end of this script.
# If you don't want the script to send emails with the result of the signing process, just comment out the line before the final "fi" of the script.

if [[ $(( ($(date +%s)/86400) % 3 )) == 0 ]]
then
   declare -a domains=("example.com" "secondsite.net" "thirdsite.info" "fourthsite.org" "fifthsite.us")
   declare -a messages=()
   declare -a failedzones=()
   n=${#domains[@]}
   k=0
   cd /etc/bind

   for i in "${!domains[@]}"
   do
     serial=`/usr/sbin/named-checkzone "${domains[$i]}" "db.${domains[$i]}" | egrep -ho '[0-9]{10}'`
     sed -i 's/'$serial'/'$(($serial+1))'/' "db.${domains[$i]}"
     result=`/usr/sbin/dnssec-signzone -A -3 $(od  -vN 8 -An -tx1 /dev/urandom | tr -d " \n" ; echo) -o "${domains[$i]}" -t "db.${domains[$i]}"`

     if [[ $result = *[!\ ]* ]]
     then
         messages+=("$result")
         ((k++))
     else
         failedzones+=("${domains[$i]}")
     fi
   done

   systemctl reload named

   failedlist=`printf "%s\n\n " "${failedzones[@]}"`
   host=`hostname`

   if (($k < $n))
   then
       warning=`printf "The 'signallzones.sh' script attempted to sign all the zones configured in BIND on $host but the following zones couldn't be signed: %s\n\n $failedlist  Please check the configuration of the failed zones from above ! %s\n\n The zones for which the signing process succeeded are listed below."`
   else
       warning=`printf "The 'signallzones.sh' script successfully signed all the zones configured in BIND on $host. The result of the signing process is listed below."`
   fi

   finalmessage=`printf "%s\n\n" "${messages[@]}"`

   echo -e "Subject: DNSSEC Zone Signing \n\n Hello, \n\n $warning \n\n $finalmessage \n\n\n Yours, \n 'signallzones.sh' on $host" | /usr/sbin/sendmail admin@example.com
fi

Replace the values in red with your own values. Later, when you want to add a new domain to the DNSSEC signing process, just add it at the end of the ‘domains’ array, between double quotation marks. If you don’t want the script to send an email with the results when signing the zones, just comment out the line before the final fi.

Make the script executable, with the appropriate permissions:

chmod 700 signallzones.sh

Next, set up the cron job:

crontab -e

At the bottom of the file add the fowllowing lines:

# Run the DNS zones signing script every day at 1:36 AM
36 1 * * * /etc/bind/signallzones.sh > /dev/null 2>&1

The above cron job will run the zones signing script every day, at 1:36 AM. However, the following line located at the beginning of the script:

if [[ $(( ($(date +%s)/86400) % 3 )) == 0 ]]

will ensure that the signing process will take place only once every 3 days, which is in general frequent enough.

If, every 3 days you receive an email mentioning that “All the zones were signed successfully.”, this means everything is working as expected; if the email message tells you that one or more zones couldn’t be signed, it means that the respective zones were misconfigured or something else happened, so you have to investigate what caused the signing process to fail for those zones.

31.9. Configure Fail2ban to protect BIND

The following configurations have to be implemented on both the master server and the slave server.

To use Fail2ban to monitor BIND log and block attackers’ IPs first we have to configure BIND logging by editing the /etc/bind/named.conf file:

nano /etc/bind/named.conf

Enter the following lines at the bottom of the file:

logging {
    channel security_file {
        file "/var/log/named/security.log" versions 3 size 30m;
        severity dynamic;
        print-time yes;
    };
    category security {
        security_file;
    };
};

Next, create a directory for BIND logs and set the proper ownership for it:

mkdir /var/log/named
chown bind:bind /var/log/named

Restart BIND to apply the changes:

systemctl restart named

After restart you can check that the new log file /var/log/named/security.log has been created.

Since you configured BIND to write to a specific log file, you have to remember to also configure logrotate to rotate the new logs, once they reach a certain dimension. Create the logrotate configuration file:

nano /etc/logrotate.d/named-security

Enter the following content inside this file:

/var/log/named/security.log {
  missingok
  rotate 7
  compress
  delaycompress
  notifempty
  size 2M
  create 640 bind bind
  postrotate
    /usr/sbin/invoke-rc.d named reload > /dev/null
  endscript
}

Then open the local jail configuration file of Fail2ban:

nano /etc/fail2ban/jail.local

Search for the section that begins with [named-refused] and make it look like this:

[named-refused]

enabled  = true
port     = domain,53,953
filter   = named-refused
logpath  = /var/log/named/security.log
findtime = 2100
maxretry = 3
bantime  = 604800

You can adjust findtime, maxretry and bantime according to your needs but banning an IP for 7 days (604800 seconds) after making 3 failed queries in 35 minutes (2100 seconds), is a reasonable policy. Please note that Fail2ban will listen on both TCP and UDP traffic, since you didn’t specify protocol = tcp or protocol = udp.

Next restart Fail2ban:

systemctl restart fail2ban

Then you can check if the new jail has been activated by running:

fail2ban-client status

Among the active jails listed you should see the new jail: ‘named-refused’.

31.10. Upgrading BIND

Since BIND has been installed from the official Debian repository, to upgrade it, all you need to do is to run apt-get update && apt-get dist-upgrade with a specific frequency, as described in the Maintenance steps chapter. This command will upgrade BIND if there is a new version available. Also, during these upgrades, the configuration changes implemented as described above, will be preserved.

You can send your questions and comments to: