From 53565dd4fe86d1b7b2f65636b1d32004a38199f7 Mon Sep 17 00:00:00 2001 From: Kaladin Light <0.kaladin@gmail.com> Date: Tue, 19 Apr 2016 14:01:55 -0400 Subject: [PATCH] First commit of reworked installer --- Default.txt | 15 ++ README.md | 156 ++++++++++- auto_install/install.sh | 531 +++++++++++++++++++++++++++++++++++++ ca_info.txt | 8 + firewall-openvpn-rules.txt | 3 + pivpn | 71 +++++ scripts/bash-completion | 18 ++ scripts/listOVPN.sh | 32 +++ scripts/makeOVPN.sh | 81 ++++++ scripts/pivpnDebug.sh | 2 + scripts/removeOVPN.sh | 47 ++++ scripts/uninstall.sh | 117 ++++++++ server_config.txt | 37 +++ 13 files changed, 1116 insertions(+), 2 deletions(-) create mode 100644 Default.txt create mode 100644 auto_install/install.sh create mode 100644 ca_info.txt create mode 100644 firewall-openvpn-rules.txt create mode 100644 pivpn create mode 100644 scripts/bash-completion create mode 100644 scripts/listOVPN.sh create mode 100644 scripts/makeOVPN.sh create mode 100644 scripts/pivpnDebug.sh create mode 100644 scripts/removeOVPN.sh create mode 100644 scripts/uninstall.sh create mode 100644 server_config.txt diff --git a/Default.txt b/Default.txt new file mode 100644 index 0000000..6c382dd --- /dev/null +++ b/Default.txt @@ -0,0 +1,15 @@ +client +dev tun +proto udp +remote IPv4pub 1194 +resolv-retry infinite +nobind +persist-key +persist-tun +mute-replay-warnings +ns-cert-type server +key-direction 1 +cipher AES-128-CBC +comp-lzo +verb 1 +mute 20 diff --git a/README.md b/README.md index f0d9567..d50bda1 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,154 @@ -# pivpn -Simple OpenVPN installer, designed for raspberry pi. +PiVPN +============ + +About +----- + +Visit the [PiVPN](http://pivpn.io) site for more information. +This is a set of shell scripts that server to easily turn your Raspberry Pi (TM) +into a VPN server using the free, open-source [OpenVPN](https://openvpn.net) software. + +The master branch of this script installs and configures OpenVPN on Raspbian +Jessie, and should be used if you are running Jessie or Jessie Lite. Jessie Lite +is recommended if this will just be a server. The goal is for this to also work +on Debian Jessie built on a free-tier Amazon AWS server for those that want thier +tunneled traffic to be encrypted out of their home ISP. + +Prerequisites +------------- + +To follow this guide and use the script to setup OpenVPN, you will need to have +a Raspberry Pi Model B or later with an ethernet port, an SD or microSD card +(depending on the model) with Raspbian installed, a power adapter appropriate to + the power needs of your model, and an ethernet cable or wifi adapter to connect your Pi to your +router or gateway. It is recommended that you use a fresh image of Raspbian +Jessie Lite from https://raspberrypi.org/downloads, but if you don't, +be sure to make a backup image of your existing installation before proceeding. +You should also setup your Pi with a static IP address (see either source + 1 or 2 at the bottom of this Readme) but it is not required as the script can do this for you. + You will need to have your router forward UPD port 1194 + (varies by model & manufacturer; consult your router manufacturer's + documentation to do this). + Enabling SSH on your Pi is also highly recommended, so that + you can run a very compact headless server without a monitor or keyboard and + be able to access it even more conveniently (This is also covered by source 2). + + +Installation +----------------- + + +```shell +curl -L install.pivpn.io | bash +``` + +The script will first update your APT repositories, upgrade packages, and install OpenVPN, +which will take some time. +It will ask which encryption method you wish the guts of your server to use, 1024-bit or 2048-bit. +2048-bit is more secure, but will take much longer to set up. If you're unsure or don't +have a convincing reason one way or the other I'd use 2048 today. + +After this, the script will go back to the command line as it builds the server's own +certificate authority. If you wish to enter identifying information for the +CA, replace the default values in the file ca_info.txt (CO for country, ST for +state/province/territory, ORG for organization, etc.) before executing the setup script; +however, this is not required, and you may leave the ca_info.txt file as-is. After this, +the script will prompt you in the command line for input in similar identifying information +fields as it generates your server certificate. Enter whatever you like, or if you do not +desire to fill them out, skip them by pressing enter; make sure to skip the challenge field +and leave it blank. After these fields, you will be asked whether you want to sign the +certificate; you must press 'y'. You'll also be asked if you want to commit - press 'y' +again. + +Finally, the script will take some time to build the server's Diffie-Hellman key +exchange. If you chose 1024-bit encryption, this will just take a few minutes, but if you +chose 2048-bit, it will take much longer (anywhere from 40 minutes to several hours on a +Model B+). The script will also make some changes to your system to allow it to forward +internet traffic and allow VPN connections through the Pi's firewall. When the script +informs you that it has finished configuring OpenVPN, reboot the system to apply the +changes, and the VPN server-side setup will be complete! + +Managing the PiVPN +---------------------- + +After the installation is complete you can use the command 'pivpn' to manage the server. + +"pivpn add" +You will be prompted to enter a name for your client. Pick anything you like and hit 'enter'. +You will be asked to enter a pass phrase for the client key; make sure it's one you'll remember. +You'll then be prompted for input in more identification fields, which you can again ignore if +you like; make sure you again leave the challenge field blank. The script will then ask if you +want to sign the client certificate and commit; press 'y' for both. You'll then be asked to enter +the pass phrase you just chose in order to encrypt the client key, and immediately after to choose +another pass phrase for the encrypted key - if you're normal, just use the same one. After this, +the script will assemble the client .ovpn file and place it in the directory 'ovpns' within your +home directory. + +Importing .ovpn Profiles on Client Machines +-------------------------------------------- + +To move a client .ovpn profile to Windows, use a program like WinSCP or Cyberduck. Note that +you may need administrator permission to move files to some folders on your Windows machine, +so if you have trouble transferring the profile to a particular folder with your chosen file +transfer program, try moving it to your desktop. To move a profile to Android, you can either +retrieve it on PC and then move it to your device via USB, or you can use an app like Turbo +FTP & SFTP client to retrieve it directly from your Android device. + +To import the profile to OpenVPN on Windows, download the OpenVPN GUI from the community downloads +section of openvpn.net, install it, and place the profile in the 'config' folder of your OpenVPN +directory, i.e., in 'C:\Program Files\OpenVPN\config'. To import the profile on Android, install +the OpenVPN Connect app, select 'Import' from the drop-down menu in the upper right corner of the +main screen, choose the directory on your device where you stored the .ovpn file, and select the +file. + +After importing, connect to the VPN server on Windows by running the OpenVPN GUI with +administrator permissions, right-clicking on the icon in the system tray, and clicking 'Connect', +or on Android by selecting the profile under 'OpenVPN Profile' and pressing 'Connect'. You'll be +asked to enter the pass phrase you chose. Do so, and you're in! Enjoy your ~$50 USD private VPN. + +Removing OpenVPN +---------------- + +If at any point you wish to remove OpenVPN from your Pi and revert it to a +pre-installation state, such as if you want to undo a failed installation to try again or +you want to remove OpenVPN without installing a fresh Raspbian image, just run +'pivpn uninstall' + +Feedback & Support +-------- + +I am interested in making this script work for as many people as possible, so I +welcome any feedback on your experience. If you have problems using it, feel +free to post an issue here on github. I'll classify the issues the best I can +to keep things sorted. + +I also encourage discussion of issues, solutions, and ideas on the RaspberryPi.org forum thread for the project [here.](https://www.raspberrypi.org/forums/viewtopic.php?f=36&t=137240&p=911599&hilit=OpenVPN#p911599) I'd love for users to have the opportunity to discuss their ideas with each other! + +Contributions +------------- + +I'm also interested in improving this script, and will be adding features to it +over time to make it easier, more intuitive, and more versatile. If you have any + feature ideas or requests, or are interested in adding your ideas to it, + testing it on other platforms, or localizing it to another language, please + comment or leave a pull request. I will be happy to work with you! + +If you have found this tool to be useful and want to use +[this PayPal link](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=K99QGVL7KA6ZL) +to buy me a gallon of gas, I would be very grateful! + +If you decide to do so, please also consider supporting OpenVPN; they +have produced a wonderful open-source product, and all credit for it goes to +their community and their hard work. All I did was write a little automated +front-end for its installation on Raspbian. + +Sources +------- + +1: [ModMyPi: How to give your Raspberry Pi a Static IP Address](https://www.modmypi.com/blog/tutorial-how-to-give-your-raspberry-pi-a-static-ip-address) + +2: [ReadWrite: 5 Pointers To Supercharge Your Raspberry Pi Projects](http://readwrite.com/2014/04/09/raspberry-pi-projects-ssh-remote-desktop-static-ip-tutorial?utm_content=readwrite3-orionautotweet&awesm=readwr.it_b1UN&utm_campaign=&utm_medium=readwr.it-twitter&utm_source=t.co#awesm=~oAXilI0BMOHsS3) + +3: [ReadWrite: Building A Raspberry Pi VPN Part 1](http://readwrite.com/2014/04/10/raspberry-pi-vpn-tutorial-server-secure-web-browsing) + +4: [ReadWrite: Building A Raspberry Pi VPN Part 2](http://readwrite.com/2014/04/11/building-a-raspberry-pi-vpn-part-two-creating-an-encrypted-client-side#awesm=~oB89WBfWrt21bV) diff --git a/auto_install/install.sh b/auto_install/install.sh new file mode 100644 index 0000000..deabc66 --- /dev/null +++ b/auto_install/install.sh @@ -0,0 +1,531 @@ +#!/usr/bin/env bash +# PiVPN: Trivial openvpn setup and configuration +# Easiest setup and mangement of openvpn on Raspberry Pi +# https://github.com/StarshipEngineer/OpenVPN-Setup/ +# Installs pivpn +# Heavily adapted from the pi-hole project +# +# Install with this command (from your Pi): +# +# curl -L vigilcode.com/pivpnsetup | bash + + +######## VARIABLES ######### + +tmpLog=/tmp/pivpn-install.log +instalLogLoc=/etc/pivpn/install.log + +pivpnGitUrl="https://github.com/0-kaladin/OpenVPN-Setup.git" +pivpnFilesDir="/etc/.pivpn" + + +# Find the rows and columns +rows=$(tput lines) +columns=$(tput cols) + +# Divide by two so the dialogs take up half of the screen, which looks nice. +r=$(( rows / 2 )) +c=$(( columns / 2 )) + + +# Find IP used to route to outside world + +IPv4dev=$(ip route get 8.8.8.8 | awk '{for(i=1;i<=NF;i++)if($i~/dev/)print $(i+1)}') +IPv4addr=$(ip -o -f inet addr show dev "$IPv4dev" | awk '{print $4}' | awk 'END {print}') +IPv4gw=$(ip route get 8.8.8.8 | awk '{print $3}') + +availableInterfaces=$(ip -o link | awk '{print $2}' | grep -v "lo" | cut -d':' -f1) +availableUsers=$(awk -F':' '$3>=500 && $3<=60000 {print $1}' /etc/passwd) +dhcpcdFile=/etc/dhcpcd.conf + +######## FIRST CHECK ######## +# Must be root to install +echo ":::" +if [[ $EUID -eq 0 ]];then + echo "::: You are root." +else + echo "::: sudo will be used for the install." + # Check if it is actually installed + # If it isn't, exit because the install cannot complete + if [[ $(dpkg-query -s sudo) ]];then + export SUDO="sudo" + else + echo "::: Please install sudo or run this as root." + exit 1 + fi +fi + +####### FUNCTIONS ########## +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" +} + +welcomeDialogs() { + # Display the welcome dialog + whiptail --msgbox --backtitle "Welcome" --title "PiVPN Automated Installer" "This installer will transform your Raspberry Pi into an openvpn server!" $r $c + + # Explain the need for a static address + whiptail --msgbox --backtitle "Initiating network interface" --title "Static IP Needed" "The PiVPN is a SERVER so it needs a STATIC IP ADDRESS to function properly. + +In the next section, you can choose to use your current network settings (DHCP) or to manually edit them." $r $c +} + +chooseUser() { + # Explain the local user + whiptail --msgbox --backtitle "Parsing User List" --title "Local Users" "Choose a local user that will hold your ovpn configurations." $r $c + + userArray=() + firstloop=1 + + while read -r line + do + mode="OFF" + if [[ $firstloop -eq 1 ]]; then + firstloop=0 + mode="ON" + fi + userArray+=("$line" "available" "$mode") + done <<< "$availableUsers" + + # Find out how many users are available to choose from + userCount=$(echo "$availableUsers" | wc -l) + chooseUserCmd=(whiptail --title "Choose A User" --separate-output --radiolist "Choose:" $r $c $userCount) + chooseUserOptions=$("${chooseUserCmd[@]}" "${userArray[@]}" 2>&1 >/dev/tty) + if [[ $? = 0 ]]; then + for desiredUser in $chooseUserOptions + do + pivpnUser=$desiredUser + echo "::: Using User: $pivpnUser" + echo "${pivpnUser}" > /tmp/pivpnUSR + done + else + echo "::: Cancel selected, exiting...." + exit 1 + fi +} + + +verifyFreeDiskSpace() { + # I have no idea what the minimum space needed is, but checking for at least 50MB sounds like a good idea. + requiredFreeBytes=51200 + + existingFreeBytes=$(df -lk / 2>&1 | awk '{print $4}' | head -2 | tail -1) + if ! [[ "$existingFreeBytes" =~ ^([0-9])+$ ]]; then + existingFreeBytes=$(df -lk /dev 2>&1 | awk '{print $4}' | head -2 | tail -1) + fi + + if [[ $existingFreeBytes -lt $requiredFreeBytes ]]; then + whiptail --msgbox --backtitle "Insufficient Disk Space" --title "Insufficient Disk Space" "\nYour system appears to be low on disk space. PiVPN recomends a minimum of $requiredFreeBytes Bytes.\nYou only have $existingFreeBytes Free.\n\nIf this is a new install you may need to expand your disk.\n\nTry running:\n 'sudo raspi-config'\nChoose the 'expand file system option'\n\nAfter rebooting, run this installation again.\n\ncurl -L vigilcode.com/pivpnsetup | bash\n" $r $c + echo "$existingFreeBytes is less than $requiredFreeBytes" + echo "Insufficient free space, exiting..." + exit 1 + fi +} + + +chooseInterface() { + # Turn the available interfaces into an array so it can be used with a whiptail dialog + interfacesArray=() + firstloop=1 + + while read -r line + do + mode="OFF" + if [[ $firstloop -eq 1 ]]; then + firstloop=0 + mode="ON" + fi + interfacesArray+=("$line" "available" "$mode") + done <<< "$availableInterfaces" + + # Find out how many interfaces are available to choose from + interfaceCount=$(echo "$availableInterfaces" | wc -l) + chooseInterfaceCmd=(whiptail --separate-output --radiolist "Choose An Interface" $r $c $interfaceCount) + chooseInterfaceOptions=$("${chooseInterfaceCmd[@]}" "${interfacesArray[@]}" 2>&1 >/dev/tty) + if [[ $? = 0 ]]; then + for desiredInterface in $chooseInterfaceOptions + do + pivpnInterface=$desiredInterface + echo "::: Using interface: $pivpnInterface" + echo "${pivpnInterface}" > /tmp/pivpnINT + done + else + echo "::: Cancel selected, exiting...." + exit 1 + fi +} + +getStaticIPv4Settings() { + # Ask if the user wants to use DHCP settings as their static IP + if (whiptail --backtitle "Calibrating network interface" --title "Static IP Address" --yesno "Do you want to use your current network settings as a static address? + IP address: $IPv4addr + Gateway: $IPv4gw" $r $c) then + # If they choose yes, let the user know that the IP address will not be available via DHCP and may cause a conflict. + whiptail --msgbox --backtitle "IP information" --title "FYI: IP Conflict" "It is possible your router could still try to assign this IP to a device, which would cause a conflict. But in most cases the router is smart enough to not do that. +If you are worried, either manually set the address, or modify the DHCP reservation pool so it does not include the IP you want. +It is also possible to use a DHCP reservation, but if you are going to do that, you might as well set a static address." $r $c + # Nothing else to do since the variables are already set above + else + # Otherwise, we need to ask the user to input their desired settings. + # Start by getting the IPv4 address (pre-filling it with info gathered from DHCP) + # Start a loop to let the user enter their information with the chance to go back and edit it if necessary + until [[ $ipSettingsCorrect = True ]] + do + # Ask for the IPv4 address + IPv4addr=$(whiptail --backtitle "Calibrating network interface" --title "IPv4 address" --inputbox "Enter your desired IPv4 address" $r $c "$IPv4addr" 3>&1 1>&2 2>&3) + if [[ $? = 0 ]];then + echo "::: Your static IPv4 address: $IPv4addr" + # Ask for the gateway + IPv4gw=$(whiptail --backtitle "Calibrating network interface" --title "IPv4 gateway (router)" --inputbox "Enter your desired IPv4 default gateway" $r $c "$IPv4gw" 3>&1 1>&2 2>&3) + if [[ $? = 0 ]];then + echo "::: Your static IPv4 gateway: $IPv4gw" + # Give the user a chance to review their settings before moving on + if (whiptail --backtitle "Calibrating network interface" --title "Static IP Address" --yesno "Are these settings correct? + IP address: $IPv4addr + Gateway: $IPv4gw" $r $c)then + # If the settings are correct, then we need to set the piVPNIP + # Saving it to a temporary file us to retrieve it later when we run the gravity.sh script + echo "${IPv4addr%/*}" > /tmp/pivpnIP + echo "$pivpnInterface" > /tmp/pivpnINT + # After that's done, the loop ends and we move on + ipSettingsCorrect=True + else + # If the settings are wrong, the loop continues + ipSettingsCorrect=False + fi + else + # Cancelling gateway settings window + ipSettingsCorrect=False + echo "::: Cancel selected. Exiting..." + exit 1 + fi + else + # Cancelling IPv4 settings window + ipSettingsCorrect=False + echo "::: Cancel selected. Exiting..." + exit 1 + fi + done + # End the if statement for DHCP vs. static + fi +} + +setDHCPCD() { + # Append these lines to dhcpcd.conf to enable a static IP + echo "::: interface $pivpnInterface + static ip_address=$IPv4addr + static routers=$IPv4gw + static domain_name_servers=$IPv4gw" | $SUDO tee -a $dhcpcdFile >/dev/null +} + +setStaticIPv4() { + # Tries to set the IPv4 address + if grep -q "$IPv4addr" $dhcpcdFile; then + # address already set, noop + : + else + setDHCPCD + $SUDO ip addr replace dev "$pivpnInterface" "$IPv4addr" + echo ":::" + echo "::: Setting IP to $IPv4addr. You may need to restart after the install is complete." + echo ":::" + fi +} + +function valid_ip() +{ + local ip=$1 + local stat=1 + + if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then + OIFS=$IFS + IFS='.' + ip=($ip) + IFS=$OIFS + [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \ + && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]] + stat=$? + fi + return $stat +} + +installScripts() { + # Install the scripts from /etc/.pivpn to their various locations + $SUDO echo ":::" + $SUDO echo -n "::: Installing scripts to /opt/pivpn..." + if [ ! -d /opt/pivpn ]; then + $SUDO mkdir /opt/pivpn + $SUDO chown "$pivpnUser":root /opt/pivpn + $SUDO chmod u+srwx /opt/pivpn + fi + $SUDO cp /etc/.pivpn/scripts/makeOVPN.sh /opt/pivpn/makeOVPN.sh + $SUDO cp /etc/.pivpn/scripts/listOVPN.sh /opt/pivpn/listOVPN.sh + $SUDO cp /etc/.pivpn/scripts/removeOVPN.sh /opt/pivpn/removeOVPN.sh + $SUDO cp /etc/.pivpn/scripts/uninstall.sh /opt/pivpn/uninstall.sh + $SUDO cp /etc/.pivpn/scripts/pivpnDebug.sh /opt/pivpn/pivpnDebug.sh + $SUDO chmod 0755 /opt/pivpn/{makeOVPN,listOVPN,removeOVPN,uninstall,pivpnDebug}.sh + $SUDO cp /etc/.pivpn/pivpn /usr/local/bin/pivpn + $SUDO chmod 0755 /usr/local/bin/pivpn + $SUDO cp /etc/.pivpn/scripts/bash-completion /etc/bash_completion.d/pivpn + source /etc/bash_completion.d/pivpn + + $SUDO echo " done." +} + +stopServices() { + # Stop openvpn + $SUDO echo ":::" + $SUDO echo -n "::: Stopping openvpn service..." + $SUDO service openvpn stop || true + $SUDO echo " done." +} + +checkForDependencies() { + #Running apt-get update/upgrade with minimal output can cause some issues with + #requiring user input (e.g password for phpmyadmin see #218) + #We'll change the logic up here, to check to see if there are any updates availible and + # if so, advise the user to run apt-get update/upgrade at their own discretion + #Check to see if apt-get update has already been run today + # it needs to have been run at least once on new installs! + + timestamp=$(stat -c %Y /var/cache/apt/) + timestampAsDate=$(date -d @"$timestamp" "+%b %e") + today=$(date "+%b %e") + + if [ ! "$today" == "$timestampAsDate" ]; then + #update package lists + echo ":::" + echo -n "::: apt-get update has not been run today. Running now..." + $SUDO apt-get -qq update & spinner $! + echo " done!" + fi + echo ":::" + echo -n "::: Checking apt-get for upgraded packages...." + updatesToInstall=$($SUDO apt-get -s -o Debug::NoLocking=true upgrade | grep -c ^Inst) + echo " done!" + echo ":::" + if [[ $updatesToInstall -eq "0" ]]; then + echo "::: Your pi is up to date! Continuing with PiVPN installation..." + else + echo "::: There are $updatesToInstall updates availible for your pi!" + echo "::: We recommend you run 'sudo apt-get upgrade' after installing PiVPN! " + echo ":::" + fi + echo ":::" + echo "::: Checking dependencies:" + + dependencies=( openvpn easy-rsa git iptables-persistent dnsutils ) + for i in "${dependencies[@]}"; do + echo -n "::: Checking for $i..." + if [ "$(dpkg-query -W -f='${Status}' "$i" 2>/dev/null | grep -c "ok installed")" -eq 0 ]; then + echo -n " Not found! Installing...." + #Supply answers to the questions so we don't prompt user + if [[ $i -eq "iptables-persistent" ]]; then + echo iptables-persistent iptables-persistent/autosave_v4 boolean true | $SUDO debconf-set-selections + echo iptables-persistent iptables-persistent/autosave_v6 boolean false | $SUDO debconf-set-selections + fi + $SUDO apt-get -y -qq install "$i" > /dev/null & spinner $! + echo " done!" + else + echo " already installed!" + fi + done +} + +getGitFiles() { + # Setup git repos for base files + echo ":::" + echo "::: Checking for existing base files..." + if is_repo $pivpnFilesDir; then + make_repo $pivpnFilesDir $pivpnGitUrl + else + update_repo $pivpnFilesDir + fi +} + +is_repo() { + # If the directory does not have a .git folder it is not a repo + echo -n "::: Checking $1 is a repo..." + if [ -d "$1/.git" ]; then + echo " OK!" + return 1 + fi + echo " not found!!" + return 0 +} + +make_repo() { + # Remove the non-repos interface and clone the interface + echo -n "::: Cloning $2 into $1..." + $SUDO rm -rf "$1" + $SUDO git clone -q "$2" "$1" > /dev/null & spinner $! + echo " done!" +} + +update_repo() { + # Pull the latest commits + echo -n "::: Updating repo in $1..." + cd "$1" || exit + $SUDO git pull -q > /dev/null & spinner $! + echo " done!" +} + +confOpenVPN () { + # Ask user for desired level of encryption + ENCRYPT=$(whiptail --backtitle "Setup OpenVPN" --title "Encryption Strength" --radiolist \ + "Choose your desired level of encryption:" $r $c 2 \ + "2048" "Use 2048-bit encryption. Slower to set up, but more secure." ON \ + "1024" "Use 1024-bit encryption. Faster to set up, but less secure." OFF 3>&1 1>&2 2>&3) + + exitstatus=$? + if [ $exitstatus != 0 ]; then + echo "::: Cancel selected. Exiting..." + exit 1 + fi + # Copy the easy-rsa files to a directory inside the new openvpn directory + cp -r /usr/share/easy-rsa /etc/openvpn + + # Edit the EASY_RSA variable in the vars file to point to the new easy-rsa directory, + # And change from default 1024 encryption if desired + cd /etc/openvpn/easy-rsa + sed -i 's:"`pwd`":"/etc/openvpn/easy-rsa":' vars + if [[ $ENCRYPT -eq "1024" ]]; then + sed -i 's:KEY_SIZE=2048:KEY_SIZE=1024:' vars + fi + + # source the vars file just edited + source ./vars + + # Remove any previous keys + ./clean-all + + # Build the certificate authority + ./build-ca < /etc/.pivpn/ca_info.txt + + whiptail --msgbox --backtitle "Setup OpenVPN" --title "Server Information" "You will now be asked for identifying information for the server. Press 'Enter' to skip a field." $r $c + # can export env variables here for users to provide. export KEY_EMAIL will set email field for example. + + # Build the server + ./build-key-server --batch server + + # Generate Diffie-Hellman key exchange + ./build-dh + + # Generate static HMAC key to defend against DDoS + openvpn --genkey --secret keys/ta.key + + # Write config file for server using the template .txt file + LOCALIP=$(ifconfig $pivpnInterface | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*') + sed 's/LOCALIP/'$LOCALIP'/' /etc/openvpn/server.conf + if [ $ENCRYPT = 2048 ]; then + sed -i 's:dh1024:dh2048:' /etc/openvpn/server.conf + fi +} + +confNetwork() { + # Enable forwarding of internet traffic + sed -i '/#net.ipv4.ip_forward=1/c\net.ipv4.ip_forward=1' /etc/sysctl.conf + $SUDO sysctl -p + + # Write script to run openvpn and allow it through firewall on boot using the template .txt file + $SUDO iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o $IPv4dev -j MASQUERADE + $SUDO netfilter-persistent save +} + +confOVPN() { + IPv4pub=$(dig +short myip.opendns.com @resolver1.opendns.com) + $SUDO cp /tmp/pivpnUSR /etc/pivpn/INSTALL_USER + + # Set status that no certs have been revoked + $SUDO echo 0 > /etc/pivpn/REVOKE_STATUS + + METH=$(whiptail --title "Public IP or DNS" --radiolist "Will clients use a Public IP or DNS?" $r $c 2 \ + "$IPv4pub" "Use this public IP" "ON" \ + "DNS Entry" "Use a public DNS" "OFF" 3>&1 1>&2 2>&3) + + exitstatus=$? + if [ $exitstatus != 0 ]; then + echo "::: Cancel selected. Exiting..." + exit 1 + fi + + + if [ "$METH" == "$IPv4pub" ]; then + sed 's/IPv4pub/'$IPv4pub'/' /etc/openvpn/easy-rsa/keys/Default.txt + else + PUBLICDNS=$(whiptail --title "PiVPN Setup" --inputbox "What is the public DNS name of this Raspberry Pi?" $r $c 3>&1 1>&2 2>&3) + exitstatus=$? + if [ $exitstatus = 0 ]; then + sed 's/IPv4pub/'$PUBLICDNS'/' /etc/openvpn/easy-rsa/keys/Default.txt + whiptail --title "Setup OpenVPN" --infobox "Using PUBLIC DNS: $PUBLICDNS" $r $c + else + whiptail --title "Setup OpenVPN" --infobox "Cancelled" $r $c + exit 1 + fi + fi + + mkdir /home/$pivpnUser/ovpns + chmod 0777 -R /home/$pivpnUser/ovpns +} + +installPiVPN() { + checkForDependencies + stopServices + $SUDO mkdir -p /etc/pivpn/ + getGitFiles + installScripts + confOpenVPN + confNetwork + confOVPN +} + +displayFinalMessage() { + # Final completion message to user + $SUDO systemctl enable openvpn.service + $SUDO systemctl start openvpn.service + whiptail --msgbox --backtitle "Make it so." --title "Installation Complete!" "Now run 'pivpn add' to create the ovpn profiles. +Run 'pivpn help' to see what else you can do! +The install log is in /etc/pivpn." $r $c + if (whiptail --title "Reboot" --yesno --defaultno "It is strongly recommended you reboot after installation. Would you like to reboot now?" $r $c); then + whiptail --title "Rebooting" --msgbox "The system will now reboot." $r $c + printf "\nRebooting system...\n" + sleep 3 + shutdown -r now + fi +} + +######## SCRIPT ############ +# Start the installer +welcomeDialogs + +# Verify there is enough disk space for the install +verifyFreeDiskSpace + +# Find interfaces and let the user choose one +chooseInterface +getStaticIPv4Settings +setStaticIPv4 + +# Choose the user for the ovpns +chooseUser + +# Install and log everything to a file +installPiVPN + +# Move the log file into /etc/pivpn for storage +#$SUDO mv $tmpLog $installLogLoc + +displayFinalMessage + +echo "::: Install Complete..." diff --git a/ca_info.txt b/ca_info.txt new file mode 100644 index 0000000..df01b22 --- /dev/null +++ b/ca_info.txt @@ -0,0 +1,8 @@ +CO +ST +CITY +ORG +ORG-UNIT +COMMON-NAME +NAME +EMAIL diff --git a/firewall-openvpn-rules.txt b/firewall-openvpn-rules.txt new file mode 100644 index 0000000..1fc98bf --- /dev/null +++ b/firewall-openvpn-rules.txt @@ -0,0 +1,3 @@ +#!/bin/sh + +iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o IPv4dev -j MASQUERADE diff --git a/pivpn b/pivpn new file mode 100644 index 0000000..752ec04 --- /dev/null +++ b/pivpn @@ -0,0 +1,71 @@ +#!/bin/bash + +# Must be root to use this tool +if [[ ! $EUID -eq 0 ]];then + #echo "::: You are root." +#else + #echo "::: Sudo will be used for this tool." + # Check if it is actually installed + # If it isn't, exit because the pivpn cannot be invoked without privileges. + if [[ $(dpkg-query -s sudo) ]];then + export SUDO="sudo" + else + echo "::: Please install sudo or run this as root." + exit 1 + fi +fi + +function makeOVPNFunc { + $SUDO /opt/pivpn/makeOVPN.sh + exit 1 +} + +function listOVPNFunc { + $SUDO /opt/pivpn/listOVPN.sh + exit 1 +} + +function debugFunc { + $SUDO /opt/pivpn/pivpnDebug.sh + exit 1 +} + +function removeOVPNFunc { + $SUDO /opt/pivpn/removeOVPN.sh + exit 1 +} + +function uninstallFunc { + $SUDO /opt/pivpn/uninstall.sh + exit 1 +} + +function helpFunc { + echo "::: Control all PiVPN specific functions!" + echo ":::" + echo "::: Usage: pivpn [options]" + echo ":::" + echo "::: Options:" + echo "::: -a, add Create a client ovpn profile" + echo "::: -d, debug Start a debugging session if having trouble" + echo "::: -l, list List all valid and revoked certificates" + echo "::: -r, revoke Revoke a client ovpn profile" + echo "::: -h, help Show this help dialog" + echo "::: -u, uninstall Uninstall PiVPN from your system!" + exit 1 +} + +if [[ $# = 0 ]]; then + helpFunc +fi + +# Handle redirecting to specific functions based on arguments +case "$1" in +"-a" | "add" ) makeOVPNFunc;; +"-d" | "debug" ) debugFunc;; +"-l" | "list" ) listOVPNFunc;; +"-r" | "revoke" ) removeOVPNFunc;; +"-h" | "help" ) helpFunc;; +"-u" | "uninstall" ) uninstallFunc;; +* ) helpFunc;; +esac diff --git a/scripts/bash-completion b/scripts/bash-completion new file mode 100644 index 0000000..6d18ea8 --- /dev/null +++ b/scripts/bash-completion @@ -0,0 +1,18 @@ +_pivpn() +{ + local cur prev opts + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + opts="debug add list revoke uninstall help" + + if [[ ${cur} == -* ]] ; then + opts="-a -d -l -r -h -u" + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + fi + + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 +} +complete -F _pivpn pivpn diff --git a/scripts/listOVPN.sh b/scripts/listOVPN.sh new file mode 100644 index 0000000..fe1cc6a --- /dev/null +++ b/scripts/listOVPN.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +# PiVPN: list clients script + +INDEX="/etc/openvpn/easy-rsa/keys/index.txt" +printf "\n" +if [ ! -f $INDEX ]; then + printf "The file: $INDEX \n" + printf "Was not Found!\n" + exit 1 +fi + +printf ": NOTE : You should always have a valid server entry below!\n" +printf "\n" +printf "\e[1m::: Certificate Status List :::\e[0m\n" +printf " ::\e[4m Status \e[0m||\e[4m Name \e[0m:: \n" + +while read -r line || [[ -n "$line" ]]; do + status=$(echo $line | awk '{print $1}') + if [[ $status = "V" ]]; then + printf " Valid :: " + var=$(echo $line | awk '{print $5}' | cut -d'/' -f7) + var=${var#CN=} + printf " $var\n" + fi + if [[ $status = "R" ]]; then + printf " Revoked :: " + var=$(echo $line | awk '{print $6}' | cut -d'/' -f7) + var=${var#CN=} + printf " $var\n" + fi +done <$INDEX +printf "\n" diff --git a/scripts/makeOVPN.sh b/scripts/makeOVPN.sh new file mode 100644 index 0000000..ede89ee --- /dev/null +++ b/scripts/makeOVPN.sh @@ -0,0 +1,81 @@ +#!/bin/bash +# Create OVPN Client +# Default Variable Declarations +DEFAULT="Default.txt" +FILEEXT=".ovpn" +CRT=".crt" +OKEY=".key" +KEY=".3des.key" +CA="ca.crt" +TA="ta.key" +INSTALL_USER=$(cat /etc/pivpn/INSTALL_USER) + +echo "Please enter a Name for the Client:" +read NAME + +#Build the client key and then encrypt the key +cd /etc/openvpn/easy-rsa +source /etc/openvpn/easy-rsa/vars +./build-key-pass $NAME +cd keys +openssl rsa -in $NAME$OKEY -des3 -out $NAME$KEY + +#1st Verify that clients Public Key Exists +if [ ! -f $NAME$CRT ]; then + echo "[ERROR]: Client Public Key Certificate not found: $NAME$CRT" + exit +fi +echo "Client's cert found: $NAME$CRT" + +#Then, verify that there is a private key for that client +if [ ! -f $NAME$KEY ]; then + echo "[ERROR]: Client 3des Private Key not found: $NAME$KEY" + exit +fi +echo "Client's Private Key found: $NAME$KEY" + +#Confirm the CA public key exists +if [ ! -f $CA ]; then + echo "[ERROR]: CA Public Key not found: $CA" + exit +fi +echo "CA public Key found: $CA" + +#Confirm the tls-auth ta key file exists +if [ ! -f $TA ]; then + echo "[ERROR]: tls-auth Key not found: $TA" + exit +fi +echo "tls-auth Private Key found: $TA" + +#Ready to make a new .ovpn file - Start by populating with the +#default file +cat $DEFAULT > $NAME$FILEEXT + +#Now, append the CA Public Cert +echo "" >> $NAME$FILEEXT +cat $CA >> $NAME$FILEEXT +echo "" >> $NAME$FILEEXT + +#Next append the client Public Cert +echo "" >> $NAME$FILEEXT +cat $NAME$CRT | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' >> $NAME$FILEEXT +echo "" >> $NAME$FILEEXT + +#Then, append the client Private Key +echo "" >> $NAME$FILEEXT +cat $NAME$KEY >> $NAME$FILEEXT +echo "" >> $NAME$FILEEXT + +#Finally, append the TA Private Key +echo "" >> $NAME$FILEEXT +cat $TA >> $NAME$FILEEXT +echo "" >> $NAME$FILEEXT + +# Copy the .ovpn profile to the home directory for convenient remote access +cp /etc/openvpn/easy-rsa/keys/$NAME$FILEEXT /home/$INSTALL_USER/ovpns/$NAME$FILEEXT +echo "$NAME$FILEEXT moved to home directory." +whiptail --title "MakeOVPN" --msgbox "Done! $NAME$FILEEXT successfully created and \ +moved to directory /home/$INSTALL_USER/ovpns." 8 78 + +# Original script written by Eric Jodoin. diff --git a/scripts/pivpnDebug.sh b/scripts/pivpnDebug.sh new file mode 100644 index 0000000..ea2f72c --- /dev/null +++ b/scripts/pivpnDebug.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +echo "::: This feature is not yet implemented... stay tuned!" diff --git a/scripts/removeOVPN.sh b/scripts/removeOVPN.sh new file mode 100644 index 0000000..cc9ba2c --- /dev/null +++ b/scripts/removeOVPN.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +# PiVPN: revoke client script + +INSTALL_USER=$(cat /etc/pivpn/INSTALL_USER) +REVOKE_STATUS=$(cat /etc/pivpn/REVOKE_STATUS) +INDEX="/etc/openvpn/easy-rsa/keys/index.txt" + +if [ ! -f $INDEX ]; then + printf "The file: $INDEX \n" + printf "Was not Found!\n" + exit 1 +fi + +printf "\n" +printf " ::\e[4m Certificate List \e[0m:: \n" + +while read -r line || [[ -n "$line" ]]; do + status=$(echo $line | awk '{print $1}') + if [[ $status = "V" ]]; then + var=$(echo $line | awk '{print $5}' | cut -d'/' -f7) + var=${var#CN=} + if [ "$var" != "server" ]; then + printf " $var\n" + fi + fi +done <$INDEX +printf "\n" + +echo "::: Please enter the Name of the client to be revoked from the list above:" +read NAME + +cd /etc/openvpn/easy-rsa +source /etc/openvpn/easy-rsa/vars + +./revoke-full $NAME +echo "::: Certificate revoked, removing ovpns from /home/$INSTALL_USER/ovpns" +rm /home/$INSTALL_USER/ovpns/$NAME.ovpn +cp /etc/openvpn/easy-rsa/keys/crl.pem /etc/openvpn/crl.pem +echo "::: Completed!" + +if [ $REVOKE_STATUS == 0 ]; then + echo 1 > /etc/pivpn/REVOKE_STATUS + printf "\nThis seems to be the first time you have revoked a cert.\n" + printf "We are adding the CRL to the server.conf and restarting openvpn.\n" + sed -i '/#crl-verify/c\crl-verify /etc/openvpn/crl.pem' /etc/openvpn/server.conf + systemctl restart openvpn.service +fi diff --git a/scripts/uninstall.sh b/scripts/uninstall.sh new file mode 100644 index 0000000..e1a0d5b --- /dev/null +++ b/scripts/uninstall.sh @@ -0,0 +1,117 @@ +#!/usr/bin/env bash +# PiVPN: Uninstall Script + +# Must be root to uninstall +if [[ $EUID -eq 0 ]];then + echo "::: You are root." +else + echo "::: Sudo will be used for the uninstall." + # Check if it is actually installed + # If it isn't, exit because the unnstall cannot complete + if [[ $(dpkg-query -s sudo) ]];then + export SUDO="sudo" + else + echo "::: Please install sudo or run this as root." + exit 1 + fi +fi + +INSTALL_USER=$(cat /etc/pivpn/INSTALL_USER) + +# Find the rows and columns +rows=$(tput lines) +columns=$(tput cols) + +# Divide by two so the dialogs take up half of the screen, which looks nice. +r=$(( rows / 2 )) +c=$(( columns / 2 )) + +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" +} + +function removeAll { + # Purge dependencies +echo ":::" + dependencies=( openvpn easy-rsa git iptables-persistent dnsutils ) + for i in "${dependencies[@]}"; do + if [ "$(dpkg-query -W --showformat='${Status}\n' "$i" 2> /dev/null | grep -c "ok installed")" -eq 1 ]; then + while true; do + read -rp "::: Do you wish to remove $i from your system? [y/n]: " yn + case $yn in + [Yy]* ) printf ":::\tRemoving %s..." "$i"; $SUDO apt-get -y remove --purge "$i" &> /dev/null & spinner $!; printf "done!\n"; + if [ "$i" == "openvpn" ]; then UINST_OVPN=1 ; fi + break;; + [Nn]* ) printf ":::\tSkipping %s" "$i\n"; break;; + * ) printf "::: You must answer yes or no!\n";; + esac + done + else + printf ":::\tPackage %s not installed... Not removing.\n" "$i" + fi + done + + # Take care of any additional package cleaning + printf "::: Auto removing remaining dependencies..." + $SUDO apt-get -y autoremove &> /dev/null & spinner $!; printf "done!\n"; + printf "::: Auto cleaning remaining dependencies..." + $SUDO apt-get -y autoclean &> /dev/null & spinner $!; printf "done!\n"; + + echo ":::" + # Removing pivpn files + echo "::: Removing pivpn system files..." + $SUDO rm -rf /opt/pivpn &> /dev/null + $SUDO rm -rf /etc/.pivpn &> /dev/null + $SUDO rm -rf /etc/pivpn &> /dev/null + $SUDO rm -rf /home/$INSTALL_USER/ovpns &> /dev/null + + $SUDO rm -rf /var/log/*pivpn* &> /dev/null + $SUDO rm -rf /var/log/*openvpn* &> /dev/null + if [[ $UINST_OVPN = 1 ]]; then + $SUDO rm -rf /etc/openvpn &> /dev/null + fi + $SUDO rm /usr/local/bin/pivpn &> /dev/null + $SUDO rm /etc/bash_completion.d/pivpn + + # Disable IPv4 forwarding + sed -i '/net.ipv4.ip_forward=1/c\#net.ipv4.ip_forward=1' /etc/sysctl.conf + sysctl -p + + echo ":::" + printf "::: Finished removing PiVPN from your system.\n" + printf "::: Reinstall by simpling running\n:::\n:::\tcurl -L vigilcode.com/pivpnsetup | bash\n:::\n::: at any time!\n:::\n" +} + +function 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/server_config.txt b/server_config.txt new file mode 100644 index 0000000..3bb1761 --- /dev/null +++ b/server_config.txt @@ -0,0 +1,37 @@ +dev tun +proto udp +port 1194 +ca /etc/openvpn/easy-rsa/keys/ca.crt +cert /etc/openvpn/easy-rsa/keys/server.crt +key /etc/openvpn/easy-rsa/keys/server.key +dh /etc/openvpn/easy-rsa/keys/dh1024.pem +server 10.8.0.0 255.255.255.0 +# server and remote endpoints +ifconfig 10.8.0.1 10.8.0.2 +# Add route to Client routing table for the OpenVPN Server +push "route 10.8.0.1 255.255.255.255" +# Add route to Client routing table for the OPenVPN Subnet +push "route 10.8.0.0 255.255.255.0" +# your local subnet +push "route LOCALIP 255.255.255.0" +# Set your primary domain name server address to Google DNS 8.8.8.8 +push "dhcp-option DNS 8.8.8.8" +# Override the Client default gateway by using 0.0.0.0/1 and +# 128.0.0.0/1 rather than 0.0.0.0/0. This has the benefit of +# overriding but not wiping out the original default gateway. +push "redirect-gateway def1" +client-to-client +duplicate-cn +keepalive 10 120 +tls-auth /etc/openvpn/easy-rsa/keys/ta.key 0 +cipher AES-128-CBC +comp-lzo +user nobody +group nogroup +persist-key +persist-tun +#crl-verify /etc/openvpn/crl.pem +status /var/log/openvpn-status.log 20 +log /var/log/openvpn.log +verb 1 +# This configuration file was originally written by Lauren Orsini at ReadWrite.