From c316fabccc5439d983bdc7074e3082c6daa76973 Mon Sep 17 00:00:00 2001
From: Iosif Nicolae <iosif@mailo.dev>
Date: Mon, 21 Sep 2020 02:00:16 -0700
Subject: [PATCH] Add auto-install functionality

---
 wireguard-install.sh | 653 ++++++++++++++++++++-----------------------
 1 file changed, 304 insertions(+), 349 deletions(-)

diff --git a/wireguard-install.sh b/wireguard-install.sh
index c752dbf..9f20c2e 100644
--- a/wireguard-install.sh
+++ b/wireguard-install.sh
@@ -4,157 +4,155 @@
 # https://github.com/angristan/wireguard-install
 
 function isRoot() {
-	if [ "${EUID}" -ne 0 ]; then
-		echo "You need to run this script as root"
-		exit 1
-	fi
+  if [ "${EUID}" -ne 0 ]; then
+    echo "You need to run this script as root"
+    exit 1
+  fi
 }
 
 function checkVirt() {
-	if [ "$(systemd-detect-virt)" == "openvz" ]; then
-		echo "OpenVZ is not supported"
-		exit 1
-	fi
+  if [ "$(systemd-detect-virt)" == "openvz" ]; then
+    echo "OpenVZ is not supported"
+    exit 1
+  fi
 
-	if [ "$(systemd-detect-virt)" == "lxc" ]; then
-		echo "LXC is not supported (yet)."
-		echo "WireGuard can technically run in an LXC container,"
-		echo "but the kernel module has to be installed on the host,"
-		echo "the container has to be run with some specific parameters"
-		echo "and only the tools need to be installed in the container."
-		exit 1
-	fi
+  if [ "$(systemd-detect-virt)" == "lxc" ]; then
+    echo "LXC is not supported (yet)."
+    echo "WireGuard can technically run in an LXC container,"
+    echo "but the kernel module has to be installed on the host,"
+    echo "the container has to be run with some specific parameters"
+    echo "and only the tools need to be installed in the container."
+    exit 1
+  fi
 }
 
 function checkOS() {
-	# Check OS version
-	if [[ -e /etc/debian_version ]]; then
-		source /etc/os-release
-		OS="${ID}" # debian or ubuntu
-		if [[ ${ID} == "debian" || ${ID} == "raspbian" ]]; then
-			if [[ ${VERSION_ID} -ne 10 ]]; then
-				echo "Your version of Debian (${VERSION_ID}) is not supported. Please use Debian 10 Buster"
-				exit 1
-			fi
-		fi
-	elif [[ -e /etc/fedora-release ]]; then
-		source /etc/os-release
-		OS="${ID}"
-	elif [[ -e /etc/centos-release ]]; then
-		OS=centos
-	elif [[ -e /etc/arch-release ]]; then
-		OS=arch
-	else
-		echo "Looks like you aren't running this installer on a Debian, Ubuntu, Fedora, CentOS or Arch Linux system"
-		exit 1
-	fi
+  # Check OS version
+  if [[ -e /etc/debian_version ]]; then
+    source /etc/os-release
+    OS="${ID}" # debian or ubuntu
+    if [[ ${ID} == "debian" || ${ID} == "raspbian" ]]; then
+      if [[ ${VERSION_ID} -ne 10 ]]; then
+        echo "Your version of Debian (${VERSION_ID}) is not supported. Please use Debian 10 Buster"
+        exit 1
+      fi
+    fi
+  elif [[ -e /etc/fedora-release ]]; then
+    source /etc/os-release
+    OS="${ID}"
+  elif [[ -e /etc/centos-release ]]; then
+    OS=centos
+  elif [[ -e /etc/arch-release ]]; then
+    OS=arch
+  else
+    echo "Looks like you aren't running this installer on a Debian, Ubuntu, Fedora, CentOS or Arch Linux system"
+    exit 1
+  fi
 }
 
 function initialCheck() {
-	isRoot
-	checkVirt
-	checkOS
+  isRoot
+  checkVirt
+  checkOS
 }
 
 function installQuestions() {
-	echo "Welcome to the WireGuard installer!"
-	echo "The git repository is available at: https://github.com/angristan/wireguard-install"
-	echo ""
-	echo "I need to ask you a few questions before starting the setup."
-	echo "You can leave the default options and just press enter if you are ok with them."
-	echo ""
+  echo "Welcome to the WireGuard installer!"
+  echo "The git repository is available at: https://github.com/angristan/wireguard-install"
+  echo ""
+  echo "I need to ask you a few questions before starting the setup."
+  echo "You can leave the default options and just press enter if you are ok with them."
+  echo ""
 
-	# Detect public IPv4 or IPv6 address and pre-fill for the user
-	SERVER_PUB_IP=$(ip -4 addr | sed -ne 's|^.* inet \([^/]*\)/.* scope global.*$|\1|p' | head -1)
-	if [[ -z ${SERVER_PUB_IP} ]]; then
-		# Detect public IPv6 address
-		SERVER_PUB_IP=$(ip -6 addr | sed -ne 's|^.* inet6 \([^/]*\)/.* scope global.*$|\1|p' | head -1)
-	fi
-	read -rp "IPv4 or IPv6 public address: " -e -i "${SERVER_PUB_IP}" SERVER_PUB_IP
+  # Detect public IPv4 or IPv6 address and pre-fill for the user
+  SERVER_PUB_IP=$(ip -4 addr | sed -ne 's|^.* inet \([^/]*\)/.* scope global.*$|\1|p' | head -1)
+  if [[ -z ${SERVER_PUB_IP} ]]; then
+    # Detect public IPv6 address
+    SERVER_PUB_IP=$(ip -6 addr | sed -ne 's|^.* inet6 \([^/]*\)/.* scope global.*$|\1|p' | head -1)
+  fi
 
-	# Detect public interface and pre-fill for the user
-	SERVER_NIC="$(ip -4 route ls | grep default | grep -Po '(?<=dev )(\S+)' | head -1)"
-	until [[ ${SERVER_PUB_NIC} =~ ^[a-zA-Z0-9_]+$ ]]; do
-		read -rp "Public interface: " -e -i "${SERVER_NIC}" SERVER_PUB_NIC
-	done
+  # Detect public interface and pre-fill for the user
+  SERVER_NIC="$(ip -4 route ls | grep default | grep -Po '(?<=dev )(\S+)' | head -1)"
 
-	until [[ ${SERVER_WG_NIC} =~ ^[a-zA-Z0-9_]+$ ]]; do
-		read -rp "WireGuard interface name: " -e -i wg0 SERVER_WG_NIC
-	done
+  # Generate random number within private ports range
+  RANDOM_PORT=$(shuf -i49152-65535 -n1)
 
-	until [[ ${SERVER_WG_IPV4} =~ ^([0-9]{1,3}\.){3} ]]; do
-		read -rp "Server's WireGuard IPv4: " -e -i 10.66.66.1 SERVER_WG_IPV4
-	done
+  if [[ $AUTO_INSTALL != "y" ]]; then
+    read -rp "IPv4 or IPv6 public address: " -e -i "${SERVER_PUB_IP}" SERVER_PUB_IP
 
-	until [[ ${SERVER_WG_IPV6} =~ ^([a-f0-9]{1,4}:){3,4}: ]]; do
-		read -rp "Server's WireGuard IPv6: " -e -i fd42:42:42::1 SERVER_WG_IPV6
-	done
+    until [[ ${SERVER_PUB_NIC} =~ ^[a-zA-Z0-9_]+$ ]]; do
+      read -rp "Public interface: " -e -i "${SERVER_NIC}" SERVER_PUB_NIC
+    done
 
-	# Generate random number within private ports range
-	RANDOM_PORT=$(shuf -i49152-65535 -n1)
-	until [[ ${SERVER_PORT} =~ ^[0-9]+$ ]] && [ "${SERVER_PORT}" -ge 1 ] && [ "${SERVER_PORT}" -le 65535 ]; do
-		read -rp "Server's WireGuard port [1-65535]: " -e -i "${RANDOM_PORT}" SERVER_PORT
-	done
+    until [[ ${SERVER_WG_NIC} =~ ^[a-zA-Z0-9_]+$ ]]; do
+      read -rp "WireGuard interface name: " -e -i wg0 SERVER_WG_NIC
+    done
 
-	# Adguard DNS by default
-	until [[ ${CLIENT_DNS_1} =~ ^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$ ]]; do
-		read -rp "First DNS resolver to use for the clients: " -e -i 176.103.130.130 CLIENT_DNS_1
-	done
-	until [[ ${CLIENT_DNS_2} =~ ^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$ ]]; do
-		read -rp "Second DNS resolver to use for the clients (optional): " -e -i 176.103.130.131 CLIENT_DNS_2
-		if [[ ${CLIENT_DNS_2} == "" ]]; then
-			CLIENT_DNS_2="${CLIENT_DNS_1}"
-		fi
-	done
+    until [[ ${SERVER_WG_IPV4} =~ ^([0-9]{1,3}\.){3} ]]; do
+      read -rp "Server's WireGuard IPv4: " -e -i 10.66.66.1 SERVER_WG_IPV4
+    done
 
-	echo ""
-	echo "Okay, that was all I needed. We are ready to setup your WireGuard server now."
-	echo "You will be able to generate a client at the end of the installation."
-	read -n1 -r -p "Press any key to continue..."
+    until [[ ${SERVER_WG_IPV6} =~ ^([a-f0-9]{1,4}:){3,4}: ]]; do
+      read -rp "Server's WireGuard IPv6: " -e -i fd42:42:42::1 SERVER_WG_IPV6
+    done
+
+    until [[ ${SERVER_PORT} =~ ^[0-9]+$ ]] && [ "${SERVER_PORT}" -ge 1 ] && [ "${SERVER_PORT}" -le 65535 ]; do
+      read -rp "Server's WireGuard port [1-65535]: " -e -i "${RANDOM_PORT}" SERVER_PORT
+    done
+
+    # Adguard DNS by default
+    until [[ ${CLIENT_DNS_1} =~ ^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$ ]]; do
+      read -rp "First DNS resolver to use for the clients: " -e -i 176.103.130.130 CLIENT_DNS_1
+    done
+    until [[ ${CLIENT_DNS_2} =~ ^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$ ]]; do
+      read -rp "Second DNS resolver to use for the clients (optional): " -e -i 176.103.130.131 CLIENT_DNS_2
+      if [[ ${CLIENT_DNS_2} == "" ]]; then
+        CLIENT_DNS_2="${CLIENT_DNS_1}"
+      fi
+    done
+    echo ""
+    echo "Okay, that was all I needed. We are ready to setup your WireGuard server now."
+    echo "You will be able to generate a client at the end of the installation."
+    read -n1 -r -p "Press any key to continue..."
+  fi
 }
