Set up a DNS server using BIND





In a previous article, Introduction to the Domain Name System (DNS), I described how the DNS database is structured and how to configure name services on a client. I also listed and describe some of the more common DNS records you are likely to encounter when building a name server or just trying to interpret the results of a dig command.

In this article I show you how to build your own name server using BIND, the Berkeley Internet Name Domain. It is not as difficult as you might think, especially since it can be done in two stages.

In this article you will start by learning how to create a caching name server. Then you will move on and learn how to upgrade that to a complete primary (master) domain name server for your network complete with forward and reverse zone files.

Setting up a name server using BIND is quite straightforward so I thought I would show you how to do so on any computer you might happen to have available for experimentation. This little lab project will show you how to install and configure BIND on your computer as a caching name server, test it, then set it up as a primary name server with a zone file that you can use as a name resolver for your network or just for testing.

It is technically possible to set up a name server on any GNU/Linux computer you have available because it will not interfere with other hosts on the network or their operation. However you should probably not do this on a computer that you do not own or have the right to modify unless you have explicit permission to do so.

My setup

You only need one computer to perform all but one of the tasks in this lab project. I use this setup on my much more powerful Thinkpad because the name servers provided by DHCP when I connect to non-home networks using either wired or wireless connections can sometimes be unreliable. To show that almost any host can perform well as a name server, I have tested this project on an old ASUS EeePC 900 netbook that has the following specifications.

Item Description
Motherboard ASUSTeK 900A
CPU Intel(R) Atom(TM) CPU N270, single core, 32-bit with hyperthreading
Speed 1.6GHz
RAM 2GB
Swap 2GB
sda Internal 4GB SSD
sdb 32GB SD card
Operating System Fedora 25 32-bit
Hostname epc

 

I will use the private IP address of my ASUS for this project but you should use the IP address of the host that you are using.

The hosts file

First let’s take a look at the /etc/hosts file. In its default state, there should only be two lines in the hosts file, the first two lines seen in Listing 1, below.

127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 
# Lab hosts 
192.168.25.1      server 
192.168.25.21     host1 
192.168.25.22     host2 
192.168.25.23     host3 
192.168.25.24     host4

Listing 1: A simple hosts file can be maintained by a user to perform the function of a resolver in small networks.


Although you can add hostnames and their respective IP Addresses as shown in Listing 1, that is not an optimal solution to name services, especially when traveling. If there are other entries in your hosts file you may need to comment them out for the duration of this project if they interfere with naming or IP addresses. Most of you will not have any entries other than the two default lines.

Preparation

A caching nameserver cannot replace our use of /etc/hosts to resolve hostnames on the internal network but compared to using an ISP or other public nameserver, however, a caching nameserver can improve performance when resolving external names that are commonly used, such as www.cnn.com. The best part is that setting up a caching nameserver is quite easy. Before starting, you should prepare by performing the following steps.

First, make backup copies of the files /etc/hosts, /etc/named.conf, resolv.conf, and /etc/sysconfig/iptables.

If they are not already installed, use your distribution’s package manager to install the following BIND RPMs: bind, bind-chroot, and bind-utils. To enable your lab host to use the caching nameserver, you must add a nameserver line to point to your own host in /etc/resolv.conf. For example, if your lab host IP Address is 192.168.0.203, as is my epc, add the following line to the top of the nameserver list in /etc/resolv.conf:

nameserver 192.168.0.203

Be sure to use the IP Address of the host on which you are doing this project.

You could use the IP Address of your localhost, 127.0.0.1 instead of the external IP address. You should also comment out any lines pointing to other hosts as name servers. Be sure to save the revised resolv.conf file.

These changes will take effect immediately and no reboot or service restart is required. Now attempt to ping a common public host that does not block ICMP packets; feel free to use my firewall, which is a Raspberry Pi.

ping wally2.both.org

You should get an “unknown host” or “Name or service not known” error because you currently have no working DNS service or resolver defined in the resolv.conf file. Now use the dig command to see if name services is working.

dig wally2.both.com

