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
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)
# Put your OpenVPN client keys in here - if you've got a config file then put it here as Gateway.conf.
ca.crt lan.crt lan.csr lan.key Gateway.conf
Our next step is to edit (or create) the configuration file.
# If this is a new file, you want to add the following
remote [YOUR VPN SERVER IP] 1194
# These are the two definitions we want to add if your file already existed
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
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
sed -i 's/daemon/\#daemon/g' 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]184.108.40.206: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;
Now, we're going to force the connection through the VPN. First we need to establish the IP's that need to be routed
www.whatismyip.com has address 220.127.116.11
www.whatismyip.com has address 18.104.22.168
So we want to route for 22.214.171.124 and 126.96.36.199. 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 188.8.131.52 gw 10.14.0.5
route add 184.108.40.206 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 220.127.116.11 -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
*/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 18.104.22.168 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.