I’m building my redundant DNS server setup. DNS is short for Domain Name System.

Very basically explained DNS translates domain names into IP addresses and vice versa.

You can find more information about DNS on wikipedia article:
http://en.wikipedia.org/wiki/Domain_Name_System

I’ll be installing my DNS server on a SUSE Linux Enterprise Server (SLES) hosted on a vmware virtual environment. The DNS software I’ll be using is BIND (Berkeley Internet Name Domain).
I’m choosing to use BIND because there is a lot of information out there about BIND and it is the de facto standard DNS server software if you are running a Unix-like OS.

These are the features I want:

  • Run a DNS to resolve internal and external domain names into IP addresses and vice versa.
    (the internal domain name will be biolizards.local, the ip range will be 172.30.0.0/16)
  • Make my DNS server Redundant against server outage

I will split this guide in 2 posts:

DNS step 1: Setting up a BIND master DNS server on SLES

DNS step 2: Setting up a BIND slave DNS server on SLES

Step 1: Setting up a BIND master DNS server on SLES

The virtual machine I’ll be installing BIND on has the following specifications:

  • 1 vCPU
  • 512 MB Ram
  • Harddisk – 10GB
  • Network to your operational lan (ip: 172.30.1.2)
  • OS SLES 11 (64-bit)

Connect to the console and login
We need to install the ‘bind’ and ‘bind-utils’ package.
Start the installation by entering the following command:

DNSMaster:~ # yast2 -i bind bind-utils

Once the installation is finished we can start the configuration.
We will need to make some changes to the following configuration files:

/etc/named.conf
This is the main configuration file that the BIND DNS uses. All global options are declared in this configuration file.

/etc/named.conf.include
This configuration file may need to be created. This file just holds zone declarations. The reason for this is so that the named.conf file does not get over populated.

Before we start configuring we need to test if the file /etc/named.conf.include exists

DNSMaster:~ # ls /etc/named.conf.include
ls: cannot access /etc/named.conf.include: No such file or directory
DNSMaster:~ #

apparently not :-0, let’s create it

DNSMaster:~ # touch /etc/named.conf.include

Everything is prepared now, let’s start configuring
We are configuring a authoritative nameserver for the domain biolizards.local.
Open the config file /etc/named.conf

DNSMaster:~ #
vi /etc/named.conf

TIP: Before making big changes to a file copy it, this way you have something to fall back on.

Change the content to the following:

options {
     # The directory statement defines the name server's working directory
     directory "/var/lib/named";
     # Write dump and statistics file to the log subdirectory.    
     # The pathenames are relative to the chroot jail.

     # Defines the absolute path where BIND dumps the database (cache)   
     # in response to a rndc dumpdb.
     dump-file "/var/log/named_dump.db";
     # File-name to which data will be written when the command rndc
     # stats is issued.
     statistics-file "/var/log/named.stats";
     # The forwarders record contains a list of servers to which queries
     # should be forwarded.  Enable this line and modify the IP address to
     # your provider's name server.  Up to three servers may be listed.

     # The listen-on-v6 record enables or disables listening on IPv6  
     # interfaces.  Allowed values are 'any' and 'none' or a list of addresses.
     listen-on-v6 { any; };
     # If notify is set to yes (default), notify messages are sent to other
     # name servers when the the zone data is changed.  Instead of setting
     # a global 'notify' statement in the 'options' section, a separate
     # 'notify' can be added to each zone definition.
     notify no;
     # version specifies the string that will be returned to a version.
     # bind query when using the chaos class only. We tend to use it in
     # all named.conf files to avoid giving out a version number such that
     # an attacker can exploit known version-specific weaknesses.
     version "Biolizards DNS server"; };

# The following zone definitions don't need any modification.  The first one
# is the definition of the root name servers.  The second one defines
# localhost while the third defines the reverse lookup for localhost.
zone "." in { type hint; file "root.hint"; }; 
zone "localhost" in { type master; file "localhost.zone"; };

zone "0.0.127.in-addr.arpa" in { type master; file "127.0.0.zone"; }; 
# Include the meta include file generated by createNamedConfInclude.  This
# includes all files as configured in NAMED_CONF_INCLUDE_FILES from
# /etc/sysconfig/named
include "/etc/named.conf.include";

I have added the comment in the file so you know what you are configuring

Now it’s time to configure our domain name (biolizards.local) and reverse IP range (172.30.0.0/16)
Open the file /etc/named.conf.include for editing

DNSMaster:~ # vi /etc/named.conf.include

Insert the following content:

zone "biolizards.local" in { 
 type master; 
 file "master/biolizards.local.zone"; 
}; 

