Merge pull request #1572 from giulio-coa/formatting_enhancements

Reformatted the code according to google bash code style.
This commit is contained in:
4s3ti 2022-08-12 22:37:37 +02:00 committed by GitHub
commit f59c693ba6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 5861 additions and 4353 deletions

View file

@ -3,15 +3,13 @@ language: shell
addons: addons:
hosts: hosts:
- pivpn.test - pivpn.test
apt:
packages:
- shellcheck
services: services:
- docker - docker
stages: stages:
- lint - lint
- style
- test - test
branches: branches:
@ -24,11 +22,29 @@ jobs:
- stage: lint - stage: lint
name: "Shellcheck lint" name: "Shellcheck lint"
dist: focal dist: focal
addons:
apt:
packages:
- shellcheck
virt: vm virt: vm
arch: amd64 arch: amd64
script: script:
- shellcheck auto_install/install.sh - shellcheck -x auto_install/install.sh
- find scripts/ -type f | xargs shellcheck - find ciscripts/ -type f -regex '.*\.sh' -exec shellcheck -x {} \;
- find scripts/ -type f -exec shellcheck -x {} \;
- stage: style
name: "Shell Style Guide"
dist: xenial
addons:
snaps:
- shfmt
virt: vm
arch: amd64
script:
- shfmt -d -i 2 -ci -sr -bn auto_install/install.sh
- find ciscripts/ -type f -regex '.*\.sh' -exec shfmt -d -i 2 -ci -sr -bn {} \;
- find scripts/ -type f -exec shfmt -d -i 2 -ci -sr -bn {} \;
- stage: test - stage: test
name: "OpenVPN Xenial & Commands" name: "OpenVPN Xenial & Commands"

View file

@ -22,6 +22,11 @@ Please report unacceptable behavior to any project maintainer.
* Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable. * Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable.
* Use the following [commit rules](https://github.com/angular/angular/blob/main/CONTRIBUTING.md#-commit-message-format).
* Use the following [code style rules](https://google.github.io/styleguide/shellguide.html).
We suggest you to use `shfmt` with the options `-i 2 -ci -sr -w -bn`
### **PiVPN Website** ### **PiVPN Website**
* Yes the site is open source as well! You can find and contribute to [pivpn.io](https://github.com/pivpn/pivpn.io) directly. * Yes the site is open source as well! You can find and contribute to [pivpn.io](https://github.com/pivpn/pivpn.io) directly.

File diff suppressed because it is too large Load diff

View file

@ -1,46 +1,61 @@
#!/bin/sh #!/bin/bash
interface=$(ip -o link | awk '{print $2}' | cut -d':' -f1 | cut -d'@' -f1 | grep -v -w 'lo' | head -1) interface=$(ip -o link \
ipaddress=$(ip addr show "$interface" | grep -o -E "([0-9]{1,3}[\.]){3}[0-9]{1,3}/[0-9]{2}") | awk '{print $2}' \
| cut -d ':' -f 1 \
| cut -d '@' -f 1 \
| grep -v -w 'lo' \
| head -1)
ipaddress=$(ip addr show "${interface}" \
| grep -o -E "([0-9]{1,3}[\.]){3}[0-9]{1,3}/[0-9]{2}")
gateway=$(ip route show | awk '/default/ {print $3}') gateway=$(ip route show | awk '/default/ {print $3}')
hostname="pivpn.test" hostname="pivpn.test"
err() {
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
}
common() { common() {
sed -i "s/INTERFACE/$interface/g" "$vpnconfig" sed -i "s/INTERFACE/${interface}/g" "${vpnconfig}"
sed -i "s|IPADDRESS|$ipaddress|g" "$vpnconfig" sed -i "s|IPADDRESS|${ipaddress}|g" "${vpnconfig}"
sed -i "s/GATEWAY/$gateway/g" "$vpnconfig" sed -i "s/GATEWAY/${gateway}/g" "${vpnconfig}"
} }
openvpn() { openvpn() {
vpnconfig="ciscripts/ci_openvpn.conf" vpnconfig="ciscripts/ci_openvpn.conf"
twofour=1 twofour=1
common common
sed -i "s/2POINT4/$twofour/g" "$vpnconfig" sed -i "s/2POINT4/${twofour}/g" "${vpnconfig}"
cat $vpnconfig cat "${vpnconfig}"
exit 0 exit 0
} }
wireguard() { wireguard() {
vpnconfig="ciscripts/ci_wireguard.conf" vpnconfig="ciscripts/ci_wireguard.conf"
common common
cat $vpnconfig cat "${vpnconfig}"
exit 0 exit 0
} }
if [ $# -lt 1 ]; then if [[ "$#" -lt 1 ]]; then
echo "specifiy a VPN protocol to prepare" err "specifiy a VPN protocol to prepare"
exit 1 exit 1
else else
chmod +x auto_install/install.sh chmod +x auto_install/install.sh
sudo hostnamectl set-hostname $hostname sudo hostnamectl set-hostname "${hostname}"
cat /etc/os-release cat /etc/os-release
while true; do while true; do
case "$1" in case "${1}" in
-o | --openvpn ) openvpn -o | --openvpn)
openvpn
;; ;;
-w | --wireguard ) wireguard -w | --wireguard)
wireguard
;; ;;
* ) echo "unknown vpn protocol"; exit 1 *)
err "unknown vpn protocol"
exit 1
;; ;;
esac esac
done done

View file

@ -5,6 +5,7 @@ if command -v systemctl > /dev/null; then
elif command -v rc-service > /dev/null; then elif command -v rc-service > /dev/null; then
rc-service openvpn status rc-service openvpn status
fi fi
pivpn add -n foo pivpn add -n foo
pivpn -qr foo pivpn -qr foo
pivpn -bk pivpn -bk

View file

@ -2,9 +2,9 @@
# PiVPN: Backup Script # PiVPN: Backup Script
# Find the rows and columns. Will default to 80x24 if it can not be detected. # Find the rows and columns. Will default to 80x24 if it can not be detected.
screen_size=$(stty size 2>/dev/null || echo 24 80) screen_size="$(stty size 2> /dev/null || echo 24 80)"
rows=$(echo "$screen_size" | awk '{print $1}') rows="$(echo "${screen_size}" | awk '{print $1}')"
columns=$(echo "$screen_size" | awk '{print $2}') columns="$(echo "${screen_size}" | awk '{print $2}')"
# Divide by two so the dialogs take up half of the screen, which looks nice. # Divide by two so the dialogs take up half of the screen, which looks nice.
r=$((rows / 2)) r=$((rows / 2))
@ -14,93 +14,107 @@ r=$(( r < 20 ? 20 : r ))
c=$((c < 70 ? 70 : c)) c=$((c < 70 ? 70 : c))
backupdir=pivpnbackup backupdir=pivpnbackup
date=$(date +%Y%m%d-%H%M%S) date="$(date +%Y%m%d-%H%M%S)"
setupVarsFile="setupVars.conf" setupVarsFile="setupVars.conf"
setupConfigDir="/etc/pivpn" setupConfigDir="/etc/pivpn"
CHECK_PKG_INSTALLED='dpkg-query -s' CHECK_PKG_INSTALLED='dpkg-query -s'
if [ -r "${setupConfigDir}/wireguard/${setupVarsFile}" ] && [ -r "${setupConfigDir}/openvpn/${setupVarsFile}" ]; then if [[ -r "${setupConfigDir}/wireguard/${setupVarsFile}" ]] \
&& [[ -r "${setupConfigDir}/openvpn/${setupVarsFile}" ]]; then
# Two protocols have been installed, check if the script has passed # Two protocols have been installed, check if the script has passed
# an argument, otherwise ask the user which one he wants to remove # an argument, otherwise ask the user which one he wants to remove
if [ $# -ge 1 ]; then if [[ "$#" -ge 1 ]]; then
VPN="$1" VPN="${1}"
echo "::: Backing up VPN: $VPN" echo "::: Backing up VPN: ${VPN}"
else else
chooseVPNCmd=(whiptail --backtitle "Setup PiVPN" --title "Backup" --separate-output --radiolist "Both OpenVPN and WireGuard are installed, choose a VPN to backup (press space to select):" "${r}" "${c}" 2) chooseVPNCmd=(whiptail
--backtitle "Setup PiVPN"
--title "Backup"
--separate-output
--radiolist "Both OpenVPN and WireGuard are installed, choose a VPN to \
backup (press space to select):"
"${r}" "${c}" 2)
VPNChooseOptions=(WireGuard "" on VPNChooseOptions=(WireGuard "" on
OpenVPN "" off) OpenVPN "" off)
if VPN=$("${chooseVPNCmd[@]}" "${VPNChooseOptions[@]}" 2>&1 >/dev/tty) ; then if VPN="$("${chooseVPNCmd[@]}" "${VPNChooseOptions[@]}" 2>&1 \
echo "::: Backing up VPN: $VPN" > /dev/tty)"; then
echo "::: Backing up VPN: ${VPN}"
VPN="${VPN,,}" VPN="${VPN,,}"
else else
echo "::: Cancel selected, exiting...." err "::: Cancel selected, exiting...."
exit 1 exit 1
fi fi
fi fi
setupVars="${setupConfigDir}/${VPN}/${setupVarsFile}" setupVars="${setupConfigDir}/${VPN}/${setupVarsFile}"
else else
if [[ -r "${setupConfigDir}/wireguard/${setupVarsFile}" ]]; then
if [ -r "${setupConfigDir}/wireguard/${setupVarsFile}" ]; then
setupVars="${setupConfigDir}/wireguard/${setupVarsFile}" setupVars="${setupConfigDir}/wireguard/${setupVarsFile}"
elif [ -r "${setupConfigDir}/openvpn/${setupVarsFile}" ]; then elif [[ -r "${setupConfigDir}/openvpn/${setupVarsFile}" ]]; then
setupVars="${setupConfigDir}/openvpn/${setupVarsFile}" setupVars="${setupConfigDir}/openvpn/${setupVarsFile}"
fi fi
fi fi
if [ ! -f "${setupVars}" ]; then if [[ ! -f "${setupVars}" ]]; then
echo "::: Missing setup vars file!" err "::: Missing setup vars file!"
exit 1 exit 1
fi fi
# shellcheck disable=SC1090 # shellcheck disable=SC1090
source "${setupVars}" source "${setupVars}"
if [ "${PLAT}" == 'Alpine' ]; then if [[ "${PLAT}" == 'Alpine' ]]; then
CHECK_PKG_INSTALLED='apk --no-cache info -e' CHECK_PKG_INSTALLED='apk --no-cache info -e'
fi fi
checkbackupdir(){ err() {
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
}
checkbackupdir() {
# Disabling shellcheck error $install_home sourced from $setupVars # Disabling shellcheck error $install_home sourced from $setupVars
# shellcheck disable=SC2154 # shellcheck disable=SC2154
if [[ ! -d $install_home/$backupdir ]]; then mkdir -p "${install_home}/${backupdir}"
mkdir -p "$install_home"/"$backupdir"
fi
} }
backup_openvpn() { backup_openvpn() {
openvpndir=/etc/openvpn openvpndir=/etc/openvpn
ovpnsdir=${install_home}/ovpns ovpnsdir="${install_home}/ovpns"
checkbackupdir backupzip="${date}-pivpnovpnbackup.tgz"
backupzip=$date-pivpnovpnbackup.tgz
# shellcheck disable=SC2210
tar czpf "$install_home"/"$backupdir"/"$backupzip" "$openvpndir" "$ovpnsdir" > /dev/null 2>&1
echo -e "Backup created in $install_home/$backupdir/$backupzip \nTo restore the backup, follow instructions at:\nhttps://docs.pivpn.io/openvpn/#migrating-pivpn-openvpn\n"
checkbackupdir
# shellcheck disable=SC2210
tar czpf "${install_home}/${backupdir}/${backupzip}" "${openvpndir}" \
"${ovpnsdir}" > /dev/null 2>&1
echo -e "Backup created in ${install_home}/${backupdir}/${backupzip} "
echo -e "To restore the backup, follow instructions at:"
echo -ne "https://docs.pivpn.io/openvpn/"
echo -e "#migrating-pivpn-openvpn"
} }
backup_wireguard() { backup_wireguard() {
wireguarddir=/etc/wireguard wireguarddir=/etc/wireguard
configsdir=${install_home}/configs configsdir="${install_home}/configs"
checkbackupdir backupzip="${date}-pivpnwgbackup.tgz"
backupzip=$date-pivpnwgbackup.tgz
tar czpf "$install_home"/"$backupdir"/"$backupzip" "$wireguarddir" "$configsdir" > /dev/null 2>&1
echo -e "Backup created in $install_home/$backupdir/$backupzip \nTo restore the backup, follow instructions at:\nhttps://docs.pivpn.io/wireguard/#migrating-pivpn-wireguard\n"
checkbackupdir
tar czpf "${install_home}/${backupdir}/${backupzip}" "${wireguarddir}" \
"${configsdir}" > /dev/null 2>&1
echo -e "Backup created in ${install_home}/${backupdir}/${backupzip} "
echo -e "To restore the backup, follow instructions at:"
echo -ne "https://docs.pivpn.io/openvpn/"
echo -e "wireguard/#migrating-pivpn-wireguard"
} }
if [[ ! $EUID -eq 0 ]]; then if [[ "${EUID}" -ne 0 ]]; then
if eval "${CHECK_PKG_INSTALLED} sudo" &> /dev/null; then if ${CHECK_PKG_INSTALLED} sudo &> /dev/null; then
export SUDO="sudo" export SUDO="sudo"
else else
echo "::: Please install sudo or run this as root." err "::: Please install sudo or run this as root."
exit 1 exit 1
fi fi
fi fi

View file

@ -1,21 +1,25 @@
#!/bin/bash #!/bin/bash
_pivpn()
{ _pivpn() {
local cur prev opts local cur prev opts
COMPREPLY=() COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}" cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD - 1]}" prev="${COMP_WORDS[COMP_CWORD - 1]}"
dashopts="-a -c -d -l -r -h -u -up -bk" dashopts="-a -c -d -l -r -h -u -up -bk"
opts="debug add clients list revoke uninstall help update backup" opts="debug add clients list revoke uninstall help update backup"
if [ "${#COMP_WORDS[@]}" -eq 2 ]; then
if [[ ${cur} == -* ]] ; then if [[ "${#COMP_WORDS[@]}" -eq 2 ]]; then
if [[ "${cur}" == -* ]]; then
COMPREPLY=("$(compgen -W "${dashopts}" -- "${cur}")") COMPREPLY=("$(compgen -W "${dashopts}" -- "${cur}")")
else else
COMPREPLY=("$(compgen -W "${opts}" -- "${cur}")") COMPREPLY=("$(compgen -W "${opts}" -- "${cur}")")
fi fi
elif [[ ( "$prev" == "add" || "$prev" == "-a" ) && "${#COMP_WORDS[@]}" -eq 3 ]]; then elif [[ ("${prev}" == "add" || "${prev}" == "-a") ]] \
&& [[ "${#COMP_WORDS[@]}" -eq 3 ]]; then
COMPREPLY=("$(compgen -W "nopass" -- "${cur}")") COMPREPLY=("$(compgen -W "nopass" -- "${cur}")")
fi fi
return 0 return 0
} }
complete -F _pivpn pivpn complete -F _pivpn pivpn

View file

