commit 3fcbfca3ba3ec24c08e8a8a8b08affc9164ed998 Author: Christoph Date: Fri Nov 11 12:32:58 2022 +0100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0d22c07 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.swp +*~ +conf/*.conf +log/* diff --git a/conf/wireguard.conf.sample b/conf/wireguard.conf.sample new file mode 100644 index 0000000..306a154 --- /dev/null +++ b/conf/wireguard.conf.sample @@ -0,0 +1,107 @@ +# -------------------- +# Configuration for a n instanze of the WireGuard Service +# -------------------- + +# COMPANY_TOKEN +# +# Example +# COMPANY_TOKEN="wf" +# COMPANY_TOKEN="o.open" +# +# No default Value +# +#COMPANY_TOKEN="" + + +# WG_LISTEN_PORT +# +# Port on whixh WireGuard Service is listen +# +# Defaults to: +# WG_LISTEN_PORT=51820 +# +#WG_LISTEN_PORT=51820 + + +# WG_SERVER_DIR +# +# The directory containing wireguard confiuration files +# +# Defaukts to: +# WG_SERVER_DIR="/etc/wireguard" +# +#WG_SERVER_DIR="/etc/wireguard" + + +# WG_CLIENT_BASE_DIR +# +# Base directory containg client configs +# +# Defaults to: +# WG_CLIENT_BASE_DIR="${WG_SERVER_DIR}/Clients +# +#WG_CLIENT_BASE_DIR="" + + +# WG_SERVER_CONFIG +# +# then servers configuration file +# +# Defaults to +# WG_SERVER_CONFIG="${WG_SERVER_DIR}/wg-${COMPANY_TOKEN}-${WG_INSTANCE_NAME}.conf" +# +#WG_SERVER_CONFIG="" + + +# WG_NETWORK +# +# CLASS C Networkaddress for wireguard connections +# +# Example: +# WG_NETWORK==10.10.52.0 +# +# No default value +# +#WG_NETWORK="" + + +# WG_DNS +# +# DNS server pushed to the clients +# +# Example: +# WG_DNS=I192.168.52.1" +# +# No default value +# +#WG_DNS="" + + +# WG_ALLOWED_IPS +# +# IP ranges, which is allowed to access throug wireguard connection +# +# !! Note !!: +# Servers IP Address on wireguaed device is automatically added +# +# Example: +# WG_ALLOWED_IPS="192.168.52.0/24 192.168.42.0/24" +# +# No Default Value +# +# Blank separated list of Network addresses +# +#WG_ALLOWED_IPS="" + + +# WG_SERVER_ENDPOINT +# +# Usually the server name or the server IP address under which the Wireguard service +# can be reached from the Internet. +# +# Example: +# WG_SERVER_ENDPOINT="gw-d11.oopen.de" +# +# No default value +# +#WG_SERVER_ENDPOINT="" diff --git a/connect-wg.sh b/connect-wg.sh new file mode 100755 index 0000000..0abe3da --- /dev/null +++ b/connect-wg.sh @@ -0,0 +1,340 @@ +#!/usr/bin/env bash + +# ----- +# - You need the the following sudo permissions (visudo) for that user, +# - who starts this script +# - +# - chris ALL=(ALL) NOPASSWD: /usr/bin/find +# - chris ALL=(ALL) NOPASSWD: /usr/bin/systemctl start wg-quick* +# - chris ALL=(ALL) NOPASSWD: /usr/bin/systemctl stop wg-quick* +# - chris ALL=(ALL) NOPASSWD:/bin/rm -f /var/run/* +# - chris ALL=(ALL) NOPASSWD:/bin/kill +# ----- + + +script_name="$(basename $(realpath $0))" +working_dir="$(dirname $(realpath $0))" + +log_file="$(mktemp)" + +conf_file="${working_dir}/conf/${script_name%%.*}.conf" + + + +DEFAULT_WIREGUARD_CLIENT_DIR="/etc/wireguard" +DEFAULT_VPN_User="chris" + +VPN_Network="" + +declare -a wireguard_connection_arr=() + +# ---------- +# Base Function(s) +# ---------- + +clean_up() { + + 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 +} + +fatal(){ + echo "" + if $terminal ; then + echo -e " [ \033[31m\033[1mFatal\033[m ] $*" + else + echo -e " [ Fatal ] $*" + fi + echo "" + if $terminal ; then + echo -e " \033[1mScript terminated\033[m.." + else + echo -e " Script terminated.." + fi + echo "" + + rm -f $log_file + exit 1 + +} + +error (){ + echo "" + if $terminal ; then + echo -e " [ \033[31m\033[1mError\033[m ] $*" + else + echo " [ Error ] $*" + fi + echo "" +} + + +warn (){ + if $terminal ; then + echo "" + if $terminal ; then + echo -e " [ \033[33m\033[1mWarn\033[m ] $*" + else + echo " [ Warn ] $*" + fi + echo "" + fi +} + + +info (){ + if $terminal ; then + echo "" + if $terminal ; then + echo -e " [ \033[32m\033[1mInfo\033[m ] $*" + else + echo " [ Warn ] $*" + fi + echo "" + fi +} + + + + +echo_done() { + if $terminal ; then + echo -e "\033[75G[ \033[32mdone\033[m ]" + fi +} +echo_failed(){ + if $terminal ; then + echo -e "\033[75G[ \033[1;31mfailed\033[m ]" + fi +} +echo_wait(){ + if $terminal ; then + echo -en "\033[75G[ \033[5m\033[1m..\033[m ]" + fi +} +echo_skipped() { + if $terminal ; then + echo -e "\033[75G[ \033[33m\033[1mskipped\033[m ]" + fi +} + + + +blank_line() { + if $terminal ; then + echo "" + fi +} + +is_valid_ipv4() { + local -a octets=( ${1//\./ } ) + local RETURNVALUE=0 + + # return an error if the IP doesn't have exactly 4 octets + [[ ${#octets[@]} -ne 4 ]] && return 1 + + for octet in ${octets[@]} + do + if [[ ${octet} =~ ^[0-9]{1,3}$ ]] + then # shift number by 8 bits, anything larger than 255 will be > 0 + ((RETURNVALUE += octet>>8 )) + else # octet wasn't numeric, return error + return 1 + fi + done + return ${RETURNVALUE} +} + +# - Test if given argument is a valid IPv6 Address +# - +is_valid_ipv6() { + local _ipv6="$1" + + _regex_ipv6='^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$' + + + if [[ "$_ipv6" =~ ${_regex_ipv6} ]]; then + return 0 + else + return 1 + 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 + + +# ---------- +# - Some checks .. +# ---------- + +# - Running in a terminal? +# - +if [[ -t 1 ]] ; then + terminal=true +else + terminal=false +fi + +[[ -n "$WIREGUARD_CLIENT_DIR" ]] || WIREGUARD_CLIENT_DIR="$DEFAULT_WIREGUARD_CLIENT_DIR" +[[ -n "$VPN_User" ]] || VPN_User="$DEFAULT_VPN_User" + + +# ---------- +# - 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 + +blank_line +echononl "Load Configuration File $(basename ${conf_file}).." +if [[ -f "$conf_file" ]]; then + source "$conf_file" > $log_file 2>&1 + if [[ $? -eq 0 ]]; then + echo_done + else + echo_failed + fatal "$(cat $log_file)" + fi + +else + echo_skipped +fi + +blank_line + + + +# ---------- +# - Main part of script +# ---------- + +if $terminal ; then + + # - Get available WireGuard configuration files. + # - + while IFS='' read -r -d '' _file_name ; do + + #[[ "$_file_name" = ".." ]] && continue + #[[ "$_file_name" = "." ]] && continue + + _wg_conf_file="$(basename "$_file_name")" + _wg_device="${_wg_conf_file%%.conf}" + wireguard_connection_arr+=("$(basename "$_file_name")") + wireguard_device_arr+=("$_wg_device") + if $(ip -br addr show | grep "$_wg_device" > /dev/null 2>&1 ) ; then + wireguard_device_online_arr+=("$_wg_device") + else + wireguard_device_offline_arr+=("$_wg_device") + fi + + done < <(sudo find "$WIREGUARD_CLIENT_DIR" -mindepth 1 -maxdepth 1 -type f -regex '.*.conf' -print0 | sort -z) + + + if [[ ${#wireguard_connection_arr[@]} -eq 0 ]] ; then + + fatal "No WireGuard VPN configured!" + clean_up 1 + fi + + if [[ ${#wireguard_device_offline_arr[@]} -eq 0 ]]; then + + info "All available WireGuard connections already online." + clean_up 2 + fi + + echo "" + echo "" + echo "" + echo -e " \033[1mWhich WireGuard Connection should be started?\033[m" + echo "" + + + for i in ${!wireguard_device_offline_arr[@]}; do + + + WG_ENTRY="${wireguard_device_offline_arr[$i]}" + WG_ENTRY="${WG_ENTRY#wg-}" + + echo -e " [$i]\033[9G$WG_ENTRY" + + done + echo "" + echo -e " [99]\033[9G\033[33mExit programm\033[m" + + echo "" + echononl "Choose: " + + _OK=false + while ! $_OK ; do + read _IN + if is_number "$_IN" && [[ -n ${wireguard_device_offline_arr[$_IN]} ]]; then + WG_DEVICE="${wireguard_device_offline_arr[$_IN]}" + _OK=true + elif is_number "$_IN" && [[ $_IN -eq 99 ]] ;then + echo"" + exit 0 + else + echo "" + echo -e "\tWrong value !" + echo "" + echononl "Choose again: " + fi + done +fi + + +blank_line +blank_line +echononl "Start WireGuard connection \033[32m\033[1m${WG_DEVICE#wg-}\033[m.." + +sudo systemctl start wg-quick@${WG_DEVICE} +if [[ $? -gt 0 ]] ; then + echo_failed +else + echo_done +fi + +clean_up 0 + diff --git a/create_wireguard_config.sh b/create_wireguard_config.sh new file mode 100755 index 0000000..8aef717 --- /dev/null +++ b/create_wireguard_config.sh @@ -0,0 +1,1321 @@ +#!/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 + erro "$(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#*=}")" + 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 + + while grep -E -i -q "^\s*AllowedIPs\s*=\s*${WG_CLIENT_FIRST_IPv4}" "${WG_SERVER_CONFIG}" 2> "/dev/null" ; do + octets=() + octets=( ${WG_CLIENT_FIRST_IPv4//\./ } ) + WG_CLIENT_FIRST_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_PRIV_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 + +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_PRIV_KEY}/$(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") +PresharedKey = ${WG_CLIENT_PESHARED_KEY} +ListenPort = ${WG_LISTEN_PORT} +DNS = ${WG_DNS} + +[Peer] +PublicKey = ${WG_SERVER_PUB_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_PRIV_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 + + +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 + diff --git a/disconnect-wg.sh b/disconnect-wg.sh new file mode 100755 index 0000000..39d5951 --- /dev/null +++ b/disconnect-wg.sh @@ -0,0 +1,340 @@ +#!/usr/bin/env bash + +# ----- +# - You need the the following sudo permissions (visudo) for that user, +# - who starts this script +# - +# - chris ALL=(ALL) NOPASSWD: /usr/bin/find +# - chris ALL=(ALL) NOPASSWD: /usr/bin/systemctl start wg-quick* +# - chris ALL=(ALL) NOPASSWD: /usr/bin/systemctl stop wg-quick* +# - chris ALL=(ALL) NOPASSWD:/bin/rm -f /var/run/* +# - chris ALL=(ALL) NOPASSWD:/bin/kill +# ----- + + +script_name="$(basename $(realpath $0))" +working_dir="$(dirname $(realpath $0))" + +log_file="$(mktemp)" + +conf_file="${working_dir}/conf/${script_name%%.*}.conf" + + + +DEFAULT_WIREGUARD_DIR="/etc/wireguard" +DEFAULT_VPN_User="chris" + +VPN_Network="" + +declare -a wireguard_connection_arr=() + +# ---------- +# Base Function(s) +# ---------- + +clean_up() { + + 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 +} + +fatal(){ + echo "" + if $terminal ; then + echo -e " [ \033[31m\033[1mFatal\033[m ] $*" + else + echo -e " [ Fatal ] $*" + fi + echo "" + if $terminal ; then + echo -e " \033[1mScript terminated\033[m.." + else + echo -e " Script terminated.." + fi + echo "" + + rm -f $log_file + exit 1 + +} + +error (){ + echo "" + if $terminal ; then + echo -e " [ \033[31m\033[1mError\033[m ] $*" + else + echo " [ Error ] $*" + fi + echo "" +} + + +warn (){ + if $terminal ; then + echo "" + if $terminal ; then + echo -e " [ \033[33m\033[1mWarn\033[m ] $*" + else + echo " [ Warn ] $*" + fi + echo "" + fi +} + + +info (){ + if $terminal ; then + echo "" + if $terminal ; then + echo -e " [ \033[32m\033[1mInfo\033[m ] $*" + else + echo " [ Warn ] $*" + fi + echo "" + fi +} + + + + +echo_done() { + if $terminal ; then + echo -e "\033[75G[ \033[32mdone\033[m ]" + fi +} +echo_failed(){ + if $terminal ; then + echo -e "\033[75G[ \033[1;31mfailed\033[m ]" + fi +} +echo_wait(){ + if $terminal ; then + echo -en "\033[75G[ \033[5m\033[1m..\033[m ]" + fi +} +echo_skipped() { + if $terminal ; then + echo -e "\033[75G[ \033[33m\033[1mskipped\033[m ]" + fi +} + + + +blank_line() { + if $terminal ; then + echo "" + fi +} + +is_valid_ipv4() { + local -a octets=( ${1//\./ } ) + local RETURNVALUE=0 + + # return an error if the IP doesn't have exactly 4 octets + [[ ${#octets[@]} -ne 4 ]] && return 1 + + for octet in ${octets[@]} + do + if [[ ${octet} =~ ^[0-9]{1,3}$ ]] + then # shift number by 8 bits, anything larger than 255 will be > 0 + ((RETURNVALUE += octet>>8 )) + else # octet wasn't numeric, return error + return 1 + fi + done + return ${RETURNVALUE} +} + +# - Test if given argument is a valid IPv6 Address +# - +is_valid_ipv6() { + local _ipv6="$1" + + _regex_ipv6='^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$' + + + if [[ "$_ipv6" =~ ${_regex_ipv6} ]]; then + return 0 + else + return 1 + 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 + + +# ---------- +# - Some checks .. +# ---------- + +# - Running in a terminal? +# - +if [[ -t 1 ]] ; then + terminal=true +else + terminal=false +fi + +[[ -n "$WIREGUARD_DIR" ]] || WIREGUARD_DIR="$DEFAULT_WIREGUARD_DIR" +[[ -n "$VPN_User" ]] || VPN_User="$DEFAULT_VPN_User" + + +# ---------- +# - 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 + +blank_line +echononl "Load Configuration File $(basename ${conf_file}).." +if [[ -f "$conf_file" ]]; then + source "$conf_file" > $log_file 2>&1 + if [[ $? -eq 0 ]]; then + echo_done + else + echo_failed + fatal "$(cat $log_file)" + fi + +else + echo_skipped +fi + +blank_line + + + +# ---------- +# - Main part of script +# ---------- + +if $terminal ; then + + # - Get available WireGuard configuration files. + # - + while IFS='' read -r -d '' _file_name ; do + + #[[ "$_file_name" = ".." ]] && continue + #[[ "$_file_name" = "." ]] && continue + + _wg_conf_file="$(basename "$_file_name")" + _wg_device="${_wg_conf_file%%.conf}" + wireguard_connection_arr+=("$(basename "$_file_name")") + wireguard_device_arr+=("$_wg_device") + if $(ip -br addr show | grep "$_wg_device" > /dev/null 2>&1 ) ; then + wireguard_device_online_arr+=("$_wg_device") + else + wireguard_device_offline_arr+=("$_wg_device") + fi + + done < <(sudo find "$WIREGUARD_DIR" -mindepth 1 -maxdepth 1 -type f -regex '.*.conf' -print0 | sort -z) + + + if [[ ${#wireguard_connection_arr[@]} -eq 0 ]] ; then + + fatal "No WireGuard VPN configured!" + clean_up 1 + fi + + if [[ ${#wireguard_device_online_arr[@]} -eq 0 ]]; then + + info "All available WireGuard connections already offline." + clean_up 2 + fi + + echo "" + echo "" + echo "" + echo -e " \033[1mWhich Connection should be terminated?\033[m" + echo "" + + + for i in ${!wireguard_device_online_arr[@]}; do + + + WG_ENTRY="${wireguard_device_online_arr[$i]}" + WG_ENTRY="${WG_ENTRY#wg-}" + + echo -e " [$i]\033[9G$WG_ENTRY" + + done + echo "" + echo -e " [99]\033[9G\033[33mExit programm\033[m" + + echo "" + echononl "Choose: " + + _OK=false + while ! $_OK ; do + read _IN + if is_number "$_IN" && [[ -n ${wireguard_device_online_arr[$_IN]} ]]; then + WG_DEVICE="${wireguard_device_online_arr[$_IN]}" + _OK=true + elif is_number "$_IN" && [[ $_IN -eq 99 ]] ;then + echo"" + exit 0 + else + echo "" + echo -e "\tWrong value !" + echo "" + echononl "Choose again: " + fi + done +fi + +blank_line +blank_line + +echononl "Terminate WireGuard connection \033[32m\033[1m${WG_DEVICE#wg-}\033[m.." + +sudo systemctl stop wg-quick@${WG_DEVICE} +if [[ $? -gt 0 ]] ; then + echo_failed +else + echo_done +fi + +clean_up 0 + diff --git a/keys/noc-ckubu-preshared.key b/keys/noc-ckubu-preshared.key new file mode 100644 index 0000000..2d862fd --- /dev/null +++ b/keys/noc-ckubu-preshared.key @@ -0,0 +1 @@ +OLxzf1B5I8n91CETayfDqV68/HFTwCW0bh/3/bm/d1E= diff --git a/keys/noc-ckubu-private.key b/keys/noc-ckubu-private.key new file mode 100644 index 0000000..ccac3fc --- /dev/null +++ b/keys/noc-ckubu-private.key @@ -0,0 +1 @@ +0OVBpCDtys9DluLUWAlOuD2h/Psm/gCwdRwbPrQy4Ws= diff --git a/keys/noc-ckubu-public.key b/keys/noc-ckubu-public.key new file mode 100644 index 0000000..661463a --- /dev/null +++ b/keys/noc-ckubu-public.key @@ -0,0 +1 @@ +WLFxFHItkyHbCTAavqYvxolRW7wQIkS8tqoYR4MmdXw= diff --git a/keys/noc-service-private.key b/keys/noc-service-private.key new file mode 100644 index 0000000..c575546 --- /dev/null +++ b/keys/noc-service-private.key @@ -0,0 +1 @@ +gNJMeXXGgJ70So3CwLcGwzCX5RdaX3Rz9JX1fwsR30M= diff --git a/keys/noc-service-public.key b/keys/noc-service-public.key new file mode 100644 index 0000000..3082174 --- /dev/null +++ b/keys/noc-service-public.key @@ -0,0 +1 @@ +EuyFTg7beEU9CwmcEmFZ27Lbh06G+7J2ptlCKYONDkQ=