#!/usr/bin/env bash script_name="$(basename $(realpath $0))" script_dir="$(dirname $(realpath $0))" conf_file="${script_dir}/conf/${script_name%%.*}.conf" LOCK_DIR="/tmp/${script_name%%.*}.LOCK" log_file="${LOCK_DIR}/${script_name%%.*}.log" backup_date="$(date +%Y-%m-%d-%H%M)" _needed_debian_packages="wireguard" declare -a needed_debian_package_arr=() # ------------- # - Default values # ------------- # - Give your default values here # - DEFAULT_WG_LISTEN_PORT=51820 DEFAULT_WG_SERVER_DIR="/etc/wireguard" # ---------- # Base Function(s) # ---------- clean_up() { # Perform program exit housekeeping rm -rf "${LOCK_DIR}" 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 } fatal(){ echo "" if $terminal ; then echo -e " [ \033[31m\033[1mFatal\033[m ]: $*" echo "" echo -e " \033[31m\033[1mScript was interupted\033[m!" else echo " [ Fatal ]: $*" echo "" echo " Script was terminated...." fi echo "" clean_up 1 } error (){ echo "" if $terminal ; then echo -e " [ \033[31m\033[1mError\033[m ]: $*" else echo " [ Error ]: $*" fi echo "" } warn (){ if $terminal ; then echo "" echo -e " [ \033[33m\033[1mWarning\033[m ]: $*" echo "" fi } info (){ if $terminal ; then echo "" echo -e " [ \033[32m\033[1mInfo\033[m ]: $*" echo "" fi } ok (){ if $terminal ; then echo "" echo -e " [ \033[32m\033[1mOk\033[m ] $*" echo "" 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_warn() { if $terminal ; then echo -e "\033[75G[ \033[33mwarn\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[90m\033[1mskipped\033[m ]" fi } echo_wait(){ if $terminal ; then echo -en "\033[75G[ \033[5m\033[1m...\033[m ]" fi } 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 } 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]*}" ]]) } is_int() { return $(test "$@" -eq "$@" > /dev/null 2>&1); } # ---------- # - Jobhandling # ---------- # - Run 'clean_up' for signals SIGHUP SIGINT SIGTERM # - trap clean_up SIGHUP SIGINT SIGTERM # - Create lock directory '$LOCK_DIR" # mkdir "$LOCK_DIR" # ---------- # - Some checks .. # ---------- # - Running in a terminal? # - if [[ -t 1 ]] ; then terminal=true else terminal=false fi declare -a conf_file_arr=() declare -a conf_name_arr=() for _conf_file in `ls ${script_dir}/conf/wireguard-*.conf 2>/dev/null` ; do conf_file_arr+=("${_conf_file}") _basename=$(basename $_conf_file) _tmp_name=${_basename%%.*} _tmp_name=${_tmp_name#*-} conf_name_arr+=("$_tmp_name") done if [[ ${#conf_file_arr[@]} -lt 1 ]] ; then fatal "NO Configuration found!" fi echo "" declare -i i=0 if [[ ${#conf_file_arr[@]} -gt 1 ]] ; then echo "" echo "Which Configuration should be loaded?" echo "" for _conf_file in ${conf_file_arr[@]} ; do echo " [${i}] ${conf_name_arr[${i}]}" (( i++ )) done _OK=false echo echononl "Eingabe: " while ! $_OK ; do read _IN if is_number "$_IN" && [[ -n ${conf_file_arr[$_IN]} ]]; then conf_file=${conf_file_arr[$_IN]} WG_INSTANCE_NAME=${conf_name_arr[$_IN]} _OK=true else echo "" echo -e "\tFalsche Eingabe !" echo "" echononl "Eingabe: " fi done else conf_file=${conf_file_arr[0]} WG_INSTANCE_NAME=${conf_name_arr[0]} fi echononl " Load Configuration File $(basename ${conf_file}).." if [[ ! -f "$conf_file" ]]; then echo_failed fatal "Configuration file \033[37m\033[1m$(basename ${conf_file})\033[m not found!" else source "${conf_file}" > $log_file 2>&1 if [[ $? -eq 0 ]]; then echo_ok else echo_failed fatal "$(cat $log_file)" fi fi [[ -z "$COMPANY_TOKEN" ]] && fatal "No value for parameter \033[1mCOMPANY_TOKEN\033[m was given" [[ -z "$WG_SERVER_ENDPOINT" ]] && fatal "No value for parameter \033[1mWG_SERVER_ENDPOINT\033[m was given" [[ -z "${WG_ALLOWED_IPS}" ]] && fatal "No IP range for WG service was given (variable \033[1mWG_ALLOWED_IPS\033[m).." declare -i index=1 for _ip in ${WG_ALLOWED_IPS}; do if [[ $index -eq 1 ]]; then WG_ALLOWED_IP_LIST="$_ip" else WG_ALLOWED_IP_LIST="$WG_ALLOWED_IP_LIST, $_ip" fi (( index++ )) done [[ -z "${WG_LISTEN_PORT}" ]] && WG_LISTEN_PORT="${DEFAULT_WG_LISTEN_PORT}" [[ -z "${WG_SERVER_DIR}" ]] && WG_SERVER_DIR="${DEFAULT_WG_SERVER_DIR}" WG_SERVER_KEY_DIR="${WG_SERVER_DIR}/Server" [[ -z "${WG_CLIENT_BASE_DIR}" ]] && WG_CLIENT_BASE_DIR="${WG_SERVER_DIR}/Clients" [[ -z "${WG_SERVER_CONFIG}" ]] && WG_SERVER_CONFIG="${WG_SERVER_DIR}/wg-${COMPANY_TOKEN}-${WG_INSTANCE_NAME}.conf" _basename_server_config="$(basename "${WG_SERVER_CONFIG}")" WG_SERVICE_NAME="${_basename_server_config%%.*}" WG_SYSTEMD_SERVICE="wg-quick@${WG_SERVICE_NAME}" if $terminal ; then echo "" echo "" echo -e " \033[32mGoing to install WireGuard\033[m" echo "" fi # Check if needed debian package(s) are installed # _error=false : > $log_file blank_line echononl "Check if needed packages are installed.." for _pkg in $_needed_debian_packages ; do if aptitude search "$_pkg" | grep " $_pkg " | grep -e "^i" >> "$log_file" 2>&1 ; then continue else needed_debian_package_arr+=("$_pkg") fi [[ $? -gt 0 ]] && _error=true done if $_error ; then echo_failed error "$(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." else echo_ok fi if [[ ${#needed_debian_package_arr[@]} -gt 0 ]]; then # Download package information from all configured sources. # echononl "Download package information from all configured sources.." apt-get update > "$log_file" 2>&1 if [[ $? -eq 0 ]] ; then echo_ok else echo_failed error "$(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." fi # Upgrade Packages # echononl "Upgrade Packages.." apt-get full-upgrade > "$log_file" 2>&1 if [[ $? -eq 0 ]] ; then echo_ok else echo_failed error "$(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." fi for _debian_pkg in ${needed_debian_package_arr[@]} ; do if [[ "$_debian_pkg" = "wireguard" ]]; then echononl "Backup directory '/etc/wireguard'.." if [[ -d "/etc/wireguard" ]] || [[ -f "/etc/wireguard" ]] ; then mv "/etc/wireguard" "/etc/wireguard.${backup_date}" > "$log_file" 2>&1 if [[ $? -eq 0 ]] ; then echo_ok else echo_failed error "$(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." fi else echo_skipped fi fi echononl "Installing $_debian_pkg .." DEBIAN_FRONTEND=noninteractive apt-get -y install $_debian_pkg > "$log_file" 2>&1 if [[ $? -eq 0 ]] ; then echo_ok else echo_failed error "$(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." fi done else echononl "Installing needed debian packages.." echo_skipped fi blank_line if [[ ! -d "$WG_SERVER_DIR" ]] ; then echononl "Directory '$WG_SERVER_DIR' does not exist. Create it.." mkdir "$WG_SERVER_DIR" > "$log_file" 2>&1 if [[ $? -eq 0 ]] ; then echo_ok else echo_failed error "$(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." fi fi echo "" echo -e "\033[32m--\033[m" echo "" WG_NEW_CLIENT_NAME="" if [ -z "$WG_NEW_CLIENT_NAME" ]; then echo "Insert key name." echo "" echo "" echononl "key name: " read WG_NEW_CLIENT_NAME while [ "X$WG_NEW_CLIENT_NAME" = "X" ] ; do echo -e "\n\t\033[33m\033[1mKey name is required!\033[m\n" echononl "key name: " read WG_NEW_CLIENT_NAME done fi WG_CLIENT_DIR="${WG_CLIENT_BASE_DIR}/${WG_NEW_CLIENT_NAME}" WG_CLIENT_CONFIG="${WG_CLIENT_DIR}/wg-${COMPANY_TOKEN}-${WG_NEW_CLIENT_NAME}.conf" blank_line echononl "Generate a preshared key (using command: \033[1mwg genpsk\033[m.." WG_CLIENT_PESHARED_KEY="$(wg genpsk 2> "$log_file")" if [[ -s "$log_file" ]] ; then echo_failed error "Command was: \033[1mWG_CLIENT_PESHARED_KEY=\"\$(wg genpsk 2> \"$log_file\")\033[m $(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." else echo_ok fi declare -a octets=() octets=( ${WG_NETWORK//\./ } ) if [[ -f "${WG_SERVER_CONFIG}" ]]; then WG_SERVER_CONFIG_PRESENT=true _found=false while IFS='' read -r _line || [[ -n $_line ]] ; do if $(echo "$_line" | grep -i -E "^\[Interface\]" > /dev/null 2>&1) ; then _found=true fi if $_found ; then if $(echo "$_line" | grep -q -e "^[[:space:]]*$" > /dev/null 2>&1) ; then _found=false fi fi if $_found ; then if $(echo "$_line" | grep -i -E "^\s*PrivateKey" > /dev/null 2>&1) ; then WG_SERVER_PRIV_KEY="$(trim "${_line#*=}")" WG_SERVER_PUB_KEY="$(echo ${WG_SERVER_PRIV_KEY} | wg pubkey)" fi if $(echo "$_line" | grep -i -E "^\s*Address" > /dev/null 2>&1) ; then WG_SERVER_IPv4="$(trim "${_line#*=}")" WG_SERVER_IPv4="${WG_SERVER_IPv4%/*}" fi fi done < "${WG_SERVER_CONFIG}" octets=( ${WG_SERVER_IPv4//\./ } ) if [[ ${octets[3]} -eq 101 ]] ; then WG_CLIENT_FIRST_IPv4="${octets[0]}.${octets[1]}.${octets[2]}.102" else WG_CLIENT_FIRST_IPv4="${octets[0]}.${octets[1]}.${octets[2]}.101" fi WG_CLIENT_IPv4="${WG_CLIENT_FIRST_IPv4}" while grep -E -i -q "^\s*AllowedIPs\s*=\s*${WG_CLIENT_IPv4}" "${WG_SERVER_CONFIG}" 2> "/dev/null" ; do octets=() octets=( ${WG_CLIENT_IPv4//\./ } ) WG_CLIENT_IPv4="${octets[0]}.${octets[1]}.${octets[2]}.$(expr ${octets[3]} + 1)" done else WG_SERVER_CONFIG_PRESENT=false octets=( ${WG_NETWORK//\./ } ) WG_SERVER_IPv4="${octets[0]}.${octets[1]}.${octets[2]}.1/32" WG_CLIENT_IPv4="${octets[0]}.${octets[1]}.${octets[2]}.101" fi WG_ALLOWED_IP_LIST="$WG_ALLOWED_IP_LIST, $WG_SERVER_IPv4" if $terminal ; then echo "" echo "" echo -e " \033[1m----------\033[m" echo "" echo " Wireguard Server directory.......: $WG_SERVER_DIR" echo " Wireguard Server Configuration...: $WG_SERVER_CONFIG" echo "" echo " Wireguard Server IPv4 Address....: $WG_SERVER_IPv4" echo " Wireguard Server Listen Port.....: $WG_LISTEN_PORT" echo "" echo -e " Wireguard service name...........: \033[33m${WG_SERVICE_NAME}\033[m" echo -e " Wireguard systemd service........: \033[33m${WG_SYSTEMD_SERVICE}\033[m" if $WG_SERVER_CONFIG_PRESENT ; then echo "" echo -e " Wireguard Server Private Key.....: \033[33m${WG_SERVER_PRIV_KEY}\033[m" echo -e " Wireguard Server Public Key......: \033[33m${WG_SERVER_PUB_KEY}\033[m" fi echo "" echo " Wireguard Client Base dir........: $WG_CLIENT_BASE_DIR" echo " Wireguard Client dir.............: $WG_CLIENT_DIR" echo "" echo " Wireguard Client Configuration...: $WG_CLIENT_CONFIG" echo "" echo " Wireguard Instance Name..........: $WG_INSTANCE_NAME" echo "" echo " Company token....................: $COMPANY_TOKEN" echo "" echo " New Client Name..................: $WG_NEW_CLIENT_NAME" echo " Client IPv4 Address..............: $WG_CLIENT_IPv4" echo " Client Allowed IPv4 Address......: $WG_ALLOWED_IP_LIST" echo "" echo " Clients preshared key............: $WG_CLIENT_PESHARED_KEY" echo "" echo -e " \033[1m----------\033[m" if [ "$(id -u)" -ne 0 ]; then warn "You may want to run this script with root privileges. Then stop here and start again with the following command:: \033[1msudo $0\033[m" fi echo "" echo -n " Type upper case 'YES' to start: " read OK if [[ "$OK" != "YES" ]] ; then fatal "Abort by user request - Answer iwas not 'YES'" fi echo "" fi # ---------- # Installing WireGuard and Generating a (Server) Key Pair # ---------- if $terminal ; then echo "" echo "" echo -e " \033[32mGenerating a Server Configuraation\033[m" echo "" fi if $WG_SERVER_CONFIG_PRESENT ; then info "Server Configuration for WireGuard already exists" else echononl "Create directory, where this script saves server keys and server configuration." if [[ ! -d "${WG_SERVER_KEY_DIR}" ]]; then mkdir "${WG_SERVER_KEY_DIR}" > "$log_file" 2>&1 if [[ $? -eq 0 ]] ; then echo_ok else echo_failed error "$(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." fi else echo_skipped fi echononl "Place a README file in directory '${WG_SERVER_KEY_DIR}'.." if [[ ! -d "${WG_SERVER_KEY_DIR}/README" ]] ; then cat < "${WG_SERVER_KEY_DIR}/README" 2> "$log_file" # Directory: ${WG_SERVER_KEY_DIR} # # ********************************************************************************************* # This directory is NOT part of wireguard distribution and is NOT needed for running wireguard. # ********************************************************************************************* # # This directory holds configuration history and also servers private and public key EOF if [[ $? -eq 0 ]] ; then echo_ok else echo_failed error "$(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." fi else echo_skipped fi blank_line echononl "Generate servers private key.." WG_SERVER_PRIV_KEY="$(wg genkey | tee "${WG_SERVER_KEY_DIR}/wg-${COMPANY_TOKEN}-${WG_INSTANCE_NAME}-private.key" 2> "$log_file")" if [[ -s "$log_file" ]] ; then echo_failed error "$(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." else echo_ok fi echononl "Change permissions (ugo= ) on newly created private key.." chmod go= "${WG_SERVER_KEY_DIR}/wg-${COMPANY_TOKEN}-${WG_INSTANCE_NAME}-private.key" > "$log_file" 2>&1 if [[ $? -eq 0 ]] ; then echo_ok else echo_failed error "$(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." fi echononl "Get servers concerning public key.." WG_SERVER_PUB_KEY="$(echo "${WG_SERVER_PRIV_KEY}" | wg pubkey | tee "${WG_SERVER_KEY_DIR}/wg-${COMPANY_TOKEN}-${WG_INSTANCE_NAME}-public.key" 2> "$log_file")" if [[ -s "$log_file" ]] ; then echo_failed error "$(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." else echo_ok fi echononl "Create WireGuard Server Configuration" cat < ${WG_SERVER_CONFIG} 2> "$log_file" [Interface] Address = ${WG_SERVER_IPv4} #SaveConfig = true ListenPort = ${WG_LISTEN_PORT} PrivateKey = ${WG_SERVER_PRIV_KEY} EOF if [[ -s "$log_file" ]] ; then echo_failed error "$(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." else echo_ok fi echononl "Save a copy of server Configuration at '${WG_SERVER_PRIV_KEY}'.." cp -a "${WG_SERVER_CONFIG}" "${WG_SERVER_DIR}/" > "$log_file" 2>&1 if [[ $? -eq 0 ]] ; then echo_ok else echo_failed error "$(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." fi fi if $terminal ; then echo "" echo "" echo -e " \033[32mConfigure a WireGuard Peer\033[m" echo "" fi # Backup existing client configuration file # echononl "Backup existing client configuration file.." if [[ -f "${WG_CLIENT_CONFIG}" ]]; then mv "${WG_CLIENT_CONFIG}" "${WG_CLIENT_CONFIG}.${backup_date}" > "$log_file" 2>&1 if [[ $? -eq 0 ]] ; then echo_ok else echo_failed error "$(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." fi else echo_skipped fi # Backup existing private key ... # echononl "Backup existing (Cient) private key.." if [[ -f "${WG_CLIENT_DIR}/${WG_NEW_CLIENT_NAME}-private.key" ]]; then mv "${WG_CLIENT_DIR}/${WG_NEW_CLIENT_NAME}-private.key" \ "${WG_CLIENT_DIR}/${WG_NEW_CLIENT_NAME}-private.key.${backup_date}" > "$log_file" 2>&1 if [[ $? -eq 0 ]] ; then echo_ok else echo_failed error "$(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." fi else echo_skipped fi # Backup existing public key ... # _client_key_already_present=false echononl "Backup existing (Cient) public key.." if [[ -f "${WG_CLIENT_DIR}/${WG_NEW_CLIENT_NAME}-public.key" ]]; then _client_key_already_present=true mv "${WG_CLIENT_DIR}/${WG_NEW_CLIENT_NAME}-public.key" \ "${WG_CLIENT_DIR}/${WG_NEW_CLIENT_NAME}-public.key.${backup_date}" > "$log_file" 2>&1 if [[ $? -eq 0 ]] ; then echo_ok else echo_failed error "$(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." fi else echo_skipped fi # Backup existing preshared key ... # echononl "Backup existing preshared key.." if [[ -f "${WG_CLIENT_DIR}/${WG_NEW_CLIENT_NAME}-preshared.key" ]]; then mv "${WG_CLIENT_DIR}/${WG_NEW_CLIENT_NAME}-preshared.key" \ "${WG_CLIENT_DIR}/${WG_NEW_CLIENT_NAME}-preshared.key.${backup_date}" > "$log_file" 2>&1 if [[ $? -eq 0 ]] ; then echo_ok else echo_failed error "$(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." fi else echo_skipped fi if $_client_key_already_present ; then WG_CLIENT_OLD_PUBLIC_KEY="$(trim $(cat "${WG_CLIENT_DIR}/${WG_NEW_CLIENT_NAME}-public.key.${backup_date}"))" else WG_CLIENT_OLD_PUBLIC_KEY="" fi # '+' sign breaks regexp in grep-statement. # We need to replace '+' with '\+' # _CHECK_WG_CLIENT_OLD_PUBLIC_KEY="${WG_CLIENT_OLD_PUBLIC_KEY//+/\\+}" blank_line echononl "Delete existing configuration for \033[1m${WG_NEW_CLIENT_NAME}\033[m" echo_wait if $WG_SERVER_CONFIG_PRESENT && [[ -n "${WG_CLIENT_OLD_PUBLIC_KEY}" ]]; then _server_configfile_name="$(basename "${WG_SERVER_CONFIG}")" _tmp_server_configfile_name="_$(basename "${WG_SERVER_CONFIG}")" if $(grep -q -E "^\s*PublicKey\s*=\s*${_CHECK_WG_CLIENT_OLD_PUBLIC_KEY}" "${WG_SERVER_CONFIG}" 2> "/dev/null") ; then _found=false _last_line="X" declare -i index=1 _number_of_lines="$(wc -l < ${WG_SERVER_CONFIG})" : > "${LOCK_DIR}/${_server_configfile_name}" while IFS='' read -r _line || [[ -n $_line ]] ; do (( index++ )) if $(echo "$_line" | grep -q -e "^[[:space:]]*$" > /dev/null 2>&1) \ && $(echo "$_last_line" | grep -q -e "^[[:space:]]*$" > /dev/null 2>&1) ; then continue else echo "${_line}" >> "${LOCK_DIR}/${_tmp_server_configfile_name}" fi if $(echo "$_line" | grep -q -e "^[[:space:]]*$" > /dev/null 2>&1) \ || [[ $index -gt $_number_of_lines ]]; then if ! $_found ; then cat "${LOCK_DIR}/${_tmp_server_configfile_name}" >> "${LOCK_DIR}/${_server_configfile_name}" 2> "$log_file" else _found=false fi : > "${LOCK_DIR}/${_tmp_server_configfile_name}" else if $(echo "$_line" | grep -q -E "^\s*PublicKey\s*=\s*${_CHECK_WG_CLIENT_OLD_PUBLIC_KEY}" 2> "/dev/null") ; then _found=true fi fi _last_line="${_line}" done < "${WG_SERVER_CONFIG}" if [[ -s "$log_file" ]] ; then echo_failed error "$(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." else echo_ok fi echononl "Write back WireGuard Server configuration.." mv "${LOCK_DIR}/${_server_configfile_name}" "${WG_SERVER_CONFIG}" > "$log_file" 2>&1 if [[ $? -eq 0 ]]; then echo_ok else echo_failed error "$(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." fi else echo_skipped fi else echo_skipped fi # Create client base directory if not exists # echononl "Create client base directory if not exists .." if [[ ! -d "${WG_CLIENT_BASE_DIR}" ]] ; then mkdir "${WG_CLIENT_BASE_DIR}" > "$log_file" 2>&1 if [[ $? -eq 0 ]] ; then echo_ok else echo_failed error "$(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." fi else echo_skipped fi echononl "Place a README file in directory '${WG_CLIENT_BASE_DIR}'.." if [[ ! -d "${WG_CLIENT_BASE_DIR}/README" ]] ; then cat < "${WG_CLIENT_BASE_DIR}/README" 2> "$log_file" # Directory: ${WG_CLIENT_BASE_DIR} # # ********************************************************************************************* # This directory is NOT part of wireguard distribution and is NOT needed for running wireguard. # ********************************************************************************************* # # This directory holds client configurations and also clients private and public key EOF if [[ $? -eq 0 ]] ; then echo_ok else echo_failed error "$(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." fi else echo_skipped fi # Create client directory if not exists # echononl "Create client directory if not exists .." if [[ ! -d "${WG_CLIENT_BASE_DIR}/${WG_NEW_CLIENT_NAME}" ]] ; then mkdir "${WG_CLIENT_BASE_DIR}/${WG_NEW_CLIENT_NAME}" > "$log_file" 2>&1 if [[ $? -eq 0 ]] ; then echo_ok else echo_failed error "$(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." fi else echo_skipped fi blank_line # Create the private key for new WireGuard Client # echononl "Create the private key for new WireGuard Client '${WG_NEW_CLIENT_NAME}'.." wg genkey > "${WG_CLIENT_DIR}/${WG_NEW_CLIENT_NAME}-private.key" 2> "$log_file" if [[ $? -eq 0 ]] ; then echo_ok else echo_failed error "Command was: \033[1mwg genkey > \"${WG_CLIENT_DIR}/${WG_NEW_CLIENT_NAME}-private.key\"\033[m $(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." fi # Change permissions on newly created key # echononl "Change permissions (ugo= ) on newly created key.." chmod go= "${WG_CLIENT_DIR}/${WG_NEW_CLIENT_NAME}-private.key" 2> "$log_file" if [[ $? -eq 0 ]] ; then echo_ok else echo_failed error "Command was: \033[1mchmod go= \"${WG_CLIENT_DIR}/${WG_NEW_CLIENT_NAME}-private.key\"\033[m $(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." fi # Create corresponding public key # echononl "Create corresponding public key for Client '${WG_NEW_CLIENT_NAME}'.." cat "${WG_CLIENT_DIR}/${WG_NEW_CLIENT_NAME}-private.key" \ | wg pubkey > "${WG_CLIENT_DIR}/${WG_NEW_CLIENT_NAME}-public.key" 2> "$log_file" if [[ $? -eq 0 ]] ; then echo_ok else echo_failed error "Command was: \033[1mcat \"${WG_CLIENT_DIR}/${WG_NEW_CLIENT_NAME}-private.key\" \\ | wg pubkey > \"${WG_CLIENT_DIR}/${WG_NEW_CLIENT_NAME}-public.key\"\033[m $(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." fi echononl "Save preshared key into file '${WG_NEW_CLIENT_NAME}-preshared.key'.." echo "${WG_CLIENT_PESHARED_KEY}" > ""${WG_CLIENT_DIR}/${WG_NEW_CLIENT_NAME}-preshared.key"" 2> "$log_file" if [[ $? -eq 0 ]] ; then echo_ok else echo_failed fi echononl "Backup server configuration at '${WG_SERVER_CONFIG}'.." if [[ -f "${WG_SERVER_CONFIG}" ]]; then cp -a "${WG_SERVER_CONFIG}" \ "${WG_SERVER_KEY_DIR}/$(basename "${WG_SERVER_CONFIG}").${backup_date}" > "$log_file" 2>&1 if [[ $? -eq 0 ]] ; then echo_ok else echo_failed error "$(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." fi else echo_skipped fi echononl "Create client configuration file.." cat < "${WG_CLIENT_CONFIG}" 2> "$log_file" [Interface] Address = ${WG_CLIENT_IPv4} PrivateKey = $(cat "${WG_CLIENT_DIR}/${WG_NEW_CLIENT_NAME}-private.key") ListenPort = ${WG_LISTEN_PORT} DNS = ${WG_DNS} [Peer] PublicKey = ${WG_SERVER_PUB_KEY} PresharedKey = ${WG_CLIENT_PESHARED_KEY} AllowedIPs = ${WG_ALLOWED_IP_LIST} Endpoint = ${WG_SERVER_ENDPOINT}:${WG_LISTEN_PORT} EOF if [[ -s "$log_file" ]] ; then echo_failed error "$(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." else echo_ok fi echononl "Add client configuration to server configuration file.." cat <> ${WG_SERVER_CONFIG} 2> "$log_file" # ${WG_NEW_CLIENT_NAME} [Peer] PublicKey = $(cat "${WG_CLIENT_DIR}/${WG_NEW_CLIENT_NAME}-public.key") PresharedKey = ${WG_CLIENT_PESHARED_KEY} AllowedIPs = ${WG_CLIENT_IPv4} EOF if [[ -s "$log_file" ]] ; then echo_failed error "Command was: \033[1mwg genkey > \"${WG_CLIENT_DIR}/${WG_NEW_CLIENT_NAME}-private.key\"\033[m $(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." else echo_ok fi echononl "Save a copy of server configuration at '${WG_SERVER_PRIV_KEY}'.." cp -a "${WG_SERVER_CONFIG}" "${WG_SERVER_KEY_DIR}/" > "$log_file" 2>&1 if [[ $? -eq 0 ]] ; then echo_ok else echo_failed error "$(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." fi blank_line if $WG_SERVER_CONFIG_PRESENT ; then echononl "Reload WireGuard Service" systemctl reload ${WG_SYSTEMD_SERVICE} > "$log_file" 2>&1 if [[ $? -eq 0 ]] ; then echo_ok else echo_failed error "Command was: \033[1msystemctl reload ${WG_SYSTEMD_SERVICE}\033[m $(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." fi else echononl "Enable Wireguard Service at boottime and start service now.." systemctl enable --now ${WG_SYSTEMD_SERVICE} > "$log_file" 2>&1 if [[ $? -eq 0 ]] ; then echo_ok else echo_failed error "Command was: \033[1msystemctl enable --now ${WG_SYSTEMD_SERVICE}\033[m $(cat $log_file)" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interrupted by user." fi fi blank_line warn "Please do not forget to set up port forwarding (${ListenPort}) in the DSL router." blank_line clean_up 0