4.- DNS

The number of interconnected computers is growing day by day. It is possible to design a hierarchical network addressing schema that assigns network addresses according to the computer physical location, but even in this case, it will allways be easier to refer to the computers by using names instead of IP addresses. A local DNS server will allow us to establish a direct relation between a computer name and an IP address which, in turn, will make much easier to identify a local machine.

4.1.- DNS Service

In order to communicate with each other, every computer in the network must be assigned a unique IP address. It could be said that there is a certain analogy with a phone network, in which a phone number identifies a single device and makes it possible for it to communicate with the other phones.

Working with IP Addresses is fine for computers, but it is also cumbersome for the people. It would be necessary to remember the IP address of every single device we wanted to connect to. It is definitely much more convenient using names like www.google.es or www.redhat.com, which are much easier to remember.

Internally, the computers communicate with each other by using their IP addresses, not their associated domain names. So it is necessary to have a system which is able to determine the IP Addres(es) associated with a domain name.

So, for instance, when we type http://www.google.es in our favorite Web browser, our PC has to be able to know the actual IP address associated with the name www.google.es. Once it finds out that the IP address is 173.194.41.215 it establishes a connection and shows the Web page to the user.

If we had written in the address bar http://173.194.41.215 it wouldn’t have been necessary to ask about the IP address of www.google.es.

A DNS Server is a machine that keeps a list of associations name - IP address. In the early days of the Internet this was achieved with a single text file that all computers had to know in order to communicate with each other. This file is /etc/hosts, and it is still present in every computer. It can be used to provide some sort of basic name resolution. For instance we could open the file /etc/hosts and add the following line:

1 192.168.10.19		www.dummy-domain.com

From now on, every time our computer needs to know the address of the name www.dummy-domain.com it will assume this IP address is 192.168.10.19.

 1 [root@localhost ~]# cat /etc/hosts
 2 127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
 3 ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
 4 192.168.10.19   dummy-server.example.com
 5 192.168.10.19   www.dummy-domain.com
 6 [root@localhost ~]# ping www.dummy-domain.com
 7 PING www.dummy-domain.com (192.168.10.19) 56(84) bytes of data.
 8 64 bytes from dummy-server.example.com (192.168.10.19): icmp_seq=1 ttl=64 time=0\
 9 .056 ms
10 64 bytes from dummy-server.example.com (192.168.10.19): icmp_seq=2 ttl=64 time=0\
11 .058 ms
12 64 bytes from dummy-server.example.com (192.168.10.19): icmp_seq=3 ttl=64 time=0\
13 .052 ms
14 ^C
15 --- www.dummy-domain.com ping statistics ---
16 3 packets transmitted, 3 received, 0% packet loss, time 2459ms
17 rtt min/avg/max/mdev = 0.052/0.055/0.058/0.006 ms

Using the host file for name resolution can still be appropriate for small networks, but as the Internet began to grow it became pretty clear that a new name resolution system was needed. And so the DNS service was developed.

A DNS server mantains a database with all the IP addresses and names included in its domain. Of course a single DNS server can’t store all the IP addresses that exist in the world, on the contrary they usually keep only the information about their domain.

The DNS servers are organized in a hierarchical way, as it can be seen in Fig. 51, so, when the assigned DNS can’t resolve a name, it will pass the request to another DNS server form an upper layer. It’s easy to understand with an example.

Fig 51:DNS Hierarchy
Fig 51:DNS Hierarchy

Let’s say we are sitting in front of a computer in the acme.net domain and we want to access the web es.wikipedia.org. The computer will query its local DNS server about the name es.wikipedia.org, but this server only knows about www.acme.net, mail.acme.net, etc… so it decides to query the .net server. The .net server doesn’t know about es.wikipedia.org so it has to query the root (.) server. The root server doesn’t know the exact address of es.wikipedia.org but it knows the address of the .org server, so it passes the query to this server. The .org server then will query the wikipedia.org server and this server will finally tell the IP address associated with the name es.wikipedia.org, the answer will be passed back to the DNS server in acme.net which, in turn, will give that information to the computer that requested it.

4.2.- Installing a DNS server

To illustrate what we have seen we are going to install a working DNS server. The package we’ll need to install is bind. If we already have an Internet connection we can use use yum without the –disablerepo and –enablerepo options, as it will download the software from the preconfigured Internet repositories. We can also pass the -y parameter to automatically answer yes to any confirmation message. Otherwise, if we still haven’t got an Internet connection we’ll have to use the options we saw earlier and make sure that the DVD is mounted.

1 [root@localhost ~]# yum -y install bind 

4.2.1.- Starting the service in CentOS 6

Once installed, we should have a new script in the /etc/init.d directory. This script will be called named.

1 [root@localhost ~]# ls /etc/init.d/named 
2 /etc/init.d/named 

We can check the status of this new installed service by calling the script with the status parameter.

1 [root@localhost ~]# /etc/init.d/named status 
2 rndc: neither /etc/rndc.conf nor /etc/rndc.key was found 
3 named is stopped 

Or we can use the service command.

1 [root@localhost ~]# service named status 
2 rndc: neither /etc/rndc.conf nor /etc/rndc.key was found 
3 named is stopped 

In both cases we’re told that named is stopped. And a couple of files seem to be missing too. We’ll get more into detail in a moment. Anyway, we can start the service with the following command:

1 [root@localhost ~]# service named start 
2 Starting named:                                            [  OK  ] 
3 [root@localhost ~]# service named status 
4 rndc: neither /etc/rndc.conf nor /etc/rndc.key was found 
5 named (pid  1570) is running... 

Now we should make sure that the service starts everytime the system boots. We can check this with chkconfig.

1 [root@localhost ~]# chkconfig --list named 
2 named           0:off   1:off   2:off   3:off   4:off   5:off   6:off 

We can see that, right now, named is not configured to be active on any of the 6 runlevels. We will change this.

1 [root@localhost ~]# chkconfig named on 
2 [root@localhost ~]# chkconfig --list named 
3 named           0:off   1:off   2:on    3:on    4:on    5:on    6:off 

Now named will be started in every runlevel except 0 (shutdown), 1 (single user) or 6 (reboot) We haven’t talked about runlevels so far, but we can say that it is the way the OS has to identify if the machine is shutdown (runlevel 0), in single user mode(runlevel 1), in multiuser text mode with limited networking, in multiuser text mode with full networking(runlevel 3), in graphic multiuser mode (runlevel 5) or rebooting (runlevel 6).

4.2.2.- Starting the service in CentOS 7

In Centos 7 the service management has undergone many changes and the system no longer uses the scripts in /etc/init.d, except for a few services. The rest of the services are managed by systemd.

To check the status of a service we’ll have to use the systemctl command.

1 [root@Centos7 ~]# systemctl status named
2 named.service - Berkeley Internet Name Domain (DNS)
3    Loaded: loaded (/usr/lib/systemd/system/named.service; disabled)
4    Active: inactive (dead)

We see that the service is stopped, so we start it.

 1 [root@Centos7 ~]# systemctl start named
 2 [root@Centos7 ~]# systemctl status named
 3 named.service - Berkeley Internet Name Domain (DNS)
 4    Loaded: loaded (/usr/lib/systemd/system/named.service; disabled)
 5    Active: active (running) since dom 2014-11-23 01:05:36 CET; 4s ago
 6   Process: 2855 ExecStart=/usr/sbin/named -u named $OPTIONS (code=exited, status\
 7 =0/SUCCESS)
 8   Process: 2853 ExecStartPre=/usr/sbin/named-checkconf -z /etc/named.conf (code=\
 9 exited, status=0/SUCCESS)
10  Main PID: 2857 (named)
11    CGroup: /system.slice/named.service
12            └─2857 /usr/sbin/named -u named
13 
14 nov 23 01:05:37 Centos7 named[2857]: validating @0x7fa9c062ff10: . NS: veri...un
15 nov 23 01:05:37 Centos7 named[2857]: validating @0x7fa9c062ff10: . NS: no v...nd
16 nov 23 01:05:37 Centos7 named[2857]: error (no valid RRSIG) resolving './NS...53
17 nov 23 01:05:37 Centos7 named[2857]: error (network unreachable) resolving ...53
18 nov 23 01:05:37 Centos7 named[2857]: validating @0x7fa9c062ff10: . NS: veri...un
19 nov 23 01:05:37 Centos7 named[2857]: validating @0x7fa9c062ff10: . NS: no v...nd
20 nov 23 01:05:37 Centos7 named[2857]: error (no valid RRSIG) resolving './NS...53
21 nov 23 01:05:37 Centos7 named[2857]: validating @0x7fa9c062ff10: . NS: veri...un
22 nov 23 01:05:37 Centos7 named[2857]: validating @0x7fa9c062ff10: . NS: no v...nd
23 nov 23 01:05:37 Centos7 named[2857]: error (no valid RRSIG) resolving './NS...53
24 Hint: Some lines were ellipsized, use -l to show in full.

