Server Howto: DNS

This guide assumes you already have a working installation of Red Hat Enterprise Linux, or one of its clones: CentOS Linux, Rocky Linux, et al, and you wish to install an IPv4 DNS server, perhaps to move the function from an in-house/in-office router that is not offering all of the features you require, and/or to bypass your ISPs restrictive DNS. This guide does not cover IPv6, because hardly anyone is bothering to use it, and it is too complex!

This particular example is taken from a working CentOS 7 server and modified with an example IP address range.

yum commands are given here. You can substitute for dnf if you are using RHEL 8 or one of its clones.


1: Install

The first thing to do is install the BIND DNS server software: yum install bind (as root). You will find bind-libs and bind-utils are present as they are needed for ordinary DNS operation; i.e. as a client.

The default installation of bind from Red Hat is configured to operate as a caching name-server, however, it requires a little modification to ensure it works in your own local network environment.


2: /etc/named.conf

This file is the main configuration for the named daemon. Errors in here, or in the files in the /etc/named directory will stop the daemon from starting. You will need to make some changes before you can start offering an in-house/office caching DNS function from this server.

Open up the /etc/named.conf file in your favourite text editor.

The line listen-on port 53 { 127.0.0.1; }; needs to be changed to: listen-on port 53 { any; }; if you want to serve DNS queries to other systems on the network. The default is to only listen on the localhost, not on any network adapters; e.g. eth0.

The line listen-on-v6 port 53 { ::1; }; should be commented out with // or simply deleted. This set-up is not offering IPv6 look-ups. IMPORTANT: you also need to set OPTIONS="-4" in the file /etc/sysconfig/named to stop BIND from complaining in /var/log/messages that there are no IPv6 adapters to bind to, and no IPv6 upstream to talk to.

The line allow-query { localhost; }; should be expanded to suit your local network; e.g. allow-query { localhost; 192.168.30.0/24; 192.168.31.0/24; 192.168.254.0/30; }; allows clients on the two /24 networks, and clients on the smaller /30 subnet to query this DNS server.

If you make a horrendous mistake, you can download the original conf file here.


3: systemctl

Once the above is complete, you can enable and start the BIND daemon to test you are resolving DNS queries.

If you are now ready to enable the DNS server, use the following command: systemctl enable named

And start the server with: systemctl start named

It is a good idea to have a second SSH terminal running to your server so you can watch the logging. BIND daemon (named) messages are written-out to /var/log/messages. The command: tail -f /var/log/messages will detail all of the BIND daemon activities, plus everything else, as the named daemon is controlled by systemd, and both "named" and "bash" statements end up logged.

If the daemon starts correctly, you should see something like this in /var/log/messages:

