How To Configure BIND as a Private Network DNS Server on linux network namespaces

An important part of managing server configuration and infrastructure includes maintaining an easy way to look up network interfaces and IP addresses by name, by setting up a proper Domain Name System (DNS). Using fully qualified domain names (FQDNs), instead of IP addresses, to specify network addresses eases the configuration of services and applications, and increases the maintainability of configuration files. Setting up your own DNS for your private network is a great way to improve the management of your servers. Instead of doing this on a actual physical network we will emulate a private network using linux network namespaces and setup a DNS server on a namespace.

In this tutorial, we will go over how to set up an internal DNS server, using the BIND name server software (BIND9) on linux network namespaces, that can be used by servers/clients to resolve private hostnames and private IP addresses while playing with DNS.

Prerequisites

  • A fresh Ubuntu 20.04 machine with iproute2 insatlled.

We will setup and configure a DNS server and a client.

Configuration

HostRolePrivate FQDNPrivate IP Address
ns1DNS name serverns1.test.dns10.2.1.7
host1Clienthost1.test.dns10.2.1.8

Installing and configuring Bind

sudo apt-get update
sudo apt-get install bind9 bind9utils bind9-doc

Since we want to install and configure bind on a namespace, we have to make the necessary configurations in /etc/netns/ns1 before creating the namespaces as netns uses configuration from /etc/netns/<namespace-name> if present.

For applications that are aware of network namespaces, the convention is to look for global network configuration files first in /etc/netns/NAME/ then in /etc/. For example, if you want a different version of /etc/resolv.conf for a network namespace used to isolate your vpn you would name it /etc/netns/myvpn/resolv.conf.

-- ip-netns man page

So we will create netns directory and copy bind.

sudo mkdir -p /etc/netns/ns1
sudo cp -r /etc/bind /etc/netns/ns1

Note: The configuration files edited below are from /etc/netns/ns1 and not /etc/bind

Configuring the Local File

Aside from a few comments, the file should be empty. Here, we will specify our forward and reverse zones. DNS zones designate a specific scope for managing and defining DNS records. Edit /etc/netns/ns1/bind/named.conf.local

sudo vim named.conf.local

Add the forward zone with the following lines, substituting the zone name with your own.

zone "test.dns" {
    type master;
    file "/etc/bind/zones/db.test.dns"; # zone file path
};

Assuming that our private subnet is 10.2.0.0/16, add the reverse zone by with the following lines (note that our reverse zone name starts with “2.10” which is the octet reversal of “10.2”):

zone "2.10.in-addr.arpa" {
    type master;
    file "/etc/bind/zones/db.2.10";  # 10.2.0.0/16 subnet
};

Now that our zones are specified in BIND, we need to create the corresponding forward and reverse zone files.

Creating the Forward Zone File

The forward zone file is where we define DNS records for forward DNS lookups. That is, when the DNS receives a name query, “host1.test.dns” for example, it will look in the forward zone file to resolve host1’s corresponding private IP address.

Let’s create the directory where our zone files will reside. According to our named.conf.local configuration, that location should be /etc/netns/ns1/bind/zones:

sudo mkdir /etc/netns/ns1/bind/zones

We will base our forward zone file on the sample db.local zone file. Copy it to the proper location with the following commands:

sudo cp /etc/netns/ns1/bind/db.local /etc/netns/ns1/bind/zones/db.test.dns

Now edit the forward zone file

sudo nano /etc/netns/ns1/bind/zones/db.test.dns

First, you will want to edit the SOA record. Replace the first “localhost” with ns1’s FQDN, then replace “root.localhost” with “admin.test.dns.”. Every time you edit a zone file, you need to increment the serial value before you restart the named process. We will increment it to “3”. Now add your name server records (replace the names with your own) and then add the A records for your hosts that belong in this zone. This includes any server whose name we want to end with “.test.dns.” (substitute the names and private IP addresses). Our final example forward zone file looks like the following:

;
; BIND data file for local loopback interface
;
$TTL    604800
@       IN      SOA     ns1.test.dns. admin.test.dns. (
                              3         ; Serial
                         604800         ; Refresh
                          86400         ; Retry
                        2419200         ; Expire
                         604800 )       ; Negative Cache TTL
;
; name servers - NS records
     IN      NS      ns1.test.dns.

; name servers - A records
ns1.test.dns.          IN      A       10.2.1.7

; 10.2.0.0/16 - A records
host1.test.dns.        IN      A      10.2.1.8

Creating the Reverse Zone File(s)

Reverse zone files are where we define DNS PTR records for reverse DNS lookups. That is, when the DNS receives a query by IP address, “10.2.1.8” for example, it will look in the reverse zone file(s) to resolve the corresponding FQDN, “host1.test.dns” in this case. On ns1, for each reverse zone specified in the named.conf.local file, create a reverse zone file. We will base our reverse zone file(s) on the sample db.127 zone file. Copy it to the proper location with the following commands (substituting the destination filename so it matches your reverse zone definition):