@ -1,13 +1,17 @@
#!/usr/bin/env bash #!/bin/bash
# PiVPN: client status script # PiVPN: client status script
STATUS_LOG="/var/log/openvpn-status.log" STATUS_LOG="/var/log/openvpn-status.log"
if [ ! -f "${STATUS_LOG}" ]; then if [[ ! -f "${STATUS_LOG}" ]]; then
echo "The file: $STATUS_LOG was not found!" err "The file: ${STATUS_LOG} was not found!"
exit 1 exit 1
fi fi
err() {
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
}
scriptusage() { scriptusage() {
echo "::: List any connected clients to the server" echo "::: List any connected clients to the server"
echo ":::" echo ":::"
@ -20,10 +24,9 @@ scriptusage(){
} }
hr() { hr() {
numfmt --to=iec-i --suffix=B "$1" numfmt --to=iec-i --suffix=B "${1}"
} }
listClients() { listClients() {
printf ": NOTE : The output below is NOT real-time!\n" printf ": NOTE : The output below is NOT real-time!\n"
printf ": : It may be off by a few minutes.\n" printf ": : It may be off by a few minutes.\n"
@ -31,25 +34,35 @@ listClients(){
printf "\e[1m::: Client Status List :::\e[0m\n" printf "\e[1m::: Client Status List :::\e[0m\n"
{ {
printf "\e[4mName\e[0m \t \e[4mRemote IP\e[0m \t \e[4mVirtual IP\e[0m \t \e[4mBytes Received\e[0m \t \e[4mBytes Sent\e[0m \t \e[4mConnected Since\e[0m\n" printf "\e[4mName\e[0m \t \e[4mRemote IP\e[0m \t "
printf "\e[4mVirtual IP\e[0m \t \e[4mBytes Received\e[0m \t "
printf "\e[4mBytes Sent\e[0m \t \e[4mConnected Since\e[0m\n"
if grep -q "^CLIENT_LIST" "${STATUS_LOG}"; then if grep -q "^CLIENT_LIST" "${STATUS_LOG}"; then
if [ -n "$(type -t numfmt)" ]; then if [[ -n "$(type -t numfmt)" ]]; then
if [ "$HR" = 1 ]; then
while read -r line; do while read -r line; do
read -r -a array <<< "$line" read -r -a array <<< "${line}"
[[ ${array[0]} = CLIENT_LIST ]] || continue
printf "%s \t %s \t %s \t %s \t %s \t %s %s %s - %s\n" "${array[1]}" "${array[2]}" "${array[3]}" "$(hr "${array[4]}")" "$(hr "${array[5]}")" "${array[7]}" "${array[8]}" "${array[10]}" "${array[9]}" [[ "${array[0]}" == 'CLIENT_LIST' ]] || continue
done <$STATUS_LOG
printf "%s \t %s \t " "${array[1]}" "${array[2]}"
printf "%s \t " "${array[3]}"
if [[ "${HR}" == 1 ]]; then
printf "%s \t %s" "$(hr "${array[4]}")" "$(hr "${array[5]}")"
else else
while read -r line; do printf "%'d \t %'d" "${array[4]}" "${array[5]}"
read -r -a array <<< "$line"
[[ ${array[0]} = CLIENT_LIST ]] || continue
printf "%s \t %s \t %s \t %'d \t %'d \t %s %s %s - %s\n" "${array[1]}" "${array[2]}" "${array[3]}" "${array[4]}" "${array[5]}" "${array[7]}" "${array[8]}" "${array[10]}" "${array[9]}"
done <$STATUS_LOG
fi fi
printf " \t %s %s %s " "${array[7]}" "${array[8]}" "${array[10]}"
printf "- %s\n" "${array[9]}"
done < "${STATUS_LOG}"
else else
awk -F' ' -v s='CLIENT_LIST' '$1 == s {print $2"\t\t"$3"\t"$4"\t"$5"\t\t"$6"\t\t"$8" "$9" "$11" - "$10"\n"}' ${STATUS_LOG} awk -F ' ' -v s='CLIENT_LIST' \
'$1 == s {
print $2"\t\t"$3"\t"$4"\t"$5"\t\t"$6"\t\t"$8" "$9" "$11" - "$10"\n"
}' \
"${STATUS_LOG}"
fi fi
else else
printf "\nNo Clients Connected!\n" printf "\nNo Clients Connected!\n"
@ -59,12 +72,12 @@ listClients(){
} | column -t -s $'\t' } | column -t -s $'\t'
} }
if [[ $# -eq 0 ]]; then if [[ "$#" -eq 0 ]]; then
HR=1 HR=1
listClients listClients
else else
while true; do while true; do
case "$1" in case "${1}" in
-b | bytes) -b | bytes)
HR=0 HR=0
listClients listClients

View file

@ -1,42 +1,57 @@
#!/usr/bin/env bash #!/bin/bash
# PiVPN: list clients script # PiVPN: list clients script
# Updated Script to include Expiration Dates and Clean up Escape Seq -- psgoundar # Updated Script to include Expiration Dates and
# Clean up Escape Seq -- psgoundar
INDEX="/etc/openvpn/easy-rsa/pki/index.txt" INDEX="/etc/openvpn/easy-rsa/pki/index.txt"
if [ ! -f "${INDEX}" ]; then
echo "The file: $INDEX was not found!" err() {
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
}
if [[ ! -f "${INDEX}" ]]; then
err "The file: ${INDEX} was not found!"
exit 1 exit 1
fi fi
EASYRSA="/etc/openvpn/easy-rsa/easyrsa" EASYRSA="/etc/openvpn/easy-rsa/easyrsa"
if [ ! -f "${EASYRSA}" ]; then
echo "The file: $EASYRSA was not found!" if [[ ! -f "${EASYRSA}" ]]; then
err "The file: ${EASYRSA} was not found!"
exit 1 exit 1
fi fi
$EASYRSA update-db >> /dev/null 2>&1 "${EASYRSA}" update-db >> /dev/null 2>&1
printf ": NOTE : The first entry is your server, which should always be valid!\n" printf ": NOTE : The first entry is your server, "
printf "which should always be valid!\n"
printf "\\n" printf "\\n"
printf "\\e[1m::: Certificate Status List :::\\e[0m\\n" printf "\\e[1m::: Certificate Status List :::\\e[0m\\n"
{ {
printf "\\e[4mStatus\\e[0m \t \\e[4mName\\e[0m\\e[0m \t \\e[4mExpiration\\e[0m\\n" printf "\\e[4mStatus\\e[0m \t \\e[4mName\\e[0m\\e[0m \t "
printf "\\e[4mExpiration\\e[0m\\n"
while read -r line || [ -n "$line" ]; do while read -r line || [[ -n "${line}" ]]; do
STATUS=$(echo "$line" | awk '{print $1}') STATUS="$(echo "${line}" | awk '{print $1}')"
NAME=$(echo "$line" | awk -FCN= '{print $2}') NAME="$(echo "${line}" | awk -FCN= '{print $2}')"
EXPD=$(echo "$line" | awk '{if (length($2) == 15) print $2; else print "20"$2}' | cut -b 1-8 | date +"%b %d %Y" -f -) EXPD="$(echo "${line}" \
| awk '{if (length($2) == 15) print $2; else print "20"$2}' \
| cut -b 1-8 \
| date +"%b %d %Y" -f -)"
if [ "${STATUS}" == "V" ]; then if [[ "${STATUS}" == "V" ]]; then
printf "Valid \t %s \t %s\\n" "$(echo -e "$NAME")" "$EXPD" printf "Valid"
elif [ "${STATUS}" == "R" ]; then elif [[ "${STATUS}" == "R" ]]; then
printf "Revoked \t %s \t %s\\n" "$(echo -e "$NAME")" "$EXPD" printf "Revoked"
elif [ "${STATUS}" == "E" ]; then elif [[ "${STATUS}" == "E" ]]; then
printf "Expired \t %s \t %s\\n" "$(echo -e "$NAME")" "$EXPD" printf "Expired"
else else
printf "Unknown \t %s \t %s\\n" "$(echo -e "$NAME")" "$EXPD" printf "Unknown"
fi fi
done <${INDEX} printf " \t %s \t %s\\n" "$(echo -e "${NAME}")" "${EXPD}"
done < "${INDEX}"
printf "\\n" printf "\\n"
} | column -t -s $'\t' } | column -t -s $'\t'

View file

@ -1,4 +1,5 @@
#!/bin/bash #!/bin/bash
# Create OVPN Client # Create OVPN Client
# Default Variable Declarations # Default Variable Declarations
setupVars="/etc/pivpn/openvpn/setupVars.conf" setupVars="/etc/pivpn/openvpn/setupVars.conf"
@ -10,74 +11,100 @@ CA="ca.crt"
TA="ta.key" TA="ta.key"
INDEX="/etc/openvpn/easy-rsa/pki/index.txt" INDEX="/etc/openvpn/easy-rsa/pki/index.txt"
if [ ! -f "${setupVars}" ]; then if [[ ! -f "${setupVars}" ]]; then
echo "::: Missing setup vars file!" err "::: Missing setup vars file!"
exit 1 exit 1
fi fi
# shellcheck disable=SC1090 # shellcheck disable=SC1090
source "${setupVars}" source "${setupVars}"
err() {
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
}
helpFunc() { helpFunc() {
echo "::: Create a client ovpn profile, optional nopass" echo "::: Create a client ovpn profile, optional nopass"
echo ":::" echo ":::"
echo "::: Usage: pivpn <-a|add> [-n|--name <arg>] [-p|--password <arg>]|[nopass] [-d|--days <number>] [-b|--bitwarden] [-i|--iOS] [-o|--ovpn] [-h|--help]" echo -n "::: Usage: pivpn <-a|add> [-n|--name <arg>] "
echo -n "[-p|--password <arg>]|[nopass] [-d|--days <number>] "
echo "[-b|--bitwarden] [-i|--iOS] [-o|--ovpn] [-h|--help]"
echo ":::" echo ":::"
echo "::: Commands:" echo "::: Commands:"
echo "::: [none] Interactive mode" echo "::: [none] Interactive mode"
echo "::: nopass Create a client without a password" echo "::: nopass Create a client without a password"
echo "::: -n,--name Name for the Client (default: \"$(hostname)\")" echo -n "::: -n,--name Name for the Client "
echo "(default: \"$(hostname)\")"
echo "::: -p,--password Password for the Client (no default)" echo "::: -p,--password Password for the Client (no default)"
echo "::: -d,--days Expire the certificate after specified number of days (default: 1080)" echo -n "::: -d,--days Expire the certificate after specified "
echo "number of days (default: 1080)"
echo "::: -b,--bitwarden Create and save a client through Bitwarden" echo "::: -b,--bitwarden Create and save a client through Bitwarden"
echo "::: -i,--iOS Generate a certificate that leverages iOS keychain" echo -n "::: -i,--iOS Generate a certificate that leverages iOS "
echo "::: -o,--ovpn Regenerate a .ovpn config file for an existing client" echo "keychain"
echo -n "::: -o,--ovpn Regenerate a .ovpn config file for an "
echo "existing client"
echo "::: -h,--help Show this help dialog" echo "::: -h,--help Show this help dialog"
} }
if [ -z "$HELP_SHOWN" ]; then if [[ -z "${HELP_SHOWN}" ]]; then
helpFunc helpFunc
echo echo
echo "HELP_SHOWN=1" >> "$setupVars" echo "HELP_SHOWN=1" >> "${setupVars}"
fi fi
# Parse input arguments # Parse input arguments
while test $# -gt 0; do while [[ "$#" -gt 0 ]]; do
_key="$1" _key="${1}"
case "$_key" in
case "${_key}" in
-n | --name | --name=*) -n | --name | --name=*)
_val="${_key##--name=}" _val="${_key##--name=}"
if test "$_val" = "$_key"; then
test $# -lt 2 && echo "Missing value for the optional argument '$_key'." && exit 1 if [[ "${_val}" == "${_key}" ]]; then
_val="$2" [[ "$#" -lt 2 ]] \
&& err "Missing value for the optional argument '${_key}'." \
&& exit 1
_val="${2}"
shift shift
fi fi
NAME="$_val"
NAME="${_val}"
;; ;;
-p | --password | --password=*) -p | --password | --password=*)
_val="${_key##--password=}" _val="${_key##--password=}"
if test "$_val" = "$_key"; then
test $# -lt 2 && echo "Missing value for the optional argument '$_key'." && exit 1 if [[ "${_val}" == "${_key}" ]]; then
_val="$2" [[ "$#" -lt 2 ]] \
&& err "Missing value for the optional argument '${_key}'." \
&& exit 1
_val="${2}"
shift shift
fi fi
PASSWD="$_val"
PASSWD="${_val}"
;; ;;
-d | --days | --days=*) -d | --days | --days=*)
_val="${_key##--days=}" _val="${_key##--days=}"
if test "$_val" = "$_key"; then
test $# -lt 2 && echo "Missing value for the optional argument '$_key'." && exit 1 if [[ "${_val}" == "${_key}" ]]; then
_val="$2" [[ "$#" -lt 2 ]] \
&& err "Missing value for the optional argument '${_key}'." \
&& exit 1
_val="${2}"
shift shift
fi fi
DAYS="$_val"
DAYS="${_val}"
;; ;;
-i | --iOS) -i | --iOS)
if [ "$TWO_POINT_FOUR" -ne 1 ]; then if [[ "${TWO_POINT_FOUR}" -ne 1 ]]; then
iOS=1 iOS=1
else else
echo "Sorry, can't generate iOS-specific configs for ECDSA certificates" err "Sorry, can't generate iOS-specific configs for ECDSA certificates"
echo "Generate traditional certificates using 'pivpn -a' or reinstall PiVPN without opting in for OpenVPN 2.4 features" err "Generate traditional certificates using 'pivpn -a' or reinstall PiVPN without opting in for OpenVPN 2.4 features"
exit 1 exit 1
fi fi
;; ;;
@ -94,15 +121,17 @@ while test $# -gt 0; do
else else
echo 'Bitwarden not found, please install bitwarden' echo 'Bitwarden not found, please install bitwarden'
if [ "${PLAT}" == 'Alpine' ]; then if [[ "${PLAT}" == 'Alpine' ]]; then
echo 'You can download it through the following commands:' echo 'You can download it through the following commands:'
echo $'\t' 'curl -fLo bitwarden.zip --no-cache https://github.com/bitwarden/clients/releases/download/cli-v2022.6.2/bw-linux-2022.6.2.zip' echo -n $'\t''curl -fLo bitwarden.zip --no-cache https://github.com/'
echo $'\t' 'apk --no-cache -X https://dl-cdn.alpinelinux.org/alpine/edge/testing/ add atool' echo -n 'bitwarden/clients/releases/download/cli-v2022.6.2/'
echo $'\t' 'aunpack -F zip bitwarden.zip' echo 'bw-linux-2022.6.2.zip'
echo $'\t''apk --no-cache unzip'
echo $'\t''unzip bitwarden.zip'
echo $'\t''mv bw /opt/bw' echo $'\t''mv bw /opt/bw'
echo $'\t''chmod 755 /opt/bw' echo $'\t''chmod 755 /opt/bw'
echo $'\t''rm bitwarden.zip' echo $'\t''rm bitwarden.zip'
echo $'\t' 'apk --no-cache --purge del -r atool' echo $'\t''apk --no-cache --purge del -r unzip'
fi fi
exit 1 exit 1
@ -113,18 +142,18 @@ while test $# -gt 0; do
GENOVPNONLY=1 GENOVPNONLY=1
;; ;;
*) *)
echo "Error: Got an unexpected argument '$1'" err "Error: Got an unexpected argument '${1}'"
helpFunc helpFunc
exit 1 exit 1
;; ;;
esac esac
shift shift
done done
# Functions def # Functions def
function keynoPASS() { keynoPASS() {
# Build the client key # Build the client key
expect << EOF expect << EOF
set timeout -1 set timeout -1
@ -132,18 +161,17 @@ function keynoPASS() {
spawn ./easyrsa build-client-full "${NAME}" nopass spawn ./easyrsa build-client-full "${NAME}" nopass
expect eof expect eof
EOF EOF
cd pki || exit cd pki || exit
} }
function useBitwarden() { useBitwarden() {
# login and unlock vault # login and unlock vault
printf "****Bitwarden Login****" printf "****Bitwarden Login****"
printf "\n" printf "\n"
SESSION_KEY=$(bw login --raw)
export BW_SESSION=$SESSION_KEY SESSION_KEY="$(bw login --raw)"
export BW_SESSION="${SESSION_KEY}"
printf "Successfully Logged in!" printf "Successfully Logged in!"
printf "\n" printf "\n"
@ -152,39 +180,50 @@ function useBitwarden() {
read -r NAME read -r NAME
# check name # check name
until [[ "$NAME" =~ ^[a-zA-Z0-9.@_-]+$ && ${NAME::1} != "." && ${NAME::1} != "-" ]]; do until [[ "${NAME}" =~ ^[a-zA-Z0-9.@_-]+$ ]] \
echo "Name can only contain alphanumeric characters and these characters (.-@_). The name also cannot start with a dot (.) or a dash (-). Please try again." && [[ "${NAME::1}" != "." ]] \
&& [[ "${NAME::1}" != "-" ]]; do
echo -n "Name can only contain alphanumeric characters and these "
echo -n "characters (.-@_). The name also cannot start with a dot (.)"
echo " or a dash (-). Please try again."
# ask user for username again # ask user for username again
printf "Enter the username: " printf "Enter the username: "
read -r NAME read -r NAME
done done
# ask user for length of password # ask user for length of password
printf "Please enter the length of characters you want your password to be (minimum 12): " printf "Please enter the length of characters you want your password to be "
printf "(minimum 12): "
read -r LENGTH read -r LENGTH
# check length # check length
until [[ "$LENGTH" -gt 11 && "$LENGTH" -lt 129 ]]; do until [[ "${LENGTH}" -gt 11 ]] && [[ "${LENGTH}" -lt 129 ]]; do
echo "Password must be between from 12 to 128 characters, please try again." echo "Password must be between from 12 to 128 characters, please try again."
# ask user for length of password # ask user for length of password
printf "Enter the length of characters you want your password to be (minimum 12): " printf "Please enter the length of characters you want your password to be "
printf "(minimum 12): "
read -r LENGTH read -r LENGTH
done done
printf "Creating a PiVPN item for your vault..." printf "Creating a PiVPN item for your vault..."
printf "\n" printf "\n"
# create a new item for your PiVPN Password
PASSWD=$(bw generate -usln --length "$LENGTH")
bw get template item | jq '.login.type = "1"'| jq '.name = "PiVPN"' | jq -r --arg NAME "$NAME" '.login.username = $NAME' | jq -r --arg PASSWD "$PASSWD" '.login.password = $PASSWD' | bw encode | bw create item
bw logout
# create a new item for your PiVPN Password
PASSWD="$(bw generate -usln --length "${LENGTH}")"
bw get template item \
| jq '.login.type = "1"' \
| jq '.name = "PiVPN"' \
| jq -r --arg NAME "${NAME}" '.login.username = $NAME' \
| jq -r --arg PASSWD "${PASSWD}" '.login.password = $PASSWD' \
| bw encode \
| bw create item
bw logout
} }
function keyPASS() { keyPASS() {
if [[ -z "${PASSWD}" ]]; then if [[ -z "${PASSWD}" ]]; then
stty -echo stty -echo
while true; do while true; do
printf "Enter the password for the client: " printf "Enter the password for the client: "
read -r PASSWD read -r PASSWD
@ -192,28 +231,64 @@ function keyPASS() {
printf "Enter the password again to verify: " printf "Enter the password again to verify: "
read -r PASSWD2 read -r PASSWD2
printf "\n" printf "\n"
[ "${PASSWD}" = "${PASSWD2}" ] && break
[[ "${PASSWD}" == "${PASSWD2}" ]] && break
printf "Passwords do not match! Please try again.\n" printf "Passwords do not match! Please try again.\n"
done done
stty echo stty echo
if [[ -z "${PASSWD}" ]]; then if [[ -z "${PASSWD}" ]]; then
echo "You left the password blank" err "You left the password blank"
echo "If you don't want a password, please run:" err "If you don't want a password, please run:"
echo "pivpn add nopass" err "pivpn add nopass"
exit 1 exit 1
fi fi
fi fi
if [ ${#PASSWD} -lt 4 ] || [ ${#PASSWD} -gt 1024 ]; then
echo "Password must be between from 4 to 1024 characters" if [[ "${#PASSWD}" -lt 4 ]] || [[ "${#PASSWD}" -gt 1024 ]]; then
err "Password must be between from 4 to 1024 characters"
exit 1 exit 1
fi fi
# Escape chars in PASSWD # Escape chars in PASSWD
PASSWD_UNESCAPED="${PASSWD}" PASSWD_UNESCAPED="${PASSWD}"
PASSWD=$(echo -n "${PASSWD}" | sed -E -e 's/\\/\\\\/g' -e 's/\//\\\//g' -e 's/\$/\\\$/g' -e 's/!/\\!/g' -e 's/\./\\\./g' -e "s/'/\\'/g" -e 's/"/\\"/g' -e 's/\*/\\\*/g' -e 's/@/\\@/g' -e 's/#/\\#/g' -e 's/£/\\£/g' -e 's/%/\\%/g' -e 's/\^/\\\^/g' -e 's/&/\\&/g' -e 's/\(/\\\(/g' -e 's/\)/\\\)/g' -e 's/\-/\\\-/g' -e 's/_/\\_/g' -e 's/\+/\\\+/g' -e 's/=/\\=/g' -e 's/\[/\\\[/g' -e 's/\]/\\\]/g' -e 's/;/\\;/g' -e 's/:/\\:/g' -e 's/\|/\\\|/g' -e 's/\</\\\</g' -e 's/\>/\\\>/g' -e 's/,/\\,/g' -e 's/\?/\\\?/g' -e 's/~/\\~/g' -e 's/\{/\\\{/g' -e 's/\}/\\\}/g')
PASSWD="${PASSWD//\\/\\\\}"
PASSWD="${PASSWD//\//\\\/}"
PASSWD="${PASSWD//\$/\\\$}"
PASSWD="${PASSWD//!/\\!}"
PASSWD="${PASSWD//\./\\\.}"
PASSWD="${PASSWD//\'/\\\'}"
PASSWD="${PASSWD//\"/\\\"}"
PASSWD="${PASSWD//*/\\*}"
PASSWD="${PASSWD//@/\\@}"
PASSWD="${PASSWD//#/\\#}"
PASSWD="${PASSWD///\\}"
PASSWD="${PASSWD//%/\\%}"
PASSWD="${PASSWD//\^/\\\^}"
PASSWD="${PASSWD//\&/\\\&}"
PASSWD="${PASSWD//\(/\\\(}"
PASSWD="${PASSWD//\)/\\\)}"
PASSWD="${PASSWD//\-/\\\-}"
PASSWD="${PASSWD//\_/\\\_}"
PASSWD="${PASSWD//\+/\\\+}"
PASSWD="${PASSWD//\=/\\\=}"
PASSWD="${PASSWD//\[/\\\[}"
PASSWD="${PASSWD//\]/\\\]}"
PASSWD="${PASSWD//:/\\:}"
PASSWD="${PASSWD//\;/\\\;}"
PASSWD="${PASSWD//\|/\\\|}"
PASSWD="${PASSWD//\</\\\<}"
PASSWD="${PASSWD//\>/\\\>}"
PASSWD="${PASSWD//\,/\\\,}"
PASSWD="${PASSWD//\~/\\\~}"
PASSWD="${PASSWD//\?/\\\?}"
PASSWD="${PASSWD//\{/\\\{}"
PASSWD="${PASSWD//\}/\\\}}"
# Build the client key and then encrypt the key # Build the client key and then encrypt the key
expect << EOF expect << EOF
set timeout -1 set timeout -1
set env(EASYRSA_CERT_EXPIRE) "${DAYS}" set env(EASYRSA_CERT_EXPIRE) "${DAYS}"
@ -223,16 +298,15 @@ function keyPASS() {
expect eof expect eof
EOF EOF
cd pki || exit cd pki || exit
} }
#make sure ovpns dir exists #make sure ovpns dir exists
# Disabling warning for SC2154, var sourced externaly # Disabling warning for SC2154, var sourced externaly
# shellcheck disable=SC2154 # shellcheck disable=SC2154
if [ ! -d "$install_home/ovpns" ]; then if [[ ! -d "${install_home}/ovpns" ]]; then
mkdir "$install_home/ovpns" mkdir "${install_home}/ovpns"
chown "$install_user":"$install_user" "$install_home/ovpns" chown "${install_user}:${install_user}" "${install_home}/ovpns"
chmod 0750 "$install_home/ovpns" chmod 0750 "${install_home}/ovpns"
fi fi
#bitWarden #bitWarden
@ -240,70 +314,68 @@ if [[ "${BITWARDEN}" =~ "2" ]]; then
useBitwarden useBitwarden
fi fi
if [ -z "${NAME}" ]; then if [[ -z "${NAME}" ]]; then
printf "Enter a Name for the Client: " printf "Enter a Name for the Client: "
read -r NAME read -r NAME
fi elif [[ "${NAME::1}" == "." ]] || [[ "${NAME::1}" == "-" ]]; then
err "Names cannot start with a dot (.) or a dash (-)."
if [[ ${NAME::1} == "." ]] || [[ ${NAME::1} == "-" ]]; then exit 1
echo "Names cannot start with a dot (.) or a dash (-)." elif [[ "${NAME}" =~ [^a-zA-Z0-9.@_-] ]]; then
err "Name can only contain alphanumeric characters and these symbols (.-@_)."
exit 1
elif [[ "${NAME}" =~ ^[0-9]+$ ]]; then
err "Names cannot be integers."
exit 1
elif [[ -z "${NAME}" ]]; then
err "You cannot leave the name blank."
exit 1 exit 1
fi fi
if [[ "${NAME}" =~ [^a-zA-Z0-9.@_-] ]]; then if [[ "${GENOVPNONLY}" == 1 ]]; then
echo "Name can only contain alphanumeric characters and these characters (.-@_)."
exit 1
fi
if [[ "${NAME}" =~ ^[0-9]+$ ]]; then
echo "Names cannot be integers."
exit 1
fi
if [[ -z "${NAME}" ]]; then
echo "You cannot leave the name blank."
exit 1
fi
if [ "${GENOVPNONLY}" == "1" ]; then
# Generate .ovpn configuration file # Generate .ovpn configuration file
cd /etc/openvpn/easy-rsa/pki || exit cd /etc/openvpn/easy-rsa/pki || exit
else else
# Check if name is already in use # Check if name is already in use
while read -r line || [ -n "${line}" ]; do while read -r line || [[ -n "${line}" ]]; do
STATUS=$(echo "$line" | awk '{print $1}') STATUS=$(echo "${line}" | awk '{print $1}')
if [ "${STATUS}" == "V" ]; then if [[ "${STATUS}" == "V" ]]; then
# Disabling SC2001 as ${variable//search/replace} doesn't go well with regexp # Disabling SC2001 as ${variable//search/replace}
# doesn't go well with regexp
# shellcheck disable=SC2001 # shellcheck disable=SC2001
CERT=$(echo "$line" | sed -e 's:.*/CN=::') CERT="$(echo "${line}" | sed -e 's:.*/CN=::')"
if [ "${CERT}" == "${NAME}" ]; then
if [[ "${CERT}" == "${NAME}" ]]; then
INUSE="1" INUSE="1"
break break
fi fi
fi fi
done <${INDEX} done < "${INDEX}"
if [ "${INUSE}" == "1" ]; then if [[ "${INUSE}" == 1 ]]; then
printf "\n!! This name is already in use by a Valid Certificate." err "!! This name is already in use by a Valid Certificate."
printf "\nPlease choose another name or revoke this certificate first.\n" err "Please choose another name or revoke this certificate first."
exit 1 exit 1
fi
# Check if name is reserved # Check if name is reserved
if [ "${NAME}" == "ta" ] || [ "${NAME}" == "server" ] || [ "${NAME}" == "ca" ]; then elif [[ "${NAME}" == "ta" ]] \
echo "Sorry, this is in use by the server and cannot be used by clients." || [[ "${NAME}" == "server" ]] \
|| [[ "${NAME}" == "ca" ]]; then
err "Sorry, this is in use by the server and cannot be used by clients."
exit 1 exit 1
fi fi
#As of EasyRSA 3.0.6, by default certificates last 1080 days, see https://github.com/OpenVPN/easy-rsa/blob/6b7b6bf1f0d3c9362b5618ad18c66677351cacd1/easyrsa3/vars.example # As of EasyRSA 3.0.6, by default certificates last 1080 days,
if [ -z "${DAYS}" ]; then # see https://github.com/OpenVPN/easy-rsa/blob/6b7b6bf1f0d3c9362b5618ad18c66677351cacd1/easyrsa3/vars.example
if [[ -z "${DAYS}" ]]; then
read -r -e -p "How many days should the certificate last? " -i 1080 DAYS read -r -e -p "How many days should the certificate last? " -i 1080 DAYS
fi fi
if [[ ! "$DAYS" =~ ^[0-9]+$ ]] || [ "$DAYS" -lt 1 ] || [ "$DAYS" -gt 3650 ]; then if [[ ! "${DAYS}" =~ ^[0-9]+$ ]] \
#The CRL lasts 3650 days so it doesn't make much sense that certificates would last longer || [[ "${DAYS}" -lt 1 ]] \
echo "Please input a valid number of days, between 1 and 3650 inclusive." || [[ "${DAYS}" -gt 3650 ]]; then
# The CRL lasts 3650 days so it doesn't make much sense
# that certificates would last longer
err "Please input a valid number of days, between 1 and 3650 inclusive."
exit 1 exit 1
fi fi
@ -311,7 +383,7 @@ else
if [[ "${NO_PASS}" =~ "1" ]]; then if [[ "${NO_PASS}" =~ "1" ]]; then
if [[ -n "${PASSWD}" ]]; then if [[ -n "${PASSWD}" ]]; then
echo "Both nopass and password arguments passed to the script. Please use either one." err "Both nopass and password arguments passed to the script. Please use either one."
exit 1 exit 1
else else
keynoPASS keynoPASS
@ -322,38 +394,43 @@ else
fi fi
#1st Verify that clients Public Key Exists #1st Verify that clients Public Key Exists
if [ ! -f "issued/${NAME}${CRT}" ]; then if [[ ! -f "issued/${NAME}${CRT}" ]]; then
echo "[ERROR]: Client Public Key Certificate not found: $NAME$CRT" err "[ERROR]: Client Public Key Certificate not found: ${NAME}${CRT}"
exit exit
fi fi
echo "Client's cert found: $NAME$CRT"
echo "Client's cert found: ${NAME}${CRT}"
#Then, verify that there is a private key for that client #Then, verify that there is a private key for that client
if [ ! -f "private/${NAME}${KEY}" ]; then if [[ ! -f "private/${NAME}${KEY}" ]]; then
echo "[ERROR]: Client Private Key not found: $NAME$KEY" err "[ERROR]: Client Private Key not found: ${NAME}${KEY}"
exit exit
fi fi
echo "Client's Private Key found: $NAME$KEY"
echo "Client's Private Key found: ${NAME}${KEY}"
#Confirm the CA public key exists #Confirm the CA public key exists
if [ ! -f "${CA}" ]; then if [[ ! -f "${CA}" ]]; then
echo "[ERROR]: CA Public Key not found: $CA" err "[ERROR]: CA Public Key not found: ${CA}"
exit exit
fi fi
echo "CA public Key found: $CA"
echo "CA public Key found: ${CA}"
#Confirm the tls key file exists #Confirm the tls key file exists
if [ ! -f "${TA}" ]; then if [[ ! -f "${TA}" ]]; then
echo "[ERROR]: tls Private Key not found: $TA" err "[ERROR]: tls Private Key not found: ${TA}"
exit exit
fi fi
echo "tls Private Key found: $TA"
echo "tls Private Key found: ${TA}"
## Added new step to create an .ovpn12 file that can be stored on iOS keychain ## Added new step to create an .ovpn12 file that can be stored on iOS keychain
## This step is more secure method and does not require the end-user to keep entering passwords, or storing the client private cert where it can be easily tampered ## This step is more secure method and does not require the end-user to keep
## entering passwords, or storing the client private cert where it can be easily
## tampered
## https://openvpn.net/faq/how-do-i-use-a-client-certificate-and-private-key-from-the-ios-keychain/ ## https://openvpn.net/faq/how-do-i-use-a-client-certificate-and-private-key-from-the-ios-keychain/
if [ "$iOS" = "1" ]; then
# Generates the .ovpn file WITHOUT the client private key # Generates the .ovpn file WITHOUT the client private key
{ {
# Start by populating with the default file # Start by populating with the default file
@ -366,55 +443,20 @@ if [ "$iOS" = "1" ]; then
# Next append the client Public Cert # Next append the client Public Cert
echo "<cert>" echo "<cert>"
sed -n -e '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' < "issued/${NAME}${CRT}" sed -n \
echo "</cert>" -e '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' \
< "issued/${NAME}${CRT}"
#Finally, append the tls Private Key
echo "<tls-auth>"
cat "${TA}"
echo "</tls-auth>"
} > "${NAME}${FILEEXT}"
# Copy the .ovpn profile to the home directory for convenient remote access
printf "========================================================\n"
printf "Generating an .ovpn12 file for use with iOS devices\n"
printf "Please remember the export password\n"
printf "as you will need this import the certificate on your iOS device\n"
printf "========================================================\n"
openssl pkcs12 -passin pass:"$PASSWD_UNESCAPED" -export -in "issued/${NAME}${CRT}" -inkey "private/${NAME}${KEY}" -certfile ${CA} -name "${NAME}" -out "$install_home/ovpns/$NAME.ovpn12"
chown "$install_user":"$install_user" "$install_home/ovpns/$NAME.ovpn12"
chmod 640 "$install_home/ovpns/$NAME.ovpn12"
printf "========================================================\n"
printf "\e[1mDone! %s successfully created!\e[0m \n" "$NAME.ovpn12"
printf "You will need to transfer both the .ovpn and .ovpn12 files\n"
printf "to your iOS device.\n"
printf "========================================================\n\n"
else
#This is the standard non-iOS configuration
#Ready to make a new .ovpn file
{
# Start by populating with the default file
cat "${DEFAULT}"
#Now, append the CA Public Cert
echo "<ca>"
cat "${CA}"
echo "</ca>"
#Next append the client Public Cert
echo "<cert>"
sed -n -e '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' < "issued/${NAME}${CRT}"
echo "</cert>" echo "</cert>"
if [[ "${iOS}" != 1 ]]; then
# Then, append the client Private Key # Then, append the client Private Key
echo "<key>" echo "<key>"
cat "private/${NAME}${KEY}" cat "private/${NAME}${KEY}"
echo "</key>" echo "</key>"
fi
# Finally, append the tls Private Key # Finally, append the tls Private Key
if [ "$TWO_POINT_FOUR" -eq 1 ]; then if [[ "${iOS}" != 1 ]] && [[ "${TWO_POINT_FOUR}" -eq 1 ]]; then
echo "<tls-crypt>" echo "<tls-crypt>"
cat "${TA}" cat "${TA}"
echo "</tls-crypt>" echo "</tls-crypt>"
@ -423,16 +465,43 @@ else
cat "${TA}" cat "${TA}"
echo "</tls-auth>" echo "</tls-auth>"
fi fi
} > "${NAME}${FILEEXT}" } > "${NAME}${FILEEXT}"
if [[ "${iOS}" == 1 ]]; then
# Copy the .ovpn profile to the home directory for convenient remote access
printf "========================================================\n"
printf "Generating an .ovpn12 file for use with iOS devices\n"
printf "Please remember the export password\n"
printf "as you will need this import the certificate on your iOS device\n"
printf "========================================================\n"
openssl pkcs12 \
-passin pass:"${PASSWD_UNESCAPED}" \
-export \
-in "issued/${NAME}${CRT}" \
-inkey "private/${NAME}${KEY}" \
-certfile "${CA}" \
-name "${NAME}" \
-out "${install_home}/ovpns/${NAME}.ovpn12"
chown "${install_user}:${install_user}" "${install_home}/ovpns/${NAME}.ovpn12"
chmod 640 "${install_home}/ovpns/${NAME}.ovpn12"
printf "========================================================\n"
printf "\e[1mDone! %s successfully created!\e[0m \n" "${NAME}.ovpn12"
printf "You will need to transfer both the .ovpn and .ovpn12 files\n"
printf "to your iOS device.\n"
printf "========================================================\n\n"
fi fi
cidrToMask() { cidrToMask() {
# Source: https://stackoverflow.com/a/20767392 # Source: https://stackoverflow.com/a/20767392
set -- $(( 5 - ($1 / 8) )) 255 255 255 255 $(( (255 << (8 - ($1 % 8))) & 255 )) 0 0 0 set -- $((5 - (${1} / 8))) \
shift "$1" 255 255 255 255 \
echo "${1-0}"."${2-0}"."${3-0}"."${4-0}" $(((255 << (8 - (${1} % 8))) & 255)) \
0 0 0
shift "${1}"
echo "${1-0}.${2-0}.${3-0}.${4-0}"
} }
#disabling SC2514, variable sourced externaly #disabling SC2514, variable sourced externaly
@ -446,32 +515,39 @@ for i in {2..254}; do
# cycle to the end without finding and available octet. # cycle to the end without finding and available octet.
# disabling SC2514, variable sourced externaly # disabling SC2514, variable sourced externaly
# shellcheck disable=SC2154 # shellcheck disable=SC2154
if [ -z "$(ls -A /etc/openvpn/ccd)" ] || ! find /etc/openvpn/ccd -type f -exec grep -q "${NET_REDUCED}.${i}" {} +; then if [[ -z "$(ls -A /etc/openvpn/ccd)" ]] \
|| ! find /etc/openvpn/ccd -type f \
-exec grep -q "${NET_REDUCED}.${i}" {} +; then
COUNT="${i}" COUNT="${i}"
echo "ifconfig-push ${NET_REDUCED}.${i} $(cidrToMask "$subnetClass")" >> /etc/openvpn/ccd/"${NAME}" echo -n "ifconfig-push ${NET_REDUCED}.${i}" >> /etc/openvpn/ccd/"${NAME}"
cidrToMask "${subnetClass}" >> /etc/openvpn/ccd/"${NAME}"
break break
fi fi
done done
if [ -f /etc/pivpn/hosts.openvpn ]; then if [[ -f /etc/pivpn/hosts.openvpn ]]; then
echo "${NET_REDUCED}.${COUNT} ${NAME}.pivpn" >> /etc/pivpn/hosts.openvpn echo "${NET_REDUCED}.${COUNT} ${NAME}.pivpn" >> /etc/pivpn/hosts.openvpn
if killall -SIGHUP pihole-FTL; then if killall -SIGHUP pihole-FTL; then
echo "::: Updated hosts file for Pi-hole" echo "::: Updated hosts file for Pi-hole"
else else
echo "::: Failed to reload pihole-FTL configuration" err "::: Failed to reload pihole-FTL configuration"
fi fi
fi fi
# Copy the .ovpn profile to the home directory for convenient remote access # Copy the .ovpn profile to the home directory for convenient remote access
cp "/etc/openvpn/easy-rsa/pki/$NAME$FILEEXT" "$install_home/ovpns/$NAME$FILEEXT" dest_path="${install_home}/ovpns/${NAME}${FILEEXT}"
chown "$install_user":"$install_user" "$install_home/ovpns/$NAME$FILEEXT" cp "/etc/openvpn/easy-rsa/pki/${NAME}${FILEEXT}" "${dest_path}"
chmod 640 "/etc/openvpn/easy-rsa/pki/$NAME$FILEEXT" chown "${install_user}:${install_user}" "${dest_path}"
chmod 640 "$install_home/ovpns/$NAME$FILEEXT" chmod 640 "/etc/openvpn/easy-rsa/pki/${NAME}${FILEEXT}"
chmod 640 "${dest_path}"
unset dest_path
printf "\n\n" printf "\n\n"
printf "========================================================\n" printf "========================================================\n"
printf "\e[1mDone! %s successfully created!\e[0m \n" "$NAME$FILEEXT" printf "\e[1mDone! %s successfully created!\e[0m \n" "${NAME}${FILEEXT}"
printf "%s was copied to:\n" "$NAME$FILEEXT" printf "%s was copied to:\n" "${NAME}${FILEEXT}"
printf " %s/ovpns\n" "$install_home" printf " %s/ovpns\n" "${install_home}"
printf "for easy transfer. Please use this profile only on one\n" printf "for easy transfer. Please use this profile only on one\n"
printf "device and create additional profiles for other devices.\n" printf "device and create additional profiles for other devices.\n"
printf "========================================================\n\n" printf "========================================================\n\n"

View file

@ -7,11 +7,11 @@ if grep -qsEe "^NAME\=['\"]?Alpine[a-zA-Z ]*['\"]?$" /etc/os-release; then
fi fi
# Must be root to use this tool # Must be root to use this tool
if [[ ! $EUID -eq 0 ]]; then if [[ "${EUID}" -ne 0 ]]; then
if eval "${CHECK_PKG_INSTALLED} sudo" &> /dev/null; then if ${CHECK_PKG_INSTALLED} sudo &> /dev/null; then
export SUDO="sudo" export SUDO="sudo"
else else
echo "::: Please install sudo or run this as root." err "::: Please install sudo or run this as root."
exit 1 exit 1
fi fi
fi fi
@ -19,57 +19,62 @@ fi
scriptDir="/opt/pivpn" scriptDir="/opt/pivpn"
vpn="openvpn" vpn="openvpn"
function makeOVPNFunc { err() {
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
}
makeOVPNFunc() {
shift shift
$SUDO ${scriptDir}/${vpn}/makeOVPN.sh "$@" ${SUDO} "${scriptDir}/${vpn}/makeOVPN.sh" "$@"
exit "$?" exit "${?}"
} }
function listClientsFunc { listClientsFunc() {
shift shift
$SUDO ${scriptDir}/${vpn}/clientStat.sh "$@" ${SUDO} "${scriptDir}/${vpn}/clientStat.sh" "$@"
exit "$?" exit "${?}"
} }
function listOVPNFunc { listOVPNFunc() {
$SUDO ${scriptDir}/${vpn}/listOVPN.sh ${SUDO} "${scriptDir}/${vpn}/listOVPN.sh"
exit "$?" exit "${?}"
} }
function debugFunc { debugFunc() {
echo "::: Generating Debug Output" echo "::: Generating Debug Output"
$SUDO ${scriptDir}/${vpn}/pivpnDebug.sh | tee /tmp/debug.log
${SUDO} "${scriptDir}/${vpn}/pivpnDebug.sh" | tee /tmp/debug.log
echo "::: " echo "::: "
echo "::: Debug output completed above." echo "::: Debug output completed above."
echo "::: Copy saved to /tmp/debug.log" echo "::: Copy saved to /tmp/debug.log"
echo "::: " echo "::: "
exit "$?" exit "${?}"
} }
function removeOVPNFunc { removeOVPNFunc() {
shift shift
$SUDO ${scriptDir}/${vpn}/removeOVPN.sh "$@" ${SUDO} "${scriptDir}/${vpn}/removeOVPN.sh" "$@"
exit "$?" exit "${?}"
} }
function uninstallFunc { uninstallFunc() {
$SUDO ${scriptDir}/uninstall.sh "${vpn}" ${SUDO} "${scriptDir}/uninstall.sh" "${vpn}"
exit "$?" exit "${?}"
} }
function update { update() {
shift shift
$SUDO ${scriptDir}/update.sh "$@" ${SUDO} "${scriptDir}/update.sh" "$@"
exit "$?" exit "${?}"
} }
function backup { backup() {
$SUDO ${scriptDir}/backup.sh "${vpn}" ${SUDO} "${scriptDir}/backup.sh" "${vpn}"
exit "$?" exit "${?}"
} }
helpFunc() {
function helpFunc {
echo "::: Control all PiVPN specific functions!" echo "::: Control all PiVPN specific functions!"
echo ":::" echo ":::"
echo "::: Usage: pivpn <command> [option]" echo "::: Usage: pivpn <command> [option]"
@ -87,20 +92,40 @@ function helpFunc {
exit 0 exit 0
} }
if [[ $# = 0 ]]; then if [[ "$#" == 0 ]]; then
helpFunc helpFunc
fi fi
# Handle redirecting to specific functions based on arguments # Handle redirecting to specific functions based on arguments
case "$1" in case "${1}" in
"-a" | "add" ) makeOVPNFunc "$@";; "-a" | "add")
"-c" | "clients" ) listClientsFunc "$@";; makeOVPNFunc "$@"
"-d" | "debug" ) debugFunc;; ;;
"-l" | "list" ) listOVPNFunc;; "-c" | "clients")
"-r" | "revoke" ) removeOVPNFunc "$@";; listClientsFunc "$@"
"-h" | "help" ) helpFunc;; ;;
"-u" | "uninstall" ) uninstallFunc;; "-d" | "debug")
"-up"| "update" ) update "$@" ;; debugFunc
"-bk"| "backup" ) backup;; ;;
* ) helpFunc;; "-l" | "list")
listOVPNFunc
;;
"-r" | "revoke")
removeOVPNFunc "$@"
;;
"-h" | "help")
helpFunc
;;
"-u" | "uninstall")
uninstallFunc
;;
"-up" | "update")
update "$@"
;;
"-bk" | "backup")
backup
;;
*)
helpFunc
;;
esac esac

