Linux – Tunnel specific traffic through OpenVPN

linuxnetworkingopenvpntrafficvpn

I have Ubuntu Server, and I would like to filter traffic and have only a specific users or groups traffic be sent through the VPN, and the rest of the traffic sent through the standard internet connection. I would think this would be rather easy to do, but I'm having a lot of trouble getting it set up.

I have been able to successfully set up a VPN connection using:

openvpn --config '/etc/openvpn/Sweden.ovpn' --auth-user-pass '/etc/openvpn/pia.txt' --persist-key --persist-tun --tls-client --remote-cert-tls server --user vpn &

The configuration file for OpenVPN contains the following:

client
dev tun
proto udp
remote sweden.privateinternetaccess.com 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca ca.crt
tls-client
remote-cert-tls server
auth-user-pass
comp-lzo
verb 1
reneg-sec 0

Which creates a new interface named "tun0". Using that interface works perfectly fine:

curl -v --interface tun0 icanhazip.com

However, when I attempt to use the eth0 interface, the connection will timeout:

curl -v --interface eth0 icanhazip.com

If I disable the OpenVPN connection, then my curl call through eth0 will work correctly.

Once I am able to get both eth0 and tun0 working, I had planned on using something similar to this command to route a specific group through the OpenVPN tunnel:

iptables -A OUTPUT -m owner --gid-owner vpn \! -o tun0 -j REJECT

Does anyone know of a way that I could get both eth0 and tun0 to work at the same time, so that I may route the traffic of a specific user/group through it and leave all other traffic alone?

Similar posts:
How to route specific traffic through OpenVPN? – I only have one network card in my solver, this solution appears to use two network cards.

Best Answer

There is a problem with your curl-test, which I know how to solve, and a problem with your scheme at large, to which I can suggest a solution.

curl cannot possibly work this way: after starting the VPN, there is no gateway defined on that interface (eth0): the eth0 NIC has an IP address, and can reach your LAN, but there is no gateway from which the internet, and icanhazip.com in particular, can be reached. For curl to work this way, you will have to instruct your kernel that the specific route to 216.69.252.101 (icanhazip.com) is through the eth0 interface:

   ip ro add 216.69.252.101 via your_home_routers_IP_address

Now the curl call will work as you wish.

If you want to communicate both through the VPN and outside it on a stable, complete basis, the correct way to proceed is to install a second routing table by means of policy based routing. You can find a good and concise introduction to the topic by David Schwartz on a sister-site, here. The reason why you need this contraption is that you are envisioning a system with two distinct gateways, which are not allowed unless of course there are two distinct routing tables.

Now, in order to accomplish your goal, i.e., to route packets along different routes according to user identity, you will have to set appropriate rules that select the relevant routing table. So let us suppose you now have two tables, called vpn and novpn. You will have first to use the mangle table of iptables to mark the packets according to user identity, and then supply rules for policy based routing according to the the presence (or absence) of the said mark.

It could work like this:

  iptables -t mangle -I OUTPUT -m owner --uid-owner some-user -j MARK --set-mark 100
  ip rule add fwmark 100 table vpn

for a user destined to use vpn, and

  iptables -t mangle -I OUTPUT -m owner --uid-owner some-other-user -j MARK --set-mark 300
  ip rule add fwmark 300 table novpn

for those you want to route outside the VPN. Also, it is always best to set a routing table for anything else, i.e., a default. Hope this helps.

Related Question