Skip to content

Commit

Permalink
Merge pull request #110 from thrnz/meta-override
Browse files Browse the repository at this point in the history
Add optional env vars for using 'meta' servers for initial PIA API requests
  • Loading branch information
thrnz authored Jun 19, 2024
2 parents 30fb739 + b8e31e4 commit fe1e19c
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 31 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ The rest are optional:
|```FWD_IFACE``` ```PF_DEST_IP```|If needed, the container can be used as a gateway for other containers or devices by setting these. See [issue #20](https://github.com/thrnz/docker-wireguard-pia/issues/20) for more info. Note that these are for a specific use case, and in many cases using Docker's ```--net=container:xyz``` or docker-compose's ```network_mode: service:xyz``` instead, and leaving these vars unset, would be an easier way of accessing the VPN and forwarded port from other containers.
|`PRE_UP` `POST_UP` `PRE_DOWN` `POST_DOWN`|Custom commands and/or scripts can be run at certain stages if needed. See [below](#scripting) for more info.
|`PIA_DIP_TOKEN`|A dedicated ip token can be used by setting this. When set, `LOC` is not used.
|`META_IP=x.x.x.x` `META_CN=hostname401` `META_PORT=443`|On startup, the container needs untunnelled access to PIA's API in order to download the server list and to generate a persistent auth token if needed. Optionally, PIA's 'meta' servers (found in PIA's [server list](https://serverlist.piaservers.net/vpninfo/servers/v6)) can be used instead of the default API endpoints by setting `META_IP` and `META_CN`. These can be set to a different location than `LOC`. `META_PORT` is optional and defaults to 443, although 8080 also appears to be available. See [issue #109](https://github.com/thrnz/docker-wireguard-pia/issues/109) for more info.

## Scripting
Custom commands and/or scripts can be run at certain stages of the container's life-cycle by setting the `PRE_UP`, `POST_UP`, `PRE_DOWN`, and `POST_DOWN` env vars. `PRE_UP` is run prior to generating the WireGuard config, `POST_UP` is run after the WireGuard interface is brought up, and `PRE_DOWN` and `POST_DOWN` are run before and after the interface is brought down again when the container exits.
Expand Down
64 changes: 49 additions & 15 deletions extra/pia-auth.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,17 @@
# Options:
# -u <username>
# -p <password>
# -i <meta server ip> (Optional)
# -o <meta server port> (Optional)
# -n <meta server cn> (Optional)
# -c <cacert path> (Optional) Path to ca cert used to secure communication with "meta" servers
#
# Example:
# pia-auth.sh -u myusername -p mypassword > ~/.pia-token
# Examples:
# ./pia-auth.sh -u myusername -p mypassword > ~/.pia-token
# ./pia-auth.sh -u myusername -p mypassword -i 12.34.56.78 -n location401 -p 443 -c /path/to/ca.crt > ~/.pia-token
#
# By default, the www.privateinternetaccess.com API endpoint is used.
# If needed, 'meta' services on the VPN servers themselves can be used instead.
#
# deauth using:
# curl --silent --show-error --request POST \
Expand All @@ -20,36 +28,62 @@

[ -n "$DEBUG" ] && set -o xtrace

while getopts ":u:p:" args; do
while getopts ":u:p:i:c:o:n:" args; do
case ${args} in
u)
user=$OPTARG
user="$OPTARG"
;;
p)
pass=$OPTARG
pass="$OPTARG"
;;
i)
meta_ip="$OPTARG"
;;
c)
cacert="$OPTARG"
;;
o)
meta_port="$OPTARG"
;;
n)
meta_cn="$OPTARG"
;;
esac
done

usage() {
echo "Options:"
echo " -u <username>"
echo " -p <password>"
echo 'Options:
-u <username>
-p <password>
-i <meta-server ip> (Optional)
-o <meta-server port> (Optional)
-n <meta-server cn> (Optional)
-c <cacert path> (Optional) Path to ca cert used to secure communication with "meta" servers'
exit 1
}

