Home RSS icon My CV icon

Configure Dns Servers With Failover Using Bind

Date: 14 April 2023

1 Introduction

We are going to setup and confgure a DNS server with a failover and dynamic updates on RockyLinux using BIND.

named stands for NAMEserver Daemon.

The Bind packages is called named in the RedHat-like distribution like RockyLinux.

2 Prerequisites

Two VMs with RockyLinux with the following configurations

Hostname IP address Roles SELinux FirewallD
admin1.hl.test 10.10.0.2/24 Master DNS Enforcing Enabled
admin2.hl.test 10.10.0.3/24 Backup DNS Enforcing Enabled

3 The Plan

  1. Install the required packages on both servers
  2. RNDC Setup
  3. Configure Master DNS
  4. Configure Backup DNS
  5. Configure a client server for testing

4 Primary configuration on the nodes

On both server, install the following packages

sudo dnf install bind bind-utils -y

Let's make sure that the service is enabled at startup.

sudo systemctl enable named

Allow DNS traffic

sudo firewall-cmd --add-service=dns --permanent
sudo firewall-cmd --reload
success
success

Setup the log directory for named

sudo mkdir -p -m 0700 /var/log/named
sudo chown named:named /var/log/named
sudo ls -ldh /var/log/named
drwx------. 2 named named 6 Apr 14 14:40 /var/log/named

5 RNDC Setup

Check out this great book for more information about DNS and other System Administration stuff.

unix_linux_handbook_5th_edition.png

RNDC or "Remote Name Daemon Control Utility". It's a command that allows you to control you Domain Name System (DNS) without altering or modifying you DNS configuration files.

To use the rndc command, we must first generate a key and then import it into the named configuration file.

Let's create a key

sudo rndc-confgen -a -b 512
wrote key file "/etc/rndc.key"

We need to give it appropriate permissions.

chown root:named /etc/rndc.key
chmod 0640 /etc/rndc.key

6 Master DNS configuration

We will seperate our configuration into multiple files and use include statement to embed these files into /etc/named.conf file. This will help us seperate the the parts of the configuraton that are static from those that can be changed overtime.

sudo tree /etc/named --noreport
/etc/named
├── logging.conf
└── zones.conf

The main configuration file

the main configuration file for named is /etc/named.conf, open this file and add the following content

# vim: syntax=named

# Include RFC 1912 compliant zone files
include "/etc/named.rfc1912.zones";

# Include root DNSSEC trust anchor key
include "/etc/named.root.key";

# Include rndc key for remote control of named
include "/etc/rndc.key";

# Include zones configuration file
include "/etc/named/zones.conf";

# Include logging configuration file
include "/etc/named/logging.conf";

# Allow rndc management on localhost using rndc-key
controls {
  inet 127.0.0.1 port 953 allow { 127.0.0.1; } keys { "rndc-key"; };
};

# Limit access to trusted networks
acl "trusted" {
  # Allow loopback addresses
  127.0.0.0/8;
  # Add local LAN subnet(s)
  10.10.0.0/24;
};

# Set global options
options {
  # Listen on port 53 for requests from localhost and 10.10.0.2 (MASTER)
  listen-on port 53 { 127.0.0.1; 10.10.0.2; };

  # Disable IPv6
  listen-on-v6 port 53 { none; };

  # Set directory for zone files, cache dump, stats, and root DNSSEC trust anchors
  directory "/var/named";
  dump-file "/var/named/data/cache_dump.db";
  statistics-file "/var/named/data/named_stats.txt";
  memstatistics-file "/var/named/data/named_mem_stats.txt";
  secroots-file "/var/named/data/named.secroots";
  recursing-file "/var/named/data/named.recursing";

  # Disable built-in server information zones
  version none;
  hostname none;
  server-id none;

  # Enable recursion and allow queries from trusted networks only
  recursion yes;
  allow-recursion { trusted; };
  allow-query { trusted; };

  # Allow zone transfers from localhost and 10.10.0.3 (SLAVE)
  allow-transfer { localhost; 10.10.0.3; };

  # Enable DNSSEC validation
  dnssec-validation yes;

  # Set directory for managed keys
  managed-keys-directory "/var/named/dynamic";

  # Set directory for GeoIP data
  geoip-directory "/usr/share/GeoIP";

  # Set PID file and session key file
  pid-file "/run/named/named.pid";
  session-keyfile "/run/named/session.key";

  # Include bind crypto policies configuration
  include "/etc/crypto-policies/back-ends/bind.config";
};

The zones configuration file

Here we define our zones; each zone must have its corresponding reverse zone

In our case, we need to setup a forward zone and a reverse zone for our local domain hl.test. All data related to this zones is saved on /data/db.hl.test and /data=db.0.10.10 respectively.

Of course, you can use whatever filename with the file clause in the zone section, here I chose to use db.hl.test and db.0.10.10 for example.

reverse zone is indentified as follow:
<subnet ip in reverse>.in-addr.arpa
in-addr.arpa is a fixed suffix.

# vim: syntax=named
# Use the root hints file for "." zone
zone "." IN {
    type hint;
    file "named.ca";
};

# Internal zone definitions
zone "hl.test" {
    type master;
    file "data/db.hl.test";
    # Allow updates with rndc key
    allow-update { key rndc-key; }; 
    # Notify slave servers when zone changes
    notify yes; 
};

# Reverse DNS zone for 10.10.0.0/16 subnet
zone "0.10.10.in-addr.arpa" {
    type master;
    file "data/db.0.10.10";
    # Allow updates with rndc key
    allow-update { key rndc-key; };
    # Notify slave servers when zone changes
    notify yes; 
};

Our DNS records are stored in files that act as a database on the primary server and called the Zones files. The secondary server fetches this data regularly for consistency.

Hence, the full path is /var/named/data/db.hl.test

As you can see from the zones configuration we used above, we ordered our server to fetch it's records data from data/db.hl.test.
Of course, this path is relative, because we mentioned the root directory in the main configuration above with directory "/var/named"

The forward zone records.

Make sure to update the Serial number in the zone files file every time it is modified. This allows Bind to recognize that a change has been made.

; vim: ft=bindzone
$TTL 86400      ; 1 day
@                       IN SOA  dns1.hl.test. root.hl.test. (
                                3 ; Serial
                                3600       ; Refresh (1 hour)
                                3600       ; Retry (1 hour)
                                604800     ; Expire (1 week)
                                3600       ; Minimum (1 hour)
)
; name servers -- NS records
@                           IN  NS      ns1.hl.test.
@                           IN  NS      ns2.hl.test.
; name servers -- A records
ns1.hl.test.            IN  A   10.10.0.2
ns2.hl.test.            IN  A   10.10.0.3

; 10.10.0.0/24 -- A records
admin1.hl.test.         IN  A   10.10.0.2
admin2.hl.test.         IN  A   10.10.0.3

And then, the reverse zone records

; vim: ft=bindzone
;
; BIND reverse data file for broadcast zone
;
$TTL    604800
@       IN      SOA     hl.test. root.hl.test. (
                              3         ; Serial
                         604800         ; Refresh
                          86400         ; Retry
                        2419200         ; Expire
                         604800 )       ; Negative Cache TTL
;
; name servers
      IN      NS      ns1.hl.test.
      IN      NS      ns2.hl.test.

; PTR Records
2               IN  PTR ns1.hl.test.    ; 10.10.0.2
3               IN  PTR ns2.hl.test.    ; 10.10.0.2
2               IN  PTR admin1.hl.test.    ; 10.10.0.2
3               IN  PTR admin2.hl.test.    ; 10.10.0.2

The logging configuration file

And the logging configuration file

# vim: syntax=named
# Logging configuration
logging {
    # Default debug channel
    channel default_debug {
        file "data/named.run";
        severity dynamic;
    };

    # Common log channel
    channel "common_log" {
        file "/var/log/named/named.log" versions 10 size 5m;
        severity dynamic;
        print-category yes;
        print-severity yes;
        print-time yes;
    };

    # Categories for logging
    category default { "common_log"; };
    category general { "common_log"; };
    category queries { "common_log"; };
    category client { "common_log"; };
    category security { "common_log"; };
    category query-errors { "common_log"; };
    category lame-servers { null; };
};

7 Backup DNS configuration

The main configuration file

Now with the backup DNS configuration

# vim: syntax=named

# Include RFC 1912 compliant zone files
include "/etc/named.rfc1912.zones";

# Include root DNSSEC trust anchor key
include "/etc/named.root.key";

# Include zones configuration file
include "/etc/named/zones.conf";

# Include logging configuration file
include "/etc/named/logging.conf";

# Limit access to trusted networks
acl "trusted" {
  # Allow loopback addresses
  127.0.0.0/8;
  # Add local LAN subnet(s)
  10.10.0.0/24;
};

# Set global options
options {
  # Listen on port 53 for requests from localhost and 10.10.0.3 (SLAVE)
  listen-on port 53 { 127.0.0.1; 10.10.0.3; };

  # Disable IPv6
  listen-on-v6 port 53 { none; };

  # Set directory for zone files, cache dump, stats, and root DNSSEC trust anchors
  directory "/var/named";
  dump-file "/var/named/data/cache_dump.db";
  statistics-file "/var/named/data/named_stats.txt";
  memstatistics-file "/var/named/data/named_mem_stats.txt";
  secroots-file "/var/named/data/named.secroots";
  recursing-file "/var/named/data/named.recursing";

  # Disable built-in server information zones
  version none;
  hostname none;
  server-id none;

  # Enable recursion and allow queries from trusted networks only
  recursion yes;
  allow-recursion { trusted; };
  allow-query { trusted; };

  allow-transfer { none };

  # Enable DNSSEC validation
  dnssec-validation yes;

  # Set directory for managed keys
  managed-keys-directory "/var/named/dynamic";

  # Set directory for GeoIP data
  geoip-directory "/usr/share/GeoIP";

  # Set PID file and session key file
  pid-file "/run/named/named.pid";
  session-keyfile "/run/named/session.key";

  # Include bind crypto policies configuration
  include "/etc/crypto-policies/back-ends/bind.config";
};

The zones configuration file

# vim: syntax=named
# Use the root hints file for "." zone
zone "." IN {
    type hint;
    file "named.ca";
};

# Internal zone definitions
zone "hl.test" {
    type slave;
          file "data/db.hl.test";
    masters { 10.10.0.2; };
    allow-notify { 10.10.0.2; };
};

zone "0.10.10.in-addr.arpa" {
          type slave;
          file "data/db.0.10.10";
    masters { 10.10.0.2; };
    allow-notify { 10.10.0.2; };
};

The logging configuration file

And then the logging configuration file.

# vim: syntax=named
# Logging configuration
logging {
    # Default debug channel
    channel default_debug {
        file "data/named.run";
        severity dynamic;
    };

    # Common log channel
    channel "common_log" {
        file "/var/log/named/named.log" versions 10 size 5m;
        severity dynamic;
        print-category yes;
        print-severity yes;
        print-time yes;
    };

    # Categories for logging
    category default { "common_log"; };
    category general { "common_log"; };
    category queries { "common_log"; };
    category client { "common_log"; };
    category security { "common_log"; };
    category query-errors { "common_log"; };
    category lame-servers { null; };
};

8 Configure a client server

  • The number of nameservers allowed on /etc/resolv.conf are 3.
  • The first request are tried against the first nameserver, if the query was timed out, it will move to the next.
  • Each nameserver is tried 4 times.

To configure the client, all we need to do is to update the /etc/resolv.conf file with the IP addresses of our new local DNS server.

sudo nmcli c mod eth0 ipv4.dns '10.10.0.2 10.10.0.3'
cat /etc/resolv.conf 
# Generated by NetworkManager
nameserver 10.10.0.2
nameserver 10.10.0.3

Creative Commons License

Copyright © 2023 Zakaria Kebairia
Content licensed CC-BY-SA 4.0 unless otherwise noted.