Basic BIND Installation

This is a basic tutorial on how to install BIND, the Berkeley Internet Name Domain server, on a Ubuntu server in order to run it as an authoritative DNS server. It differs from other tutorials because I am using three servers (one as a hidden primary and two slaves as the public accessible ones), as well as some security such as denying recursive lookups and public zone transfers, as well as using TSIG for authenticating internal zone transfers. That is, this post is not an absolute beginner’s guide.

The basic environment looks like that. Note that I am showing my real IP addresses. Don’t be confused about that and change them to your IPs accordingly:

Some notes about the installation of the servers:

My domain for these test servers is weberdns.de.

The main motivation for the hidden primary approach comes from DNSSEC (will be published later), in which I am managing the keys only on the hidden primary but not on the slaves. No single access is possible from the public Internet to this server.

I am using only the private IPv4 or global IPv6 addresses through site-to-site VPN tunnels in order to transfer the zones between the DNS servers. This brings encryption when traversing the Internet, as well as appropriate security policies on the intermediate firewalls.

By default, each server sends notifications to all other NS servers in case of a zone change. In my case, the notifications are set to “explicit” to only notify the private IPv4 addresses specified in the zone configuration “also-notify { };” and not the public ones.

TSIG is used in order to authenticate the zone transfers (even though not really mandatory since I am using VPN tunnels anyway). For each slave, I am using an unique key.

Public zone transfers (AXFR) are disabled globally. Only servers that authenticated with their key within the “allow-transfer { };” statement are allowed to transfer the zone.

Per-zone statistics are enabled on all servers.

I am using Ubuntu servers version 14.04 LTS either on VMs or on hardware. Of course they have static (NATted) IPv4 and IPv6 addresses. The bind9 package from Ubuntu at the time of writing is version 9.9.5-3ubuntu0.8-Ubuntu (June 2016).

BIND Installation

To install the BIND package simply use the following two statements:

1

2

sudo apt-getupdate

sudo apt-getinstall bind9

All configuration files are stored in the folder
/etc/bind/ .

The started process is called “named“. It listens on udp and tcp port 53, each for IPv4 and IPv6:

1

2

3

4

5

6

7

8

9

weberjoh@jw-vm07-ns1:~$sudo netstat-tulpen|grepnamed

tcp00192.168.110.25:530.0.0.0:*LISTEN1064808214703/named

tcp00127.0.0.1:530.0.0.0:*LISTEN1064808194703/named

tcp00127.0.0.1:9530.0.0.0:*LISTEN1064808224703/named

tcp600:::53:::*LISTEN1064808144703/named

tcp600::1:953:::*LISTEN1064808234703/named

udp00192.168.110.25:530.0.0.0:*1064808204703/named

udp00127.0.0.1:530.0.0.0:*1064808184703/named

udp600:::53:::*1064808134703/named

To view syslog messages, grep for the “named” process:

1

tail-f/var/log/syslog|grepnamed

Master

The master server is the one on which the zone files are maintained. At first, some options are set to secure the authoritative server. These are set within the named.conf.options file (in the /etc/bind/ folder).

1

sudo nano named.conf.options

Add the following options:

1

2

3

4

5

6

7

8

9

10

11

12

//per zone statistics

zone-statistics yes;

//no recursion atall

recursion no;

//notransferafxrbydefault

allow-transfer{"none";};

//no notify toother NS RRs

//notify only toalso-notify IPs

notify explicit;

Then, add a zone statement inside the named.conf.local file:

1

sudo nano named.conf.local

In my case a zone weberdns.de of type master. The allow-transfer statement lists the two slave servers that should be able to transfer the zone. Similarly the also-notify statement lists the slaves, too, in order to notify them in case of a zone update.

1

2

3

4

5

6

zone"weberdns.de"{

typemaster;

file"/etc/bind/db.weberdns.de";

allow-transfer{2003:51:6012:110::a07:53;192.168.90.10;};

also-notify{2003:51:6012:110::a07:53;192.168.90.10;};

};

Finally, the zone file must be created. I am using the template from Hetzner. All relevant statements are already explained there, so I won’t repeat them here.

