#!/bin/sh # Requests a forwarded port from PIA, keeps it bound and points deluge's # listen port at it. PIA only forwards ports on non-US regions. VPN_DEV="${VPN_DEV:-tun0}" TOKEN_URL="https://www.privateinternetaccess.com/api/client/v2/token" BIND_INTERVAL=900 log() { echo "pia-port-forward: $*" } # PIA_USER/PIA_PASS win; otherwise reuse the auth-user-pass file from the VPN config load_credentials() { if [ -n "${PIA_USER:-}" ] && [ -n "${PIA_PASS:-}" ]; then return 0 fi auth_file=$(awk '$1 == "auth-user-pass" { print $2; exit }' /vpn/vpn 2>/dev/null) if [ -z "$auth_file" ]; then log "set PIA_USER and PIA_PASS, or use auth-user-pass in the VPN config" return 1 fi case "$auth_file" in /*) ;; *) auth_file="/vpn/$auth_file" ;; esac PIA_USER=$(sed -n 1p "$auth_file" | tr -d '\r') PIA_PASS=$(sed -n 2p "$auth_file" | tr -d '\r') if [ -z "$PIA_USER" ] || [ -z "$PIA_PASS" ]; then log "could not read credentials from $auth_file" return 1 fi } wait_for_tunnel() { until ip -4 addr show dev "$VPN_DEV" 2>/dev/null | grep -q inet; do sleep 2 done } # The port forwarding API listens on the VPN gateway that redirect-gateway routes through vpn_gateway() { ip -4 route show dev "$VPN_DEV" | awk ' $1 == "0.0.0.0/1" && $2 == "via" { print $3; found = 1; exit } $2 == "via" && !first { first = $3 } END { if (!found && first) print first }' } get_token() { printf '%s' "$PIA_PASS" | curl -s -m 15 -X POST "$TOKEN_URL" \ --form "username=$PIA_USER" \ --form "password=<-" | jq -r '.token // empty' } # -k: the API is only reachable inside the tunnel and its certificate is issued # for the server's hostname, which we don't know here pf_api() { endpoint=$1 shift curl -sk -m 15 -G "$@" "https://$gateway:19999/$endpoint" } set_deluge_port() { log "setting deluge listen port to $1" until su deluge -c "deluge-console -c /config 'connect 127.0.0.1:$PORT; config --set listen_ports ($1, $1)'" 2>&1 | grep -q "Configuration value successfully updated"; do sleep 5 done } load_credentials || exit 1 while true; do wait_for_tunnel gateway=$(vpn_gateway) if [ -z "$gateway" ]; then log "no gateway found on $VPN_DEV" sleep 30 continue fi token=$(get_token) if [ -z "$token" ]; then log "failed to get a PIA token, check the username and password" sleep 60 continue fi response=$(pf_api getSignature --data-urlencode "token=$token") if [ "$(echo "$response" | jq -r '.status // empty' 2>/dev/null)" != "OK" ]; then log "getSignature failed (does this region support port forwarding?): $response" sleep 300 continue fi payload=$(echo "$response" | jq -r .payload) signature=$(echo "$response" | jq -r .signature) port=$(echo "$payload" | base64 -d | jq -r .port) log "PIA assigned port $port" deluge_port_set=false while [ "$(pf_api bindPort --data-urlencode "payload=$payload" --data-urlencode "signature=$signature" | jq -r '.status // empty' 2>/dev/null)" = "OK" ]; do if [ "$deluge_port_set" = false ]; then set_deluge_port "$port" deluge_port_set=true fi sleep "$BIND_INTERVAL" done log "bindPort failed, requesting a new port" sleep 10 done