sudo cp /etc/netns/ns1/bind/db.127 /etc/netns/ns1/bind/zones/db.2.10

Edit the reverse zone file that corresponds to the reverse zone(s) defined in named.conf.local:

sudo vim /etc/netns/ns1/bind/zones/db.2.10

In the same manner as the forward zone file, you will want to edit the SOA record and increment the serial value. At the end of the file add your name server records (replace the names with your own). Note that the second column specifies that these are “NS” records: Then add PTR records for all of your servers whose IP addresses are on the subnet of the zone file that you are editing. Note that the first column consists of the last two octets of your servers’ private IP addresses in reversed order. Save and close the reverse zone file (repeat this section if you need to add more reverse zone files). Finally db.2.10(reverse zone) looks like the following

;
; BIND reverse data file for local loopback interface
;
$TTL    604800
@    IN    SOA    ns1.test.dns. admin.test.dns. (
                  2        ; Serial
             604800        ; Refresh
              86400        ; Retry
            2419200        ; Expire
             604800 )    ; Negative Cache TTL
;
; name servers
      IN      NS      ns1.test.dns.

; PTR Records
7.1   IN      PTR     ns1.test.dns.    ; 10.2.1.7
8.1   IN      PTR     host1.test.dns.  ; 10.2.1.8

Checking the BIND Configuration Syntax

Run the following command to check the syntax of the named.conf* files:

sudo named-checkconf

If your named configuration files have no syntax errors, you will return to your shell prompt and see no error messages. If there are problems with your configuration files, review the error message and the above steps, then try named-checkconf again. The named-checkzone command can be used to check the correctness of your zone files. Its first argument specifies a zone name, and the second argument specifies the corresponding zone file, which are both defined in named.conf.local.

sudo named-checkzone ns1.test.dns db.test.dns

We have successfully setup the DNS server, we now make some configurations on host1 namespace to use ns1 as a DNS server to resolve the domain names.

Copy the resolv.conf file from the root directory to /etc/netns/host1 and edit it.

sudo mkdir -p /etc/netns/host1
sudo cp /etc/resolv.conf /etc/netns/host1/
sudo vim /etc/netns/host1/resolv.conf

Add this line on the top of the file and save it.

nameserver 10.2.1.7

Create a peer-peer topology using namespaces

Once we have bind installed and configured in /etc/netns/ns1/bind, we create a peer-peer topology to test.

Topology

Run the below script to setup the topology as shown above. To know more about namespaces and how to create topologies using namespaces refer this.

# Cleanup
sudo ip -all netns delete

# Setup topology
sudo ip netns add ns1
sudo ip netns add host1
sudo ip link add veth0 type veth peer name veth1
sudo ip link set veth0 netns ns1
sudo ip link set veth1 netns host1
sudo ip netns exec ns1 ip addr add 10.2.1.7/16 dev veth0
sudo ip netns exec host1 ip addr add 10.2.1.8/16 dev veth1
sudo ip netns exec ns1 ip link set dev veth0 up
sudo ip netns exec host1 ip link set dev veth1 up
sudo ip netns exec ns1 ip link set dev lo up
sudo ip netns exec host1 ip link set dev lo up
sudo ip netns exec host1 ip route add default via 10.2.1.7
echo 1 > /proc/sys/net/ipv4/ip_forward

Now we start the named(bind) service on ns1 namespace.

sudo ip netns exec ns1 named

To test the DNS server running on the ns1 namespace we should query from host1 we use dig to do this.

 sudo ip netns exec host1 dig ns1.test.dns
 sudo ip netns exec host1 dig host1.test.dns

These queries should respond with a answer containing their corresponding private IP addresses.

Example response.

root@ubuntu:/home/vmi# sudo ip netns exec host1 dig ns1.test.dns
<<>> DiG 9.16.1-Ubuntu <<>> >> ns1.test.dns 
;; global options: +cmd
;; Got answer: 
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 8213 
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORItY: 0, ADDITiONal: 1
;; OPT PSEUDOSECTION:
;; EDNS: version: 0, flags:; udp: 4096 
;; COOKIE: f2d24fe168242432010000006227b4f92b4d0e895a786627 (good) 
;; QUESTION SECtION: 
;ns1.test.dns.            IN    A
;; ANSWER SECTION: 
ns1.test.dns. 604800 IN A 10.2.1.7
;; Query time: 0 msec 
;;SERVER: 10.2.1.7#53(10.2.1.7)
WHEN: Tue Mar 08 11:56:41 PST 2022
;;MSG SIZE rcvd: 85

We can also do a reverse lookup from host1

 sudo ip netns exec host1 dig 10.2.1.7

This will respond with the domain names corresponding to the IP address.

Conclusion

That's it! You have successfully installed and configured BIND 9 on linux network namespaces. Similar network-level isolation and DNS server setup could have been set up using VMs. However, that seems a much more expensive solution for system resources and time investment to build up such an environment to play with DNS.

Did you find this article valuable?

Support Balajinaidu by becoming a sponsor. Any amount is appreciated!