-
 function installWireGuard() {
-	# Run setup questions first
-	installQuestions
-
-	# Install WireGuard tools and module
-	if [[ ${OS} == 'ubuntu' ]]; then
-		apt-get update
-		apt-get install -y wireguard iptables resolvconf qrencode
-	elif [[ ${OS} == 'debian' ]]; then
-		if ! grep -rqs "^deb .* buster-backports" /etc/apt/; then
-			echo "deb http://deb.debian.org/debian buster-backports main" >/etc/apt/sources.list.d/backports.list
-			apt-get update
-		fi
-		apt update
-		apt-get install -y iptables resolvconf qrencode
-		apt-get install -y -t buster-backports wireguard
-	elif [[ ${OS} == 'fedora' ]]; then
-		if [[ ${VERSION_ID} -lt 32 ]]; then
-			dnf install -y dnf-plugins-core
-			dnf copr enable -y jdoss/wireguard
-			dnf install -y wireguard-dkms
-		fi
-		dnf install -y wireguard-tools iptables qrencode
-	elif [[ ${OS} == 'centos' ]]; then
-		curl -Lo /etc/yum.repos.d/wireguard.repo https://copr.fedorainfracloud.org/coprs/jdoss/wireguard/repo/epel-7/jdoss-wireguard-epel-7.repo
-		yum -y install epel-release kernel kernel-devel kernel-headers
-		yum -y install wireguard-dkms wireguard-tools iptables qrencode
-	elif [[ ${OS} == 'arch' ]]; then
-		pacman -S --noconfirm linux-headers
-		pacman -S --noconfirm wireguard-tools iptables qrencode
-	fi
-
-	# Make sure the directory exists (this does not seem the be the case on fedora)
-	mkdir /etc/wireguard >/dev/null 2>&1
-
-	chmod 600 -R /etc/wireguard/
-
-	SERVER_PRIV_KEY=$(wg genkey)
-	SERVER_PUB_KEY=$(echo "${SERVER_PRIV_KEY}" | wg pubkey)
-
-	# Save WireGuard settings
-	echo "SERVER_PUB_IP=${SERVER_PUB_IP}
+  # Run setup questions first
+  installQuestions
+  # Install WireGuard tools and module
+  if [[ ${OS} == 'ubuntu' ]]; then
+    apt-get update
+    apt-get install -y wireguard iptables resolvconf qrencode
+  elif [[ ${OS} == 'debian' ]]; then
+    if ! grep -rqs "^deb .* buster-backports" /etc/apt/; then
+      echo "deb http://deb.debian.org/debian buster-backports main" >/etc/apt/sources.list.d/backports.list
+      apt-get update
+    fi
+    apt update
+    apt-get install -y iptables resolvconf qrencode
+    apt-get install -y -t buster-backports wireguard
+  elif [[ ${OS} == 'fedora' ]]; then
+    if [[ ${VERSION_ID} -lt 32 ]]; then
+      dnf install -y dnf-plugins-core
+      dnf copr enable -y jdoss/wireguard
+      dnf install -y wireguard-dkms
+    fi
+    dnf install -y wireguard-tools iptables qrencode
+  elif [[ ${OS} == 'centos' ]]; then
+    curl -Lo /etc/yum.repos.d/wireguard.repo https://copr.fedorainfracloud.org/coprs/jdoss/wireguard/repo/epel-7/jdoss-wireguard-epel-7.repo
+    yum -y install epel-release kernel kernel-devel kernel-headers
+    yum -y install wireguard-dkms wireguard-tools iptables qrencode
+  elif [[ ${OS} == 'arch' ]]; then
+    pacman -S --noconfirm linux-headers
+    pacman -S --noconfirm wireguard-tools iptables qrencode
+  fi
+  # Make sure the directory exists (this does not seem the be the case on fedora)
+  mkdir /etc/wireguard >/dev/null 2>&1
+  chmod 600 -R /etc/wireguard/
+  SERVER_PRIV_KEY=$(wg genkey)
+  SERVER_PUB_KEY=$(echo "${SERVER_PRIV_KEY}" | wg pubkey)
+  # Save WireGuard settings
+  echo "SERVER_PUB_IP=${SERVER_PUB_IP}
 SERVER_PUB_NIC=${SERVER_PUB_NIC}
 SERVER_WG_NIC=${SERVER_WG_NIC}
 SERVER_WG_IPV4=${SERVER_WG_IPV4}
@@ -164,257 +162,214 @@ SERVER_PRIV_KEY=${SERVER_PRIV_KEY}
 SERVER_PUB_KEY=${SERVER_PUB_KEY}
 CLIENT_DNS_1=${CLIENT_DNS_1}
 CLIENT_DNS_2=${CLIENT_DNS_2}" >/etc/wireguard/params
-
-	# Add server interface
-	echo "[Interface]
+  # Add server interface
+  echo "[Interface]
 Address = ${SERVER_WG_IPV4}/24,${SERVER_WG_IPV6}/64
 ListenPort = ${SERVER_PORT}
 PrivateKey = ${SERVER_PRIV_KEY}" >"/etc/wireguard/${SERVER_WG_NIC}.conf"
-
-	if pgrep firewalld; then
-		FIREWALLD_IPV4_ADDRESS=$(echo "${SERVER_WG_IPV4}" | cut -d"." -f1-3)".0"
-		FIREWALLD_IPV6_ADDRESS=$(echo "${SERVER_WG_IPV6}" | sed 's/:[^:]*$/:0/')
-		echo "PostUp = firewall-cmd --add-port ${SERVER_PORT}/udp && firewall-cmd --add-rich-rule='rule family=ipv4 source address=${FIREWALLD_IPV4_ADDRESS}/24 masquerade' && firewall-cmd --add-rich-rule='rule family=ipv6 source address=${FIREWALLD_IPV6_ADDRESS}/24 masquerade'
+  if pgrep firewalld; then
+    FIREWALLD_IPV4_ADDRESS=$(echo "${SERVER_WG_IPV4}" | cut -d"." -f1-3)".0"
+    FIREWALLD_IPV6_ADDRESS=$(echo "${SERVER_WG_IPV6}" | sed 's/:[^:]*$/:0/')
+    echo "PostUp = firewall-cmd --add-port ${SERVER_PORT}/udp && firewall-cmd --add-rich-rule='rule family=ipv4 source address=${FIREWALLD_IPV4_ADDRESS}/24 masquerade' && firewall-cmd --add-rich-rule='rule family=ipv6 source address=${FIREWALLD_IPV6_ADDRESS}/24 masquerade'
 PostDown = firewall-cmd --remove-port ${SERVER_PORT}/udp && firewall-cmd --remove-rich-rule='rule family=ipv4 source address=${FIREWALLD_IPV4_ADDRESS}/24 masquerade' && firewall-cmd --remove-rich-rule='rule family=ipv6 source address=${FIREWALLD_IPV6_ADDRESS}/24 masquerade'" >>"/etc/wireguard/${SERVER_WG_NIC}.conf"
-	else
-		echo "PostUp = iptables -A FORWARD -i ${SERVER_WG_NIC} -j ACCEPT; iptables -t nat -A POSTROUTING -o ${SERVER_PUB_NIC} -j MASQUERADE; ip6tables -A FORWARD -i ${SERVER_WG_NIC} -j ACCEPT; ip6tables -t nat -A POSTROUTING -o ${SERVER_PUB_NIC} -j MASQUERADE
+  else
+    echo "PostUp = iptables -A FORWARD -i ${SERVER_WG_NIC} -j ACCEPT; iptables -t nat -A POSTROUTING -o ${SERVER_PUB_NIC} -j MASQUERADE; ip6tables -A FORWARD -i ${SERVER_WG_NIC} -j ACCEPT; ip6tables -t nat -A POSTROUTING -o ${SERVER_PUB_NIC} -j MASQUERADE
 PostDown = iptables -D FORWARD -i ${SERVER_WG_NIC} -j ACCEPT; iptables -t nat -D POSTROUTING -o ${SERVER_PUB_NIC} -j MASQUERADE; ip6tables -D FORWARD -i ${SERVER_WG_NIC} -j ACCEPT; ip6tables -t nat -D POSTROUTING -o ${SERVER_PUB_NIC} -j MASQUERADE" >>"/etc/wireguard/${SERVER_WG_NIC}.conf"
-	fi
-
-	# Enable routing on the server
-	echo "net.ipv4.ip_forward = 1
+  fi
+  # Enable routing on the server
+  echo "net.ipv4.ip_forward = 1
 net.ipv6.conf.all.forwarding = 1" >/etc/sysctl.d/wg.conf
-
-	sysctl --system
-
-	systemctl start "wg-quick@${SERVER_WG_NIC}"
-	systemctl enable "wg-quick@${SERVER_WG_NIC}"
-
-	# Check if WireGuard is running
-	systemctl is-active --quiet "wg-quick@${SERVER_WG_NIC}"
-	WG_RUNNING=$?
-
-	# WireGuard might not work if we updated the kernel. Tell the user to reboot
-	if [[ ${WG_RUNNING} -ne 0 ]]; then
-		echo -e "\nWARNING: WireGuard does not seem to be running."
-		echo "You can check if WireGuard is running with: systemctl status wg-quick@${SERVER_WG_NIC}"
-		echo "If you get something like \"Cannot find device ${SERVER_WG_NIC}\", please reboot!"
-	fi
-
-	newClient
-	echo "If you want to add more clients, you simply need to run this script another time!"
+  sysctl --system
+  systemctl start "wg-quick@${SERVER_WG_NIC}"
+  systemctl enable "wg-quick@${SERVER_WG_NIC}"
+  # Check if WireGuard is running
+  systemctl is-active --quiet "wg-quick@${SERVER_WG_NIC}"
+  WG_RUNNING=$?
+  # WireGuard might not work if we updated the kernel. Tell the user to reboot
+  if [[ ${WG_RUNNING} -ne 0 ]]; then
+    echo -e "\nWARNING: WireGuard does not seem to be running."
+    echo "You can check if WireGuard is running with: systemctl status wg-quick@${SERVER_WG_NIC}"
+    echo "If you get something like \"Cannot find device ${SERVER_WG_NIC}\", please reboot!"
+  fi
+  newClient
+  echo "If you want to add more clients, you simply need to run this script another time!"
 }