The service is running now, but we have to make sure that it starts every time the system boots.

1 [root@Centos7 ~]# systemctl enable named
2 ln -s '/usr/lib/systemd/system/named.service' '/etc/systemd/system/multi-user.ta\
3 rget.wants/named.service'

We can check that the service is actually enabled with the following command.

1 [root@Centos7 ~]# systemctl list-unit-files --type=service

It will list all the services installed in the computer.

1 UNIT FILE                                   STATE   
2 auditd.service                              enabled 
3 .
4 .
5 .
6 named.service                               enabled 
7 .
8 .
9 .

4.3.- Installing a master server

Before we move on to the next step we’ll talk a bit more about the types of DNS servers:

As we already know, a DNS server translates names into IP addresses. But it can do this through different approaches:

  • Cache only server. In this case, the server doesn’t hold any information about the associations name - IP address, so it has to query another server. But once it gets an answer it keeps it in the cache, so that when another client performs the same query it can respond quickly without forwarding the request to another server.
  • Master server. The server holds a copy of the names and IPs of the computers belonging to the domain. What is called a zone. This server has authority to change the IP associated to a certain name, as well as add or delete new registers.
  • Slave server. The server holds a copy of the zone too, but it is a read-only one. The server has all the information it needs to answer queries about the domain, but it cannot change, add or delete any register.

We have already installed the software necessary but, obviously, we still haven’t configured it. Let’s assume we manage a domain called olimpus.local, and a few machines called prometheus, zeus, aphrodite, etc… and we want to make sure that when a client computer searchs for the computer aphrodite.olimpus.com it gets its IP address asociated. In order to achieve this, we’ll have to create the zone. Let’s see the procedure step by step.

The main configuration file of the DNS server is /etc/named.conf. Right after a fresh installation it will look like this:

 1 // 
 2 // named.conf 
 3 // 
 4 // Provided by Red Hat bind package to configure the ISC BIND named(8) DNS 
 5 // server as a caching only nameserver (as a localhost DNS resolver only). 
 6 // 
 7 // See /usr/share/doc/bind*/sample/ for example named configuration files. 
 8 // 
 9 
10 options { 
11         listen-on port 53 { 127.0.0.1; }; 
12         listen-on-v6 port 53 { ::1; }; 
13         directory       "/var/named"; 
14         dump-file       "/var/named/data/cache_dump.db"; 
15         statistics-file "/var/named/data/named_stats.txt"; 
16         memstatistics-file "/var/named/data/named_mem_stats.txt"; 
17         allow-query     { localhost; }; 
18         recursion yes; 
19 
20         dnssec-enable yes; 
21         dnssec-validation yes; 
22         dnssec-lookaside auto; 
23 
24         /* Path to ISC DLV key */ 
25         bindkeys-file "/etc/named.iscdlv.key"; 
26 }; 
27 
28 logging { 
29         channel default_debug { 
30                 file "data/named.run"; 
31                 severity dynamic; 
32         }; 
33 }; 
34 
35 zone "." IN { 
36         type hint; 
37         file "named.ca"; 
38 }; 
39 
40 include "/etc/named.rfc1912.zones"; 

This is the configuration file of a CentOS 6 server, in CentOS 7 the file is slightly different but the way to configure it is exactly the same in both cases.

These are some of the most important options:

1 listen-on port 53 { 127.0.0.1; }; 
2 listen-on-v6 port 53 { ::1; }; 

The server will listen only in the localhost address, that is, it won’t be accesible from other computers on the network. As we want to be able to query the DNS server from other computers we will change these two lines.

1 listen-on port 53 { any; }; 
2 listen-on-v6 port 53 { any; }; 
3 
4 
5 directory       "/var/named"; 

This only means that the default directory for the zone files will be in /var/named. We don’t need to change this.

1 allow-query     { localhost; }; 

We want the server to answers queries from any computer, so we change this value.

1 allow-query     { any; }; 
2 
3 zone "." IN { 
4         type hint; 
5         file "named.ca"; 
6 }; 

This is the only zone defined so far in the configuration file. The top most zone in the hierarchy. If we open the /var/named/named.ca file we will see that it contains the address of the root servers on the Internet. Here we will need to tell the server about our domain olimpus.local. Below the “.” zone definition we will type this:

1 zone "olimpus.local" IN { 
2     type master; 
3     file "olimpus.local.zone"; 
4 }; 

We can now save the changes. To make sure the syntax of the file named.conf is correct we can use named-checkconf.

1 [root@localhost ~]# named-checkconf 
2 [root@localhost ~]# 

As we can see, the program didn’t show any output so we can assume the syntax is correct. If there were a syntax error the program would tell us about it. For instance, if we had forget a curly bracket we could get a message like this.

1 [root@localhost ~]# named-checkconf 
2 /etc/named.conf:26: '}' expected near ';' 

But now we have to create the /var/named/olimpus.local.zone file. As expected, the file needs to have a proper syntax. If we’re creating a zone file from scratch and we don’t remember all the details about the syntax we can take a look at some of the sample files in the /usr/share/doc/bind-9.7.3/sample directory. In fact, the /usr/share/doc folder is always very helpful when we try to configure or tune a service, as we can find there plenty of sample configuration files of almost all the software installed in the server.

The zone file should be something like this:

 1 ; 
 2 ;Data file for olimpus.local 
 3 ; 
 4 $TTL 2D 
 5 olimpus.local.  IN SOA olimpus.local. root.olimpus.local. ( 
 6                 2014082701;       Serial 
 7                 1D;             Refresh 
 8                 2H;             Retry 
 9                 1W;             Expire 
10                 2D);            Default TTL 
11 
12         IN NS delphos.olimpus.local. 
13         IN MX 10 prometheus.olimpus.local. 
14 
15 delphos         IN A    192.168.1.20 
16 prometheus      IN A    192.168.1.21 
17 aphrodite       IN A    192.168.1.22 
18 delphos         IN AAAA fe80::20c:29ff:fe78:4cb1 
19 dns             IN CNAME        delphos 
20 mail            IN CNAME        prometheus 

The lines beginning with “;” are comments used to clarify the content of the file. After that, we define the parameters associated with the zone file, such as the refresh and retry rates, the expire time and the default TTL. Every zone file must have a serial number associated, this number will be used when replicating information between DNS servers, to know wether there is a newer version of a zone file.

1 IN NS delphos.olimpus.local. 

This is a NS register, it tells what are the name servers of olimpus.local. This is a mandatory register. In this case the only name server is delphos.olimpus.local but we could have many of them.

1 IN MX 10 prometheus.olimpus.local.

Similarly, we define here the mail server for the olimpus.local domain and the priority associated (10). In this case, we have only a mail server but we could have two or even more, and assign different priorities to every one of them according to their processing power. We’ll see this again when we talk about the mail service.

1 delphos         IN A    192.168.1.20 
2 prometheus      IN A    192.168.1.21 
3 aphrodite       IN A    192.168.1.22 

Now we have a list with all the machines in the zone and their IP address associated. These are called type A registers.

1 delphos         IN AAAA fe80::20c:29ff:fe78:4cb1 

In addition we can associate names and IPv6 addresses, that’s what AAAA registers are for.

1 dns             IN CNAME        delphos 
2 mail            IN CNAME        prometheus 

And finally we have a couple of CNAME registers, which work as alias. That is, the client will be able to ping delphos.olimpus.local or dns.olimpus.local indistinctly.

Once we’re done, we can check the syntax with the named-checkzone command.

1 [root@localhost named]# named-checkzone olimpus.local olimpus.local.zone 
2 zone olimpus.local/IN: loaded serial 20140827 
3 OK 

We start now the named service.

In CentOS 6:

1 [root@localhost named]# service named start 
2 Starting named:                                            [  OK  ] 

In CentOS 7:

1 [root@Centos7 ~]# systemctl start named

Apparently everything was fine, but to make sure we’ll query the DNS server for the address of the delphos.olimpus.local machine. We’ll see later in more detail some of the tools we can use to check the DNS service, but to make sure our name server is working we’ll introduce here the dig command.

Dig allows us to query the DNS server we choose. To check our new name server we could type this:

1 [root@localhost named]# dig @192.168.1.20 delphos.olimpus.local 
2 -bash: dig: command not found 

