#!/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" DEFAULT_BIND_CACHE_DIR="/var/cache/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" [[ -n "$BIND_CACHE_DIR" ]] && DEFAULT_BIND_CACHE_DIR="$BIND_CACHE_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_BIND_CACHE_DIR" 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" 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 if [[ -f "$conf_file" ]]; then 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 [[ -z "$CONF_FILE_DIR" ]] && CONF_FILE_DIR="$DEFAULT_CONF_FILE_DIR" 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="${DEFAULT_BIND_CACHE_DIR}" 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 '${ZONE_FILE_SLAVE_DIR}' (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 zone declaration was the last one in file "$ZONES_DECLARATION_FILE" # - if $_found && [[ $_last_line -eq 0 ]]; then _last_line=$line_number _found=false fi 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