Bind Transmission to vpn using vpn policy based routing


#1

I followed this guide to bind transmission to my vpn interface.
However it is not working for me.

#!/bin/sh                                                                                                                          
                                                                                                                                   
/etc/init.d/transmission stop                                                                                                      
                                                                                                                                   
VPNADDR=`ifconfig | grep -A 5 "tun_airvpn" | grep "inet addr:" | cut -d: -f2 | awk '{ print $1}'`                                        
if [ -z "$VPNADDR" ]; then                                                                                                         
        VPNADDR=127.0.0.1                                                                                                          
fi                                                                                                                                 
                                                                                                                                   
cat /etc/config/transmission | sed "s/.*bind_address_ipv4.*/ \toption bind_address_ipv4 \'$VPNADDR\' /g" > /etc/config/transmission
                                                                                                                                   
chmod 666 /etc/config/transmission_test                                                                                            

mv /etc/config/transmission_test /etc/config/transmission                                                                          
                                                                                                                                   
/etc/init.d/transmission start 

1 created the script "updatebindaddress" and changed the tun interface to the one I am using.
2 added the line option route_up '/etc/openvpn/updatebindaddress' to my vpn config.
3 restart openvpn
4 script runs with error that transmission_test is missing
5 transmission config file gets cleared

so I did this

0 created the file /etc/config/transmission_test (as a copy of /etc/config/transmission)
1 created the script "updatebindaddress" and changed the tun interface to the one I am using.
2 added the line option route_up '/etc/openvpn/updatebindaddress' to my vpn config.
3 restart openvpn
4 script runs fine
5 no changes to transmission test however, obviously because of the 'mv command'

So why is the script not working for me?


Nevermind. I changed the script to use "uci set".

#!/bin/sh

/etc/init.d/transmission stop

VPNADDR=`ifconfig | grep -A 5 "tun_airvpn" | grep "inet addr:" | cut -d: -f2 | awk '{ print $1}'`
if [ -z "$VPNADDR" ]; then
        VPNADDR=127.0.0.1
fi

uci set transmission.@transmission[0].bind_address_ipv4=$VPNADDR
uci commit

/etc/init.d/transmission start

It is now working, but only when I manually call it. I set permissions for the file to "0755 - rwxr-xr-x".


#2

I've optimized the code:

#!/bin/sh

VPN_ADDR="${ifconfig_local}"

if [ -z "${VPN_ADDR}" ]
then     
    VPN_ADDR="127.0.0.1"
fi

uci set transmission.@transmission[0].bind_address_ipv4="${VPN_ADDR}"
/etc/init.d/transmission restart

The original guide is here:


#3

Thanks for this!
But the script is still not called when starting the vpn.

BTW: Why is uci commit not necessary?


#4

VPN-address is valid only for runtime state.
There's no need to save it in transmission persistent config.
If you want to prevent transmission traffic leak, set default to:

uci set transmission.@transmission[0].bind_address_ipv4="127.0.0.1"
uci commit transmission
/etc/init.d/transmission restart

And then you can optimize the code even more:

#!/bin/sh

if [ -n "${ifconfig_local}" ]
then     
    uci set transmission.@transmission[0].bind_address_ipv4="${ifconfig_local}"
    /etc/init.d/transmission restart
fi

#5

Makes sense!

Where does the script get the ${ifconfig_local} from?
It is not working for me.
Also the script is still not called after starting the vpn, which is right now my biggest problem. ^^


#6

It is an environment variable passed to the script:
https://openvpn.net/community-resources/reference-manual-for-openvpn-2-4/#environmental-variables

# openvpn.conf
script-security 2

#7

Please provide your vpn config. You may be missing some option.


#8
vpn config
config openvpn 'AirVPN'
	option client '1'
	option dev_type 'tun'
	option dev 'tun_airvpn'
	option proto 'udp'
	option port '443'
	list remote 'nl3.vpn.airdns.org'
	option mssfix '1464'
	option resolv_retry 'infinite'
	option keepalive '10 60'
	option nobind '1'
	option persist_key '1'
	option persist_tun '1'
	option auth_nocache '1'
	option route_nopull '1'
	option route_delay '5'
	option route_up '/etc/openvpn/airvpn_client_up.sh'
	option explicit_exit_notify '5'
        option script_security '2'
	option verb '3'
	option auth 'SHA512'
	option cipher 'AES-256-CBC'
	option remote_cert_tls 'server'
	option tls_crypt '/etc/openvpn/client/airvpn/tls-crypt.key'
	option ca '/etc/openvpn/client/airvpn/ca.crt'
	option cert '/etc/openvpn/client/airvpn/admin_router.crt'
	option key '/etc/openvpn/client/airvpn/admin_router.key'
	option enabled '1'
