December 9, 2018

Per-User VPN Routing

This tutorial will show how to route all the traffic belonging to particular user account through an OpenVPN tunnel

This tutorial will show how to route all the traffic belonging to particular user account through an OpenVPN tunnel. This can be done through iptables rules that 'mark' the user's packets, which in turn allow the kernel to apply a different routing table for marked traffic

As a practical example, suppose you had Transmission daemon Bitorrent client installed. This service usually runs as the debian-transmission user. Only debian-transmission traffic will be routed through the VPN.

Step one - Disable OpenVPN Client from changing default gateway
In most configurations, the OpenVPN server pushes the redirect-gateway to the clients. We don't want the VPN as the system wide default gateway.

Add the following to your client.ovpn file

pull-filter ignore redirect-gateway

Step two - Change rp_filter kernel setting

The kernel uses reverse path filtering (rp_filtering) to detect spoofed traffic. This setting must be changed for the tun0 interface

sysctl net.ipv4.conf.tun0.rp_filter = 2

Step three - Create the iptables rules

In this example, I'm using firewalld, which manages an iptables backend.

 firewall-cmd --direct --permanent \
 --add-rule ipv4 mangle OUTPUT 1 -m owner --uid-owner 106 -j MARK --set-mark 0xa
 
 firewall-cmd --direct --permanent \
 --add-rule ipv4 nat POSTROUTING 1 -o tun0 -j MASQUERADE   
 
 firewall-cmd --reload

Step four - Create the routing rules

Begin by creating a new routing table, and populating it with a default route

ip route add to default via $vpn_gateway_address dev tun0 table 10
ip rule add fwmark 0xa table 10
ip route flush cache

Step five - Test it's working

Your VPN origin address should appear below

sudo -u debian-transmission curl ipecho.net/plain
1.2.3.4