-
 function newClient() {
-	ENDPOINT="${SERVER_PUB_IP}:${SERVER_PORT}"
-
-	echo ""
-	echo "Tell me a name for the client."
-	echo "The name must consist of alphanumeric character. It may also include an underscore or a dash."
-
-	until [[ ${CLIENT_NAME} =~ ^[a-zA-Z0-9_-]+$ && ${CLIENT_EXISTS} == '0' ]]; do
-		read -rp "Client name: " -e CLIENT_NAME
-		CLIENT_EXISTS=$(grep -c -E "^### Client ${CLIENT_NAME}\$" "/etc/wireguard/${SERVER_WG_NIC}.conf")
-
-		if [[ ${CLIENT_EXISTS} == '1' ]]; then
-			echo ""
-			echo "A client with the specified name was already created, please choose another name."
-			echo ""
-		fi
-	done
-
-	for DOT_IP in {2..254}; do
-		DOT_EXISTS=$(grep -c "${SERVER_WG_IPV4::-1}${DOT_IP}" "/etc/wireguard/${SERVER_WG_NIC}.conf")
-		if [[ ${DOT_EXISTS} == '0' ]]; then
-			break
-		fi
-	done
-
-	if [[ ${DOT_EXISTS} == '1' ]]; then
-		echo ""
-		echo "The subnet configured supports only 253 clients."
-		exit 1
-	fi
-
-	until [[ ${IPV4_EXISTS} == '0' ]]; do
-		read -rp "Client's WireGuard IPv4: ${SERVER_WG_IPV4::-1}" -e -i "${DOT_IP}" DOT_IP
-		CLIENT_WG_IPV4="${SERVER_WG_IPV4::-1}${DOT_IP}"
-		IPV4_EXISTS=$(grep -c "$CLIENT_WG_IPV4" "/etc/wireguard/${SERVER_WG_NIC}.conf")
-
-		if [[ ${IPV4_EXISTS} == '1' ]]; then
-			echo ""
-			echo "A client with the specified IPv4 was already created, please choose another IPv4."
-			echo ""
-		fi
-	done
-
-	until [[ ${IPV6_EXISTS} == '0' ]]; do
-		read -rp "Client's WireGuard IPv6: ${SERVER_WG_IPV6::-1}" -e -i "${DOT_IP}" DOT_IP
-		CLIENT_WG_IPV6="${SERVER_WG_IPV6::-1}${DOT_IP}"
-		IPV6_EXISTS=$(grep -c "${CLIENT_WG_IPV6}" "/etc/wireguard/${SERVER_WG_NIC}.conf")
-
-		if [[ ${IPV6_EXISTS} == '1' ]]; then
-			echo ""
-			echo "A client with the specified IPv6 was already created, please choose another IPv6."
-			echo ""
-		fi
-	done
-
-	# Generate key pair for the client
-	CLIENT_PRIV_KEY=$(wg genkey)
-	CLIENT_PUB_KEY=$(echo "${CLIENT_PRIV_KEY}" | wg pubkey)
-	CLIENT_PRE_SHARED_KEY=$(wg genpsk)
-
-	# Home directory of the user, where the client configuration will be written
-	if [ -e "/home/${CLIENT_NAME}" ]; then # if $1 is a user name
-		HOME_DIR="/home/${CLIENT_NAME}"
-	elif [ "${SUDO_USER}" ]; then # if not, use SUDO_USER
-		HOME_DIR="/home/${SUDO_USER}"
-	else # if not SUDO_USER, use /root
-		HOME_DIR="/root"
-	fi
-
-	# Create client file and add the server as a peer
-	echo "[Interface]
+  ENDPOINT="${SERVER_PUB_IP}:${SERVER_PORT}"
+  echo ""
+  echo "Tell me a name for the client."
+  echo "The name must consist of alphanumeric character. It may also include an underscore or a dash."
+  until [[ ${CLIENT_NAME} =~ ^[a-zA-Z0-9_-]+$ && ${CLIENT_EXISTS} == '0' ]]; do
+    read -rp "Client name: " -e CLIENT_NAME
+    CLIENT_EXISTS=$(grep -c -E "^### Client ${CLIENT_NAME}\$" "/etc/wireguard/${SERVER_WG_NIC}.conf")
+    if [[ ${CLIENT_EXISTS} == '1' ]]; then
+      echo ""
+      echo "A client with the specified name was already created, please choose another name."
+      echo ""
+    fi
+  done
+  for DOT_IP in {2..254}; do
+    DOT_EXISTS=$(grep -c "${SERVER_WG_IPV4::-1}${DOT_IP}" "/etc/wireguard/${SERVER_WG_NIC}.conf")
+    if [[ ${DOT_EXISTS} == '0' ]]; then
+      break
+    fi
+  done
+  if [[ ${DOT_EXISTS} == '1' ]]; then
+    echo ""
+    echo "The subnet configured supports only 253 clients."
+    exit 1
+  fi
+  until [[ ${IPV4_EXISTS} == '0' ]]; do
+    read -rp "Client's WireGuard IPv4: ${SERVER_WG_IPV4::-1}" -e -i "${DOT_IP}" DOT_IP
+    CLIENT_WG_IPV4="${SERVER_WG_IPV4::-1}${DOT_IP}"
+    IPV4_EXISTS=$(grep -c "$CLIENT_WG_IPV4" "/etc/wireguard/${SERVER_WG_NIC}.conf")
+    if [[ ${IPV4_EXISTS} == '1' ]]; then
+      echo ""
+      echo "A client with the specified IPv4 was already created, please choose another IPv4."
+      echo ""
+    fi
+  done
+  until [[ ${IPV6_EXISTS} == '0' ]]; do
+    read -rp "Client's WireGuard IPv6: ${SERVER_WG_IPV6::-1}" -e -i "${DOT_IP}" DOT_IP
+    CLIENT_WG_IPV6="${SERVER_WG_IPV6::-1}${DOT_IP}"
+    IPV6_EXISTS=$(grep -c "${CLIENT_WG_IPV6}" "/etc/wireguard/${SERVER_WG_NIC}.conf")
+    if [[ ${IPV6_EXISTS} == '1' ]]; then
+      echo ""
+      echo "A client with the specified IPv6 was already created, please choose another IPv6."
+      echo ""
+    fi
+  done
+  # Generate key pair for the client
+  CLIENT_PRIV_KEY=$(wg genkey)
+  CLIENT_PUB_KEY=$(echo "${CLIENT_PRIV_KEY}" | wg pubkey)
+  CLIENT_PRE_SHARED_KEY=$(wg genpsk)
+  # Home directory of the user, where the client configuration will be written
+  if [ -e "/home/${CLIENT_NAME}" ]; then # if $1 is a user name
+    HOME_DIR="/home/${CLIENT_NAME}"
+  elif [ "${SUDO_USER}" ]; then # if not, use SUDO_USER
+    HOME_DIR="/home/${SUDO_USER}"
+  else # if not SUDO_USER, use /root
+    HOME_DIR="/root"
+  fi
+  # Create client file and add the server as a peer
+  echo "[Interface]
 PrivateKey = ${CLIENT_PRIV_KEY}
 Address = ${CLIENT_WG_IPV4}/32,${CLIENT_WG_IPV6}/128
 DNS = ${CLIENT_DNS_1},${CLIENT_DNS_2}
-
 [Peer]
 PublicKey = ${SERVER_PUB_KEY}
 PresharedKey = ${CLIENT_PRE_SHARED_KEY}
 Endpoint = ${ENDPOINT}
 AllowedIPs = 0.0.0.0/0,::/0" >>"${HOME_DIR}/${SERVER_WG_NIC}-client-${CLIENT_NAME}.conf"
-
-	# Add the client as a peer to the server
-	echo -e "\n### Client ${CLIENT_NAME}
+  # Add the client as a peer to the server
+  echo -e "\n### Client ${CLIENT_NAME}
 [Peer]
 PublicKey = ${CLIENT_PUB_KEY}
 PresharedKey = ${CLIENT_PRE_SHARED_KEY}
 AllowedIPs = ${CLIENT_WG_IPV4}/32,${CLIENT_WG_IPV6}/128" >>"/etc/wireguard/${SERVER_WG_NIC}.conf"
-
-	systemctl restart "wg-quick@${SERVER_WG_NIC}"
-
-	echo -e "\nHere is your client config file as a QR Code:"
-
-	qrencode -t ansiutf8 -l L <"${HOME_DIR}/${SERVER_WG_NIC}-client-${CLIENT_NAME}.conf"
-
-	echo "It is also available in ${HOME_DIR}/${SERVER_WG_NIC}-client-${CLIENT_NAME}.conf"
+  systemctl restart "wg-quick@${SERVER_WG_NIC}"
+  echo -e "\nHere is your client config file as a QR Code:"
+  qrencode -t ansiutf8 -l L <"${HOME_DIR}/${SERVER_WG_NIC}-client-${CLIENT_NAME}.conf"
+  echo "It is also available in ${HOME_DIR}/${SERVER_WG_NIC}-client-${CLIENT_NAME}.conf"
 }