systemd: Starting Generate rndc key for BIND (DNS)...
systemd: Started Generate rndc key for BIND (DNS).
systemd: Starting Berkeley Internet Name Domain (DNS)...
bash: zone localhost.localdomain/IN: loaded serial 0
bash: zone localhost/IN: loaded serial 0
bash: 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/IN: loaded serial 0
bash: zone 1.0.0.127.in-addr.arpa/IN: loaded serial 0
bash: zone 0.in-addr.arpa/IN: loaded serial 0
named[37848]: starting BIND 9.11.4-P2-RedHat-9.11.4-26.P2.el7_9.5 (Extended Support Version)
named[37848]: running on Linux x86_64 3.10.0-1160.36.2.el7.x86_64 #1 SMP Wed Jul 21 11:57:15 UTC 2021
named[37848]: running as: named -u named -c /etc/named.conf -4
named[37848]: compiled by GCC 4.8.5 20150623 (Red Hat 4.8.5-44)
named[37848]: compiled with OpenSSL version: OpenSSL 1.0.2k 26 Jan 2017
named[37848]: linked to OpenSSL version: OpenSSL 1.0.2k-fips 26 Jan 2017
named[37848]: compiled with libxml2 version: 2.9.1
named[37848]: linked to libxml2 version: 20901
named[37848]: compiled with zlib version: 1.2.7
named[37848]: linked to zlib version: 1.2.7
named[37848]: threads support is enabled
named[37848]: ----------------------------------------------------
named[37848]: BIND 9 is maintained by Internet Systems Consortium,
named[37848]: Inc. (ISC), a non-profit 501(c)(3) public-benefit
named[37848]: corporation. Support and training for BIND 9 are
named[37848]: available at https://www.isc.org/support
named[37848]: ----------------------------------------------------
named[37848]: adjusted limit on open files from 4096 to 1048576
named[37848]: found 4 CPUs, using 4 worker threads
named[37848]: using 3 UDP listeners per interface
named[37848]: using up to 21000 sockets
named[37848]: loading configuration from '/etc/named.conf'
named[37848]: reading built-in trust anchors from file '/etc/named.iscdlv.key'
named[37848]: initializing GeoIP Country (IPv4) (type 1) DB
named[37848]: GEO-106FREE 20180327 Build 1 Copyright (c) 2018 MaxMind Inc All Rights Reserved
named[37848]: initializing GeoIP Country (IPv6) (type 12) DB
named[37848]: GEO-106FREE 20180605 Build 1 Copyright (c) 2018 MaxMind Inc All Rights Reserved
named[37848]: GeoIP City (IPv4) (type 2) DB not available
named[37848]: GeoIP City (IPv4) (type 6) DB not available
named[37848]: GeoIP City (IPv6) (type 30) DB not available
named[37848]: GeoIP City (IPv6) (type 31) DB not available
named[37848]: GeoIP Region (type 3) DB not available
named[37848]: GeoIP Region (type 7) DB not available
named[37848]: GeoIP ISP (type 4) DB not available
named[37848]: GeoIP Org (type 5) DB not available
named[37848]: GeoIP AS (type 9) DB not available
named[37848]: GeoIP Domain (type 11) DB not available
named[37848]: GeoIP NetSpeed (type 10) DB not available
named[37848]: using default UDP/IPv4 port range: [32768, 60999]
named[37848]: listening on IPv4 interface lo, 127.0.0.1#53
named[37848]: listening on IPv4 interface eth0, 192.168.30.253#53 named[37848]: generating session key for dynamic DNS
named[37848]: sizing zone task pool based on 9 zones
named[37848]: none:104: 'max-cache-size 90%' - setting to 14256MB (out of 15840MB)
named[37848]: set up managed keys zone for view _default, file '/var/named/dynamic/managed-keys.bind'
named[37848]: automatic empty zone: 10.IN-ADDR.ARPA
named[37848]: automatic empty zone: 16.172.IN-ADDR.ARPA
named[37848]: automatic empty zone: 17.172.IN-ADDR.ARPA
named[37848]: automatic empty zone: 18.172.IN-ADDR.ARPA
named[37848]: automatic empty zone: 19.172.IN-ADDR.ARPA
named[37848]: automatic empty zone: 20.172.IN-ADDR.ARPA
named[37848]: automatic empty zone: 21.172.IN-ADDR.ARPA
named[37848]: automatic empty zone: 22.172.IN-ADDR.ARPA
named[37848]: automatic empty zone: 23.172.IN-ADDR.ARPA
named[37848]: automatic empty zone: 24.172.IN-ADDR.ARPA
named[37848]: automatic empty zone: 25.172.IN-ADDR.ARPA
named[37848]: automatic empty zone: 26.172.IN-ADDR.ARPA
named[37848]: automatic empty zone: 27.172.IN-ADDR.ARPA
named[37848]: automatic empty zone: 28.172.IN-ADDR.ARPA
named[37848]: automatic empty zone: 29.172.IN-ADDR.ARPA
named[37848]: automatic empty zone: 30.172.IN-ADDR.ARPA
named[37848]: automatic empty zone: 31.172.IN-ADDR.ARPA
named[37848]: automatic empty zone: 168.192.IN-ADDR.ARPA
named[37848]: automatic empty zone: 64.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 65.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 66.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 67.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 68.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 69.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 70.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 71.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 72.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 73.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 74.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 75.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 76.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 77.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 78.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 79.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 80.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 81.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 82.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 83.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 84.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 85.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 86.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 87.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 88.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 89.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 90.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 91.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 92.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 93.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 94.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 95.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 96.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 97.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 98.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 99.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 100.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 101.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 102.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 103.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 104.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 105.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 106.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 107.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 108.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 109.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 110.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 111.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 112.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 113.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 114.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 115.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 116.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 117.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 118.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 119.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 120.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 121.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 122.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 123.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 124.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 125.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 126.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 127.100.IN-ADDR.ARPA
named[37848]: automatic empty zone: 127.IN-ADDR.ARPA
named[37848]: automatic empty zone: 254.169.IN-ADDR.ARPA
named[37848]: automatic empty zone: 2.0.192.IN-ADDR.ARPA
named[37848]: automatic empty zone: 100.51.198.IN-ADDR.ARPA
named[37848]: automatic empty zone: 113.0.203.IN-ADDR.ARPA
named[37848]: automatic empty zone: 255.255.255.255.IN-ADDR.ARPA
named[37848]: 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
named[37848]: automatic empty zone: D.F.IP6.ARPA
named[37848]: automatic empty zone: 8.E.F.IP6.ARPA
named[37848]: automatic empty zone: 9.E.F.IP6.ARPA
named[37848]: automatic empty zone: A.E.F.IP6.ARPA
named[37848]: automatic empty zone: B.E.F.IP6.ARPA
named[37848]: automatic empty zone: 8.B.D.0.1.0.0.2.IP6.ARPA
named[37848]: automatic empty zone: EMPTY.AS112.ARPA
named[37848]: automatic empty zone: HOME.ARPA
named[37848]: none:104: 'max-cache-size 90%' - setting to 14256MB (out of 15840MB)
named[37848]: configuring command channel from '/etc/rndc.key'
named[37848]: command channel listening on 127.0.0.1#953
named[37848]: managed-keys-zone: loaded serial 20952
named[37848]: zone 0.in-addr.arpa/IN: loaded serial 0
named[37848]: 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/IN: loaded serial 0
named[37848]: zone 254.168.192.in-addr.arpa/IN: loaded serial 2019101568
named[37848]: zone 1.0.0.127.in-addr.arpa/IN: loaded serial 0
named[37848]: zone gaztronics.net/IN: loaded serial 2019101973
named[37848]: zone localhost/IN: loaded serial 0
named[37848]: zone 10.168.192.in-addr.arpa/IN: loaded serial 2019101679
named[37848]: zone localhost.localdomain/IN: loaded serial 0
named[37848]: all zones loaded
named[37848]: running
systemd: Started Berkeley Internet Name Domain (DNS).
named[37848]: resolver priming query complete

