Common tasks on DNS using BIND

1. Run BIND on a server dedicated to DNS only:

#!/bin/bash

# Update the package lists for upgrades and new package installations
sudo apt-get update

# Install BIND9 and related packages
sudo apt-get install -y bind9 bind9utils bind9-doc dnsutils

# Check the status of BIND (named) service
sudo systemctl status bind9

# If not active, start the BIND service
sudo systemctl start bind9

# Enable BIND service to start on boot
sudo systemctl enable bind9

# Open the named.conf.options file in an editor
sudo nano /etc/bind/named.conf.options

# Add the following lines to the options section of the file
# replace 'your_dns_servers' with the IP addresses of your DNS servers
# forwarders {
#     your_dns_servers;
# };

# Save and close the file

# Check the configuration syntax for errors
sudo named-checkconf

# If the above command doesn't return any errors, restart the BIND service
sudo systemctl restart bind9

2. Run separate authoritative and recursive DNS servers

#!/bin/bash

# Define your domain
domain="yourdomain.com"

# Define DNS data directory
dnsDataDir="/etc/bind"

# Define named.conf.options file path
optionsFile="${dnsDataDir}/named.conf.options"

# Define named.conf.local file path
localFile="${dnsDataDir}/named.conf.local"

# Configure the options file for the recursive server
echo 'options {
    directory "/var/cache/bind";
    recursion yes;  # enables recursive queries
    allow-recursion { any; };  # allows recursive queries from "any" hosts
};' > $optionsFile

# Configure the local file for the authoritative server
echo 'zone "'$domain'" {
    type master;
    file "/etc/bind/db.'$domain'";
};' > $localFile

# Create a basic DB file for the domain
echo '$TTL    604800
@       IN      SOA     ns.'$domain'. root.localhost. (
                              2         ; Serial
                         604800         ; Refresh
                          86400         ; Retry
                        2419200         ; Expire
                         604800 )       ; Negative Cache TTL
; name servers - NS records
    IN      NS      ns.'$domain'.

; name servers - CNAME records
ns.'$domain'.          IN      CNAME   www.'$domain'.

; 192.0.2.0/24 - CNAME records
www.'$domain'.         IN      CNAME   ns.'$domain'.' > "${dnsDataDir}/db.${domain}"

# Restart BIND9 service
service bind9 restart

3. Prevent external access to internal data by design

// named.conf
options {
    directory "/var/named";
};

view "internal" {
    match-clients { 192.168.0.0/24; }; // your network
    zone "example.com" {
        type master;
        file "internal/db.example.com"; // internal zone file
    };
    // additional internal zones go here
};

view "external" {
    match-clients { any; };
    zone "example.com" {
        type master;
        file "external/db.example.com"; // external zone file
    };
    // additional external zones go here
};

4. Have at least Two Internal DNS servers:

On dns1.example.com, your named.conf might look like this:

// named.conf on dns1.example.com
options {
    directory "/var/named";
    allow-transfer { dns2.example.com; }; // allow zone transfers to dns2
};

zone "example.com" {
    type master;
    file "db.example.com"; // zone file
};

And on dns2.example.com, your named.conf might look like this:

// named.conf on dns2.example.com
options {
    directory "/var/named";
};

zone "example.com" {
    type slave;
    masters { dns1.example.com; }; // get zone data from dns1
    file "bak.db.example.com"; // backup zone file
};

5. Point Clients to The Closest DNS Server:

# dhcpd.conf
subnet 192.168.1.0 netmask 255.255.255.0 {
    option domain-name-servers 192.168.1.1; # DNS server for this subnet
    # ... rest of subnet configuration ...
}

subnet 192.168.2.0 netmask 255.255.255.0 {
    option domain-name-servers 192.168.2.1; # DNS server for this subnet
    # ... rest of subnet configuration ...
}

6. Configure Aging and Scavenging of DNS records:

Here’s a basic example of how you might set up a BIND zone file with TTL values:

// db.example.com
$TTL 1h // default TTL is 1 hour
example.com. IN SOA ns.example.com. admin.example.com. (
    2022010101 ; serial number
    1d ; refresh after 1 day
    2h ; retry after 2 hours
    4w ; expire after 4 weeks
    1h ; minimum TTL is 1 hour
)
; other DNS records go here