You should get the error, “connection timed out; no servers could be reached.”

Set up a Caching Nameserver

A caching name server is not an authoritative source for any domain. It simply caches the results of all name resolver requests from the network which it serves in order to speed up responses to future requests for the same remote host.

For the initial setup of the caching name server it is necessary to make a couple modifications to the default /etc/named.conf file so edit that file using your favorite editor. First, add the IP address of your local test host to the “listen-on port 53” line as shown in Listing 2, below. This enables named to listen on the external IP Address of your host so that other computers can use it as a nameserver as well.

Note: The named.conf file is very particular about syntax and especially punctuation. Semi-colons are used to delineate the end of an entry and the end of a stanza as well as the end of a line. Be sure to add them in correctly as shown in the samples.

By default, BIND refers to the Internet’s root Name Servers to locate the authoritative name servers for a domain. It is possible to specify other servers that are called “Forwarders” to which the local instance of BIND will send requests instead of the root servers. This does increase the possibility of DNS hijacking.

Add a “forwarders” line as shown below. This tells your caching DNS server where to obtain IP Addresses when they are not already cached locally. The IP Addresses in the listing below is for the Google public DNS servers You could use your local ISP or OpenDNS or some other public name server as your forwarder. It is not necessary to define any forwarders and, in that case, BIND would use the Internet root servers as defined in the file /var/named/named.ca to locate the authoritative name servers for domains if no forwarders are defined. But for this exercise, please define the forwarders as I have in Listing 2.

Comment out the IPV6 line as we are not using IPV6 in the lab environment. Note that the “//” two forward slashes denote comments in the named.conf file.

//
// named.conf
// Provided by Red Hat bind package to configure the ISC BIND named(8) DNS
// server as a caching only nameserver (as a localhost DNS resolver only).
// See /usr/share/doc/bind*/sample/ for example named configuration files.
//
//

options {
     listen-on port 53 { 127.0.0.1; 192.168.0.203; };
     // listen-on-v6 port 53 { ::1; };
     forwarders { 8.8.8.8; 8.8.4.4; };
     directory "/var/named";
     dump-file "/var/named/data/cache_dump.db";
     statistics-file "/var/named/data/named_stats.txt";
     memstatistics-file "/var/named/data/named_mem_stats.txt";
     allow-query { localhost; 192.168.0.0/24; };
     recursion yes;
     dnssec-enable yes;
     dnssec-validation yes;
     dnssec-lookaside auto;
     /* Path to ISC DLV key */
     bindkeys-file "/etc/named.iscdlv.key";
     managed-keys-directory "/var/named/dynamic";
};

logging {
     channel default_debug {
     file "data/named.run";
     severity dynamic;
};
};

zone "." IN {
     type hint;
     file "named.ca";
};

include "/etc/named.rfc1912.zones";
include "/etc/named.root.key";

Listing 2: The /etc/named.conf file provides the simple configuration required to set up a caching name server. The lines that need to be added or changed are highlighted in bold.

Add the local network address, 192.168.0.0/24, to the allow-query line. This line specifies the network(s) from which DNS queries will be accepted by this DNS server.

Start the Name Service

Now start the named service and configure the named service to start at every boot. I use the systemctl command on my Fedora 25 host, but the command may be different on your host, depending upon the distribution you are using. Note that the name of the BIND resolver service is named.

systemctl enable named
systemctl start named

The first test you can perform to ensure that your caching name server is working is to use dig to locate the DNS database information for wally2.both.org. To further test your caching nameserver, use the dig command to obtain the IP Address(es) for some common Internet web sites, such as www.opensource.com, CNN, Wired, and any others you like. The results should now show your host as the responding server.

At this point your caching nameserver will correctly resolve hosts on the Internet. That is because those DNS requests for public hosts are forwarded to the Google public name servers. Refer to the “forwarders” line in named.conf. However you are still dependent upon the /etc/hosts file for internal name services. Creating a primary name server can solve that problem.

Creating a primary Nameserver

Once a caching nameserver has been created, it is not too difficult to convert it into a full-fledged primary nameserver. A primary name server is the authoritative source for the domain it represents.