zone "30.172.in-addr.arpa" in { 
 type master; 
 file "master/172.30.zone"; 
};

Note that for the reverse zone the last octal digits for the IP range are left off.

Now that we have added the zone definitions to the named.conf.include file, we will need to create the two zone files master/biolizards.local.zone and master/172.30.zone

Because the files don’t defer to much from the localhost.zone and the 127.0.0.zone we will copy them.

DNSMaster:~ # cp /var/lib/named/localhost.zone /var/lib/named/master/biolizards.local.zone

DNSMaster:~ # cp /var/lib/named/127.0.0.zone /var/lib/named/master/172.30.zone

Now we need to edit those files, let’s start with the biolizards.local.zone file:

DNSMaster:~ # vi /var/lib/named/master/biolizards.local.zone

$TTL 1W
@		IN SOA 		dnsmaster.biolizards.local. root.biolizards.local. (
				2011072700 ; serial (yyyymmddvv)
				2D ; refresh
				4H ; retry
				6W ; expiry
				1W ) ; minimum

biolizards.local.	IN NS 		dnsmaster.biolizards.local.
dnsmaster              	IN A 		172.30.1.2
ns1 			CNAME 		dnsmaster

$TTL 1W
TTL specifies the time to live for all records in the zone that do not have an explicit TTL.

@ IN SOA biolizards.local. root.biolizards.local. (
This section specifies the State Of Authority. The fourth field (biolizards.local) states where the zone file comes from and the fifth field (root.biolizards.local) specifies the administrators email address.

2011072700 ; serial (yyyymmddvv)
This entry specifies the serial number. The serial number is used for determining if the zone has changed on master servers (so slave servers do not always need to synchronize the entire zone). I’m using the following format to build my serial yyyy (year) mm (month) dd (day)
vv (version number)

2D ; refresh
Refresh sets how often the zone should be synchronized from master name server to slave name servers.

4H ; retry
Retry sets how often slave servers try to synchronize the zone from the master server if synchronization fails.

6W ; expiry
Expiration means the period after which the zone expires on slave servers and slave servers stop answering replies until it is synchronized.

1W ) ; minimum
Minimum sets the duration the slave servers should cache negative answers (name resolution failed).

biolizards.local. IN NS dnsmaster.biolizards.local.
This section specifies the nameserver resource record.

dnsmaster. IN A 172.30.1.2
This section specifies an A (address) record which will convert dnsmaster.biolizards.local into 172.30.1.2.

ns1 CNAME dnsmaster
CNAME: Alias for Domain Name: Record Key is a hostname relative to the current zone or a fully qualified hostname followed by a dot. Value is a hostname relative to the current zone or a fully qualified hostname followed by a dot. It must be represented by an A record.

The second file we needed to change was 172.30.zone

DNSMaster:~ # vi /var/lib/named/master/172.30.zone

$TTL 1W
@               IN SOA          dnsmaster.biolizards.local.   root.biolizards.local. (
                                2011072700      ; serial (yyyymmddvv)
                                2D              ; refresh
                                4H              ; retry
                                6W              ; expiry
                                1W )            ; minimum

30.172.in-addr.arpa.            IN NS           dnsmaster.biolizards.local.
2.1.30.172.in-addr.arpa.        IN PTR          dnsmaster.biolizards.local.

As you can see there are a lot of similarity’s with the previous file, the last line is a new one:

2.1 IN PTR biolizards.local.

This section specifies a pointer record witch will convert the ip 172.30.1.2 to biolizards.local

Because the bind-chrootenv package is automatically installed when we installed the bind package the named service will start with the user named. Because named doesn’t has rights on the folder /var/lib/named/ it will not be allowed to read the configuration files therefor we need to change the user and the group of the folder /var/lib/named/ and all underlying files and folders to user named and group named

DNSMaster:~ # chown named.named /var/lib/named/ -R

The configuration is ready we can create the BIND system startup links now and start it:

DNSMaster:~ # chkconfig –add named

named                     0:off  1:off  2:off  3:on   4:off  5:on   6:off

DNSMaster:~ # /etc/init.d/named start

or
DNSMaster:~ # service named start

We can check the /var/log/messages file to find out if the bind server is started successfully or check for errors to correct.

Here is the output of my /var/log/messages file after starting the named service:

