Route all transmission-daemon traffic over OpenVPN by using network namespaces
So I have:
- Debian 11 server with transmission-daemon installed,
- an OpenVPN client config file.
I need to connect to OpenVPN but not to route anything except Transmission through the tunnel. Let's do this!
Starting the OpenVPN client service
Place your .ovpn
config to the /etc/openvpn/client
directory and change its extension to .conf
.
If server pushes defalut route, add following line to the config to ignore it:
pull-filter ignore redirect-gateway
Enable and start OpenVPN:
systemctl enable openvpn-client@your-config-name
systemctl start openvpn-client@your-config-name
You can check if it's working by running for example systemctl status openvpn-client@your-config-name
.
Networking configuration
First of all, make sure to enable IP forwarding. To do so, add net.ipv4.ip_forward = 1
line to /etc/sysctl.conf
and run sysctl -p
.
Create network namespace called vpn
and a pair of veth devices.
VETH_ADDR=10.200.1.1
VPEER_ADDR=10.200.1.2
OUT_IFACE=tun0 # this is the OpenVPN tunnel interface
VETH_IFACE=vethns1
VPEER_IFACE=vpeerns1
VPN_NS=vpn
ip netns add $VPN_NS
ip link add $VETH_IFACE type veth peer name $VPEER_IFACE
ip link set $VPEER_IFACE netns $VPN_NS
ip addr add $VETH_ADDR/24 dev $VETH_IFACE
ip link set $VETH_IFACE up
ip netns exec $VPN_NS ip addr add $VPEER_ADDR/24 dev $VPEER_IFACE
ip netns exec $VPN_NS ip link set $VPEER_IFACE up
ip netns exec $VPN_NS ip link set lo up
ip netns exec $VPN_NS ip route add default via $VETH_ADDR
Routing
Define new routing table, call it vpn
:
echo "100 vpn" >> /etc/iproute2/rt_tables
Add fwmark matching rule for this table (I use value of 100
here just for convenience, it can be anything, but must match the value in iptables rule):
ip rule add fwmark 100 table vpn
Add tun0
as the default route of the table vpn
(10.8.0.8
is ipv4 address assigned to my tun0
device):
ip r add default via 10.8.0.8 dev tun0 table vpn
Okay, routing and netns stuff is done, time for some iptables.
Firewall configuration
Let's say 192.168.1.2
is the ipv4 address of our linux box. 9091
is the transmission's web interface port and we want it to be accessible:
iptables -t nat -A PREROUTING -d 192.168.1.2 -p tcp -m tcp --dport 9091 -j DNAT --to-destination 10.200.1.2:9091
iptables -t nat -A POSTROUTING -s $VPEER_ADDR/24 -o $OUT_IFACE -j MASQUERADE
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d 10.200.1.0/24 -j MASQUERADE
iptables -t mangle -A PREROUTING -s 10.200.1.0/24 ! -d 10.200.1.1 -j MARK --set-xmark 0x64/0xffffffff
At this point, internet should be accessible from within the vpn
netns and all traffic coming from apps launched inside it must flow through the tun0
device.
Does it work? Check it before continuing
Let's run some tests, first, see if you can at least ping google:
ip netns exec vpn ping 8.8.8.8
If it works, try DNS resolving next. Sometimes it may be a problem, depending on your system DNS resolver:
ip netns exec vpn host google.com
If it fails to resolve, it's most probably because you have some local resolver server put to your /etc/resolv.conf
(pushed by your router, for example), and it's, obviously, not accessible from within the vpn
namespace because all traffic goes through tun0
.
There are several ways of solving the issue.
- Add some rules to the
vpn
routing table for your LAN. I don't like it because it kinda defeats the purpose: we wanted to route ALL traffic, coming from that netns, through the VPN. - (Not really a solution.)
ip-netns
util supports overridingresolv.conf
for programs launched byip netns exec
. Just create a file named/etc/netns/vpn/resolv.conf
and put some external resolver there, and it will be used instead of/etc/resolv.conf
. It's ok forip netns exec
, but we're not going to use it for starting transmission-daemon. - Just change the system resolver (in
/etc/resolv.conf
). For instance, set it to some public DNS service and mark the file immutable withchattr +i
to prevent it from being modified by DHCP clients, network managers and other smart stuff. Or, if you feel that you can't stand the lack of privacy when using public DNS services, you can create some more complicated setup with local dnsmasq resolver listening atlocalhost:53
and dnscrypt-proxy as its backend... well it's up for you. Just make it work. - I could make another trick and also add a mount namespace with substituted
/etc/resolv.conf
, but I didn't bother. I just use the 3rd option.
Launching Transmission
Preparations are done and we're ready to launch transmission-daemon, but we need to launch it inside our new vpn
network namespace. Fortunately, since version 242 systemd supports NetworkNamespacePath
option that is very handy for us.
Copy the unit file, we're going to edit it:
cp /lib/systemd/system/transmission-daemon.service /etc/systemd/system/
Under the [Service]
section add the following line:
NetworkNamespacePath=/run/netns/vpn
Probably reload systemd configuration and enable service if needed:
systemctl daemon-reload
systemctl enable transmission-daemon
Start it!
systemctl start transmission-daemon
Try connecting to 192.168.1.2:9091
and happy torrenting!