We need to change named.conf again and create a couple new files. We will create a domain called example.com which is a domain name reserved for example purposes in documents like this one. The example.com domain does have an IP address on the Internet and a very spare web site, but we can use the name in the rest of our lab project without causing problems for anyone. The example.com domain will be the internal domain name for the rest of this exercise.

The two new files we will create are the forward and reverse zone files. They will be located in the /var/named directory. This location is specified by the “directory” directive in the named.conf configuration file.

Create the Forward Zone File

The forward zone file contains “A” records that pair the names of the hosts in the zone, aka domain, with their respective IP addresses. It may also contain CNAME records that are aliases for the real hostnames in the A records, and MX records for mail servers.

Create a basic forward zone file, /var/named/example.com.zone and add the following lines to it. Your zone file should look like the sample zone file in Listing 3, below, when you are finished.

; Authoritative data for example.com zone 
; 
$TTL 1D 
@   IN SOA  epc.example.com   root.epc.example.com. ( 
                                       2017031301      ; serial 
                                       1D              ; refresh 
                                       1H              ; retry 
                                       1W              ; expire 
                                       3H )            ; minimum 

$ORIGIN         example.com. 
example.com.            IN      NS      epc.example.com. 
epc                     IN      A       127.0.0.1 
server                  IN      A       192.168.25.1 
www                     IN      CNAME   server 
mail                    IN      CNAME   server 
test1                   IN      A       192.168.25.21 
t1                      IN      CNAME   test1 
test2                   IN      A       192.168.25.22 
test3                   IN      A       192.168.25.23 
test4                   IN      A       192.168.25.24 

; Mail server MX record 
example.com.            IN      MX      10      mail.example.com.
Listing 3: The forward zone file for the example.com domain contains the hostnames and their IP addresses for this domain.


The first non-comment line in Listing 3 is the Time To Live specifier – in this case one day for all records that are not otherwise specified. D stands for Day. The specifiers in the Start Of Authority (SOA) line are just as obvious. Details of the parameters in the SOA record are described in some detail here.

The NS record must have the fully qualified domain name (FQDN) of the host on which you are performing this lab project. There must also be an A record in the file with a valid IP address for for the host. In this case you should use the localhost IP address of 127.0.0.1.

The entries shown above will give you a few hostnames to experiment with.

Be sure to use today’s date and append a counter starting at 01 for the serial number. The serial number above is the first change of March 4, 2017. The serial number is incremented whenever the zone file is changed. If there were secondary name servers that used this one for a primary, they would not be updated unless the serial number is incremented.

Add the Forward Zone Files to named.conf

Before your DNS server will work, however, you need to create an entry in /etc/named.conf that will point to your new zone file. Add the following lines below the entry for the top level hints zone but before the “include” lines.

zone "example.com" IN {
    type master;
    file "example.com.zone";
};

Listing 4: Add these lines to the named.conf file to add the example.com zone file to the resolver configuration.

Now restart named to make these changes take effect. Test your name server by using the dig and nsloookup commands to obtain the IP Addresses for the hosts you have configured in the forward zone file. Note that the host does not have to exist on the network for the dig and nslookup commands to return an IP Address.

dig test1.example.com
dig t1.example.com
dig mx example.com
dig mail.example.com
nslookup test3.example.com
dig www.amazon.com

Be aware that it is necessary to use the FQDN for the both commands but not for the nslookup command so long as the domain and search entries of “example.com” are provided in the /etc/resolv.conf file. In this case they probably are not, so just use the FQDNs for all testing in this project.

Using the root name servers

You will notice that the root name servers are given as the authoritative servers for the amazon.com lookup. But remember we are using the Google public name servers as forwarders. Now comment out the forwarders line in named.conf and restart named. Run the above commands again to compare the results that are returned. The results should look similar to the ones below in Listing 5.

# dig www.amazon.com

; <<>> DiG 9.10.4-P6-RedHat-9.10.4-4.P6.fc25 <<>> www.amazon.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 65004
;; flags: qr rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 4, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www.amazon.com. IN A

