My Iptables trick

Tell what you want about Linux, but it is malleable. For several years now I’ve been relying on a VPN setup based on my virtualized apps configuration that makes use of one simple but elegant Iptables trick. Essentially, the whole thing is a VirtualBox VM running Ubuntu with OpenVPN, Firefox, and Transmission installed. Keeping the VPN connection isolated from my primary OS allows me to separate any anonymous browsing from more humdrum network activities. To give you a (purely theoretic) example: when I visit my family in Russia, I don’t want my personal e-mails to go through the same VPN server I use to access a government-blocked website (don’t get too excited, as it can be as boring as LinkedIn).

A screenshot of VirtualBox with full screen Firefox running in it. The Google search results page is opened in the browser tab. It shows that the user’s current location is Iceland.
VPN in a box

All things considered, accidentally directing personal, identifiable traffic through a 3rd party VPN server is a relatively rare concern. For most VPN users, a more prominent fear is sending the packets purported for the VPN through your regular network interface in case of a sudden VPN connection breakage. Some VPN clients support kill-switches that shut down the network should the worst happen, but that only helps if you do intend to use the VPN server for the entirety of your traffic. Otherwise, this is where my little Linux trick comes in.

The Linux kernel exposes various ways of filtering network packets via the iptables frontend. Whereas the ability to match packets by port number or interface is well-known, other options such as filtering by originating process ID (PID) or user ID (UID) aren’t as commonly used. Since the sole purpose of my VM is to access the web via VPN, I’ve configured iptables to filter all outgoing packets to the default network interface sent by my login user. This covers all network protocols (TCP, UDP, etc.) and in practice means that when I power up my VPN VM, I have no network access until the root establishes a VPN connection. If that connection goes down, the firewall will prevent me from sending anything through the default interface. All this can be achieved by running a single command as your login user:

; Replace eth1 with your primary network interface
; `id -u $USER` returns the UID of your user. Replace with explicit number if needed.

sudo iptables -A OUTPUT -o eth1 -m owner --uid-owner `id -u $USER` -j DROP

One nice side effect of this configuration is that I can still update the system and install new packages without having to connect to the VPN first, just because apt runs as root. The configuration isn’t limited to single-purpose VMs, but can also be adopted by Linux users who rely on VPN for all their Internet activities. Try it, and never worry about leaked traffic on a public WiFi again.

I’m sure none of this will be a revelation to an experienced UNIX administrator who has managed multi-user systems and had to fine-tune user permissions and network access. But, coming from the world of single-purpose servers and single-user desktop machines, I’m nevertheless fascinated to be reminded of the multi-user systems legacy (and associated tooling) carried by modern Linux systems. And yes, there’s something to be said for the appeal of one-liners.