get_auth_token () {
if [ -n "$meta_port" ] && [ -n "$meta_ip" ] && [ -n "$meta_cn" ] && [ -n "$cacert" ]; then
# https://github.com/pia-foss/desktop/blob/master/daemon/src/metaserviceapibase.h
token_response=$(curl --silent --location --show-error --request POST --max-time "$curl_max_time" \
--resolve "$meta_cn:$meta_port:$meta_ip" \
--form "username=$user" \
--form "password=$pass" \
--cacert "$cacert" \
"https://$meta_cn:$meta_port/api/client/v2/token")
else
token_response=$(curl --silent --location --show-error --request POST --max-time "$curl_max_time" \
'https://www.privateinternetaccess.com/api/client/v2/token' \
--form "username=$user" \
--form "password=$pass")
TOK=$(jq -r .'token' <<< "$token_response")
if [ -z "$TOK" ]; then
echo "Failed to acquire new auth token. Response:" >&2
echo "$token_response" >&2
exit 1
fi
echo "$TOK"
fi
TOK=$(jq -r .'token' <<< "$token_response")
if [ -z "$TOK" ]; then
echo "Failed to acquire new auth token. Response:" >&2
echo "$token_response" >&2
exit 1
fi
echo "$TOK"
}

if [ -z "$pass" ] || [ -z "$user" ]; then
Expand Down
47 changes: 35 additions & 12 deletions extra/wg-gen.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@
# To use a dedicated ip, the PIA_DIP_TOKEN env var must be set
# eg: $ PIA_DIP_TOKEN=DIPabc123 wg-gen.sh -t ~/.token -o ~/wg.conf
#
# API requests can be sent via PIA's 'meta' servers by setting the META_IP META_CN and META_PORT env vars
# eg: $ META_IP=123.45.67.89 META_CN=hostname401 META_PORT=443 ./wg-gen.sh -t ~/.token ~/wg.conf
#
# Available servers can be found here:
# https://serverlist.piaservers.net/vpninfo/servers/v4
# https://serverlist.piaservers.net/vpninfo/servers/v6
# The public key for verifying the server list can be found here:
# https://github.com/pia-foss/desktop/blob/122710c6ada5db83620c63faff2d805ea52d7f40/daemon/src/environment.cpp#L30
# The PIA ca cert can be found here:
Expand All @@ -43,6 +46,8 @@
# 3: Invalid server location
# 4: Registration failed

[ -n "$DEBUG" ] && set -o xtrace