View file

@ -1,10 +1,14 @@
#!/usr/bin/env bash #!/bin/bash
# This scripts runs as root # This scripts runs as root
setupVars="/etc/pivpn/openvpn/setupVars.conf" setupVars="/etc/pivpn/openvpn/setupVars.conf"
if [ ! -f "${setupVars}" ]; then err() {
echo "::: Missing setup vars file!" echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
}
if [[ ! -f "${setupVars}" ]]; then
err "::: Missing setup vars file!"
exit 1 exit 1
fi fi
@ -15,41 +19,62 @@ echo -e "::::\t\t\e[4mPiVPN debug\e[0m\t\t ::::"
printf "=============================================\n" printf "=============================================\n"
echo -e "::::\t\t\e[4mLatest commit\e[0m\t\t ::::" echo -e "::::\t\t\e[4mLatest commit\e[0m\t\t ::::"
echo -n "Branch: " echo -n "Branch: "
git --git-dir /usr/local/src/pivpn/.git rev-parse --abbrev-ref HEAD git --git-dir /usr/local/src/pivpn/.git rev-parse --abbrev-ref HEAD
git --git-dir /usr/local/src/pivpn/.git log -n 1 --format='Commit: %H%nAuthor: %an%nDate: %ad%nSummary: %s' git \
--git-dir /usr/local/src/pivpn/.git log -n 1 \
--format='Commit: %H%nAuthor: %an%nDate: %ad%nSummary: %s'
printf "=============================================\n" printf "=============================================\n"
echo -e "::::\t \e[4mInstallation settings\e[0m \t ::::" echo -e "::::\t \e[4mInstallation settings\e[0m \t ::::"
# shellcheck disable=SC2154 # shellcheck disable=SC2154
sed "s/$pivpnHOST/REDACTED/" < ${setupVars} sed "s/${pivpnHOST}/REDACTED/" < "${setupVars}"
printf "=============================================\n" printf "=============================================\n"
echo -e ":::: \e[4mServer configuration shown below\e[0m ::::" echo -e ":::: \e[4mServer configuration shown below\e[0m ::::"
cat /etc/openvpn/server.conf cat /etc/openvpn/server.conf
printf "=============================================\n" printf "=============================================\n"
echo -e ":::: \e[4mClient template file shown below\e[0m ::::" echo -e ":::: \e[4mClient template file shown below\e[0m ::::"
sed "s/$pivpnHOST/REDACTED/" < /etc/openvpn/easy-rsa/pki/Default.txt
sed "s/${pivpnHOST}/REDACTED/" < /etc/openvpn/easy-rsa/pki/Default.txt
printf "=============================================\n" printf "=============================================\n"
echo -e ":::: \t\e[4mRecursive list of files in\e[0m\t ::::\n::: \e[4m/etc/openvpn/easy-rsa/pki shows below\e[0m :::" echo -e ":::: \t\e[4mRecursive list of files in\e[0m\t ::::\n"
echo -e "::: \e[4m/etc/openvpn/easy-rsa/pki shows below\e[0m :::"
ls -LR /etc/openvpn/easy-rsa/pki/ -Ireqs -Icerts_by_serial ls -LR /etc/openvpn/easy-rsa/pki/ -Ireqs -Icerts_by_serial
printf "=============================================\n" printf "=============================================\n"
echo -e "::::\t\t\e[4mSelf check\e[0m\t\t ::::" echo -e "::::\t\t\e[4mSelf check\e[0m\t\t ::::"
/opt/pivpn/self_check.sh "${VPN}" /opt/pivpn/self_check.sh "${VPN}"
printf "=============================================\n" printf "=============================================\n"
echo -e ":::: Having trouble connecting? Take a look at the FAQ:" echo -e ":::: Having trouble connecting? Take a look at the FAQ:"
echo -e ":::: \e[1mhttps://docs.pivpn.io/faq\e[0m" echo -e ":::: \e[1mhttps://docs.pivpn.io/faq\e[0m"
printf "=============================================\n" printf "=============================================\n"
if [ "${PLAT}" != 'Alpine' ]; then if [[ "${PLAT}" != 'Alpine' ]]; then
echo -e ":::: \e[4mSnippet of the server log\e[0m ::::" echo -e ":::: \e[4mSnippet of the server log\e[0m ::::"
OVPNLOG="$(tail -n 20 /var/log/openvpn.log)" OVPNLOG="$(tail -n 20 /var/log/openvpn.log)"
# Regular expession taken from https://superuser.com/a/202835, it will match invalid IPs # Regular expession taken from https://superuser.com/a/202835,
# like 123.456.789.012 but it's fine since the log only contains valid ones. # it will match invalid IPs like 123.456.789.012 but it's fine
declare -a IPS_TO_HIDE=("$(grepcidr -v 10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 <<< "$OVPNLOG" | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | uniq)") # since the log only contains valid ones.
declare -a IPS_TO_HIDE=("$(echo "${OVPNLOG}" \
| grepcidr -v 10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 \
| grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' \
| uniq)")
for IP in "${IPS_TO_HIDE[@]}"; do for IP in "${IPS_TO_HIDE[@]}"; do
OVPNLOG="${OVPNLOG//"$IP"/REDACTED}" OVPNLOG="${OVPNLOG//"$IP"/REDACTED}"
done done
echo "$OVPNLOG" echo "${OVPNLOG}"
printf "=============================================\n" printf "=============================================\n"
fi fi
echo -e "::::\t\t\e[4mDebug complete\e[0m\t\t ::::" echo -e "::::\t\t\e[4mDebug complete\e[0m\t\t ::::"

View file

