PIA automatic port-forward update for Transmission daemon
-
Hi!
This guide explains how to remotely update port number in Transmission daemon if PIA VPN restarts with new assigned forwarding port.
I know that there is already a similar thread but it is quite old with several updates and variants of the solution. So i am sharing mine which takes slightly different approach. Yet main credits goes to original script author which i used as starting point.
#Key points:
-Working with pfSense 2.4.4-RELEASE-p3 + Transmission-daemon 2.94_3
-Automatic NAT rule update upon PIA forward port change
-Immediate port update of Transmission daemon without restart
-pfSense updates the port remotely instead of transmission "fetching" it. No CRON job needed, no delay.
-Key-based SSH connections.#Future ideas:
-Email notifications in case of failure
-Force-restart OpenVPN in case the the port gets closed from PIA side unnoticed (i never had such issue but few people faced such behavior)Hope this helps ... so here we go :]
You need to have PIA VPN already configured. Use for example this guide
I. pfSense side
1.Enable SSH on pfSense
System -> Advanced => tick "Enable Secure Shell"
2.Create custom user
Go to System -> User manager -> Add
-Fill Username, password
-Add "admins" group
-Grant "WebCfg - All pages" and "User - System: Shell account access" priviledges
-(Optional) generate SSH keys for your custom user
3.Install SUDO package
-Go to System -> Package Manager => install SUDO package
-Go to System -> sudo => create user permissions as bellow
4.Create Alias for port forward
-Go to Firewall -> Aliases -> Ports
-Create new port with name "Trans_Port"
-Give it the current port (if you have it) or non-zero value
5.Create Alias for Transmission IP address
-Go to Firewall -> Aliases -> IP
-Create new port with name "Trans_IP"
-Define IP or FQDN of your Transmisson daemon server
6.Create NAT rule for port-forward using the ALIAS instead of specific port/IP
-Go to Firewall -> NAT
-Create new rule like bellow (blue values could be different depending on your current VPN configuration)
7.Generate SSH keys for enhanced security
-SSH to the pfSense box with the user created in step 2.sudo su - #<enter your user password> #Enter an option: 8 for shell mkdir .ssh chmod 700 .ssh cd .ssh ssh-keygen -b 4096 -f ~/.ssh/id_rsa #When prompted for "Enter passphrase" just hit ENTER twice #Files id_rsa and id_rsa.pub will be generated. cat id_rsa.pub #Store the content of the file somewhere as it will be required later on
8.Create custom devd config file
-Still under root user from previous step domkdir /usr/local/etc/devd cd /usr/local/etc/devd vi piaport.conf
-paste following code and save ( :wq )
notify 0 { match "system" "IFNET"; match "subsystem" "(ovpnc1)"; match "type" "LINK_UP"; action "logger $subsystem is UP"; action "/home/custom/piaportforward/piaportfwd.sh"; }; notify 0 { match "system" "IFNET"; match "subsystem" "(ovpnc1)"; match "type" "LINK_DOWN"; action "logger $subsystem is DOWN"; };
Note: The "ovpnc1" is a technical name of the OpenVPN interface from within the pfSense UI
9.Create the custom port-update script
-Still under root user from previous step domkdir /home/custom mkdir /home/custom/piaportforward cd /home/custom/piaportforward touch piaportfwd.sh chmod u+x piaportfwd.sh vi piaportfwd.sh
-Paste the code bellow OR just unzip/upload the file [ piaportfwd.zip ] and chmod +x it.
-No customization is necessary. Everything is fetched from config file.#!/bin/sh export PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/root/bin # Vers: 1.2 # Date: 1.2.2020 ############# Update following if necessary ################ # OpenVPN interface name OVPNIFACE='ovpnc1' # Alias name for port forward PORTALIAS='Trans_Port' # Alias name for Transmission IP IPALIAS='Trans_IP' # Email notification # TBD !!! ############## Other vars - do not touch ################### # pfSense config file and tempconfig location CONFFILE='/cf/conf/config.xml' TMPCONFFILE='/tmp/tmpconfig.xml' # Fetch remote Transmission IP from config TRANSIP=`xml sel -t -v "//alias[name=\"$IPALIAS\"]/address" $CONFFILE` ######################## MAIN CODE ######################### # Wait for VPN interface to get fully UP sleep 10 # Get the Unique ID of the client system # More details at: https://www.privateinternetaccess.com/forum/discussion/23431/new-pia-port-forwarding-api PIA_CLIENTID=`head -n 100 /dev/urandom | shasum -a 256 | tr -d " -"` logger "[PIA] Client-ID: $PIA_CLIENTID" # Request port-forward from PIA API PIA_PORT=$(curl --interface $OVPNIFACE "http://209.222.18.222:2000/\?client_id=$PIA_CLIENTID" 2>/dev/null | awk -F ':' '{ print $2 }'| awk -F '}' '{ print $1 }') if [ "$PIA_PORT" == "" ]; then PIA_PORT='0' logger "[PIA] Port forwarding is already activated on this connection, has expired, or you are not connected to a PIA region that supports port forwarding." exit 0 elif ! [ "$PIA_PORT" -eq "$PIA_PORT" ] 2> /dev/null; then logger "[PIA] Fatal error! Value $PIA_PORT is not a number. PIA API has most probably changed. Manual check necessary." # EMAIL exit 1 elif [ "$PIA_PORT" -lt 1024 ] || [ "$PIA_PORT" -gt 65535 ]; then logger "[PIA] Fatal error! Value $PIA_PORT outside allowed port range. PIA API has most probably changed. Manual check necessary." # EMAIL exit 1 fi logger "[PIA] Acquired forwarding port: $PIA_PORT" # Get current NAT port number using xmlstarlet to parse the config file. NATPORT=`xml sel -t -v "//alias[name=\"$PORTALIAS\"]/address" $CONFFILE` logger "[PIA] Current NAT rule port: $NATPORT" # If the acquired port is the same as already configured do not pointlessly reload config. if [ "$NATPORT" -eq "$PIA_PORT" ]; then logger "[PIA] Acquired port $PIA_PORT equals the already configured port $NATPORT - no action required." exit 0 fi # If the port has changed update the tempconfig file. xml ed -u "//alias[name=\"$PORTALIAS\"]/address" -v $PIA_PORT $CONFFILE > $TMPCONFFILE # Validate the XML file just to ensure we don't nuke whole configuration xml val -q $TMPCONFFILE XMLVAL=$? if [ "$XMLVAL" -eq 1 ]; then logger "[PIA] Fatal error! Updated tempconf file $TMPCONFFILE does not have valid XML format. Verify that the port alias is correct in script header and exists in pfSense Alias list" # EMAIL exit 1 fi # If the updated tempconfig is valid backup and replace the real config file. cp $CONFFILE ${CONFFILE}.bck cp $TMPCONFFILE $CONFFILE # Force pfSense to re-read it's config and reload the rules. rm /tmp/config.cache /etc/rc.filter_configure logger "[PIA] New port $PIA_PORT udpated in pfSense config file." # Check if Transmission host is reachable ping -c1 -t1 -q $TRANSIP PINGRC=$? if [ "$PINGRC" -gt 0 ]; then logger "[PIA] Error! Transmission host $TRANSIP is not reachable!" # EMAIL exit 1 fi # Update remote Transmission config with new port ssh transmission@${TRANSIP} "./transportupdate.sh ${PIA_PORT}" TRANSRC=$? if [ "$TRANSRC" -gt 0 ]; then logger "[PIA] Error! Unable to remotely update Transmission port over SSH!" # EMAIL exit 1 fi logger "[PIA] New port successfully updated in remote Transmission system." exit 0
-Disconnect form pfSense
-(Optional) Disable SSH via WebUI under System -> Advanced => un-tick "Enable Secure Shell"II. Transmission host side
-This part is for FreeBSD host systems but it will work just fine for any Linux host.
-If there is something already configured on your side please read the steps anyway just to be sure there are no tiny difference.1.Enable SSH daemon
-This is mainly for FreeBSD hosts (like FreeNAS) with Jails
-Access the Jail via jexec and add following lines to /etc/rc.conf# Enable SSHd sshd_enable="YES"
-Start sshd service by service sshd start
2.Secure Transmission RPC Protocol
-This is optional but recommended for security purpose
-STOP the transmission daemon by service transmission stop
-Edit /usr/local/etc/transmission/settings.json
-Note that the location of settings.json may vary. The above path is from FeeBSD port.
-Update/add following parameters. Replace username, password. Ensure that IP address of your pfSense is in whitelist."rpc-authentication-required": true, "rpc-username": "SomeUserName", "rpc-password": "SomePassword", "rpc-whitelist": "127.0.0.1,10.10.10.1,10.10.10.5",
-Start the transmission again service transmission start
3.Create local port-update script
-This needs to be done under transmission user, not as root!su - transmission touch ~/transportupdate.sh chmod u+x ~/transportupdate.sh vi ~/transportupdate.sh
-Paste the code bellow OR just unzip/upload the file [ transportupdate.zip ] and chmod +x it.
-UPDATE the USERNAME='username' and PASSWORD='password' at the beginning of the file as per the credentials configured in step II.2.#!/bin/sh export PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/root/bin # Vers: 1.2 # Date: 1.2.2020 ############ Update these please ############# # Transmission-remote WEB credentials USERNAME='username' PASSWORD='password' # Transmission-remote binary is usually under known environment location. # Validate the command is known by " which transmission-remote " # If the "transmission-remote" is not known try to " find / -name transmission-remote " # Then update the variable bellow with full-path to the binary TRANSREMOTE='transmission-remote' #TRANSREMOTE='/usr/local/bin/transmission-remote' ############ Rest of the code - do not touch ############# # Port numbers NEWPORT="$1" # Verify that received new port is a valid number. if ! [ "$NEWPORT" -eq "$NEWPORT" ] 2> /dev/null; then logger "Non-numeric port ( $NEWPORT ) received from remote host. Aborting!" # EMAIL exit 1 fi # Check if Transmission is running service transmission status TRANSSVCRC=$? if [ "$TRANSSVCRC" -gt 0 ]; then logger "Transmission service is not running. Port update aborted!" # EMAIL exit 1 else # Configure new port received from remote system $TRANSREMOTE --auth ${USERNAME}:${PASSWORD} -p ${NEWPORT} TRANSREMOTERC=$? if [ "$TRANSREMOTERC" -gt 0 ]; then logger "Error when calling transmission-remote binary. Port was NOT updated!" # EMAIL exit 1 fi logger "Transmission port succesfully updated. New port is: ${NEWPORT}" exit 0 fi
4.Create/Upload public SSH key for pfSense connection
-Still under transmission usermkdir ~/.ssh chmod 700 ~/.ssh cd ~/.ssh touch authorized_keys chmod 644 authorized_keys vi authorized_keys
-Paste the content of id_rsa.pub generated in step I.7. and save ( :wq )
5.Restart OpenVPN in pfSense
.
-Wait for ~15secs and check Status -> System logs to see results
.
-All OK, port changed
.
DONE !! :] -
This is a great writeup - thanks for the effort you put into it.
I'm getting an error with
piaportfwd.sh
and the xml command within it (I ran the command directly on the command line to show the problem with xml not being found);[2.4.5-RELEASE][root@router]: xml sel -t -v "//alias[name='Trans_IP'']/address" /cf/conf/config.xml xml: Command not found.
Do you have any ideas on how to address this?
-
@dl_sdk Hi! Thanks, i did not realized the xmlstarlet is not pfSense default package. I guess I've installed it manually some time ago. Anyway the fix is simple:
pkg install xmlstarlet
Then relog your session and the script should work for you just fine.
I'll update the guide above as well.
//I can't do that "Error. You are only allowed to edit posts for 3600 second(s) after posting". -
pkg install xmlstarlet
worked!That lead to
[PIA] Error! Unable to remotely update Transmission port over SSH!
in the logs.I could ssh from pfsense to the transmission host without issue. On the transmission host, calling the transport update script, got;
transmission@404-03:~$ ./transportupdate.sh 59227 Unit transmission.service could not be found.
Once I changed the service status to the below, things worked nicely.
# Check if Transmission is running service transmission-daemon status
Thank you once more for this.
-
@dl_sdk Hey, glad you figured it out. Yes the service name vary across distros/packages. In my case it is just a pkg inside BSD Jail. I could change that to get the real service name from service -e output but then it might fail on the service command itself.
Anyway thanks for posting the command which works for you so other ppl can adjust the script if necessary. -
if you have issues parsing the port from the API: i have noticed sometimes the query to the api is too fast, i added a sleep 15 before the API call in the script and now it seems to pull the port more reliably:
# Get the Unique ID of the client system # More details at: https://www.privateinternetaccess.com/forum/discussion/23431> PIA_CLIENTID=`head -n 100 /dev/urandom | shasum -a 256 | tr -d " -"` logger "[PIA] Client-ID: $PIA_CLIENTID" sleep 15 # Request port-forward from PIA API PIA_PORT=$(curl --interface $OVPNIFACE "http://209.222.18.222:2000/\?client_id=>
hope it helps!
-
Seems to no longer be working with the move to "Next Gen" servers?
-
@Apocracy no it works, i am using it right now, i think right now only 2 or 3 servers support port forwarding, Canada and Germany don't work, they said they are working on a fix
-
This post is deleted!