diff --git a/auto_install/install.sh b/auto_install/install.sh index ff9200c..7d00f54 100755 --- a/auto_install/install.sh +++ b/auto_install/install.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# PiVPN: Trivial OpenVPN or WireGUard setup and configuration +# PiVPN: Trivial OpenVPN or WireGuard setup and configuration # Easiest setup and mangement of OpenVPN or WireGuard on Raspberry Pi # http://pivpn.io # Heavily adapted from the pi-hole.net project and... @@ -20,7 +20,12 @@ PKG_CACHE="/var/lib/apt/lists/" UPDATE_PKG_CACHE="${PKG_MANAGER} update" PKG_INSTALL="${PKG_MANAGER} --yes --no-install-recommends install" PKG_COUNT="${PKG_MANAGER} -s -o Debug::NoLocking=true upgrade | grep -c ^Inst || true" +# Dependencies that are required by the script, regardless of the VPN protocol chosen BASE_DEPS=(git tar wget grep iptables-persistent dnsutils whiptail net-tools dhcpcd5) +# Dependencies that where actually installed by the script. For example if the script requires +# grep and dnsutils but dnsutils is already installed, we save grep here. This way when uninstalling +# PiVPN we won't prompt to remove packages that may have been installed by the user for other reasons +TO_INSTALL=() pivpnGitUrl="https://github.com/orazioedoardo/pivpn.git" easyrsaVer="3.0.6" @@ -30,7 +35,7 @@ easyrsaRel="https://github.com/OpenVPN/easy-rsa/releases/download/v${easyrsaVer} UNATTUPG_RELEASE="1.14" UNATTUPG_CONFIG="https://github.com/mvo5/unattended-upgrades/archive/${UNATTUPG_RELEASE}.tar.gz" -WG_SNAPSHOT="0.0.20190913" +WG_SNAPSHOT="0.0.20191012" WG_SOURCE="https://git.zx2c4.com/WireGuard/snapshot/WireGuard-${WG_SNAPSHOT}.tar.xz" # Find the rows and columns. Will default to 80x24 if it can not be detected. @@ -212,10 +217,6 @@ notifyPackageUpdatesAvailable(){ fi } -packageCheckInstall(){ - dpkg-query -W -f='${Status}' "${1}" 2>/dev/null | grep -c "ok installed" || ${PKG_INSTALL} "${1}" -} - preconfigurePackages(){ # Add support for https repositories if there are any that use it otherwise the installation will silently fail if grep -q https /etc/apt/sources.list; then @@ -236,14 +237,20 @@ installDependentPackages(){ # No spinner - conflicts with set -e declare -a argArray1=("${!1}") + for i in "${argArray1[@]}"; do + echo -n "::: Checking for $i..." + if dpkg-query -W -f='${Status}' "${i}" 2>/dev/null | grep -q "ok installed"; then + echo " installed!" + else + TO_INSTALL+=("${i}") + echo " not installed!" + fi + done + if command -v debconf-apt-progress &> /dev/null; then $SUDO debconf-apt-progress -- ${PKG_INSTALL} "${argArray1[@]}" else - for i in "${argArray1[@]}"; do - echo -n "::: Checking for $i..." - $SUDO packageCheckInstall "${i}" &> /dev/null - echo " installed!" - done + ${PKG_INSTALL} "${argArray1[@]}" fi } @@ -301,8 +308,8 @@ chooseInterface(){ } avoidStaticIPv4Ubuntu() { - # If we are in Ubuntu then they need to have previously set their network, so just use what you have. - whiptail --msgbox --backtitle "IP Information" --title "IP Information" "Since we think you are not using Raspbian, we will not configure a static IP for you. + # If we are in Ubuntu then they need to have previously set their network, so just use what you have. + whiptail --msgbox --backtitle "IP Information" --title "IP Information" "Since we think you are not using Raspbian, we will not configure a static IP for you. If you are in Amazon then you can not configure a static IP anyway. Just ensure before this installer started you had set an elastic IP on your instance." ${r} ${c} } @@ -559,13 +566,13 @@ Pin-Priority: 500" | $SUDO tee /etc/apt/preferences.d/limit-unstable > /dev/null $SUDO apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 04EE7237B7D453EC 648ACFD622F3D138 $SUDO ${UPDATE_PKG_CACHE} &> /dev/null - PIVPN_DEPS=(raspberrypi-kernel-headers wireguard) + PIVPN_DEPS=(raspberrypi-kernel-headers wireguard wireguard-tools wireguard-dkms) installDependentPackages PIVPN_DEPS[@] elif [ "$(uname -m)" = "armv6l" ]; then echo "::: Installing WireGuard from source... " - PIVPN_DEPS=(libmnl-dev libelf-dev raspberrypi-kernel-headers build-essential pkg-config qrencode) + PIVPN_DEPS=(checkinstall dkms libmnl-dev libelf-dev raspberrypi-kernel-headers build-essential pkg-config qrencode) installDependentPackages PIVPN_DEPS[@] # Delete any leftover code @@ -591,8 +598,12 @@ Pin-Priority: 500" | $SUDO tee /etc/apt/preferences.d/limit-unstable > /dev/null exit 1 fi + # Use checkinstall to install userspace tools so if the user wants to uninstall + # PiVPN we can just do apt remove wireguard-tools, instead of manually removing + # files from the file system echo "::: Installing WireGuard tools... " - if $SUDO make install tools; then + if $SUDO checkinstall --pkgname wireguard-tools --pkgversion "${WG_SNAPSHOT}" -y make tools-install; then + TO_INSTALL+=("wireguard-tools") echo "done!" else echo "failed!" @@ -619,6 +630,7 @@ Pin-Priority: 500" | $SUDO tee /etc/apt/preferences.d/limit-unstable > /dev/null echo "::: Installing WireGuard modules via DKMS... " if $SUDO dkms install wireguard/"${WG_SNAPSHOT}"; then + TO_INSTALL+=("wireguard-dkms") echo "done!" else echo "failed!" @@ -628,12 +640,14 @@ Pin-Priority: 500" | $SUDO tee /etc/apt/preferences.d/limit-unstable > /dev/null elif [ "$(uname -m)" = "x86_64" ] || [ "$(uname -m)" = "i686" ]; then + echo "::: Installing WireGuard from Debian package... " + echo "::: Adding Debian repository... " echo "deb http://deb.debian.org/debian/ unstable main" | $SUDO tee /etc/apt/sources.list.d/unstable.list > /dev/null echo "Package: * Pin: release a=unstable Pin-Priority: 90" | $SUDO tee /etc/apt/preferences.d/limit-unstable > /dev/null $SUDO ${UPDATE_PKG_CACHE} &> /dev/null - PIVPN_DEPS=(linux-headers-amd64 qrencode wireguard) + PIVPN_DEPS=(linux-headers-amd64 qrencode wireguard wireguard-tools wireguard-dkms) installDependentPackages PIVPN_DEPS[@] fi @@ -726,7 +740,25 @@ askCustomPort(){ echo "pivpnPORT=${pivpnPORT}" >> /tmp/setupVars.conf } -askClientDNS() { +askClientDNS(){ + + # Detect and offer to use Pi-hole + if command -v pihole &>/dev/null; then + if (whiptail --backtitle "Setup PiVPN" --title "Pi-hole" --yesno "We have detected a Pi-hole installation, do you want to use it as the DNS server for the VPN, so you get ad blocking on the go?" ${r} ${c}); then + if [ "$VPN" = "WireGuard" ]; then + pivpnDEV="wg0" + elif [ "$VPN" = "OpenVPN" ]; then + pivpnDEV="tun0" + fi + + pivpnDNS1="$IPv4addr" + echo "interface=$pivpnDNS" | $SUDO tee /etc/dnsmasq.d/02-pivpn.conf > /dev/null + $SUDO pihole restartdns + echo "pivpnDNS1=${pivpnDNS1}" >> /tmp/setupVars.conf + return + fi + fi + DNSChoseCmd=(whiptail --separate-output --radiolist "Select the DNS Provider for your VPN Clients (press space to select). To use your own, select Custom." ${r} ${c} 6) DNSChooseOptions=(Google "" on OpenDNS "" off @@ -799,6 +831,7 @@ askClientDNS() { exit 1 fi + echo "USING_PIHOLE=${USING_PIHOLE}" >> /tmp/setupVars.conf echo "pivpnDNS1=${pivpnDNS1}" >> /tmp/setupVars.conf echo "pivpnDNS2=${pivpnDNS2}" >> /tmp/setupVars.conf } @@ -1221,6 +1254,7 @@ installScripts(){ fi FOLDER=$(tr '[:upper:]' '[:lower:]' <<< "$VPN") + $SUDO cp /etc/.pivpn/scripts/uninstall.sh /opt/pivpn/ $SUDO cp /etc/.pivpn/scripts/$FOLDER/*.sh /opt/pivpn/ $SUDO chmod 0755 /opt/pivpn/*.sh $SUDO cp /etc/.pivpn/scripts/$FOLDER/pivpn /usr/local/bin/pivpn @@ -1344,6 +1378,8 @@ main(){ askUnattendedUpgrades confUnattendedUpgrades + echo "TO_INSTALL=(${TO_INSTALL[*]})" >> /tmp/setupVars.conf + $SUDO cp /tmp/setupVars.conf "$setupVars" installScripts diff --git a/scripts/openvpn/backup.sh b/scripts/openvpn/backup.sh index 8ef6006..2bed93c 100755 --- a/scripts/openvpn/backup.sh +++ b/scripts/openvpn/backup.sh @@ -19,7 +19,7 @@ backup_openvpn(){ cp -r $openvpndir $ovpnsdir $backupdir 2&>1 backupzip=$date-pivpnbackup.tgz tar -czf $backupzip -C ${install_home} $backupdir 2&>1 - echo -e "Backup crated to $install_home/$backupdir/$backupzip \nTo restore the backup, follow instructions at:\nhttps://github.com/pivpn/pivpn/wiki/FAQ#how-can-i-migrate-my-configs-to-another-pivpn-instance" + echo -e "Backup crated to $install_home/$backupdir/$backupzip \nTo restore the backup, follow instructions at:\nhttps://github.com/pivpn/pivpn/wiki/FAQ#how-can-i-migrate-my-configs-to-another-pivpn-instance" } diff --git a/scripts/openvpn/makeOVPN.sh b/scripts/openvpn/makeOVPN.sh index e0c8891..d37769c 100755 --- a/scripts/openvpn/makeOVPN.sh +++ b/scripts/openvpn/makeOVPN.sh @@ -36,7 +36,7 @@ helpFunc() { if [ -z "$HELP_SHOWN" ]; then helpFunc echo - echo "HELP_SHOWN=1" >> "$setupVars" + echo "HELP_SHOWN=1" >> "$setupVars" fi # Parse input arguments @@ -351,9 +351,9 @@ if [ "$iOS" = "1" ]; then fi } > "${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" diff --git a/scripts/openvpn/pivpn b/scripts/openvpn/pivpn index de55586..4d2317c 100755 --- a/scripts/openvpn/pivpn +++ b/scripts/openvpn/pivpn @@ -62,7 +62,7 @@ function update { function backup { - $SUDO /opt/pivpn/backup.sh + $SUDO /opt/pivpn/backup.sh exit 0 } diff --git a/scripts/openvpn/removeOVPN.sh b/scripts/openvpn/removeOVPN.sh index 86457c2..f191eab 100755 --- a/scripts/openvpn/removeOVPN.sh +++ b/scripts/openvpn/removeOVPN.sh @@ -46,7 +46,7 @@ fi if [[ -z "${CERTS_TO_REVOKE}" ]]; then printf "\n" printf " ::\e[4m Certificate List \e[0m:: \n" - + i=0 while read -r line || [ -n "$line" ]; do STATUS=$(echo "$line" | awk '{print $1}') @@ -61,26 +61,26 @@ if [[ -z "${CERTS_TO_REVOKE}" ]]; then fi done <${INDEX} printf "\n" - + echo -n "::: Please enter the Name of the client to be revoked from the list above: " read -r NAME - + if [[ -z "${NAME}" ]]; then echo "You can not leave this blank!" exit 1 fi - + for((x=1;x<=i;++x)); do if [ "${CERTS[$x]}" = "${NAME}" ]; then VALID=1 fi done - + if [ -z "${VALID}" ]; then printf "You didn't enter a valid cert name!\n" exit 1 fi - + CERTS_TO_REVOKE=( "${NAME}" ) else i=0 @@ -92,7 +92,7 @@ else let i=i+1 fi done <${INDEX} - + for (( ii = 0; ii < ${#CERTS_TO_REVOKE[@]}; ii++)); do VALID=0 for((x=1;x<=i;++x)); do @@ -100,7 +100,7 @@ else VALID=1 fi done - + if [ "${VALID}" != 1 ]; then printf "You passed an invalid cert name: '"%s"'!\n" "${CERTS_TO_REVOKE[ii]}" exit 1 diff --git a/scripts/openvpn/update.sh b/scripts/openvpn/update.sh index fb74450..eac73d5 100755 --- a/scripts/openvpn/update.sh +++ b/scripts/openvpn/update.sh @@ -1,4 +1,4 @@ -#/bin/bash +#!/bin/bash ###Updates pivpn scripts (Not PiVPN) ###Main Vars @@ -11,7 +11,7 @@ bashcompletiondir="/etc/bash_completion.d/pivpn" ###Functions ##Updates scripts updatepivpnscripts(){ - ##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 echo "going do update PiVPN Scripts" if [[ -d $pivpnlocalpath ]]; then @@ -25,9 +25,9 @@ updatepivpnscripts(){ echo "PiVPN Scripts have been updated" } -##Updates scripts using test branch +##Updates scripts using test branch updatefromtest(){ - ##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 echo "PiVPN Scripts updating from test branch" if [[ -d /etc/.pivpn ]]; then @@ -89,8 +89,8 @@ else scriptusage exit 0 ;; - * ) - updatepivpnscripts + * ) + updatepivpnscripts exit 0 ;; esac diff --git a/scripts/uninstall.sh b/scripts/uninstall.sh new file mode 100755 index 0000000..d5fc1a6 --- /dev/null +++ b/scripts/uninstall.sh @@ -0,0 +1,197 @@ +#!/usr/bin/env bash +# PiVPN: Uninstall Script + +PKG_MANAGER="apt-get" +WG_SNAPSHOT="0.0.20191012" +setupVars="/etc/pivpn/setupVars.conf" + +if [ ! -f "${setupVars}" ]; then + echo "::: Missing setup vars file!" + exit 1 +fi + +source "${setupVars}" + +# 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) +rows=$(echo $screen_size | awk '{print $1}') +columns=$(echo $screen_size | awk '{print $2}') + +# Divide by two so the dialogs take up half of the screen, which looks nice. +r=$(( rows / 2 )) +c=$(( columns / 2 )) +# Unless the screen is tiny +r=$(( r < 20 ? 20 : r )) +c=$(( c < 70 ? 70 : c )) + +spinner(){ + local pid=$1 + local delay=0.50 + local spinstr='/-\|' + while [ "$(ps a | awk '{print $1}' | grep "$pid")" ]; do + local temp=${spinstr#?} + printf " [%c] " "$spinstr" + local spinstr=$temp${spinstr%"$temp"} + sleep $delay + printf "\b\b\b\b\b\b" + done + printf " \b\b\b\b" +} + +removeAll(){ + # Stopping and disabling services + echo "::: Stopping and disabling services..." + + if [ "$VPN" = "WireGuard" ]; then + systemctl stop wg-quick@wg0 + systemctl disable wg-quick@wg0 &> /dev/null + elif [ "$VPN" = "OpenVPN" ]; then + systemctl stop openvpn + systemctl disable openvpn &> /dev/null + fi + + # Removing firewall rules. + echo "::: Removing firewall rules..." + + if [ "$VPN" = "WireGuard" ]; then + pivpnDEV="wg0" + pivpnNET="10.6.0.0/24" + elif [ "$VPN" = "OpenVPN" ]; then + pivpnDEV="tun0" + pivpnNET="10.8.0.0/24" + fi + + if [ "$USING_UFW" -eq 1 ]; then + + ufw delete allow "${pivpnPORT}"/udp > /dev/null + ufw route delete allow in on "$pivpnDEV" from "$pivpnNET" out on "${IPv4dev}" to any > /dev/null + sed -z "s/*nat\n:POSTROUTING ACCEPT \[0:0\]\n-I POSTROUTING -s 10.6.0.0\/24 -o ${IPv4dev} -j MASQUERADE\nCOMMIT\n\n//" -i /etc/ufw/before.rules + ufw reload &> /dev/null + + elif [ "$USING_UFW" -eq 0 ]; then + + if [ "$INPUT_CHAIN_EDITED" -eq 1 ]; then + iptables -D INPUT -i "${IPv4dev}" -p udp --dport "${pivpnPORT}" -j ACCEPT + fi + + if [ "$FORWARD_CHAIN_EDITED" -eq 1 ]; then + iptables -D FORWARD -d "$pivpnNET" -i "${IPv4dev}" -o "$pivpnDEV" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT + iptables -D FORWARD -s "$pivpnNET" -i "$pivpnDEV" -o "${IPv4dev}" -j ACCEPT + fi + + iptables -t nat -D POSTROUTING -s "$pivpnNET" -o "${IPv4dev}" -j MASQUERADE + iptables-save > /etc/iptables/rules.v4 + + fi + + # Disable IPv4 forwarding + sed -i '/net.ipv4.ip_forward=1/c\#net.ipv4.ip_forward=1' /etc/sysctl.conf + sysctl -p + + # Purge dependencies + echo "::: Purge dependencies..." + + for i in "${TO_INSTALL[@]}"; do + while true; do + read -rp "::: Do you wish to remove $i from your system? [Y/n]: " yn + case $yn in + [Yy]* ) if [ "${i}" = "wireguard" ]; then + + if [ "$(uname -m)" = "armv7l" ] || [ "$(uname -m)" = "x86_64" ] || [ "$(uname -m)" = "i686" ]; then + rm /etc/apt/sources.list.d/unstable.list + rm /etc/apt/preferences.d/limit-unstable + $PKG_MANAGER update &> /dev/null + fi + rm -rf /etc/wireguard + rm -rf $install_home/configs + + elif [ "${i}" = "wireguard-dkms" ]; then + + # If we installed wireguard-dkms and we are on armv6l, then we manually need + # to remove the kernel module and skip the apt uninstallation (since it's not an + # actual package) + if [ "$(uname -m)" = "armv6l" ]; then + dkms remove wireguard/"${WG_SNAPSHOT}" --all + rm -rf /usr/src/wireguard-* + break + fi + + elif [ "${i}" = "dirmngr" ]; then + + # If dirmngr was installed, then we had previously installed wireguard on armv7l + # so we remove the repository keys + apt-key remove E1CF20DDFFE4B89E802658F1E0B11894F66AEC98 80D15823B7FD1561F9F7BCDDDC30D7C23CBBABEE &> /dev/null + + elif [ "${i}" = "openvpn" ]; then + + rm -rf /var/log/*openvpn* + rm -rf /etc/openvpn + rm -rf $install_home/ovpns + + elif [ "${i}" = "unattended-upgrades" ]; then + + rm -rf /var/log/unattended-upgrades + rm -rf /etc/apt/apt.conf.d/*periodic + rm -rf /etc/apt/apt.conf.d/*unattended-upgrades + + fi + printf ":::\tRemoving %s..." "$i"; $PKG_MANAGER -y remove --purge "$i" &> /dev/null & spinner $!; printf "done!\n"; + break + ;; + [Nn]* ) printf ":::\tSkipping %s\n" "$i"; + break + ;; + * ) printf "::: You must answer yes or no!\n";; + esac + done + done + + # Take care of any additional package cleaning + printf "::: Auto removing remaining dependencies..." + $PKG_MANAGER -y autoremove &> /dev/null & spinner $!; printf "done!\n"; + printf "::: Auto cleaning remaining dependencies..." + $PKG_MANAGER -y autoclean &> /dev/null & spinner $!; printf "done!\n"; + + echo ":::" + # Removing pivpn files + echo "::: Removing pivpn system files..." + + if [ -f /etc/dnsmasq.d/02-pivpn.conf ]; then + rm /etc/dnsmasq.d/02-pivpn.conf + pihole restartdns + fi + + rm -rf /opt/pivpn + rm -rf /etc/.pivpn + rm -rf /etc/pivpn + rm -rf /var/log/*pivpn* + rm /usr/local/bin/pivpn + rm /etc/bash_completion.d/pivpn + + echo ":::" + printf "::: Finished removing PiVPN from your system.\n" + printf "::: Reinstall by simpling running\n:::\n:::\tcurl -L https://install.pivpn.io | bash\n:::\n::: at any time!\n:::\n" +} + +askreboot(){ + printf "It is \e[1mstrongly\e[0m recommended to reboot after un-installation.\n" + read -p "Would you like to reboot now? [y/n]: " -n 1 -r + echo + if [[ ${REPLY} =~ ^[Yy]$ ]]; then + printf "\nRebooting system...\n" + sleep 3 + shutdown -r now + fi +} + +######### SCRIPT ########### +echo "::: Preparing to remove packages, be sure that each may be safely removed depending on your operating system." +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;; + esac +done diff --git a/scripts/wireguard/qrcodeCONF.sh b/scripts/wireguard/qrcodeCONF.sh index 40fce8f..0420eb5 100755 --- a/scripts/wireguard/qrcodeCONF.sh +++ b/scripts/wireguard/qrcodeCONF.sh @@ -29,7 +29,7 @@ done cd /etc/wireguard/configs if [ ! -s clients.txt ]; then - echo "::: There are no clients to remove" + echo "::: There are no clients to show" exit 1 fi diff --git a/scripts/wireguard/removeCONF.sh b/scripts/wireguard/removeCONF.sh index 403da3c..263fde3 100755 --- a/scripts/wireguard/removeCONF.sh +++ b/scripts/wireguard/removeCONF.sh @@ -79,18 +79,18 @@ for CLIENT_NAME in "${CLIENTS_TO_REMOVE[@]}"; do # Then remove the client matching the variables above sed "/${CLIENT_NAME} ${CREATION_DATE} ${COUNT}/d" -i configs/clients.txt - + # Remove the peer section from the server config sed "/# begin ${CLIENT_NAME}/,/# end ${CLIENT_NAME}/d" -i wg0.conf echo "::: Updated server config" - + rm "configs/${CLIENT_NAME}.conf" echo "::: Client config for ${CLIENT_NAME} removed" rm "keys/${CLIENT_NAME}_priv" rm "keys/${CLIENT_NAME}_pub" echo "::: Client Keys for ${CLIENT_NAME} removed" - + # Find all .conf files in the home folder of the user matching the checksum of the # config and delete them. '-maxdepth 3' is used to avoid traversing too many folders. find "${install_home}" -maxdepth 3 -type f -name '*.conf' -print0 | while IFS= read -r -d '' CONFIG; do @@ -108,7 +108,7 @@ for CLIENT_NAME in "${CLIENTS_TO_REMOVE[@]}"; do done # Restart WireGuard only if some clients were actually deleted -if [ "${DELETED_COUNT}" -gt 0 ]; then +if [ "${DELETED_COUNT}" -gt 0 ]; then if systemctl restart wg-quick@wg0; then echo "::: WireGuard restarted" else