Lots of output to confuse, and most of it can be ignored if the daemon has started correctly. [37848] in the above example is the programme-ID (PID) of the running BIND daemon.


4: Testing

On the server you have just installed the BIND daemon, you can now test if DNS look-ups are working. Firstly change the entry (or entries) in /etc/resolv.conf to read: nameserver 127.0.0.1. Comment-out or remove any other nameserver entries, otherwise your system will use those and you will not be able to tell if you are working with your local server. The server should now be looking at its own BIND daemon for name resolution. Test this with the dig command:

Try looking up something like www.nasa.gov with: dig www.nasa.gov

If your nameserver is working you should see something like this:

; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7_9.5 <<>> www.nasa.gov
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 63858
;; flags: qr rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 4, ADDITIONAL: 5

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www.nasa.gov. IN A

;; ANSWER SECTION:
www.nasa.gov. 600 IN CNAME www.nasawestprime.com.
www.nasawestprime.com. 30 IN CNAME d30etcnkn29cv0.cloudfront.net.
d30etcnkn29cv0.cloudfront.net. 60 IN A 65.9.73.30
d30etcnkn29cv0.cloudfront.net. 60 IN A 65.9.73.28
d30etcnkn29cv0.cloudfront.net. 60 IN A 65.9.73.113
d30etcnkn29cv0.cloudfront.net. 60 IN A 65.9.73.108

;; AUTHORITY SECTION:
d30etcnkn29cv0.cloudfront.net. 1831 IN NS ns-1703.awsdns-20.co.uk.
d30etcnkn29cv0.cloudfront.net. 1831 IN NS ns-708.awsdns-24.net.
d30etcnkn29cv0.cloudfront.net. 1831 IN NS ns-393.awsdns-49.com.
d30etcnkn29cv0.cloudfront.net. 1831 IN NS ns-1157.awsdns-16.org.