As we have mentioned several times before, if the utility is not installed by default we’ll have to find out the package it belongs to and install it. From now on we won’t insist again in this subject.

 1 [root@localhost named]# yum --disablerepo=* --enablerepo=c6-media provides dig 
 2 Loaded plugins: fastestmirror 
 3 Loading mirror speeds from cached hostfile 
 4  * c6-media: 
 5 Warning: 3.0.x versions of yum would erroneously match against filenames. 
 6  You can use "*/dig" and/or "*bin/dig" to get that behaviour 
 7 No Matches found 
 8 [root@localhost named]# yum --disablerepo=* --enablerepo=c6-media provides */dig 
 9 Loaded plugins: fastestmirror 
10 Loading mirror speeds from cached hostfile 
11  * c6-media: 
12 32:bind-utils-9.7.3-8.P3.el6.i686 : Utilities for querying DNS name servers 
13 Repo        : c6-media 
14 Matched from: 
15 Filename    : /usr/bin/dig 
16 
17 [root@localhost named]# yum --disablerepo=* --enablerepo=c6-media install bind-u\
18 tils 
19 Loaded plugins: fastestmirror 
20 Loading mirror speeds from cached hostfile 
21  * c6-media: 
22 Setting up Install Process 
23 Resolving Dependencies 
24 --> Running transaction check 
25 ---> Package bind-utils.i686 32:9.7.3-8.P3.el6 will be installed 
26 --> Finished Dependency Resolution 
27 
28 Dependencies Resolved 
29 
30 ================================================================================ 
31  Package           Arch        Version                    Repository       Size 
32 ================================================================================ 
33 Installing: 
34  bind-utils        i686        32:9.7.3-8.P3.el6          c6-media        177 k 
35 
36 Transaction Summary 
37 ================================================================================ 
38 Install       1 Package(s) 
39 
40 Total download size: 177 k 
41 Installed size: 423 k 
42 Is this ok [y/N]: y 
43 Downloading Packages: 
44 Running rpm_check_debug 
45 Running Transaction Test 
46 Transaction Test Succeeded 
47 Running Transaction 
48   Installing : 32:bind-utils-9.7.3-8.P3.el6.i686                            1/1 
49 
50 Installed: 
51   bind-utils.i686 32:9.7.3-8.P3.el6 
52 
53 Complete! 
54 [root@localhost named]# 

Now we can actually perform the query…

 1 [root@localhost named]# dig @192.168.1.20 delphos.olimpus.local                 
 2 ; <<>> DiG 9.7.3-P3-RedHat-9.7.3-8.P3.el6 <<>> @192.168.1.20 delphos.olimpus.loc\
 3 al 
 4 ; (1 server found) 
 5 ;; global options: +cmd 
 6 ;; Got answer: 
 7 ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 27770 
 8 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1 
 9 
10 ;; QUESTION SECTION: 
11 ;delphos.olimpus.local.         IN      A 
12 
13 ;; ANSWER SECTION: 
14 delphos.olimpus.local.  172800  IN      A       192.168.1.20 
15 
16 ;; AUTHORITY SECTION: 
17 olimpus.local.          172800  IN      NS      delphos.olimpus.local. 
18 
19 ;; ADDITIONAL SECTION: 
20 delphos.olimpus.local.  172800  IN      AAAA    fe80::20c:29ff:fe78:4cb1 
21 
22 ;; Query time: 7 msec 
23 ;; SERVER: 192.168.1.20#53(192.168.1.20) 
24 ;; WHEN: Sat Aug  2 10:42:07 2014 
25 ;; MSG SIZE  rcvd: 97 
26 
27 [root@localhost named]# 

We wanted to query the 192.168.1.20 server, so we pass it as a parameter(@192.168.1.20). We can see that the query executed correctly (status: NOERROR). In addition the server reported that delphos.olimpus.local has the IPv4 address 192.168.1.20 and the IPv6 address fe80::20c:29ff:fe78:4cb1, which is correct.

It looks like we have a working DNS server, but unfortunately this is not completely true. So far we have a way to translate names into IP addresses. This is what is called direct lookup, but we should also have a way to translate IP addreses into machine names (reverse lookup). To achieve this the procedure is quite similar to what we have seen before.

In the /etc/named.conf file we’ll define the new zone that provides the reverse lookup. We’ll type it just below the olimpus.local zone.

1     zone "1.168.192.in-addr.arpa" IN { 
2             type master; 
3             file "192.168.1.zone"; 
4     }; 

The format x.x.x.in-addr.arpa, where x.x.x is the network address in reverse order, is a standard way of naming reverse zones.

Now we create the /var/named/192.168.1.zone file. The syntax is quite similar to the one used in the file olimpus.local.zone.

 1 $TTL 2D; 
 2 1.168.192.in-addr.arpa. IN SOA delphos.olimpus.local. root.olimpus.local. ( 
 3                         2014082701      ;serial 
 4                         259200          ;refresh(3 days) 
 5                         14400           ;retry(4 hours) 
 6                         18140           ;expire(3 weeks) 
 7                         604800          ;minimum(1 week) 
 8                         ) 
 9                 NS delphos.olimpus.local. 
10 
11 20              PTR delphos.olimpus.local. 

And we check it.

1 [root@localhost named]# named-checkzone 1.168.192.in-addr.arpa 192.168.1.zone 
2 zone 1.168.192.in-addr.arpa/IN: loaded serial 2014082701 
3 OK 

We restart the service…

In CentOS 6:

1 [root@localhost named]# service named restart 
2 Stopping named:                                            [  OK  ] 
3 Starting named:                                            [  OK  ] 

In CentOS 7:

1 [root@Centos7 ~]# systemctl restart named

…and query the server with dig.

 1 [root@localhost named]# dig @192.168.1.20 -x 192.168.1.20 
 2 
 3 ; <<>> DiG 9.7.3-P3-RedHat-9.7.3-8.P3.el6 <<>> @192.168.1.20 -x 192.168.1.20 
 4 ; (1 server found) 
 5 ;; global options: +cmd 
 6 ;; Got answer: 
 7 ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 62275 
 8 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2 
 9 
10 ;; QUESTION SECTION: 
11 ;20.1.168.192.in-addr.arpa.     IN      PTR 
12 
13 ;; ANSWER SECTION: 
14 20.1.168.192.in-addr.arpa. 172800 IN    PTR     delphos.olimpus.local. 
15 
16 ;; AUTHORITY SECTION: 
17 1.168.192.in-addr.arpa. 172800  IN      NS      delphos.olimpus.local. 
18 
19 ;; ADDITIONAL SECTION: 
20 delphos.olimpus.local.  172800  IN      A       192.168.1.20 
21 delphos.olimpus.local.  172800  IN      AAAA    fe80::20c:29ff:fe78:4cb1 
22 
23 ;; Query time: 2 msec 
24 ;; SERVER: 192.168.1.20#53(192.168.1.20) 
25 ;; WHEN: Sat Aug  2 11:28:31 2014 
26 ;; MSG SIZE  rcvd: 136 

As it happened before, we can see the query executed without errors (status: NOERROR), and the server answered that the IPv4 address 192.168.1.20 is assigned to the server delphos.olimpus.local.

Finally we’ll create the reverse zone for IPv6. We open the /etc/named.conf file again and add the following lines.

1 zone "0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa" IN { 
2         type master; 
3         file "fe80.0.0.0.zone"; 
4 }; 

As we see, the standard name is similar to the one used with IPv4 zones, it also consists of the network address in reverse order but now the suffix is ip6.arpa.

As for the /var/named/fe80.0.0.0.zone this is what we’ll type.

 1 $TTL 172800 ; 2 days 
 2 0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa. IN SOA delphos.olimpus.local. root.oli\
 3 mpus.local. ( 
 4                         2014082701      ;serial 
 5                         259200          ;refresh(3 days) 
 6                         14400           ;retry(4 hours) 
 7                         18140           ;expire(3 weeks) 
 8                         604800          ;minimum(1 week) 
 9                         ) 
10 
11                                 NS delphos.olimpus.local. 
12 1.b.c.4.8.7.e.f.f.f.9.2.c.0.2.0 IN PTR delphos 

And we check the result.

1 [root@localhost named]# named-checkzone 0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa\
2  fe80.0.0.0.zone 
3 zone 0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa/IN: loaded serial 2014082701 
4 OK 

We restart the named service and query the server again.

 1 [root@localhost named]# dig @192.168.1.20 -x fe80::20c:29ff:fe78:4cb1 
 2 
 3 ; <<>> DiG 9.7.3-P3-RedHat-9.7.3-8.P3.el6 <<>> @192.168.1.20 -x fe80::20c:29ff:f\
 4 e78:4cb1 
 5 ; (1 server found) 
 6 ;; global options: +cmd 
 7 ;; Got answer: 
 8 ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 29346 
 9 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2 