7. Setup PTR Records:

// named.conf
zone "1.168.192.in-addr.arpa" {
    type master;
    file "db.192.168.1"; // reverse zone file
};

// db.192.168.1
$TTL 1h
@ IN SOA ns.example.com. admin.example.com. (
    2022010101 ; serial number
    1d ; refresh after 1 day
    2h ; retry after 2 hours
    4w ; expire after 4 weeks
    1h ; minimum TTL is 1 hour
)
@ IN NS ns.example.com.
1 IN PTR host1.example.com.
2 IN PTR host2.example.com.

8. Root Hints vs Forwarding:

Root hints are used by default in BIND, if you have a fresh installation of BIND, it will use root hints to resolve DNS queries.

#!/bin/bash
# Start the BIND service
sudo systemctl start named
# Enable the BIND service to start on boot
sudo systemctl enable named

If you want to use forwarders, you’ll need to modify the BIND configuration file (/etc/named.conf or /etc/bind/named.conf.options depending on your Linux distribution).

#!/bin/bash
# Define your forwarder DNS server
FORWARDER="8.8.8.8"

# Add the forwarder to the BIND configuration
echo "forwarders { $FORWARDER; };" | sudo tee -a /etc/named.conf

# Restart the BIND service to apply changes
sudo systemctl restart named

*9. Enable Debug Logging:

#!/bin/bash

# Define the path to the BIND log file
BIND_LOG="/var/log/named/debug.log"

# Add the logging configuration to the BIND configuration
echo "
logging {
    channel debug_log {
        file \"$BIND_LOG\" versions 3 size 5m;
        severity dynamic;
        print-time yes;
    };
    category default { debug_log; };
};" | sudo tee -a /etc/named.conf

# Restart the BIND service to apply changes
sudo systemctl restart named

10. Use CNAME Records for Alias (Instead of A Record):

#!/bin/bash

# Define your domain and the alias
DOMAIN="example.com."
ALIAS="www.example.com."

# Backup the original BIND zone file
sudo cp /var/named/db.$DOMAIN /var/named/db.$DOMAIN.backup

# Add the CNAME record to the BIND zone file
echo "$ALIAS IN CNAME $DOMAIN" | sudo tee -a /var/named/db.$DOMAIN

# Increment the serial number in the zone file
sudo sed -i '/Serial/ s/[0-9]\+/&+1/' /var/named/db.$DOMAIN

# Check the BIND configuration for errors
sudo named-checkconf

# Check the BIND zone file for errors
sudo named-checkzone $DOMAIN /var/named/db.$DOMAIN

# If no errors, restart the BIND service to apply changes
sudo systemctl restart named

11. Best DNS Order on Domain Controllers:

#!/bin/bash

# Define the loopback address and the address of the other domain controller
LOOPBACK_ADDRESS="127.0.0.1"
SECONDARY_DNS="192.168.1.2" # Replace with the IP address of your secondary domain controller

# Define the path to your named.conf file
NAMED_CONF="/etc/bind/named.conf.options"

# Backup the original named.conf file
cp $NAMED_CONF $NAMED_CONF.bak

# Define the new DNS settings
DNS_SETTINGS="
options {
    directory \"/var/cache/bind\";
    recursion yes;
    allow-recursion { any; };
    listen-on { $LOOPBACK_ADDRESS; $SECONDARY_DNS; };
    allow-transfer { none; };

    dnssec-validation auto;
    auth-nxdomain no;    # conform to RFC1035
    listen-on-v6 { any; };
};
"

# Update the named.conf file with the new DNS settings
echo "$DNS_SETTINGS" > $NAMED_CONF

# Restart the BIND service to apply the changes
service bind9 restart

12. Domain-joined Computers Should Only Use Internal DNS Servers:

#!/bin/bash

# Define the IP address of your internal DNS server
INTERNAL_DNS="192.168.1.1"

# Backup the original resolv.conf file
sudo cp /etc/resolv.conf /etc/resolv.conf.backup

# Clear the resolv.conf file
echo "" | sudo tee /etc/resolv.conf

# Set the internal DNS server
echo "nameserver $INTERNAL_DNS" | sudo tee -a /etc/resolv.conf

