31. Install BIND

by Cover Tower - Updated October 15, 2021

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 VPSs or dedicated 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.11.5-P4-5.1+deb10u2-Debian (Extended Support Version) <id:998753c>

Start BIND:

systemctl start bind9

Check if it’s running:

systemctl status bind9

● 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 bind9

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.11.5-P4-5.1+deb10u2-Debian (Extended Support Version) <id:998753c>

running on mail.example.com: Linux x86_64 4.19.0-11-amd64 #1 SMP Debian 4.19.146-1 (2020-09-17)

boot time: Wed, 30 Sep 2020 13:18:23 GMT

last configured: Wed, 30 Sep 2020 13:18:23 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: 4/150

server is up and running

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


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.

Next restart BIND:

systemctl restart bind9

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 we’ll do later, 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/bind9.service in a way that will preserve the modifications during future updates. Thus run the command:

systemctl edit bind9.service

and add

[Service]

Restart=always

in the new file that will be created. The systemctl edit bind9.service command will create the /etc/systemd/system/bind9.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/bind9.service file.

Next run:

systemctl daemon-reload

systemctl restart bind9

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

bind9.service - BIND Domain Name Server

Loaded: loaded (/lib/systemd/system/bind9.service; enabled; vendor preset: enabled)

Drop-In: /etc/systemd/system/bind9.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, we created a new zone with the zone clause and we specified that this is the master zone. The zone file is /etc/bind/db.example.com, where we 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, edit the 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. (

2020101501 ; 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 change, etc.

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.
  • 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 bind9

It’s ok to have separate DNS servers for each domain that you host on your server. For example, if you host example.com, secondsite.net, thirdsite.info, fourthsite.org, fifthsite.us, you’ll have the following DNS servers for them 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

The DNS servers are listed in their respective domain’s zone file.

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:

named-checkconf

If there are no errors restart BIND:

systemctl restart bind9

After BIND9 restarts, 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 in the control panel offered by the company you rent your VPS/dedicated server from, or it can be added by the hosting company, after you ask for it in a support ticket.

31.4.1. Adding a reverse DNS record for an OVH server

If you rented a server from OVH and you want to add a reverse DNS record for your mail server, you have to add a reverse DNS record for the hostname of your server: mail.example.com. To do this, log in to your OVH account, click ‘Server’ in the upper bar, then in the left panel click on ‘IP’, then in the ‘Reverse’ column of your IP click on the ‘Edit’ icon, enter mail.example.com, then click on the ‘save’ sign. You have to do this for both the IPv4 and IPv6 IPs.

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

Next, log in to your domains registrar’s website and create glue records, so that the Internet can know the IP addresses of your name servers. The glue records are A and AAAA records for ns1.domain.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 domains, so that all the requests for those domains, will be directed to your newly configured DNS servers.

Thus, the Name Servers for the somedomain.com domain, should be set to:

ns1.somedomain.com

ns2.somedomain.com

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

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

– next wait about 24 hours to have the records propagate and become functional.

If you have problems with data synchronization between the master and the slave server, try running the following command on each server, to see if the data is synchronized:

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://www.bind9.net/bind-9.13.3-manual.pdf

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

Add the following lines in the options configuration block, right above listen-on-v6 { any; };

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

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

Next, 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 bind9

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

Add the following lines in the options configuration block, right above listen-on-v6 { any; };

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.

Next restart BIND:

systemctl restart bind9

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 records that have 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 records 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' in the left panel, click on the 'MANAGE' button next to the domain you want to configure, then click on the 'Advanced DNS' tab in the upper bar; next, in the 'DNSSEC' section toggle the Status switch to On, then add below two DS records corresponding to the two lines in the /etc/bind/dsset-somedomain.com. file, like this:

Key Tag Algorithm Digest Type Digest

58465 7 RSASHA1-NSEC3-SHA1 1 SHA-1 BD3A3BD829934F86BCB434A16E297D6E0E26B84A

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 two lines of the /etc/bind/dsset-somedomain.com. file. Please note that the second digest type is 2 SHA-256 and not 1 SHA-1. Please also note that the digest string in the second row, 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 two records 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 the two DS records for each domain configured with 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 bind9

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, we 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 we have to write a new script and set up a cron job that will run the script every 3 days. First let's create the script which we'll call signallzones.sh:

cd /etc/bind

nano 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 bind9

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 let's 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

Next restart BIND to apply the changes:

systemctl restart bind9

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

Since we configured BIND to write to a specific log file, we 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/bind9-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 bind9 reload > /dev/null

endscript

}

Next 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 we 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 was installed from the Debian repository, it will be upgraded automatically whenever there is a new version available and you run:

apt-get update

apt-get dist-upgrade

The configuration files will be preserved during upgrade, so you won’t have to configure it again after upgrade.