From c1421521bb71fa6e67ed1521a57e5d464b856329 Mon Sep 17 00:00:00 2001 From: Christoph Date: Fri, 4 Jan 2019 04:53:21 +0100 Subject: [PATCH] Add script 'bind_create_dkim_delegation.sh' --- bind_create_dkim_delegation.sh | 521 +++++++++++++++++++++++++++++++++ 1 file changed, 521 insertions(+) create mode 100755 bind_create_dkim_delegation.sh diff --git a/bind_create_dkim_delegation.sh b/bind_create_dkim_delegation.sh new file mode 100755 index 0000000..ee38a4e --- /dev/null +++ b/bind_create_dkim_delegation.sh @@ -0,0 +1,521 @@ +#!/usr/bin/env bash + +# - Adds DKIM subdomain delegation for a given domain +# - +# - Return (Exit) Codes: +# - success: +# - 0: DKIM subdomain delegation already exists +# - 1: DKIM subdomain delegation added +# - error: +# - 11: No zonefile found +# - 15: Hostname/Domain not supported +# - 16: Determin Nameservers failed +# - 21: Adding Record failed +# - 99: Fatal error +# - +# - Example: +# - bind_create_dkim_delegation.sh oopen.de + +script_name="$(basename $(realpath $0))" +working_dir="$(dirname $(realpath $0))" + +conf_file="${working_dir}/conf/bind.conf" + +log_file="$(mktemp)" + +backup_date="$(date +%Y-%m-%d-%H%M)" + +# ---------- +# Setting Defaults +# ---------- + +DEFAULT_CONF_FILE_DIR="/etc/bind" +DEFAULT_BIND_USER="bind" +DEFAULT_BIND_GROUP="bind" + + +# ********** +# Don't make changes after this +# ********** + + +# ---------- +# Base Function(s) +# ---------- + +usage() { + + + [[ -n "$1" ]] && error "$1" + + + [[ $verbose ]] && echo -e " +\033[1mUsage:\033[m + + $(basename $0) [Options] | check + +\033[1mDescription\033[m + + Scripts add a nameserver delegation for zone _domainkey.. The nameserver + for the new zone are the same as for the domain itself. + +\033[1mReturn (Exit) Codes\033[m + + success: + 0: DKIM subdomain delegation already exists + 1: DKIM subdomain delegation added + + error: + 11: No zonefile found + 15: Hostname/Domain not supported + 16: Determin Nameservers failed + 21: Adding Record failed + 99: Fatal error + +\033[1mOptions\033[m + + -h + Prints this help. + + -q + Runs in silent mode. + +\033[1mFiles\033[m + + $conf_file: Configuration file + +\033[1mExample:\033[m + + Create DKIM delegation for domain oopen.de. + + \033[1m$(basename $0) oopen.de\033[m + + This results in NS Records like: + + _domainkey.oopen.de. IN NS name-server-1 + _domainkey.oopen.de. IN NS name-server-2 + +" + + clean_up 1 + +} + + +clean_up() { + + # Perform program exit housekeeping + rm $log_file + blank_line + exit $1 +} + +echononl(){ + if $verbose ; 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 +} + +warn (){ + if $verbose ; then + echo "" + echo -e " [ \033[33m\033[1mWarning\033[m ]: $*" + echo "" + fi +} + +info (){ + if $verbose ; then + echo "" + echo -e " [ \033[32m\033[1mInfo\033[m ]: $*" + echo "" + fi +} + +error(){ + if $verbose ; then + echo "" + echo -e " [ \033[31m\033[1mFehler\033[m ]: $*" + echo "" + fi +} + +echo_ok() { + if $verbose ; then + echo -e "\033[75G[ \033[32mok\033[m ]" + fi +} +echo_failed(){ + if $verbose ; then + echo -e "\033[75G[ \033[1;31mfailed\033[m ]" + fi +} +echo_skipped() { + if $verbose ; then + echo -e "\033[75G[ \033[33m\033[1mskipped\033[m ]" + fi +} + +backup_dir () { + dir_to_backup=$1 + echononl "Backup existing directory \"$dir_to_backup\" .." + if [[ -d "$dir_to_backup" ]] ; then + cp -a "$dir_to_backup" "${dir_to_backup}.$backup_date" > $log_file 2>&1 + if [[ $? -eq 0 ]]; then + echo_ok + else + echo_failed + error "Backup directory \"$dir_to_backup\" failed!" + clean_up 99 + fi + else + echo_failed + error "Directory \"$dir_to_backup\" not found. No Backup written!" + clean_up 99 + fi + +} + +blank_line() { + if $verbose ; then + echo "" + fi +} + +trim() { + local var="$*" + var="${var#"${var%%[![:space:]]*}"}" # remove leading whitespace characters + var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters + echo -n "$var" +} + + +# ---------- +# - Jobhandling +# ---------- + +# - Run 'clean_up' for signals SIGHUP SIGINT SIGTERM +# - +trap clean_up SIGHUP SIGINT SIGTERM + + +# ---------- +# - Some checks .. +# ---------- + +# - Running in a terminal? +# - +if [[ -t 1 ]] ; then + verbose=true +else + verbose=false +fi + +# -Is systemd supported on this system? +# - +systemd_supported=false +systemd=$(which systemd) +systemctl=$(which systemctl) + +if [[ -n "$systemd" ]] && [[ -n "$systemctl" ]] ; then + systemd_supported=true +fi + + +# - Print help? +# - +if [[ "$(trim $*)" = " -h" ]] || [[ "$(trim $*)" = " --help" ]] ; then + usage +fi + +if [[ -z "$(which basename)" ]]; then + fatal 'It seems "basename" is not installed, but needed!' +fi + +if [[ -z "$(which realpath)" ]]; then + fatal 'It seems "realpath" is not installed, but needed!' +fi + + +# ========== +# - Begin Main Script +# ========== + +# ---------- +# - Headline +# ---------- + +if $terminal ; then + echo "" + echo -e "\033[1m----------\033[m" + echo -e "\033[32m\033[1mRunning script \033[m\033[1m$script_name\033[32m .. \033[m" + echo -e "\033[1m----------\033[m" +fi + + +# ---------- +# - Read commandline parameter +# ---------- + +while getopts bh opt ; do + case $opt in + q) verbose=true + ;; + h) usage + ;; + \?) usage + ;; + *) ;; + esac +done + +#shift $(expr $OPTIND - 1) +#[[ $# -eq "1" ]] || usage "Wrong number of arguments!" + + +if [[ "$1" = "check" ]]; then + info "Script \033[1m$(basename $0)\033[m was successfully invoked, but its only a test." + clean_up 0 +fi + +dkim_domain="$1" + + +# ---------- +# Read Configurations from $conf_file +# ---------- + +blank_line +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" ]] || CONF_FILE_DIR="$DEFAULT_CONF_FILE_DIR" +[[ -n "$ZONES_DECLARATION_FILE" ]] || ZONES_DECLARATION_FILE="${CONF_FILE_DIR}/named.conf.local" +[[ -n "$BIND_USER" ]] || BIND_USER="$DEFAULT_BIND_USER" +[[ -n "$BIND_GROUP" ]] || BIND_GROUP="$DEFAULT_BIND_GROUP" + + +# - Determin zone (domain) +# - +blank_line +echononl "Determine zone for '$dkim_domain'" +_failed=false +_hostname=$dkim_domain +_tmp_hostname=$(echo ${_hostname//\./\\.}) +while ! grep -e "$_tmp_hostname" $ZONES_DECLARATION_FILE > /dev/null 2>&1 ; do + _hostname=${_hostname#*.} + _tmp_hostname=$(echo ${_hostname//\./\\.}) + if [[ ! $_tmp_hostname =~ \. ]]; then + _failed=true + break + fi +done + +if $_failed ; then + echo_failed + error "Given hostname/domain \"$dkim_domain\" not supported by this nameserver!" + exit 15 +else + echo_ok + domain=$_hostname +fi + + +# - Determine zonefile (by reading bind configuration) +# - +echononl "Determine zonefile (by reading bind configuration)" +_found=false +declare -i _number=0 +regex_zone="^[[:space:]]*zone[[:space:]]+\"$_tmp_hostname\"" +regex_file="^[[:space:]]*file" +while IFS='' read -r line || [[ -n "$line" ]] ; do + if [[ $line =~ $regex_zone ]]; then + _found=true + fi + if $_found ; then + if [[ $line =~ $regex_file ]]; 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 + let number++ + break + fi + fi +done < $ZONES_DECLARATION_FILE + +if [[ $number -eq 0 ]] ; then + echo_failed + error "No Zonefile (master) found for domain \"$dkim_domain\" ." + clean_up 11 +else + echo_ok + zone_file_dir="$(dirname $zone_file)" +fi + + +# - Check if subdomain delegation already exists +# - +record_name="_domainkey.$dkim_domain" +record_type="NS" +if grep -E "^(${record_name}\..+$record_type|_domainkey\s+.+$record_type)" $zone_file > /dev/null 2>&1 ; then + info "Subdomain delegation for $record_name already exists!" + clean_up 0 +fi + + +# - We will place the new NS Record after the last existing one. +# - +# - first we will count the number ox existing NS records +# - +declare -i _count +search_string="^[^;].+\s+IN\s+NS" +_count=$(grep -Eo "$search_string" $zone_file | wc -l) +if [[ $_count -eq 0 ]]; then + error "No existing NS record found. Check and add subdomain delegation manually!" + clean_up 99 +fi + + +# - Get DNS server +# - +echononl "Get Namservers for domain '$domain'" +dns_servers="$(grep -E "^\s*(@|)\s+IN\s+NS" $zone_file 2>/dev/null | sed 's/@//' | sed 's/\.$//' | awk '{print$3}')" +if [[ -n "$dns_servers" ]]; then + echo_ok +else + echo_failed + error "Determin DNS servers for domain '$domain' failed!" + clean_up 16 +fi + +# - This is needed, because the dns servers are requested above, in +# - an IFS='' environment! +# - +declare -i i=0 +for _dns_server in $dns_servers ; do + dns_server_arr+=("$_dns_server") +done + + +# - Backup zone directory +# - +blank_line +backup_dir $zone_file_dir +blank_line + + +# - Add subdomain delegation +# - + +CUR_IFS=$IFS +IFS='' +_tmpfile=`mktemp` +> $_tmpfile + +echononl "Add Subdomain delegation for DKIM TXT Records .." +while read -r line || [[ -n "$line" ]]; do + + echo $line >> $_tmpfile + + if echo "$line" | grep -E "$search_string" > /dev/null 2>&1 ; then + let _count-- + fi + if [[ $_count -eq 0 ]]; then + echo "" >> $_tmpfile + echo "; Subdomain delegation for DKIM TXT Records" >> $_tmpfile + + declare -i _number=0 + + while [[ $_number -lt ${#dns_server_arr[@]} ]] ; do + if [[ "$dkim_domain" = "$domain" ]] ; then + echo -e "_domainkey.${dkim_domain}. IN NS ${dns_server_arr[${_number}]}." >> $_tmpfile + fi + ((_number++)) + done + echo "" >> $_tmpfile + + _count=-1 + fi +done < "$zone_file" +if [[ $? -eq 0 ]] ; then + echo_ok +else + echo_failed + rm $_tmpfile + exit 21 +fi + +IFS=$CUR_IFS +mv $_tmpfile $zone_file + + +# - Set Correct Owner/Permission +# - +blank_line +echononl "Correct Owner for $zone_file .." +chown $BIND_USER:$BIND_GROUP $zone_file +if [[ $? -eq 0 ]] ; then + echo_ok +else + echo_failed + error "Setting ownership for '$zone_file' failed!" + clean_up 99 +fi +echononl "Correct permissions on $zone_file .." +chmod 644 $zone_file +if [[ $? -eq 0 ]] ; then + echo_ok +else + echo_failed + error "Correct permissions on '$zone_file' failed!" + clean_up 99 +fi + +_return_value=1 + + +# - Remove backup of zonefile directory if no changes are made +# - +if [[ -d "${zone_file_dir}.$backup_date" ]] ; then + diff -Nur "$zone_file_dir" "${zone_file_dir}.$backup_date" > /dev/null 2>&1 + if [[ $? -eq 0 ]]; then + info "No zone file has changed.\n Removing previously created backup." + echononl "Delete '${zone_file_dir}.$backup_date'.." + rm -rf "${zone_file_dir}.$backup_date" > $log_file 2>&1 + if [[ $? -eq 0 ]]; then + echo_ok + else + echo_failed + fi + fi +fi + +warn "Serial was not incremented and zone not reloaded.\n Use script \033[1mbind_set_new_serial.sh\033[m to do that." + + +blank_line +clean_up $_return_value +