diff --git a/README.md b/README.md index 99c70a4..f1b4cb1 100644 --- a/README.md +++ b/README.md @@ -6,14 +6,28 @@ This repository contains documentation on how to create native WireGuard connect You will find a lot of information bellow. However if you prefer a hands-on approach, here is the __TL/DR__: * clone this repo: `git clone https://github.com/pia-foss/manual-connections.git` * use `get_region_and_token.sh` to get the best region and a token - * use `wireguard_and_pf.sh` to create a WireGuard connection with/without PF + * use `connect_to_wireguard_with_token.sh` to create a WireGuard connection with/without PF + +Here is a oneliner example: +``` +sudo PIA_AUTOCONNECT=wireguard PIA_USER=p0123456 PIA_PASS=xxxxxxxxxx ./get_region_and_token.sh +``` ### Dependencies In order for the scripts to work (probably even if you do a manual setup), you will need the following packages: * `curl` * `jq` - * `wireguard-tools` (which give you the `wg-quick` utility) + * (only for WireGuard) `wireguard-tools` and wireguard kernel module + * (only for OpenVPN) `openvpn` + +### Confirmed distributions + +The functionality of the scripts within this repository has been tested and confirmed on the following distributions: + * Arch + * Artix + * Fedora 32 + * Ubuntu 20.04 ## PIA Port Forwarding @@ -26,9 +40,10 @@ This service can be used only AFTER establishing a VPN connection. In order to help you use VPN services and PF on any device, we have prepare a few bash scripts that should help you through the process of setting everything up. The scripts also contain a lot of comments, just in case you require detailed information regarding how the technology works. Here is a list of scripts you could find useful: - * [region and token script](get_region_and_token.sh): This script helps you to get the best region and also to get a token for VPN authentication. The script will extend it's functionality if you add extra environment variables. Adding your PIA credentials will allow the script to also get a VPN token. The script can also trigger the WireGuard script to create a connection, if you specify `WG_AUTOCONNECT=true`. - * [wireguard and pf script](wireguard_and_pf.sh): This script allow you to connect to the VPN server via WireGuard. You can specify `PIA_PF=true` if you also wish to get Port Forwarding for your connection. - * OpenVPN automation is not ready yet, however will be available soon enough. + * [Get the best region and a token](get_region_and_token.sh): This script helps you to get the best region and also to get a token for VPN authentication. The script will extend it's functionality if you add extra environment variables. Adding your PIA credentials will allow the script to also get a VPN token. The script can also trigger the WireGuard script to create a connection, if you specify `WG_AUTOCONNECT=true`. + * [Connect to WireGuard](connect_to_wireguard_with_token.sh): This script allow you to connect to the VPN server via WireGuard. You can specify `PIA_PF=true` if you also wish to get Port Forwarding for your connection. + * Connect to OpenVPN: We are still working on this script. + * [Enable Port Forwarding](port_forwarding.sh): Enables you to add Port Forwarding to an existing VPN connection. ## Manual setup of PF @@ -90,3 +105,6 @@ listening on any, link-type LINUX_SLL (Linux cooked v1), capture size 262144 byt 22:44:01.510804 IP 81.180.227.170.33884 > 10.4.143.34.47047: Flags [S], seq 906854496, win 64860, options [mss 1380,sackOK,TS val 2608022390 ecr 0,nop,wscale 7], length 0 22:44:01.510895 IP 10.4.143.34.47047 > 81.180.227.170.33884: Flags [R.], seq 0, ack 906854497, win 0, length 0 ``` + +## License +This project is licensed under the [MIT (Expat) license](https://choosealicense.com/licenses/mit/), which can be found [here](/LICENSE). diff --git a/wireguard_and_pf.sh b/connect_to_wireguard_with_token.sh similarity index 56% rename from wireguard_and_pf.sh rename to connect_to_wireguard_with_token.sh index 80b3cfd..a282a3f 100755 --- a/wireguard_and_pf.sh +++ b/connect_to_wireguard_with_token.sh @@ -127,93 +127,14 @@ fi echo " This script got started with PIA_PF=true. -Starting procedure to enable port forwarding." +Starting procedure to enable port forwarding by running the following command: +PIA_TOKEN=$WG_TOKEN \\ + PF_GATEWAY=\"$(echo "$wireguard_json" | jq -r '.server_vip')\" \\ + PF_HOSTNAME=\"$WG_HOSTNAME\" \\ + ./port_forwarding.sh +" -# The port forwarding system has required two variables: -# PAYLOAD: contains the token, the port and the expiration date -# SIGNATURE: certifies the payload originates from the PIA network. - -# Basically PAYLOAD+SIGNATURE=PORT. You can use the same PORT on all servers. -# The system has been designed to be completely decentralized, so that your -# privacy is protected even if you want to host services on your systems. - -# You can get your PAYLOAD+SIGNATURE with a simple curl request to any VPN -# gateway, no matter what protocol you are using. -# Since this is the script for wireguard, you can just get the gateway -# from the JSON response you got at the previous step from the Wireguard API. -gateway="$(echo "$wireguard_json" | jq -r '.server_vip')" - -# Get the payload and the signature from the PF API. This will grant you -# access to a random port, which you can activate on any server you connect to. -# If you already have a signature, and you would like to re-use that port, -# save the payload_and_signature received from your previous request -# in the env var PAYLOAD_AND_SIGNATURE, and that will be used instead. -if [[ ! $PAYLOAD_AND_SIGNATURE ]]; then - echo "Getting new signature..." - payload_and_signature="$(curl -s -m 5 \ - --connect-to "$WG_HOSTNAME::$gateway:" \ - --cacert "ca.rsa.4096.crt" \ - -G --data-urlencode "token=${WG_TOKEN}" \ - "https://${WG_HOSTNAME}:19999/getSignature")" -else - payload_and_signature="$PAYLOAD_AND_SIGNATURE" - echo "Using the following payload_and_signature from the env var:" -fi -echo "$payload_and_signature" -export payload_and_signature - -# Check if the payload and the signature are OK. -# If they are not OK, just stop the script. -if [ "$(echo "$payload_and_signature" | jq -r '.status')" != "OK" ]; then - echo "The payload_and_signature variable does not contain an OK status." - exit 1 -fi - -# We need to get the signature out of the previous response. -# The signature will allow the us to bind the port on the server. -signature="$(echo "$payload_and_signature" | jq -r '.signature')" - -# The payload has a base64 format. We need to extract it from the -# previous reponse and also get the following information out: -# - port: This is the port you got access to -# - expires_at: this is the date+time when the port expires -payload="$(echo "$payload_and_signature" | jq -r '.payload')" -port="$(echo "$payload" | base64 -d | jq -r '.port')" - -# The port normally expires after 2 months. If you consider -# 2 months is not enough for your setup, please open a ticket. -expires_at="$(echo "$payload" | base64 -d | jq -r '.expires_at')" - -# Display some information on the screen for the user. -echo "The signature is OK. - ---> The port is $port and it will expire on $expires_at. <-- - -Trying to bind the port..." - -# Now we have all required data to create a request to bind the port. -# We will repeat this request every 15 minutes, in order to keep the port -# alive. The servers have no mechanism to track your activity, so they -# will just delete the port forwarding if you don't send keepalives. -while true; do - bind_port_response="$(curl -Gs -m 5 \ - --connect-to "$WG_HOSTNAME::$gateway:" \ - --cacert "ca.rsa.4096.crt" \ - --data-urlencode "payload=${payload}" \ - --data-urlencode "signature=${signature}" \ - "https://${WG_HOSTNAME}:19999/bindPort")" - echo "$bind_port_response" - - # If port did not bind, just exit the script. - # This script will exit in 2 months, since the port will expire. - export bind_port_response - if [ "$(echo "$bind_port_response" | jq -r '.status')" != "OK" ]; then - echo "The API did not return OK when trying to bind port. Exiting." - exit 1 - fi - echo Port $port refreshed on $(date). \ - This port will expire on $(date --date="$expires_at") - - # sleep 15 minutes - sleep 900 -done +PIA_TOKEN=$WG_TOKEN \ + PF_GATEWAY="$(echo "$wireguard_json" | jq -r '.server_vip')" \ + PF_HOSTNAME="$WG_HOSTNAME" \ + ./port_forwarding.sh diff --git a/get_region_and_token.sh b/get_region_and_token.sh index 129da66..9822275 100755 --- a/get_region_and_token.sh +++ b/get_region_and_token.sh @@ -136,16 +136,16 @@ token="$(echo "$generateTokenResponse" | jq -r '.token')" echo "This token will expire in 24 hours. " -if [ "$WG_AUTOCONNECT" != true ]; then +if [ "$PIA_AUTOCONNECT" != wireguard ]; then echo If you wish to automatically connect to WireGuard after detecting the best - echo region, please run the script with the env var WG_AUTOCONNECT=true. You can + echo region, please run the script with the env var PIA_AUTOCONNECT=wireguard. You can echo also specify the env var PIA_PF=true to get port forwarding. Example: echo $ PIA_USER=p0123456 PIA_PASS=xxx \ - WG_AUTOCONNECT=true PIA_PF=true ./sort_regions_by_latency.sh + PIA_AUTOCONNECT=true PIA_PF=true ./sort_regions_by_latency.sh echo - echo You can connect by running: + echo You can also connect manually by running: echo WG_TOKEN=\"$token\" WG_SERVER_IP=$bestServer_WG_IP \ - WG_HOSTNAME=$bestServer_WG_hostname ./wireguard_and_pf.sh + WG_HOSTNAME=$bestServer_WG_hostname ./connect_to_wireguard_with_token.sh exit fi @@ -153,7 +153,7 @@ if [ "$PIA_PF" != true ]; then PIA_PF="false" fi -echo "The ./get_region_and_token.sh script got started with WG_AUTOCONNECT=true, +echo "The ./get_region_and_token.sh script got started with PIA_AUTOCONNECT=wireguard, so we will automatically connect to WireGuard, by running this command: $ WG_TOKEN=\"$token\" \\ WG_SERVER_IP=$bestServer_WG_IP WG_HOSTNAME=$bestServer_WG_hostname \\ @@ -161,4 +161,4 @@ $ WG_TOKEN=\"$token\" \\ " PIA_PF=$PIA_PF WG_TOKEN="$token" WG_SERVER_IP=$bestServer_WG_IP \ - WG_HOSTNAME=$bestServer_WG_hostname ./wireguard_and_pf.sh + WG_HOSTNAME=$bestServer_WG_hostname ./connect_to_wireguard_with_token.sh diff --git a/port_forwarding.sh b/port_forwarding.sh new file mode 100755 index 0000000..2e90b3e --- /dev/null +++ b/port_forwarding.sh @@ -0,0 +1,125 @@ +#!/bin/bash +# Copyright (C) 2020 Private Internet Access, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +# Check if the mandatory environment variables are set. +if [[ ! $PF_GATEWAY || ! $PIA_TOKEN ]]; then + echo This script requires 2 env vars: + echo PF_GATEWAY - the IP of your gateway + echo PF_HOSTNAME - name of the host used for SSL/TLS certificate verification + echo PIA_TOKEN - the token you use to connect to the vpn services + echo + echo An easy solution is to just run get_region_and_token.sh + echo as it will guide you through getting the best server and + echo also a token. Detailed information can be found here: + echo https://github.com/pia-foss/manual-connections +exit 1 +fi + +# The port forwarding system has required two variables: +# PAYLOAD: contains the token, the port and the expiration date +# SIGNATURE: certifies the payload originates from the PIA network. + +# Basically PAYLOAD+SIGNATURE=PORT. You can use the same PORT on all servers. +# The system has been designed to be completely decentralized, so that your +# privacy is protected even if you want to host services on your systems. + +# You can get your PAYLOAD+SIGNATURE with a simple curl request to any VPN +# gateway, no matter what protocol you are using. Considering WireGuard has +# already been automated in this repo, here is a command to help you get +# your gateway if you have an active OpenVPN connection: +# $ ip route | head -1 | grep tun | awk '{ print $3 }' +# This section will get updated as soon as we created the OpenVPN script. + +# Get the payload and the signature from the PF API. This will grant you +# access to a random port, which you can activate on any server you connect to. +# If you already have a signature, and you would like to re-use that port, +# save the payload_and_signature received from your previous request +# in the env var PAYLOAD_AND_SIGNATURE, and that will be used instead. +if [[ ! $PAYLOAD_AND_SIGNATURE ]]; then + echo "Getting new signature..." + payload_and_signature="$(curl -s -m 5 \ + --connect-to "$PF_HOSTNAME::$PF_GATEWAY:" \ + --cacert "ca.rsa.4096.crt" \ + -G --data-urlencode "token=${WG_TOKEN}" \ + "https://${PF_HOSTNAME}:19999/getSignature")" +else + payload_and_signature="$PAYLOAD_AND_SIGNATURE" + echo "Using the following payload_and_signature from the env var:" +fi +echo "$payload_and_signature" +export payload_and_signature + +# Check if the payload and the signature are OK. +# If they are not OK, just stop the script. +if [ "$(echo "$payload_and_signature" | jq -r '.status')" != "OK" ]; then + echo "The payload_and_signature variable does not contain an OK status." + exit 1 +fi + +# We need to get the signature out of the previous response. +# The signature will allow the us to bind the port on the server. +signature="$(echo "$payload_and_signature" | jq -r '.signature')" + +# The payload has a base64 format. We need to extract it from the +# previous reponse and also get the following information out: +# - port: This is the port you got access to +# - expires_at: this is the date+time when the port expires +payload="$(echo "$payload_and_signature" | jq -r '.payload')" +port="$(echo "$payload" | base64 -d | jq -r '.port')" + +# The port normally expires after 2 months. If you consider +# 2 months is not enough for your setup, please open a ticket. +expires_at="$(echo "$payload" | base64 -d | jq -r '.expires_at')" + +# Display some information on the screen for the user. +echo "The signature is OK. + +--> The port is $port and it will expire on $expires_at. <-- + +Trying to bind the port..." + +# Now we have all required data to create a request to bind the port. +# We will repeat this request every 15 minutes, in order to keep the port +# alive. The servers have no mechanism to track your activity, so they +# will just delete the port forwarding if you don't send keepalives. +while true; do + bind_port_response="$(curl -Gs -m 5 \ + --connect-to "$PF_HOSTNAME::$PF_GATEWAY:" \ + --cacert "ca.rsa.4096.crt" \ + --data-urlencode "payload=${payload}" \ + --data-urlencode "signature=${signature}" \ + "https://${PF_HOSTNAME}:19999/bindPort")" + echo "$bind_port_response" + + # If port did not bind, just exit the script. + # This script will exit in 2 months, since the port will expire. + export bind_port_response + if [ "$(echo "$bind_port_response" | jq -r '.status')" != "OK" ]; then + echo "The API did not return OK when trying to bind port. Exiting." + exit 1 + fi + echo Port $port refreshed on $(date). \ + This port will expire on $(date --date="$expires_at") + + # sleep 15 minutes + sleep 900 +done