opbr config

config policy
	option name 'Torrent'
	option proto 'tcp udp'
	option interface 'airvpn'
	option local_address '10.0.0.0/24'
	option chain 'OUTPUT'

config policy
	option proto 'tcp udp'
	option name 'VPN'
	option interface 'airvpn'
	option chain 'PREROUTING'
	option local_address '192.168.1.59'

config vpn-policy-routing 'config'
	option verbosity '2'
	option ipv6_enabled '0'
	option dnsmasq_enabled '0'
	option boot_timeout '60'
	list supported_interface 'airvpn'
	list supported_interface 'ibvpn'
	option strict_enforcement '1'
	option proto_control '1'
	option chain_control '1'
	option ipset_enabled '1'
	option enabled '1'
	list ignored_interface 'ovpn_server'

this line was missing, the vpn config is now calling the script.

The traffic is still being routed through wan, after the script passed, even though uci show transmission tells me that transmission gets assigned to the ipv4 of the tun_airvpn interface.

current script
# bind transmission to airvpn tun interface
/etc/init.d/transmission stop
VPN_ADDR="${ifconfig_local}"

if [ -z "${VPN_ADDR}" ]
then
    VPN_ADDR="127.0.0.1"
fi

uci set transmission.@transmission[0].bind_address_ipv4="${VPN_ADDR}"

# now restart services
sleep 5
/etc/init.d/vpn-policy-routing restart
sleep 5
/etc/init.d/transmission start

I added sleep 5 because the opbr readme says that vpn interfaces need to be up before starting the opbr service or it might lead to errors. (opbr readme)


#9

Now that I have figured out some other problems, I can get back to this one.
Does anyone have any idea what I might be doing wrong?

I also noticed some strange behaviour in my network once OPBR starts. Even when there are no rules set. Network clients seem to have trouble accessing internet websites or services like netflix.


#10

Sorry, it's a bit troublesome to reproduce, because I forward all the traffic into VPN-tunnel and do not use PBR, but I hope that someone can help you.


#11

I changed my script again and it is now doing what it should.
I also changed my VPN client config and added a route_down script, which stops transmission and binds it back to the localhost. The latter might be unnecessary since the daemon is stopped anyways, but better safe than sorry.
https://forums.openvpn.net/viewtopic.php?t=8539
https://openvpn.net/community-resources/reference-manual-for-openvpn-2-4/
Reading trough the openvpn wiki I found that "option persist_key '1' " shouldn't be used when doing something like vpn policy routing. Also it is a good idea to wait until the route is up, so include "route_delay", before running the "route_up" script.

Notice that I don't want all my network traffic to go trough the vpn, that is way I included "option route_nopull '1' " in my client config. I just want certain devices/services to use it.

finally all the scripts and configs

vpn-policy-routing config
config policy
	option name 'torrent'
	option proto 'tcp udp'
	option interface 'airvpn'
	option chain 'OUTPUT'
	option local_address '10.0.0.0/24' --> depending of your vpn provider
	option local_port '0-65535'

vpn client config
config openvpn 'AirVPN'
	option client '1'
	option dev_type 'tun'
	option dev 'tun_airvpn'
	option proto 'udp'
	option port '443'
	list remote 'nl3.vpn.airdns.org'
#### you might not need the below line
	option mssfix '1464'
#### but the rest for sure
	option resolv_retry 'infinite'
	option keepalive '10 60'
	option nobind '1'
	option persist_key '1'
	option auth_nocache '1'
	option route_nopull '1'
	option route_delay '5'
	option up_delay '1'
	option up_restart '1'
	option route_up '/etc/openvpn/airvpn_client_up.sh'
	option route_down '/etc/openvpn/airvpn_client_down.sh'
	option explicit_exit_notify '5'
	option script_security '2'
	option verb '3'
	option auth 'SHA512'
	option cipher 'AES-256-CBC'
	option remote_cert_tls 'server'
	option tls_crypt '/etc/openvpn/client/airvpn/tls-crypt.key'
	option ca '/etc/openvpn/client/airvpn/ca.crt'
	option cert '/etc/openvpn/client/airvpn/admin_router.crt'
	option key '/etc/openvpn/client/airvpn/admin_router.key'
	option enabled '1'