fatal_error () {
cleanup
[ -n "$1" ] && exit "$1"
Expand Down Expand Up @@ -115,14 +120,26 @@ verify_serverlist ()

get_dip_serverinfo ()
{
echo "$(date): Fetching dedicated ip server info"
dip_response=$(curl --silent --show-error $curl_params --location --request POST \
'https://www.privateinternetaccess.com/api/client/v2/dedicated_ip' \
--header 'Content-Type: application/json' \
--header "Authorization: Token $(cat $tokenfile)" \
--data-raw '{
"tokens":["'"$PIA_DIP_TOKEN"'"]
}')
if [ -n "$META_IP" ] && [ -n "$META_CN" ] && [ -n "$META_PORT" ]; then
echo "$(date): Fetching dedicated ip server info via meta server: ip: $META_IP, cn: $META_CN, port: $META_PORT"
dip_response=$(curl --silent --show-error $curl_params --location --request POST \
"https://$META_CN:$META_PORT/api/client/v2/dedicated_ip" \
--header 'Content-Type: application/json' \
--header "Authorization: Token $(cat $tokenfile)" \
--cacert "$pia_cacert" --resolve "$META_CN:$META_PORT:$META_IP" \
--data-raw '{
"tokens":["'"$PIA_DIP_TOKEN"'"]
}')
else
echo "$(date): Fetching dedicated ip server info"
dip_response=$(curl --silent --show-error $curl_params --location --request POST \
'https://www.privateinternetaccess.com/api/client/v2/dedicated_ip' \
--header 'Content-Type: application/json' \
--header "Authorization: Token $(cat $tokenfile)" \
--data-raw '{
"tokens":["'"$PIA_DIP_TOKEN"'"]
}')
fi

[ "$dip_response" == "HTTP Token: Access denied." ] && echo "Auth failed" && fatal_error 2

Expand All @@ -143,9 +160,15 @@ get_dip_serverinfo ()
}

get_servers() {
echo "Fetching next-gen PIA server list"
curl --silent --show-error $curl_params \
"https://serverlist.piaservers.net/vpninfo/servers/v6" > "$servers_raw"
if [ -n "$META_IP" ] && [ -n "$META_CN" ] && [ -n "$META_PORT" ]; then
echo "Fetching next-gen PIA server list via meta server: ip: $META_IP, cn: $META_CN, port: $META_PORT"
curl --silent --show-error $curl_params --cacert "$pia_cacert" --resolve "$META_CN:$META_PORT:$META_IP" \
"https://$META_CN:$META_PORT/vpninfo/servers/v6" > "$servers_raw"
else
echo "Fetching next-gen PIA server list"
curl --silent --show-error $curl_params \
"https://serverlist.piaservers.net/vpninfo/servers/v6" > "$servers_raw"
fi
head -n 1 "$servers_raw" | tr -d '\n' > "$servers_json"
tail -n +3 "$servers_raw" | base64 -d > "$servers_sig"
[ -n "$pia_pubkey" ] && verify_serverlist
Expand Down
13 changes: 9 additions & 4 deletions run
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
[[ "$PORT_FATAL" =~ ^[0-1]$ ]] || PORT_FATAL=0
# Should be a positive integer
[[ "$KEEPALIVE" =~ ^[0-9]+$ ]] || KEEPALIVE=0
[[ "$META_PORT" =~ ^[0-9]+$ ]] || export META_PORT=443
# Maybe also check the following. They are all blank by default.
# LOCAL_NETWORK=
# PIA_CN=
Expand Down Expand Up @@ -56,12 +57,15 @@ firewall_init () {
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# Temporarily allow DNS queries
# We also need to temporarily allow the following:
# DNS queries
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT

# We also need to temporarily allow the following
# HTTPS to download the server list and access API for generating auth token
iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT
# API access to register the public WireGuard key
iptables -A OUTPUT -p tcp --dport 1337 -j ACCEPT
# Non-default API port if set
[ "$META_PORT" -ne 443 ] && iptables -A OUTPUT -p tcp --dport "$META_PORT" -j ACCEPT
}

# Alpine 3.19 changed the default iptables backend to iptables-nft
Expand Down Expand Up @@ -137,7 +141,7 @@ get_auth_token () {
[ -z "$USER" ] && echo "$(date): PIA username not set. Unable to retrieve new auth token." && fatal_error
echo "$(date): Generating auth token"
local token
if ! token=$(/scripts/pia-auth.sh -u "$USER" -p "$PASS"); then
if ! token=$(/scripts/pia-auth.sh -u "$USER" -p "$PASS" -n "$META_CN" -i "$META_IP" -o "$META_PORT" -c "$pia_cacrt"); then
echo "$(date): Failed to acquire new auth token" && fatal_error
fi
echo "$token" > "$tokenfile"
Expand Down Expand Up @@ -226,6 +230,7 @@ if [ $FIREWALL -eq 1 ]; then
iptables -D OUTPUT -p udp --dport 53 -j ACCEPT
iptables -D OUTPUT -p tcp --dport 443 -j ACCEPT
iptables -D OUTPUT -p tcp --dport 1337 -j ACCEPT
[ "$META_PORT" -ne 443 ] && iptables -D OUTPUT -p tcp --dport "$META_PORT" -j ACCEPT

# Allow docker network input/output
for iface in /sys/class/net/*; do
Expand Down

0 comments on commit fe1e19c

Please sign in to comment.