#!/usr/bin/env bash CUR_IFS=$IFS script_name="$(basename $(realpath $0))" script_dir="$(dirname $(realpath $0))" conf_dir="${script_dir}/conf" conf_file="${conf_dir}/${script_name%%.*}.conf" log_file="$(mktemp)" backup_date=$(date +%Y-%m-%d-%H%M) # ============= # --- Some functions # ============= usage() { [[ -n "$1" ]] && error "$1" [[ $terminal ]] && echo -e " \033[1mUsage:\033[m \033[1m$(basename $0)\033[m [-a|--enable-email] [-d|--domain ] [-h|--help] [--mx-host-1 ] [--mx-host-1 ] [--ns-host-1 ] [--ns-host-2 ] [-q|--quiet ] [--webserver-ipv4 ] [--webserver-ipv6 ] [-a|--disable-email] \033[1mDescription\033[m Script a new zone file for local bind nameservice. If running in a terminal and NOT '-q' is used, script acts in interactive mode. You will then be asked to confirm or override the default setting. Script uses defaults by reading from file ${conf_file}. It is also possible to specify command line parameters. These parameters take precedence over those from the configuration file. You will be asked to confirm or override the default setting. \033[1mOptions\033[m -a | --enable-email creates zone file with MX Record. This is the default -d | --domain The name of the domain, for which is a zonefile should be created. -h | --help Prints this help. --mx-host-1 Hostname for the (first) MX Record. Defaults to: \033[1m${MX_HOST_1}\033[m --mx-host-2 Hostname for a further (second) MX Record." if [[ -n "${MX_HOST_2}" ]] ; then echo -e " Defaults to: \033[1m${MX_HOST_2}\033[m" else echo " Default is only one MX Record (MX Hosst)." fi echo -e " --ns-host-1 Hostname of the master DNS Server. Defaults to: \033[1m${NS_HOST_1}\033[m --ns-host-2 Hostname of the second (slave) DNS Server. Defaults to: \033[1m${NS_HOST_2}\033[m -q | --quite Be quiet. If '-q' is used, also a domain must be given using parameter '-d'. --webserver-ipv4 Webservers IPv4 Address." if [[ -n "${WEB_SERVER_IP_4}" ]] ; then echo -e " Defaults to: \033[1m${WEB_SERVER_IP_4}\033[m" fi echo -e " --webserver-ipv6 Webservers IPv6 Address." if [[ -n "${WEB_SERVER_IP_6}" ]] ; then echo -e " Defaults to: \033[1m${WEB_SERVER_IP_6}\033[m" fi echo -e " -x | --disable-email creates zone file without MX Record. \033[1mFiles\033[m $conf_file: Configuration file \033[1mExample:\033[m Create zone file for domain \033[1mjanine-wissler.de\033[m with E-Mail support (MX Record). Interactive mod: ask for further settings \033[1m$(basename $0) -d janine-wissler.de -a\033[m Create zone file for domain \033[1mjaninewissler.de\033[m without E-Mail support (MX Record). Non-interactive mode (-q): Don't ask for further settings, use the default ones. \033[1m$(basename $0) -d janinewissler.de -x -q\033[m Complete interactive mode. All values will be ask for. \033[1m$(basename $0)\033[m " clean_up 1 } clean_up() { # Perform program exit housekeeping rm -f $log_file blank_line exit $1 } echononl(){ if $terminal ; 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 } echo_done() { if $terminal ; then echo -e "\033[75G[ \033[32mdone\033[m ]" fi } echo_ok() { if $terminal ; then echo -e "\033[75G[ \033[32mok\033[m ]" fi } echo_warning() { if $terminal ; then echo -e "\033[75G[ \033[33m\033[1mwarn\033[m ]" fi } echo_failed(){ if $terminal ; then echo -e "\033[75G[ \033[1;31mfailed\033[m ]" fi } echo_skipped() { if $terminal ; then echo -e "\033[75G[ \033[37mskipped\033[m ]" fi } fatal (){ echo "" echo "" if $terminal ; then echo -e "\t[ \033[31m\033[1mFatal\033[m ]: \033[37m\033[1m$*\033[m" echo "" echo -e "\t\033[31m\033[1m Script will be interrupted..\033[m\033[m" else echo "" echo " [ Fatal ]: $*" echo " Script will be interrupted.." echo "" fi clean_up 1 } error(){ echo "" if $terminal ; then echo -e "\t[ \033[31m\033[1mFehler\033[m ]: $*" else echo "Error: $*" fi echo "" } warn (){ echo "" if $terminal ; then echo -e "\t[ \033[33m\033[1mWarning\033[m ]: $*" else echo "Warning: $*" fi echo "" } info (){ if $terminal ; then echo -e "\t[ \033[32m\033[1mInfo\033[m ]: $*" fi } ## - Check if a given array (parameter 2) contains a given string (parameter 1) ## - containsElement () { local e for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done return 1 } get_domain_by_hostname() { _domain=$1 _tmp_domain="${_domain#*.}" while [[ "$_tmp_domain" =~ \. ]]; do _domain="$_tmp_domain" _tmp_domain="${_domain#*.}" done echo $_domain } is_number() { return $(test ! -z "${1##*[!0-9]*}" > /dev/null 2>&1); # - also possible # - #[[ ! -z "${1##*[!0-9]*}" ]] && return 0 || return 1 #return $([[ ! -z "${1##*[!0-9]*}" ]]) } trim() { local var="$*" var="${var#"${var%%[![:space:]]*}"}" # remove leading whitespace characters var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters echo -n "$var" } blank_line() { if $terminal ; then echo "" fi } # ---------- # - 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 terminal=true else terminal=false fi DEFAULT_ENABLE_E_MAILS=yes # - Read Configuration # - blank_line echononl " Include Configuration file.." if [[ ! -f $conf_file ]]; then echo_failed fatal "Missing configuration file '$conf_file'" else source $conf_file echo_ok fi blank_line TEMP=$(getopt -o ad:hqx --long domain:,ns-host-1:,ns-host-2:,mx-host-1:,mx-host-2:,--webserver-ipv4:,--webserver-ipv6: -n "$script_name" -- "$@") if [ $? != 0 ] ; then fatal "Terminating..." >&2 fi # Note the quotes around '$TEMP': they are essential! eval set -- "$TEMP" while true; do case "$1" in -a | --enable-email ) ENABLE_E_MAILS=true; shift ;; -h | --help ) usage ;; -d | --domain ) DOMAIN="$2"; shift 2 ;; -q | --qiet ) terminal=false; shift ;; --mx-host-1 ) MX_HOST_1="$2"; shift 2 ;; --mx-host-2 ) MX_HOST_2="$2"; shift 2 ;; --ns-host-1 ) NS_HOST_1="$2"; shift 2 ;; --ns-host-2 ) NS_HOST_2="$2"; shift 2 ;; --webserver-ipv4 ) WEB_SERVER_IP_4="$2"; shift 2 ;; --webserver-ipv6 ) WEB_SERVER_IP_6="$2"; shift 2 ;; -x | --disable-email ) ENABLE_E_MAILS=false; shift ;; -- ) shift; break ;; * ) break ;; esac done [[ -z "$ZONE_FILE_MASTER_DIR" ]] && ZONE_FILE_MASTER_DIR=/etc/bind/master [[ -n "${NS_HOST_1}" ]] && DEFAULT_NS_HOST_1="${NS_HOST_1}" [[ -n "${NS_HOST_2}" ]] && DEFAULT_NS_HOST_2="${NS_HOST_2}" [[ -n "${MX_HOST_1}" ]] && DEFAULT_MX_HOST_1="${MX_HOST_1}" if [[ -n "${MX_HOST_2}" ]]; then DEFAULT_MX_HOST_2="${MX_HOST_2}" else DEFAULT_MX_HOST_2="None" fi [[ -n "${WEB_SERVER_IP_4}" ]] && DEFAULT_WEB_SERVER_IP_4="${WEB_SERVER_IP_4}" [[ -n "${WEB_SERVER_IP_6}" ]] && DEFAULT_WEB_SERVER_IP_6="${WEB_SERVER_IP_6}" if $terminal ; then clear fi if $terminal ; then echo "" echo -e "\033[32m-----\033[m" echo "Create Zone file for a given domain" echo -e "\033[32m-----\033[m" fi if $terminal ; then echo "" echo "" echo -e "\033[32m--\033[m" if [[ -z "$DOMAIN" ]]; then _OK=false echo "" echo "Insert Domain for which a zone file should be created?" echo "" while [ "X$DOMAIN" = "X" ] do echononl " Domain for which a zone file is to be created: " read DOMAIN if [ "X$DOMAIN" = "X" ]; then echo "" echo -e "Eingabe erforderlich" fi done fi if [[ -f "${ZONE_FILE_MASTER_DIR}/${DOMAIN}.zone" ]]; then warn "Zonefile for domain \033[1m${DOMAIN}\033[m already exists." echo echononl "Continue with overwriting zone file? [\033[1myes/no\033[m]: " read OK while [[ "${OK,,}" != "yes" ]] && [[ "${OK,,}" != "no" ]] ; do echononl "\033[33mWrong entry!\033[m [\033[1myes/no\033[m]: " read OK done [[ "${OK,,}" = "yes" ]] || fatal "Canceled by user input." fi NS_HOST_1= echo "" echo "" echo -e "\033[32m--\033[m" echo " Give Hostname for the first (Master) Nameserver" echo "" if [[ -n "$DEFAULT_NS_HOST_1" ]]; then echo "" echo -e " Type \033[33m\033[m to accept the default." echo "" echo -en "First (Master) Nameserver [${DEFAULT_NS_HOST_1}]: " read NS_HOST_1 if [[ -z "$(trim ${NS_HOST_1})" ]] ; then NS_HOST_1="${DEFAULT_NS_HOST_1}" fi else declare -i index=0 while [[ -z "$(trim "${NS_HOST_1}")" ]]; do ((index++)) if [[ $index -lt 2 ]] ; then echo -en "First (master) Nameserver: " else echo "" echo -e " \033[33mA Master Nameserver is mandatiory!\033[m" echo "" echo -en "First (master) Nameserver: " fi read NS_HOST_1 done fi NS_HOST_2= echo "" echo "" echo -e "\033[32m--\033[m" echo " Give the Hostname for the second Nameserver" echo "" if [[ -n "$DEFAULT_NS_HOST_2" ]]; then echo "" echo -e " Type \033[33m\033[m to accept the default." echo "" echo -en "Second Nameserver [${DEFAULT_NS_HOST_2}]: " read NS_HOST_2 if [[ -z "$(trim ${NS_HOST_2})" ]] ; then NS_HOST_2="${DEFAULT_NS_HOST_2}" fi else declare -i index=0 while [[ -z "$(trim "${NS_HOST_2}")" ]]; do ((index++)) if [[ $index -lt 2 ]] ; then echo -en "Second Nameserver: " else echo "" echo -e " \033[33mA Second Nameserver is mandatiory!\033[m" echo "" echo -en "Second Nameserver: " fi read NS_HOST_2 done fi echo "" echo "" echo -e "\033[32m--\033[m" echo " Should e-mails be activated for domain '$DOMAIN'? [yes/no]" echo "" echo -e " Type \033[33m\033[m to accept the default." echo "" YES_NO="" if [[ -z "$ENABLE_E_MAILS" ]] ; then ENABLE_E_MAILS=false elif [[ "${ENABLE_E_MAILS,,}" = "false" ]] || [[ "${ENABLE_E_MAILS,,}" = "no" ]] ; then DEFAULT_ENABLE_E_MAILS="no" ENABLE_E_MAILS=false fi echononl "\033[1mAdd MX Record to zone file for domain '$DOMAIN'?\033[m [$DEFAULT_ENABLE_E_MAILS]: " read YES_NO if [[ -z "$(trim "$YES_NO")" ]]; then YES_NO="$DEFAULT_ENABLE_E_MAILS" fi while [[ "${YES_NO,,}" != "yes" ]] && [[ "${YES_NO,,}" != "no" ]] ; do echo -e " Wrong entry. try again.." echononl "\033[1mActivated for domain '$DOMAIN'?\033[m [yes/no]: " read YES_NO done [[ "${YES_NO,,}" = "yes" ]] && ENABLE_E_MAILS=true if $ENABLE_E_MAILS ; then MX_HOST_1= echo "" echo "" echo -e "\033[32m--\033[m" echo " Give Hostname for the first (Master) Mailserver" echo "" if [[ -n "$DEFAULT_MX_HOST_1" ]]; then echo "" echo -e " Type \033[33m\033[m to accept the default." echo "" echo -en "First (Master) Mailserver [${DEFAULT_MX_HOST_1}]: " read MX_HOST_1 if [[ -z "$(trim ${MX_HOST_1})" ]] ; then MX_HOST_1="${DEFAULT_MX_HOST_1}" fi else declare -i index=0 while [[ -z "$(trim "${MX_HOST_1}")" ]]; do ((index++)) if [[ $index -lt 2 ]] ; then echo -en "First (master) Mailserver: " else echo "" echo -e " \033[33mA Master Mailserver is mandatiory!\033[m" echo "" echo -en "First (master) Mailserver: " fi read MX_HOST_1 done fi MX_HOST_2= echo "" echo "" echo -e "\033[32m--\033[m" echo " Give the Hostname for the second Mailserver" echo "" echo "" echo -e " Type \033[33mNone\033[m if no second Mailserver is present." echo -e " Type \033[33m\033[m to accept the default." echo "" echo -en "Second Mailserver [${DEFAULT_MX_HOST_2}]: " read MX_HOST_2 if [[ -z "$(trim ${MX_HOST_2})" ]] ; then MX_HOST_2="${DEFAULT_MX_HOST_2}" fi [[ "$(trim ${MX_HOST_2,,})" = "none" ]] && MX_HOST_2="" fi WEB_SERVER_IP_4= echo "" echo "" echo -e "\033[32m--\033[m" echo " Give IPv4 Address og the Webserver" echo "" echo "" echo -e " Type \033[33mNone\033[m if no IPv4 Adress of the Webserver is present." if [[ -n "$DEFAULT_WEB_SERVER_IP_4" ]]; then echo -e " Type \033[33m\033[m to accept the default." echo "" echo -en "Webservers IPv4 Address [${DEFAULT_WEB_SERVER_IP_4}]: " read WEB_SERVER_IP_4 if [[ -z "$(trim ${WEB_SERVER_IP_4})" ]] ; then WEB_SERVER_IP_4="${DEFAULT_WEB_SERVER_IP_4}" fi else declare -i index=0 while [[ -z "$(trim "${WEB_SERVER_IP_4}")" ]]; do ((index++)) if [[ $index -lt 2 ]] ; then echo -en "IPv4 Address of th Webserver: " else echo "" echo -e " \033[33mIf no IPv4 Address is present, type 'None'!\033[m" echo "" echo -en "IPv4 Address of th Webserver: : " fi read WEB_SERVER_IP_4 done fi [[ "$(trim ${WEB_SERVER_IP_4,,})" = "none" ]] && WEB_SERVER_IP_4="" WEB_SERVER_IP_6= echo "" echo "" echo -e "\033[32m--\033[m" echo " Give IPv6 Address og the Webserver" echo "" echo "" echo -e " Type \033[33mNone\033[m if no IPv6 Adress of the Webserver is present." if [[ -n "$DEFAULT_WEB_SERVER_IP_6" ]]; then echo -e " Type \033[33m\033[m to accept the default." echo "" echo -en "Webservers IPv6 Address [${DEFAULT_WEB_SERVER_IP_6}]: " read WEB_SERVER_IP_6 if [[ -z "$(trim ${WEB_SERVER_IP_6})" ]] ; then WEB_SERVER_IP_6="${DEFAULT_WEB_SERVER_IP_6}" fi else declare -i index=0 while [[ -z "$(trim "${WEB_SERVER_IP_6}")" ]]; do ((index++)) if [[ $index -lt 2 ]] ; then echo -en "IPv6 Address of th Webserver: " else echo "" echo -e " \033[33mIf no IPv6 Address is present, type 'None'!\033[m" echo "" echo -en "IPv6 Address of th Webserver: : " fi read WEB_SERVER_IP_6 done fi [[ "$(trim ${WEB_SERVER_IP_6,,})" = "none" ]] && WEB_SERVER_IP_6="" echo "" echo "" echo -e " \033[32m\033[1mParameter Summary:\033[m" echo "" echo " New Domain........................: $DOMAIN" echo "" echo " Directory for master zone files...: $ZONE_FILE_MASTER_DIR" echo "" echo " First Nameserver..................: $NS_HOST_1" echo " Second Nameserver.................: $NS_HOST_2" echo "" if [[ -n "${WEB_SERVER_IP_4}" ]] ; then echo " IPv4 Address of the webserver.....: $WEB_SERVER_IP_4" else echo -e " IPv4 Address of the webserver.....: \033[33mNot present\033[m" fi if [[ -n "${WEB_SERVER_IP_6}" ]] ; then echo " IPv6 Address of the webserver.....: $WEB_SERVER_IP_6" else echo -e " IPv6 Address of the webserver.....: \033[33mNot present\033[m" fi echo "" echo " Add MX entry to zone file.........: $ENABLE_E_MAILS" if $ENABLE_E_MAILS ; then if [[ -n "$MX_HOST_2" ]] ; then echo " MX Hoste 1........................: $MX_HOST_1" echo " MX Hoste 2........................: $MX_HOST_2" else echo " MX Hoste..........................: $MX_HOST_1" fi fi echo "" echo " Webserver's IPv4 address..........: $WEB_SERVER_IP_4" echo " Webserver's IPv6 address..........: $WEB_SERVER_IP_6" echo "" echononl "Continue with this parameters? [\033[1myes/no\033[m]: " read OK while [[ "${OK,,}" != "yes" ]] && [[ "${OK,,}" != "no" ]] ; do echononl "\033[33mWrong entry!\033[m [\033[1myes/no\033[m]: " read OK done [[ "${OK,,}" = "yes" ]] || fatal "Canceled by user input." else if [[ -z "$DOMAIN" ]] ; then fatal "No Domain was given." fi if [[ -z "$NS_HOST_1" ]]; then if [[ -z "$NS_HOST_2" ]]; then fatal "No Nameserver was given. Both, firts and secind are madatory." else fatal "No first (master) nameserver was given" fi elif [[ -z "$NS_HOST_2" ]]; then fatal "No second nameserver was given!" fi fi _NS_DOMAIN="$(get_domain_by_hostname "${MX_HOST_1}")" SOA_HOST_NAME="" if [[ "${_NS_DOMAIN}" = "oopen.de" ]] ; then SOA_HOST_NAME="domreg.${_NS_DOMAIN}" elif [[ "${_NS_DOMAIN}" = "warenform.de" ]] ; then SOA_HOST_NAME="admin.${_NS_DOMAIN}" elif [[ "${_NS_DOMAIN}" = "so36net.de" ]] ; then SOA_HOST_NAME="root.${_NS_DOMAIN}" else SOA_HOST_NAME="postmaster.${_NS_DOMAIN}" fi blank_line echononl " Backup directory '${ZONE_FILE_MASTER_DIR}'.." if [[ -d ${ZONE_FILE_MASTER_DIR}.${backup_date} ]] ; then echo_skipped else cp -a "${ZONE_FILE_MASTER_DIR}" "${ZONE_FILE_MASTER_DIR}.${backup_date}" > $log_file 2>&1 if [[ $? -eq 0 ]]; then echo_ok else echo_failed fatal "$(cat $log_file)" fi fi echononl " Write new zone file \033[1m${DOMAIN}.zone\033[m .." cat << EOF > "${ZONE_FILE_MASTER_DIR}/${DOMAIN}.zone" ; - domain: ${DOMAIN} ; - \$TTL 43200 @ 86400 IN SOA ${NS_HOST_1}. ${SOA_HOST_NAME}. ( $(date +%Y%m%d01) ; serial 14400 ; refresh 3600 ; retry 604800 ; expire 86400 ; minimum ) ; ; NS Records ; @ IN NS ${NS_HOST_1}. @ IN NS ${NS_HOST_2}. EOF if $ENABLE_E_MAILS ; then cat << EOF >> "${ZONE_FILE_MASTER_DIR}/${DOMAIN}.zone" ; ; MX Records ; @ IN MX 10 ${MX_HOST_1}. EOF if [[ -n "$MX_HOST_2" ]] ; then cat << EOF >> "${ZONE_FILE_MASTER_DIR}/${DOMAIN}.zone" @ IN MX 10 ${MX_HOST_2}. EOF fi cat << EOF >> "${ZONE_FILE_MASTER_DIR}/${DOMAIN}.zone" ; ; TXT (u.a. SPF) ; @ 3600 IN TXT "v=spf1 a mx mx:lists.warenform.de mx:lists.oopen.de mx:lists.initiativenserver.de mx:listi.jpberlin.de ~all" ; ; DMARC ; _dmarc IN TXT "v=DMARC1; p=none;" EOF elif [[ -n "${DEFAULT_MX_HOST_1}" ]] ; then cat << EOF >> "${ZONE_FILE_MASTER_DIR}/${DOMAIN}.zone" ; ; MX Records ; ;@ IN MX 10 ${MX_HOST_1}. ; ; TXT (u.a. SPF) ; ;@ 3600 IN TXT "v=spf1 a mx mx:lists.warenform.de mx:lists.oopen.de mx:lists.initiativenserver.de mx:listi.jpberlin.de ~all" ; ; DMARC ; ;_dmarc IN TXT "v=DMARC1; p=none;" EOF fi cat << EOF >> "${ZONE_FILE_MASTER_DIR}/${DOMAIN}.zone" ; ; IPv4 Hostaddresses ; EOF if [[ -n "${WEB_SERVER_IP_4}" ]] ; then cat << EOF >> "${ZONE_FILE_MASTER_DIR}/${DOMAIN}.zone" @ IN A ${WEB_SERVER_IP_4} www IN A ${WEB_SERVER_IP_4} EOF fi cat << EOF >> "${ZONE_FILE_MASTER_DIR}/${DOMAIN}.zone" ; ; IPv6 Hostaddresses ; EOF if [[ -n "${WEB_SERVER_IP_6}" ]] ; then cat << EOF >> "${ZONE_FILE_MASTER_DIR}/${DOMAIN}.zone" @ IN AAAA ${WEB_SERVER_IP_6} www IN AAAA ${WEB_SERVER_IP_6} EOF else cat << EOF >> "${ZONE_FILE_MASTER_DIR}/${DOMAIN}.zone" EOF fi echo_done if $terminal ; then echo "" echo "" info "New Zone File '${ZONE_FILE_MASTER_DIR}/${DOMAIN}.zone' written." else echo "" echo " [ Info ]: New Zone File '${ZONE_FILE_MASTER_DIR}/${DOMAIN}.zone' written." echo "" fi blank_line clean_up 0