13. Use Anycast and Load-balancing:

#!/bin/bash

# Define the IP address of your Anycast network
ANYCAST_IP="10.0.0.1"

# Define the network interface you want to apply the Anycast IP to
INTERFACE="eth0"

# Define the path to your BIND configuration file
BIND_CONF="/etc/bind/named.conf.options"

# Backup the original BIND configuration file
sudo cp $BIND_CONF $BIND_CONF.backup

# Clear the BIND configuration file
echo "" | sudo tee $BIND_CONF

# Set the BIND configuration for Anycast
echo "options {
    listen-on { $ANYCAST_IP; };
    listen-on-v6 { none; };
};" | sudo tee -a $BIND_CONF

# Restart BIND
sudo systemctl restart bind9

# Install keepalived
sudo apt-get install keepalived

# Define the path to your keepalived configuration file
KEEPALIVED_CONF="/etc/keepalived/keepalived.conf"

# Backup the original keepalived configuration file
sudo cp $KEEPALIVED_CONF $KEEPALIVED_CONF.backup

# Clear the keepalived configuration file
echo "" | sudo tee $KEEPALIVED_CONF

# Set the keepalived configuration for Anycast and Load Balancing
echo "vrrp_instance VI_1 {
    state MASTER
    interface $INTERFACE
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        $ANYCAST_IP
    }
}" | sudo tee -a $KEEPALIVED_CONF

# Restart keepalived
sudo systemctl restart keepalived

14. Implement Unified change management:

#!/bin/bash

# Path to your zone file
ZONEFILE="/etc/bind/db.yourdomain.com"

# Function to add a DNS record
add_dns_record() {
    echo "$1 IN A $2" >> $ZONEFILE
    rndc reload
}

# Function to delete a DNS record
delete_dns_record() {
    sed -i "/^$1/d" $ZONEFILE
    rndc reload
}

# Function to list all DNS records
list_dns_records() {
    cat $ZONEFILE
}

# Check command line arguments and call the appropriate function
if [ "$1" = "add" ]; then
    add_dns_record $2 $3
elif [ "$1" = "delete" ]; then
    delete_dns_record $2
elif [ "$1" = "list" ]; then
    list_dns_records
else
    echo "Usage: $0 {add|delete|list} {hostname} {ip-address}"
fi

15. Enable DNS Logging:

#!/bin/bash

# Define the path to the named.conf file
named_conf="/etc/named.conf"

# Define the logging clause
logging_clause="
logging {
    channel simple_log {
        file "/var/log/named/bind.log" versions 3 size 5m;
        severity dynamic;
        print-time yes;
        print-severity yes;
        print-category yes;
    };
    category default {
        simple_log;
    };
};"

# Backup the original named.conf file
cp $named_conf $named_conf.bak

# Append the logging clause to the named.conf file
echo "$logging_clause" >> $named_conf

# Restart the BIND service to apply changes
service named restart

16. Lock DNS Cache:

#!/bin/bash

# Define the path to the named.conf file
named_conf="/etc/named.conf"

# Define the options clause
options_clause="
options {
    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\";
    allow-query { any; };
    recursion yes;
    allow-recursion { any; };
    listen-on port 53 { any; };
    allow-transfer { none; };  # This line disables zone transfers
    version \"not currently available\";  # This line hides BIND version
};"

# Backup the original named.conf file
cp $named_conf $named_conf.bak

# Append the options clause to the named.conf file
echo "$options_clause" >> $named_conf

# Restart the BIND service to apply changes
service named restart

17. Filter DNS Requests to Block Malicious Domains:

#!/bin/bash

# Define the path to the named.conf file
named_conf="/etc/named.conf"

# Define the path to the file containing the list of blocked domains
blocked_domains="/etc/named/blockeddomains.conf"

# Define the options clause
options_clause="
options {
    directory \"/var/named\";
    response-policy { zone \"rpz\"; };
};"

# Define the rpz zone clause
rpz_zone_clause="
zone \"rpz\" {
    type master;
    file \"$blocked_domains\";
};"

# Backup the original named.conf file
cp $named_conf $named_conf.bak

# Append the options and rpz zone clauses to the named.conf file
echo "$options_clause" >> $named_conf
echo "$rpz_zone_clause" >> $named_conf

