| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
- #!/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 <file> 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
|