-
-
Notifications
You must be signed in to change notification settings - Fork 420
VPN with Traffic Splitting
Contents
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