-
 function revokeClient() {
-	NUMBER_OF_CLIENTS=$(grep -c -E "^### Client" "/etc/wireguard/${SERVER_WG_NIC}.conf")
-	if [[ ${NUMBER_OF_CLIENTS} == '0' ]]; then
-		echo ""
-		echo "You have no existing clients!"
-		exit 1
-	fi
-
-	echo ""
-	echo "Select the existing client you want to revoke"
-	grep -E "^### Client" "/etc/wireguard/${SERVER_WG_NIC}.conf" | cut -d ' ' -f 3 | nl -s ') '
-	until [[ ${CLIENT_NUMBER} -ge 1 && ${CLIENT_NUMBER} -le ${NUMBER_OF_CLIENTS} ]]; do
-		if [[ ${CLIENT_NUMBER} == '1' ]]; then
-			read -rp "Select one client [1]: " CLIENT_NUMBER
-		else
-			read -rp "Select one client [1-${NUMBER_OF_CLIENTS}]: " CLIENT_NUMBER
-		fi
-	done
-
-	# match the selected number to a client name
-	CLIENT_NAME=$(grep -E "^### Client" "/etc/wireguard/${SERVER_WG_NIC}.conf" | cut -d ' ' -f 3 | sed -n "${CLIENT_NUMBER}"p)
-
-	# remove [Peer] block matching $CLIENT_NAME
-	sed -i "/^### Client ${CLIENT_NAME}\$/,/^$/d" "/etc/wireguard/${SERVER_WG_NIC}.conf"
-
-	# remove generated client file
-	rm -f "${HOME}/${SERVER_WG_NIC}-client-${CLIENT_NAME}.conf"
-
-	# restart wireguard to apply changes
-	systemctl restart "wg-quick@${SERVER_WG_NIC}"
+  NUMBER_OF_CLIENTS=$(grep -c -E "^### Client" "/etc/wireguard/${SERVER_WG_NIC}.conf")
+  if [[ ${NUMBER_OF_CLIENTS} == '0' ]]; then
+    echo ""
+    echo "You have no existing clients!"
+    exit 1
+  fi
+  echo ""
+  echo "Select the existing client you want to revoke"
+  grep -E "^### Client" "/etc/wireguard/${SERVER_WG_NIC}.conf" | cut -d ' ' -f 3 | nl -s ') '
+  until [[ ${CLIENT_NUMBER} -ge 1 && ${CLIENT_NUMBER} -le ${NUMBER_OF_CLIENTS} ]]; do
+    if [[ ${CLIENT_NUMBER} == '1' ]]; then
+      read -rp "Select one client [1]: " CLIENT_NUMBER
+    else
+      read -rp "Select one client [1-${NUMBER_OF_CLIENTS}]: " CLIENT_NUMBER
+    fi
+  done
+  # match the selected number to a client name
+  CLIENT_NAME=$(grep -E "^### Client" "/etc/wireguard/${SERVER_WG_NIC}.conf" | cut -d ' ' -f 3 | sed -n "${CLIENT_NUMBER}"p)
+  # remove [Peer] block matching $CLIENT_NAME
+  sed -i "/^### Client ${CLIENT_NAME}\$/,/^$/d" "/etc/wireguard/${SERVER_WG_NIC}.conf"
+  # remove generated client file
+  rm -f "${HOME}/${SERVER_WG_NIC}-client-${CLIENT_NAME}.conf"
+  # restart wireguard to apply changes
+  systemctl restart "wg-quick@${SERVER_WG_NIC}"
 }
