Sfoglia il codice sorgente

Request port forward

Spencer Gardner 1 settimana fa
parent
commit
0b067462a5
3 ha cambiato i file con 129 aggiunte e 2 eliminazioni
  1. 2 2
      Dockerfile
  2. 10 0
      deluged_init.sh
  3. 117 0
      pia_port_forward.sh

+ 2 - 2
Dockerfile

@@ -30,7 +30,7 @@ RUN apt-get update && \
     apt-get install -y --no-install-recommends software-properties-common gpg-agent && \
     add-apt-repository ppa:deluge-team/stable -y && \
     apt-get update && \
-    apt-get install -y --no-install-recommends deluged && \
+    apt-get install -y --no-install-recommends deluged deluge-console curl jq && \
     apt-get purge -y --auto-remove software-properties-common gpg-agent && \
     rm -rf /var/lib/apt/lists/*
 
@@ -39,6 +39,6 @@ COPY --from=webapi-build /src/dist/WebAPI-*.egg /config/plugins/
 RUN useradd -ms /bin/bash deluge && \
     chown -R deluge:deluge /config
 
-COPY deluged_init.sh /sbin/deluged_init.sh
+COPY deluged_init.sh pia_port_forward.sh /sbin/
 
 CMD ["/sbin/deluged_init.sh"]

+ 10 - 0
deluged_init.sh

@@ -5,5 +5,15 @@
 # /config is usually a mounted volume; make sure the deluge user can write to it
 chown -R deluge:deluge /config
 
+# Starting before the tunnel is up makes the first announces and DHT bootstrap fail
+echo "waiting for ${VPN_DEV:-tun0}"
+until ip -4 addr show dev "${VPN_DEV:-tun0}" 2>/dev/null | grep -q inet; do
+    sleep 1
+done
+
+if [ "${PIA_PORT_FORWARD:-true}" = "true" ]; then
+    /sbin/pia_port_forward.sh &
+fi
+
 echo starting deluge on port $PORT
 su deluge bash -c "deluged -c /config -d -p $PORT -u 0.0.0.0"

+ 117 - 0
pia_port_forward.sh

@@ -0,0 +1,117 @@
+#!/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