;; ANSWER SECTION:
www.amazon.com. 1800 IN CNAME www.cdn.amazon.com.
www.cdn.amazon.com. 300 IN CNAME d3ag4hukkh62yn.cloudfront.net.
d3ag4hukkh62yn.cloudfront.net. 60 IN A 52.85.147.120
d3ag4hukkh62yn.cloudfront.net. 60 IN A 52.85.147.50
d3ag4hukkh62yn.cloudfront.net. 60 IN A 52.85.147.92
d3ag4hukkh62yn.cloudfront.net. 60 IN A 52.85.147.109

;; AUTHORITY SECTION:
d3ag4hukkh62yn.cloudfront.net. 1831 IN NS ns-1144.awsdns-15.org.
d3ag4hukkh62yn.cloudfront.net. 1831 IN NS ns-130.awsdns-16.com.
d3ag4hukkh62yn.cloudfront.net. 1831 IN NS ns-2021.awsdns-60.co.uk.
d3ag4hukkh62yn.cloudfront.net. 1831 IN NS ns-824.awsdns-39.net.

;; Query time: 3857 msec
;; SERVER: 192.168.0.203#53(192.168.0.203)
;; WHEN: Mon Mar 13 09:18:30 EDT 2017
;; MSG SIZE rcvd: 306

Listing 5: The results of a lookup on www.amazon.com have some interesting information including times to live for the various record types.

When I did this, the first call to resolve the external address for Amazon took 3857ms while the data was located and returned. Subsequent results to perform the same query was 1ms which shows the advantage of caching resolver results locally. Notice the numbers 1800, 300, and 60 in the answer section lines and 1831 in authority section lines. These are TTL – Times To Live in seconds. If you perform the lookup multiple times, these numbers will change, showing the amount of time that the records have remaining to live in local cache.

Creating the Reverse Zone File

A reverse zone for your domain will provide the ability to do reverse lookups. many organizations do not do these internally, but reverse lookups can be helpful in doing problem determination. Many spam fighting configurations such as SpamAssassin look for reverse lookups to verify valid email servers.

Create the reverse zone file, /var/named/example.com.rev and add the following contents. Be sure to use an appropriate serial number.

; Authoritative data for example.com  reverse zone
;
$TTL 1D
@   IN SOA  test1.example.com   root.test1.example.com. (
                                        2017031501      ; serial
                                        1D              ; refresh
                                        1H              ; retry
                                        1W              ; expire
                                        3H )            ; minimum

@       IN      NS      epc.example.com.
example.com.    IN      NS      epc.example.com.
1               IN      PTR     mail.example.com.
1               IN      PTR     server.example.com.
21              IN      PTR     test1.example.com.
22              IN      PTR     test2.example.com.
23              IN      PTR     test3.example.com.
24              IN      PTR     test4.example.com.
Listing 6: Create this reverse zone file, example.com.rev, for your name server.

You could also name your reverse zone file /var/named/25.168.192.in-addr.arpa which follows older conventions. You can actually name it anything you want because you will point to it explicitly in the named.conf file, but using one of the two conventions will make it easier for others to follow your work.

Add the Reverse Zone to named.conf

zone    "25.168.192.in-addr.arpa" IN { 
       type master; 
       file "example.com.rev"; 
};

Listing 7: Adding this stanza to the named.conf file enables reverse lookups.


Add the stanza in Listing 7 to the /etc/named.conf file to point to the new reverse zone. Now reload named and test your reverse zone using the commands in Listing 8. Your results should look similar to those below.

# systemctl reload named
# dig -x 192.168.25.23 

; <<>> DiG 9.10.4-P6-RedHat-9.10.4-4.P6.fc25 <<>> -x 192.168.25.23 
;; global options: +cmd 
;; Got answer: 
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48607 
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1 

;; OPT PSEUDOSECTION: 
; EDNS: version: 0, flags:; udp: 4096 
;; QUESTION SECTION: 
;23.25.168.192.in-addr.arpa.    IN      PTR 