-
 function uninstallWg() {
-	checkOS
-
-	systemctl stop "wg-quick@${SERVER_WG_NIC}"
-	systemctl disable "wg-quick@${SERVER_WG_NIC}"
-
-	if [[ ${OS} == 'ubuntu' ]]; then
-		apt-get autoremove --purge -y wireguard qrencode
-	elif [[ ${OS} == 'debian' ]]; then
-		apt-get autoremove --purge -y wireguard qrencode
-	elif [[ ${OS} == 'fedora' ]]; then
-		dnf remove -y wireguard-tools qrencode
-		if [[ ${VERSION_ID} -lt 32 ]]; then
-			dnf remove -y wireguard-dkms
-			dnf copr disable -y jdoss/wireguard
-		fi
-		dnf autoremove -y
-	elif [[ ${OS} == 'centos' ]]; then
-		yum -y remove wireguard-dkms wireguard-tools qrencode
-		rm -f "/etc/yum.repos.d/wireguard.repo"
-		yum -y autoremove
-	elif [[ ${OS} == 'arch' ]]; then
-		pacman -Rs --noconfirm wireguard-tools qrencode
-	fi
-
-	rm -rf /etc/wireguard
-	rm -f /etc/sysctl.d/wg.conf
-
-	# Reload sysctl
-	sysctl --system
-
-	# Check if WireGuard is running
-	systemctl is-active --quiet "wg-quick@${SERVER_WG_NIC}"
-	WG_RUNNING=$?
-
-	if [[ ${WG_RUNNING} -eq 0 ]]; then
-		echo "WireGuard failed to uninstall properly."
-		exit 1
-	else
-		echo "WireGuard uninstalled successfully."
-		exit 0
-	fi
+  checkOS
+  systemctl stop "wg-quick@${SERVER_WG_NIC}"
+  systemctl disable "wg-quick@${SERVER_WG_NIC}"
+  if [[ ${OS} == 'ubuntu' ]]; then
+    apt-get autoremove --purge -y wireguard qrencode
+  elif [[ ${OS} == 'debian' ]]; then
+    apt-get autoremove --purge -y wireguard qrencode
+  elif [[ ${OS} == 'fedora' ]]; then
+    dnf remove -y wireguard-tools qrencode
+    if [[ ${VERSION_ID} -lt 32 ]]; then
+      dnf remove -y wireguard-dkms
+      dnf copr disable -y jdoss/wireguard
+    fi
+    dnf autoremove -y
+  elif [[ ${OS} == 'centos' ]]; then
+    yum -y remove wireguard-dkms wireguard-tools qrencode
+    rm -f "/etc/yum.repos.d/wireguard.repo"
+    yum -y autoremove
+  elif [[ ${OS} == 'arch' ]]; then
+    pacman -Rs --noconfirm wireguard-tools qrencode
+  fi
+  rm -rf /etc/wireguard
+  rm -f /etc/sysctl.d/wg.conf
+  # Reload sysctl
+  sysctl --system
+  # Check if WireGuard is running
+  systemctl is-active --quiet "wg-quick@${SERVER_WG_NIC}"
+  WG_RUNNING=$?
+  if [[ ${WG_RUNNING} -eq 0 ]]; then
+    echo "WireGuard failed to uninstall properly."
+    exit 1
+  else
+    echo "WireGuard uninstalled successfully."
+    exit 0
+  fi
 }
