Setting Up a Forwarding DNS Server On Debian

About DNS

The Domain Name System (DNS) is a hierarchical distributed naming system for computers, services, or any resource connected to the Internet or a private network. It associates various information with domain names assigned to each of the participating entities. Most prominently, it translates more readily memorized domain names to the numerical IP addresses needed for the purpose of locating and identifying computer services and device with the underlying network protocols. By providing a worldwide, distributed directory service, the Domain Name System is an essential component of the functionality of the Internet.

Forwarding DNS Server

A forwarder is a Domain Name System (DNS) server on a network that forwards DNS queries for external DNS names to DNS servers outside that network. You can also forward queries according to specific domain names using conditional forwarders.

Setting Up Forwarder DNS Server

Linux Distro Debian 8.2 Jessie
Server IP 10.42.0.109

So, in this post we are going to create a forwarding DNS Server in our Debian server using BIND9, we are going to install it in our server by typing:

# apt-get install bind9 bind9utils
root@debian-server:~# apt-get install bind9 bind9utils
Reading package lists... Done
Building dependency tree
Reading state information... Done
Suggested packages:
  bind9-doc resolvconf
The following NEW packages will be installed:
  bind9 bind9utils
0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
Need to get 481 kB of archives.
After this operation, 1,458 kB of additional disk space will be used.
Get:1 http://security.debian.org/ jessie/updates/main bind9utils amd64 1:9.9.5.dfsg-9+deb8u5 [167 kB]
Get:2 http://security.debian.org/ jessie/updates/main bind9 amd64 1:9.9.5.dfsg-9+deb8u5 [314 kB]
Fetched 481 kB in 8s (58.8 kB/s)
Preconfiguring packages ...
Selecting previously unselected package bind9utils.
(Reading database ... 35694 files and directories currently installed.)
Preparing to unpack .../bind9utils_1%3a9.9.5.dfsg-9+deb8u5_amd64.deb ...
Unpacking bind9utils (1:9.9.5.dfsg-9+deb8u5) ...
Selecting previously unselected package bind9.
Preparing to unpack .../bind9_1%3a9.9.5.dfsg-9+deb8u5_amd64.deb ...
Unpacking bind9 (1:9.9.5.dfsg-9+deb8u5) ...
Processing triggers for man-db (2.7.0.2-5) ...
Processing triggers for systemd (215-17+deb8u2) ...
Processing triggers for ufw (0.33-2) ...
Setting up bind9utils (1:9.9.5.dfsg-9+deb8u5) ...
Setting up bind9 (1:9.9.5.dfsg-9+deb8u5) ...
Adding group `bind' (GID 119) ...
Done.
Adding system user `bind' (UID 111) ...
Adding new user `bind' (UID 111) with group `bind' ...
Not creating home directory `/var/cache/bind.
wrote key file "/etc/bind/rndc.key"
#
Processing triggers for systemd (215-17+deb8u2) ...
Processing triggers for ufw (0.33-2) ...
root@debian-server:~#

Now installation is done, we are going to edit the configuration files which is the /etc/bind/named.conf.options which by default looks like this

options {
        directory "/var/cache/bind";

        // If there is a firewall between you and nameservers you want
        // to talk to, you may need to fix the firewall to allow multiple
        // ports to talk.  See http://www.kb.cert.org/vuls/id/800113

        // If your ISP provided one or more IP addresses for stable
        // nameservers, you probably want to use them as forwarders.
        // Uncomment the following block, and insert the addresses replacing
        // the all-0's placeholder.

        // forwarders {
        //      0.0.0.0;
        // };

        //========================================================================
        // If BIND logs error messages about the root key being expired,
        // you will need to update your keys.  See https://www.isc.org/bind-keys
        //========================================================================
        dnssec-validation auto;

        auth-nxdomain no;    # conform to RFC1035
        listen-on-v6 { any; };
};

Then we start our modification, in a situation where we want to only accept DNS queries from clients on our network and some specific IPs, we would prepend this line to the file

acl allowed_clients {
  localhost;
  10.42.0.0/24;
};

We have created a list of IPs to accept DNS queries from, now we are going into the options block editing the forwarders to forward DNS queries the server could not resolve locally to an external DNS server and we are using Google DNS. Uncomment this line

// forwarders {
//      0.0.0.0;
// };

To

forwarders {
                8.8.8.8;
                8.8.4.4;
        };

Since we already specified with ACL, clients it should accept queries from, we now use it here in the options block. Adding these lines:

forwarders {
                8.8.8.8;
                8.8.4.4;
        };
        recursion yes;
        allow-query { allowed_clients; };

Any request from a client which is not present in the allowed_clients ACL would be refused. Of course this can also be done with IPTABLES too. Our server is a forwarding DNS Server, why not make it clear to the server that it’s job is to forward requests that it can’t resolve to the outside servers. Now we add this line:

forwarders {
                8.8.8.8;
                8.8.4.4;
        };
        recursion yes;
        allow-query { allowed_clients; };
        forward only;

Save the file, at the end named.conf.options should look like this:

acl allowed_clients {
        localhost;
        10.42.0.0/24;
};

options {
        directory "/var/cache/bind";

        // If there is a firewall between you and nameservers you want
        // to talk to, you may need to fix the firewall to allow multiple
        // ports to talk.  See http://www.kb.cert.org/vuls/id/800113

        // If your ISP provided one or more IP addresses for stable
        // nameservers, you probably want to use them as forwarders.
        // Uncomment the following block, and insert the addresses replacing
        // the all-0's placeholder.

        forwarders {
                8.8.8.8;
                8.8.4.4;
        };
        recursion yes;
        allow-query { allowed_clients; };
        forward only;

        //========================================================================
        // If BIND logs error messages about the root key being expired,
        // you will need to update your keys.  See https://www.isc.org/bind-keys
        //========================================================================
        dnssec-validation auto;

        auth-nxdomain no;    # conform to RFC1035
        listen-on-v6 { any; };
};

Checking BIND Configuration

We are done with configuration, now to set our DNS Server working. We are going to check if we are having error in our named.conf.options, we type

# named-checkconf

If it returns no result, we are good to go. Restart bind now and make sure its working

# systemctl restart bind9
# systemctl status bind9
root@debian-server:/etc/bind# systemctl status  bind9
● bind9.service - BIND Domain Name Server
   Loaded: loaded (/lib/systemd/system/bind9.service; enabled)
  Drop-In: /run/systemd/generator/bind9.service.d
           └─50-insserv.conf-$named.conf
   Active: active (running) since Fri 2016-01-22 08:34:18 WAT; 5min ago
     Docs: man:named(8)
  Process: 2220 ExecStop=/usr/sbin/rndc stop (code=exited, status=0/SUCCESS)
 Main PID: 2225 (named)
   CGroup: /system.slice/bind9.service
           └─2225 /usr/sbin/named -f -u bind

Jan 22 08:34:18 debian-server named[2225]: command channel listening on ::1#953
Jan 22 08:34:18 debian-server named[2225]: managed-keys-zone: loaded serial 2
Jan 22 08:34:18 debian-server named[2225]: zone 0.in-addr.arpa/IN: loaded serial 1
Jan 22 08:34:18 debian-server named[2225]: zone 127.in-addr.arpa/IN: loaded serial 1
Jan 22 08:34:18 debian-server named[2225]: zone 255.in-addr.arpa/IN: loaded serial 1
Jan 22 08:34:18 debian-server named[2225]: zone localhost/IN: loaded serial 2
Jan 22 08:34:18 debian-server named[2225]: all zones loaded
Jan 22 08:34:18 debian-server named[2225]: running

Testing Out DNS Server on Client System

On client system we are going to test out our  DNS server if it’s actually resolving.

$ dig @10.42.0.109 unixmen.com
; <<>> DiG 9.9.5-9+deb8u5-Debian <<>> @10.42.0.109 unixmen.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 16997
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

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

;; ANSWER SECTION:
unixmen.com.            12032   IN      A       158.69.30.189

;; Query time: 1 msec
;; SERVER: 10.42.0.109#53(10.42.0.109)
;; WHEN: Fri Jan 22 08:48:45 WAT 2016
;; MSG SIZE  rcvd: 56

It resolved, means it’s working

 

Creating Zones

In our network, we might want to resolve a specific domain locally (i.e only if you are using the DNS Server).

Firstly, we will try to resolve the domain name local.server on a client and see the output

$ host local.server 10.42.0.109
Using domain server:
Name: 10.42.0.109
Address: 10.42.0.109#53
Aliases:

Host local.server not found: 3(NXDOMAIN)

As it couldn’t resolve the domain name, which is what we are about to solve.

We will be editing the /etc/bind/named.conf.local and we want to resolve local.server to a client on same network, add this line to the file

zone "local.server" {
        type master;
        file "/etc/bind/db.local.server";
};

It’s a master zone and the zone file is /etc/bind/db.local.server  which we are still about to create. We will copy the example file which is db.empty to db.local.server

# cp /etc/bind/db.empty /etc/bind/db.local.server

And then we edit /etc/bind/db.local.server which by default should look similar to this

; BIND reverse data file for empty rfc1918 zone
;
; DO NOT EDIT THIS FILE - it is used for multiple zones.
; Instead, copy it, edit named.conf, and use that copy.
;
$TTL    86400
@       IN      SOA     localhost. root.localhost. (
                              1         ; Serial
                         604800         ; Refresh
                          86400         ; Retry
                        2419200         ; Expire
                          86400 )       ; Negative Cache TTL
;
@       IN      NS      localhost.

In the first line, replace localhost. to local.server. making it look like this

@       IN      SOA     local.server. root.localhost. (

Then we start adding records, append these lines to the file

@       IN      A       10.42.0.1
sub     IN      CNAME   @

Save the file, in complete the file now looks like this

; BIND reverse data file for empty rfc1918 zone
;
; DO NOT EDIT THIS FILE - it is used for multiple zones.
; Instead, copy it, edit named.conf, and use that copy.
;
$TTL    86400
@       IN      SOA     local.server. root.localhost. (
                              1         ; Serial
                         604800         ; Refresh
                          86400         ; Retry
                        2419200         ; Expire
                          86400 )       ; Negative Cache TTL
;
@       IN      NS      localhost.
@       IN      A       10.42.0.1
sub     IN      CNAME   @

Restart bind9 once again.

Testing Out Zone

We have successfully added the zones, we should now retry looking up the domain name again on the client and see if it’s actually working

donjajo@jajo-pc:~$ host local.server 10.42.0.109
Using domain server:
Name: 10.42.0.109
Address: 10.42.0.109#53
Aliases:

local.server has address 10.42.0.1
donjajo@jajo-pc:~$ host sub.local.server 10.42.0.109
Using domain server:
Name: 10.42.0.109
Address: 10.42.0.109#53
Aliases:

sub.local.server is an alias for local.server.
local.server has address 10.42.0.1

And yes, it successfully resolved local.server and it’s CNAME sub.local.server

Now we’ve got our DNS Server working!