# Restart the BIND service to apply changes
service named restart

Keep the following format for blockeddomains.conf:

maliciousdomain1.com CNAME .
maliciousdomain2.com CNAME .

18. Firewalls should be hardened to close unneeded ports:

#!/bin/bash

# Flush all current rules from iptables
iptables -F

# Allow connections from your internal network
iptables -A INPUT -s 192.168.0.0/16 -j ACCEPT

# Allow connections from localhost
iptables -A INPUT -s 127.0.0.1 -j ACCEPT

# Allow incoming connections on ports that your DNS server needs
iptables -A INPUT -p tcp --dport 53 -j ACCEPT
iptables -A INPUT -p udp --dport 53 -j ACCEPT

# Deny all other incoming connections
iptables -P INPUT DROP

# Allow all outgoing connections
iptables -P OUTPUT ACCEPT

# Save rules
/sbin/service iptables save

19. Disable any queries for domains you don’t own, except from your internal/local machines:

Go to named.conf

acl "trusted" {
    192.168.0.0/16;    # your network
    127.0.0.1;         # localhost
};

options {
    listen-on port 53 { any; };
    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";
    allow-query { trusted; }; # allow queries from "trusted" clients
    recursion yes;
    allow-recursion { trusted; }; # allow recursive queries from "trusted" clients
};

zone "yourdomain.com" IN {
    type master;
    file "yourdomain.com.zone";
    allow-query { any; };
};

20. Allow queries only for your managed domains:

#!/bin/bash

# Define your domain
domain="yourdomain.com"

# Path to named.conf
named_conf="/etc/bind/named.conf.local"

# Check if domain is already in named.conf
if grep -q "\$domain" "\$named_conf"; then
    echo "Domain \$domain is already configured."
else
    # If not, add it
    echo "
zone \"\$domain\" {
    type master;
    file \"/etc/bind/db.\$domain\";
};
" >> "\$named_conf"

    echo "Domain \$domain has been configured."
fi

21. Require multi-factor authentication for access to DNS servers:

#!/bin/bash

# Install Google Authenticator and PAM
sudo apt-get install libpam-google-authenticator

# Run Google Authenticator
google-authenticator

# This will ask you a series of questions. Answer yes (y) to all

# Edit the PAM configuration to enable Google Authenticator
echo "auth required pam_google_authenticator.so" | sudo tee -a /etc/pam.d/sshd

# Edit the SSH configuration to enable ChallengeResponseAuthentication
sudo sed -i 's/#ChallengeResponseAuthentication no/ChallengeResponseAuthentication yes/g' /etc/ssh/sshd_config

# Restart the SSH service to apply the changes
sudo systemctl restart sshd

22. Keep DNS servers patched and up to date:

#!/bin/bash

# Update package lists for upgrades and new package installations
sudo apt-get update

# Upgrade all the installed packages to their latest versions
sudo apt-get upgrade

# Install Livepatch to apply critical kernel patches without rebooting
sudo snap install canonical-livepatch

# Enable Livepatch (replace 'TOKEN' with your Livepatch token)
sudo canonical-livepatch enable TOKEN

# Check that Livepatch is running properly
canonical-livepatch status

23. Uninstall or disable unnecessary applications on DNS servers:

#!/bin/bash

# List all installed packages
dpkg --list

# Uninstall a package
sudo apt-get --purge remove package-name

# Disable a service
sudo systemctl disable service-name

24. Configure Access Control Lists:

#!/bin/bash

# Define the zone
zone="yourdomain.com"

# Define the ACL
acl "trusted" {
    192.0.2.0/24;    # Network 1
    203.0.113.0/24;  # Network 2
    localhost;
};

# Change to the appropriate directory
cd /etc/bind

# Add the ACL to the options file
echo "acl \"trusted\" {" >> /etc/bind/named.conf.options
echo "    192.0.2.0/24;    # Network 1" >> /etc/bind/named.conf.options
echo "    203.0.113.0/24;  # Network 2" >> /etc/bind/named.conf.options
echo "    localhost;" >> /etc/bind/named.conf.options
echo "};" >> /etc/bind/named.conf.options

