1 (edited by ExaltedVanguard 2017-03-11 16:55:21)

Topic: Routing a specific client's access through VPN

This guide will go through the process of making a single client use the vpn tunnel while routing all other traffic normally.

This can have any number of uses. For example, let's say you want to run a NAS server that doubles as a seedbox for your homebrew linux distribution. You ISP throttles you when it detects bittorrent traffic, so you'll have to send that traffic via VPN, however you don't want your entire network going through the tunnel due to privacy concerns. Setting up a VPN and routing traffic on the NAS itself while maintaining connectivity to all your LAN clients can make the network settings overly complicated. It is instead easier to manage this on the router. Another use-case would be if you want to send 2 or 3 clients' connections through the VPN, but your VPN only allows a single active tunnel.

---

First off, this is not going to be a full tutorial for novices. This is intended for advanced users who understand all the individual commands used, but maybe not how to piece it all together.

You should not blindly follow this like a tutorial. Inappropriate settings may make your router unreachable, requiring you to enter recovery mode to fix your mistakes.

Make sure you have the relevant packages for openvpn as well as the package ip.

This guide is written with the following considerations:

  • IP routing table and IP rules have not already been extensively modified/any previous modifications do not conflict.

  • Our VPN provider is privateinternetaccess (PIA)

  • If the VPN tunnel falls, we do not want traffic to default to the normal interface, since this will result in throttling of the connection

  • We will be using the port-forwarding feature of PIA to request a forwarded port

---

We're going to start by adding a new routing table. Edit /etc/iproute2/rt_tables and add a new routing table by adding a new line following the default formatting. ID and name are arbitrary, but should be unique:

10 vpn

Create your VPN .conf file and place it in /etc/openvpn and follow my guide on setting up an openvpn client connection on openwrt. For ease of use, I recommend using an openvpn .conf file rather than the UCI commands (although either way is plenty functional):
https://wiki.openwrt.org/doc/howto/vpn.openvpn

This will be VPN-provider specific of course, and I'm going to assume you're familiar with these files (the openvpn manual is very good). Make sure you include the route-nopull directive so that openvpn does not alter your default routing table. You will also be using a route-up script (routing.sh), so add that (and script-security 2) as well. Below is the config for PIA. Note that I'm using a tunnel named tunCA rather than tun0. Clear names simplify things in a complex environment. Modify accordingly:

client
dev tunCA
dev-type tun
route-nopull
proto udp
remote ca-toronto.privateinternetaccess.com 1198
resolv-retry infinite
nobind
persist-key
persist-tun
cipher aes-128-cbc
auth sha1
tls-client
remote-cert-tls server
auth-user-pass /etc/openvpn/PIA/.vpnauth
comp-lzo
verb 1
reneg-sec 0
crl-verify /etc/openvpn/PIA/crl.rsa.2048.pem
ca /etc/openvpn/PIA/ca.rsa.2048.crt
route-up "/bin/sh /etc/openvpn/PIA/routing.sh"
script-security 2

Your routing.sh file will contain the following, which tells our new routing table (vpn) to use the tunnel, and to run a secondary script to request a port from PIA.

#!/bin/bash

ip route replace default via $ifconfig_remote dev tunCA table vpn
ip route flush cache

/bin/sh /etc/openvpn/PIA/portconfig.sh &

(As an aside, the port request must be sent in a secondary script because the tunnel won't send data till the route-up script is finished, and the port-request must be sent over the tunnel. Requesting a port from the route-up script will cause the program to hang.)

The following are the contents of portconfig.sh. It will create a file called port that contains the port number.

You will need to provide a client ID, which is a completely arbitrary SHA-256 hash. If you want to try to keep the same port between disconnects, you should use a static hash (just type something random in here). Those concerned with privacy should generate a random hash on the fly, or just not use PIA's port-forwarding.

#!/bin/bash

client_id="TYPE YOUR SHA-256 HASH HERE"

json=`wget -q -t 3 --connect-timeout=15 -O - "http://209.222.18.222:2000/?client_id=$client_id" | head -1 | tr -d '{$

if [ "$json" == "" ]; then
  json='Port forwarding failed.'
fi

echo $json > /etc/openvpn/PIA/port

Now we just need to utilize our new routing table. Add the following to /etc/rc.local (so that these commands will be run at boot).

The first line makes the PIA port-forwarding request use the tunnel. The second and third lines are the IPs of the clients you'd like to use the tunnel. Repeat as many times as you desire (or use bitmasks for ranges).

ip rule add to 209.222.18.222 priority 10 table vpn
ip rule add from 192.168.1.50 priority 10 table vpn
ip rule add from 192.168.1.51 priority 10 table vpn

Lastly, we're going to make it so that our clients will only use the VPN by firewalling their connections on our WAN interface incase the tunnel loses connection. Add the following to /etc/config/firewall (or use LUCI or UCI commands to accomplish the same):

config rule
        option name 'VPNBlock'
        option src_ip '192.168.1.50'
        option dest 'wan'
        option target 'REJECT'
        option proto 'all'
        option src '*'

config rule
        option name 'VPNBlock2'
        option src_ip '192.168.1.51'
        option dest 'wan'
        option target 'REJECT'
        option proto 'all'
        option src '*'

All done. Enjoy.

Re: Routing a specific client's access through VPN

I don't understand about portconfig and client ID, what is the purpose of it?

Re: Routing a specific client's access through VPN

ulmwind wrote:

I don't understand about portconfig and client ID, what is the purpose of it?

It's a feature of PIA's VPN service. If you don't know what it is, you probably don't need it.