airvpn_client_up.sh
#!/bin/sh

# bind transmission to airvpn tun interface
/etc/init.d/transmission stop
VPN_ADDR="${ifconfig_local}"

if [ -z "${VPN_ADDR}" ]
then
    VPN_ADDR="127.0.0.1"
fi
uci set transmission.@transmission[0].bind_address_ipv4="${VPN_ADDR}"

# restart services
# wait again for the tun interface to be up, just to be sure
sleep 5
/etc/init.d/vpn-policy-routing restart
# wait for vpn-policy-routing to apply routing and then start transmission
sleep 5
/etc/init.d/transmission start

airvpn_client_down.sh
#!/bin/sh

# stop transmission and bind to localhost
/etc/init.d/transmission stop
uci set transmission.@transmission[0].bind_address_ipv4="127.0.0.1"

And as said earlier in this topic one should bind transmission by default to localhost.

/etc/init.d/transmission stop
uci set transmission.@transmission[0].bind_address_ipv4="127.0.0.1"
uci commit transmission
/etc/init.d/transmission start

If you ask me the only point of error now is the vpn-policy-routing package.
If that fails for some reason, the binding stops and all traffic goes trough wan. But this doesn't belong in this topic.


#12

I just restarted my router and traffic is again not routed to the vpn.
Everything goes through wan.


#13

Probably it is a race condition:


#14

Since binding is not working 100 % of the time.
How can I assure, that if it is not bind correctly, it is atleast not using the WAN interface.

How would a firewall rule look like that is blocking all connections of transmission to the wan interface?
I want to run transmission on port 5270. (forwarded this at my vpn provider)


#15

How about binding to loopback interface by default:

uci set transmission.@transmission[0].bind_address_ipv4="127.0.0.1"
uci commit transmission
/etc/init.d/transmission restart

I believe, it should initialize fast enough to avoid race condition.
Or add firewall rules to reject outgoing/incoming traffic from/to interface wan and port 51413/tcp+udp.


#16

This is working perfectly, until I bind it to the VPN IP.

uci set transmission.@transmission[0].bind_address_ipv4="10.x.x.x"
uci commit transmission
/etc/init.d/transmission restart

Without policy based routing the traffic is still going trough wan.
Guess because I added the nopull option in the vpn config, which I want to keep.
When I get policy based routing to work, it is going trough vpn.
But once I stop that

If I bind transmission to a subnet that doesn't exist ( f.e. 192.168.10.0 ) it doesn't have internet access. So why does it have internet access if it is bound to the VPN subnet, even if the vpn interface is down?

Something like this?

config rule
	option enabled '1'
	option src 'wan'
	option name 'Block-Torrent-WAN'
	option src_port '5270'
	option dest 'lan'
	option dest_port '5270'
	option target 'DROP'

config rule
	option enabled '1'
	option src 'lan'
	option name 'Block-Torrent-WAN'
	option src_port '5270'
	option dest 'wan'
	option dest_port '5270'
	option target 'DROP'

#17

In the first rule remove

option src_port '5270'

As you don't know from which port the packets will come to you.

option dest 'lan'

As the destination is the device itself, not the LAN.

In the second rule remove

option dest_port '5270'

as you don't know the port that other peers listen to.

option src 'lan'

as the source is the device itself, not the LAN.


#18
config rule
	option enabled '1'
	option src 'wan'
	option name 'Block-Torrent-Inbound-WAN'
	option dest_port '5270'
	option target 'DROP'
	option dest '*'

config rule
	option enabled '1'
	option name 'Block-Torrent-Outbound-WAN'
	option src_port '5270'
	option target 'DROP'
	option src '*'
	option dest 'wan'

transmission can still access wan


#19

Why did you add the src and dest '*' ?
Also have you bound port 5270 as source for transmission?


#20

Do I have to completely remove the lines?
Yes I have set it to port 5270