# Restrict queries to the trusted ACL
echo "allow-query { trusted; };" >> /etc/bind/named.conf.options

# Restart BIND
service bind9 restart

25. Design robust server architecture to improve redundancy and capacity for resilience against failure or DDoS attacks:

options {
    directory "/var/named";
    recursion no;
    
    // Enable rate limiting
    rate-limit {
        responses-per-second 5;  // Limit the number of responses per second
        window 5;  // The size of the window in seconds for rate limiting
    };
};

zone "example.com" in {
    type master;
    file "master/example.com.db";
};

26. DNSSEC Deployment:

#!/bin/bash

# Define your domain
domain="example.com"

# Change to the directory where your zone files are located
cd /etc/bind

# Generate the Key Signing Key (KSK)
dnssec-keygen -a RSASHA256 -b 2048 -n ZONE -f KSK $domain

# Generate the Zone Signing Key (ZSK)
dnssec-keygen -a RSASHA256 -b 1024 -n ZONE $domain

# Include the keys in your zone file
echo "\$INCLUDE K$domain*.key" >> db.$domain

# Sign the zone
dnssec-signzone -A -3 $(head -c 1000 /dev/random | sha1sum | cut -b 1-16) -N INCREMENT -o $domain -t db.$domain

# Reload BIND
rndc reload

# Verify the DNSSEC deployment
dig +dnssec www.$domain

27. DNSSEC Security Components Automation:

#!/bin/bash

# Define your domain
domain="example.com"

# Define the directory where your zone files are located
zone_directory="/etc/bind"

# Define the key directory
key_directory="/etc/bind/keys"

# Change to the key directory
cd $key_directory

# Generate new keys every month
if [ $(date +%m -d tomorrow) != $(date +%m) ]; then
    # Generate the Key Signing Key (KSK)
    dnssec-keygen -a RSASHA256 -b 2048 -n ZONE -f KSK $domain

    # Generate the Zone Signing Key (ZSK)
    dnssec-keygen -a RSASHA256 -b 1024 -n ZONE $domain
fi

# Change to the zone directory
cd $zone_directory

# Include the keys in your zone file
echo "\$INCLUDE $key_directory/K$domain*.key" >> db.$domain

# Sign the zone
dnssec-signzone -A -3 $(head -c 1000 /dev/random | sha1sum | cut -b 1-16) -N INCREMENT -o $domain -t db.$domain

# Reload BIND
rndc reload

# Verify the DNSSEC deployment
dig +dnssec www.$domain

28. Enable DNSSEC to ensure that DNS responses are digitally signed:

#!/bin/bash

# Edit the BIND configuration file
sudo vi /etc/named.conf

# Find and set the following directives:
# dnssec-enable yes;
# dnssec-validation yes;
# dnssec-lookaside auto;

# Save and exit the file

# Restart the BIND service to apply the changes
sudo systemctl restart named

# Test DNSSEC validation
dig . DNSKEY | grep -Ev '^ ($|;)' > root.keys
dig +sigchase +trusted-key=./root.keys . SOA | grep -i validation

29. Validate DNS Data Integrity with DNSSEC:

#!/bin/bash

# Define the zone
zone="yourdomain.com"

# Change to the appropriate directory
cd /etc/bind

# Enable DNSSEC validation
echo "dnssec-validation auto;" >> /etc/bind/named.conf.options

# Define the trusted keys for the zone
echo "trusted-keys {" >> /etc/bind/named.conf.options
echo "    \"$zone\" {" >> /etc/bind/named.conf.options
echo "        // Paste the public KSK for the zone here" >> /etc/bind/named.conf.options
echo "    };" >> /etc/bind/named.conf.options
echo "};" >> /etc/bind/named.conf.options

# Restart BIND
service bind9 restart

Disclaimer

DISCLAIMER: The information and code provided here are intended for educational and informational purposes only. The user assumes full responsibility for the use of this information and code. The provider of this information and code makes no representations or warranties, express or implied, about the completeness, accuracy, reliability, suitability, or availability of the information and code provided. Any reliance you place on such information and any use of this code is therefore strictly at your own risk. In no event will the provider be liable for any loss or damage including without limitation, indirect or consequential loss or damage, arising out of, or in connection with, the use of this information and code.