Automatically Bind Transmission to OpenVPN when using PIA (i.e creating a killswitch)

pro_trouble

Dabbler
Joined
Oct 2, 2014
Messages
10
I've been doing a lot of searching around this forum and the internet and haven't found a good solution for implementing a VPN killswitch with Transmission when using Private Internet Access (PIA) as a provider. I have come up with a hack solution that strangely seems to work well by picking through various posts. Feel free to pick it apart or provide suggestions for enhancement - I'm not an expert by any means, so I may have found an especially roundabout solution. Hopefully it can help somebody out.

I made this guide using Freenas 9.3.

First, follow this post for installing OpenVPN to work with PIA:

GUIDE: Setting up Transmission with OpenVPN and PIA
https://forums.freenas.org/index.ph...g-up-transmission-with-openvpn-and-pia.24566/

The only things I did differently from the above guide was use vim instead of nano. Nano's formatting was giving me a headache.

At this point you should have Transmission working through your OpenVPN connection. Also note, that if you stop OpenVPN:
Code:
#service stop openvpn

Transmission will momentarily pause then pick right back up again... which is exactly what we don't want.

The way to fix this is to set the "bind-address-ipv4" setting in Transmission's settings.json file match to the IP in the tun0 interface setup by OpenVPN. I made a script to do this:

/media/update_bind.sh
Code:
#!/usr/local/bin/bash                                                         
VPNADDR=`ifconfig | grep -A 5 "tun" | grep "inet" | cut -f2 -d" "`            
if [ -z "$VPNADDR" ]; then                                                    
        VPNADDR=127.0.0.1                                                     
fi                                                                            
cat /usr/pbi/transmission-amd64/etc/transmission/home/settings.json | sed "s/.*bind-address-ipv4.*/    \"bind-address-ipv4\"\: \"$VPNADDR\",/g" > /media/settings.json                                                                        
chmod 600 /media/settings.json                                                
chown transmission:transmission /media/settings.json                          
mv /media/settings.json /usr/pbi/transmission-amd64/etc/transmission/home/settings.json


This script gets the correct address to bin from the tun0 interface, then updates Transmission's settings.json file with this address. If OpenVPN isn't running, then it returns the localhost IP for the bind address, effectively blocking Transmission. I made this script executable by anyone, mainly because I couldn't be bothered to figure out the correct permissions:

Code:
chmod 755 /media/update_bind.sh


The only issue left now is that the update doesn't work if Transmission is already running. Since I wanted this to be automatically done whenever transmission was restarted, I modified

/usr/pbi/transmission-amd64/etc/rc.d/transmission

and added the following line just before the final curly brace in transmission_prestart()

Code:
/media/update_bind.sh


Now whenever I start or restart Transmission the settings.json file is updated with the correct bind address and Transmission stops functioning if the OpenVPN connection is lost.

The only issue here is that I haven't dealt with the order that things services start in the jail. So if transmission starts before OpenVPN, you'll have re manually restart it. Fixing that is a project for another day.

I have no expectation that this will continue to function through an upgrade to the jail or the system overall so use at your own risk.

I hope this was helpful.
 

Syner9y

Cadet
Joined
Jan 11, 2016
Messages
5
I followed your instructions, but Transmission still keeps working after I stop OpenVPN. Additionally, when I restart Transmission's service, it complains about chown:
root@transmission_1:/var/db/transmission/torrents # service transmission restart
Stopping transmission.
Waiting for PIDS: 43678.
usage: chown [-fhvx] [-R [-H | -L | -P]] owner[:group] file ...
chown [-fhvx] [-R [-H | -L | -P]] :group file ...
Starting transmission.
root@transmission_1:/var/db/transmission/torrents #

Any thoughts or help? Thanks!
 

NigelNoFriends

Explorer
Joined
Mar 29, 2016
Messages
56
I've been doing a lot of searching around this forum and the internet and haven't found a good solution for implementing a VPN killswitch with Transmission when using Private Internet Access (PIA) as a provider. I have come up with a hack solution that strangely seems to work well by picking through various posts. Feel free to pick it apart or provide suggestions for enhancement - I'm not an expert by any means, so I may have found an especially roundabout solution. Hopefully it can help somebody out.

I made this guide using Freenas 9.3.

First, follow this post for installing OpenVPN to work with PIA:

GUIDE: Setting up Transmission with OpenVPN and PIA
https://forums.freenas.org/index.ph...g-up-transmission-with-openvpn-and-pia.24566/

The only things I did differently from the above guide was use vim instead of nano. Nano's formatting was giving me a headache.

At this point you should have Transmission working through your OpenVPN connection. Also note, that if you stop OpenVPN:
Code:
#service stop openvpn

Transmission will momentarily pause then pick right back up again... which is exactly what we don't want.

The way to fix this is to set the "bind-address-ipv4" setting in Transmission's settings.json file match to the IP in the tun0 interface setup by OpenVPN. I made a script to do this:

