Usurping the BTHomeHub with a Raspberry Pi: Part 4 - Using a VPN to Tunnel Connections to Specific IPs

Content Filtering is becoming increasingly popular amongst Politicians, ISPs and generally clueless do-gooders. The problem  is, whatever you think of their motives, it's generally poorly implemented and interferes with the end-users browsing experience, even when it's not supposed to (the image to the right appeared with filtering off! - click to enlarge).

As we've been Usurping the BTHomeHub with a Raspberry Pi, we're going to take a brief break to implement some useful functionality that the HomeHub didn't provide.

In this Part, we're going to configure our Raspberry Pi to connect to an OpenVPN server and route some of our traffic over the tunnel - depending on the destination IP (i.e. Split tunnelling). This will allow us to easily bypass the troublesome content filtering, whilst not un-necessarily introducing any latency to any connection that is (for the time being at least) unaffected by the filters.

Note: We'll be manually specifying the connections that are routed via VPN, so that we can 'whitelist' mistakes such as the EFF and Wikipedia, whilst still being 'protected' against other filtered pages.

Unless otherwise stated, all commands need to be run as root

 

We need an OpenVPN Endpoint

The first step is obvious, you need an off-net OpenVPN server, if you don't have one but have a VPS/Dedicated server, follow the relevant guide to installing OpenVPN.

 

Grabbing Some Pre-Requisites

The idea, longer term, is that we'll have a simple management interface allowing us to identify traffic that needs to pass over the VPN. As a result, we can't simply run OpenVPN as a service, though we do need it installed. So start by installing OpenVPN and lynx (which we'll be using for testing)

apt-get install openvpn lynx

Next we'll grab the management script

cd /root
git clone https://github.com/bentasker/RaspbPiVPNRoutingMgr.git

 

Configuring a connection

Now that we have a OpenVPN server to connect to, we're going to add the connection config to our Pi. During the setup of your OpenVPN server you'll have created some keys and (possibly) a configuration file. We need to put these on the Pi and amend the config file ever so slightly.

We're going to call our VPN endpoint Gateway - you can change the name, but ensure the containing directory and the config file use the same name (it's case sensitive)

cd /root/VPNs/config/VPNs
mkdir Gateway
cd Gateway

# Put your OpenVPN client keys in here - if you've got a config file then put it here as Gateway.conf.
ls
 ca.crt lan.crt lan.csr lan.key Gateway.conf

Our next step is to edit (or create) the configuration file.

nano Gateway.conf

# If this is a new file, you want to add the following
client
dev tun
port 1194
proto udp
remote [YOUR VPN SERVER IP] 1194
nobind

ca ca.crt
cert lan.crt
key lan.key

comp-lzo
persist-key
persist-tun

# These are the two definitions we want to add if your file already existed
route-nopull
daemon

Essentially the change we're making to an existing config file is to add route-nopull and daemon. We want the Pi to make the decisions regarding which traffic goes over the VPN, so need to ensure we ignore the routes that the OpenVPN server suggests. Daemon just ensures that OpenVPN forks into the background

 

Manually establishing a connection

Before we configure our Pi to automatically establish a connection we're going to take a manual runthrough first (this will also help you to understand what the scripts do)

To begin with, let's make a note of the current routing configuration

route -n

Now we're going to start OpenVPN, and should see that the routes don't change. To aid in debugging, we're quickly going to disable the daemon declaration in the configuration

cd /root/VPNs/config/VPNs/Gateway/
sed -i 's/daemon/\#daemon/g' Gateway.conf
openvpn Gateway.conf

We should now see OpenVPN successfully establish a connection to the remote server,

Sat Jan 25 11:46:37 2014 [Gateway] Peer Connection Initiated with [AF_INET]1.1.1.1:1194
Sat Jan 25 11:46:39 2014 TUN/TAP device tun0 opened
Sat Jan 25 11:46:39 2014 do_ifconfig, tt->ipv6=0, tt->did_ifconfig_ipv6_setup=0
Sat Jan 25 11:46:39 2014 /sbin/ifconfig tun0 10.14.0.6 pointopoint 10.14.0.5 mtu 1500
Sat Jan 25 11:46:39 2014 Initialization Sequence Completed

