2020-09-18 17:52:20 +00:00
|
|
|
#!/bin/bash
|
2020-09-18 20:24:40 +00:00
|
|
|
# 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.
|
|
|
|
|
2020-09-22 21:32:44 +00:00
|
|
|
# This function allows you to check if the required tools have been installed.
|
|
|
|
function check_tool() {
|
|
|
|
cmd=$1
|
|
|
|
package=$2
|
|
|
|
if ! command -v $cmd &>/dev/null
|
|
|
|
then
|
|
|
|
echo "$cmd could not be found"
|
|
|
|
echo "Please install $package"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
}
|
2020-09-22 21:34:02 +00:00
|
|
|
# Now we call the function to make sure we can use curl and jq.
|
2020-09-22 21:32:44 +00:00
|
|
|
check_tool curl curl
|
|
|
|
check_tool jq jq
|
2020-09-18 20:24:40 +00:00
|
|
|
|
2020-09-22 21:32:44 +00:00
|
|
|
# This allows you to set the maximum allowed latency in seconds.
|
|
|
|
# All servers that repond slower than this will be ignored.
|
|
|
|
# You can inject this with the environment variable MAX_LATENCY.
|
2020-09-22 21:17:46 +00:00
|
|
|
# The default value is 50 milliseconds.
|
|
|
|
MAX_LATENCY=${MAX_LATENCY:-0.05}
|
|
|
|
export MAX_LATENCY
|
2020-09-18 17:52:20 +00:00
|
|
|
|
|
|
|
serverlist_url='https://serverlist.piaservers.net/vpninfo/servers/v4'
|
|
|
|
|
|
|
|
# This function checks the latency you have to a specific region.
|
|
|
|
# It will print a human-readable message to stderr,
|
|
|
|
# and it will print the variables to stdout
|
|
|
|
printServerLatency() {
|
|
|
|
serverIP="$1"
|
|
|
|
regionID="$2"
|
2020-09-18 19:25:39 +00:00
|
|
|
regionName="$(echo ${@:3} |
|
|
|
|
sed 's/ false//' | sed 's/true/(geo)/')"
|
2020-09-18 17:52:20 +00:00
|
|
|
time=$(curl -o /dev/null -s \
|
2020-09-22 21:17:46 +00:00
|
|
|
--connect-timeout $MAX_LATENCY \
|
2020-09-18 17:52:20 +00:00
|
|
|
--write-out "%{time_connect}" \
|
|
|
|
http://$serverIP:443)
|
|
|
|
if [ $? -eq 0 ]; then
|
2020-09-18 19:25:39 +00:00
|
|
|
>&2 echo Got latency ${time}s for region: $regionName
|
2020-09-18 17:52:20 +00:00
|
|
|
echo $time $regionID $serverIP
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
export -f printServerLatency
|
|
|
|
|
|
|
|
echo -n "Getting the server list... "
|
|
|
|
# Get all region data since we will need this on multiple ocasions
|
|
|
|
all_region_data=$(curl -s "$serverlist_url" | head -1)
|
|
|
|
|
|
|
|
# If the server list has less than 1000 characters, it means curl failed.
|
|
|
|
if [[ ${#all_region_data} < 1000 ]]; then
|
|
|
|
echo "Could not get correct region data. To debug this, run:"
|
|
|
|
echo "$ curl -v $serverlist_url"
|
|
|
|
echo "If it works, you will get a huge JSON as a response."
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
# Notify the user that we got the server list.
|
|
|
|
echo "OK!"
|
|
|
|
|
2020-09-24 19:54:19 +00:00
|
|
|
# Test one server from each region to get the closest region
|
|
|
|
# Only filter port forwarding enabled servers if specified
|
|
|
|
if [[ $PIA_PF == "true" ]]; then
|
|
|
|
echo Port Forwarding is enabled, so regions that do not support
|
|
|
|
echo port forwarding will get filtered out.
|
|
|
|
summarized_region_data="$( echo $all_region_data |
|
|
|
|
jq -r '.regions[] | select(.port_forward==true) |
|
|
|
|
.servers.meta[0].ip+" "+.id+" "+.name+" "+(.geo|tostring)' )"
|
|
|
|
else
|
|
|
|
summarized_region_data="$( echo $all_region_data |
|
|
|
|
jq -r '.regions[] |
|
|
|
|
.servers.meta[0].ip+" "+.id+" "+.name+" "+(.geo|tostring)' )"
|
|
|
|
fi
|
2020-09-18 19:25:39 +00:00
|
|
|
echo Testing regions that respond \
|
2020-09-22 21:17:46 +00:00
|
|
|
faster than $MAX_LATENCY seconds:
|
2020-09-19 22:39:14 +00:00
|
|
|
bestRegion="$(echo "$summarized_region_data" |
|
2020-09-18 17:52:20 +00:00
|
|
|
xargs -i bash -c 'printServerLatency {}' |
|
|
|
|
sort | head -1 | awk '{ print $2 }')"
|
|
|
|
|
|
|
|
# Get all data for the best region
|
|
|
|
regionData="$( echo $all_region_data |
|
|
|
|
jq --arg REGION_ID "$bestRegion" -r \
|
|
|
|
'.regions[] | select(.id==$REGION_ID)')"
|
|
|
|
|
2020-09-18 19:25:39 +00:00
|
|
|
echo -n The closest region is "$(echo $regionData | jq -r '.name')"
|
|
|
|
if echo $regionData | jq -r '.geo' | grep true > /dev/null; then
|
|
|
|
echo " (geolocated region)."
|
|
|
|
else
|
|
|
|
echo "."
|
|
|
|
fi
|
2020-09-18 17:52:20 +00:00
|
|
|
echo
|
|
|
|
bestServer_meta_IP="$(echo $regionData | jq -r '.servers.meta[0].ip')"
|
|
|
|
bestServer_meta_hostname="$(echo $regionData | jq -r '.servers.meta[0].cn')"
|
|
|
|
bestServer_WG_IP="$(echo $regionData | jq -r '.servers.wg[0].ip')"
|
|
|
|
bestServer_WG_hostname="$(echo $regionData | jq -r '.servers.wg[0].cn')"
|
|
|
|
bestServer_OT_IP="$(echo $regionData | jq -r '.servers.ovpntcp[0].ip')"
|
|
|
|
bestServer_OT_hostname="$(echo $regionData | jq -r '.servers.ovpntcp[0].cn')"
|
|
|
|
bestServer_OU_IP="$(echo $regionData | jq -r '.servers.ovpnudp[0].ip')"
|
|
|
|
bestServer_OU_hostname="$(echo $regionData | jq -r '.servers.ovpnudp[0].cn')"
|
|
|
|
|
2020-09-18 18:44:40 +00:00
|
|
|
echo "The script found the best servers from the region closest to you.
|
2020-09-18 17:52:20 +00:00
|
|
|
When connecting to an IP (no matter which protocol), please verify
|
|
|
|
the SSL/TLS certificate actually contains the hostname so that you
|
|
|
|
are sure you are connecting to a secure server, validated by the
|
|
|
|
PIA authority. Please find bellow the list of best IPs and matching
|
|
|
|
hostnames for each protocol:
|
|
|
|
Meta Services: $bestServer_meta_IP // $bestServer_meta_hostname
|
|
|
|
WireGuard: $bestServer_WG_IP // $bestServer_WG_hostname
|
|
|
|
OpenVPN TCP: $bestServer_OT_IP // $bestServer_OT_hostname
|
|
|
|
OpenVPN UDP: $bestServer_OU_IP // $bestServer_OU_hostname
|
|
|
|
"
|
|
|
|
|
|
|
|
if [[ ! $PIA_USER || ! $PIA_PASS ]]; then
|
|
|
|
echo If you want this script to automatically get a token from the Meta
|
|
|
|
echo service, please add the variables PIA_USER and PIA_PASS. Example:
|
|
|
|
echo $ PIA_USER=p0123456 PIA_PASS=xxx ./get_region_and_token.sh
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
echo "The ./get_region_and_token.sh script got started with PIA_USER and PIA_PASS,
|
|
|
|
so we will also use a meta service to get a new VPN token."
|
|
|
|
|
|
|
|
echo "Trying to get a new token by authenticating with the meta service..."
|
|
|
|
generateTokenResponse=$(curl -s -u "$PIA_USER:$PIA_PASS" \
|
|
|
|
--connect-to "$bestServer_meta_hostname::$bestServer_meta_IP:" \
|
|
|
|
--cacert "ca.rsa.4096.crt" \
|
|
|
|
"https://$bestServer_meta_hostname/authv3/generateToken")
|
|
|
|
echo "$generateTokenResponse"
|
|
|
|
|
|
|
|
if [ "$(echo "$generateTokenResponse" | jq -r '.status')" != "OK" ]; then
|
|
|
|
echo "Could not get a token. Please check your account credentials."
|
|
|
|
echo "You can also try debugging by manually running the curl command:"
|
|
|
|
echo $ curl -vs -u "$PIA_USER:$PIA_PASS" --cacert ca.rsa.4096.crt \
|
|
|
|
--connect-to "$bestServer_meta_hostname::$bestServer_meta_IP:" \
|
|
|
|
https://$bestServer_meta_hostname/authv3/generateToken
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
token="$(echo "$generateTokenResponse" | jq -r '.token')"
|
|
|
|
echo "This token will expire in 24 hours.
|
|
|
|
"
|
|
|
|
|
2020-09-18 21:08:43 +00:00
|
|
|
if [ "$PIA_AUTOCONNECT" != wireguard ]; then
|
2020-09-18 17:52:20 +00:00
|
|
|
echo If you wish to automatically connect to WireGuard after detecting the best
|
2020-09-18 21:08:43 +00:00
|
|
|
echo region, please run the script with the env var PIA_AUTOCONNECT=wireguard. You can
|
2020-09-18 17:52:20 +00:00
|
|
|
echo also specify the env var PIA_PF=true to get port forwarding. Example:
|
|
|
|
echo $ PIA_USER=p0123456 PIA_PASS=xxx \
|
2020-09-18 21:08:43 +00:00
|
|
|
PIA_AUTOCONNECT=true PIA_PF=true ./sort_regions_by_latency.sh
|
2020-09-18 17:52:20 +00:00
|
|
|
echo
|
2020-09-19 22:39:14 +00:00
|
|
|
echo You can also connect now by running this command:
|
|
|
|
echo $ WG_TOKEN=\"$token\" WG_SERVER_IP=$bestServer_WG_IP \
|
2020-09-18 21:08:43 +00:00
|
|
|
WG_HOSTNAME=$bestServer_WG_hostname ./connect_to_wireguard_with_token.sh
|
2020-09-18 17:52:20 +00:00
|
|
|
exit
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [ "$PIA_PF" != true ]; then
|
|
|
|
PIA_PF="false"
|
|
|
|
fi
|
|
|
|
|
2020-09-18 21:08:43 +00:00
|
|
|
echo "The ./get_region_and_token.sh script got started with PIA_AUTOCONNECT=wireguard,
|
2020-09-18 17:52:20 +00:00
|
|
|
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 \\
|
2020-09-18 21:35:47 +00:00
|
|
|
PIA_PF=$PIA_PF ./connect_to_wireguard_with_token.sh
|
2020-09-18 17:52:20 +00:00
|
|
|
"
|
|
|
|
|
|
|
|
PIA_PF=$PIA_PF WG_TOKEN="$token" WG_SERVER_IP=$bestServer_WG_IP \
|
2020-09-18 21:08:43 +00:00
|
|
|
WG_HOSTNAME=$bestServer_WG_hostname ./connect_to_wireguard_with_token.sh
|