-
 function manageMenu() {
-	echo "Welcome to WireGuard-install!"
-	echo "The git repository is available at: https://github.com/angristan/wireguard-install"
-	echo ""
-	echo "It looks like WireGuard is already installed."
-	echo ""
-	echo "What do you want to do?"
-	echo "   1) Add a new user"
-	echo "   2) Revoke existing user"
-	echo "   3) Uninstall WireGuard"
-	echo "   4) Exit"
-	until [[ ${MENU_OPTION} =~ ^[1-4]$ ]]; do
-		read -rp "Select an option [1-4]: " MENU_OPTION
-	done
-	case "${MENU_OPTION}" in
-	1)
-		newClient
-		;;
-	2)
-		revokeClient
-		;;
-	3)
-		uninstallWg
-		;;
-	4)
-		exit 0
-		;;
-	esac
+  echo "Welcome to WireGuard-install!"
+  echo "The git repository is available at: https://github.com/angristan/wireguard-install"
+  echo ""
+  echo "It looks like WireGuard is already installed."
+  echo ""
+  echo "What do you want to do?"
+  echo "   1) Add a new user"
+  echo "   2) Revoke existing user"
+  echo "   3) Uninstall WireGuard"
+  echo "   4) Exit"
+  until [[ ${MENU_OPTION} =~ ^[1-4]$ ]]; do
+    read -rp "Select an option [1-4]: " MENU_OPTION
+  done
+  case "${MENU_OPTION}" in
+  1)
+    newClient
+    ;;
+  2)
+    revokeClient
+    ;;
+  3)
+    uninstallWg
+    ;;
+  4)
+    exit 0
+    ;;
+  esac
 }
-
 # Check for root, virt, OS...
 initialCheck
-
 # Check if WireGuard is already installed and load params
 if [[ -e /etc/wireguard/params ]]; then
-	source /etc/wireguard/params
-	manageMenu
+  source /etc/wireguard/params
+  manageMenu
 else
-	installWireGuard
+  installWireGuard
 fi