The penultimate line contains informationt that we need to make a note of, we've been assigned IP 10.14.0.6 and our gateway is 10.14.0.5

We'll want to keep that connection open for the time being, so open another SSH connection.

 

Manually Adding A Route

Now we're going to add a route so that connections to www.whatismyip.com get routed via VPN. Let's start by verifying that we can connect

lynx -useragent "Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.15 (KHTML, like Gecko) Ubuntu/10.04 Chromium/18.0.996.0 Chrome/18.0.996.0 Safari/535.15" www.whatismyip.com

Note: The Useragent definition is needed as whatismyip appear to have blocked Lynx

We should find that our Home IP appears within the page;

   [Site Navigation_____________]
IP:
86.131.91.139

Now, we're going to force the connection through the VPN. First we need to establish the IP's that need to be routed

host www.whatismyip.com
 www.whatismyip.com has address 141.101.120.15
 www.whatismyip.com has address 141.101.120.14

So we want to route for 141.101.120.15 and 141.101.120.14. This is where the information we gleaned from our OpenVPN connection output becomes important, we need to use the gateway information to build our route

route add 141.101.120.15 gw 10.14.0.5
route add 141.101.120.14 gw 10.14.0.5

Now, if we connect via Lynx again, we should see the public IP of our VPN endpoint. To enable the same functionality for LAN clients, we just need to throw a quick NAT rule at iptables - this time rather than using the VPN gateway IP we're using the IP we were assigned

iptables -t nat -I POSTROUTING -d 141.101.120.14 -j SNAT --to-source 10.14.0.6

Any LAN Client using the Pi for routing (which, if you've followed Part Three, should be all of them) should now be able to access WhatIsMyIP.com and see the IP of the VPN endpoint

 

Automating The Process

We've achieved what we wanted to do, but via manual process. Really, we want the Pi to do the work of making sure the tunnels are open and assigning routes accordingly. 

The scripts we cloned from GitHub earlier do just that. So let's get them set up, start by disconnecting the OpenVPN session that we left open.

To begin with, let's put OpenVPN back into daemon mode, so in our configuration directory we need to run

sed -i 's/\#daemon/daemon/g' Gateway.conf

Next, we want to tell the management scripts about the connection

echo "Gateway" > /root/VPNs/config/VPNS

The next step is to schedule a monitor run to check the tunnels every 5 minutes

crontab -e
*/5 * * * * /root/VPNs/scripts/monitor_vpns.sh

If we wait a few minutes, we should see the VPN link come up

ps aux | grep openvpn
 root 7035 18.0 0.5 5548 2620 ? Ss 12:35 0:00 /usr/sbin/openvpn Gateway.conf

 

Adding IP's/Websites to the routing list

To add whatismyip, we performed a DNS lookup to get the relevant IP addresses. However, the add_vpn_routing_by_name script will allow us to simply pass the hostname. At time of writing we do need to supply some additional arguments - the Gateway IP to use and the IP to NAT from. Based on the commands we ran above these will be 10.14.0.5 and 10.14.0.6 respectively

/root/VPNs/scripts/add_vpn_routing_by_name.sh www.whatismyip.com 10.14.0.5 10.14.0.6

Whenever the rules are refreshed, a DNS lookup will be performed against whatismyip.com and the resulting IP's will be used to define the routing.

 

Alternatively, if we already know the IP (and are sure it won't change), we can use add_vpn_routing_by_ip. It takes the same arguments as the _by_name script, except that it expects an IP instead

/root/VPNs/scripts/add_vpn_routing_by_ip.sh 141.101.120.14 10.14.0.5 10.14.0.6

 

When Tunnels Go Down

Sometimes your VPN tunnels will go down, perhaps as a result of issues communicating with the OpenVPN server. When the tunnel collapses, the routes will be purged and clients will communicate with sites directly rather than over the VPN. Keep in mind then, that the methodology we've used here isn't really suitable if you're wanting to route over a VPN for purely security reasons.

 

In Part Five, We'll configure our Pi to accept inbound OpenVPN connections.