/media/update_bind.sh
Code:
#!/usr/local/bin/bash                                                       
VPNADDR=`ifconfig | grep -A 5 "tun" | grep "inet" | cut -f2 -d" "`          
if [ -z "$VPNADDR" ]; then                                                  
        VPNADDR=127.0.0.1                                                   
fi                                                                          
cat /usr/pbi/transmission-amd64/etc/transmission/home/settings.json | sed "s/.*bind-address-ipv4.*/    \"bind-address-ipv4\"\: \"$VPNADDR\",/g" > /media/settings.json                                                                      
chmod 600 /media/settings.json                                              
chown transmission:transmission /media/settings.json                        
mv /media/settings.json /usr/pbi/transmission-amd64/etc/transmission/home/settings.json


This script gets the correct address to bin from the tun0 interface, then updates Transmission's settings.json file with this address. If OpenVPN isn't running, then it returns the localhost IP for the bind address, effectively blocking Transmission. I made this script executable by anyone, mainly because I couldn't be bothered to figure out the correct permissions:

Code:
chmod 755 /media/update_bind.sh


The only issue left now is that the update doesn't work if Transmission is already running. Since I wanted this to be automatically done whenever transmission was restarted, I modified

/usr/pbi/transmission-amd64/etc/rc.d/transmission

and added the following line just before the final curly brace in transmission_prestart()

Code:
/media/update_bind.sh


Now whenever I start or restart Transmission the settings.json file is updated with the correct bind address and Transmission stops functioning if the OpenVPN connection is lost.

The only issue here is that I haven't dealt with the order that things services start in the jail. So if transmission starts before OpenVPN, you'll have re manually restart it. Fixing that is a project for another day.

I have no expectation that this will continue to function through an upgrade to the jail or the system overall so use at your own risk.

I hope this was helpful.

This broke Transmission plugin, for me. After following guide, can't get Transmission plugin to start again.

Not sure if maybe the directory/paths have changed slightly since your guide was written? Updated Transmission pkg or FreeNAS itself?

I'm running the current stable 9.10 FreeNAS and the most recent Transmission plugin.

Also, just to confirm, ssh into the transmission_1 jail, then cd into 'media' to create your update_bind.sh script - is this the correct location?

Also, here's where I placed the command inside the tansmission text file (very last line) - is it correct?