10 
11 ;; QUESTION SECTION: 
12 ;1.b.c.4.8.7.e.f.f.f.9.2.c.0.2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa. IN PT\
13 R 
14 
15 ;; ANSWER SECTION: 
16 1.b.c.4.8.7.e.f.f.f.9.2.c.0.2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa. 172800\
17  IN PTR delphos.0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa. 
18 
19 ;; AUTHORITY SECTION: 
20 0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa. 172800 IN NS delphos.olimpus.local. 
21 
22 ;; ADDITIONAL SECTION: 
23 delphos.olimpus.local.  172800  IN      A       192.168.1.20 
24 delphos.olimpus.local.  172800  IN      AAAA    fe80::20c:29ff:fe78:4cb1 
25 
26 ;; Query time: 1 msec 
27 ;; SERVER: 192.168.1.20#53(192.168.1.20) 
28 ;; WHEN: Sat Aug  2 11:58:03 2014 
29 ;; MSG SIZE  rcvd: 191 

Everything is working fine now, so we’ll configure it to start automatically after a reboot. There are different ways to do it, for example in CentOS 6 we can use chkconfig.

1 [root@localhost ~]# chkconfig named on 
2 [root@localhost ~]# chkconfig --list named 
3 named           0:off   1:off   2:on    3:on    4:on    5:on    6:off 

In CentOS 7 we should use the systemctl command.

1 [root@localhost ~]# systemctl enable named

From now on, every time we restart the server the named service will be activated.

Now we’ll be able to resolve the domain names we have defined in our zones, but if we want our server to resolve internet domain names such as www.google.com, we’ll need to forward those requests to an external DNS server. If the external DNS server IP address is 192.168.1.1, we need to include the following lines in the /etc/named.conf file:

1 forwarders {
2                 192.168.1.1;
3         };