1

sudo nano db.weberdns.de

This is my basic zone file. The SOA record starts with “ns1.weberdns.de”. There are two NS records (ns1. and ns2.) for this domain, as well as an MX record. Some examples of A, AAAA, CNAME, and TXT records are also shown. And remember to increment the serial number after each modification of the zone file! 😉

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

;

;BIND data fileforweberdns.de

;

$TTL1h

@INSOA ns1.weberdns.de.webmaster.weberdns.de.(

2016051804;Serial

1h;Refresh

15m;Retry

4w;Expire

3m);Negative Cache TTL

;

@INNS ns1.weberdns.de.

@INNS ns2.weberdns.de.

@INMX10mail.weberdns.de.

fgINA80.154.108.233

INAAAA2003:51:6012::4

ip INCNAME ip.webernetz.net.

mail INA80.154.108.237

INAAAA2003:51:6012:110::15

ns1 INA80.154.108.230

INAAAA2003:51:6012:110::a07:53

ns2 INA213.61.29.182

pa INA80.154.108.228

INAAAA2003:51:6012::2

txt INTXT"This is a text."

www INCNAME blog.webernetz.net.

After these steps, the BIND server must be restarted for all changes to work:

1

sudo service bind9 restart

A check of the configuration can be done with
named-checkconf-z . If no errors occur, everything works fine.

For updates of the zone file, a reload of BIND fits. No restart is required. The reload can be triggered by either one of these two commands:

1

2

sudo service bind9 reload

sudo rndc reload

A basic test can be done with the dig tool, such as:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

weberjoh@jw-vm16-ns0:/etc/bind$dig@localhost fg.weberdns.de

;<<>>DiG9.9.5-3ubuntu0.8-Ubuntu<<>>@localhost fg.weberdns.de

;(2servers found)

;;global options:+cmd

;;Got answer:

;;->>HEADER<<-opcode:QUERY,status:NOERROR,id:44847

;;flags:qr aa rd;QUERY:1,ANSWER:1,AUTHORITY:2,ADDITIONAL:4

;;WARNING:recursion requested but notavailable

;;OPT PSEUDOSECTION:

;EDNS:version:0,flags:;udp:4096

;;QUESTION SECTION:

;fg.weberdns.de.INA

;;ANSWER SECTION:

fg.weberdns.de.3600INA80.154.108.233

;;AUTHORITY SECTION:

weberdns.de.3600INNS ns2.weberdns.de.

weberdns.de.3600INNS ns1.weberdns.de.

;;ADDITIONAL SECTION:

ns1.weberdns.de.3600INA80.154.108.230

ns1.weberdns.de.3600INAAAA2003:51:6012:110::a07:53

ns2.weberdns.de.3600INA213.61.29.182

;;Query time:3msec

;;SERVER:::1#53(::1)

;;WHEN:Wed May1816:02:11CEST2016

;;MSG SIZE rcvd:155

Note the “aa” flag in line 8 which indicates that this is an “authoritative answer”.

To view the statistics, run
sudo rndc stats in order to dump the stats into the following file:
cat/var/cache/bind/named.stats . The new statistics are always appended to this file and are listed between the following strings, while the number in brackets is the unixtime:

1

2

3

+++Statistics Dump+++(1471872885)

[...]

---Statistics Dump---(1471872885)

Great so far. 😉

Slave

The two slave servers are installed in the same way as the primary. The additional options should be the following (
sudo nano named.conf.options ):

1

2

3

4

5

6

7

8

9

10

11

//per zone statistics

zone-statistics yes;

//no recursion atall

recursion no;

//notransferafxrbydefault

allow-transfer{"none";};

//no NOTIFY toNS RRs

notify no;

Note that it is REALLY crucial to put in these lines, at least the “allow-transfer none” one. Otherwise the zone is fully loadable through an axfr request. (A painful mistake is to only place this statement at the hidden primary but to forget it on the slave units.)

Now, the only portion to configure in order to be a slave is inside the named.conf.local file.

1

sudo nano named.conf.local

In my case, it only lists the following lines:

1

2

3

