How to set up an OpenWRT router/gateway as an IPsec/L2TP gateway for Andoid and iPhone clients
The only "reasonable" (that is, not counting PPTP due to its known security issues) VPN protocol supported by default on non-rooted / non-jailbroken Android / iPhone phones as clients is the combination of IPsec and L2TP. Most probably, this was chosen due to its out-of-the-box support by newer Windows clients and MacOS/X as well.
The set-up described on this page therefore focussed on setting up a Linux VPN server to act as a gateway for Android and iPhone clients without additional software installations on the mobile phones. For convenience, I chose OpenWRT as the gateway Linux distribution to be able to run the gateway on my old Asus WL-500G Premium (v1) WLAN router (which has sufficient internal flash and RAM to support such use-cases as well as hardware-accelerated crypto support).
Most of the information on this page has been copied from various sources, most notably Jacco de Leeuw's excellent tutorial page, which he has been updating for years already, and taking some hints from here concerning Android and X.509 certificates. We had previous contact in terms of Debian support of L2TP in my openswan and strongswan packages, and he has a lot of experience with corner cases in different clients. Thanks to Jacco for his continuous efforts.
Client authentication is typically performed in two stages:
- IPsec authenticated the "outer" transport mode connection, either via
- pre-shared key (PSK) or
- X.509 certificates (with corresponding private keys on the gateway and the clients)
- L2TP invokes an inner PPP tunnel, which then authenticates based on user/password combination, most typically via the MSCHAP-v2 challenge-response protocol.
Many clients either don't support X.509 certificate authentication or make it hard to set up. Therefore, I will start with PSK IPsec authentication.
At the time of this writing, the newest OpenWRT release is "backfire" (10.03), and on the Asus WL-500GP I chose the newer kernel 2.6 with the bcrm47xx target image. Starting with the default install, the following packages need to be added (e.g. using opkg on the shell or the LuCi package management interface):
- kmod-ocf-ubsec-ssb for hardware-accelerated crypto support
- openswan as IPsec IKE daemon
- ipsec-tools for the "setkey" command
- xl2tpd as L2TP server (there are multiple L2TP server implementations available, I chose x2ltpd because of known-good integration with openswan and because it is being actively maintained)
- iptables-mod-ipsec kmod-ipsec4 kmod-ipsec6 kmod-ipt-ipsec for kernel support modules.
If, in addition to the IPsec/L2TP protocol, another option with sometimes better NAT traversal support is desired, then I recommend OpenVPN (which has clients for most operating systems). For OpenVPN support, the following packages are installed on OpenWRT:
- luci-app-openvpn for a simple administration interface
- openvpn-easy-rsa for certificate management
The first part to configure is IPsec in the form of openswan /etc/ipsec.conf file. Simply add a block:
conn L2TP-PSK authby=secret pfs=no compress=no rekey=no keyingtries=3 type=transport left=%defaultroute leftnexthop=%defaultroute leftprotoport=17/1701 right=%any rightsubnet=vhost:%no,%priv rightprotoport=17/%any auto=add
and exclude the locally used network from virtual_private in the config setup block, if it is a "private" address range, e.g.:
for a local address range of 172.17.2.0/24.
The specific configuration options are documented in detail in the ipsec.conf manual page, and are thus not repeated here. In essence, this block adds an IPsec policy for PSK-authenticated connections that only allow UDP port 1701 (L2TP), but from any source address connecting via the gateway default route.
Then, the PSK is configured in /etc/ipsec.secrets (which may not exist on a default installation and needs to be created):
%any %any : PSK "your super secret password here"
To automatically start the IPsec service on bootup, first create a file /etc/modules.d/99-local-ipsec:
af_key ipcomp4 esp4 ah4 tunnel4 xfrm_mode_tansport xfrm_tunnel xfrm_ipcomp
and create a symlink to start openswan pluto with ln -s /etc/init.d/ipsec /etc/rc.d/S99ipsec.
Next, to configure the L2TP server, edit /etc/xl2tpd/xl2tpd.conf to read like this:
[global] port = 1701 ;auth file = /etc/xl2tpd/xl2tp-secrets access control = no ipsec saref = yes [lns default] exclusive = yes ip range = 172.17.2.192-172.17.2.254 local ip = 172.17.2.191 ;hidden bit = no length bit = yes name = VPNServer ppp debug = yes require authentication = yes unix authentication = no require chap = yes refuse pap = yes pppoptfile = /etc/ppp/options.xl2tpd
The PPP options file /etc/ppp/options.xl2tpd should contain these options:
# CCP seems to confuse Android clients, better turn it off
where the local IP addresses and ranges in both files will obviously need to be adapted. Note that all addresses should be within the local network to which the L2TP server provides access. User names and passwords are configured in /etc/ppp/chap-secrets without any special considerations, including the possibility to specify static IP addresses for users.
Also create a symlink to start xl2tpd with ln -s /etc/init.d/xl2tpd /etc/rc.d/S99xl2tpd.
Finally create a firewall rule (e.g. via LuCi) to allow access from the WAN interface to UDP port 500 and 4500 as well as the ESP protocol. A more specific rule to allow L2TP traffic from the WAN interface only when encrypted with IPsec can not be set in the interface, and therefore must be entered manually e.g. in /etc/firewall.user:
iptables -A input_wan -m policy --strict --dir in --pol ipsec --proto esp -j ACCEPT
Using strongSwan on an Alix 2D13 AMD Geode board
As an alternative to an OpenWRT installation running on a common (typically ARM or MIPS based) access point, I also use my own Gibraltar firewall Linux distribution running e.g. on Alix 2D13 embedded network appliance boards with AMD Geode CPUs. The only catch here is that strongSwan needs to be compiled with support for the IPsec transport mode (in combination with NAT traversal). This requires the configure option --enable-nat-transport, which is disabled by default. My Debian packages enable this option starting with version 4.5.0-1, and Gibraltar version 3.1 includes updated packages with this option enabled.
As mobile devices typically only support IKEv1 but not IKEv2 at the time of this writing, plutostart=yes is required in the config setup section of ipsec.conf for strongSwan. All other configuration options (e.g. the conn section or the xl2tpd configuration) are equal to the ones for OpenWRT as described above.
For improved performance specifically with AMD Geode CPUs, load the geode_aes kernel module for hardware AES acceleration (128 bits only, though).
On Android clients, simply use the supplied settings screen to create an IPsec/L2TP connection, specifying the PSK, username, password, and obviously the server hostname or IP address. This will allow to connect the Android client and get an internal IP address.
Unfortunately, at the time of this writing, testing with an HTC Desire and the stock Android 2.2 ROM leads to automatic disconnects after 10s when connecting to the OpenWRT gateway, seemingly initated by the Android device ('rcvd [LCP TermReq id=0x3 "User request"]' is printed in the server log). I am still searching for this issue. However, the connection works well and is not terminated automatically when connecting from the same mobile phone to a Gibraltar firewall 3.1 with strongswan 4.4.1-6, xl2tpd 1.2.0+dfsg-1, and ppp 2.4.4rel-10.1 Debian packages.
Update: The problem with disconnects after 10s is not specific to the OpenWRT setup, but is caused by openswan! With exactly the same configuration for openswan/strongswan and xl2tpd on a fresh Debian Squeeze i386 installation, strongswan 4.4.1-6 works (no disconnects), but openswan 2.6.35-1 does not (both using NETKEY with the default 2.6.32-5-686 kernel on Debian Squeeze). It seems that openswan pluto is buggy in combination with Android and L2TP, although I do not yet know if this is specific to the NETKEY stack. I will have to try strongswan under OpenWRT to verify that strongswan+xl2tpd work independently of the platform.