@ -1,21 +1,26 @@
#!/usr/bin/env bash #!/bin/bash
# PiVPN: revoke client script # PiVPN: revoke client script
setupVars="/etc/pivpn/openvpn/setupVars.conf" setupVars="/etc/pivpn/openvpn/setupVars.conf"
INDEX="/etc/openvpn/easy-rsa/pki/index.txt" INDEX="/etc/openvpn/easy-rsa/pki/index.txt"
if [ ! -f "${setupVars}" ]; then if [[ ! -f "${setupVars}" ]]; then
echo "::: Missing setup vars file!" err "::: Missing setup vars file!"
exit 1 exit 1
fi fi
# shellcheck disable=SC1090 # shellcheck disable=SC1090
source "${setupVars}" source "${setupVars}"
err() {
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
}
helpFunc() { helpFunc() {
echo "::: Revoke a client ovpn profile" echo "::: Revoke a client ovpn profile"
echo ":::" echo ":::"
echo "::: Usage: pivpn <-r|revoke> [-y|--yes] [-h|--help] [<client-1>] ... [<client-n>] ..." echo -n "::: Usage: pivpn <-r|revoke> [-y|--yes] [-h|--help] "
echo "[<client-1> ... [<client-2>] ...]"
echo ":::" echo ":::"
echo "::: Commands:" echo "::: Commands:"
echo "::: [none] Interactive mode" echo "::: [none] Interactive mode"
@ -25,9 +30,10 @@ helpFunc() {
} }
# Parse input arguments # Parse input arguments
while test $# -gt 0; do while [[ "$#" -gt 0 ]]; do
_key="$1" _key="${1}"
case "$_key" in
case "${_key}" in
-h | --help) -h | --help)
helpFunc helpFunc
exit 0 exit 0
@ -36,14 +42,15 @@ while test $# -gt 0; do
CONFIRM=true CONFIRM=true
;; ;;
*) *)
CERTS_TO_REVOKE+=("$1") CERTS_TO_REVOKE+=("${1}")
;; ;;
esac esac
shift shift
done done
if [ ! -f "${INDEX}" ]; then if [[ ! -f "${INDEX}" ]]; then
printf "The file: %s was not found\n" "$INDEX" err "The file: ${INDEX} was not found"
exit 1 exit 1
fi fi
@ -54,74 +61,80 @@ if [[ -z "${CERTS_TO_REVOKE}" ]]; then
printf " ::\e[4m Certificate List \e[0m:: \n" printf " ::\e[4m Certificate List \e[0m:: \n"
i=0 i=0
while read -r line || [ -n "$line" ]; do while read -r line || [[ -n "${line}" ]]; do
STATUS=$(echo "$line" | awk '{print $1}') STATUS=$(echo "${line}" | awk '{print $1}')
if [[ "${STATUS}" = "V" ]]; then
if [[ "${STATUS}" == "V" ]]; then
# Disabling SC2001 warning, suggested method doesn't work with regexp # Disabling SC2001 warning, suggested method doesn't work with regexp
# shellcheck disable=SC2001 # shellcheck disable=SC2001
NAME=$(echo "$line" | sed -e 's:.*/CN=::') NAME=$(echo "${line}" | sed -e 's:.*/CN=::')
if [ "$i" != 0 ]; then
if [[ "${i}" != 0 ]]; then
# Prevent printing "server" certificate # Prevent printing "server" certificate
CERTS[$i]=$(echo -e "${NAME}") CERTS["${i}"]=$(echo -e "${NAME}")
fi fi
((i++)) ((i++))
fi fi
done <${INDEX} done < "${INDEX}"
i=1 i=1
len=${#CERTS[@]} len="${#CERTS[@]}"
while [ $i -le "${len}" ]; do while [[ "${i}" -le "${len}" ]]; do
printf "%0${#len}s) %s\r\n" ${i} "${CERTS[(($i))]}" printf "%0${#len}s) %s\r\n" "${i}" "${CERTS[(($i))]}"
((i++)) ((i++))
done done
printf "\n"
echo -n "::: Please enter the Index/Name of the client to be revoked from the list above: " printf "\n"
echo -n "::: Please enter the Index/Name of the client to be revoked "
echo -n "from the list above: "
read -r NAME read -r NAME
if [[ -z "${NAME}" ]]; then if [[ -z "${NAME}" ]]; then
echo "You can not leave this blank!" err "You can not leave this blank!"
exit 1 exit 1
fi fi
re='^[0-9]+$' re='^[0-9]+$'
if [[ ${NAME} =~ $re ]] ; then if [[ "${NAME}" =~ $re ]]; then
NAME=${CERTS[$((NAME))]} NAME="${CERTS[$((NAME))]}"
fi fi
for ((x = 1; x <= i; ++x)); do for ((x = 1; x <= i; ++x)); do
if [ "${CERTS[$x]}" = "${NAME}" ]; then if [[ "${CERTS[$x]}" == "${NAME}" ]]; then
VALID=1 VALID=1
fi fi
done done
if [ -z "${VALID}" ]; then if [[ -z "${VALID}" ]]; then
printf "You didn't enter a valid cert name!\n" err "You didn't enter a valid cert name!"
exit 1 exit 1
fi fi
CERTS_TO_REVOKE=("${NAME}") CERTS_TO_REVOKE=("${NAME}")
else else
i=0 i=0
while read -r line || [ -n "$line" ]; do while read -r line || [[ -n "${line}" ]]; do
STATUS=$(echo "$line" | awk '{print $1}') STATUS=$(echo "${line}" | awk '{print $1}')
if [[ "${STATUS}" = "V" ]]; then
NAME=$(echo -e "$line" | sed -e 's:.*/CN=::') if [[ "${STATUS}" == "V" ]]; then
CERTS[$i]=${NAME} NAME=$(echo -e "${line}" | sed -e 's:.*/CN=::')
CERTS["${i}"]="${NAME}"
((i++)) ((i++))
fi fi
done <${INDEX} done < "${INDEX}"
for ((ii = 0; ii < ${#CERTS_TO_REVOKE[@]}; ii++)); do for ((ii = 0; ii < ${#CERTS_TO_REVOKE[@]}; ii++)); do
VALID=0 VALID=0
for ((x = 1; x <= i; ++x)); do for ((x = 1; x <= i; ++x)); do
if [ "${CERTS[$x]}" = "${CERTS_TO_REVOKE[ii]}" ]; then if [[ "${CERTS[$x]}" == "${CERTS_TO_REVOKE[ii]}" ]]; then
VALID=1 VALID=1
fi fi
done done
if [ "${VALID}" != 1 ]; then if [[ "${VALID}" != 1 ]]; then
printf "You passed an invalid cert name: '%s'! \n" "${CERTS_TO_REVOKE[ii]}" err "You passed an invalid cert name: '${CERTS_TO_REVOKE[ii]}'!"
exit 1 exit 1
fi fi
done done
@ -130,17 +143,21 @@ fi
cd /etc/openvpn/easy-rsa || exit cd /etc/openvpn/easy-rsa || exit
for ((ii = 0; ii < ${#CERTS_TO_REVOKE[@]}; ii++)); do for ((ii = 0; ii < ${#CERTS_TO_REVOKE[@]}; ii++)); do
if [ -n "$CONFIRM" ]; then if [[ -n "${CONFIRM}" ]]; then
REPLY="y" REPLY="y"
else else
read -r -p "Do you really want to revoke '${CERTS_TO_REVOKE[ii]}'? [y/N] " read -r -p "Do you really want to revoke '${CERTS_TO_REVOKE[ii]}'? [y/N] "
fi fi
if [[ $REPLY =~ ^[Yy]$ ]]; then
if [[ "${REPLY}" =~ ^[Yy]$ ]]; then
printf "\n::: Revoking certificate '%s'. \n" "${CERTS_TO_REVOKE[ii]}" printf "\n::: Revoking certificate '%s'. \n" "${CERTS_TO_REVOKE[ii]}"
./easyrsa --batch revoke "${CERTS_TO_REVOKE[ii]}" ./easyrsa --batch revoke "${CERTS_TO_REVOKE[ii]}"
./easyrsa gen-crl ./easyrsa gen-crl
printf "\n::: Certificate revoked, and CRL file updated.\n" printf "\n::: Certificate revoked, and CRL file updated.\n"
printf "::: Removing certs and client configuration for this profile.\n" printf "::: Removing certs and client configuration for this profile.\n"
rm -rf "pki/reqs/${CERTS_TO_REVOKE[ii]}.req" rm -rf "pki/reqs/${CERTS_TO_REVOKE[ii]}.req"
rm -rf "pki/private/${CERTS_TO_REVOKE[ii]}.key" rm -rf "pki/private/${CERTS_TO_REVOKE[ii]}.key"
rm -rf "pki/issued/${CERTS_TO_REVOKE[ii]}.crt" rm -rf "pki/issued/${CERTS_TO_REVOKE[ii]}.crt"
@ -149,7 +166,9 @@ for (( ii = 0; ii < ${#CERTS_TO_REVOKE[@]}; ii++)); do
# shellcheck disable=SC2154 # shellcheck disable=SC2154
# Grab the client IP address # Grab the client IP address
NET_REDUCED="${pivpnNET::-2}" NET_REDUCED="${pivpnNET::-2}"
STATIC_IP=$(grep -v "^#" /etc/openvpn/ccd/"${CERTS_TO_REVOKE[ii]}" | grep -w ifconfig-push | grep -oE "${NET_REDUCED}\.[0-9]{1,3}") STATIC_IP="$(grep -v "^#" /etc/openvpn/ccd/"${CERTS_TO_REVOKE[ii]}" \
| grep -w ifconfig-push \
| grep -oE "${NET_REDUCED}\.[0-9]{1,3}")"
rm -rf /etc/openvpn/ccd/"${CERTS_TO_REVOKE[ii]}" rm -rf /etc/openvpn/ccd/"${CERTS_TO_REVOKE[ii]}"
# disablung warning SC2154, $install_home sourced externally # disablung warning SC2154, $install_home sourced externally
@ -159,14 +178,18 @@ for (( ii = 0; ii < ${#CERTS_TO_REVOKE[@]}; ii++)); do
cp /etc/openvpn/easy-rsa/pki/crl.pem /etc/openvpn/crl.pem cp /etc/openvpn/easy-rsa/pki/crl.pem /etc/openvpn/crl.pem
# If using Pi-hole, remove the client from the hosts file # If using Pi-hole, remove the client from the hosts file
if [ -f /etc/pivpn/hosts.openvpn ]; then if [[ -f /etc/pivpn/hosts.openvpn ]]; then
sed "\#${STATIC_IP} ${CERTS_TO_REVOKE[ii]}.pivpn#d" -i /etc/pivpn/hosts.openvpn sed \
-e "\#${STATIC_IP} ${CERTS_TO_REVOKE[ii]}.pivpn#d" \
-i /etc/pivpn/hosts.openvpn
if killall -SIGHUP pihole-FTL; then if killall -SIGHUP pihole-FTL; then
echo "::: Updated hosts file for Pi-hole" echo "::: Updated hosts file for Pi-hole"
else else
echo "::: Failed to reload pihole-FTL configuration" err "::: Failed to reload pihole-FTL configuration"
fi fi
fi fi
fi fi
done done
printf "::: Completed!\n" printf "::: Completed!\n"

View file

@ -7,25 +7,29 @@ if grep -qsEe "^NAME\=['\"]?Alpine[a-zA-Z ]*['\"]?$" /etc/os-release; then
fi fi
# Must be root to use this tool # Must be root to use this tool
if [ $EUID -ne 0 ]; then if [[ "${EUID}" -ne 0 ]]; then
if eval "${CHECK_PKG_INSTALLED} sudo" &> /dev/null; then if ${CHECK_PKG_INSTALLED} sudo &> /dev/null; then
export SUDO="sudo" export SUDO="sudo"
else else
echo "::: Please install sudo or run this as root." err "::: Please install sudo or run this as root."
exit 1 exit 1
fi fi
fi fi
scriptDir="/opt/pivpn" scriptDir="/opt/pivpn"
err() {
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
}
uninstallServer() { uninstallServer() {
$SUDO ${scriptDir}/uninstall.sh ${SUDO} "${scriptDir}/uninstall.sh"
exit "$?" exit "${?}"
} }
backup() { backup() {
$SUDO ${scriptDir}/backup.sh ${SUDO} "${scriptDir}/backup.sh"
exit "$?" exit "${?}"
} }
showHelp() { showHelp() {
@ -40,16 +44,28 @@ showHelp(){
exit 0 exit 0
} }
if [ $# = 0 ]; then if [[ "$#" == 0 ]]; then
showHelp showHelp
fi fi
# Handle redirecting to specific functions based on arguments # Handle redirecting to specific functions based on arguments
case "$1" in case "${1}" in
wg ) "${scriptDir}/wireguard/pivpn.sh" "${@:2}";; wg)
ovpn ) "${scriptDir}/openvpn/pivpn.sh" "${@:2}";; "${scriptDir}/wireguard/pivpn.sh" "${@:2}"
"-h" | "help" ) showHelp;; ;;
"-u" | "uninstall" ) uninstallServer;; ovpn)
"-bk" | "backup" ) backup ;; "${scriptDir}/openvpn/pivpn.sh" "${@:2}"
* ) showHelp;; ;;
"-h" | "help")
showHelp
;;
"-u" | "uninstall")
uninstallServer
;;
"-bk" | "backup")
backup
;;
*)
showHelp
;;
esac esac

View file

@ -1,14 +1,19 @@
#!/bin/bash #!/bin/bash
PLAT=$(grep -sEe '^NAME\=' /etc/os-release | sed -E -e "s/NAME\=[\'\"]?([^ ]*).*/\1/") PLAT="$(grep -sEe '^NAME\=' /etc/os-release \
| sed -E -e "s/NAME\=[\'\"]?([^ ]*).*/\1/")"
# dual protocol, VPN type supplied as $1 # dual protocol, VPN type supplied as $1
VPN=$1 VPN="${1}"
setupVars="/etc/pivpn/${VPN}/setupVars.conf" setupVars="/etc/pivpn/${VPN}/setupVars.conf"
ERR=0 ERR=0
if [ ! -f "${setupVars}" ]; then err() {
echo "::: Missing setup vars file!" echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
}
if [[ ! -f "${setupVars}" ]]; then
err "::: Missing setup vars file!"
exit 1 exit 1
fi fi
@ -16,156 +21,264 @@ fi
# shellcheck disable=SC1090 # shellcheck disable=SC1090
source "${setupVars}" source "${setupVars}"
if [ "$VPN" = "wireguard" ]; then if [[ "${VPN}" == "wireguard" ]]; then
VPN_PRETTY_NAME="WireGuard"
VPN_SERVICE="wg-quick@wg0" VPN_SERVICE="wg-quick@wg0"
if [ "${PLAT}" == 'Alpine' ]; then if [[ "${PLAT}" == 'Alpine' ]]; then
VPN_SERVICE='wg-quick' VPN_SERVICE='wg-quick'
fi fi
elif [[ "${VPN}" == "openvpn" ]]; then
VPN_PRETTY_NAME="WireGuard"
elif [ "$VPN" = "openvpn" ]; then
VPN_SERVICE="openvpn" VPN_SERVICE="openvpn"
VPN_PRETTY_NAME="OpenVPN" VPN_PRETTY_NAME="OpenVPN"
fi fi
if [ "$(</proc/sys/net/ipv4/ip_forward)" -eq 1 ]; then if [[ "$(< /proc/sys/net/ipv4/ip_forward)" -eq 1 ]]; then
echo ":: [OK] IP forwarding is enabled" echo ":: [OK] IP forwarding is enabled"
else else
ERR=1 ERR=1
read -r -p ":: [ERR] IP forwarding is not enabled, attempt fix now? [Y/n] " REPLY read -r \
if [[ ${REPLY} =~ ^[Yy]$ ]] || [[ -z ${REPLY} ]]; then -p ":: [ERR] IP forwarding is not enabled, attempt fix now? [Y/n] " \
REPLY
if [[ "${REPLY}" =~ ^[Yy]$ ]] || [[ -z "${REPLY}" ]]; then
sed -i '/net.ipv4.ip_forward=1/s/^#//g' /etc/sysctl.conf sed -i '/net.ipv4.ip_forward=1/s/^#//g' /etc/sysctl.conf
sysctl -p sysctl -p
echo "Done" echo "Done"
fi fi
fi fi
if [ "$USING_UFW" -eq 0 ]; then if [[ "${USING_UFW}" -eq 0 ]]; then
# Disabled SC Warnings for SC2154, values
# Disabled SC Warnings for SC2154, values for variables are sourced from setupVars # for variables are sourced from setupVars
# shellcheck disable=SC2154 # shellcheck disable=SC2154
if iptables -t nat -C POSTROUTING -s "${pivpnNET}/${subnetClass}" -o "${IPv4dev}" -j MASQUERADE -m comment --comment "${VPN}-nat-rule" &> /dev/null; then if iptables \
-t nat \
-C POSTROUTING \
-s "${pivpnNET}/${subnetClass}" \
-o "${IPv4dev}" \
-j MASQUERADE \
-m comment \
--comment "${VPN}-nat-rule" &> /dev/null; then
echo ":: [OK] Iptables MASQUERADE rule set" echo ":: [OK] Iptables MASQUERADE rule set"
else else
ERR=1 ERR=1
read -r -p ":: [ERR] Iptables MASQUERADE rule is not set, attempt fix now? [Y/n] " REPLY echo -n ":: [ERR] Iptables MASQUERADE rule is not set, "
if [[ ${REPLY} =~ ^[Yy]$ ]] || [[ -z ${REPLY} ]]; then echo -n "attempt fix now? [Y/n] "
iptables -t nat -I POSTROUTING -s "${pivpnNET}/${subnetClass}" -o "${IPv4dev}" -j MASQUERADE -m comment --comment "${VPN}-nat-rule" read -r REPLY
if [[ "${REPLY}" =~ ^[Yy]$ ]] || [[ -z "${REPLY}" ]]; then
iptables \
-t nat \
-I POSTROUTING \
-s "${pivpnNET}/${subnetClass}" \
-o "${IPv4dev}" \
-j MASQUERADE \
-m comment \
--comment "${VPN}-nat-rule"
iptables-save > /etc/iptables/rules.v4 iptables-save > /etc/iptables/rules.v4
echo "Done" echo "Done"
fi fi
fi fi
if [ "$INPUT_CHAIN_EDITED" -eq 1 ]; then if [[ "${INPUT_CHAIN_EDITED}" -eq 1 ]]; then
# Disabled SC Warnings for SC2154, values
# Disabled SC Warnings for SC2154, values for variables are sourced from setupVars # for variables are sourced from setupVars
# shellcheck disable=SC2154 # shellcheck disable=SC2154
if iptables -C INPUT -i "${IPv4dev}" -p "${pivpnPROTO}" --dport "${pivpnPORT}" -j ACCEPT -m comment --comment "${VPN}-input-rule" &> /dev/null; then if iptables \
-C INPUT \
-i "${IPv4dev}" \
-p "${pivpnPROTO}" \
--dport "${pivpnPORT}" \
-j ACCEPT \
-m comment \
--comment "${VPN}-input-rule" &> /dev/null; then
echo ":: [OK] Iptables INPUT rule set" echo ":: [OK] Iptables INPUT rule set"
else else
ERR=1 ERR=1
read -r -p ":: [ERR] Iptables INPUT rule is not set, attempt fix now? [Y/n] " REPLY read -r \
if [[ ${REPLY} =~ ^[Yy]$ ]] || [[ -z ${REPLY} ]]; then -p ":: [ERR] Iptables INPUT rule is not set, attempt fix now? [Y/n] " \
iptables -I INPUT 1 -i "${IPv4dev}" -p "${pivpnPROTO}" --dport "${pivpnPORT}" -j ACCEPT -m comment --comment "${VPN}-input-rule" REPLY
if [[ "${REPLY}" =~ ^[Yy]$ ]] || [[ -z "${REPLY}" ]]; then
iptables \
-I INPUT 1 \
-i "${IPv4dev}" \
-p "${pivpnPROTO}" \
--dport "${pivpnPORT}" \
-j ACCEPT \
-m comment \
--comment "${VPN}-input-rule"
iptables-save > /etc/iptables/rules.v4 iptables-save > /etc/iptables/rules.v4
echo "Done" echo "Done"
fi fi
fi fi
fi fi
if [ "$FORWARD_CHAIN_EDITED" -eq 1 ]; then if [[ "${FORWARD_CHAIN_EDITED}" -eq 1 ]]; then
# Disabled SC Warnings for SC2154, values
# Disabled SC Warnings for SC2154, values for variables are sourced from setupVars # for variables are sourced from setupVars
# shellcheck disable=SC2154 # shellcheck disable=SC2154
if iptables -C FORWARD -s "${pivpnNET}/${subnetClass}" -i "${pivpnDEV}" -o "${IPv4dev}" -j ACCEPT -m comment --comment "${VPN}-forward-rule" &> /dev/null; then if iptables \
-C FORWARD \
-s "${pivpnNET}/${subnetClass}" \
-i "${pivpnDEV}" \
-o "${IPv4dev}" \
-j ACCEPT \
-m comment \
--comment "${VPN}-forward-rule" &> /dev/null; then
echo ":: [OK] Iptables FORWARD rule set" echo ":: [OK] Iptables FORWARD rule set"
else else
ERR=1 ERR=1
read -r -p ":: [ERR] Iptables FORWARD rule is not set, attempt fix now? [Y/n] " REPLY echo -n ":: [ERR] Iptables FORWARD rule is not set, "
if [[ ${REPLY} =~ ^[Yy]$ ]] || [[ -z ${REPLY} ]]; then echo -n "attempt fix now? [Y/n] "
iptables -I FORWARD 1 -d "${pivpnNET}/${subnetClass}" -i "${IPv4dev}" -o "${pivpnDEV}" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -m comment --comment "${VPN}-forward-rule" read -r REPLY
iptables -I FORWARD 2 -s "${pivpnNET}/${subnetClass}" -i "${pivpnDEV}" -o "${IPv4dev}" -j ACCEPT -m comment --comment "${VPN}-forward-rule"
if [[ "${REPLY}" =~ ^[Yy]$ ]] || [[ -z "${REPLY}" ]]; then
iptables \
-I FORWARD 1 \
-d "${pivpnNET}/${subnetClass}" \
-i "${IPv4dev}" \
-o "${pivpnDEV}" \
-m conntrack \
--ctstate RELATED,ESTABLISHED \
-j ACCEPT \
-m comment \
--comment "${VPN}-forward-rule"
iptables \
-I FORWARD 2 \
-s "${pivpnNET}/${subnetClass}" \
-i "${pivpnDEV}" \
-o "${IPv4dev}" \
-j ACCEPT \
-m comment \
--comment "${VPN}-forward-rule"
iptables-save > /etc/iptables/rules.v4 iptables-save > /etc/iptables/rules.v4
echo "Done" echo "Done"
fi fi
fi fi
fi fi
else else
if LANG="en_US.UTF-8" ufw status | grep -qw 'active'; then if LANG="en_US.UTF-8" ufw status | grep -qw 'active'; then
echo ":: [OK] Ufw is enabled" echo ":: [OK] Ufw is enabled"
else else
ERR=1 ERR=1
read -r -p ":: [ERR] Ufw is not enabled, try to enable now? [Y/n] " REPLY echo -n ":: [ERR] Ufw is not enabled, "
if [[ ${REPLY} =~ ^[Yy]$ ]] || [[ -z ${REPLY} ]]; then echo -n "try to enable now? [Y/n] "
read -r REPLY
if [[ "${REPLY}" =~ ^[Yy]$ ]] || [[ -z "${REPLY}" ]]; then
ufw enable ufw enable
fi fi
fi fi
if iptables -t nat -C POSTROUTING -s "${pivpnNET}/${subnetClass}" -o "${IPv4dev}" -j MASQUERADE -m comment --comment "${VPN}-nat-rule" &> /dev/null; then if iptables \
-t nat \
-C POSTROUTING \
-s "${pivpnNET}/${subnetClass}" \
-o "${IPv4dev}" \
-j MASQUERADE \
-m comment \
--comment "${VPN}-nat-rule" &> /dev/null; then
echo ":: [OK] Iptables MASQUERADE rule set" echo ":: [OK] Iptables MASQUERADE rule set"
else else
ERR=1 ERR=1
read -r -p ":: [ERR] Iptables MASQUERADE rule is not set, attempt fix now? [Y/n] " REPLY echo -n ":: [ERR] Iptables MASQUERADE rule is not set, "
if [[ ${REPLY} =~ ^[Yy]$ ]] || [[ -z ${REPLY} ]]; then echo -n "attempt fix now? [Y/n] "
sed "/delete these required/i *nat\n:POSTROUTING ACCEPT [0:0]\n-I POSTROUTING -s ${pivpnNET}/${subnetClass} -o ${IPv4dev} -j MASQUERADE -m comment --comment ${VPN}-nat-rule\nCOMMIT\n" -i /etc/ufw/before.rules read -r REPLY
if [[ "${REPLY}" =~ ^[Yy]$ ]] || [[ -z "${REPLY}" ]]; then
sed_pattern='/delete these required/i'
sed_pattern="${sed_pattern} *nat\n:POSTROUTING ACCEPT [0:0]\n"
sed_pattern="${sed_pattern} -I POSTROUTING"
sed_pattern="${sed_pattern} -s ${pivpnNET}/${subnetClass}"
sed_pattern="${sed_pattern} -o ${IPv4dev}"
sed_pattern="${sed_pattern} -j MASQUERADE"
sed_pattern="${sed_pattern} -m comment"
sed_pattern="${sed_pattern} --comment ${VPN}-nat-rule\n"
sed_pattern="${sed_pattern}COMMIT\n"
sed "${sed_pattern}" -i /etc/ufw/before.rules
ufw reload ufw reload
echo "Done" echo "Done"
unset sed_pattern
fi fi
fi fi
if iptables -C ufw-user-input -p "${pivpnPROTO}" --dport "${pivpnPORT}" -j ACCEPT &> /dev/null; then if iptables \
-C ufw-user-input \
-p "${pivpnPROTO}" \
--dport "${pivpnPORT}" \
-j ACCEPT &> /dev/null; then
echo ":: [OK] Ufw input rule set" echo ":: [OK] Ufw input rule set"
else else
ERR=1 ERR=1
read -r -p ":: [ERR] Ufw input rule is not set, attempt fix now? [Y/n] " REPLY read -r \
if [[ ${REPLY} =~ ^[Yy]$ ]] || [[ -z ${REPLY} ]]; then -p ":: [ERR] Ufw input rule is not set, attempt fix now? [Y/n] " \
REPLY
if [[ "${REPLY}" =~ ^[Yy]$ ]] || [[ -z "${REPLY}" ]]; then
ufw insert 1 allow "${pivpnPORT}"/"${pivpnPROTO}" ufw insert 1 allow "${pivpnPORT}"/"${pivpnPROTO}"
ufw reload ufw reload
echo "Done" echo "Done"
fi fi
fi fi
if iptables -C ufw-user-forward -i "${pivpnDEV}" -o "${IPv4dev}" -s "${pivpnNET}/${subnetClass}" -j ACCEPT &> /dev/null; then if iptables \
-C ufw-user-forward \
-i "${pivpnDEV}" \
-o "${IPv4dev}" \
-s "${pivpnNET}/${subnetClass}" \
-j ACCEPT &> /dev/null; then
echo ":: [OK] Ufw forwarding rule set" echo ":: [OK] Ufw forwarding rule set"
else else
ERR=1 ERR=1
read -r -p ":: [ERR] Ufw forwarding rule is not set, attempt fix now? [Y/n] " REPLY read -r \
if [[ ${REPLY} =~ ^[Yy]$ ]] || [[ -z ${REPLY} ]]; then -p ":: [ERR] Ufw forwarding rule is not set, attempt fix now? [Y/n] " \
ufw route insert 1 allow in on "${pivpnDEV}" from "${pivpnNET}/${subnetClass}" out on "${IPv4dev}" to any REPLY
if [[ "${REPLY}" =~ ^[Yy]$ ]] || [[ -z "${REPLY}" ]]; then
ufw route insert 1 allow in on "${pivpnDEV}" \
from "${pivpnNET}/${subnetClass}" out on "${IPv4dev}" to any
ufw reload ufw reload
echo "Done" echo "Done"
fi fi
fi fi
fi fi
if [ "${PLAT}" == 'Alpine' ]; then if [[ "${PLAT}" == 'Alpine' ]]; then
if [ "$(rc-service "${VPN_SERVICE}" status | sed -E -e 's/.*status\: (.*)/\1/')" == 'started' ]; then if [[ "$(rc-service "${VPN_SERVICE}" status \
| sed -E -e 's/.*status\: (.*)/\1/')" == 'started' ]]; then
echo ":: [OK] ${VPN_PRETTY_NAME} is running" echo ":: [OK] ${VPN_PRETTY_NAME} is running"
else else
ERR=1 ERR=1
read -r -p ":: [ERR] ${VPN_PRETTY_NAME} is not running, try to start now? [Y/n] " REPLY echo -n ":: [ERR] ${VPN_PRETTY_NAME} is not running, "
echo -n "try to start now? [Y/n] "
read -r REPLY
if [[ ${REPLY} =~ ^[Yy]$ ]] || [[ -z ${REPLY} ]]; then if [[ "${REPLY}" =~ ^[Yy]$ ]] || [[ -z "${REPLY}" ]]; then
rc-service -s "${VPN_SERVICE}" restart rc-service -s "${VPN_SERVICE}" restart
rc-service -N "${VPN_SERVICE}" start rc-service -N "${VPN_SERVICE}" start
echo "Done" echo "Done"
fi fi
fi fi
if rc-update show default | grep -sEe "\s*${VPN_SERVICE} .*" &> /dev/null; then if rc-update show default \
echo ":: [OK] ${VPN_PRETTY_NAME} is enabled (it will automatically start on reboot)" | grep -sEe "\s*${VPN_SERVICE} .*" &> /dev/null; then
echo -n ":: [OK] ${VPN_PRETTY_NAME} is enabled "
echo "(it will automatically start on reboot)"
else else
ERR=1 ERR=1
read -r -p ":: [ERR] ${VPN_PRETTY_NAME} is not enabled, try to enable now? [Y/n] " REPLY echo -n ":: [ERR] ${VPN_PRETTY_NAME} is not enabled, "
echo -n "try to enable now? [Y/n] "
read -r REPLY
if [[ ${REPLY} =~ ^[Yy]$ ]] || [[ -z ${REPLY} ]]; then if [[ "${REPLY}" =~ ^[Yy]$ ]] || [[ -z "${REPLY}" ]]; then
rc-update add "${VPN_SERVICE}" default rc-update add "${VPN_SERVICE}" default
echo "Done" echo "Done"
fi fi
fi fi
@ -174,19 +287,26 @@ else
echo ":: [OK] ${VPN_PRETTY_NAME} is running" echo ":: [OK] ${VPN_PRETTY_NAME} is running"
else else
ERR=1 ERR=1
read -r -p ":: [ERR] ${VPN_PRETTY_NAME} is not running, try to start now? [Y/n] " REPLY echo -n ":: [ERR] ${VPN_PRETTY_NAME} is not running, "
if [[ ${REPLY} =~ ^[Yy]$ ]] || [[ -z ${REPLY} ]]; then echo -n "try to start now? [Y/n] "
read -r REPLY
if [[ "${REPLY}" =~ ^[Yy]$ ]] || [[ -z "${REPLY}" ]]; then
systemctl start "${VPN_SERVICE}" systemctl start "${VPN_SERVICE}"
echo "Done" echo "Done"
fi fi
fi fi
if systemctl is-enabled -q "${VPN_SERVICE}"; then if systemctl is-enabled -q "${VPN_SERVICE}"; then
echo ":: [OK] ${VPN_PRETTY_NAME} is enabled (it will automatically start on reboot)" echo ":: [OK] ${VPN_PRETTY_NAME} is enabled "
echo "(it will automatically start on reboot)"
else else
ERR=1 ERR=1
read -r -p ":: [ERR] ${VPN_PRETTY_NAME} is not enabled, try to enable now? [Y/n] " REPLY echo -n ":: [ERR] ${VPN_PRETTY_NAME} is not enabled, "
if [[ ${REPLY} =~ ^[Yy]$ ]] || [[ -z ${REPLY} ]]; then echo -n "try to enable now? [Y/n] "
read -r REPLY
if [[ "${REPLY}" =~ ^[Yy]$ ]] || [[ -z "${REPLY}" ]]; then
systemctl enable "${VPN_SERVICE}" systemctl enable "${VPN_SERVICE}"
echo "Done" echo "Done"
fi fi
@ -195,13 +315,16 @@ fi
# grep -w (whole word) is used so port 11940 won't match when looking for 1194 # grep -w (whole word) is used so port 11940 won't match when looking for 1194
if netstat -antu | grep -wqE "${pivpnPROTO}.*${pivpnPORT}"; then if netstat -antu | grep -wqE "${pivpnPROTO}.*${pivpnPORT}"; then
echo ":: [OK] ${VPN_PRETTY_NAME} is listening on port ${pivpnPORT}/${pivpnPROTO}" echo -n ":: [OK] ${VPN_PRETTY_NAME} is listening "
echo "on port ${pivpnPORT}/${pivpnPROTO}"
else else
ERR=1 ERR=1
read -r -p ":: [ERR] ${VPN_PRETTY_NAME} is not listening, try to restart now? [Y/n] " REPLY echo -n ":: [ERR] ${VPN_PRETTY_NAME} is not listening, "
echo -n "try to restart now? [Y/n] "
read -r REPLY
if [[ ${REPLY} =~ ^[Yy]$ ]] || [[ -z ${REPLY} ]]; then if [[ "${REPLY}" =~ ^[Yy]$ ]] || [[ -z "${REPLY}" ]]; then
if [ "${PLAT}" == 'Alpine' ]; then if [[ "${PLAT}" == 'Alpine' ]]; then
rc-service -s "${VPN_SERVICE}" restart rc-service -s "${VPN_SERVICE}" restart
rc-service -N "${VPN_SERVICE}" start rc-service -N "${VPN_SERVICE}" start
else else
@ -212,6 +335,6 @@ else
fi fi
fi fi
if [ "$ERR" -eq 1 ]; then if [[ "${ERR}" -eq 1 ]]; then
echo -e "[INFO] Run \e[1mpivpn -d\e[0m again to see if we detect issues" echo -e "[INFO] Run \e[1mpivpn -d\e[0m again to see if we detect issues"
fi fi

View file

@ -1,13 +1,15 @@
#!/usr/bin/env bash #!/bin/bash
# PiVPN: Uninstall Script # PiVPN: Uninstall Script
### FIXME: global: config storage, refactor all scripts to adhere to the storage ### FIXME:
### FIXME: use variables where appropriate, reduce magic numbers by 99.9%, at least. ### global: config storage, refactor all scripts to adhere to the storage
### FIXME:
### use variables where appropriate, reduce magic numbers by 99.9%, at least.
# Find the rows and columns. Will default to 80x24 if it can not be detected. # Find the rows and columns. Will default to 80x24 if it can not be detected.
screen_size=$(stty size 2>/dev/null || echo 24 80) screen_size="$(stty size 2> /dev/null || echo 24 80)"
rows=$(echo "$screen_size" | awk '{print $1}') rows="$(echo "${screen_size}" | awk '{print $1}')"
columns=$(echo "$screen_size" | awk '{print $2}') columns="$(echo "${screen_size}" | awk '{print $2}')"
# Divide by two so the dialogs take up half of the screen, which looks nice. # Divide by two so the dialogs take up half of the screen, which looks nice.
r=$((rows / 2)) r=$((rows / 2))
@ -24,33 +26,42 @@ setupConfigDir="/etc/pivpn"
pivpnFilesDir="/usr/local/src/pivpn" pivpnFilesDir="/usr/local/src/pivpn"
pivpnScriptDir="/opt/pivpn" pivpnScriptDir="/opt/pivpn"
PLAT=$(grep -sEe '^NAME\=' /etc/os-release | sed -E -e "s/NAME\=[\'\"]?([^ ]*).*/\1/") PLAT="$(grep -sEe '^NAME\=' /etc/os-release \
| sed -E -e "s/NAME\=[\'\"]?([^ ]*).*/\1/")"
if [ "${PLAT}" == 'Alpine' ]; then if [[ "${PLAT}" == 'Alpine' ]]; then
PKG_MANAGER='apk' PKG_MANAGER='apk'
PKG_REMOVE="${PKG_MANAGER} --no-cache --purge del -r" PKG_REMOVE="${PKG_MANAGER} --no-cache --purge del -r"
fi fi
UPDATE_PKG_CACHE="${PKG_MANAGER} update" UPDATE_PKG_CACHE="${PKG_MANAGER} update"
if [ -r "${setupConfigDir}/wireguard/${setupVarsFile}" ] && [ -r "${setupConfigDir}/openvpn/${setupVarsFile}" ]; then if [[ -r "${setupConfigDir}/wireguard/${setupVarsFile}" ]] \
&& [[ -r "${setupConfigDir}/openvpn/${setupVarsFile}" ]]; then
vpnStillExists=1 vpnStillExists=1
# Two protocols have been installed, check if the script has passed # Two protocols have been installed, check if the script has passed
# an argument, otherwise ask the user which one he wants to remove # an argument, otherwise ask the user which one he wants to remove
if [ $# -ge 1 ]; then if [[ "$#" -ge 1 ]]; then
VPN="$1" VPN="${1}"
echo "::: Uninstalling VPN: $VPN" echo "::: Uninstalling VPN: ${VPN}"
else else
chooseVPNCmd=(whiptail --backtitle "Setup PiVPN" --title "Uninstall" --separate-output --radiolist "Both OpenVPN and WireGuard are installed, choose a VPN to uninstall (press space to select):" "${r}" "${c}" 2) chooseVPNCmd=(whiptail
--backtitle "Setup PiVPN"
--title "Uninstall"
--separate-output
--radiolist "Both OpenVPN and WireGuard are installed, \
choose a VPN to uninstall (press space to select):"
"${r}" "${c}" 2)
VPNChooseOptions=(WireGuard "" on VPNChooseOptions=(WireGuard "" on
OpenVPN "" off) OpenVPN "" off)
if VPN=$("${chooseVPNCmd[@]}" "${VPNChooseOptions[@]}" 2>&1 >/dev/tty) ; then if VPN="$("${chooseVPNCmd[@]}" "${VPNChooseOptions[@]}" 2>&1 \
echo "::: Uninstalling VPN: $VPN" > /dev/tty)"; then
echo "::: Uninstalling VPN: ${VPN}"
VPN="${VPN,,}" VPN="${VPN,,}"
else else
echo "::: Cancel selected, exiting...." err "::: Cancel selected, exiting...."
exit 1 exit 1
fi fi
fi fi
@ -59,33 +70,39 @@ if [ -r "${setupConfigDir}/wireguard/${setupVarsFile}" ] && [ -r "${setupConfigD
else else
vpnStillExists=0 vpnStillExists=0
if [ -r "${setupConfigDir}/wireguard/${setupVarsFile}" ]; then if [[ -r "${setupConfigDir}/wireguard/${setupVarsFile}" ]]; then
setupVars="${setupConfigDir}/wireguard/${setupVarsFile}" setupVars="${setupConfigDir}/wireguard/${setupVarsFile}"
elif [ -r "${setupConfigDir}/openvpn/${setupVarsFile}" ]; then elif [[ -r "${setupConfigDir}/openvpn/${setupVarsFile}" ]]; then
setupVars="${setupConfigDir}/openvpn/${setupVarsFile}" setupVars="${setupConfigDir}/openvpn/${setupVarsFile}"
fi fi
fi fi
if [ ! -f "${setupVars}" ]; then if [[ ! -f "${setupVars}" ]]; then
echo "::: Missing setup vars file!" err "::: Missing setup vars file!"
exit 1 exit 1
fi fi
# shellcheck disable=SC1090 # shellcheck disable=SC1090
source "${setupVars}" source "${setupVars}"
err() {
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
}
### FIXME: introduce global lib ### FIXME: introduce global lib
spinner() { spinner() {
local pid=$1 local pid="${1}"
local delay=0.50 local delay=0.50
local spinstr='/-\|' local spinstr='/-\|'
while ps a | awk '{print $1}' | grep -q "$pid"; do
local temp=${spinstr#?} while ps a | awk '{print $1}' | grep -q "${pid}"; do
printf " [%c] " "$spinstr" local temp="${spinstr#?}"
local spinstr=$temp${spinstr%"$temp"} printf " [%c] " "${spinstr}"
sleep $delay local spinstr="${temp}${spinstr%"$temp"}"
sleep "${delay}"
printf "\\b\\b\\b\\b\\b\\b" printf "\\b\\b\\b\\b\\b\\b"
done done
printf " \\b\\b\\b\\b" printf " \\b\\b\\b\\b"
} }
@ -93,19 +110,19 @@ removeAll(){
# Stopping and disabling services # Stopping and disabling services
echo "::: Stopping and disabling services..." echo "::: Stopping and disabling services..."
if [ "${PLAT}" == 'Alpine' ]; then if [[ "${PLAT}" == 'Alpine' ]]; then
if [ "${VPN}" = "wireguard" ]; then if [[ "${VPN}" == "wireguard" ]]; then
rc-service wg-quick stop rc-service wg-quick stop
rc-update del wg-quick default &> /dev/null rc-update del wg-quick default &> /dev/null
elif [ "${VPN}" = "openvpn" ]; then elif [[ "${VPN}" == "openvpn" ]]; then
rc-service openvpn stop rc-service openvpn stop
rc-update del openvpn default &> /dev/null rc-update del openvpn default &> /dev/null
fi fi
else else
if [ "${VPN}" = "wireguard" ]; then if [[ "${VPN}" == "wireguard" ]]; then
systemctl stop wg-quick@wg0 systemctl stop wg-quick@wg0
systemctl disable wg-quick@wg0 &> /dev/null systemctl disable wg-quick@wg0 &> /dev/null
elif [ "${VPN}" = "openvpn" ]; then elif [[ "${VPN}" == "openvpn" ]]; then
systemctl stop openvpn systemctl stop openvpn
systemctl disable openvpn &> /dev/null systemctl disable openvpn &> /dev/null
fi fi
@ -114,37 +131,84 @@ removeAll(){
# Removing firewall rules. # Removing firewall rules.
echo "::: Removing firewall rules..." echo "::: Removing firewall rules..."
if [ "$USING_UFW" -eq 1 ]; then if [[ "${USING_UFW}" -eq 1 ]]; then
### Ignoring SC2154, value sourced from setupVars file
# shellcheck disable=SC2154
ufw delete allow "${pivpnPORT}/${pivpnPROTO}" > /dev/null
### Ignoring SC2154, value sourced from setupVars file
# shellcheck disable=SC2154
ufw route delete allow in on "${pivpnDEV}" \
from "${pivpnNET}/${subnetClass}" out on "${IPv4dev}" to any > /dev/null
ufw delete allow in on "${pivpnDEV}" to any port 53 \
from "${pivpnNET}/${subnetClass}" > /dev/null
sed_pattern='/-I POSTROUTING'
sed_pattern="${sed_pattern} -s ${pivpnNET}\\/${subnetClass}"
sed_pattern="${sed_pattern} -o ${IPv4dev}"
sed_pattern="${sed_pattern} -j MASQUERADE"
sed_pattern="${sed_pattern} -m comment"
sed_pattern="${sed_pattern} --comment ${VPN}-nat-rule/d"
sed "${sed_pattern}" -i /etc/ufw/before.rules
unset sed_pattern
iptables \
-t nat \
-D POSTROUTING \
-s "${pivpnNET}/${subnetClass}" \
-o "${IPv4dev}" \
-j MASQUERADE \
-m comment \
--comment "${VPN}-nat-rule"
### Ignoring SC2154, value sourced from setupVars file
# shellcheck disable=SC2154
ufw delete allow "${pivpnPORT}"/"${pivpnPROTO}" > /dev/null
### Ignoring SC2154, value sourced from setupVars file
# shellcheck disable=SC2154
ufw route delete allow in on "${pivpnDEV}" from "${pivpnNET}/${subnetClass}" out on "${IPv4dev}" to any > /dev/null
ufw delete allow in on "${pivpnDEV}" to any port 53 from "${pivpnNET}/${subnetClass}" >/dev/null
sed "/-I POSTROUTING -s ${pivpnNET}\\/${subnetClass} -o ${IPv4dev} -j MASQUERADE -m comment --comment ${VPN}-nat-rule/d" -i /etc/ufw/before.rules
iptables -t nat -D POSTROUTING -s "${pivpnNET}/${subnetClass}" -o "${IPv4dev}" -j MASQUERADE -m comment --comment "${VPN}-nat-rule"
ufw reload &> /dev/null ufw reload &> /dev/null
elif [[ "${USING_UFW}" -eq 0 ]]; then
elif [ "$USING_UFW" -eq 0 ]; then if [[ "${INPUT_CHAIN_EDITED}" -eq 1 ]]; then
iptables \
if [ "$INPUT_CHAIN_EDITED" -eq 1 ]; then -D INPUT \
iptables -D INPUT -i "${IPv4dev}" -p "${pivpnPROTO}" --dport "${pivpnPORT}" -j ACCEPT -m comment --comment "${VPN}-input-rule" -i "${IPv4dev}" \
-p "${pivpnPROTO}" \
--dport "${pivpnPORT}" \
-j ACCEPT \
-m comment \
--comment "${VPN}-input-rule"
fi fi
if [ "$FORWARD_CHAIN_EDITED" -eq 1 ]; then if [[ "${FORWARD_CHAIN_EDITED}" -eq 1 ]]; then
iptables -D FORWARD -d "${pivpnNET}/${subnetClass}" -i "${IPv4dev}" -o "${pivpnDEV}" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -m comment --comment "${VPN}-forward-rule" iptables \
iptables -D FORWARD -s "${pivpnNET}/${subnetClass}" -i "${pivpnDEV}" -o "${IPv4dev}" -j ACCEPT -m comment --comment "${VPN}-forward-rule" -D FORWARD \
-d "${pivpnNET}/${subnetClass}" \
-i "${IPv4dev}" \
-o "${pivpnDEV}" \
-m conntrack \
--ctstate RELATED,ESTABLISHED \
-j ACCEPT \
-m comment \
--comment "${VPN}-forward-rule"
iptables \
-D FORWARD \
-s "${pivpnNET}/${subnetClass}" \
-i "${pivpnDEV}" \
-o "${IPv4dev}" \
-j ACCEPT \
-m comment \
--comment "${VPN}-forward-rule"
fi fi
iptables -t nat -D POSTROUTING -s "${pivpnNET}/${subnetClass}" -o "${IPv4dev}" -j MASQUERADE -m comment --comment "${VPN}-nat-rule" iptables \
-t nat \
-D POSTROUTING \
-s "${pivpnNET}/${subnetClass}" \
-o "${IPv4dev}" \
-j MASQUERADE \
-m comment \
--comment "${VPN}-nat-rule"
iptables-save > /etc/iptables/rules.v4 iptables-save > /etc/iptables/rules.v4
fi fi
# Disable IPv4 forwarding # Disable IPv4 forwarding
if [ "${vpnStillExists}" -eq 0 ]; then if [[ "${vpnStillExists}" -eq 0 ]]; then
sed -i '/net.ipv4.ip_forward=1/c\#net.ipv4.ip_forward=1' /etc/sysctl.conf sed -i '/net.ipv4.ip_forward=1/c\#net.ipv4.ip_forward=1' /etc/sysctl.conf
sysctl -p sysctl -p
fi fi
@ -154,38 +218,45 @@ removeAll(){
for i in "${INSTALLED_PACKAGES[@]}"; do for i in "${INSTALLED_PACKAGES[@]}"; do
while true; do while true; do
read -rp "::: Do you wish to remove $i from your system? [Y/n]: " yn read -rp "::: Do you wish to remove ${i} from your system? [Y/n]: " yn
case $yn in
case "${yn}" in
[Yy]*) [Yy]*)
if [ "${PLAT}" == 'Alpine' ]; then if [[ "${PLAT}" == 'Alpine' ]]; then
if [ "${i}" == 'openvpn' ]; then if [[ "${i}" == 'openvpn' ]]; then
deluser openvpn deluser openvpn
rm -f /etc/rsyslog.d/30-openvpn.conf /etc/logrotate.d/openvpn rm -f /etc/rsyslog.d/30-openvpn.conf /etc/logrotate.d/openvpn
fi fi
else else
if [ "${i}" == "wireguard-tools" ]; then if [[ "${i}" == "wireguard-tools" ]]; then
# The bullseye repo may not exist if wireguard was available at the # The bullseye repo may not exist if wireguard was available at
# time of installation. # the time of installation.
if [ -f /etc/apt/sources.list.d/pivpn-bullseye-repo.list ]; then tmp_path='/etc/apt/sources.list.d/pivpn-bullseye-repo.list'
if [[ -f "${tmp_path}" ]]; then
echo "::: Removing Debian Bullseye repo..." echo "::: Removing Debian Bullseye repo..."
rm -f /etc/apt/sources.list.d/pivpn-bullseye-repo.list rm -f "${tmp_path}"
rm -f /etc/apt/preferences.d/pivpn-limit-bullseye rm -f /etc/apt/preferences.d/pivpn-limit-bullseye
echo "::: Updating package cache..." echo "::: Updating package cache..."
${UPDATE_PKG_CACHE} &> /dev/null & ${UPDATE_PKG_CACHE} &> /dev/null &
spinner $! spinner "$!"
fi fi
if [ -f /etc/systemd/system/wg-quick@.service.d/override.conf ]; then tmp_path='/etc/systemd/system/wg-quick@.service.d/override.conf'
rm -f /etc/systemd/system/wg-quick@.service.d/override.conf
if [[ -f "${tmp_path}" ]]; then
rm -f "${tmp_path}"
fi fi
elif [ "${i}" = "unattended-upgrades" ]; then
unset tmp_path
elif [[ "${i}" == "unattended-upgrades" ]]; then
rm -rf /var/log/unattended-upgrades /etc/apt/apt.conf.d/*periodic rm -rf /var/log/unattended-upgrades /etc/apt/apt.conf.d/*periodic
rm -rf /etc/apt/apt.conf.d/*unattended-upgrades rm -rf /etc/apt/apt.conf.d/*unattended-upgrades
elif [ "${i}" = "openvpn" ]; then elif [[ "${i}" == "openvpn" ]]; then
if [ -f /etc/apt/sources.list.d/pivpn-openvpn-repo.list ]; then if [[ -f /etc/apt/sources.list.d/pivpn-openvpn-repo.list ]]; then
echo "::: Removing OpenVPN software repo..." echo "::: Removing OpenVPN software repo..."
rm -f /etc/apt/sources.list.d/pivpn-openvpn-repo.list rm -f /etc/apt/sources.list.d/pivpn-openvpn-repo.list
@ -193,7 +264,7 @@ removeAll(){
echo "::: Updating package cache..." echo "::: Updating package cache..."
${UPDATE_PKG_CACHE} &> /dev/null & ${UPDATE_PKG_CACHE} &> /dev/null &
spinner $! spinner "$!"
fi fi
deluser openvpn deluser openvpn
@ -201,76 +272,78 @@ removeAll(){
fi fi
fi fi
printf ":::\\tRemoving %s..." "$i" printf ":::\\tRemoving %s..." "${i}"
"${PKG_REMOVE}" "$i" &> /dev/null & ${PKG_REMOVE} "${i}" &> /dev/null &
spinner $! spinner "$!"
printf "done!\\n"; printf "done!\\n"
break break
;; ;;
[Nn]*) [Nn]*)
printf ":::\\tSkipping %s\\n" "$i"; printf ":::\\tSkipping %s\\n" "${i}"
break break
;; ;;
*) *)
printf "::: You must answer yes or no!\\n" err "::: You must answer yes or no!"
;; ;;
esac esac
done done
done done
if [ "${PLAT}" != 'Alpine' ]; then if [[ "${PLAT}" != 'Alpine' ]]; then
# Take care of any additional package cleaning # Take care of any additional package cleaning
printf "::: Auto removing remaining dependencies..." printf "::: Auto removing remaining dependencies..."
"${PKG_MANAGER}" -y autoremove &> /dev/null & "${PKG_MANAGER}" -y autoremove &> /dev/null &
spinner $! spinner "$!"
printf "done!\\n"; printf "done!\\n"
printf "::: Auto cleaning remaining dependencies..." printf "::: Auto cleaning remaining dependencies..."
"${PKG_MANAGER}" -y autoclean &> /dev/null & "${PKG_MANAGER}" -y autoclean &> /dev/null &
spinner $! spinner "$!"
printf "done!\\n"; printf "done!\\n"
fi fi
if [ -f "$dnsmasqConfig" ]; then if [[ -f "${dnsmasqConfig}" ]]; then
rm -f "$dnsmasqConfig" rm -f "${dnsmasqConfig}"
pihole restartdns pihole restartdns
fi fi
echo ":::" echo ":::"
echo "::: Removing VPN configuration files..." echo "::: Removing VPN configuration files..."
if [ "$VPN" = "wireguard" ]; then if [[ "${VPN}" == "wireguard" ]]; then
rm -f /etc/wireguard/wg0.conf rm -f /etc/wireguard/wg0.conf
rm -rf /etc/wireguard/configs rm -rf /etc/wireguard/configs
rm -rf /etc/wireguard/keys rm -rf /etc/wireguard/keys
### Ignoring SC2154, value sourced from setupVars file ### Ignoring SC2154, value sourced from setupVars file
# shellcheck disable=SC2154 # shellcheck disable=SC2154
rm -rf "$install_home/configs" rm -rf "${install_home}/configs"
elif [ "$VPN" = "openvpn" ]; then elif [[ "${VPN}" == "openvpn" ]]; then
rm -rf /var/log/*openvpn* rm -rf /var/log/*openvpn*
rm -f /etc/openvpn/server.conf rm -f /etc/openvpn/server.conf
rm -f /etc/openvpn/crl.pem rm -f /etc/openvpn/crl.pem
rm -rf /etc/openvpn/easy-rsa rm -rf /etc/openvpn/easy-rsa
rm -rf /etc/openvpn/ccd rm -rf /etc/openvpn/ccd
rm -rf "$install_home/ovpns" rm -rf "${install_home}/ovpns"
fi fi
if [ "${vpnStillExists}" -eq 0 ]; then if [[ "${vpnStillExists}" -eq 0 ]]; then
echo ":::" echo ":::"
echo "::: Removing pivpn system files..." echo "::: Removing pivpn system files..."
rm -rf "${setupConfigDir}" rm -rf "${setupConfigDir}"
rm -rf "${pivpnFilesDir}" rm -rf "${pivpnFilesDir}"
rm -f /var/log/*pivpn* rm -f /var/log/*pivpn*
rm -f /etc/bash_completion.d/pivpn rm -f /etc/bash_completion.d/pivpn
unlink "${pivpnScriptDir}" unlink "${pivpnScriptDir}"
unlink /usr/local/bin/pivpn unlink /usr/local/bin/pivpn
else else
if [[ ${VPN} == 'wireguard' ]]; then if [[ "${VPN}" == 'wireguard' ]]; then
othervpn='openvpn' othervpn='openvpn'
else else
othervpn='wireguard' othervpn='wireguard'
@ -282,23 +355,36 @@ removeAll(){
rm -f "${setupConfigDir}/${VPN}/${setupVarsFile}" rm -f "${setupConfigDir}/${VPN}/${setupVarsFile}"
# Restore single pivpn script and bash completion for the remaining VPN # Restore single pivpn script and bash completion for the remaining VPN
$SUDO unlink /usr/local/bin/pivpn ${SUDO} unlink /usr/local/bin/pivpn
$SUDO ln -s -T "${pivpnFilesDir}/scripts/${othervpn}/pivpn.sh" /usr/local/bin/pivpn
$SUDO ln -s -T "${pivpnFilesDir}/scripts/${othervpn}/bash-completion" /etc/bash_completion.d/pivpn ${SUDO} ln \
-sT "${pivpnFilesDir}/scripts/${othervpn}/pivpn.sh" \
/usr/local/bin/pivpn
${SUDO} ln \
-sT "${pivpnFilesDir}/scripts/${othervpn}/bash-completion" \
/etc/bash_completion.d/pivpn
# shellcheck disable=SC1091 # shellcheck disable=SC1091
. /etc/bash_completion.d/pivpn . /etc/bash_completion.d/pivpn
fi fi
echo ":::" echo ":::"
printf "::: Finished removing PiVPN from your system.\\n" printf "::: Finished removing PiVPN from your system.\\n"
printf "::: Reinstall by simply running\\n:::\\n:::\\tcurl -L https://install.pivpn.io | bash\\n:::\\n::: at any time!\\n:::\\n" printf "::: Reinstall by simply running\\n:::\\n:::\\t"
printf "curl -L https://install.pivpn.io | "
printf "bash\\n:::\\n::: at any time!\\n:::\\n"
} }
askreboot() { askreboot() {
printf "It is \\e[1mstrongly\\e[0m recommended to reboot after un-installation.\\n" printf "It is \\e[1mstrongly\\e[0m recommended to reboot "
printf "after un-installation.\\n"
read -p "Would you like to reboot now? [y/n]: " -n 1 -r read -p "Would you like to reboot now? [y/n]: " -n 1 -r
echo echo
if [[ ${REPLY} =~ ^[Yy]$ ]]; then
if [[ "${REPLY}" =~ ^[Yy]$ ]]; then
printf "\\nRebooting system...\\n" printf "\\nRebooting system...\\n"
sleep 3 sleep 3
reboot reboot
@ -306,13 +392,25 @@ askreboot(){
} }
######### SCRIPT ########### ######### SCRIPT ###########
echo "::: Preparing to remove packages, be sure that each may be safely removed depending on your operating system." echo -n "::: Preparing to remove packages, be sure that each may be safely "
echo "removed depending on your operating system."
echo "::: (SAFE TO REMOVE ALL ON RASPBIAN)" echo "::: (SAFE TO REMOVE ALL ON RASPBIAN)"
while true; do
read -rp "::: Do you wish to completely remove PiVPN configuration and installed packages from your system? (You will be prompted for each package) [y/n]: " yn
case $yn in
[Yy]* ) removeAll; askreboot; break;;
[Nn]* ) printf "::: Not removing anything, exiting...\\n"; break;; while true; do
echo -n "::: Do you wish to completely remove PiVPN configuration and "
echo -n "installed packages from your system? "
echo -n "(You will be prompted for each package) [y/n]: "
read -r yn
case "${yn}" in
[Yy]*)
removeAll
askreboot
break
;;
[Nn]*)
err "::: Not removing anything, exiting..."
break
;;
esac esac
done done

View file

@ -8,9 +8,9 @@ pivpnscripts="/opt/pivpn/"
bashcompletiondir="/etc/bash_completion.d/" bashcompletiondir="/etc/bash_completion.d/"
# Find the rows and columns. Will default to 80x24 if it can not be detected. # Find the rows and columns. Will default to 80x24 if it can not be detected.
screen_size=$(stty size 2>/dev/null || echo 24 80) screen_size="$(stty size 2> /dev/null || echo 24 80)"
rows=$(echo "$screen_size" | awk '{print $1}') rows="$(echo "${screen_size}" | awk '{print $1}')"
columns=$(echo "$screen_size" | awk '{print $2}') columns="$(echo "${screen_size}" | awk '{print $2}')"
# Divide by two so the dialogs take up half of the screen, which looks nice. # Divide by two so the dialogs take up half of the screen, which looks nice.
r=$((rows / 2)) r=$((rows / 2))
@ -19,32 +19,51 @@ c=$(( columns / 2 ))
r=$((r < 20 ? 20 : r)) r=$((r < 20 ? 20 : r))
c=$((c < 70 ? 70 : c)) c=$((c < 70 ? 70 : c))
echo "::: The updating functionality for PiVPN scripts is temporarily disabled" # TODO: Delete this section when the updating functionality will be re-enabled
echo "::: To keep the VPN (and the system) up to date, use 'apt update' and 'apt upgrade'" ###
exit 0 err() {
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
}
chooseVPNCmd=(whiptail --backtitle "Setup PiVPN" --title "Installation mode" --separate-output --radiolist "Choose a VPN to update (press space to select):" "${r}" "${c}" 2) err "::: The updating functionality for PiVPN scripts is temporarily disabled"
err "::: To keep the VPN (and the system) up to date, use:"
err " apt update; apt upgrade"
exit 0
###
chooseVPNCmd=(whiptail
--backtitle "Setup PiVPN"
--title "Installation mode"
--separate-output
--radiolist "Choose a VPN to update (press space to select):"
"${r}" "${c}" 2)
VPNChooseOptions=(WireGuard "" on VPNChooseOptions=(WireGuard "" on
OpenVPN "" off) OpenVPN "" off)
if VPN=$("${chooseVPNCmd[@]}" "${VPNChooseOptions[@]}" 2>&1 >/dev/tty) ; then if VPN="$("${chooseVPNCmd[@]}" "${VPNChooseOptions[@]}" 2>&1 > /dev/tty)"; then
echo "::: Using VPN: $VPN" echo "::: Using VPN: ${VPN}"
VPN="${VPN,,}" VPN="${VPN,,}"
else else
echo "::: Cancel selected, exiting...." err "::: Cancel selected, exiting...."
exit 1 exit 1
fi fi
setupVars="/etc/pivpn/${VPN}/setupVars.conf" setupVars="/etc/pivpn/${VPN}/setupVars.conf"
if [ ! -f "${setupVars}" ]; then if [[ ! -f "${setupVars}" ]]; then
echo "::: Missing setup vars file!" err "::: Missing setup vars file!"
exit 1 exit 1
fi fi
# shellcheck disable=SC1090 # shellcheck disable=SC1090
source "${setupVars}" source "${setupVars}"
# TODO: Uncomment this function when the updating functionality
# will be re-enabled
#err() {
# echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
#}
scriptusage() { scriptusage() {
echo "::: Updates PiVPN scripts" echo "::: Updates PiVPN scripts"
echo ":::" echo ":::"
@ -59,66 +78,62 @@ scriptusage(){
### Functions ### Functions
## Updates scripts ## Updates scripts
updatepivpnscripts() { updatepivpnscripts() {
local branch
branch="${1}"
## We don't know what sort of changes users have made. ## We don't know what sort of changes users have made.
## Lets remove first /etc/.pivpn dir then clone it back again ## Lets remove first /etc/.pivpn dir then clone it back again
echo "going do update PiVPN Scripts" echo -n "Going do update PiVPN Scripts"
if [[ -d "$pivpnlocalpath" ]]; then
if [[ -n "$pivpnlocalpath" ]]; then
rm -rf "${pivpnlocalpath}/../.pivpn"
cloneandupdate
fi
else
cloneandupdate
fi
echo "PiVPN Scripts have been updated"
# Disabling warning for SC1090
}
##Updates scripts using test branch if [[ -z "${branch}" ]]; then
updatefromtest(){ echo "from ${branch} branch"
##We don't know what sort of changes users have made.
##Lets remove first /etc/.pivpn dir then clone it back again
echo "PiVPN Scripts updating from test branch"
if [[ -d "$pivpnlocalpath" ]]; then
if [[ -n "$pivpnlocalpath" ]]; then
rm -rf "${pivpnlocalpath}/../.pivpn"
cloneupdttest
fi
else else
cloneupdttest echo
fi
if [[ -d "${pivpnlocalpath}" ]] \
&& [[ -n "${pivpnlocalpath}" ]]; then
rm -rf "${pivpnlocalpath}/../.pivpn"
fi
cloneandupdate "${branch}"
echo -n "PiVPN Scripts have been updated"
if [[ -z "${branch}" ]]; then
echo "from ${branch} branch"
else
echo
fi fi
echo "PiVPN Scripts updated have been updated from test branch"
} }
## Clone and copy pivpn scripts to /opt/pivpn ## Clone and copy pivpn scripts to /opt/pivpn
cloneandupdate() { cloneandupdate() {
git clone "$pivpnrepo" "$pivpnlocalpath" local branch
cp "${pivpnlocalpath}"/scripts/*.sh "$pivpnscripts" branch="${1}"
cp "${pivpnlocalpath}"/scripts/"$VPN"/*.sh "$pivpnscripts" git clone "${pivpnrepo}" "${pivpnlocalpath}"
cp "${pivpnlocalpath}"/scripts/"$VPN"/bash-completion "$bashcompletiondir"
}
##same as cloneandupdate() but from test branch if [[ -z "${branch}" ]]; then
##and falls back to master branch again after updating git -C "${pivpnlocalpath}" checkout "${branch}"
cloneupdttest(){ git -C "${pivpnlocalpath}" pull origin "${branch}"
git clone "$pivpnrepo" "$pivpnlocalpath" fi
git -C "$pivpnlocalpath" checkout test
git -C "$pivpnlocalpath" pull origin test cp "${pivpnlocalpath}"/scripts/*.sh "${pivpnscripts}"
cp "${pivpnlocalpath}"/scripts/*.sh "$pivpnscripts" cp "${pivpnlocalpath}"/scripts/"${VPN}"/*.sh "${pivpnscripts}"
cp "${pivpnlocalpath}"/scripts/"$VPN"/*.sh "$pivpnscripts" cp "${pivpnlocalpath}"/scripts/"${VPN}"/bash-completion "${bashcompletiondir}"
cp "${pivpnlocalpath}"/scripts/"$VPN"/bash-completion "$bashcompletiondir"
git -C "$pivpnlocalpath" checkout master if [[ -z "${branch}" ]]; then
git -C "${pivpnlocalpath}" checkout master
fi
} }
## SCRIPT ## SCRIPT
if [[ $# -eq 0 ]]; then if [[ "$#" -eq 0 ]]; then
updatepivpnscripts updatepivpnscripts
else else
while true; do while true; do
case "$1" in case "${1}" in
-t | test) -t | test)
updatefromtest updatepivpnscripts 'test'
exit 0 exit 0
;; ;;
-h | help) -h | help)

View file

@ -1,18 +1,22 @@
#!/bin/bash #!/bin/bash
_pivpn()
{ _pivpn() {
local cur opts local cur opts
COMPREPLY=() COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}" cur="${COMP_WORDS[COMP_CWORD]}"
dashopts="-a -c -d -l -qr -r -h -u -up -bk -off -on" dashopts="-a -c -d -l -qr -r -h -u -up -bk -off -on"
opts="add clients debug list qrcode remove help uninstall update backup (temp) off (temp) on" opts="add clients debug list qrcode remove help uninstall update"
if [ "${#COMP_WORDS[@]}" -eq 2 ]; then opts="${opts} backup (temp) off (temp) on"
if [[ ${cur} == -* ]] ; then
if [[ "${#COMP_WORDS[@]}" -eq 2 ]]; then
if [[ "${cur}" == -* ]]; then
COMPREPLY=("$(compgen -W "${dashopts}" -- "${cur}")") COMPREPLY=("$(compgen -W "${dashopts}" -- "${cur}")")
else else
COMPREPLY=("$(compgen -W "${opts}" -- "${cur}")") COMPREPLY=("$(compgen -W "${opts}" -- "${cur}")")
fi fi
fi fi
return 0 return 0
} }
complete -F _pivpn pivpn complete -F _pivpn pivpn

View file

@ -1,13 +1,17 @@
#!/usr/bin/env bash #!/bin/bash
# PiVPN: client status script # PiVPN: client status script
CLIENTS_FILE="/etc/wireguard/configs/clients.txt" CLIENTS_FILE="/etc/wireguard/configs/clients.txt"
if [ ! -s "$CLIENTS_FILE" ]; then if [[ ! -s "${CLIENTS_FILE}" ]]; then
echo "::: There are no clients to list" err "::: There are no clients to list"
exit 0 exit 0
fi fi
err() {
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
}
scriptusage() { scriptusage() {
echo "::: List any connected clients to the server" echo "::: List any connected clients to the server"
echo ":::" echo ":::"
@ -20,12 +24,12 @@ scriptusage(){
} }
hr() { hr() {
numfmt --to=iec-i --suffix=B "$1" numfmt --to=iec-i --suffix=B "${1}"
} }
listClients() { listClients() {
if DUMP="$(wg show wg0 dump)"; then if DUMP="$(wg show wg0 dump)"; then
DUMP="$(tail -n +2 <<< "$DUMP")" DUMP="$(tail -n +2 <<< "${DUMP}")"
else else
exit 1 exit 1
fi fi
@ -33,48 +37,58 @@ listClients(){
printf "\e[1m::: Connected Clients List :::\e[0m\n" printf "\e[1m::: Connected Clients List :::\e[0m\n"
{ {
printf "\e[4mName\e[0m \t \e[4mRemote IP\e[0m \t \e[4mVirtual IP\e[0m \t \e[4mBytes Received\e[0m \t \e[4mBytes Sent\e[0m \t \e[4mLast Seen\e[0m\n" printf "\e[4mName\e[0m \t \e[4mRemote IP\e[0m \t \e[4mVirtual IP\e[0m"
printf "\t \e[4mBytes Received\e[0m \t \e[4mBytes Sent\e[0m "
printf "\t \e[4mLast Seen\e[0m\n"
while IFS= read -r LINE; do while IFS= read -r LINE; do
if [ -n "${LINE}" ]; then if [[ -n "${LINE}" ]]; then
PUBLIC_KEY="$(awk '{ print $1 }' <<< "$LINE")" PUBLIC_KEY="$(awk '{ print $1 }' <<< "${LINE}")"
REMOTE_IP="$(awk '{ print $3 }' <<< "$LINE")" REMOTE_IP="$(awk '{ print $3 }' <<< "${LINE}")"
VIRTUAL_IP="$(awk '{ print $4 }' <<< "$LINE")" VIRTUAL_IP="$(awk '{ print $4 }' <<< "${LINE}")"
BYTES_RECEIVED="$(awk '{ print $6 }' <<< "$LINE")" BYTES_RECEIVED="$(awk '{ print $6 }' <<< "${LINE}")"
BYTES_SENT="$(awk '{ print $7 }' <<< "$LINE")" BYTES_SENT="$(awk '{ print $7 }' <<< "${LINE}")"
LAST_SEEN="$(awk '{ print $5 }' <<< "$LINE")" LAST_SEEN="$(awk '{ print $5 }' <<< "${LINE}")"
CLIENT_NAME="$(grep "$PUBLIC_KEY" "$CLIENTS_FILE" | awk '{ print $1 }')" CLIENT_NAME="$(grep "${PUBLIC_KEY}" "${CLIENTS_FILE}" \
if [ "$HR" = 1 ]; then | awk '{ print $1 }')"
if [ "$LAST_SEEN" -ne 0 ]; then printf "%s \t %s \t %s \t " \
printf "%s \t %s \t %s \t %s \t %s \t %s\n" "$CLIENT_NAME" "$REMOTE_IP" "${VIRTUAL_IP/\/32/}" "$(hr "$BYTES_RECEIVED")" "$(hr "$BYTES_SENT")" "$(date -d @"$LAST_SEEN" '+%b %d %Y - %T')" "${CLIENT_NAME}" \
"${REMOTE_IP}" \
"${VIRTUAL_IP/\/32/}"
if [[ "${HR}" == 1 ]]; then
printf "%s \t %s \t " \
"$(hr "${BYTES_RECEIVED}")" \
"$(hr "${BYTES_SENT}")"
else else
printf "%s \t %s \t %s \t %s \t %s \t %s\n" "$CLIENT_NAME" "$REMOTE_IP" "${VIRTUAL_IP/\/32/}" "$(hr "$BYTES_RECEIVED")" "$(hr "$BYTES_SENT")" "(not yet)" printf "%s \t %s \t " "${BYTES_RECEIVED}" "${BYTES_SENT}"
fi fi
if [[ "${LAST_SEEN}" -ne 0 ]]; then
printf "%s" "$(date -d @"${LAST_SEEN}" '+%b %d %Y - %T')"
else else
if [ "$LAST_SEEN" -ne 0 ]; then printf "(not yet)"
printf "%s \t %s \t %s \t %'d \t %'d \t %s\n" "$CLIENT_NAME" "$REMOTE_IP" "${VIRTUAL_IP/\/32/}" "$BYTES_RECEIVED" "$BYTES_SENT" "$(date -d @"$LAST_SEEN" '+%b %d %Y - %T')"
else
printf "%s \t %s \t %s \t %'d \t %'d \t %s\n" "$CLIENT_NAME" "$REMOTE_IP" "${VIRTUAL_IP/\/32/}" "$BYTES_RECEIVED" "$BYTES_SENT" "(not yet)"
fi fi
fi
fi
done <<< "$DUMP"
printf "\n" printf "\n"
} | column -t -s $'\t' fi
done <<< "${DUMP}"
printf "\n"
} | column -ts $'\t'
cd /etc/wireguard || return cd /etc/wireguard || return
echo "::: Disabled clients :::" echo "::: Disabled clients :::"
grep '\[disabled\] ### begin' wg0.conf | sed 's/#//g; s/begin//' grep '\[disabled\] ### begin' wg0.conf | sed 's/#//g; s/begin//'
} }
if [[ $# -eq 0 ]]; then if [[ "$#" -eq 0 ]]; then
HR=1 HR=1
listClients listClients
else else
while true; do while true; do
case "$1" in case "${1}" in
-b | bytes) -b | bytes)
HR=0 HR=0
listClients listClients

View file

@ -2,18 +2,23 @@
setupVars="/etc/pivpn/wireguard/setupVars.conf" setupVars="/etc/pivpn/wireguard/setupVars.conf"
if [ ! -f "${setupVars}" ]; then if [[ ! -f "${setupVars}" ]]; then
echo "::: Missing setup vars file!" err "::: Missing setup vars file!"
exit 1 exit 1
fi fi
# shellcheck disable=SC1090 # shellcheck disable=SC1090
source "${setupVars}" source "${setupVars}"
err() {
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
}
helpFunc() { helpFunc() {
echo "::: Disable client conf profiles" echo "::: Disable client conf profiles"
echo ":::" echo ":::"
echo "::: Usage: pivpn <-off|off> [-h|--help] [-v] [<client-1> ... [<client-2>] ...] " echo -n "::: Usage: pivpn <-off|off> [-h|--help] [-v] "
echo "[<client-1> ... [<client-2>] ...]"
echo ":::" echo ":::"
echo "::: Commands:" echo "::: Commands:"
echo "::: [none] Interactive mode" echo "::: [none] Interactive mode"
@ -24,9 +29,10 @@ helpFunc(){
} }
# Parse input arguments # Parse input arguments
while test $# -gt 0; do while [[ "$#" -gt 0 ]]; do
_key="$1" _key="${1}"
case "$_key" in
case "${_key}" in
-h | --help) -h | --help)
helpFunc helpFunc
exit 0 exit 0
@ -38,39 +44,43 @@ while test $# -gt 0; do
DISPLAY_DISABLED=true DISPLAY_DISABLED=true
;; ;;
*) *)
CLIENTS_TO_CHANGE+=("$1") CLIENTS_TO_CHANGE+=("${1}")
;; ;;
esac esac
shift shift
done done
cd /etc/wireguard || exit cd /etc/wireguard || exit
if [ ! -s configs/clients.txt ]; then
echo "::: There are no clients to change" if [[ ! -s configs/clients.txt ]]; then
err "::: There are no clients to change"
exit 1 exit 1
fi fi
if [[ "${DISPLAY_DISABLED}" ]]; then
if [ "$DISPLAY_DISABLED" ]; then
grep '\[disabled\] ### begin' wg0.conf | sed 's/#//g; s/begin//' grep '\[disabled\] ### begin' wg0.conf | sed 's/#//g; s/begin//'
exit 1 exit 1
fi fi
mapfile -t LIST < <(awk '{print $1}' configs/clients.txt) mapfile -t LIST < <(awk '{print $1}' configs/clients.txt)
if [ "${#CLIENTS_TO_CHANGE[@]}" -eq 0 ]; then
if [[ "${#CLIENTS_TO_CHANGE[@]}" -eq 0 ]]; then
echo -e "::\e[4m Client list \e[0m::" echo -e "::\e[4m Client list \e[0m::"
len=${#LIST[@]} len="${#LIST[@]}"
COUNTER=1 COUNTER=1
while [ $COUNTER -le "${len}" ]; do
while [[ "${COUNTER}" -le "${len}" ]]; do
printf "%0${#len}s) %s\r\n" "${COUNTER}" "${LIST[(($COUNTER - 1))]}" printf "%0${#len}s) %s\r\n" "${COUNTER}" "${LIST[(($COUNTER - 1))]}"
((COUNTER++)) ((COUNTER++))
done done
read -r -p "Please enter the Index/Name of the Client to be removed from the list above: " CLIENTS_TO_CHANGE echo -n "Please enter the Index/Name of the Client to be removed "
echo -n "from the list above: "
read -r CLIENTS_TO_CHANGE
if [ -z "${CLIENTS_TO_CHANGE}" ]; then if [[ -z "${CLIENTS_TO_CHANGE}" ]]; then
echo "::: You can not leave this blank!" err "::: You can not leave this blank!"
exit 1 exit 1
fi fi
fi fi
@ -78,10 +88,9 @@ fi
CHANGED_COUNT=0 CHANGED_COUNT=0
for CLIENT_NAME in "${CLIENTS_TO_CHANGE[@]}"; do for CLIENT_NAME in "${CLIENTS_TO_CHANGE[@]}"; do
re='^[0-9]+$' re='^[0-9]+$'
if [[ ${CLIENT_NAME} =~ $re ]] ; then if [[ "${CLIENT_NAME}" =~ $re ]]; then
CLIENT_NAME=${LIST[$((CLIENT_NAME -1))]} CLIENT_NAME="${LIST[$((CLIENT_NAME - 1))]}"
fi fi
if ! grep -q "^${CLIENT_NAME} " configs/clients.txt; then if ! grep -q "^${CLIENT_NAME} " configs/clients.txt; then
@ -89,40 +98,41 @@ for CLIENT_NAME in "${CLIENTS_TO_CHANGE[@]}"; do
elif grep -q "#\[disabled\] ### begin ${CLIENT_NAME}" wg0.conf; then elif grep -q "#\[disabled\] ### begin ${CLIENT_NAME}" wg0.conf; then
echo -e "::: \e[1m${CLIENT_NAME}\e[0m is already disabled" echo -e "::: \e[1m${CLIENT_NAME}\e[0m is already disabled"
else else
if [ -n "$CONFIRM" ]; then if [[ -n "${CONFIRM}" ]]; then
REPLY="y" REPLY="y"
else else
read -r -p "Confirm you want to disable $CLIENT_NAME? [Y/n] " read -r -p "Confirm you want to disable ${CLIENT_NAME}? [Y/n] "
fi fi
if [[ $REPLY =~ ^[Yy]$ ]]; then if [[ "${REPLY}" =~ ^[Yy]$ ]]; then
# Disable the peer section from the server config # Disable the peer section from the server config
echo "${CLIENT_NAME}" echo "${CLIENT_NAME}"
sed -e "/### begin ${CLIENT_NAME}/,/end ${CLIENT_NAME}/ s/^/#\[disabled\] /" -i wg0.conf
echo "::: Updated server config"
sed_pattern="/### begin ${CLIENT_NAME}/,"
sed_pattern="${sed_pattern}/end ${CLIENT_NAME}/ s/^/#\[disabled\] /"
sed -e "${sed_pattern}" -i wg0.conf
unset sed_pattern
echo "::: Updated server config"
((CHANGED_COUNT++)) ((CHANGED_COUNT++))
echo "::: Successfully disabled ${CLIENT_NAME}" echo "::: Successfully disabled ${CLIENT_NAME}"
fi fi
fi fi
done done
# Restart WireGuard only if some clients were actually deleted # Restart WireGuard only if some clients were actually deleted
if [ "${CHANGED_COUNT}" -gt 0 ]; then if [[ "${CHANGED_COUNT}" -gt 0 ]]; then
if [ "${PLAT}" == 'Alpine' ]; then if [[ "${PLAT}" == 'Alpine' ]]; then
if rc-service wg-quick restart; then if rc-service wg-quick restart; then
echo "::: WireGuard reloaded" echo "::: WireGuard reloaded"
else else
echo "::: Failed to reload WireGuard" err "::: Failed to reload WireGuard"
fi fi
else else
if systemctl reload wg-quick@wg0; then if systemctl reload wg-quick@wg0; then
echo "::: WireGuard reloaded" echo "::: WireGuard reloaded"
else else
echo "::: Failed to reload WireGuard" err "::: Failed to reload WireGuard"
fi fi
fi fi
fi fi

View file

@ -2,18 +2,23 @@
setupVars="/etc/pivpn/wireguard/setupVars.conf" setupVars="/etc/pivpn/wireguard/setupVars.conf"
if [ ! -f "${setupVars}" ]; then if [[ ! -f "${setupVars}" ]]; then
echo "::: Missing setup vars file!" err "::: Missing setup vars file!"
exit 1 exit 1
fi fi
# shellcheck disable=SC1090 # shellcheck disable=SC1090
source "${setupVars}" source "${setupVars}"
err() {
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
}
helpFunc() { helpFunc() {
echo "::: Enables client conf profiles" echo "::: Enables client conf profiles"
echo ":::" echo ":::"
echo "::: Usage: pivpn <-on|on> [-h|--help] [-v] [<client-1> ... [<client-2>] ...] " echo -n "::: Usage: pivpn <-on|on> [-h|--help] [-v] "
echo "[<client-1> ... [<client-2>] ...]"
echo ":::" echo ":::"
echo "::: Commands:" echo "::: Commands:"
echo "::: [none] Interactive mode" echo "::: [none] Interactive mode"
@ -24,9 +29,10 @@ helpFunc(){
} }
# Parse input arguments # Parse input arguments
while test $# -gt 0; do while [[ "$#" -gt 0 ]]; do
_key="$1" _key="${1}"
case "$_key" in
case "${_key}" in
-h | --help) -h | --help)
helpFunc helpFunc
exit 0 exit 0
@ -38,37 +44,43 @@ while test $# -gt 0; do
DISPLAY_DISABLED=true DISPLAY_DISABLED=true
;; ;;
*) *)
CLIENTS_TO_CHANGE+=("$1") CLIENTS_TO_CHANGE+=("${1}")
;; ;;
esac esac
shift shift
done done
cd /etc/wireguard || exit cd /etc/wireguard || exit
if [ ! -s configs/clients.txt ]; then
echo "::: There are no clients to change" if [[ ! -s configs/clients.txt ]]; then
err "::: There are no clients to change"
exit 1 exit 1
fi fi
if [ "$DISPLAY_DISABLED" ]; then if [[ "${DISPLAY_DISABLED}" ]]; then
grep '\[disabled\] ### begin' wg0.conf | sed 's/#//g; s/begin//' grep '\[disabled\] ### begin' wg0.conf | sed 's/#//g; s/begin//'
exit 1 exit 1
fi fi
mapfile -t LIST < <(awk '{print $1}' configs/clients.txt) mapfile -t LIST < <(awk '{print $1}' configs/clients.txt)
if [ "${#CLIENTS_TO_CHANGE[@]}" -eq 0 ]; then
if [[ "${#CLIENTS_TO_CHANGE[@]}" -eq 0 ]]; then
echo -e "::\e[4m Client list \e[0m::" echo -e "::\e[4m Client list \e[0m::"
len=${#LIST[@]} len="${#LIST[@]}"
COUNTER=1 COUNTER=1
while [ $COUNTER -le "${len}" ]; do
while [[ "${COUNTER}" -le "${len}" ]]; do
printf "%0${#len}s) %s\r\n" "${COUNTER}" "${LIST[(($COUNTER - 1))]}" printf "%0${#len}s) %s\r\n" "${COUNTER}" "${LIST[(($COUNTER - 1))]}"
((COUNTER++)) ((COUNTER++))
done done
read -r -p "Please enter the Index/Name of the Client to be enabled from the list above: " CLIENTS_TO_CHANGE echo -n "Please enter the Index/Name of the Client to be enabled "
echo -n "from the list above: "
read -r CLIENTS_TO_CHANGE
if [ -z "${CLIENTS_TO_CHANGE}" ]; then if [[ -z "${CLIENTS_TO_CHANGE}" ]]; then
echo "::: You can not leave this blank!" err "::: You can not leave this blank!"
exit 1 exit 1
fi fi
fi fi
@ -76,49 +88,50 @@ fi
CHANGED_COUNT=0 CHANGED_COUNT=0
for CLIENT_NAME in "${CLIENTS_TO_CHANGE[@]}"; do for CLIENT_NAME in "${CLIENTS_TO_CHANGE[@]}"; do
re='^[0-9]+$' re='^[0-9]+$'
if [[ ${CLIENT_NAME} =~ $re ]] ; then
CLIENT_NAME=${LIST[$((CLIENT_NAME -1))]} if [[ "${CLIENT_NAME}" =~ $re ]]; then
CLIENT_NAME="${LIST[$((CLIENT_NAME - 1))]}"
fi fi
if ! grep -q "^${CLIENT_NAME} " configs/clients.txt; then if ! grep -q "^${CLIENT_NAME} " configs/clients.txt; then
echo -e "::: \e[1m${CLIENT_NAME}\e[0m does not exist" echo -e "::: \e[1m${CLIENT_NAME}\e[0m does not exist"
else else
if [ -n "$CONFIRM" ]; then if [[ -n "${CONFIRM}" ]]; then
REPLY="y" REPLY="y"
else else
read -r -p "Confirm you want to enable $CLIENT_NAME? [Y/n] " read -r -p "Confirm you want to enable ${CLIENT_NAME}? [Y/n] "
fi fi
if [[ $REPLY =~ ^[Yy]$ ]]; then if [[ "${REPLY}" =~ ^[Yy]$ ]]; then
# Enable the peer section from the server config # Enable the peer section from the server config
echo "${CLIENT_NAME}" echo "${CLIENT_NAME}"
sed -e "/begin ${CLIENT_NAME}/,/end ${CLIENT_NAME}/ s/#\[disabled\] //" -i wg0.conf
echo "::: Updated server config"
sed_pattern="/begin ${CLIENT_NAME}/,"
sed_pattern="${sed_pattern}/end ${CLIENT_NAME}/ s/#\[disabled\] //"
sed -e "${sed_pattern}" -i wg0.conf
unset sed_pattern
echo "::: Updated server config"
((CHANGED_COUNT++)) ((CHANGED_COUNT++))
echo "::: Successfully enabled ${CLIENT_NAME}" echo "::: Successfully enabled ${CLIENT_NAME}"
fi fi
fi fi
done done
# Restart WireGuard only if some clients were actually deleted # Restart WireGuard only if some clients were actually deleted
if [ "${CHANGED_COUNT}" -gt 0 ]; then if [[ "${CHANGED_COUNT}" -gt 0 ]]; then
if [ "${PLAT}" == 'Alpine' ]; then if [[ "${PLAT}" == 'Alpine' ]]; then
if rc-service wg-quick restart; then if rc-service wg-quick restart; then
echo "::: WireGuard reloaded" echo "::: WireGuard reloaded"
else else
echo "::: Failed to reload WireGuard" err "::: Failed to reload WireGuard"
fi fi
else else
if systemctl reload wg-quick@wg0; then if systemctl reload wg-quick@wg0; then
echo "::: WireGuard reloaded" echo "::: WireGuard reloaded"
else else
echo "::: Failed to reload WireGuard" err "::: Failed to reload WireGuard"
fi fi
fi fi
fi fi

View file

@ -1,8 +1,13 @@
#!/bin/bash #!/bin/bash
err() {
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
}
cd /etc/wireguard/configs || exit cd /etc/wireguard/configs || exit
if [ ! -s clients.txt ]; then
echo "::: There are no clients to list" if [[ ! -s clients.txt ]]; then
err "::: There are no clients to list"
exit 1 exit 1
fi fi
@ -10,24 +15,20 @@ printf "\e[1m::: Clients Summary :::\e[0m\n"
# Present the user with a summary of the clients, fetching info from dates. # Present the user with a summary of the clients, fetching info from dates.
{ {
echo -e "\e[4mClient\e[0m \t \e[4mPublic key\e[0m \t \e[4mCreation date\e[0m" echo -ne "\e[4mClient\e[0m \t \e[4mPublic key\e[0m \t "
echo -e "\e[4mCreation date\e[0m"
while read -r LINE; do while read -r LINE; do
CLIENT_NAME="$(awk '{print $1}' <<< "$LINE")" CLIENT_NAME="$(awk '{print $1}' <<< "${LINE}")"
PUBLIC_KEY="$(awk '{print $2}' <<< "${LINE}")"
PUBLIC_KEY="$(awk '{print $2}' <<< "$LINE")" CREATION_DATE="$(awk '{print $3}' <<< "${LINE}")"
CREATION_DATE="$(awk '{print $3}' <<< "$LINE")"
# Dates are converted from UNIX time to human readable. # Dates are converted from UNIX time to human readable.
CD_FORMAT="$(date -d @"$CREATION_DATE" +'%d %b %Y, %H:%M, %Z')" CD_FORMAT="$(date -d @"${CREATION_DATE}" +'%d %b %Y, %H:%M, %Z')"
echo -e "${CLIENT_NAME} \t ${PUBLIC_KEY} \t ${CD_FORMAT}"
echo -e "$CLIENT_NAME \t $PUBLIC_KEY \t $CD_FORMAT"
done < clients.txt done < clients.txt
} | column -t -s $'\t' } | column -t -s $'\t'
cd /etc/wireguard || return cd /etc/wireguard || return
echo "::: Disabled clients :::" echo "::: Disabled clients :::"
grep '\[disabled\] ### begin' wg0.conf | sed 's/#//g; s/begin//' grep '\[disabled\] ### begin' wg0.conf | sed 's/#//g; s/begin//'

View file

@ -1,20 +1,25 @@
#!/bin/bash #!/bin/bash
######## Some vars that might be empty # Some vars that might be empty but need to be defined for checks
# but need to be defined for checks
pivpnPERSISTENTKEEPALIVE="" pivpnPERSISTENTKEEPALIVE=""
pivpnDNS2="" pivpnDNS2=""
setupVars="/etc/pivpn/wireguard/setupVars.conf" setupVars="/etc/pivpn/wireguard/setupVars.conf"
# shellcheck disable=SC2154
userGroup="${install_user}:${install_user}"
if [ ! -f "${setupVars}" ]; then if [[ ! -f "${setupVars}" ]]; then
echo "::: Missing setup vars file!" err "::: Missing setup vars file!"
exit 1 exit 1
fi fi
# shellcheck disable=SC1090 # shellcheck disable=SC1090
source "${setupVars}" source "${setupVars}"
err() {
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
}
helpFunc() { helpFunc() {
echo "::: Create a client conf profile" echo "::: Create a client conf profile"
echo ":::" echo ":::"
@ -22,85 +27,85 @@ helpFunc(){
echo ":::" echo ":::"
echo "::: Commands:" echo "::: Commands:"
echo "::: [none] Interactive mode" echo "::: [none] Interactive mode"
echo "::: -n,--name Name for the Client (default: '$HOSTNAME')" echo "::: -n,--name Name for the Client (default: '${HOSTNAME}')"
echo "::: -h,--help Show this help dialog" echo "::: -h,--help Show this help dialog"
} }
# Parse input arguments # Parse input arguments
while test $# -gt 0; do while [[ "$#" -gt 0 ]]; do
_key="$1" _key="${1}"
case "$_key" in
case "${_key}" in
-n | --name | --name=*) -n | --name | --name=*)
_val="${_key##--name=}" _val="${_key##--name=}"
if test "$_val" = "$_key"; then
test $# -lt 2 && echo "::: Missing value for the optional argument '$_key'." && exit 1 if [[ "${_val}" == "${_key}" ]]; then
_val="$2" [[ "$#" -lt 2 ]] \
&& err "::: Missing value for the optional argument '${_key}'." \
&& exit 1
_val="${2}"
shift shift
fi fi
CLIENT_NAME="$_val"
CLIENT_NAME="${_val}"
;; ;;
-h | --help) -h | --help)
helpFunc helpFunc
exit 0 exit 0
;; ;;
*) *)
echo "::: Error: Got an unexpected argument '$1'" err "::: Error: Got an unexpected argument '${1}'"
helpFunc helpFunc
exit 1 exit 1
;; ;;
esac esac
shift shift
done done
# Disabling SC2154, variables sourced externaly # Disabling SC2154, variables sourced externaly
# shellcheck disable=SC2154 # shellcheck disable=SC2154
# The home folder variable was sourced from the settings file. # The home folder variable was sourced from the settings file.
if [ ! -d "${install_home}/configs" ]; then if [[ ! -d "${install_home}/configs" ]]; then
mkdir "${install_home}/configs" mkdir "${install_home}/configs"
chown "${install_user}":"${install_user}" "${install_home}/configs" chown "${userGroup}" "${install_home}/configs"
chmod 0750 "${install_home}/configs" chmod 0750 "${install_home}/configs"
fi fi
cd /etc/wireguard || exit cd /etc/wireguard || exit
if [ -z "${CLIENT_NAME}" ]; then if [[ -z "${CLIENT_NAME}" ]]; then
read -r -p "Enter a Name for the Client: " CLIENT_NAME read -r -p "Enter a Name for the Client: " CLIENT_NAME
fi elif [[ "${CLIENT_NAME}" =~ [^a-zA-Z0-9.@_-] ]]; then
err "Name can only contain alphanumeric characters and these symbols (.-@_)."
if [[ "${CLIENT_NAME}" =~ [^a-zA-Z0-9.@_-] ]]; then exit 1
echo "Name can only contain alphanumeric characters and these characters (.-@_)." elif [[ "${CLIENT_NAME:0:1}" == "-" ]]; then
err "Name cannot start with -"
exit 1
elif [[ "${CLIENT_NAME}" =~ ^[0-9]+$ ]]; then
err "Names cannot be integers."
exit 1
elif [[ -z "${CLIENT_NAME}" ]]; then
err "::: You cannot leave the name blank."
exit 1
elif [[ -f "configs/${CLIENT_NAME}.conf" ]]; then
err "::: A client with this name already exists"
exit 1 exit 1
fi fi
if [[ "${CLIENT_NAME:0:1}" == "-" ]]; then wg genkey \
echo "Name cannot start with -" | tee "keys/${CLIENT_NAME}_priv" \
exit 1 | wg pubkey > "keys/${CLIENT_NAME}_pub"
fi
if [[ "${CLIENT_NAME}" =~ ^[0-9]+$ ]]; then
echo "Names cannot be integers."
exit 1
fi
if [ -z "${CLIENT_NAME}" ]; then
echo "::: You cannot leave the name blank."
exit 1
fi
if [ -f "configs/${CLIENT_NAME}.conf" ]; then
echo "::: A client with this name already exists"
exit 1
fi
wg genkey | tee "keys/${CLIENT_NAME}_priv" | wg pubkey > "keys/${CLIENT_NAME}_pub"
wg genpsk | tee "keys/${CLIENT_NAME}_psk" &> /dev/null wg genpsk | tee "keys/${CLIENT_NAME}_psk" &> /dev/null
echo "::: Client Keys generated" echo "::: Client Keys generated"
# Find an unused number for the last octet of the client IP # Find an unused number for the last octet of the client IP
for i in {2..254}; do for i in {2..254}; do
if ! grep -q " $i$" configs/clients.txt; then if ! grep -q " ${i}$" configs/clients.txt; then
COUNT="$i" COUNT="${i}"
echo "${CLIENT_NAME} $(<keys/"${CLIENT_NAME}"_pub) $(date +%s) ${COUNT}" >> configs/clients.txt echo "${CLIENT_NAME} $(< keys/"${CLIENT_NAME}"_pub) $(date +%s) ${COUNT}" \
| tee -a configs/clients.txt > /dev/null
break break
fi fi
done done
@ -110,88 +115,95 @@ done
NET_REDUCED="${pivpnNET::-2}" NET_REDUCED="${pivpnNET::-2}"
# shellcheck disable=SC2154 # shellcheck disable=SC2154
if [ "$pivpnenableipv6" == "1" ]; then {
echo "[Interface] echo '[Interface]'
PrivateKey = $(cat "keys/${CLIENT_NAME}_priv") echo "PrivateKey = $(cat "keys/${CLIENT_NAME}_priv")"
Address = ${NET_REDUCED}.${COUNT}/${subnetClass},${pivpnNETv6}${COUNT}/${subnetClassv6}" > "configs/${CLIENT_NAME}.conf" echo -n "Address = ${NET_REDUCED}.${COUNT}/${subnetClass}"
if [[ "${pivpnenableipv6}" == 1 ]]; then
echo ",${pivpnNETv6}${COUNT}/${subnetClassv6}"
else else
echo "[Interface] echo
PrivateKey = $(cat "keys/${CLIENT_NAME}_priv")
Address = ${NET_REDUCED}.${COUNT}/${subnetClass}" > "configs/${CLIENT_NAME}.conf"
fi fi
# shellcheck disable=SC2154 echo -n "DNS = ${pivpnDNS1}"
echo -n "DNS = ${pivpnDNS1}" >> "configs/${CLIENT_NAME}.conf"
if [ -n "${pivpnDNS2}" ]; then if [[ -n "${pivpnDNS2}" ]]; then
echo ", ${pivpnDNS2}" >> "configs/${CLIENT_NAME}.conf" echo ", ${pivpnDNS2}"
else else
echo >> "configs/${CLIENT_NAME}.conf" echo
fi fi
echo >> "configs/${CLIENT_NAME}.conf"
# shellcheck disable=SC2154 echo
echo "[Peer] echo '[Peer]'
PublicKey = $(cat keys/server_pub) echo "PublicKey = $(cat keys/server_pub)"
PresharedKey = $(cat "keys/${CLIENT_NAME}_psk") echo "PresharedKey = $(cat "keys/${CLIENT_NAME}_psk")"
Endpoint = ${pivpnHOST}:${pivpnPORT} echo "Endpoint = ${pivpnHOST}:${pivpnPORT}"
AllowedIPs = ${ALLOWED_IPS}" >> "configs/${CLIENT_NAME}.conf" echo "AllowedIPs = ${ALLOWED_IPS}"
if [ -n "${pivpnPERSISTENTKEEPALIVE}" ]; then if [[ -n "${pivpnPERSISTENTKEEPALIVE}" ]]; then
echo "PersistentKeepalive = ${pivpnPERSISTENTKEEPALIVE}" >> "configs/${CLIENT_NAME}.conf" echo "PersistentKeepalive = ${pivpnPERSISTENTKEEPALIVE}"
fi fi
} > "configs/${CLIENT_NAME}.conf"
echo "::: Client config generated" echo "::: Client config generated"
if [ "$pivpnenableipv6" == "1" ]; then {
echo "### begin ${CLIENT_NAME} ### echo "### begin ${CLIENT_NAME} ###"
[Peer] echo '[Peer]'
PublicKey = $(cat "keys/${CLIENT_NAME}_pub") echo "PublicKey = $(cat "keys/${CLIENT_NAME}_pub")"
PresharedKey = $(cat "keys/${CLIENT_NAME}_psk") echo "PresharedKey = $(cat "keys/${CLIENT_NAME}_psk")"
AllowedIPs = ${NET_REDUCED}.${COUNT}/32,${pivpnNETv6}${COUNT}/128 echo -n "AllowedIPs = ${NET_REDUCED}.${COUNT}/32"
### end ${CLIENT_NAME} ###" >> wg0.conf
if [[ "${pivpnenableipv6}" == 1 ]]; then
echo ",${pivpnNETv6}${COUNT}/128"
else else
echo "### begin ${CLIENT_NAME} ### echo
[Peer]
PublicKey = $(cat "keys/${CLIENT_NAME}_pub")
PresharedKey = $(cat "keys/${CLIENT_NAME}_psk")
AllowedIPs = ${NET_REDUCED}.${COUNT}/32
### end ${CLIENT_NAME} ###" >> wg0.conf
fi fi
echo "### end ${CLIENT_NAME} ###"
} >> wg0.conf
echo "::: Updated server config" echo "::: Updated server config"
if [ -f /etc/pivpn/hosts.wireguard ]; then if [[ -f /etc/pivpn/hosts.wireguard ]]; then
echo "${NET_REDUCED}.${COUNT} ${CLIENT_NAME}.pivpn" >> /etc/pivpn/hosts.wireguard echo "${NET_REDUCED}.${COUNT} ${CLIENT_NAME}.pivpn" \
if [ "$pivpnenableipv6" == "1" ]; then | tee -a /etc/pivpn/hosts.wireguard > /dev/null
echo "${pivpnNETv6}${COUNT} ${CLIENT_NAME}.pivpn" >> /etc/pivpn/hosts.wireguard
if [[ "${pivpnenableipv6}" == 1 ]]; then
echo "${pivpnNETv6}${COUNT} ${CLIENT_NAME}.pivpn" \
| tee -a /etc/pivpn/hosts.wireguard > /dev/null
fi fi
if killall -SIGHUP pihole-FTL; then if killall -SIGHUP pihole-FTL; then
echo "::: Updated hosts file for Pi-hole" echo "::: Updated hosts file for Pi-hole"
else else
echo "::: Failed to reload pihole-FTL configuration" err "::: Failed to reload pihole-FTL configuration"
fi fi
fi fi
if [ "${PLAT}" == 'Alpine' ]; then if [[ "${PLAT}" == 'Alpine' ]]; then
if rc-service wg-quick restart; then if rc-service wg-quick restart; then
echo "::: WireGuard reloaded" echo "::: WireGuard reloaded"
else else
echo "::: Failed to reload WireGuard" err "::: Failed to reload WireGuard"
fi fi
else else
if systemctl reload wg-quick@wg0; then if systemctl reload wg-quick@wg0; then
echo "::: WireGuard reloaded" echo "::: WireGuard reloaded"
else else
echo "::: Failed to reload WireGuard" err "::: Failed to reload WireGuard"
fi fi
fi fi
cp "configs/${CLIENT_NAME}.conf" "${install_home}/configs/${CLIENT_NAME}.conf" cp "configs/${CLIENT_NAME}.conf" "${install_home}/configs/${CLIENT_NAME}.conf"
chown "${install_user}":"${install_user}" "${install_home}/configs/${CLIENT_NAME}.conf" chown "${userGroup}" "${install_home}/configs/${CLIENT_NAME}.conf"
chmod 640 "${install_home}/configs/${CLIENT_NAME}.conf" chmod 640 "${install_home}/configs/${CLIENT_NAME}.conf"
echo "======================================================================" echo "======================================================================"
echo -e "::: Done! \e[1m${CLIENT_NAME}.conf successfully created!\e[0m" echo -e "::: Done! \e[1m${CLIENT_NAME}.conf successfully created!\e[0m"
echo "::: ${CLIENT_NAME}.conf was copied to ${install_home}/configs for easy transfer." echo -n "::: ${CLIENT_NAME}.conf was copied to ${install_home}/configs for easy"
echo "transfer."
echo "::: Please use this profile only on one device and create additional" echo "::: Please use this profile only on one device and create additional"
echo -e "::: profiles for other devices. You can also use \e[1mpivpn -qr\e[0m" echo -e "::: profiles for other devices. You can also use \e[1mpivpn -qr\e[0m"
echo "::: to generate a QR Code you can scan with the mobile app." echo "::: to generate a QR Code you can scan with the mobile app."

View file

@ -7,11 +7,11 @@ if grep -qsEe "^NAME\=['\"]?Alpine[a-zA-Z ]*['\"]?$" /etc/os-release; then
fi fi
# Must be root to use this tool # Must be root to use this tool
if [ $EUID -ne 0 ]; then if [[ "${EUID}" -ne 0 ]]; then
if eval "${CHECK_PKG_INSTALLED} sudo" &> /dev/null; then if ${CHECK_PKG_INSTALLED} sudo &> /dev/null; then
export SUDO="sudo" export SUDO="sudo"
else else
echo "::: Please install sudo or run this as root." err "::: Please install sudo or run this as root."
exit 1 exit 1
fi fi
fi fi
@ -19,71 +19,77 @@ fi
scriptdir="/opt/pivpn" scriptdir="/opt/pivpn"
vpn="wireguard" vpn="wireguard"
err() {
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
}
makeConf() { makeConf() {
shift shift
$SUDO ${scriptdir}/${vpn}/makeCONF.sh "$@" ${SUDO} "${scriptdir}/${vpn}/makeCONF.sh" "$@"
exit "$?" exit "${?}"
} }
listConnected() { listConnected() {
shift shift
$SUDO ${scriptdir}/${vpn}/clientSTAT.sh "$@" ${SUDO} "${scriptdir}/${vpn}/clientSTAT.sh" "$@"
exit "$?" exit "${?}"
} }
debug() { debug() {
echo "::: Generating Debug Output" echo "::: Generating Debug Output"
$SUDO ${scriptdir}/${vpn}/pivpnDEBUG.sh | tee /tmp/debug.log
${SUDO} "${scriptdir}/${vpn}/pivpnDEBUG.sh" | tee /tmp/debug.log
echo "::: " echo "::: "
echo "::: Debug output completed above." echo "::: Debug output completed above."
echo "::: Copy saved to /tmp/debug.log" echo "::: Copy saved to /tmp/debug.log"
echo "::: " echo "::: "
exit "$?" exit "${?}"
} }
listClients() { listClients() {
$SUDO ${scriptdir}/${vpn}/listCONF.sh ${SUDO} "${scriptdir}/${vpn}/listCONF.sh"
exit "$?" exit "${?}"
} }
showQrcode() { showQrcode() {
shift shift
$SUDO ${scriptdir}/${vpn}/qrcodeCONF.sh "$@" ${SUDO} "${scriptdir}/${vpn}/qrcodeCONF.sh" "$@"
exit "$?" exit "${?}"
} }
removeClient() { removeClient() {
shift shift
$SUDO ${scriptdir}/${vpn}/removeCONF.sh "$@" ${SUDO} "${scriptdir}/${vpn}/removeCONF.sh" "$@"
exit "$?" exit "${?}"
} }
disableClient() { disableClient() {
shift shift
$SUDO ${scriptdir}/${vpn}/disableCONF.sh "$@" ${SUDO} "${scriptdir}/${vpn}/disableCONF.sh" "$@"
exit "$?" exit "${?}"
} }
enableClient() { enableClient() {
shift shift
$SUDO ${scriptdir}/${vpn}/enableCONF.sh "$@" ${SUDO} "${scriptdir}/${vpn}/enableCONF.sh" "$@"
exit "$?" exit "${?}"
} }
uninstallServer() { uninstallServer() {
$SUDO ${scriptdir}/uninstall.sh "${vpn}" ${SUDO} "${scriptdir}/uninstall.sh" "${vpn}"
exit "$?" exit "${?}"
} }
updateScripts() { updateScripts() {
shift shift
$SUDO ${scriptdir}/update.sh "$@" ${SUDO} "${scriptdir}/update.sh" "$@"
exit "$?" exit "${?}"
} }
backup() { backup() {
$SUDO ${scriptdir}/backup.sh "${vpn}" ${SUDO} "${scriptdir}/backup.sh" "${vpn}"
exit "$?" exit "${?}"
} }
showHelp() { showHelp() {
@ -96,7 +102,8 @@ showHelp(){
echo "::: -c, clients List any connected clients to the server" echo "::: -c, clients List any connected clients to the server"
echo "::: -d, debug Start a debugging session if having trouble" echo "::: -d, debug Start a debugging session if having trouble"
echo "::: -l, list List all clients" echo "::: -l, list List all clients"
echo "::: -qr, qrcode Show the qrcode of a client for use with the mobile app" echo -n "::: -qr, qrcode Show the qrcode of a client for use "
echo "with the mobile app"
echo "::: -r, remove Remove a client" echo "::: -r, remove Remove a client"
echo "::: -off, off Disable a client" echo "::: -off, off Disable a client"
echo "::: -on, on Enable a client" echo "::: -on, on Enable a client"
@ -107,23 +114,49 @@ showHelp(){
exit 0 exit 0
} }
if [ $# = 0 ]; then if [[ "$#" == 0 ]]; then
showHelp showHelp
fi fi
# Handle redirecting to specific functions based on arguments # Handle redirecting to specific functions based on arguments
case "$1" in case "${1}" in
"-a" | "add" ) makeConf "$@";; "-a" | "add")
"-c" | "clients" ) listConnected "$@";; makeConf "$@"
"-d" | "debug" ) debug;; ;;
"-l" | "list" ) listClients;; "-c" | "clients")
"-qr" | "qrcode" ) showQrcode "$@";; listConnected "$@"
"-r" | "remove" ) removeClient "$@";; ;;
"-off" | "off" ) disableClient "$@";; "-d" | "debug")
"-on" | "on" ) enableClient "$@";; debug
"-h" | "help" ) showHelp;; ;;
"-u" | "uninstall" ) uninstallServer;; "-l" | "list")
"-up" | "update" ) updateScripts "$@" ;; listClients
"-bk" | "backup" ) backup ;; ;;
* ) showHelp;; "-qr" | "qrcode")
showQrcode "$@"
;;
"-r" | "remove")
removeClient "$@"
;;
"-off" | "off")
disableClient "$@"
;;
"-on" | "on")
enableClient "$@"
;;
"-h" | "help")
showHelp
;;
"-u" | "uninstall")
uninstallServer
;;
"-up" | "update")
updateScripts "$@"
;;
"-bk" | "backup")
backup
;;
*)
showHelp
;;
esac esac

View file

@ -1,10 +1,14 @@
#!/usr/bin/env bash #!/bin/bash
# This scripts runs as root # This scripts runs as root
setupVars="/etc/pivpn/wireguard/setupVars.conf" setupVars="/etc/pivpn/wireguard/setupVars.conf"
if [ ! -f "${setupVars}" ]; then err() {
echo "::: Missing setup vars file!" echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
}
if [[ ! -f "${setupVars}" ]]; then
err "::: Missing setup vars file!"
exit 1 exit 1
fi fi
@ -15,51 +19,75 @@ echo -e "::::\t\t\e[4mPiVPN debug\e[0m\t\t ::::"
printf "=============================================\n" printf "=============================================\n"
echo -e "::::\t\t\e[4mLatest commit\e[0m\t\t ::::" echo -e "::::\t\t\e[4mLatest commit\e[0m\t\t ::::"
echo -n "Branch: " echo -n "Branch: "
git --git-dir /usr/local/src/pivpn/.git rev-parse --abbrev-ref HEAD git --git-dir /usr/local/src/pivpn/.git rev-parse --abbrev-ref HEAD
git --git-dir /usr/local/src/pivpn/.git log -n 1 --format='Commit: %H%nAuthor: %an%nDate: %ad%nSummary: %s' git \
--git-dir /usr/local/src/pivpn/.git log -n 1 \
--format='Commit: %H%nAuthor: %an%nDate: %ad%nSummary: %s'
printf "=============================================\n" printf "=============================================\n"
echo -e "::::\t \e[4mInstallation settings\e[0m \t ::::" echo -e "::::\t \e[4mInstallation settings\e[0m \t ::::"
# Disabling SC2154 warning, variable is sourced externaly and may vary # Disabling SC2154 warning, variable is sourced externaly and may vary
# shellcheck disable=SC2154 # shellcheck disable=SC2154
sed "s/$pivpnHOST/REDACTED/" < ${setupVars} sed "s/${pivpnHOST}/REDACTED/" < "${setupVars}"
printf "=============================================\n" printf "=============================================\n"
echo -e ":::: \e[4mServer configuration shown below\e[0m ::::" echo -e ":::: \e[4mServer configuration shown below\e[0m ::::"
cd /etc/wireguard/keys || exit cd /etc/wireguard/keys || exit
cp ../wg0.conf ../wg0.tmp cp ../wg0.conf ../wg0.tmp
# Replace every key in the server configuration with just its file name # Replace every key in the server configuration with just its file name
for k in *; do for k in *; do
sed "s#$(<"$k")#$k#" -i ../wg0.tmp sed "s#$(< "${k}")#${k}#" -i ../wg0.tmp
done done
cat ../wg0.tmp cat ../wg0.tmp
rm ../wg0.tmp rm ../wg0.tmp
printf "=============================================\n" printf "=============================================\n"
echo -e ":::: \e[4mClient configuration shown below\e[0m ::::" echo -e ":::: \e[4mClient configuration shown below\e[0m ::::"
EXAMPLE="$(head -1 /etc/wireguard/configs/clients.txt | awk '{print $1}')" EXAMPLE="$(head -1 /etc/wireguard/configs/clients.txt | awk '{print $1}')"
if [ -n "$EXAMPLE" ]; then
cp ../configs/"$EXAMPLE".conf ../configs/"$EXAMPLE".tmp if [[ -n "${EXAMPLE}" ]]; then
cp ../configs/"${EXAMPLE}".conf ../configs/"${EXAMPLE}".tmp
for k in *; do for k in *; do
sed "s#$(<"$k")#$k#" -i ../configs/"$EXAMPLE".tmp sed "s#$(< "${k}")#${k}#" -i ../configs/"${EXAMPLE}".tmp
done done
sed "s/$pivpnHOST/REDACTED/" < ../configs/"$EXAMPLE".tmp
rm ../configs/"$EXAMPLE".tmp sed "s/${pivpnHOST}/REDACTED/" < ../configs/"${EXAMPLE}".tmp
rm ../configs/"${EXAMPLE}".tmp
else else
echo "::: There are no clients yet" echo "::: There are no clients yet"
fi fi
printf "=============================================\n" printf "=============================================\n"
echo -e ":::: \t\e[4mRecursive list of files in\e[0m\t ::::\n::::\t\e[4m/etc/wireguard shown below\e[0m\t ::::" echo -e ":::: \t\e[4mRecursive list of files in\e[0m\t ::::"
echo -e "::::\t\e[4m/etc/wireguard shown below\e[0m\t ::::"
ls -LR /etc/wireguard ls -LR /etc/wireguard
printf "=============================================\n" printf "=============================================\n"
echo -e "::::\t\t\e[4mSelf check\e[0m\t\t ::::" echo -e "::::\t\t\e[4mSelf check\e[0m\t\t ::::"
/opt/pivpn/self_check.sh "${VPN}" /opt/pivpn/self_check.sh "${VPN}"
printf "=============================================\n" printf "=============================================\n"
echo -e ":::: Having trouble connecting? Take a look at the FAQ:" echo -e ":::: Having trouble connecting? Take a look at the FAQ:"
echo -e ":::: \e[1mhttps://docs.pivpn.io/faq\e[0m" echo -e ":::: \e[1mhttps://docs.pivpn.io/faq\e[0m"
printf "=============================================\n" printf "=============================================\n"
echo -e ":::: \e[1mWARNING\e[0m: This script should have automatically masked sensitive ::::" echo -ne ":::: \e[1mWARNING\e[0m: This script should have "
echo -e ":::: information, however, still make sure that \e[4mPrivateKey\e[0m, \e[4mPublicKey\e[0m ::::" echo -e "automatically masked sensitive ::::"
echo -e ":::: and \e[4mPresharedKey\e[0m are masked before reporting an issue. An example key ::::" echo -ne ":::: information, however, still make sure that "
echo ":::: that you should NOT see in this log looks like this: ::::" echo -e "\e[4mPrivateKey\e[0m, \e[4mPublicKey\e[0m ::::"
echo ":::: YIAoJVsdIeyvXfGGDDadHh6AxsMRymZTnnzZoAb9cxRe ::::" echo -ne ":::: and \e[4mPresharedKey\e[0m are masked before "
echo -e "reporting an issue. An example key ::::"
echo -n ":::: that you should NOT see in this log looks like this:"
echo " ::::"
echo -n ":::: YIAoJVsdIeyvXfGGDDadHh6AxsMRymZTnnzZoAb9cxRe"
echo " ::::"
printf "=============================================\n" printf "=============================================\n"
echo -e "::::\t\t\e[4mDebug complete\e[0m\t\t ::::" echo -e "::::\t\t\e[4mDebug complete\e[0m\t\t ::::"

View file

@ -1,9 +1,14 @@
#!/bin/bash #!/bin/bash
err() {
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
}
helpFunc() { helpFunc() {
echo "::: Show the qrcode of a client for use with the mobile app" echo "::: Show the qrcode of a client for use with the mobile app"
echo ":::" echo ":::"
echo "::: Usage: pivpn <-qr|qrcode> [-h|--help] [Options] [<client-1>] ... [<client-n>] ..." echo -n "::: Usage: pivpn <-qr|qrcode> [-h|--help] [Options] "
echo "[<client-1> ... [<client-2>] ...]"
echo ":::" echo ":::"
echo "::: Options:" echo "::: Options:"
echo "::: -a256|ansi256 Shows QR Code in ansi256 characters" echo "::: -a256|ansi256 Shows QR Code in ansi256 characters"
@ -15,9 +20,11 @@ helpFunc(){
# Parse input arguments # Parse input arguments
encoding="ansiutf8" encoding="ansiutf8"
while test $# -gt 0; do
_key="$1" while [[ "$#" -gt 0 ]]; do
case "$_key" in _key="${1}"
case "${_key}" in
-h | --help) -h | --help)
helpFunc helpFunc
exit 0 exit 0
@ -26,49 +33,57 @@ while test $# -gt 0; do
encoding="ansi256" encoding="ansi256"
;; ;;
*) *)
CLIENTS_TO_SHOW+=("$1") CLIENTS_TO_SHOW+=("${1}")
;; ;;
esac esac
shift shift
done done
cd /etc/wireguard/configs || exit cd /etc/wireguard/configs || exit
if [ ! -s clients.txt ]; then
echo "::: There are no clients to show" if [[ ! -s clients.txt ]]; then
err "::: There are no clients to show"
exit 1 exit 1
fi fi
mapfile -t LIST < <(awk '{print $1}' clients.txt) mapfile -t LIST < <(awk '{print $1}' clients.txt)
if [ "${#CLIENTS_TO_SHOW[@]}" -eq 0 ]; then
if [[ "${#CLIENTS_TO_SHOW[@]}" -eq 0 ]]; then
echo -e "::\e[4m Client list \e[0m::" echo -e "::\e[4m Client list \e[0m::"
len=${#LIST[@]} len="${#LIST[@]}"
COUNTER=1 COUNTER=1
while [ $COUNTER -le "${len}" ]; do
while [[ "${COUNTER}" -le "${len}" ]]; do
printf "%0${#len}s) %s\r\n" "${COUNTER}" "${LIST[(($COUNTER - 1))]}" printf "%0${#len}s) %s\r\n" "${COUNTER}" "${LIST[(($COUNTER - 1))]}"
((COUNTER++)) ((COUNTER++))
done done
read -r -p "Please enter the Index/Name of the Client to show: " CLIENTS_TO_SHOW echo -n "Please enter the Index/Name of the Client to show: "
read -r CLIENTS_TO_SHOW
if [ -z "${CLIENTS_TO_SHOW}" ]; then if [[ -z "${CLIENTS_TO_SHOW}" ]]; then
echo "::: You can not leave this blank!" err "::: You can not leave this blank!"
exit 1 exit 1
fi fi
fi fi
for CLIENT_NAME in "${CLIENTS_TO_SHOW[@]}"; do for CLIENT_NAME in "${CLIENTS_TO_SHOW[@]}"; do
re='^[0-9]+$' re='^[0-9]+$'
if [[ ${CLIENT_NAME:0:1} == "-" ]]; then
echo "${CLIENT_NAME} is not a valid client name or option" if [[ "${CLIENT_NAME:0:1}" == "-" ]]; then
err "${CLIENT_NAME} is not a valid client name or option"
exit 1 exit 1
elif [[ ${CLIENT_NAME} =~ $re ]] ; then elif [[ "${CLIENT_NAME}" =~ $re ]]; then
CLIENT_NAME=${LIST[$((CLIENT_NAME -1))]} CLIENT_NAME="${LIST[$((CLIENT_NAME - 1))]}"
fi fi
if grep -qw "${CLIENT_NAME}" clients.txt; then if grep -qw "${CLIENT_NAME}" clients.txt; then
echo -e "::: Showing client \e[1m${CLIENT_NAME}\e[0m below" echo -e "::: Showing client \e[1m${CLIENT_NAME}\e[0m below"
echo "=====================================================================" echo "====================================================================="
qrencode -t "${encoding}" < "${CLIENT_NAME}.conf" qrencode -t "${encoding}" < "${CLIENT_NAME}.conf"
echo "=====================================================================" echo "====================================================================="
else else
echo -e "::: \e[1m${CLIENT_NAME}\e[0m does not exist" echo -e "::: \e[1m${CLIENT_NAME}\e[0m does not exist"

View file

@ -2,18 +2,23 @@
setupVars="/etc/pivpn/wireguard/setupVars.conf" setupVars="/etc/pivpn/wireguard/setupVars.conf"
if [ ! -f "${setupVars}" ]; then if [[ ! -f "${setupVars}" ]]; then
echo "::: Missing setup vars file!" err "::: Missing setup vars file!"
exit 1 exit 1
fi fi
# shellcheck disable=SC1090 # shellcheck disable=SC1090
source "${setupVars}" source "${setupVars}"
err() {
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
}
helpFunc() { helpFunc() {
echo "::: Remove a client conf profile" echo "::: Remove a client conf profile"
echo ":::" echo ":::"
echo "::: Usage: pivpn <-r|remove> [-y|--yes] [-h|--help] [<client-1>] ... [<client-n>] ..." echo -n "::: Usage: pivpn <-r|remove> [-y|--yes] [-h|--help] "
echo "[<client-1> ... [<client-2>] ...]"
echo ":::" echo ":::"
echo "::: Commands:" echo "::: Commands:"
echo "::: [none] Interactive mode" echo "::: [none] Interactive mode"
@ -23,10 +28,10 @@ helpFunc(){
} }
# Parse input arguments # Parse input arguments
while test $# -gt 0 while [[ "$#" -gt 0 ]]; do
do _key="${1}"
_key="$1"
case "$_key" in case "${_key}" in
-h | --help) -h | --help)
helpFunc helpFunc
exit 0 exit 0
@ -35,32 +40,38 @@ do
CONFIRM=true CONFIRM=true
;; ;;
*) *)
CLIENTS_TO_REMOVE+=("$1") CLIENTS_TO_REMOVE+=("${1}")
;; ;;
esac esac
shift shift
done done
cd /etc/wireguard || exit cd /etc/wireguard || exit
if [ ! -s configs/clients.txt ]; then
echo "::: There are no clients to remove" if [[ ! -s configs/clients.txt ]]; then
err "::: There are no clients to remove"
exit 1 exit 1
fi fi
mapfile -t LIST < <(awk '{print $1}' configs/clients.txt) mapfile -t LIST < <(awk '{print $1}' configs/clients.txt)
if [ "${#CLIENTS_TO_REMOVE[@]}" -eq 0 ]; then
if [[ "${#CLIENTS_TO_REMOVE[@]}" -eq 0 ]]; then
echo -e "::\e[4m Client list \e[0m::" echo -e "::\e[4m Client list \e[0m::"
len=${#LIST[@]} len="${#LIST[@]}"
COUNTER=1 COUNTER=1
while [ $COUNTER -le "${len}" ]; do
while [[ "${COUNTER}" -le "${len}" ]]; do
printf "%0${#len}s) %s\r\n" "${COUNTER}" "${LIST[(($COUNTER - 1))]}" printf "%0${#len}s) %s\r\n" "${COUNTER}" "${LIST[(($COUNTER - 1))]}"
((COUNTER++)) ((COUNTER++))
done done
read -r -p "Please enter the Index/Name of the Client to be removed from the list above: " CLIENTS_TO_REMOVE echo -n "Please enter the Index/Name of the Client to be removed "
echo -n "from the list above: "
read -r CLIENTS_TO_REMOVE
if [ -z "${CLIENTS_TO_REMOVE}" ]; then if [[ -z "${CLIENTS_TO_REMOVE}" ]]; then
echo "::: You can not leave this blank!" err "::: You can not leave this blank!"
exit 1 exit 1
fi fi
fi fi
@ -68,36 +79,42 @@ fi
DELETED_COUNT=0 DELETED_COUNT=0
for CLIENT_NAME in "${CLIENTS_TO_REMOVE[@]}"; do for CLIENT_NAME in "${CLIENTS_TO_REMOVE[@]}"; do
re='^[0-9]+$' re='^[0-9]+$'
if [[ ${CLIENT_NAME} =~ $re ]] ; then
CLIENT_NAME=${LIST[$((CLIENT_NAME -1))]} if [[ "${CLIENT_NAME}" =~ $re ]]; then
CLIENT_NAME="${LIST[$((CLIENT_NAME - 1))]}"
fi fi
if ! grep -q "^${CLIENT_NAME} " configs/clients.txt; then if ! grep -q "^${CLIENT_NAME} " configs/clients.txt; then
echo -e "::: \e[1m${CLIENT_NAME}\e[0m does not exist" echo -e "::: \e[1m${CLIENT_NAME}\e[0m does not exist"
else else
REQUESTED="$(sha256sum "configs/${CLIENT_NAME}.conf" | cut -c 1-64)" REQUESTED="$(sha256sum "configs/${CLIENT_NAME}.conf" | cut -c 1-64)"
if [ -n "$CONFIRM" ]; then
if [[ -n "${CONFIRM}" ]]; then
REPLY="y" REPLY="y"
else else
read -r -p "Do you really want to delete $CLIENT_NAME? [y/N] " read -r -p "Do you really want to delete ${CLIENT_NAME}? [y/N] "
fi fi
if [[ $REPLY =~ ^[Yy]$ ]]; then if [[ "${REPLY}" =~ ^[Yy]$ ]]; then
# Grab the least significant octed of the client IP address # Grab the least significant octed of the client IP address
COUNT=$(grep "^${CLIENT_NAME} " configs/clients.txt | awk '{print $4}') COUNT="$(grep "^${CLIENT_NAME} " configs/clients.txt | awk '{print $4}')"
# The creation date of the client # The creation date of the client
CREATION_DATE="$(grep "^${CLIENT_NAME} " configs/clients.txt | awk '{print $3}')" CREATION_DATE="$(grep "^${CLIENT_NAME} " configs/clients.txt \
| awk '{print $3}')"
# And its public key # And its public key
PUBLIC_KEY="$(grep "^${CLIENT_NAME} " configs/clients.txt | awk '{print $2}')" PUBLIC_KEY="$(grep "^${CLIENT_NAME} " configs/clients.txt \
| awk '{print $2}')"
# Then remove the client matching the variables above # Then remove the client matching the variables above
sed "\#${CLIENT_NAME} ${PUBLIC_KEY} ${CREATION_DATE} ${COUNT}#d" -i configs/clients.txt sed \
-e "\#${CLIENT_NAME} ${PUBLIC_KEY} ${CREATION_DATE} ${COUNT}#d" \
-i configs/clients.txt
# Remove the peer section from the server config # Remove the peer section from the server config
sed "/### begin ${CLIENT_NAME} ###/,/### end ${CLIENT_NAME} ###/d" -i wg0.conf sed_pattern="/### begin ${CLIENT_NAME} ###/,"
sed_pattern="${sed_pattern}/### end ${CLIENT_NAME} ###/d"
sed -e "${sed_pattern}" -i wg0.conf
echo "::: Updated server config" echo "::: Updated server config"
rm "configs/${CLIENT_NAME}.conf" rm "configs/${CLIENT_NAME}.conf"
@ -108,15 +125,17 @@ for CLIENT_NAME in "${CLIENTS_TO_REMOVE[@]}"; do
rm "keys/${CLIENT_NAME}_psk" rm "keys/${CLIENT_NAME}_psk"
echo "::: Client Keys for ${CLIENT_NAME} removed" echo "::: Client Keys for ${CLIENT_NAME} removed"
# Find all .conf files in the home folder of the user matching the checksum of the # Find all .conf files in the home folder of the user matching the
# config and delete them. '-maxdepth 3' is used to avoid traversing too many folders. # checksum of the config and delete them. '-maxdepth 3' is used to
# avoid traversing too many folders.
# Disabling SC2154, variable sourced externaly and may vary # Disabling SC2154, variable sourced externaly and may vary
# shellcheck disable=SC2154 # shellcheck disable=SC2154
find "${install_home}" -maxdepth 3 -type f -name '*.conf' -print0 | while IFS= read -r -d '' CONFIG; do while IFS= read -r -d '' CONFIG; do
if sha256sum -c <<< "${REQUESTED} ${CONFIG}" &> /dev/null; then if sha256sum -c <<< "${REQUESTED} ${CONFIG}" &> /dev/null; then
rm "${CONFIG}" rm "${CONFIG}"
fi fi
done done < <(find "${install_home}" \
-maxdepth 3 -type f -name '*.conf' -print0)
((DELETED_COUNT++)) ((DELETED_COUNT++))
echo "::: Successfully deleted ${CLIENT_NAME}" echo "::: Successfully deleted ${CLIENT_NAME}"
@ -124,37 +143,41 @@ for CLIENT_NAME in "${CLIENTS_TO_REMOVE[@]}"; do
# If using Pi-hole, remove the client from the hosts file # If using Pi-hole, remove the client from the hosts file
# Disabling SC2154, variable sourced externaly and may vary # Disabling SC2154, variable sourced externaly and may vary
# shellcheck disable=SC2154 # shellcheck disable=SC2154
if [ -f /etc/pivpn/hosts.wireguard ]; then if [[ -f /etc/pivpn/hosts.wireguard ]]; then
NET_REDUCED="${pivpnNET::-2}" NET_REDUCED="${pivpnNET::-2}"
sed -e "\#${NET_REDUCED}.${COUNT} ${CLIENT_NAME}.pivpn#d" -e "\#${pivpnNETv6}${COUNT} ${CLIENT_NAME}.pivpn#d" -i /etc/pivpn/hosts.wireguard sed \
-e "\#${NET_REDUCED}.${COUNT} ${CLIENT_NAME}.pivpn#d" \
-e "\#${pivpnNETv6}${COUNT} ${CLIENT_NAME}.pivpn#d" \
-i /etc/pivpn/hosts.wireguard
if killall -SIGHUP pihole-FTL; then if killall -SIGHUP pihole-FTL; then
echo "::: Updated hosts file for Pi-hole" echo "::: Updated hosts file for Pi-hole"
else else
echo "::: Failed to reload pihole-FTL configuration" err "::: Failed to reload pihole-FTL configuration"
fi fi
fi fi
unset sed_pattern
else else
echo "Aborting operation" err "Aborting operation"
exit 1 exit 1
fi fi
fi fi
done done
# Restart WireGuard only if some clients were actually deleted # Restart WireGuard only if some clients were actually deleted
if [ "${DELETED_COUNT}" -gt 0 ]; then if [[ "${DELETED_COUNT}" -gt 0 ]]; then
if [ "${PLAT}" == 'Alpine' ]; then if [[ "${PLAT}" == 'Alpine' ]]; then
if rc-service wg-quick restart; then if rc-service wg-quick restart; then
echo "::: WireGuard reloaded" echo "::: WireGuard reloaded"
else else
echo "::: Failed to reload WireGuard" err "::: Failed to reload WireGuard"
fi fi
else else
if systemctl reload wg-quick@wg0; then if systemctl reload wg-quick@wg0; then
echo "::: WireGuard reloaded" echo "::: WireGuard reloaded"
else else
echo "::: Failed to reload WireGuard" err "::: Failed to reload WireGuard"
fi fi
fi fi
fi fi