These previous lines should be included in the general options section, so the configuration file should remain like this:

 1 options {
 2         listen-on port 53 { any; };
 3         listen-on-v6 port 53 { any; };
 4 .
 5 .
 6 .
 7 forwarders {
 8                 192.168.1.1;
 9         };
10 .
11 .
12 .

4.4.- Client configuration

In Linux we can see the current DNS client configuration in the /etc/resolv.conf file.

1 [root@delphos ~]# cat /etc/resolv.conf 
2 nameserver 192.168.1.20
3 search olimpus.local

In this example, the client will send the DNS requests to the server at 192.168.1.20. If no DNS suffix is provided it will automatically add “olimpus.local”.

We can edit this file by hand, but it is usually more convenient to use one of the administrative tools every Linux distro has at our disposal. For instance in CentOS 6 we can use the program system-config-network, in CentOS 7 there isn’t a system-config-network program, but there is a similar one called nmtui, in Suse we can do the same thing with Yast, in Ubuntu we can open “System Settings”, and then go to network.

On the other hand in Windows we have to edit the LAN connection and then edit the properties of TCP/IP (Fig. 52 and Fig. 53).

Fig 52:LAN connection properties
Fig 52:LAN connection properties
Fig 53:IP configuration
Fig 53:IP configuration

Of course for clients to be able to access the DNS server we need to allow traffic to port 53 UDP in the firewall.

In CentOS 6:

1 [root@delphos ~]# iptables -I INPUT 2 -m state --state new -p udp --dport 53 -j \
2 ACCEPT

In CentOS 7:

1 [root@CentOS7 ~]# firewall-cmd --add-service=dns
2 success

In the case of CentOS 7, with the previous command we have allowed traffic to port 53 for both protocols UDP and TCP. We can see more details about the firewall included in CentOS 7 in the section 10 of this book.

4.5.- Slave servers and zone transfers

At this point we have a name server that holds all of the information of the olimpus.local zone. As we will see along this book, the DNS is of an utmost importance as it affects many other services, so needless to say, a shutdown of the service can be a complete disaster for our network. To try and minimize this risk we could install another server to provide the name service too. This new server would be a slave server, that is a server with a read-only copy of the zone files. It would be able to answer queries but it wouldn’t be able to update the information. Thus we have two servers to share the load, besides, if the master server becomes completely unusable we could easily transform the slave server into a master server.

We have seen in a previous chapter how to install CentOS, so we’ll assume we have a working CentOS server. We’ll install the bind package as we saw before. The named.conf file will have to be modified to add the following lines:

 1 zone "olimpus.local" IN { 
 2 type slave; 
 3 file "slaves/olimpus.local.zone"; 
 4 masters { 
 5 		192.168.1.20; 
 6 	}; 
 7 };
 8 
 9 zone "1.168.192.in-addr.arpa" IN { 
10         type slave; 
11         file "slaves/192.168.1.zone"; 
12 	masters { 
13                 192.168.1.20; 
14         }; 
15 
16 }; 
17 
18 zone "0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa" IN { 
19         type slave; 
20         file "slaves/fe80.0.0.0.zone"; 
21 	masters { 
22                 192.168.1.20; 
23         }; 
24 
25 }; 

Basically we name our zones, we declare them to be slave zones and tell the server about the master servers, 192.168.1.20 in this case.

Of course we’ll have to make the same changes we made in the master server to make sure that the server listens in all the network addresses, and it can be queried by anybody.

1 listen-on port 53 { any; }; 
2 listen-on-v6 port 53 { any; }; 
3 allow-query     { any; };

We’ll also have to make some minor changes in the zone files of the master server. We’ll create another NS register for the slave server. If the new server is prometheus the new line would be like this:

1 . 
2 . 
3 . 
4 IN NS delphos.olimpus.local. 
5 IN NS prometheus.olimpus.local. 
6 .	 
7 . 
8 . 

This should be done in the olimpus.local.zone, 192.168.1.zone and fe80.0.0.0.zone files. In addition, we should also notify the slave server whenever the zone file is updated. For that, we use the notify yes directive in the zone definition of the named.conf file:

 1 zone "olimpus.local" IN { 
 2         type master; 
 3         file "olimpus.local.zone"; 
 4         notify yes;        
 5 }; 
 6 
 7 zone "1.168.192.in-addr.arpa" IN { 
 8         type master; 
 9         file "192.168.1.zone"; 
10         notify yes;        
11 }; 
12 
13 zone "0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa" IN { 
14         type master; 
15         file "fe80.0.0.0.zone"; 
16         notify yes;   
17 }; 

In the slave server the named service should be able to create the zone files in the /var/named/slaves folder, so we’ll make sure the user named has the rights to write into that directory.

1 [root@localhost named]# ls -ld slaves/ 
2 drwxrwx---. 2 named named 4096 Dec  8  2011 slaves/ 

We have already seen SELINUX briefly. It could be described as a security mechanism that creates another layer of protection against unauthorized access and limits the damage a hacker could do to the system. SELinux limits what a process can do, that includes of course the named service. We’ll see how to make named work with it.

First, we check if SELinux is active:

1 [root@localhost named]# sestatus 
2 SELinux status:                 enabled 
3 SELinuxfs mount:                /selinux 
4 Current mode:                   enforcing 
5 Mode from config file:          enforcing 
6 Policy version:                 24 
7 Policy from config file:        targeted 

We also have to check the SELinux booleans associated with the DNS service.

1 [root@localhost named]# getsebool -a | grep named 
2 named_write_master_zones --> off 

This parameter implies that named won’t be allowed to write the zone files. Obviously this would make fail the zone transfer so we have to change the value to on.

1 [root@localhost named]# setsebool named_write_master_zones on 
2 [root@localhost named]# getsebool -a | grep named 
3 named_write_master_zones --> on 

We’ll make the change permanent with (-P)

1 [root@Centos7b ~]# setsebool -P named_write_master_zones 1

When transferring zones, the slave server will need to connect to port 53 on the master server. Obviously this port needs to be accessible from the slave server. To check it we can execute the nmap program from the slave server.

 1 [root@localhost named]# nmap -p 53 192.168.1.20                                 
 2 Starting Nmap 5.21 ( http://nmap.org ) at 2013-11-12 01:12 CET 
 3 mass_dns: warning: Unable to determine any DNS servers. Reverse DNS is disabled.\
 4  Try using --system-dns or specify valid servers with --dns-servers 
 5 Nmap scan report for 192.168.1.20 
 6 Host is up (0.00026s latency). 
 7 PORT   STATE    SERVICE 
 8 53/tcp filtered domain 
 9 MAC Address: 00:0C:29:78:4C:B1 (VMware) 
10 
11 Nmap done: 1 IP address (1 host up) scanned in 0.06 seconds 

As we see, the port is being filtered. We’ll have to open the port in the firewall in the master server. We’ll also see the use of the firewall in more detail later in this book. Now we’ll just explain how to open the port. Depending on whether we are using CentOS 6 or CentOS 7 the way to do it will be different.

In CentOS 6 we can list the firewall configuration by typing iptables -L in the master server.

 1 [root@localhost named]# iptables -L 
 2 Chain INPUT (policy ACCEPT) 
 3 target     prot opt source               destination 
 4 ACCEPT     all  --  anywhere             anywhere            state RELATED,ESTAB\
 5 LISHED 
 6 ACCEPT     icmp --  anywhere             anywhere 
 7 ACCEPT     all  --  anywhere             anywhere 
 8 ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:s\
 9 sh 
10 REJECT     all  --  anywhere             anywhere            reject-with icmp-ho\
11 st-prohibited 
12 
13 Chain FORWARD (policy ACCEPT) 
14 target     prot opt source               destination 
15 REJECT     all  --  anywhere             anywhere            reject-with icmp-ho\
16 st-prohibited 
17 
18 Chain OUTPUT (policy ACCEPT) 
19 target     prot opt source               destination 

By default, only connections to the ssh port are allowed. We’ll have to add the following line to permit access to port 53.

1 [root@localhost named]# iptables -I INPUT 5 -m state --state NEW -m tcp -p tcp -\
2 -dport 53 -j ACCEPT 

We insert a new input rule in the 5th position. We specify that new connections to the port 53 should be allowed. Once established the new connection, further traffic will be allowed too, as specified on the line:

1 ACCEPT     all  --  anywhere             anywhere            state RELATED,ESTAB\
2 LISHED

The complete set of firewall rules could be similar to this:

 1 [root@localhost named]# iptables -L 
 2 Chain INPUT (policy ACCEPT) 
 3 target     prot opt source               destination 
 4 ACCEPT     all  --  anywhere             anywhere            state RELATED,ESTAB\
 5 LISHED 
 6 ACCEPT     icmp --  anywhere             anywhere 
 7 ACCEPT     all  --  anywhere             anywhere 
 8 ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:s\
 9 sh 
10 ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:d\
11 omain 
12 REJECT     all  --  anywhere             anywhere            reject-with icmp-ho\
13 st-prohibited 
14 
15 Chain FORWARD (policy ACCEPT) 
16 target     prot opt source               destination 
17 REJECT     all  --  anywhere             anywhere            reject-with icmp-ho\
18 st-prohibited 
19 
20 Chain OUTPUT (policy ACCEPT) 
21 target     prot opt source               destination 

In CentOS 7 is also possible to use iptables but it is recommended to use the firewall-cmd command instead. First of all we need to find out the default zone.

1 [root@localhost ~]# firewall-cmd --get-default-zone
2 public

And then, we list the services allowed.

1 [root@localhost ~]# firewall-cmd --zone=internal --list-services
2 ssh

In this case only the ssh service is allowed, we’ll need to add the dns service.

1 [root@localhost ~]# firewall-cmd --zone=internal --add-service=dns
2  success

If now we repeat the test with nmap from the slave server, we’ll see that the port is open.

 1 [root@localhost named]# nmap -p 53 192.168.1.20 
 2 
 3 Starting Nmap 5.21 ( http://nmap.org ) at 2013-11-12 01:31 CET 
 4 mass_dns: warning: Unable to determine any DNS servers. Reverse DNS is disabled.\
 5  Try using --system-dns or specify valid servers with --dns-servers 
 6 Nmap scan report for 192.168.1.20 
 7 Host is up (0.0020s latency). 
 8 PORT   STATE SERVICE 
 9 53/tcp open  domain 
10 MAC Address: 00:0C:29:78:4C:B1 (VMware) 
11 
12 Nmap done: 1 IP address (1 host up) scanned in 0.07 seconds 

We’ll do the same in the slave server, so that zone tranfers can take place in both directions.

We will also change the following directives of the named.conf file in both servers, which are used with DNSEC.

1 dnssec-enable no; 
2 dnssec-validation no; 

Now we can check if the transfer zone actually works by restarting the named service on the slave server.

In CentOS 6:

1 [root@localhost named]# service named restart 
2 Stopping named:                                            [  OK  ] 
3 Starting named:                                            [  OK  ] 
4 [root@localhost named]# 

In CentOS 7:

1 [root@Centos7 ~]# systemctl restart named

If everything is OK we shoud now have three files in the /var/named/slaves folder.

1 [root@localhost named]# ls /var/named/slaves/ 
2 192.168.1.zone  fe80.0.0.0.zone  olimpus.local.zone 

Now every time we modify a zone in the master server we’ll update the serial number, thus the change should be replicated to the slave server. For example, let’s say we add a new server vulcan with IPv4 192.168.1.23 and IPv6 fe80::20c:29ff:fedf:d786/64.

We add the new A and AAAA registers in the zone file.

 1 . 
 2 . 
 3 . 
 4 delphos         IN A    192.168.1.20 
 5 prometheus      IN A    192.168.1.21 
 6 aphrodite       IN A    192.168.1.22 
 7 vulcan          IN A    192.168.1.23 
 8 
 9 delphos         IN AAAA fe80::20c:29ff:fe78:4cb1 
10 prometheus      IN AAAA fe80::20c:29ff:feeb:4443 
11 vulcan          IN AAAA fe80::20c:29ff:fedf:d786 
12 . 
13 . 
14 . 

And we add the PTR registers in the reverse zone files.

1 . 
2 . 
3 . 
4 22              PTR vulcan.olimpus.local. 
5 . 
6 . 
7 . 
8 6.8.7.d.f.d.e.f.f.f.9.2.c.0.2.0 IN PTR vulcan 

Finally we update the serial number in all the three files.

1 2014090102;     Serial

The update of the zone files shoud take place at one moment or another depending on the parameters defined in the zones themselves. But, anyway we can force the zone transfer with the rndc command (see section 4.6.1 on how to install it). We execute it from the slave server.

1 rndc retransfer olimpus.local 

After a few seconds master and slave will have the same information. We can check it by querying both servers with the dig command. From the slave server we can query both servers. First we query the slave server itself.

 1 [root@localhost ~]# dig @192.168.1.21 prometheus.olimpus.local 
 2 
 3 ; <<>> DiG 9.7.3-P3-RedHat-9.7.3-8.P3.el6 <<>> @192.168.1.21 prometheus.olimpus.\
 4 local 
 5 ; (1 server found) 
 6 ;; global options: +cmd 
 7 ;; Got answer: 
 8 ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 18441 
 9 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 3 
10 
11 ;; QUESTION SECTION: 
12 ;prometheus.olimpus.local.      IN      A 
13 
14 ;; ANSWER SECTION: 
15 prometheus.olimpus.local. 172800 IN     A       192.168.1.21 
16 
17 ;; AUTHORITY SECTION: 
18 olimpus.local.          172800  IN      NS      prometheus.olimpus.local. 
19 olimpus.local.          172800  IN      NS      delphos.olimpus.local. 
20 
21 ;; ADDITIONAL SECTION: 
22 delphos.olimpus.local.  172800  IN      A       192.168.1.20 
23 delphos.olimpus.local.  172800  IN      AAAA    fe80::20c:29ff:fe78:4cb1 
24 prometheus.olimpus.local. 172800 IN     AAAA    fe80::20c:29ff:feeb:4443 
25 
26 ;; Query time: 1 msec 
27 ;; SERVER: 192.168.1.21#53(192.168.1.21) 
28 ;; WHEN: Sun Aug  3 04:40:00 2014 
29 ;; MSG SIZE  rcvd: 166 

And then we query the master server, to see if the 2 answers are the same. We must take into account that the firewall might be blocking the query. In order to allow zone transfers we opened before the firewall for connections to tcp port 53, nevertheless DNS queries don’t use TCP port 53, but UDP port 53. If this is the case, we’ll have to open UDP port 53 in the firewall.

In Centos 6:

1 [root@localhost ~]# iptables -I INPUT 4 -p udp --dport 53 -j ACCEPT 

In CentOS 7:

The same command we used to allow zone transfers will permit both transfers and queries.

1 [root@localhost ~]# firewall-cmd --zone=internal --add-service=dns
2 success

Now we can perform the query…

 1 [root@localhost ~]# dig @192.168.1.20 prometheus.olimpus.local 
 2 
 3 ; <<>> DiG 9.7.3-P3-RedHat-9.7.3-8.P3.el6 <<>> @192.168.1.20 prometheus.olimpus.\
 4 local 
 5 ; (1 server found) 
 6 ;; global options: +cmd 
 7 ;; Got answer: 
 8 ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 57417 
 9 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 3 
10 
11 ;; QUESTION SECTION: 
12 ;prometheus.olimpus.local.      IN      A 
13 
14 ;; ANSWER SECTION: 
15 prometheus.olimpus.local. 172800 IN     A       192.168.1.21 
16 
17 ;; AUTHORITY SECTION: 
18 olimpus.local.          172800  IN      NS      prometheus.olimpus.local. 
19 olimpus.local.          172800  IN      NS      delphos.olimpus.local. 
20 
21 ;; ADDITIONAL SECTION: 
22 delphos.olimpus.local.  172800  IN      A       192.168.1.20 
23 delphos.olimpus.local.  172800  IN      AAAA    fe80::20c:29ff:fe78:4cb1 
24 prometheus.olimpus.local. 172800 IN     AAAA    fe80::20c:29ff:feeb:4443 
25 
26 ;; Query time: 2 msec 
27 ;; SERVER: 192.168.1.20#53(192.168.1.20) 
28 ;; WHEN: Sun Aug  3 05:42:05 2014 
29 ;; MSG SIZE  rcvd: 166 

As we can see, the result is the same in both cases.

4.6.- DNSSEC

The domain name service is of an utmost importance in any network infrastructure, but unfortunately is quite vulnerable to attacks. If a malicious hacker manages to inject wrong dns answers in the network they’d be able to control the traffic. For example, let’s say a user wants to check their mail and so it tries to access http://gmail.com, if an attacker can send a DNS reply for the domain gmail.com the user’s computer will try to access the wrong gmail.com.

To minimize this risk DNSSEC was developed. DNSSEC doesn’t actually avoids these attacks but it makes possible to detect them. It works by signing the zone files so that we know if an unauthorized change took place. To use DNSSEC first we must generate two keys for our zone.

We’ll need to generate two sets of keys, the Zone Signing Keys (ZSK) and the Key Signing Keys (KSK). First we create the ZSK.

1 [root@localhost named]# dnssec-keygen -a RSASHA1 -b 512 -n ZONE olimpus.local 
2 Generating key pair.....++++++++++++ ....++++++++++++ 
3 Kolimpus.local.+005+08586 

The process of generating the keys can take very very long, up to several hours. If we want to speed up the process we can install haveged, which acts as a random number generator. The package haveged currently is not included as part of the CentOS 6 software packages, but it can be installed from the Internet. On the other hand, if we’re working with CentOS 7 we can download it from the EPEL repository. This repository is not part of the default repositories for CentOS 7 but it can be configured very easily by executing the following command:

1 [root@CentOS7 ~]# yum install epel-release

And now, we generate the KSK. As we said before, it can take quite a long time.

1 [root@localhost named]# dnssec-keygen -f KSK -a RSASHA1 -b 4096 -n ZONE olimpus.\
2 local 
3 Generating key pair.............++..............................................\
4 ..........................................++ 
5 Kolimpus.local.+005+35116 

Now we’ll have to add the key files we created before to the zone file.

1 [root@localhost named]# cat Kolimpus.local.*.key >> olimpus.local.zone 

And sign the zone file.

1 [root@localhost named]# dnssec-signzone -N increment -o olimpus.local olimpus.lo\
2 cal.zone 
3 Verifying the zone using the following algorithms: RSASHA1. 
4 Zone signing complete: 
5 Algorithm: RSASHA1: KSKs: 1 active, 0 stand-by, 0 revoked 
6                     ZSKs: 1 active, 0 stand-by, 0 revoked 
7 olimpus.local.zone.signed 

Now we have a new olimpus.local.zone.signed file. We’ll have to change the definition of the olimpus.local zone in /etc/named.conf to point to this new file.

 1 . 
 2 . 
 3 . 
 4 zone "olimpus.local" IN { 
 5         type master; 
 6         file "olimpus.local.zone.signed"; 
 7         notify yes; 
 8 }; 
 9 . 
10 . 
11 . 

And we restart the named service.

In CentOS 6:

1 [root@localhost named]# service named restart 
2 Stopping named:                                            [  OK  ] 
3 Starting named:                                            [  OK  ] 

IN CentOS 7:

1 [root@CentOS7 named]# systemctl restart named

To make sure that DNSSEC is actually working we can query for the DNSKEY record of the domain like this:

 1 [root@localhost ~]# dig @192.168.1.20 DNSKEY olimpus.local. +multiline 
 2 ;; Truncated, retrying in TCP mode. 
 3 
 4 ; <<>> DiG 9.7.3-P3-RedHat-9.7.3-8.P3.el6 <<>> @192.168.1.20 DNSKEY olimpus.loca\
 5 l. +multiline 
 6 ; (1 server found) 
 7 ;; global options: +cmd 
 8 ;; Got answer: 
 9 ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48176 
10 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0 
11 
12 ;; QUESTION SECTION: 
13 ;olimpus.local.         IN DNSKEY 
14 
15 ;; ANSWER SECTION: 
16 olimpus.local.          172800 IN DNSKEY 257 3 5 ( 
17                                 AwEAAeGilVrj9hxnmjRY9Yd9SqrBMwtiqKwfSda3wXhn 
18                                 d3koFZQzVI129xRVxEhaXpQvcH4tZG724hE/NF/zq6jI 
19                                 H2q6OtU0poslWLnRTE4Cte0EMP/Q4dSpSzLqjT4+cPrw 
20                                 Fyfgvv7q+dHBHJ0TiWJjeSffFDFcACPfqY3KIFHNxgD3 
21                                 bBwdO/GXgLDACBVoH7qVCNRBosuji24lmxwYu9qO0qX5 
22                                 sTF1mhmKpOm4u02CEVhSnTeXlER4XermehqLhOLlodWl 
23                                 R75EmAYc13SvMS9CoFc66eXEOpSLOl7F9eZQ/RHh/Wob 
24                                 x74moN1uSwP32fTYhJZr3GXOTey+kfnpvhBIxXRa6nbB 
25                                 2jfLsN0PMb4ZEYTAXOICtevRDYptuM3ytakPd3elNfrm 
26                                 px9vxkFMye1/18diS/VWXD7RBc8wpbK0aQBMYV94dKhB 
27                                 a3F6SV9tbXF7nTadG7k0I+US0kUSfppCjWr+TTwdfvGR 
28                                 e/M7XPM1riBv/zUgSp7XzOKWdYT2mQjPR4xl21FcsSwy 
29                                 tehCWoS+xGEd3y9AaW7RHAwPjeexMR30458/h1cqQcEs 
30                                 QCQltl3uboqjFon3s4iHcHIqtpnBUC/TaonMA39pBTXt 
31                                 VFPO+EV3YJBKFgGf1qZRW9aFAU+BHAnaRt2svPmBId7n 
32                                 4O778a14Jgaco4b64Y6Ij3Mx8as5 
33                                 ) ; key id = 9187 
34 olimpus.local.          172800 IN DNSKEY 256 3 5 ( 
35                                 AwEAAb386KgB7QrWAWBZ9+uSaHjHmpW+3TpcGkCfh9T4 
36                                 Znl6BJVb/kPp6DmfeTRzjFUQSbAGRiI3yvzJ9+iEUhra 
37                                 dME= 
38                                 ) ; key id = 28332 
39 
40 ;; Query time: 2 msec 
41 ;; SERVER: 192.168.1.20#53(192.168.1.20) 
42 ;; WHEN: Sun Aug  3 20:11:10 2014 
43 ;; MSG SIZE  rcvd: 647 

As we see, the query was answered correctly.

4.7.- Diagnostic tools

4.7.1.- rndc

Rndc is a great tool to manage the name server. If we remember, when we checked the status of the named service we saw a message saying “rndc: neither /etc/rndc.conf nor /etc/rndc.key was found”. These two files are needed by the command rndc to work. Rndc is a front-end to control the DNS server, so we’ll have to modify /etc/named.conf to allow rndc to manage the server. We can do it by hand, but is much easier to do it by typing rndc-confgen. This command will show a sample rndc.key and rndc.conf file that we can use.

Rndc-confgen will have to generate keys so it can take it as long as a few minutes to complete. A bit of patience is needed.

 1 [root@localhost ~]# rndc-confgen 
 2 # Start of rndc.conf 
 3 key "rndc-key" { 
 4         algorithm hmac-md5; 
 5         secret "Yg1R5vvMWBu/+P9RxCKm8g=="; 
 6 }; 
 7 
 8 options { 
 9         default-key "rndc-key"; 
10         default-server 127.0.0.1; 
11         default-port 953; 
12 }; 
13 # End of rndc.conf 
14 
15 # Use with the following in named.conf, adjusting the allow list as needed: 
16 # key "rndc-key" { 
17 #       algorithm hmac-md5; 
18 #       secret "Yg1R5vvMWBu/+P9RxCKm8g=="; 
19 # }; 
20 # 
21 # controls { 
22 #       inet 127.0.0.1 port 953 
23 #               allow { 127.0.0.1; } keys { "rndc-key"; }; 
24 # }; 
25 # End of named.conf 

So we create a file named /etc/rnc.conf:

 1 # Start of rndc.conf 
 2 key "rndc-key" { 
 3         algorithm hmac-md5; 
 4         secret "Yg1R5vvMWBu/+P9RxCKm8g=="; 
 5 }; 
 6 
 7 options { 
 8         default-key "rndc-key"; 
 9         default-server 127.0.0.1; 
10         default-port 953; 
11 }; 
12 # End of rndc.conf 

And we modify the /etc/named.conf as instructed. Adding the lines generated by rndc-confgen.

We restart the service and try to execute rndc.

 1 [root@localhost named]# rndc status 
 2 version: 9.7.3-P3-RedHat-9.7.3-8.P3.el6 
 3 CPUs found: 1 
 4 worker threads: 1 
 5 number of zones: 22 
 6 debug level: 0 
 7 xfers running: 0 
 8 xfers deferred: 0 
 9 soa queries in progress: 0 
10 query logging is OFF 
11 recursive clients: 0/0/1000 
12 tcp clients: 0/100 
13 server is up and running 

To see the options available we can use the -h option

 1 [root@localhost named]# rndc -h 
 2 Usage: rndc [-b address] [-c config] [-s server] [-p port] 
 3         [-k key-file ] [-y key] [-V] command 
 4 
 5 command is one of the following: 
 6 
 7   reload        Reload configuration file and zones. 
 8   reload zone [class [view]] 
 9                 Reload a single zone. 
10   refresh zone [class [view]] 
11                 Schedule immediate maintenance for a zone. 
12   retransfer zone [class [view]] 
13                 Retransfer a single zone without checking serial number. 
14   freeze        Suspend updates to all dynamic zones. 
15   freeze zone [class [view]] 
16                 Suspend updates to a dynamic zone. 
17   thaw          Enable updates to all dynamic zones and reload them. 
18   thaw zone [class [view]] 
19                 Enable updates to a frozen dynamic zone and reload it. 
20   notify zone [class [view]] 
21                 Resend NOTIFY messages for the zone. 
22   reconfig      Reload configuration file and new zones only. 
23   sign zone [class [view]] 
24                 Update zone keys, and sign as needed. 
25   loadkeys zone [class [view]] 
26                 Update keys without signing immediately. 
27   stats         Write server statistics to the statistics file. 
28   querylog      Toggle query logging. 
29   dumpdb [-all|-cache|-zones] [view ...] 
30                 Dump cache(s) to the dump file (named_dump.db). 
31   secroots [view ...] 
32                 Write security roots to the secroots file. 
33   stop          Save pending updates to master files and stop the server. 
34   stop -p       Save pending updates to master files and stop the server 
35                 reporting process id. 
36   halt          Stop the server without saving pending updates. 
37   halt -p       Stop the server without saving pending updates reporting 
38                 process id. 
39   trace         Increment debugging level by one. 
40   trace level   Change the debugging level. 
41   notrace       Set debugging level to 0. 
42   flush         Flushes all of the server's caches. 
43   flush [view]  Flushes the server's cache for a view. 
44   flushname name [view] 
45                 Flush the given name from the server's cache(s) 
46   status        Display status of the server. 
47   recursing     Dump the queries that are currently recursing (named.recursing) 
48   validation newstate [view] 
49                 Enable / disable DNSSEC validation. 
50   *restart      Restart the server. 
51   addzone ["file"] zone [class [view]] { zone-options } 
52                 Add zone to given view. Requires new-zone-file option. 
53   delzone ["file"] zone [class [view]] 
54                 Removes zone from given view. Requires new-zone-file option. 
55 
56 * == not yet implemented 
57 Version: 9.7.3-P3-RedHat-9.7.3-8.P3.el6

4.7.2.- dig

We have already seen this tool, we can use it to query a DNS server and specify the type of register we want to know about. For instance, to know the mail server of the domain olimpus.local we’d type this:

 1 [root@localhost ~]# dig mx @192.168.1.21 olimpus.local 
 2 
 3 ; <<>> DiG 9.7.3-P3-RedHat-9.7.3-8.P3.el6 <<>> mx @192.168.1.21 olimpus.local 
 4 ; (1 server found) 
 5 ;; global options: +cmd 
 6 ;; Got answer: 
 7 ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 3247 
 8 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 4 
 9 
10 ;; QUESTION SECTION: 
11 ;olimpus.local.                 IN      MX 
12 
13 ;; ANSWER SECTION: 
14 olimpus.local.          172800  IN      MX      10 prometheus.olimpus.local. 
15 
16 ;; AUTHORITY SECTION: 
17 olimpus.local.          172800  IN      NS      prometheus.olimpus.local. 
18 olimpus.local.          172800  IN      NS      delphos.olimpus.local.
19 
20 ;; ADDITIONAL SECTION: 
21 prometheus.olimpus.local. 172800 IN     A       192.168.1.21 
22 prometheus.olimpus.local. 172800 IN     AAAA    fe80::20c:29ff:feeb:4443 
23 delphos.olimpus.local.  172800  IN      A       192.168.1.20 
24 delphos.olimpus.local.  172800  IN      AAAA    fe80::20c:29ff:fe78:4cb1 
25 
26 ;; Query time: 12 msec 
27 ;; SERVER: 192.168.1.21#53(192.168.1.21) 
28 ;; WHEN: Sun Aug  3 04:37:03 2014 
29 ;; MSG SIZE  rcvd: 182 

If we don’t want to be overwhelmed with so much information we can tell dig not to show all the details of the query (+noall) and include only the answer itself(+answer).

1 [root@localhost ~]# dig +noall +answer mx @192.168.1.21 olimpus.local 
2 olimpus.local.          172800  IN      MX      10 prometheus.olimpus.local. 

We can also ask for a complete zone transfer.

 1 [root@localhost ~]# dig axfr @192.168.1.20 olimpus.local 
 2 
 3 ; <<>> DiG 9.7.3-P3-RedHat-9.7.3-8.P3.el6 <<>> axfr @192.168.1.20 olimpus.local 
 4 ; (1 server found) 
 5 ;; global options: +cmd 
 6 olimpus.local.          172800  IN      SOA     olimpus.local. root.olimpus.loca\
 7 l. 2014090103 60 7200 604800 172800 
 8 olimpus.local.          172800  IN      NS      delphos.olimpus.local. 
 9 olimpus.local.          172800  IN      NS      prometheus.olimpus.local. 
10 olimpus.local.          172800  IN      MX      10 prometheus.olimpus.local. 
11 aphrodite.olimpus.local. 172800 IN      A       192.168.1.22 
12 delphos.olimpus.local.  172800  IN      AAAA    fe80::20c:29ff:fe78:4cb1 
13 delphos.olimpus.local.  172800  IN      A       192.168.1.20 
14 dns.olimpus.local.      172800  IN      CNAME   delphos.olimpus.local. 
15 mail.olimpus.local.     172800  IN      CNAME   prometheus.olimpus.local. 
16 prometheus.olimpus.local. 172800 IN     AAAA    fe80::20c:29ff:feeb:4443 
17 prometheus.olimpus.local. 172800 IN     A       192.168.1.21 
18 vulcan.olimpus.local.   172800  IN      AAAA    fe80::20c:29ff:fedf:d786 
19 vulcan.olimpus.local.   172800  IN      A       192.168.1.23 
20 olimpus.local.          172800  IN      SOA     olimpus.local. root.olimpus.loca\
21 l. 2014090103 60 7200 604800 172800 
22 ;; Query time: 6 msec 
23 ;; SERVER: 192.168.1.20#53(192.168.1.20) 
24 ;; WHEN: Sun Aug  3 05:46:46 2014 
25 ;; XFR size: 14 records (messages 1, bytes 373) 

4.7.3.- host

Host is a tool quite similar to dig, the syntax is slightly different though.

1 [root@localhost ~]# host prometheus.olimpus.local 192.168.1.20 
2 Using domain server: 
3 Name: 192.168.1.20 
4 Address: 192.168.1.20#53 
5 Aliases: 
6 
7 prometheus.olimpus.local has address 192.168.1.21 
8 prometheus.olimpus.local has IPv6 address fe80::20c:29ff:feeb:4443 

4.8.- Troubleshooting

As every sysadmin knows, unfortunately incidents happen, and sometimes the things don’t work as expected, or don’t work at all. These are some of the most common scenarios we could see.

4.8.1.- A computer can’t resolve names

If there is only a small percentage of computers that cannot resolve names, that is probably a problem with the client computers themselves. We’ll have to check that the computer has set correctly the address of the DNS server in the network. In the case of a Linux, this is configured in the file /etc/resolv.conf. For instance, if the DNS server is 192.168.1.20, the /etc/resolv.conf file should be something like this.

1 [root@localhost ~]# cat /etc/resolv.conf 
2 nameserver 192.168.1.20 

If the file is correct we’d have to check also the network configuration and the physical connection to the network.

4.8.2.- Many computers can’t resolve names

If there are many computers unable to resolve names there might be some problem with the DNS server itself. First of all we’ll have to check that the service is running.

 1 [root@localhost ~]# service named status 
 2 version: 9.7.3-P3-RedHat-9.7.3-8.P3.el6 
 3 CPUs found: 1 
 4 worker threads: 1 
 5 number of zones: 22 
 6 debug level: 0 
 7 xfers running: 0 
 8 xfers deferred: 0 
 9 soa queries in progress: 0 
10 query logging is OFF 
11 recursive clients: 0/0/1000 
12 tcp clients: 0/100 
13 server is up and running 
14 named (pid  8616) is running... 

If the service is up and running the next step we should take is to make sure that the service can be accessed from the network. As we said before, the DNS queries are addressed to UDP port 53 in the server, so we can use nmap from a client computer to check whether the port is open or not.

1 [root@localhost ~]# nmap -sU -p 53 192.168.1.20 
2 
3 Starting Nmap 5.21 ( http://nmap.org ) at 2014-08-03 05:40 CEST 
4 Nmap scan report for delphos.olimpus.local (192.168.1.20) 
5 Host is up (0.00085s latency). 
6 PORT   STATE    SERVICE 
7 53/udp filtered domain 
8 MAC Address: 00:0C:29:78:4C:B1 (VMware) 

In this case the port is filtered, that’s the reason why the clients can’t resolve names, they’re unable to contact the name server.

 1 [root@localhost ~]# nmap -sU -p 53 192.168.1.20 
 2 
 3 Starting Nmap 5.21 ( http://nmap.org ) at 2014-08-03 06:23 CEST 
 4 Nmap scan report for delphos.olimpus.local (192.168.1.20) 
 5 Host is up (0.00033s latency). 
 6 PORT   STATE SERVICE 
 7 53/udp open  domain 
 8 MAC Address: 00:0C:29:78:4C:B1 (VMware) 
 9 
10 Nmap done: 1 IP address (1 host up) scanned in 0.07 seconds 

But now the port is open. We should perform a query from the client computer by using dig or host.

 1 [root@localhost ~]# dig @192.168.1.20 delphos.olimpus.local 
 2 
 3 ; <<>> DiG 9.7.3-P3-RedHat-9.7.3-8.P3.el6 <<>> @192.168.1.20 delphos.olimpus.loc\
 4 al 
 5 ; (1 server found) 
 6 ;; global options: +cmd 
 7 ;; Got answer: 
 8 ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 51991 
 9 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 3 
10 
11 ;; QUESTION SECTION: 
12 ;delphos.olimpus.local.         IN      A 
13 
14 ;; ANSWER SECTION: 
15 delphos.olimpus.local.  172800  IN      A       192.168.1.20 
16 
17 ;; AUTHORITY SECTION: 
18 olimpus.local.          172800  IN      NS      delphos.olimpus.local. 
19 olimpus.local.          172800  IN      NS      prometheus.olimpus.local. 
20 
21 ;; ADDITIONAL SECTION: 
22 delphos.olimpus.local.  172800  IN      AAAA    fe80::20c:29ff:fe78:4cb1 
23 prometheus.olimpus.local. 172800 IN     A       192.168.1.21 
24 prometheus.olimpus.local. 172800 IN     AAAA    fe80::20c:29ff:feeb:4443 
25 
26 ;; Query time: 2 msec 
27 ;; SERVER: 192.168.1.20#53(192.168.1.20) 
28 ;; WHEN: Sun Aug  3 06:26:04 2014 
29 ;; MSG SIZE  rcvd: 166 

In this case the DNS server seems to be working fine. The client made a query and got an answer.

 1 [root@localhost ~]# dig @192.168.1.20 neptune.olimpus.local 
 2 
 3 ; <<>> DiG 9.7.3-P3-RedHat-9.7.3-8.P3.el6 <<>> @192.168.1.20 neptune.olimpus.loc\
 4 al 
 5 ; (1 server found) 
 6 ;; global options: +cmd 
 7 ;; Got answer: 
 8 ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 60601 
 9 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0 
10 
11 ;; QUESTION SECTION: 
12 ;neptune.olimpus.local.         IN      A 
13 
14 ;; AUTHORITY SECTION: 
15 olimpus.local.          172800  IN      SOA     olimpus.local. root.olimpus.loca\
16 l. 2014090103 60 7200 604800 172800 
17 
18 ;; Query time: 2 msec 
19 ;; SERVER: 192.168.1.20#53(192.168.1.20) 
20 ;; WHEN: Sun Aug  3 06:26:21 2014 
21 ;; MSG SIZE  rcvd: 80 

On the other hand, in this case the server answered the query, but it couldn’t find any neptune.olimpus.local register. It might not exist in the zone or maybe the server has an outdated zone file.

4.8.3.- Master and slave server don’t have the same information

If the slave server has outdated information, we need to know whether there is a problem with zone transfers. As we have seen, we can use dig on the slave server to request a zone transfer.

1 [root@localhost ~]# dig axfr @192.168.1.20 olimpus.local                        
2 ;; Connection to 192.168.1.20#53(192.168.1.20) for olimpus.local failed: host un\
3 reachable. 

In this case we couldn’t perform the zone transfer, the TCP port 53 on the master server is probably closed or filtered.

 1 [root@localhost ~]# dig axfr @192.168.1.20 olimpus.local 
 2 
 3 ; <<>> DiG 9.7.3-P3-RedHat-9.7.3-8.P3.el6 <<>> axfr @192.168.1.20 olimpus.local 
 4 ; (1 server found) 
 5 ;; global options: +cmd 
 6 olimpus.local.          172800  IN      SOA     olimpus.local. root.olimpus.loca\
 7 l. 2014090103 60 7200 604800 172800 
 8 olimpus.local.          172800  IN      NS      delphos.olimpus.local. 
 9 olimpus.local.          172800  IN      NS      prometheus.olimpus.local. 
10 olimpus.local.          172800  IN      MX      10 prometheus.olimpus.local. 
11 aphrodite.olimpus.local. 172800 IN      A       192.168.1.22 
12 delphos.olimpus.local.  172800  IN      AAAA    fe80::20c:29ff:fe78:4cb1 
13 delphos.olimpus.local.  172800  IN      A       192.168.1.20 
14 dns.olimpus.local.      172800  IN      CNAME   delphos.olimpus.local. 
15 mail.olimpus.local.     172800  IN      CNAME   prometheus.olimpus.local. 
16 prometheus.olimpus.local. 172800 IN     AAAA    fe80::20c:29ff:feeb:4443 
17 prometheus.olimpus.local. 172800 IN     A       192.168.1.21 
18 vulcan.olimpus.local.   172800  IN      AAAA    fe80::20c:29ff:fedf:d786 
19 vulcan.olimpus.local.   172800  IN      A       192.168.1.23 
20 olimpus.local.          172800  IN      SOA     olimpus.local. root.olimpus.loca\
21 l. 2014090103 60 7200 604800 172800 
22 ;; Query time: 6 msec 
23 ;; SERVER: 192.168.1.20#53(192.168.1.20) 
24 ;; WHEN: Sun Aug  3 05:46:46 2014 
25 ;; XFR size: 14 records (messages 1, bytes 373) 

Now the transfer zone was correct. We can use rndc to request a zone transfer on the slave server.

1 [root@localhost ~]# rndc retransfer olimpus.local 
2 [root@localhost ~]# 

4.9.- Log files

Maybe the most important tool when troubleshooting are the log files. In a default installation of bind, the log file will be /var/named/data/named.run. This is defined in the following lines of the /etc/named.conf file:

1 logging { 
2         channel default_debug { 
3                 file "data/named.run"; 
4                 severity dynamic; 
5         }; 
6 }; 

By watching this file we can monitor the state of the server. For instance, this could be part of the log file.

 1 . 
 2 . 
 3 . 
 4 received control channel command 'stop' 
 5 shutting down: flushing changes 
 6 stopping command channel on 127.0.0.1#953 
 7 no longer listening on ::#53 
 8 no longer listening on 127.0.0.1#53 
 9 no longer listening on 192.168.1.20#53 
10 exiting 
11 zone 0.in-addr.arpa/IN: loaded serial 0 
12 zone 1.0.0.127.in-addr.arpa/IN: loaded serial 0 
13 zone 1.168.192.in-addr.arpa/IN: loaded serial 2014090102 
14 zone 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa/IN\
15 : loaded serial 0 
16 zone 0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa/IN: loaded serial 2014090102 
17 zone olimpus.local/IN: loaded serial 2014090103 
18 zone localhost.localdomain/IN: loaded serial 0 
19 zone localhost/IN: loaded serial 0 
20 . 
21 . 
22 . 

In this case we can see that the name server stopped and started to load the zone files again.