Skip to content

VPN with Traffic Splitting

chros73 edited this page May 27, 2018 · 3 revisions

VPN with Traffic Splitting

This is one of the most frequently asked questions, due to the fact that split tunneling can be achieved in tons of ways.

One of the best ways is to utilize network namespaces to completely separate applications/traffic (available in Linux kernel since around v3.0.x). Even this category has multiple solutions for the given problem.

Fortunately there's a small script namespaced-openvpn (written in python) that provides the best approach (no need for extra firewall rules, manual rooting table changes, etc.):

"namespaced-openvpn is a wrapper script for OpenVPN on Linux that uses network namespaces to solve a variety of deanonymization, information disclosure, and usability issues. The main implementation idea of namespaced-openvpn is this: instead of connecting a network namespace to the physical network using virtual Ethernet adapters and bridging, it suffices to transfer a tunnel interface into the namespace, while the process managing the tunnel (in this case openvpn) remains in the root namespace."

Please take the time to read at least the Summary and Security sections of the main readme file.

First, you need to install a few required packages. These steps must be performed by the root user (i.e. in a root shell, or by writing sudo before the actual command, more hint about sudo on Debian if something doesn't work):

apt-get update
apt-get install openvpn iproute2 python sudo dnsutils dnsmasq curl

Download namespaced-openvpn script into /usr/local/sbin directory:

cd /usr/local/sbin
curl -sLSO https://raw.githubusercontent.com/slingamn/namespaced-openvpn/master/namespaced-openvpn
chmod +x namespaced-openvpn

Then copy the provided OpenVPN *.ovpn config file(s) into ~/.config/openvpn directory as a regular user after creating that directory:

mkdir -p ~/.config/openvpn
cp *.ovpn ~/.config/openvpn/
chmod 400 ~/.config/openvpn/*.ovpn

To create an OpenVPN tunnel in the protected (default) namespace (change foo below):

sudo /usr/local/sbin/namespaced-openvpn --config /home/"$USER"/.config/openvpn/foo.ovpn --writepid /var/run/openvpn-protected-foo-"$USER".pid --log /var/log/openvpn-protected-foo-"$USER".log --daemon

To start an application in the protected namespace:

sudo ip netns exec protected sudo -u "$USER" ip addr show
sudo ip netns exec protected sudo -u "$USER" dig

To start an interactive shell in the protected namespace (every other commands will be started in the same namespace):

sudo ip netns exec protected sudo -u "$USER" -i

To get a list of available namespaces:

ip netns list

To stop the OpenVPN tunnel just kill the process, note that protected namespace is still available!:

sudo pkill -F /var/run/openvpn-protected-foo-"$USER".pid

Now let's concentrate to rtorrent.

First let's try to eliminate the lot of typing by adding netns-exec function into your ~/.profile file (you have to logout/login or source ~/.profile in the current shell to take effect):

# execute a program in 'protected' network namespace
netns-exec () {
    sudo ip netns exec protected sudo -u "$USER" "$@"
}
export -f netns-exec

After this we can lunch applications in the protected namespace by running e.g.: netns-exec rtorrent

Only the following changes are needed in .rtorrent.rc:

  • modify port numbers to the ones that the VPN provider forwards for your account
  • make sure you have set up a socket instead of port number for XMLRPC connections
  • you only have to set the local IP (no need for setting bind address)
# Port range to use for listening. (port_range)
network.port_range.set = 64210-64210
# UDP port to use for DHT
dht.port.set = 64229

# SCGI socket and make it group writeable when rtorrent starts (otherwise apps can't connect to it since it was     started by a normal user) (scgi_local)
network.scgi.open_local = /path/to/session/dir/.rtorrent.sock
schedule2 = chmod_scgi_socket, 0, 0, "execute2=chmod,g+w,(cat,(session.path),.rtorrent.sock)"

# Get public IP address without the need of having dynamic DNS service, also works from behind NAT, through tunnel
method.insert = get_public_ip_address, simple|private, "execute.capture=bash,-c,\"eval echo -n \$(dig TXT +short o-o.myaddr.l.google.com @ns1.google.com)\""
# The IP address reported to the tracker. (ip) This handles dynamic IP's as well.
schedule2 = ip_tick, 0, 1800, "network.local_address.set=(get_public_ip_address)"

We can even have caching DNS in the protected namespace by using dnsmasq. The following example uses Google's name servers:

netns-exec /usr/sbin/dnsmasq --bind-interfaces --listen-address=127.0.1.1 --server=8.8.8.8 --server 8.8.8.4 --cache-size=500 --proxy-dnssec --pid-file=/var/run/dnsmasq-protected-foo-"$USER".pid

After setting up our system, the following commands will:

  • create a tunnel
  • use caching DNS
  • and launch rtorrent
sudo /usr/local/sbin/namespaced-openvpn --config /etc/openvpn/foo.ovpn --writepid /var/run/openvpn-protected-foo-"$USER".pid --log /var/log/openvpn-protected-foo-"$USER".log --daemon
netns-exec /usr/sbin/dnsmasq --bind-interfaces --listen-address=127.0.1.1 --server=8.8.8.8 --server 8.8.8.4 --cache-size=500 --proxy-dnssec --pid-file=/var/run/dnsmasq-protected-foo-"$USER".pid
netns-exec rtorrent