Jul 28 17:53:05 dnsmaster named[20550]: starting BIND 9.5.0-P2 -t /var/lib/named -u named
Jul 28 17:53:05 dnsmaster named[20550]: found 1 CPU, using 1 worker thread
Jul 28 17:53:05 dnsmaster named[20550]: loading configuration from '/etc/named.conf'
Jul 28 17:53:05 dnsmaster named[20550]: listening on IPv6 interfaces, port 53
Jul 28 17:53:05 dnsmaster named[20550]: listening on IPv4 interface lo, 127.0.0.1#53
Jul 28 17:53:05 dnsmaster named[20550]: listening on IPv4 interface lo, 127.0.0.2#53
Jul 28 17:53:05 dnsmaster named[20550]: listening on IPv4 interface eth0, 172.30.1.2#53
Jul 28 17:53:05 dnsmaster named[20550]: default max-cache-size (33554432) applies
Jul 28 17:53:05 dnsmaster named[20550]: automatic empty zone: 0.IN-ADDR.ARPA
Jul 28 17:53:05 dnsmaster named[20550]: automatic empty zone: 127.IN-ADDR.ARPA
Jul 28 17:53:05 dnsmaster named[20550]: automatic empty zone: 254.169.IN-ADDR.ARPA
Jul 28 17:53:05 dnsmaster named[20550]: automatic empty zone: 2.0.192.IN-ADDR.ARPA
Jul 28 17:53:05 dnsmaster named[20550]: automatic empty zone: 255.255.255.255.IN-ADDR.ARPA
Jul 28 17:53:05 dnsmaster named[20550]: automatic empty zone: 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.0.IP6.ARPA
Jul 28 17:53:05 dnsmaster named[20550]: automatic empty 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
Jul 28 17:53:05 dnsmaster named[20550]: automatic empty zone: D.F.IP6.ARPA
Jul 28 17:53:05 dnsmaster named[20550]: automatic empty zone: 8.E.F.IP6.ARPA
Jul 28 17:53:05 dnsmaster named[20550]: automatic empty zone: 9.E.F.IP6.ARPA
Jul 28 17:53:05 dnsmaster named[20550]: automatic empty zone: A.E.F.IP6.ARPA
Jul 28 17:53:05 dnsmaster named[20550]: automatic empty zone: B.E.F.IP6.ARPA
Jul 28 17:53:05 dnsmaster named[20550]: default max-cache-size (33554432) applies: view _bind
Jul 28 17:53:05 dnsmaster named[20550]: command channel listening on 127.0.0.1#953
Jul 28 17:53:05 dnsmaster named[20550]: command channel listening on ::1#953
Jul 28 17:53:05 dnsmaster named[20550]: zone 0.0.127.in-addr.arpa/IN: loaded serial 42
Jul 28 17:53:05 dnsmaster named[20550]: zone 30.172.in-addr.arpa/IN: loaded serial 2011072700
Jul 28 17:53:05 dnsmaster named[20550]: zone biolizards.local/IN: loaded serial 2011072700
Jul 28 17:53:05 dnsmaster named[20550]: zone localhost/IN: loaded serial 42
Jul 28 17:53:05 dnsmaster named[20550]: running

Testing the server

DNSMaster:~ # dig @localhost ns1.biolizards.local

; <<>> DiG 9.5.0-P2 <<>> @localhost ns1.biolizards.local
; (2 servers found)
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 7978
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 1, ADDITIONAL: 0

;; QUESTION SECTION:
;ns1.biolizards.local.          IN      A

;; ANSWER SECTION:
ns1.biolizards.local.   604800  IN      CNAME   dnsmaster.biolizards.local.
dnsmaster.biolizards.local. 604800 IN   A       172.30.1.2

;; AUTHORITY SECTION:
biolizards.local.       604800  IN      NS      dnsmaster.biolizards.local.

;; Query time: 0 msec
;; SERVER: ::1#53(::1)
;; WHEN: Thu Jul 28 18:19:48 2011
;; MSG SIZE  rcvd: 92

DNSMaster:~ # dig @localhost -x 172.30.1.2

; <<>> DiG 9.5.0-P2 <<>> @localhost -x 172.30.1.2
; (2 servers found)
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48034
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 0

;; QUESTION SECTION:
;2.1.30.172.in-addr.arpa.       IN      PTR

;; ANSWER SECTION:
2.1.30.172.in-addr.arpa. 604800 IN      PTR     dnsmaster.biolizards.local.

;; AUTHORITY SECTION:
30.172.in-addr.arpa.    604800  IN      NS      dnsmaster.biolizards.local.

;; Query time: 0 msec
;; SERVER: ::1#53(::1)
;; WHEN: Thu Jul 28 18:20:55 2011
;; MSG SIZE  rcvd: 89

As you can see the names and IP’s we configured are getting resolved.
This is it for step 1 on to DNS step 2: Setting up a BIND slave DNS server on SLES