The iPhone 3G firmware is really open to the world via 3G or Wi-Fi. Compared to Wi-Fi, mobile networks are quite secure. Warning, I never said that they are bullet-proof, but tapping a mobile network requires much more resources than Wi-Fi! Wireless network are widely available, which make them a good target for hackers!
On the iPhone, common applications can be secured (HTTPS in Safari and the mail client support SSL encryption) but the remote server must offer SSL services! Fortunately, the iPhone supports VPN! Three types of VPN are available: IPSEC, L2TP and PPTP. In this case, to protect our personal information, why not encrypt all the traffic through a VPN session established with a remote server? Let’s go!
I decided to use PPTP (“Point-to-Point Tunnel Protocol“) to setup my VPN with a Linux box. PPTP became obsolete by new VPN solutions and relies on other protocols to provide authentication and encryption but is very easy to install on a Linux server. PPTP works with two sessions: a TCP session to port 1723 to initialize and manage the connection and a GRE tunnel to encapsulate PPP packets. The PPP packets are encrypted using the MPPE “Microsoft Point-to-Point Encryption“) protocol.
Warning: Some firewall or access points may not forward GRE packets!
PPTP Server Setup
My Linux runs a stock Debian distribution. To install the PPTP server, just install the package:
# apt-get install pptpd
If needed, fix your firewall to accept incoming traffic on port TCP/1723 and GRE protocol
# /sbin/iptables -A INPUT -i eth0 -p tcp --dport 1723 -j ACCEPT # /sbin/iptables -A INPUT -i eth0 -p 47 -j ACCEPT
The PPTP server relies on a single configuration file “/etc/pptpd.conf“. The default settings should work out of the box. The only thing to care of is the IP address attribution (which cannot conflict with your existing IP networks). Fix them to match your network:
localip 192.168.0.1 remoteip 192.168.0.234-238,192.168.0.245
As pptpd spawns a ppp process. The following modules must be available:
# lsmod | grep ^ppp ppp_async 6496 0 ppp_generic 13556 1 ppp_async ppp_mppe 5643 0
Normally they are installed in a standard kernel distribution. Mine is a bit exotic (Debian running on a Cobalt server).
VPN Users Setup
Now, create your VPN users. Authentication is performed by PPP. Add users accounts with the following command:
# echo "<username> pptpd <password> *" >>/etc/ppp/chap-secrets
Be sure to set safe access right to this file! If you have a lot of users, consider using another authentication method such as RADIUS.
Setup Routing and NAT
We need to enable IPv4 forwarding and NAT on the PPTP server. All packets coming from the iPhone will be translated to the server IP address to access the Internet.
# echo 1 >/proc/sys/net/ipv4/ip_forward # iptables -t nat -A POSTROUTING -o eth0 -s 192.168.0.0/24 \ -j SNAT --to <serverip>
Customize the commands above according to your environment and put them in your init scripts to survive to a reboot.
iPhone Configuration
Tap on “Settings”, “VPN” and “Add VPN Configuration”. Select “PPTP” as VPN type, and fill all the required fields:
- Description : My_PPTP_VPN
- Server : IP address or hostname of your PPTP server
- Account : The login configured in /etc/ppp/chap-secrets
- RSA SecurID : Off
- Password : You know what!
- Encrpyion Level : Auto
- Sent All Traffic : On
Save and slide the VPN switch to “On”. Your iPhone will setup the VPN. Once successfully done, use your applications as usual. Everything will be encrypted up to your Linux server!
Here is a successful connection as seen from the Linux side in debug mode:
pptpd[27539]: MGR: Launching /usr/sbin/pptpctrl to handle client pptpd[27539]: CTRL: local address = 192.168.0.1 pptpd[27539]: CTRL: remote address = 192.168.0.234 pptpd[27539]: CTRL: pppd options file = /etc/ppp/pptpd-options pptpd[27539]: CTRL: Client 81.169.73.7 control connection started pptpd[27539]: CTRL: Received PPTP Control Message (type: 1) pptpd[27539]: CTRL: Made a START CTRL CONN RPLY packet pptpd[27539]: CTRL: I wrote 156 bytes to the client. pptpd[27539]: CTRL: Sent packet to client pptpd[27539]: CTRL: Received PPTP Control Message (type: 7) pptpd[27539]: CTRL: Set parameters to 100000000 maxbps, 64 window size pptpd[27539]: CTRL: Made a OUT CALL RPLY packet pptpd[27539]: CTRL: Starting call (launching pppd, opening GRE) pptpd[27539]: CTRL: pty_fd = 6 pptpd[27539]: CTRL: tty_fd = 7 pptpd[27540]: CTRL (PPPD Launcher): program binary = /usr/sbin/pppd pptpd[27540]: CTRL (PPPD Launcher): local address = 192.168.0.1 pptpd[27540]: CTRL (PPPD Launcher): remote address = 192.168.0.234 pppd[27540]: Plugin /usr/lib/pptpd/pptpd-logwtmp.so loaded. pptpd[27539]: CTRL: I wrote 32 bytes to the client. pptpd[27539]: CTRL: Sent packet to client pppd[27540]: pppd 2.4.4 started by root, uid 0 pppd[27540]: Using interface ppp0 pppd[27540]: Connect: ppp0 <--> /dev/pts/3 pptpd[27539]: GRE: Bad checksum from pppd. pptpd[27539]: GRE: Bad checksum from pppd. pptpd[27539]: CTRL: Received PPTP Control Message (type: 15) pptpd[27539]: CTRL: Got a SET LINK INFO packet with standard ACCMs pptpd[27539]: GRE: buffering packet #1 (expecting #0, lost or reordered) pptpd[27539]: GRE: buffering packet #2 (expecting #0, lost or reordered) pptpd[27539]: GRE: timeout waiting for 1 packets pptpd[27539]: GRE: accepting #1 from queue pptpd[27539]: GRE: accepting #2 from queue pptpd[27539]: GRE: accepting packet #3 pptpd[27539]: GRE: accepting packet #4 pptpd[27539]: GRE: accepting packet #5 pptpd[27539]: GRE: accepting packet #6 pppd[27540]: kernel does not support PPP filtering pptpd[27539]: GRE: accepting packet #7 pptpd[27539]: GRE: accepting packet #8 pptpd[27539]: GRE: accepting packet #9 pptpd[27539]: GRE: accepting packet #10 pptpd[27539]: GRE: accepting packet #11 pptpd[27539]: GRE: accepting packet #12 pptpd[27539]: GRE: accepting packet #13 pppd[27540]: Cannot determine ethernet address for proxy ARP pppd[27540]: local IP address 192.168.0.1 pppd[27540]: remote IP address 192.168.0.234 pptpd[27539]: GRE: accepting packet #14 pptpd[27539]: GRE: accepting packet #15 pptpd[27539]: GRE: accepting packet #16 pptpd[27539]: GRE: accepting packet #17 pptpd[27539]: GRE: accepting packet #18 pptpd[27539]: GRE: accepting packet #19 pppd[27540]: LCP terminated by peer (User request) pppd[27540]: Connect time 0.3 minutes. pppd[27540]: Sent 0 bytes, received 1450 bytes. pptpd[27539]: CTRL: EOF or bad error reading ctrl packet length. pptpd[27539]: CTRL: couldn't read packet header (exit) pptpd[27539]: CTRL: CTRL read failed pptpd[27539]: CTRL: Reaping child PPP[27540] pppd[27540]: Modem hangup pppd[27540]: Connection terminated. pppd[27540]: Exit. pptpd[27539]: CTRL: Client 81.169.73.7 control connection finished pptpd[27539]: CTRL: Exiting now pptpd[31956]: MGR: Reaped child 27539
Have a look at the Debian Wiki: http://wiki.debian.org/HowTo/iPhoneVPNServer. This describes how to implement a VPN server using the L2TP over IPsec protocol.
Anyone still monitoring this thread! I’m having an issue getting more than one user/session connected. Firewall isn’t complaining so I’m assuming I may have a max user/session command missing from the PPTPD configuration. Any ideas on how to correct this?
I found it necessary to make sure ms-dns was not commented out , and was set to a DNS server that made the iphone happy. Eg, the same DNS server the machine running pptpd is using.
Without this, the iphone VPN would start, but DNS resolution would not work. It would appear that the VPN was not working, but you could visit a website by IP address. The DNS server you had before you enable the VPN is ignored when the VPN is enabled and unless the iphone is told the new DNS server, it doesn’t know what to use.
aye – that it is 🙂
read up on it on the poptop pages (etc). i reckon it’s down to iptables now. having said that, i haven’t restarted networking yet though, as i’m trying this on a remotely hosted box in a data center (which is probably a bad idea but i forgot to turn on my home machine before i left home)… .
Is routing enabled in the Linux box?
(echo 1 >/proc/sys/net/ipv4/ip_forward)
right, I can access my web server running on the machine I’m connected to (192.168.0.1).
my iptables looks like this:
Chain INPUT (policy ACCEPT)
target prot opt source destination
DROP all — yx-out-f136.google.com anywhere
ACCEPT all — anywhere anywhere
ACCEPT all — anywhere anywhere
ACCEPT all — anywhere anywhere
ACCEPT icmp — anywhere anywhere icmp any
ACCEPT all — anywhere anywhere state RELATED,ESTABLISHED
ACCEPT tcp — anywhere anywhere tcp dpt:www state NEW
ACCEPT tcp — anywhere anywhere tcp dpt:https state NEW
ACCEPT tcp — anywhere anywhere tcp dpt:7742 state NEW
ACCEPT tcp — anywhere anywhere tcp dpt:ftp state NEW
REJECT all — anywhere anywhere reject-with icmp-port-unreachable
ACCEPT tcp — anywhere anywhere tcp dpt:1723
ACCEPT gre — anywhere anywhere
Chain FORWARD (policy ACCEPT)
target prot opt source destination
REJECT all — anywhere anywhere reject-with icmp-port-unreachable
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all — anywhere anywhere
I’ve added “iptables -t nat -A POSTROUTING -o eth0 -s 192.168.0.0/24 -j SNAT –to 82.***.***.***” but nothing seems to be showing in the iptables config?
argh. ok I’m being very silly this morning. vpn was off…
no traffic in tcpdump and debug log looks fine.
no idea why safari thinks it’s got no connection 🙁
Nothing much happening. Safari simply says it’s not connected to the Internet.Belay that. All working now. No idea why. Oh – not to self: turn of the “auto proxy discovery” in the VPN settings on the iPhone 😉
Thanks Xavier. Your tutorial saved me a lot of reading and googling.
Hi Axel,
When you try to access the website, run a tcpdump on your Linux box. Do you see traffic? Running the pptpd in debug mode can also help sometimes.
Regarding Windows XP, no idea 🙁
Hi Xavier, thanks for this! Works on my iPhone 3G/S 3.0 🙂
However, I cannot browse the web.
Also, how can I connect from a Windows XP box? I’ve played with several settings but it hangs on the authentication stage.
Thanks in advance.