One of the coolest features of the iPhone is the way it uses the best data network that it can find. If you’re at home or at work, or even at a coffee shop, it will use the local wifi network. But if you’re out of range of any suitable wifi networks, it will use AT&T’s “3G” (UMTS) network. And if it can’t find a UMTS network, it’ll fall back to EDGE. Phone companies call this hybrid approach “ABC”, or “always best connection”.

Now that I have an internet device in my pocket, I find myself using public (or otherwise open) wifi connections quite a bit. And this carries with it some unintended consequences. That is… everything I type and everything I read is transmitted in the clear, unencrypted.

I try to make a habit of encrypting my data traffic whenever possible. My mail server is set up to only allow SSL connections. So no matter where I check my mail from, I am forced to use an encrypted connection. Similarly, banks and commerce web sites usually force you to switch to HTTPS before you start entering information. But there are a lot of applications on the iPhone that do not use encryption at all.

You might ask yourself why bother to encrypt your Twitter connection, since what you type is going to be blasted out to the world anyway. But the point is…

If you encrypt everything, then nothing is left to chance.

So I decided to explore a VPN option on the iPhone. It supports three flavors of VPN: L2TP, PPTP and IPSec. I was disappointed (but not surprised) that “openvpn” was not an option, since I already use this excellent open source SSL-based VPN package.

So I decided to give PPTP a try.

Setting up the PPTP server

On my Ubuntu 8.04 LTS server, I installed a PPTP server called, appropriately enough, “pptpd“. Configuration was very easy. Most of the setup was done for me after I did the standard apt-get install pptpd. I simply needed to pick a private subnet that would be used for my VPN clients, and an IP address in that subnet to use for the server. I chose the 172.16.4.0/16 subnet and 172.16.4.1 for the server (these addresses are part of a private network address space, defined by RFC 1918, just like 192.168.x.x and 10.x.x.x addresses).

My /etc/pptp.conf configuration file for the pptp daemon looks like this:

option /etc/ppp/pptpd-options
logwtmp
localip 172.16.4.1
remoteip 172.16.4.2-250

I also needed to tell the daemon to give out some DNS addresses when a client connects, so in the /etc/ppp/pptpd-options file, I added the two “ms-dns” lines below:

name pptpd
refuse-pap
refuse-chap
refuse-mschap
require-mschap-v2
require-mppe-128
ms-dns 208.67.222.222  # resolver1.opendns.com
ms-dns 208.67.220.220  # resolver2.opendns.com
proxyarp
nodefaultroute
lock
nobsdcomp

Finally, I needed to add an entry into the /etc/ppp/chap-secrets file that would contain my password. Mine looks like this:

alan pptpd MyHardToGuessPassword *

At this point, the PPTP server was completely configured, so I restarted it with service pptpd restart.

Setting up the iPhone

On the iPhone, I needed to set up a VPN client. This is very easy. On the settings screen, go to general / network / VPN and “Add VPN Configuration…”. Then just fill in the blanks.

  • choose “PPTP”
  • enter a description
  • your server’s IP address
  • the username (from above)
  • RSA SecurID=OFF
  • the password (from above)
  • encryption level = Auto
  • “Send All Traffic” = ON
  • Proxy = OFF

Click on “Save” and you will see a switch in the network tab and also in the main settings tab to turn the VPN on and off.

For now, I am leaving it off unless I am on a public network. I am not sure, but I think that keeping the VPN alive might use a lot of battery. So I do not use it unless I need it.

Networking

For me to get this VPN on the internet, I had to do two more things: punch a hole in my firewall for the PPTP traffic, and forward traffic from my VPN out to the rest of the world.

For my server, both of these tasks were handed by the same tool: shorewall.

I added a “masquerade” rule to /etc/shorewall/masq to NAT all of the traffic from 172.16.4.x out through my main network interface.

eth0         172.16.4.0/24    # OpenVPN and PPTP

And then I added two rules to /etc/shorewall/rules to allow the PPTP traffic in.

ACCEPT  net  fw   tcp  1723  # PPTP
ACCEPT  net  fw   gre        # PPTP

When shorewall starts, it will generate the iptables rules that are used by the kernel to filter packets. If you’re using hand-written iptables rules, then you will need some rules that look something like this:

# accept "gre" protocol traffic (PPTP tunnel traffic)
iptables -A INPUT -p gre -j ACCEPT
iptables -A OUTPUT -p gre -j ACCEPT
# accept PPTP control traffic to TCP port 1723
# (my server IP is 11.22.33.44)
iptables -A INPUT -p tcp --sport 1723 -s 11.22.33.44 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 1723 -d 11.22.33.44 -j ACCEPT
# masquerade/NAT internet traffic out of interface eth0
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
# turn on packet forwarding
echo "1" > /proc/sys/net/ipv4/ip_forward

Conclusion

Now, when I am in a coffee shop, I can turn on the VPN easily by flipping the switch in the iPhone’s main settings screen. It will make a TCP connection to my server, negotiate a few things, and then send all further network traffic through an encrypted tunnel directly to my server, which relays it out to the internet.

You can test this by going to a web site like http://www.whatismyip.com/. If the VPN is working, it will show your server’s IP address. If not, it’ll show the coffee shop’s IP address.

Once I am using the VPN, anyone in the coffee shop who happens to be sniffing traffic on the wireless network will only see a single connection from my iPhone to my server, but the contents of this connection will be scrambled.