;; ADDITIONAL SECTION:
ns-1157.awsdns-16.org. 172800 IN A 205.251.196.133
ns-1703.awsdns-20.co.uk. 172800 IN A 205.251.198.167
ns-393.awsdns-49.com. 172800 IN A 205.251.193.137
ns-708.awsdns-24.net. 172800 IN A 205.251.194.196

;; Query time: 454 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Wed Aug 25 13:32:37 UTC 2021
;; MSG SIZE rcvd: 381

I have highlighted the query time above. As this is the first time we have requested this information, the BIND daemon has gone out to the open Internet to resolve the look-up and offer the information. It you repeat that look-up with dig, you should see something like: Query time: 28 msec which indicates the look-up has been resolved via the cache. This data will live in the cache for the length of the Time-To-Live data set by the DNS administrator of that domain. TTLs can be anywhere between a few minutes to several days. A restart of the BIND daemon will always clear the cached DNS data.


5: Zone files

With a working caching nameserver, you can now start on the creation of your forward and reverse DNS zone files for your in-house/office network. In the examples for this howto, I will use my own gaztronics.net domain as a real-world example.

Zone files created in this section will need to be placed in /var/named. This directory contains several files required by the BIND daemon, and for security, directories are owned by the user named and the group named, whilst some files are own by root the named group, and others are owned completely by named. Incorrect permissions in this directory will stop the BIND daemon from working.

You may notice a slave directory. This would contain the zone files if we were offering a secondary DNS to a master server. This feature is not covered in this howto as we are assuming a single server installation.

You are going to need to create a master directory to contain your zone files. This is not documented - simply my way of setting things up. As root, and from within /var/named run the command: mkdir master and set its permissions with: chown named:named master and chmod 770 master.

Change to the master directory cd /var/named/master as this is where we will create our zone files.

Forward zone

To keep things simple, I name the forward zone file with the same name as the domain name I am using. In this howto, the file is called gaztronics.net. If your domain is planking.com, then call your file planking.com. This will become apparent later in the howto...

Create your forward zone file with your favourite text-editor and place the following inside:

$ORIGIN .
$TTL 3600 ; 1 hour
gaztronics.net        IN SOA    gaztronics.net. hostmaster.gaztronics.net. (
                2019101973 ; serial
                28800 ; refresh (8 hours)
                7200 ; retry (2 hours)
                604800 ; expire (1 week)
                86400 ; minimum (1 day)
                )
            NS dns.gaztronics.net.
            A 192.168.30.253
            MX 10 mail.gaztronics.net.
            TXT "Gaztronics Network Services"

$TTL 3600 ; 1 hour
dns            A    192.168.30.253

I suggest you read-up on how BIND zone files are created in order to gain the maximum knowledge on the correct syntax to use in this file. If you get it right, BIND will start without issue and you can start adding DNS entries. The above example should be enough to make a start on your in-house/office DNS solution.

If your domain was planking.com, then you would change all of the gaztronics.net references to suit your own domain name.

The MX entry assumes you have a mail-transport-agent (such as Sendmail) running on mail.gaztronics.net (in this example). Do not include this line if your domain will be working without email. If you do use in-house email, you will also need to provide an A record for mail. to resolve against.

The serial number should be today's date, as year, month, day, and a number. e.g. 2021082501

If you manually adjust the zone files, you should increment the serial, else changes will not be read-in at start-up/restart. Manual changes are not ideal. It is recommended to use the nsupdate command-line tool.

Reverse zone

You also need to create a pointer-record zone file to provide IP address to name resolution. As with the domain name above, I prefer to create the file name to match the in-addr.arpa standard. If your network range is 192.168.30.x/24, create your reverse zone file as: 30.168.192.in-addr.arpa and add the following to it, with your favourite text-editor.

