#!/bin/bash
#< Script to parse a basic named.conf file, and convert from master to slave configuration
# This script is part of my DNS named.conf transfer scripts. The scripts
# are designed to be used for the transferral of a frequently changing
# named.conf file from a primary nameserver to a secondary nameserver.
# The scripts assume a lot. The zone files used in my test environment
# were very "bare-bones" and simple. Example:
# Any additional configuration options present in the file would
# require script modifications (sync_to_slave.sh) to accomodate parsing
# the other configuration options. This script is designed to be easily
# modified, and should be considered a template for named.conf transfers.
# The scripts revolve around a central lock file mechanism, which aims to
# ensure that no incomplete named.conf files are transferred whilst they are
# being edited - although it will not parse a file for syntactical correctness.
# Also, this assumes that all edits to the named.conf file are made using the
# vinamed wrapper, or a custom tool that uses the lockfile mechanism used in
# these scripts.
# The scripts provided are:
# vinamed Lock file protected named.conf editing wrapper
# sync_to_slave.sh Intended to be scheduled via cron on the
# primary nameserver, BEFORE the script below
# runs on the slave nameserver.
# install_slave_config.sh Schedule this to run a few minutes after
# the sync_to_slave.sh script runs on the
# primary nameserver. This script contains
# various checks (lockfile, confirms whether
# the newly transferred named.conf file is
# modified, etc.) This script also creates
# backups of named.conf prior to, and after
# modification. Then it restarts BIND.
# Example cron jobs (depending on the frequency of your named.conf file
# edits).
# master# crontab -l | grep sync_to_slave
# 0,30 * * * * /usr/local/dns/bin/sync_to_slave.sh
# slave# crontab -l | grep install_slave_config
# 15,45 * * * * /usr/local/dns/bin/install_slave_config.sh
# You will also need to check the paths presented in the scripts, and ensure
# that the appropriate backup directories are created, or the paths
# referenced in the scripts are changed.
# For the key-based file transfer to work, I'm using a "namesync" user on each
# server.
# Executable paths
AWK="/usr/bin/awk"
CHMOD="/bin/chmod"
CHOWN="/bin/chown"
CP="/bin/cp"
DATE="/bin/date"
ECHO="/bin/echo"
ID="/usr/bin/id"
MV="/bin/mv"
RM="/bin/rm"
SCP="/usr/bin/scp"
SED="/usr/bin/sed"
TEE="/usr/bin/tee"
# Configuration and Temporary Files
NAMED_CONF="/etc/named.conf"
# Output Directory
NAMESYNC_HOME="/home/namesync"
DESTINATION="ns1.dnstest.com"
IDENTITY="${NAMESYNC_HOME}/.ssh/id_dsa"
OUTPUT_DIR="${NAMESYNC_HOME}/named.xfer"
OUTPUT_FILE="named.conf.$( ${DATE} +%Y%m%d ).$$"
LOCKFILE="/var/lock/vinamed.lock"
# Errors
SUCCESS="0"
ENOTROOT="1"
ENODIR="1"
ELOCKFILE="1"
# Function: print_error
# Arguments: $@
# Returns: Nothing
# Description: echo wrapper to output to STDERR
function print_error {
${ECHO} "Error: $@" >&2
}
# Function: print_msg
# Arguments: $@
# Returns: Nothing
# Description: echo wrapper to output to STDOUT with prefix
function print_msg {
${ECHO} "--> $@"
}
# Function: check_root_user
# Arguments: None
# Returns: Nothing - will exit on failure
# Description: Checks whether the script is being executed as root user
function check_root_user {
WHOAMI=$( ${ID} -u )
if [ "${WHOAMI}" -ne "0" ]; then
print_error "You must be root to run this program"
exit ${ENOTROOT}
fi
}
# Function: check_output_dir
# Arguments: None
# Returns: Nothing - will exit on failure
# Description: Checks to ensure that the output directory exists
function check_output_dir {
if [ ! -d "${OUTPUT_DIR}" ]; then
print_error "OUTPUT_DIR: ${OUTPUT_DIR} unavailable"
exit ${ENODIR}
fi
}
# Function: check_lockfile
# Arguments: None
# Returns: Nothing - exits on failure
# Description: Exits if the lockfile exists
function check_lockfile {
if [ -e "${LOCKFILE}" ]; then
print_error "Lockfile exists - is ${NAMED_CONF} being edited?"
exit ${ELOCKFILE}
fi
}
# Function: process_conf_file
# Arguments: None
# Returns: Nothing
# Description: Parses the named.conf file and converts it from a master
# to a slave configuration
function process_conf_file {
print_msg "Converting master named.conf to slave configuration"
${SED} -e '/^zone/,/};/ {
/0\.0\.127\.in-addr\.arpa/,/};/ {
b
}
s/type master/type slave/
}' -e 's!// ns0!// ns1!' -e 's!// master!// slave! ' ${NAMED_CONF} | ${AWK} '{
if ( $0 ~ /^[ ]*file/ &&
$0 !~ /^[ ]*file \"127\.0\.0\.zone\"/ &&
$0 !~ /^[ ]*file \"root.hint\"/ ) {
printf( "%s\n masters { 192.168.0.130; };\n", $0 )
} else if ( $0 ~ /^[ ]*allow-transfer / ) {
next
} else {
printf( "%s\n", $0 )
}
}' | ${TEE} ${OUTPUT_DIR}/${OUTPUT_FILE}
}
# Function: transfer_conf_file
# Arguments: None
# Returns: Nothing
# Description: Transfers the newly generated slave named.conf file over to the secondary
# nameserver via scp using the "namesync" user
function transfer_conf_file {
print_msg "Transferring named.conf to staging area on ${DESTINATION}"
${SCP} -i ${IDENTITY} ${OUTPUT_DIR}/${OUTPUT_FILE} namesync@${DESTINATION}:${OUTPUT_DIR}
}
#
# main
#
#
check_root_user
check_lockfile
process_conf_file
transfer_conf_file
exit ${SUCCESS}