;; ANSWER SECTION: 
23.25.168.192.in-addr.arpa. 86400 IN    PTR     test3.example.com. 

;; AUTHORITY SECTION: 
25.168.192.in-addr.arpa. 86400  IN      NS      epc.example.com. 

;; Query time: 21 msec 
;; SERVER: 192.168.0.203#53(192.168.0.203) 
;; WHEN: Wed Mar 15 16:18:59 EDT 2017 
;; MSG SIZE  rcvd: 112
Listing 8: After restarting named you should see results similar to these when you do a reverse lookup on an IP address in the reverse zone.

Be sure to test some of the other reverse entries in your network. Be sure to try the following as well as other reverse lookups you want to experiment with. The -x option means reverse lookup.

dig -x 192.168.25.23
dig -x 192.168.25.1

Note that not all hosts that have entries in the forward zone need to have entries in the reverse zone, but it does make for more consistent results if they do.

At this point you have a working name server using BIND. However external hosts cannot yet use this name server because the firewall should not yet be configured to allow DNS requests.

Configuring IPTables for DNS

You can do this step if you want other hosts on your local network to use your host as their name server.

The firewall on your test host probably blocks access to your host for name services. IPTables must be configured to allow UDP packets inbound on your name server in order for other hosts to use it for name resolution. Use the following commands to add the required entries and save them.

Add a rule to your IPTables or firewalld firewall that allows incoming packets on port 53 (domain) for UDP and save the new ruleset. Be sure to insert the new rule after the “ -A INPUT -m state –state RELATED,ESTABLISHED -j ACCEPT” line, so you will have to count the number of INPUT lines in the filter table in order to do that. The number 7 in the following command means that this rule will be inserted in position number 7 in the existing INPUT rules.

 iptables -t filter -I INPUT 7 -p udp -m conntrack --ctstate NEW -m udp --dport 53 -j ACCEPT

You can save your new firewall rules if you like, and you would if this were to be a permanent installation and not a lab project. Then test this from one of your other hosts using the command in Listing 9, below. The @epc argument tells the dig command to use the specified name server with the hostname epc. You should substitute either the IP address of the DNS server you have just created, or a resolvable hostname on your network that points to your new name server. Of course you could always add that hostname with its IP address to the /etc/hosts file of the host you are using for the remote test.

# dig @epc test1.example.com

; <<>> DiG 9.10.4-P6-RedHat-9.10.4-4.P6.fc25 <<>> @epc test1.example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 27957
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;test1.example.com. IN A

;; ANSWER SECTION:
test1.example.com. 86400 IN A 192.168.25.21

;; AUTHORITY SECTION:
example.com. 86400 IN NS epc.both.org.

;; Query time: 0 msec
;; SERVER: 192.168.0.203#53(192.168.0.203)
;; WHEN: Mon Mar 13 08:45:34 EDT 2017
;; MSG SIZE rcvd: 92

Listing 9: Testing the name resolver you have created from a different host on the same network.


Cleanup

For cleanup you should perform the following tasks using the tools appropriate for your distribution. You may just wish to keep this name server for your network if you do not already have one.

  1. Restore the original /etc/hosts file.
  2. Stop named on the resolver host used for this lab project.
  3. Disable the named service.
  4. Delete the zone files.
  5. Restore the original named.conf file.
  6. Restore the original resolv.conf file.

Conclusion

The functioning of name services seemed very obscure to me until I actually created a name server for my network using BIND. It is quite straightforward and can significantly improve DNS lookup performance for a network. Having your own name server can also prevent many of the relatively minor yet annoying name service interruptions cause by poorly maintained ISP name servers.

Note that, even though my little EeePC is running with 100% CPU usage for Seti@Home, it responds extremely quickly to resolver requests. You should be able to try this project on any Linux host you have available with miniscule impact. So I would hope that many of you will try to set up your own name server and experiment with it. The specifics of your name server installation will depend upon the details of your host and network.

Resources

Internet Assigned Numbers Authority (IANA)
Start of Authority (SOA) record
List of DNS Record Types
Common DNS records and their uses