$ORIGIN .
$TTL 3600 ; 1 hour
30.168.192.in-addr.arpa IN SOA gaztronics.net. hostmaster.gaztronics.net. (
            2019101679 ; serial
            28800 ; refresh (8 hours)
            7200 ; retry (2 hours)
            604800 ; expire (1 week)
            86400 ; minimum (1 day)
            )
            NS dns.gaztronics.net.
$ORIGIN 30.168.192.in-addr.arpa.

The serial number should be today's date, as year, month, day, and a number. e.g. 2021082501

If you manually adjust the zone files, you should increment the serial, else changes will not be read-in at start-up/restart. Manual changes are not ideal. It is recommended to use the nsupdate command-line tool.

/etc/named

In order for BIND to work with the newly created in-house/office zone files, we need to tell it about them. In the directory /etc/named create a config file for your zones. In my case, the file is called gaztronics.zones and it contains the following:

//
// named.gaztronics.zones
//

zone "gaztronics.net" {
    type master;
    file "master/gaztronics.net";
    allow-update { localhost; };
};


zone "30.168.192.in-addr.arpa" {
    type master;
    file "master/30.168.192.in-addr.arpa";
    allow-update { localhost; };
};

The line file "master/..." means BIND will look in /var/named/master for the zone file. The line allow-update { localhost; }; means BIND will only accept updates from the localhost; i.e. via nsupdate or via the Dynamic DNS function of a DHCP server.

We now need to include this configuration file in /etc/named.conf by adding the following line at the bottom of the config file: include "/etc/named/gaztronics.zones";

Restarting the BIND daemon with systemctl restart named should now load your newly created zone files. Check /var/log/messages for entries like this:

named[37848]: zone gaztronics.net/IN: loaded serial 2019101973
named[37848]: zone 30.168.192.in-addr.arpa/IN: loaded serial 2019101679

We are not quite ready to go. Fixed-IP systems on your network, including the server you are running BIND on, will not add their own names to the DNS zonefiles as they should not be running DHCP. You will need to add them manually using the nsupdate tool.

For example, after starting nsupdate you would enter:

update add server.gaztronics.net 3600 A 192.168.30.253
update add 253.30.168.192.in-addr.arpa. 3600 PTR server.gaztronics.net.
send
quit

I suggest reading-up on how nsupdate works, as it can be fussy about the syntax you feed it. If it has worked, you should be able to confirm your A and PTR records are present with appropriate dig commands.

If you now follow my DHCP howto, you should see DNS entries being send to the BIND daemon by the DHCP daemon as part of the Dynamic DNS set-up. DNS entries created via this route will come from both static assignments and via the pool. Pool addresses will take whatever DNS hostname the client says it wants to use.


6: Journal

If things are working correctly, you will notice new files in /var/named/master that have a .jnl extension. All DNS changes currently live in memory are written out to these files - and you cannot read them. You have to use the rndc command to freeze/thaw/sync the zones, as in the examples below. If you are in the /var/named/master directory, you can use BASH completion on the file names, as we made them the same as the domain names. See, there is method in the madness!

rndc freeze gaztronics.net - will stop all DNS entries being written to the zone file.

rndc thaw gaztronics.net - will allow normal operation.

rndc freeze 30.168.192.in-addr.arpa - will stop all DNS entries being written to the zone file.

rndc thaw 30.168.192.in-addr.arpa - will allow normal operation.

rndc sync -clean gaztronics.net - will flush the jnl file to the zone file.

rndc sync -clean 10.168.192.in-addr.arpa- will flush the jnl file to the zone file.

Back-up

If you plan to back-up your server (or other servers running DNS) via Rsync, it is a good idea to create a script that calls the sync -clean on each of your zone files in order to obtain a clean back-up. All of my super-user scripts live in /root/scripts. My sync script is called sync-named and it is called from a BASH script (that controls the rsync back-up process) at a point before /var items are checked for changes. The script contains the following:

#!/bin/bash
#
# Script to synchronise named master files

/sbin/rndc sync -clean gaztronics.net
/sbin/rndc sync -clean 30.168.192.in-addr.arpa

exit 0

An example of how to remotely call the script from a centralised rsync back-up server running scripts for each server being backed-up:

#---------------------------------------------------------------

# Run MySQL back-up script

ssh -l root $SERVER '/root/scripts/sync-named'

