Standing up a DNS lab environment using Bind9
In this blog post we are going to be setting up an internal zone (tyrel.local) on a home network, we will be using a laptop running Ubuntu 18.0.4 (Bionic), this will be our Master, and a Raspberry pi running Raspbian OS (Buster), this will be our Slave.
Sections:
sudo apt-get update && sudo apt-get --yes install bind9 bind9-doc dnsutils
Once installation is complete bind9 is started automatically, named
is the daemon name.
The main configuration file for bind is /etc/bind/named.conf
. In this file we find references for other configuration files:
include "/etc/bind/named.conf.options"; include "/etc/bind/named.conf.local"; include "/etc/bind/named.conf.default-zones";
The only thing we are going to be adding to the main config file is logging, which we will do a little bit later. So lets get started with options.
The options configuration file /etc/bind/named.conf.options
is where the global options are defined. By default without any other configuration we have a recursive caching server.
Here's an overview of whats enabled/configured by default:
We really don't need to do anything in the options file for a basic setup.
The first configuration piece we are going to do is in /etc/bind/named.conf.local
, this is where we define our zones and their types.
Edit the file /etc/bind/named.conf.local
and Add the following:
sudo nano /etc/bind/named.conf.local
MASTER
zone "tyrel.local" { type master; file "/etc/bind/db.tyrel.local"; allow-transfer { 192.168.1.2; }; }; zone "1.168.192.in-addr.arpa" { type master; allow-transfer { 192.168.1.2; }; file "/etc/bind/db.192"; };
SLAVE
zone "tyrel.local" { type slave; masterfile-format text; file "/etc/bind/db.tyrel.local"; masters { 192.168.1.254; }; }; zone "1.168.192.in-addr.arpa" { type slave; masterfile-format text; file "/etc/bind/db.192"; masters { 192.168.1.254; }; };
Create the zone file /etc/bind/db.tyrel.local
At a Minimum We need to define:
sudo nano /etc/bind/db.tyrel.local
MASTER
$TTL 1h ; default TTL tyrel.local. IN SOA ns1.tyrel.local. contact.tyrel.local. ( 1 1d 2h 4w 1h ) ; SOA Record tyrel.local. IN NS ns1.tyrel.local. ; NS records tyrel.local. IN NS ns2.tyrel.local. ; NS records ns1.tyrel.local. IN A 192.168.1.254 ; A records ns2.tyrel.local. IN A 192.168.1.2 ; A records
Create the zone file /etc/bind/db.192
Note In this file we are using @ instead of defining the Origin as we did in the Forward Lookup Zone, which would have been 1.168.192.in-addr.arpa
sudo nano /etc/bind/db.192
MASTER
$TTL 1h ; default TTL @ IN SOA ns1.tyrel.local. contact.tyrel.local. ( 1 1d 2h 4w 1h ) ; SOA Record IN NS ns1.tyrel.local. ; NS Record IN NS ns2.tyrel.local. ; NS Record 254 IN PTR ns1.tyrel.local. ; 192.168.1.254 PTR 2 IN PTR ns2.tyrel.local. ; 192.168.1.2 PTR
Once we have our Zone files configured we need to verify they are correct with the following:
named-checkconf -z
zone tyrel.local/IN: loaded serial 1 zone 1.168.192.in-addr.arpa/IN: loaded serial 1 zone localhost/IN: loaded serial 2 zone 127.in-addr.arpa/IN: loaded serial 1 zone 0.in-addr.arpa/IN: loaded serial 1 zone 255.in-addr.arpa/IN: loaded serial 1
named-checkzone tyrel.local /etc/bind/db.tyrel.local
zone tyrel.local/IN: loaded serial 1
OK
named-checkzone 1.168.192.in-addr.arpa /etc/bind/db.192
zone 1.168.192.in-addr.arpa/IN: loaded serial 1 OK
Once the verification checks out we need to reload the service for the changes to take effect.
sudo systemctl restart bind9
At this Point we should be able to query both the master and the slave for the NS and PTR records.
Using NSLOOKUP:
nslookup ns2 192.168.1.254
Server: ns1 Address: 192.168.1.254#53 Name: ns2.tyrel.local Address: 192.168.1.2
nslookup 192.168.1.2 192.168.1.254
2.1.168.192.in-addr.arpa name = ns2.tyrel.local.
Using DIG:
dig @192.168.1.254 ns2.tyrel.local A +short
192.168.1.2
dig @192.168.1.254 -x 192.168.1.2 PTR +short
ns2.tyrel.local.
This is optional but recommended as it makes troubleshooting much easier.
By default logging is done to /var/syslog
This is a useful adaptation that will log everything to /var/log/named/
directory and split the logs out to there respective category.
The files will rotate once they reach 5MB and 3 versions will be kept in rotation.
sudo mkdir /var/log/named
sudo chown bind:bind /var/log/named
sudo nano /etc/bind/named.conf
Append the following:
logging { channel default_file { file "/var/log/named/default.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel general_file { file "/var/log/named/general.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel database_file { file "/var/log/named/database.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel security_file { file "/var/log/named/security.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel config_file { file "/var/log/named/config.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel resolver_file { file "/var/log/named/resolver.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel xfer-in_file { file "/var/log/named/xfer-in.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel xfer-out_file { file "/var/log/named/xfer-out.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel notify_file { file "/var/log/named/notify.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel client_file { file "/var/log/named/client.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel unmatched_file { file "/var/log/named/unmatched.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel queries_file { file "/var/log/named/queries.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel network_file { file "/var/log/named/network.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel update_file { file "/var/log/named/update.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel dispatch_file { file "/var/log/named/dispatch.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel dnssec_file { file "/var/log/named/dnssec.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel lame-servers_file { file "/var/log/named/lame-servers.log" versions 3 size 5m; severity dynamic; print-time yes; }; category default { default_file; }; category general { general_file; }; category database { database_file; }; category security { security_file; }; category config { config_file; }; category resolver { resolver_file; }; category xfer-in { xfer-in_file; }; category xfer-out { xfer-out_file; }; category notify { notify_file; }; category client { client_file; }; category unmatched { unmatched_file; }; category queries { queries_file; }; category network { network_file; }; category update { update_file; }; category dispatch { dispatch_file; }; category dnssec { dnssec_file; }; category lame-servers { lame-servers_file; }; };
Again Restart the service to have this take effect:
sudo systemctl restart bind9
Most of the zone transfer config was done when we defined our zones, we still need to modify the owner of the /etc/bind
directory and /etc/bind/db.*
files. This will allow the named daemon running as user "bind" to modify these files.
SLAVE ONLY
sudo chown -R bind:bind /etc/bind
In order to verify zone transfers are function we need to kick off a zone transfer. We can do this a few ways:
Quick SLAVE verification
dig @192.168.1.254 tyrel.local. axfr
; <<>> DiG 9.11.5-P4-5.1-Raspbian <<>> @192.168.1.254 tyrel.local. axfr ; (1 server found) ;; global options: +cmd tyrel.local. 3600 IN SOA ns1.tyrel.local. contact.tyrel.local. 1 86400 7200 2419200 3600 tyrel.local. 3600 IN NS ns1.tyrel.local. tyrel.local. 3600 IN NS ns2.tyrel.local. ns1.tyrel.local. 3600 IN A 192.168.1.254 ns2.tyrel.local. 3600 IN A 192.168.1.2 tyrel.local. 3600 IN SOA ns1.tyrel.local. contact.tyrel.local. 1 86400 7200 2419200 3600 ;; Query time: 2 msec ;; SERVER: 192.168.1.254#53(192.168.1.254) ;; WHEN: Sun Apr 26 11:16:06 EDT 2020 ;; XFR size: 6 records (messages 1, bytes 216)
MASTER
sudo nano /etc/bind/db.tyrel.local
SLAVE
cat /var/log/named/xfer-in.log
transfer of 'tyrel.local/IN' from 192.168.1.254#53: connected using 192.168.1.2#59733 transfer of 'tyrel.local/IN' from 192.168.1.254#53: Transfer status: success transfer of 'tyrel.local/IN' from 192.168.1.254#53: Transfer completed: 1 messages, 6 records, 216 bytes, 0.040 secs (14250 bytes/sec) transfer of '1.168.192.in-addr.arpa/IN' from 192.168.1.254#53: connected using 192.168.1.2#53103 transfer of '1.168.192.in-addr.arpa/IN' from 192.168.1.254#53: Transfer status: success transfer of '1.168.192.in-addr.arpa/IN' from 192.168.1.254#53: Transfer completed: 1 messages, 7 records, 238 bytes, 0.004 secs (59500 bytes/sec)
cat /etc/bind/db.tyrel.local
$ORIGIN . $TTL 3600 ; 1 hour tyrel.local IN SOA ns1.tyrel.local. contact.tyrel.local. ( 1 ; serial 86400 ; refresh (1 day) 7200 ; retry (2 hours) 2419200 ; expire (4 weeks) 3600 ; minimum (1 hour) ) NS ns1.tyrel.local. NS ns2.tyrel.local. $ORIGIN tyrel.local. ns1 A 192.168.1.254 ns2 A 192.168.1.2
Note The transferred zone file format is much different than the original file
Common management actions
/etc/bind/db.tyrel
MASTER
Add a variety of records using different methods as an example
Be sure to increment the Serial Number in the SOA Record
nano /etc/bind/db.tyrel.local
tyrel.local. IN SOA ns1.tyrel.local. contact.tyrel.local. ( **8** 1d 2h 4w 1h ) ; SOA Record mail IN A 192.168.2.254 ; A to go with MX @ IN MX 10 mail ; MX Record @ TXT "Administrator: Tyrel" ; TXT Record openvpn IN A 192.168.1.2 ; A to go with SRV _vpn._udp SRV 0 0 1194 openvpn ; SRV Record blog A 192.168.1.254 ; A Record info IN CNAME blog ; CNAME Record jupyter IN A 192.168.1.15 ; A Record notebook A 192.168.1.254 pi A 192.168.1.15 pi1b A 192.168.1.2 pi2b A 192.168.1.15 pi3b A 192.168.1.7
named-checkconf -z
named-checkzone tyrel.local /etc/bind/db.tyrel.local
sudo systemctl restart bind9
dig @ns1 tyrel.local TXT +short
"Administrator: Tyrel"
dig @ns1 tyrel.local MX +short
10 mail.tyrel.local.
dig @ns1 _vpn._udp.tyrel.local SRV +short
0 0 1194 openvpn.tyrel.local.
cat /etc/bind/db.tyrel.local
$ORIGIN . $TTL 3600 ; 1 hour tyrel.local IN SOA ns1.tyrel.local. contact.tyrel.local. ( **8 ; serial** 86400 ; refresh (1 day) 7200 ; retry (2 hours) 2419200 ; expire (4 weeks) 3600 ; minimum (1 hour) ) NS ns1.tyrel.local. NS ns2.tyrel.local. MX 10 mail.tyrel.local. TXT "Administrator: Tyrel" $ORIGIN tyrel.local. _vpn._udp SRV 0 0 1194 openvpn blog A 192.168.1.254 info CNAME blog jupyter A 192.168.1.15 mail A 192.168.2.254 notebook A 192.168.1.254 ns1 A 192.168.1.254 ns2 A 192.168.1.2 openvpn A 192.168.1.2 pi A 192.168.1.15 pi1b A 192.168.1.2 pi2b A 192.168.1.15 pi3b A 192.168.1.7
Not really necessary to actively manage, however if you want to examine the recursive cache. Here's how.
View cache:
sudo rndc dumpdb -cache && sudo cat /var/cache/bind/named_dump.db |grep XYZ.com
Clear cache:
sudo rndc flush && rndc reload
https://bind9.readthedocs.io/en/latest/