Black Hat Hackers, ISPs, evil governments, script kiddies, etc. get bored easily, and when they’re bored, they’re starting to look for things to play with. And a network with several million connected users is certainly an interesting thing to play with. Some of them might start intercepting the data on the network or do other nasty things with the packets that they can get.
If these packets are encrypted, messing with them is much harder (but not impossible! – see the end of this article). So you want your packets to be always encrypted. And the best way to do that is by using a VPN.
Of course, if your VPN server is located in some unsafe place, this guide won't magically save you from all bad things. So make sure to get a good server first.
Please note that this guide is written for users who are at least a bit tech-savvy. In case you don’t know what a VPN is or don’t feel comfortable doing the things I suggest in this guide (for example because you don’t understand anything at all), please contact a hacker you trust and ask them to make your connection more secure. Please don’t ask me (except if we know each other personally), because I don’t have the time to do user support for thousands of guests.
The machine I’m using is a MacBook Pro with OS X El Capitan, and the software I use is Tunnelblick for the OpenVPN connection and PF (“packet filter”) to transmit as little unencrypted traffic as possible when the VPN goes down. And the focus of this guide is definitely that second part, because setting up the VPN is pretty easy, but if the connection breaks, is blocked or for some other reason not running, your system will by default transmit data anyway, and unencrypted data will be interceptable. So what I basically do is to forbid nearly all network traffic (using PF), except for the things that are required to connect to the VPN. PF is OS X’s recommended way of filtering packets and available in Lion or higher, afaik.
So, what do we need in order to connect to the VPN?
- Internet access. This means we should allow DHCP (for getting an IP address).
- DNS, if we don’t want to connect to the VPN by IP address. I’m using some server with static IP, so I don't need DNS.
- A connection to the VPN server(s) on whatever port the VPN uses. I’m using OpenVPN on an UDP port, and I highly recommend that you don’t use a TCP-based VPN connection. (Else, people might(?) be able to do evil things with DNS spoofing and SRV records.)
The config I use has several drawbacks:
- I completely disable IPv6. Yes, some of you will be outraged about that, and rightly so. But I find it rarely used, and I don't want to spend time configuring and testing it. Maybe after a few years I'll update this for IPv6.
- There’s no automatic detection whatsoever whether OpenVPN is running, so if you want to use the Internet without the VPN again, you’ll need to explicitly disable PF.
- It will most likely not work with so-called "Captive portals" used in many public Wi-Fi access points, for obvious reasons. I currently don't see an easy fix for that, other than temporarily manually disabling PF (dangerous!).
There’s a nice guide that explains the PF setup on OS X, and I’m not doing anything more than that here. A tutorial on PF itself, which is a OpenBSD project, is available as well.
I’m using Tunnelblick as my OpenVPN GUI. Set up your OpenVPN server, get a client certificate and the ovpn config, create the one-file client config (*.ovpn) so that it will have certificate bundled, open that in Tunnelblick, make sure that you enable “route all traffic through the VPN” in the “while connected” tab of the advanced settings. According to the Tunnelblick documentation, this is equivalent to the OpenVPN option --redirect-gateway def1
.
I found Tunnelblick (3.3) to be kind of unstable on my machine. Sometimes I had to terminate OpenVPN myself (using sudo killall openvpn
) because it wouldn’t reconnect and Tunnelblick wasn’t able to terminate it. But since the PF rules protect me from unencrypted communication, I don’t really care.
If you fuck up your firewall rules, you might end up in a situation where you can’t even google how to fix things again. Therefore, keep this command in mind: sudo pfctl -d
. It will completely disable PF.
There’s a default PF configuration file, /etc/pf.conf
, and I suggest you don’t modify it. Instead, write your own. Mine is /etc/pf.magicgoose.conf
.
In that file, you need to define one or more anchors which contain the actual rules. Therefore, my config file only contains these two lines:
anchor "magicgoose.pf"
load anchor "magicgoose.pf" from "/etc/pf.anchors/magicgoose"
Use something unique for the anchor name. The suggested way is to use a reversed domain, so if you own flauschmett.de, your anchor could be named de.flauschmett.pf. I decided to violate this rule, though.
The really interesting part of the configuration is what’s written in the anchor file, /etc/pf.anchors/magicgoose
in my case. Since that file is a bit longer and contains lots of comments (which is a good thing), it's in a separate file in the gist (the next file).
Run sudo pfctl -v -n -f /etc/pf.magicgoose.conf
to check the config for errors, and sudo pfctl -e -f /etc/pf.magicgoose.conf
to actually load it.
I guess you’ll want your PF settings to survive a reboot, so you need to add a launchd item for it. This is simply an XML file that you place in /Library/LaunchDaemons
. Note that it must be owned by root in order to do anything at all.
Do something like sudo nano -w /Library/LaunchDaemons/magicgoose.pf.plist
(pay attention to the .plist
extension) and paste the text from the third file in the gist (same name) there.
Please note that this might not work. The article I’ve linked to above suggests doing it this way, but on my machine /var/log/pf.log
contained the error message
pfctl: DIOCADDRULE: Resource busy
and the rules were not loaded. So please double-check if your PF rules have been loaded, and load them manually, if necessary. If you reboot and something starts syncing without the VPN running, you’re doing it wrong. ;)
I currently don’t know why this is happening, and certainly not how to fix it. Sorry.