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
Host | Role | Private FQDN | Private IP Address |
ns1 | DNS name server | ns1.test.dns | 10.2.1.7 |
host1 | Client | host1.test.dns | 10.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.
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.