Code:
transmission_prestart()
{
install -d -o $transmission_user ${pidfile%/*}
if checkyesno transmission_chown; then
mkdir -p $transmission_conf_dir $transmission_download_dir
chown $transmission_user:$transmission_group $transmission_down$
chown -R $transmission_user:$transmission_group $transmission_c$
chgrp $transmission_group $transmission_conf_dir
chmod 750 $transmission_conf_dir
fi
if [ -n "$transmission_web_home" ]; then
TRANSMISSION_WEB_HOME=$transmission_web_home
export TRANSMISSION_WEB_HOME
fi
/media/update_bind.sh}
 

NigelNoFriends

Explorer
Joined
Mar 29, 2016
Messages
56
Code:
#!/usr/local/bin/bash                                                       
VPNADDR=`ifconfig | grep -A 5 "tun" | grep "inet" | cut -f2 -d" "`          
if [ -z "$VPNADDR" ]; then                                                  
        VPNADDR=127.0.0.1                                                   
fi                                                                          
cat /usr/pbi/transmission-amd64/etc/transmission/home/settings.json | sed "s/.*bind-address-ipv4.*/    \"bind-address-ipv4\"\: \"$VPNADDR\",/g" > /media/settings.json                                                                      
chmod 600 /media/settings.json                                              
chown transmission:transmission /media/settings.json                        
mv /media/settings.json /usr/pbi/transmission-amd64/etc/transmission/home/settings.json

Bearing in mind I'm a complete newbie when it comes to code of any sort - I think maybe the issue is in relation to the 'settings.json' file?
I'm not sure what most of that code is/does, but I tried to at least locate that settings file, using the jail shell/terminal, at the directory noted and it's not there.
So, unless it's a hidden file (?), there doesn't appear to be anything within this directory (using the current builds): /media/settings.json /usr/pbi/transmission-amd64/etc/transmission/home

Worth noting that I did find a settings.json file in this directory: /var/db/transmission BUT, the file itself looks empty on opening...
 
Last edited:
Joined
Mar 21, 2018
Messages
1
Solved years ago, but here's an improved (IMO) version that only restarts the service if necessary...

Code:
#!/bin/bash
service=transmission-daemon
settings=/etc/$service/settings.json
param=bind-address-ipv4
# OpenVPN passes the Client IP in as a positional parameter
VPNADDR=$4

if [ -z "$VPNADDR" ]; then
   VPNADDR=`ifconfig | grep -A 5 "tun" | grep "inet" | cut -f2 -d":" | cut -f1 -d" "`
fi

if [ -z "$VPNADDR" ]; then
		VPNADDR=127.0.0.1 # localhost
fi


IPEXISTING=`cat $settings | python3 -c "import sys, json;print(json.load(sys.stdin)['$param'])"`

echo "Existing : $IPEXISTING"
echo "New	  : $VPNADDR"

if [ -z "$IPEXISTING" ]; then
		IPEXISTING= 255.255.255.255 # nonsense value, will never be written to file
fi

if [ "$IPEXISTING" = "$VPNADDR" ]; then
   echo "$param value is already set correctly, leave $service alone"
else
   echo "$param value needs to be changed (from $IPEXISTING to $VPNADDR)"
   if (( $(ps -ef | grep -v grep | grep transmission | wc -l) > 0 ))
   then
	   echo "Stopping $service"
	   /etc/init.d/$service stop
   else
	   echo "$service not running, no need to stop it"
   fi
   cat $settings | sed "s/.*$param.*/	\"$param\"\: \"$VPNADDR\",/g" > temp.json
   chown debian-transmission:debian-transmission temp.json
   mv temp.json $settings
   /etc/init.d/$service start
fi




Plus, really handy for me if/when I lose my VM and it's scripts!
 
Last edited:

timt

Cadet
Joined
Oct 24, 2017
Messages
1
Solved years ago, but here's an improved (IMO) version that only restarts the service if necessary...

Code:
#!/bin/bash
service=transmission-daemon
settings=/etc/$service/settings.json
param=bind-address-ipv4
# OpenVPN passes the Client IP in as a positional parameter
VPNADDR=$4

if [ -z "$VPNADDR" ]; then
   VPNADDR=`ifconfig | grep -A 5 "tun" | grep "inet" | cut -f2 -d":" | cut -f1 -d" "`
fi

if [ -z "$VPNADDR" ]; then
        VPNADDR=127.0.0.1 # localhost
fi


IPEXISTING=`cat $settings | python3 -c "import sys, json;print(json.load(sys.stdin)['$param'])"`

echo "Existing : $IPEXISTING"
echo "New      : $VPNADDR"

if [ -z "$IPEXISTING" ]; then
        IPEXISTING= 255.255.255.255 # nonsense value, will never be written to file
fi

if [ "$IPEXISTING" = "$VPNADDR" ]; then
   echo "$param value is already set correctly, leave $service alone"
else
   echo "$param value needs to be changed (from $IPEXISTING to $VPNADDR)"
   if (( $(ps -ef | grep -v grep | grep transmission | wc -l) > 0 ))
   then
       echo "Stopping $service"
       /etc/init.d/$service stop
   else
       echo "$service not running, no need to stop it"
   fi
   cat $settings | sed "s/.*$param.*/    \"$param\"\: \"$VPNADDR\",/g" > temp.json
   chown debian-transmission:debian-transmission temp.json
   mv temp.json $settings
   /etc/init.d/$service start
fi




Plus, really handy for me if/when I lose my VM and it's scripts!


THANK YOU for the script. I Looked for a while before I found it!

** I had to make minor changes to work with Ubuntu 20.04 **

#!/usr/bin/bash

service=transmission-daemon
settings=/etc/$service/settings.json
param=bind-address-ipv4
# OpenVPN passes the Client IP in as a positional parameter
VPNADDR=$4

if [ -z "$VPNADDR" ]; then
VPNADDR=`ifconfig | grep -A 5 "tun" | grep "inet\b" | awk '{print $2}'`
fi

if [ -z "$VPNADDR" ]; then
VPNADDR=127.0.0.1 # localhost
fi


IPEXISTING=`cat $settings | python3 -c "import sys, json;print(json.load(sys.stdin)['$param'])"`

echo "Existing : $IPEXISTING"
echo "New : $VPNADDR"

if [ -z "$IPEXISTING" ]; then
IPEXISTING= 255.255.255.255 # nonsense value, will never be written to file
fi

if [ "$IPEXISTING" = "$VPNADDR" ]; then
echo "$param value is already set correctly, leave $service alone"
else
echo "$param value needs to be changed (from $IPEXISTING to $VPNADDR)"
if (( $(ps -ef | grep -v grep | grep transmission | wc -l) > 0 ))
then
echo "Stopping $service"
/etc/init.d/$service stop
else
echo "$service not running, no need to stop it"
fi
cat $settings | sed "s/.*$param.*/ \"$param\"\: \"$VPNADDR\",/g" > temp.json
chown debian-transmission:debian-transmission temp.json
mv temp.json $settings
/etc/init.d/$service start
 

bvrulez

Cadet
Joined
Feb 1, 2021
Messages
1
Thanks for the skript. I used it on a Raspberry Pi. It is missing a further "fi" at then end, though. Also, my problem is that if I don't set the VPN as default gateway the packages are not send through it at all. Should I be able to add a static route for the VPN subnet to point to the VPN gateway?
 
Top