Captive Portal Bypass Howto

As described in CaptivePortalInsecurities, you can bypass a captive portal by tunneling IP over UDP/53 which almost always is open. This page will give you step-by-step instructions on how to do this using OpenVPN.

First, some assumptions:

OpenVPN Server

You need a *nix box somewhere that is internet accessible and is running OpenVPN. Create your keys with ids like client100, client101, ..., client199. Then some configuration like the following should work. Remember to replace w.x.y.z with your server's external IP.

You'll need to make the tap0 interface. If you use a debian derivative, that means adding a clause to /etc/network/interfaces like this:

auto tap0
iface tap0 inet static
address 10.11.254.1
netmask 255.255.255.0
broadcast 10.11.254.255
network 10.11.254.0

/etc/openvpn/server.conf

local w.x.y.z
port 53
proto udp
dev tap0
ca /etc/openvpn/crypto/ca.crt
cert /etc/openvpn/crypto/server.crt
key /etc/openvpn/crypto/server.key
dh /etc/openvpn/crypto/dh1024.pem
server-bridge 10.11.254.1 255.255.255.0 10.11.254.100 10.11.254.200
ifconfig-pool-persist /etc/openvpn/ipp.txt
client-to-client
keepalive 10 120
max-clients 100
comp-lzo
up /etc/openvpn/route.up

/etc/openvpn/route.up

echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -F POSTROUTING -t nat
iptables -A POSTROUTING -t nat -s 10.11.254.0/24 -o eth0 -j SNAT --to-source 67.102.171.61

OpenVPN Client

On the client side, you'll need to copy over the certificates and use a config like this:

/etc/openvpn/client.conf

client
remote w.x.y.z
dev tap
ca /etc/openvpn/ca.crt
cert /etc/openvpn/client100.crt
key /etc/openvpn/client100.key
comp-lzo
port 53

And, you'll need to fix your routing table to pass all traffic besides the openvpn traffic itself through the tunnel. First, look at your current routing table, maybe it looks like this:

$ ip route

10.11.49.192/26 dev eth1  proto kernel  scope link  src 10.11.49.228 
10.11.254.0/24 dev tap0  proto kernel  scope link  src 10.11.254.100 
default via 10.11.49.193 dev eth1 

We can see that our default route is 10.11.49.193. So, we can do:

$ ip route add w.x.y.z via 10.11.49.193
$ ip route del default
$ ip route add default via 10.11.254.1

This accomplishes our goal, and now, we can access the internet, satisfied that all of our traffic is being encapsulated in an encrypted tunnel and then emitted at our remote server. Yay.

Fix Me

Add client-side instructions for silly people who don't use linux and friends.