4

5

zone"weberdns.de"{

typeslave;

file"db.weberdns.de";

masters{192.168.120.21;};

};

After a restart of the service (
sudo service bind9 restart ), everything is ready. Asking the localhost should work, e.g.:
dig@localhost mail.weberdns.de .

The resource records are stored in the following path:
/var/cache/bind/. Note that these files are not readable, but can be converted into a textfile with:

This reads the raw database (-f raw) and includes the journal file (-j). It outputs text (-F text) into the file (-o outputfilename). With
catdb.weberdns.de.txt you can see your RRs.

Parent Zone: Glue Records

To become the authoritative servers, the names and/or IP addresses of the nameservers must be configured at the parent zone, in my case the DENIC which is responsible for *.de. They offer a good online check for domain servers (Nameserver Predelegation Check Web Interface) which tests the nameservers to see if everything is accessible (firewalls with udp/tcp port 53) and configured correctly (SOA record values, …). In my case, this looks like that:

Since my NS servers for “weberdns.de” are called “ns1.weberdns.de” and “ns2.weberdns.de”, (which won’t be resolvable if only these FQDNs are known), the entries for these nameservers are stored with their glue records, i.e., the name and the IP addresses.

After this step was done, a whois for weberdns.de looks like:

1

2

3

4

5

6

7

weberjoh@jw-nb12:~$whois weberdns.de

Domain:weberdns.de

Nserver:ns1.weberdns.de2003:51:6012:110:0:0:a07:5380.154.108.230

Nserver:ns2.weberdns.de213.61.29.182

Status:connect

Changed:2016-05-17T17:01:42+02:00

The Internet is now able to ask my two slave name servers for everything ending with .weberdns.de. Great again. This can easily be tested with dig +trace from any machine that has Internet access, e.g.:

1

dig www.weberdns.de+trace

Zone Transfers

At first, it is crucial to test that zone transfers of your servers are not available from the Internet. The Zone Transfer Online Test can be used for this purpose. This should fail because the “allow-transfer” options are already configured for both server types, master and slaves. Here is a sample of my domain:

Dig can be used to test the zone transfers, too, such as:

1

dig@ns1.weberdns.deweberdns.deaxfr

Of course, this command will/must work if it is issued from one of the slaves and directed to the master, in my case:

1

dig@192.168.120.21weberdns.deaxfr

To authenticate the zone transfers, TSIG can be used. (This won’t be needed in my case, because I am already using private site-to-site VPNs for the connections between my servers. However. ;)) With TSIG, a shared secret is configured on any server pair (master to slave1, and master to slave2). Only if this “password” is present, the slave is able to transfer the zone. Note that this is not encryption (confidentiality), but only authentication.

At first, the keys must be generated. Note the last option which is the key-name, in this example case “key-ns1”:

1

dnssec-keygen-r/dev/urandom-aHMAC-SHA256-b256-nHOST key-ns1

I am using two different keys for both slave servers. That is, I generated the following keys. Note that the key values in both files (*.key and *.private) are the same keys. (And no, these are not my actual keys, but only demos):

On the master server, open the named.conf file and add both keys one for each slave, such as:

1

2

3

4

5

6

7

8

9

keykey-ns1{

algorithm hmac-sha256;

secret"32r25Nl7WKMw4AU0QSNC67NHsxE0ZNeJ+POe624fE2E=";

};

keykey-ns2{

algorithm hmac-sha256;

secret"QZlvozBRA1dGQ2DlIRh90X7kryXjihuDntrl9hEjmD0=";

};

Furthermore, open the named.conf.local and change the “allow-transfer” statement to only allow connections with these keys. The IP addresses from the servers must be omitted, for example, comment them out. Otherwise, connections from this IP addresses will still be possible without the key:

1

2

//allow-transfer{2003:51:6012:110::a07:53;192.168.90.10;};

allow-transfer{key key-ns1;key key-ns2;};

Same procedure on both slaves, of course only with the single needed key, e.g., key-ns1 and key-ns2. Furthermore, the “server” statement must be configured. Open the named.conf on the first slave, ns1, and add these lines: