Install a DNS Server with a Shell Script (Linux Automation — Part I)

Iyana Garry
9 min readMar 18, 2019

--

When I set up a Red Hat virtual machine for the first time and got to the software installation part of the set-up, the automator in me wondered if there was a way to set up all of this software with my own scripts. Turns out, there is! :)

I started off by following a tutorial video on how to set up a DNS server. The video lasts about 15 minutes but the script took a few days to debug. It is my belief that half the battle in shell scripting is figuring out how text manipulation works (the “sed”, “awk” and “cut” commands.)

Fortunately, I’m willing to put in the work so you don’t have to. :)

This tutorial series will be broken down into explanations of each section of the scripts, screenshots of terminal commands, before-and-after screenshots and the complete scripts.

A screenshot of the first section of the shell script.

It is good practice to start the script with a shebang (#!/bin/bash) — in case you’re working on a Linux system that is not configured with the Bash shell by default — and an update of the system (the -y option automatically answers “yes” to future questions, such as “Are you sure? [y/N]”.)

A screenshot of the second section of the shell script.

If you’re using this section for testing purposes, then this is optional. This section of the script modifies the domain name of the system. The default domain name is “localdomain”.

A screenshot of the shell terminal.

The “hostname” command prints the fully qualified domain name (FQDN) of the system, which is a combo of the hostname and the domain name.

The “awk” command above divides the FQDN by the period “.” and prints the second column of text, which is the domain name.

A screenshot of the shell terminal.

The “ip -o link show” command prints the system’s network interfaces. The command concatenated with the “awk” command makes the text more condensed and readable.

There are four network interfaces on my system: the loopback interface (“lo”), Ethernet interface (“enp0s3”) and the virtual bridge interfaces (“virbr0” and “virbr0-nic”.)

Of course, I will be using the Ethernet interface to configure the DNS server with.

A screenshot of the third section of the shell script.

There are four files that will be configured for this tutorial (the fourth file will be mentioned later.)

The three files mentioned in this sections are:

  • “/etc/named.conf” = the DNS server’s configuration file
  • “/var/named/forward.[domain name]” = the DNS server’s forward zone file
  • “/var/named/reverse.[domain name]” = the DNS server’s reverse zone file

The forward zone file points the hosts in the forward zone, a.k.a. the domain, to their respective IPv4 addresses with “A” records.

The reverse zone file provides the ability to do reverse lookups by pointing IPv4 addresses to their respective hosts.

The “read” command in the script is a will allow you to enter the name of the network interface of your choosing.

A screenshot of the shell terminal.

The “ifconfig enp0s3” command prints networking information about the Ethernet interface. Concatenated with the “awk” command, it prints only the Ethernet interface’s IPv4 address (‘awk -F‘ ’ ‘FNR == 2 {print $2}’’ prints the second row and the second column of text that is separated by a space, ‘ ’).

A screenshot of the fourth section of the shell script.

The “net_int_ip” variable is the IPv4 address of the Ethernet interface.

The “echo” command points the Ethernet interface’s IPv4 address to the system’s FQDN and saves this to the “/etc/hosts” file, the fourth file that was mentioned earlier.

A screenshot of the shell terminal.

The “oct_1”, “oct_2”, etc. variables are the octets of the IPv4 address.

The “first_3_oct_reverse” variable reverses the first 3 octets of the IPv4 address. This will come in handy when we configure the reverse lookup zone in the “/etc/named.conf” file.

The “desktop_ip” variable is the IPv4 address of a host that would be in the domain.

A screenshot of the fifth section of the shell script.

The “bind” package installs the DNS server. The “bind-utils” package allows you to query the DNS server.

If you like more information on a particular package, use the “rpm -qi [name of package]” command.

A screenshot of the shell terminal.
A screenshot of the sixth section of the shell script.

This is where the part of learning how shell scripting works got interesting. I wanted to insert the IP address at a specific position in the “/etc/named.conf” file.

To break down this command, the “-i” option inserts the text, “13” is the line number in the file where I want to insert the text, “32” is the index of the line where I want to insert the text (meaning, the first letter of the text that I want to insert will be the 32nd character of the line) and “$_net_int_ip;” is the “net_int_ip” variable (the “/etc/named.conf” requires a “;” at the end of the IP address.)

Before-and-After screenshots of the “/etc/named.conf” file.
A screenshot of the seventh section of the shell script.

This is an array and a for-loop that sends 4 commands to the firewall. I could’ve just written out the firewall rules as such:
firewall-cmd --add-port=53/tcp --permanent --zone=public
firewall-cmd --add-port=53/udp --permanent --zone=public
firewall-cmd --reload
firewall-cmd --list-all

However, I created the array and for-loop to avoid repetitiveness.

The “\” in the array splits it in two so that you will be able to see the entire array, since I didn’t configure my Nano text editor to wrap words.

A screenshot of the eighth section of the shell script.

This is another array and for-loop that configures the system to start the DNS server during bootup, start the DNS server right now and show the status of the DNS server.

A screenshot of the ninth section of the shell script.

This section looks like a lot but it’s actually simple; it inserts the forward and reverse lookup zones in the “/etc/named.conf” file. Below is what the script did.

Before-and-After screenshots of the “/etc/named.conf” file.
A screenshot of the tenth section of the shell script.

This section creates a file for the forward lookup zone by creating a copy of the “/var/named/named.localhost” file, renaming it after the variable that I created earlier (forward_file=“/var/named/forward.[domain name]”) and entering the DNS records of the domain name and IP address at the end of the file.

Before-and-After screenshots of the “/var/named/forward.example.com” file.
A screenshot of the eleventh section of the shell script.

This section creates the reverse lookup zone file by making a copy of the forward lookup zone file and renaming it, using the “$reverse_file” variable I made earlier.

Before-and-After screenshots of the “/var/named/reverse.example.com” file.
A screenshot of the twelfth and final section of the shell script.

This section configures “root” as the user and “named” as the group that owns the forward and reverse lookup zone files, checks the validity of the files we just configured and restarts the DNS server so that the configurations will be implemented.

A screenshot of the shell terminal.

To execute the shell script, I use the “sudo sh [file path of the script]” command since there are some commands in the script that require root access, like the firewall commands and editing files in the /var and /etc directories.

A screenshot of the terminal shell output that configures the DNS server.

Based on the output, the shell script’s DNS server configuration was successful. Below is the shell script in full:

#!/bin/bash
# Update the metadata of the yum repository.
yum update -y
# Configure a domain name for your system.
host_name=$(hostname | awk -F”.” ‘{print $1}’)
echo ‘Enter a new domain name for your system: ‘
read -r “domain_name”
hostnamectl — static set-hostname “${host_name}.$domain_name”
fqdomain_name=$(hostname)
# Assign the configuration files to variables.
named_file=”/etc/named.conf”
forward_file=”/var/named/forward.$domain_name”
reverse_file=”/var/named/reverse.$domain_name”
# List the available network interfaces.
net_int=$(ip -o link show | awk -F’: ‘ ‘{print $2}’)
echo $net_int
echo ‘Enter the network interface to configure the DNS server with: ‘
read -r “net_int_name”
# Assign IP addresses to variables.
net_int_ip=$(ifconfig $net_int_name | awk -F’ ‘ ‘FNR == 2 {print $2}’)
echo “${net_int_ip} ${fqdomain_name}” >> /etc/hosts
oct_1=$(expr $net_int_ip | cut -d”.” -f1)
oct_2=$(expr $net_int_ip | cut -d”.” -f2)
oct_3=$(expr $net_int_ip | cut -d”.” -f3)
oct_4=$(expr $net_int_ip | cut -d”.” -f4)
first_3_oct_reverse=”${oct_3}.${oct_2}.${oct_1}”
desktop_ip=”${oct_1}.${oct_2}.${oct_3}.$(expr $oct_4–1)”
# Install the packages for the DNS server.
yum install -y bind bind-utils
# Configure the “named” server configuration file with the IP address at line 13.
sed -i “13s/^\(.\{32\}\)/\1$net_int_ip; /” $named_file
# Enable a firewall rule that permits DNS traffic.
firewall_array=(‘ — add-port=53/tcp — permanent — zone=public’ ‘ — add-port=53/udp — permanent — zone=public’ ‘ — reload’ ‘ — list-all’)
for i in ${firewall_array[@]}
do
firewall-cmd $i
done
# Enable, start and verify the status of the “named” server.
named_array=(‘enable’ ‘start’ ‘ — no-pager status’)
for i in ${named_array[@]}
do
systemctl $i named
done
# Configure a primary zone for the DNS server.
# Insert 12 blank lines at line 59.
sed -i ‘59s/^/\n\n\n\n\n\n\n\n\n\n\n\n/’ $named_file
# Insert ‘zone “[domain name]” IN {‘ at line 59
sed -i ‘59s/^/” IN {/’ $named_file
sed -i “59s/^/$domain_name/” $named_file
sed -i ‘59s/^/zone “/’ $named_file
# Insert ‘ type master;’ at line 60
sed -i ‘60s/^/\t type master;/’ $named_file
# Insert ‘ file “forward.[domain name]”;’ at line 61
sed -i ‘61s/^/”;/’ $named_file
sed -i “61s/^/$domain_name/” $named_file
sed -i ‘61s/^/ \t file “forward./’ $named_file
# Insert ‘ allow-update { none; };’ at line 62
sed -i ‘62s/^/ \t allow-update { none; };/’ $named_file
# Insert ‘};’ at line 63
sed -i ‘63s/^/};/’ $named_file
# Configure a reverse lookup zone for the DNS server.
# Insert ‘zone “[first 3 octets of IP address in reverse].in-addr.arpa” IN {‘ at line 65
sed -i ‘65s/^/.in-addr.arpa” IN {/’ $named_file
sed -i “65s/^/$first_3_oct_reverse/” $named_file
sed -i ‘65s/^/zone “/’ $named_file
# Insert ‘ type master;’ at line 66.
sed -i ‘66s/^/\t type master;/’ $named_file
# Insert ‘ file “reverse.[domain name]”;’ at line 67.
sed -i ‘67s/^/”;/’ $named_file
sed -i “67s/^/$domain_name/” $named_file
sed -i ‘67s/^/ \t file “reverse./’ $named_file
# Insert ‘ allow-update { none; };’ at line 68.
sed -i ‘68s/^/ \t allow-update { none; };/’ $named_file
# Insert ‘};’ at line 69.
sed -i ‘69s/^/};/’ $named_file
# Configure the DNS server’s forward zone file.
cp /var/named/named.localhost $forward_file
# Edit line 2 as “@ IN SOA [domain name]. root.[domain name]. (“
sed -i -e “2s/@ rname.invalid/${domain_name}. root.$domain_name/” $forward_file
# Remove the last 3 lines of the forward zone file.
for i in $(seq 1 3)
do
sed -i ‘$d’ $forward_file
done
# Add DNS records to the end of the forward zone line.
echo “
@ IN NS $domain_name.
@ IN A $net_int_ip
server IN A $net_int_ip
host IN A $net_int_ip
desktop IN A $desktop_ip
client IN A $desktop_ip” >> $forward_file
# Configure the reverse zone file.
cp $forward_file $reverse_file
# Edit line 10 as “@ IN PTR [domain name].”
sed -i -e “10s/A/PTR/;10s/${net_int_ip}/${domain_name}./” $reverse_file
# Add PTR records to the end of the reverse zone file.
echo “11 IN PTR server.$domain_name.
10 IN PTR desktop.$domain_name.” >> $reverse_file
# Configure the ownership of the forward and reverse zone files.
chown root:named $forward_file
chown root:named $reverse_file
# Verify the validity of the DNS server’s configuration files.
named-checkconf -z $named_file
named-checkzone forward $forward_file
named-checkzone reverse $reverse_file
# Restart the DNS server.
systemctl restart named

View Part II of this tutorial series on DHCP server automation.

View Part III of this tutorial series on blog and web server automation.

--

--

Iyana Garry
Iyana Garry

Written by Iyana Garry

Security, automation and cloud enthusiast.

Responses (1)