I have had recently the pleasure and challenge of setting up VPN server for mobile devices on top of Linux. the common method to do so would be by using IPSec + L2TP, as these are to more common methods mobile devices allow, and it should work quite fine with other types of clients (although I did not test it) like Linux, Windows and Mac.
I have decided to use PSK (Pre Shared Key) due to its relative simplicity when handling multiple clients (compared to managing certificate per-device), and its relative simplicity of setup.
My VPN server platform is Linux, x86_64 (64 bit), Centos 6. Latest release, which is for the time being 6.3 and some updates.
I have used the following link as a baseline, and added some extra about IPTables, which was a little challenge, where I wanted good-enough security around this setup.
Initially, I wanted to use OpenSWAN, however, it does not allow easy integration with dynamic IP address, and its policy, while capable of being very precise, was not flexible enough to handle varying local IP address.
First – Add the following two repositories: Nikoforge, for Racoon (ipsec-tools), and EPEL for xl2tpd.
You can add them the following way:
rpm -ivH http://repo.nikoforge.org/redhat/el6/nikoforge-release-latest
yum -y install http://vesta.informatik.rwth-aachen.de/ftp/pub/Linux/fedora-epel/6/i386/epel-release-6-7.noarch.rpm
yum -y install ipsec-tools xl2tpd
Following that, create a script called /etc/racoon/init.sh:
# set security policies
echo -e "flush;\n\
spdadd 0.0.0.0/0 0.0.0.0/0 udp -P in ipsec esp/transport//require;\n\
spdadd 0.0.0.0/0 0.0.0.0/0 udp -P out ipsec esp/transport//require;\n"\
| setkey -c
# enable IP forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward
Make sure this script allows execution, and add it to /etc/rc.local
Racoon config /etc/racoon/racoon.conf looks like this for my setup:
path include "/etc/racoon";
path pre_shared_key "/etc/racoon/psk.txt";
path certificate "/etc/racoon/certs";
path script "/etc/racoon/scripts";
The PSK is kept inside /etc/racoon/psk.txt. It looks like this for me (changed password, duh!):
Both said files (/etc/racoon/racoon.conf and /etc/racoon/psk.txt) should have only-root permissions, aka 600.
Notice the bold myHome identifier. As the local address might change (either ppp dialup, or DHCP client), this one will be used instead of the local address identifier, as the common identifier of the connection. For Android devices, it will be defined as the ‘IPSec Identifier’ value.
We need to setup xl2tpd: Edit /etc/xl2tpd/xl2tpd.conf and have it look like this:
debug tunnel = no
debug state = no
debug network = no
ipsec saref = yes
force userspace = yes
ip range = 18.104.22.168-22.214.171.124
local ip = 126.96.36.199
refuse pap = yes
require authentication = yes
name = l2tpd
ppp debug = no
pppoptfile = /etc/ppp/options.xl2tpd
length bit = yes
The IP range will define the client VPN interface address. The amount should match the expected number of clients, or be somewhat larger, to be on the safe side. Don’t try to be a smart ass with it. Use explicit IP addresses. Easier that way. The “local” IP address should be external to the pool defined, or else a client might collide with it. I haven’t tried checking if xl2tpd allowed such configuration. You are invited to test, although it’s rather pointless.
Create the file /etc/ppp/options.xl2tpd with the following contents:
The ms-dns option should specify the desired DNS the client will use. In my case – I have an internal DNS server, so I wanted it to use it. You can either use your internal, if you have any, or Google’s 188.8.131.52, for example.
Almost done – you should add the relevant login info to /etc/ppp/chap-secrets. It should look like: “username” * “password” * . In my case, it would look like this:
# Secrets for authentication using CHAP
# client server secret IP addresses
ez-aton * “SomePassw0rd” *
Select a good password. Security should not be taken lightly.
We’re almost done – we need to define IP forwarding, which can be done by adding the following line to /etc/sysctl.conf:
# Controls IP packet forwarding
net.ipv4.ip_forward = 1
and then running ‘sysctl -p’ to load these values.
Run the following commands, and your system is ready to accept connections:
chkconfig racoon on
chkconfig xl2tpd on
service racoon start
service xl2tpd start
That said – we have not configured IPTables, in case this server acts as the firewall as well. It does, in my case, so I have had to take special care for the IPTables rules.
As my rules are rather complex, I will only show the rules relevant to the system, assuming (and this is important!) it is both the firewall/router and the VPN endpoint. If this is not the case, you should search for more details about forwarding IPSec traffic to backend VPN server.
So, my IPTables rules would be these three:
iptables -A INPUT -p udp --dport 500 -j ACCEPT
iptables -A INPUT -p udp --dport 4500 -j ACCEPT
iptables -A INPUT -p esp -j ACCEPT
iptables -A INPUT -p 51 -j ACCEPT # Not sure it's required, but too lazy to test without
This covers the IPSec part, however, we would not want the L2TP server to accept connections from the net, just like that, so it has its own rule, for port 1701:
iptables -A INPUT -p udp -m policy –dir in –pol ipsec -m udp –dport 1701 -j ACCEPT
You can save your current iptables rules (after checking that they work correctly) using ‘service iptables save’, or manually (backup your original rules to be on the safe side), and you’re all ready to go.