#---------------------------------------------------------------

In the above example $SERVER would be defined in the script as the FQDN of the server being backed-up.


7: AdBlock

So you want to block advert servers at DNS level? Before we get started...

Caveat Emptor: I have come across a number of websites that try to track their visitors by using CNAME tracking of images. The Adobe owned media serving website: scene7.com is one example. The DNS blocking system described below can leave some websites completely unusable. At the time of writing, UK websites affected include: Wickes and John Lewis.

Now you have a working DNS server, this addition is quite simple, although your BIND daemon will take several seconds to restart as it loads thousand of zones into memory. A stout server with plenty of RAM is required.

There are two projects on GitHub creating block lists which aggregate lists of known advert/malware/tracking servers. This project External link  https://github.com/oznu/dns-zone-blacklist offers a variety of zone files for use with BIND and others. It takes its block lists from here: External link  https://github.com/StevenBlack/hosts

At the time of writing, the first GitHub project appears to have lost its Travis CI build system, and it is therefore out of date. If you want to use it, you can utilise the script below.

oznu/dns-zone-blacklist

In order to download the necessary zone file, I created a script called: bind-blacklist-download and its contents are:

#!/bin/bash
#
# Script to download DNS blacklist zone file
#
# Last updated: 14th January 2021

wget -q -r https://raw.githubusercontent.com/oznu/dns-zone-blacklist/master/bind/zones.blacklist \
-O /etc/named/zones.blacklist

chown root:named /etc/named/zones.blacklist

systemctl reload named

exit 0

My scripts live in /root/scripts and this file is called via cron by creating a symlink in /etc/cron.daily to /root/scripts/bind-blacklist-download and restarting cron.

In order to use the zone file, we need to add a reference to the bottom of /etc/named.conf like this: include "/etc/named/zones.blacklist";

We also need to disable a master check, else BIND will fail to start. In the options { section, add the following: check-names master ignore;

zones.blacklist references a file called null.zone.file which needs to be created in /var/named and given the same root:named and 750 permissions as the other named.* files. The file needs to be configured to suit your in-house/office DNS server, as in the example below:

; BIND db file for ad servers - point all addresses to an invalid IP
$TTL 864000 ; ten days

@       IN      SOA     dns.gaztronics.net.      hostmaster.gaztronics.net. (
                      2008032800       ; serial number YYMMDDNN
                      288000   ; refresh 80 hours
                      72000    ; retry 20 hours
                      8640000  ; expire 100 days
                      864000 ) ; min ttl 10 day
                NS      dns.gaztronics.net.

      A    0.0.0.0

*    IN      A       0.0.0.0

With the above complete, you should be ready to restart the BIND daemon with systemctl restart named; and as ever, I recommend watching /var/log/messages for any major errors. The results of the blocking should be instantly viewable on websites and inside mobile phone apps that suddenly have blank spaces where obtrusive and dangerous malverts once lurked.

StevenBlack/hosts

An alternative to the oznu/dns-zone-blacklists project is to download the hosts file from StevenBlack/hosts and convert it to a DNS zone file. You can do this with an alternative script bind-blacklist-download2 and its contents are:

#!/bin/bash
#
# Script to download DNS blacklist zone file
#
# Last updated: 25th August 2021

wget -q -r https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts \
-O /tmp/hosts

egrep '0.0.0.0' /tmp/hosts | \
awk '!/^0.0.0.0 0.0.0.0/' | \
awk '!/#/' | \
awk '{print $2}' | sort -u > /tmp/domains

# Delete old zone file
#
rm -f /etc/named/zones.blacklist

for DOMAINS in $(cat /tmp/domains); do
  echo -e "zone \"$DOMAINS\" { type master; notify no; file \"null.zone.file\"; };" >> /etc/named/zones.blacklist;
done

chown root:named /etc/named/zones.blacklist

systemctl reload named

rm -f /tmp/hosts /tmp/domains

exit 0

The egrep and awk lines strip out comments and other data we do not need.

Save the script in /root/scripts as bind-blacklist-download as as above, create a symlink in /etc/cron.daily to have the script run every day. The rest of the DNS set-up is the same.


Page updated: 28th August 2021