diff --git a/bind_remove_domain_on_slave.sh b/bind_remove_domain_on_slave.sh new file mode 100755 index 0000000..97aaa90 --- /dev/null +++ b/bind_remove_domain_on_slave.sh @@ -0,0 +1,670 @@ +#!/usr/bin/env bash + +working_dir="$(dirname $(realpath $0))" +conf_file="${working_dir}/conf/bind.conf" + +log_file="$(mktemp)" + +#--------------------------------------- +#----------------------------- +# Base Function(s) +#----------------------------- +#--------------------------------------- + +usage() { + echo + [ -n "$1" ] && echo -e "Error: $1\n" + + cat< + The name of the domain, which is requested for deletion. + + -h + Prints this help. + + -q + Be quiet. If '-q' is used, also a domain must be given using + parameter '-d'. + +EOF +clean_up 1 +} + + +clean_up() { + + # Perform program exit housekeeping + rm $log_file + exit $1 +} + +trim() { + local var="$*" + var="${var#"${var%%[![:space:]]*}"}" # remove leading whitespace characters + var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters + echo -n "$var" +} + +echononl(){ + if $terminal && $LOGGING ; then + echo X\\c > /tmp/shprompt$$ + if [ `wc -c /tmp/shprompt$$ | awk '{print $1}'` -eq 1 ]; then + echo -e -n "$*\\c" 1>&2 + else + echo -e -n "$*" 1>&2 + fi + rm /tmp/shprompt$$ + fi +} + +fatal(){ + echo "" + if $terminal ; then + echo -e "[ \033[31m\033[1mError\033[m ]: $*" + echo "" + echo -e "\t\033[31m\033[1mScript was interupted\033[m!" + else + echo " [ Fatal ]: $*" + echo "" + echo " Script was terminated...." + fi + echo "" + clean_up 1 +} + +info (){ + if $terminal && $LOGGING ; then + echo "" + echo -e "\t[ \033[32m\033[1mInfo\033[m ]: $*" + echo "" + else + if $LOGGING ; then + echo "" + echo "Info: $*" + echo "" + fi + fi +} + +warn (){ + echo "" + if $terminal ; then + echo -e "\t[ \033[33m\033[1mWarning\033[m ]: $*" + else + echo "Warning: $*" + fi + echo "" +} + +error (){ + echo "" + if $terminal ; then + echo -e "\t[ \033[31m\033[1mError\033[m ]: $*" + else + echo "Error: $*" + fi + echo "" +} + +echo_done() { + if $terminal && $LOGGING ; then + echo -e "\033[75G[ \033[32mdone\033[m ]" + else + if $LOGGING ; then + echo " [ done ]" + fi + fi +} +echo_ok() { + if $terminal && $LOGGING ; then + echo -e "\033[75G[ \033[32mok\033[m ]" + else + if $LOGGING ; then + echo " [ ok ]" + fi + fi +} +echo_failed(){ + if $terminal && $LOGGING ; then + echo -e "\033[75G[ \033[1;31mfailed\033[m ]" + else + if $LOGGING ; then + echo " [ failed ]" + fi + fi +} +echo_skipped() { + if $terminal && $LOGGING ; then + echo -e "\033[75G[ \033[33m\033[1mskipped\033[m ]" + else + if $LOGGING ; then + echo " [ skipped ]" + fi + fi +} + +trap clean_up SIGHUP SIGINT SIGTERM + + + +#--------------------------------------- +#----------------------------- +# Check some prerequisites +#----------------------------- +#--------------------------------------- + +if [[ -t 1 ]] ; then + terminal=true + LOGGING=true +else + terminal=false + LOGGING=false +fi + +while getopts d:hq opt ; do + case $opt in + d) DOMAIN_REQUESTED_TO_REMOVE="$OPTARG" + ;; + q) LOGGING=false + ;; + h) usage + ;; + *) usage + esac +done + +shift $(expr $OPTIND - 1) + +# - Parameter "check" can be used, to test whether this script +# - is accessable (e.g. from a script on a remote host) +# - +if [[ "$1" = "check" ]]; then + info "Script \033[1m$(basename $0)\033[m was successfully invoked, but its only a test." + clean_up 0 +fi + + +if ! $LOGGING && [[ -z "$DOMAIN_REQUESTED_TO_REMOVE" ]] ; then + usage "Giving Domain for deletion (option '-d') is required if using option '-q'." +fi + + + +#--------------------------------------- +#----------------------------- +# Setting Defaults +#----------------------------- +#--------------------------------------- + +DEFAULT_CONF_FILE_DIR="/etc/bind" + + +#--------------------------------------- +#----------------------------- +# Load default values from bind.conf +# +# Overwrites the settings above +# +#----------------------------- +#--------------------------------------- + +if $LOGGING ; then + clear + echo "" + echo "" + echononl " Loading default Configuration values from $(basename ${conf_file}).." + if [[ ! -f "$conf_file" ]]; then + echo_skipped + else + source "${conf_file}" > $log_file 2>&1 + if [[ $? -eq 0 ]]; then + echo_ok + else + echo_failed + fatal "$(cat $log_file)" + fi + fi + + [[ -n "$CONF_FILE_DIR" ]] && DEFAULT_CONF_FILE_DIR="$CONF_FILE_DIR" + if [[ -n "$ZONE_FILE_MASTER_DIR" ]] ; then + DEFAULT_ZONE_FILE_MASTER_DIR="$ZONE_FILE_MASTER_DIR" + else + DEFAULT_ZONE_FILE_MASTER_DIR="${DEFAULT_CONF_FILE_DIR}/master" + fi + if [[ -n "$ZONE_FILE_SLAVE_DIR" ]] ; then + DEFAULT_ZONE_FILE_SLAVE_DIR="$ZONE_FILE_SLAVE_DIR" + else + DEFAULT_ZONE_FILE_SLAVE_DIR="${DEFAULT_CONF_FILE_DIR}/slave" + fi + [[ -n "$ZONES_DECLARATION_FILE" ]] && DEFAULT_ZONES_DECLARATION_FILE="$ZONES_DECLARATION_FILE" + + + echo "" + + + if [[ -z "$DOMAIN_REQUESTED_TO_REMOVE" ]] ;then + echo "" + echo -e "\033[32m--\033[m" + echo "" + echo "Insert domain which you want to be removed from bind nameservice." + echo "" + DOMAIN_REQUESTED_TO_REMOVE="" + echononl "Remove Domain: " + read DOMAIN_REQUESTED_TO_REMOVE + while [ "X$DOMAIN_REQUESTED_TO_REMOVE" = "X" ] ; do + echo -e "\n\t\033[33m\033[1mSetting 'Remove Domain' is required!\033[m\n" + echononl "Remove Domain: " + read DOMAIN_REQUESTED_TO_REMOVE + done + fi + + + echo "" + echo "" + echo -e "\033[32m--\033[m" + echo "Common parameters" + echo -e "\033[32m--\033[m" + + + echo "" + echo "Insert directory containing the bind configuration files." + echo "" + CONF_FILE_DIR="" + if [[ -n "$DEFAULT_CONF_FILE_DIR" ]] ; then + echononl "Bind Configuration Directory [${DEFAULT_CONF_FILE_DIR}]: " + read CONF_FILE_DIR + if [[ "X$CONF_FILE_DIR" = "X" ]]; then + CONF_FILE_DIR="$DEFAULT_CONF_FILE_DIR" + fi + else + echononl "Bind Configuration Directory: " + read CONF_FILE_DIR + while [ "X$CONF_FILE_DIR" = "X" ] ; do + echo -e "\n\t\033[33m\033[1mSetting 'Bind Configuration Directory' is required!\033[m\n" + echononl "Bind Configuration Directory: " + read CONF_FILE_DIR + done + fi + + [[ -n "$DEFAULT_ZONES_DECLARATION_FILE" ]] || DEFAULT_ZONES_DECLARATION_FILE="${CONF_FILE_DIR}/named.conf.local" + [[ -n "$ZONE_FILE_MASTER_DIR" ]] || ZONE_FILE_MASTER_DIR="${CONF_FILE_DIR}/master" + [[ -n "$ZONE_FILE_SLAVE_DIR" ]] || ZONE_FILE_SLAVE_DIR="${CONF_FILE_DIR}/slave" + + + echo "" + echo -e "\033[32m--\033[m" + + echo "" + echo "Insert zones declaration file." + echo "" + ZONES_DECLARATION_FILE="" + if [[ -n "$DEFAULT_ZONES_DECLARATION_FILE" ]] ; then + echononl "Zones Declaration File [${DEFAULT_ZONES_DECLARATION_FILE}]: " + read ZONES_DECLARATION_FILE + if [[ "X$ZONES_DECLARATION_FILE" = "X" ]]; then + ZONES_DECLARATION_FILE="$DEFAULT_ZONES_DECLARATION_FILE" + fi + else + echononl "Zones Declaration File: " + read ZONES_DECLARATION_FILE + while [ "X$ZONES_DECLARATION_FILE" = "X" ] ; do + echo -e "\n\t\033[33m\033[1mSetting 'Zones Declaration File' is required!\033[m\n" + echononl "Zones Declaration File: " + read ZONES_DECLARATION_FILE + done + fi + + echo "" + echo -e "\033[32m--\033[m" + + echo "" + echo "Insert the directory, where your slave zone-files resides." + echo "" + echo "" + ZONE_FILE_SLAVE_DIR="" + if [[ -n "$DEFAULT_ZONE_FILE_SLAVE_DIR" ]] ; then + echononl "Zone File Directory (slave) [${DEFAULT_ZONE_FILE_SLAVE_DIR}]: " + read ZONE_FILE_SLAVE_DIR + if [[ "X$ZONE_FILE_SLAVE_DIR" = "X" ]]; then + ZONE_FILE_SLAVE_DIR="$DEFAULT_ZONE_FILE_SLAVE_DIR" + fi + else + echononl "Zone File Directory (slave): " + read ZONE_FILE_SLAVE_DIR + while [ "X$ZONE_FILE_SLAVE_DIR" = "X" ] ; do + echo -e "\n\t\033[33m\033[1mSetting 'Zone File Directory (master)' is required!\033[m\n" + echononl "Zone File Directory (slave): " + read ZONE_FILE_SLAVE_DIR + done + fi + + + + echo "" + echo "" + echo -e "\033[1;32mSettings for \033[1;37mRemove Domain\033[m Script" + echo "" + echo -e "\tDomain requested to remove..........: $DOMAIN_REQUESTED_TO_REMOVE" + echo "" + echo -e "\tBind Configuration Directory........: $CONF_FILE_DIR" + echo -e "\tZones Declaration File..............: $ZONES_DECLARATION_FILE" + echo -e "\tZone File Directory (slave).........: $ZONE_FILE_SLAVE_DIR" + + echo "" + info "Remove Domain \033[37m\033[1m${DOMAIN_REQUESTED_TO_REMOVE}\033[m.." + echo -n "To continue type uppercase 'YES': " + read OK + echo "" + if [[ "$OK" != "YES" ]] ; then + fatal "Abort by user request - Answer as not 'YES'" + fi + +else # if $LOGGING + + if [[ ! -f "$conf_file" ]]; then + fatal "Configuration file '$conf_file' not found!" + else + echononl " Loading default Configuration values from $(basename ${conf_file}).." + source "${conf_file}" > $log_file 2>&1 + if [[ $? -eq 0 ]]; then + echo_ok + else + echo_failed + fatal "$(cat $log_file)" + fi + fi + + if [[ -z "$CONF_FILE_DIR" ]]; then + fatal "Directory contaning bind configurations not set (see CONF_FILE_DIR)!" + fi + + [[ -n "$ZONES_DECLARATION_FILE" ]] || ZONES_DECLARATION_FILE="${CONF_FILE_DIR}/named.conf.local" + [[ -n "$ZONE_FILE_MASTER_DIR" ]] || ZONE_FILE_MASTER_DIR="${CONF_FILE_DIR}/master" + [[ -n "$ZONE_FILE_SLAVE_DIR" ]] || ZONE_FILE_SLAVE_DIR="${CONF_FILE_DIR}/slave" + +fi + +if [[ ! -f "$ZONES_DECLARATION_FILE" ]]; then + fatal "Zone declaration file '${ZONES_DECLARATION_FILE}' not found!" +fi + +if [[ ! -d "$ZONE_FILE_SLAVE_DIR" ]]; then + fatal "Zone File Directory (slave zones) not found!" +fi + +if ! grep -q -E "^\s*zone\s+\"?${DOMAIN_REQUESTED_TO_REMOVE}\"?\s+\{" $ZONES_DECLARATION_FILE 2> /dev/null ; then + fatal "No decleration for domain '${DOMAIN_REQUESTED_TO_REMOVE}' found!" +fi + +backup_date=$(date +%Y-%m-%d-%H%M) + +echononl " Backup '$ZONES_DECLARATION_FILE'.." +if [[ -f "${ZONES_DECLARATION_FILE}.$backup_date" ]] ; then + echo_skipped +else + cp -a "$ZONES_DECLARATION_FILE" "${ZONES_DECLARATION_FILE}.$backup_date" > $log_file 2>&1 + if [[ $? -gt 0 ]]; then + echo_failed + error "$(cat $log_file)" + else + echo_ok + fi +fi + +echononl " Backup directory '${ZONE_FILE_SLAVE_DIR}'.." +if [[ -d "${ZONE_FILE_SLAVE_DIR}.${backup_date}" ]] ; then + echo_skipped +else + cp -a "${ZONE_FILE_SLAVE_DIR}" "${ZONE_FILE_SLAVE_DIR}.${backup_date}" > $log_file 2>&1 + if [[ $? -eq 0 ]]; then + echo_ok + else + echo_failed + fatal "$(cat $log_file)" + fi +fi + + +declare -i line_number=0 + +_found=false +_is_slave=false +declare -i _first_line=0 +declare -i _last_line=0 +while IFS='' read -r _line || [[ -n $_line ]] ; do + let line_number++ + if [[ "$_line" =~ ^[[:space:]]*zone[[:space:]]+\"?${DOMAIN_REQUESTED_TO_REMOVE}\"?[[:space:]]+\{ ]]; then + _found=true + _first_line=$line_number + fi + if $_found ; then + if [[ "$_line" =~ ^[[:space:]]*file[[:space:]]+\"? ]]; then + zone_file="$(echo $_line | awk '{print$2}')" + shopt -s extglob + if [[ "$zone_file" =~ \;$ ]]; then + zone_file=${zone_file%%*(;)} + fi + if [[ "$zone_file" =~ ^\" ]]; then + zone_file=${zone_file##*(\")} + zone_file=${zone_file%%*(\")} + fi + shopt -u extglob + fi + if [[ "$_line" =~ type[[:space:]]+slave ]]; then + _is_slave=true + fi + if $_is_slave && [[ "$_line" =~ ^[[:space:]]*zone[[:space:]]+\"? ]]; then + _found=false + _last_line=$((line_number - 1)) + fi + fi + if [[ $_last_line -gt 0 ]] && $_is_slave ; then + break; + fi + +done < "$ZONES_DECLARATION_FILE" + +if $_found ; then + fatal "Configuration for zone '${DOMAIN_REQUESTED_TO_REMOVE}' was found, but cannot be deleted." +fi + + +$LOGGING && echo "" +echononl " Delete zone declaration for domain '${DOMAIN_REQUESTED_TO_REMOVE}'" +sed -i "${_first_line},${_last_line}d" "$ZONES_DECLARATION_FILE" > $log_file 2>&1 +if [[ $? -gt 0 ]]; then + echo_failed + error "$(cat $log_file)" +else + echo_ok +fi + +$LOGGING && echo "" +echononl " Create directory '$(dirname ${zone_file})/DELETED'.." +if [[ ! -d "$(dirname ${zone_file})/DELETED" ]] ; then + mkdir "$(dirname ${zone_file})/DELETED" > $log_file 2>&1 + if [[ $? -gt 0 ]]; then + echo_failed + error "$(cat $log_file)" + else + echo_ok + fi +else + echo_skipped +fi + +echononl " Move zone file '$(basename $zone_file)' into directory 'DELETED'" +if [[ ! -f "$zone_file" ]] ; then + echo_failed + error "Concerning zone file '$zone_file' not found!" +else + mv "${zone_file}" "$(dirname ${zone_file})/DELETED" > $log_file 2>&1 + if [[ $? -gt 0 ]]; then + echo_failed + error "$(cat $log_file)" + else + echo_ok + fi +fi + +while IFS='' read -r -d '' _file ; do + echononl " Move file '$(basename $_file)' into directory 'DELETED'" + mv "$_file" "$(dirname ${zone_file})/DELETED" > $log_file 2>&1 + if [[ $? -gt 0 ]]; then + echo_failed + #error "$(cat $log_file)" + else + echo_ok + fi +done < <(find $(dirname ${zone_file}) -mindepth 1 -maxdepth 1 -type f -name "${DOMAIN_REQUESTED_TO_REMOVE}.*" -print0) + + +if [[ -n "$key_directory" ]]; then + + $LOGGING && echo "" + + if [[ "$(dirname ${key_directory})" != "$CONF_FILE_DIR" ]]; then + backup_key_dir="$(dirname ${key_directory})" + echononl " Backup directory '${backup_key_dir}'.." + cp -a "${backup_key_dir}" "${backup_key_dir}.${backup_date}" > $log_file 2>&1 + if [[ $? -eq 0 ]]; then + echo_ok + else + echo_failed + fatal "$(cat $log_file)" + fi + fi + + _dir="$(dirname ${key_directory})/DELETED" + echononl " Create directory '${_dir}'.." + if [[ ! -d "${_dir}" ]] ; then + mkdir "${_dir}" > $log_file 2>&1 + if [[ $? -gt 0 ]]; then + echo_failed + error "$(cat $log_file)" + else + echo_ok + fi + else + echo_skipped + fi + + _dir="$(dirname ${key_directory})/DELETED/$(basename ${key_directory})" + echononl " Create directory '${_dir}'.." + if [[ ! -d "${_dir}" ]] ; then + mkdir "${_dir}" > $log_file 2>&1 + if [[ $? -gt 0 ]]; then + echo_failed + error "$(cat $log_file)" + else + echo_ok + fi + else + echo_skipped + fi + + while IFS='' read -r -d '' _file ; do + echononl " Move file '$(basename $_file)' into directory 'DELETED'" + mv "$_file" "$(dirname ${key_directory})/DELETED/$(basename ${key_directory})" > $log_file 2>&1 + if [[ $? -gt 0 ]]; then + echo_failed + error "$(cat $log_file)" + else + echo_ok + fi + done < <(find $key_directory -mindepth 1 -maxdepth 1 -type f -name "K${DOMAIN_REQUESTED_TO_REMOVE}.*" -print0) + + if [[ ! "$(ls -A $key_directory)" ]] ; then + echononl " Remove empty key directory '$(basename $key_directory)'.." + rmdir $key_directory > $log_file 2>&1 + if [[ $? -gt 0 ]]; then + echo_failed + error "$(cat $log_file)" + else + echo_ok + fi + fi +fi + + +if [[ -f "${ZONES_DECLARATION_FILE}.$backup_date" ]]; then + diff "$ZONES_DECLARATION_FILE" "${ZONES_DECLARATION_FILE}.$backup_date" > /dev/null 2>&1 + if [[ $? -eq 0 ]]; then + info "Zone declaration file $(basename $ZONES_DECLARATION_FILE) has not changed.\n\t Removing previously created backup now." + echononl "\tDelete '${ZONES_DECLARATION_FILE}.$backup_date'.." + rm "${ZONES_DECLARATION_FILE}.$backup_date" > $log_file 2>&1 + if [[ $? -eq 0 ]]; then + echo_ok + else + echo_failed + fi + fi +fi + + +if [[ -d "${ZONE_FILE_MASTER_DIR}.${backup_date}" ]] ; then + diff -Nur "${ZONE_FILE_MASTER_DIR}" "${ZONE_FILE_MASTER_DIR}.${backup_date}" > /dev/null 2>&1 + if [[ $? -eq 0 ]]; then + info "No zone file has changed.\n\t Removing previously created backup." + echononl "\tDelete '${ZONE_FILE_MASTER_DIR}.${backup_date}'.." + rm -rf "${ZONE_FILE_MASTER_DIR}.${backup_date}" > $log_file 2>&1 + if [[ $? -eq 0 ]]; then + echo_ok + else + echo_failed + error "$(cat $log_file)" + fi + fi +fi + +if [[ -d "${backup_key_dir}.${backup_date}" ]] ; then + diff -Nur "${backup_key_dir}" "${backup_key_dir}.${backup_date}" > /dev/null 2>&1 + if [[ $? -eq 0 ]]; then + info "Key directory '${backup_key_dir}' has not changed.\n\t Removing previously created backup now." + echononl "\tDelete '${backup_key_dir}.${backup_date}'.." + rm -rf "${backup_key_dir}.${backup_date}" > $log_file 2>&1 + if [[ $? -eq 0 ]]; then + echo_ok + else + echo_failed + error "$(cat $log_file)" + fi + fi +fi + + + +$LOGGING && echo "" + +echononl " Reeload bind configuration" +rndc reconfig > $log_file 2>&1 +if [[ $? -gt 0 ]]; then + echo_failed + error "$(cat $log_file)" +else + echo_done +fi + + +#echo "zone file: $zone_file" +#echo "$line_number - $_first_line , $_last_line" + + +$LOGGING && echo "" +clean_up 0 diff --git a/conf/bind.conf.sample b/conf/bind.conf.sample index 65fdcc7..8bc6359 100644 --- a/conf/bind.conf.sample +++ b/conf/bind.conf.sample @@ -27,8 +27,10 @@ # - Directory containing bind configuration files # - # - This parameter MUST be set. +# - +# - Example: CONF_FILE_DIR="/etc/bind" # - -#CONF_FILE_DIR="/etc/bind" +CONF_FILE_DIR="" # - ZONE_FILE_MASTER_DIR