Skip to main content

Raymii.org Logo (IEC resistor symbol)logo

Quis custodiet ipsos custodes?
Home | About | All pages | RSS Feed | Gopher

IPSEC L2TP VPN on Arch Linux on a Raspberry Pi with OpenSwan, xl2tpd and ppp

Published: 01-12-2014 | Author: Remy van Elst | Text only version of this article


Table of Contents


ArchonPi

The Raspberry Pi is a great little small computer, both for tinkering but alsoas a low power 24/7 running homeserver system. I've got multiple Pi's, onerunning as my home VPN gateway. It is running an IPSEC/L2TP VPN server. This isa guide on setting up an IPSEC/L2TP vpn server with Arch Linux on the RaspberryPi using Openswan as the IPsec server, xl2tpd as the l2tp provider and ppp orlocal users / PAM for authentication. It has a detailed explanation with everystep. We choose the IPSEC/L2TP protocol stack because of recent vulnerabilitiesfound in pptpd VPNs.

This tutorial is available for the following platforms:

If you like this article, consider sponsoring me by trying out a Digital OceanVPS. With this link you'll get $100 credit for 60 days). (referral link)

This tutorial was tested on a Raspberry Pi running Arch Linux ARM, installed viaNOOBS. It ran the current up to date Arch Linux ARM, here are the versions used:

IPSec encrypts your IP packets to provide encryption and authentication, so noone can decrypt or forge data between your clients and your server. L2TPprovides a tunnel to send data. It does not provide encryption andauthentication though, that is why we combine the two.

To work trough this tutorial you should have:

I do all the steps as the root user. You should do to, but only via sudo -i orsu -. Do not allow root to login via SSH!

Install ppp openswan and xl2tpd

First we will install the required packages:

pacman -Sy openswan xl2tpd ppp lsof python2

If you are running normal Arch (x86), you need to install OpenSWAN from the AUR.For the ARM/Pi version there is a package available. Python2 is required forOpenSWAN, but not listed as a dependency, therefore it is installed.

Firewall and sysctl

We are going to set the firewall and make sure the kernel forwards IP packets:

Execute this command to enable the iptables firewall to allow vpn traffic:

iptables --table nat --append POSTROUTING --jump MASQUERADE

Execute the below commands to enable kernel IP packet forwarding and disable ICPredirects.

echo "net.ipv4.ip_forward = 1" |  tee -a /etc/sysctl.confecho "net.ipv4.conf.all.accept_redirects = 0" |  tee -a /etc/sysctl.confecho "net.ipv4.conf.all.send_redirects = 0" |  tee -a /etc/sysctl.confecho "net.ipv4.conf.default.rp_filter = 0" |  tee -a /etc/sysctl.confecho "net.ipv4.conf.default.accept_source_route = 0" |  tee -a /etc/sysctl.confecho "net.ipv4.conf.default.send_redirects = 0" |  tee -a /etc/sysctl.confecho "net.ipv4.icmp_ignore_bogus_error_responses = 1" |  tee -a /etc/sysctl.conf

Set these settings for other network interfaces:

for vpn in /proc/sys/net/ipv4/conf/*; do echo 0 > $vpn/accept_redirects; echo 0 > $vpn/send_redirects; done

Apply them:

sysctl -p
Persistent settings via systemd

Arch Linux uses systemd. Init script functionality like rc.local is notavailable. To have these settings applied at boot we can however create a customsystemd service which starts at boot.

Add the following code to /usr/local/bin/vpn-boot.sh:

#!/usr/bin/env bashfor vpn in /proc/sys/net/ipv4/conf/*; do     echo 0 > $vpn/accept_redirects;     echo 0 > $vpn/send_redirects; doneiptables --table nat --append POSTROUTING --jump MASQUERADEsysctl -p

Make it executable:

chmod 755 /usr/local/bin/vpn-boot.sh

Using the following systemd service we can start the script which sets the abovethings at boot:

Add the following code to /etc/systemd/system/vpnboot.service:

[Unit]Description=VPN Settings at bootAfter=netctl@eth0.serviceBefore=openswan.service xl2tpd.service[Service]ExecStart=/usr/local/bin/vpn-boot.sh[Install]WantedBy=multi-user.target 

Then enable it:

systemctl enable vpnboot.service

Configure Openswan (IPSEC)

Use your favorite editor to edit the following file:

vim /etc/ipsec.conf  

Replace the contents with the following:

(Most lines have a comment below it explaining what it does.)

version 2 config setup    dumpdir=/var/run/pluto/    #in what directory should things started by setup (notably the Pluto daemon) be allowed to dump core?    nat_traversal=yes    #whether to accept/offer to support NAT (NAPT, also known as "IP Masqurade") workaround for IPsec    virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v6:fd00::/8,%v6:fe80::/10    #contains the networks that are allowed as subnet= for the remote client. In other words, the address ranges that may live behind a NAT router through which a client connects.    protostack=netkey    #decide which protocol stack is going to be used.    plutoopts="--interface=eth0"    # replace with your ethernet interface.    force_keepalive=yes    keep_alive=60    # Send a keep-alive packet every 60 seconds.conn L2TP-PSK-noNAT    authby=secret    #shared secret. Use rsasig for certificates.    pfs=yes    #Enable pfs    auto=add    #the ipsec tunnel should be started and routes created when the ipsec daemon itself starts.    keyingtries=3    #Only negotiate a conn. 3 times.    ikelifetime=8h    keylife=1h    type=transport    #because we use l2tp as tunnel protocol    left=%SERVERIP%    #fill in server IP above    leftprotoport=17/1701    right=%any    rightprotoport=17/%any    dpddelay=10    # Dead Peer Dectection (RFC 3706) keepalives delay    dpdtimeout=20    #  length of time (in seconds) we will idle without hearing either an R_U_THERE poll from our peer, or an R_U_THERE_ACK reply.    dpdaction=clear    # When a DPD enabled peer is declared dead, what action should be taken. clear means the eroute and SA with both be cleared.

Replace %SERVERIP% with the external IP of your Raspberry Pi. You can find itout by:

curl http://ip.mtak.nl
The shared secret

The shared secret is defined in the /etc/ipsec.secrets file. Make sure it islong and random:

%SERVERIP%  %any:   PSK "Your secret random key"

Again, replace %SERVERIP% with the external IP of your Raspberry Pi. If you wantto generate a random key you can use the following openssl command:

openssl rand -hex 30

Example output:

c12cf75b47c210b9d7094ce10e3b3544c6927ff49ca2d949252b5a94ccf5
Verify IPSEC Settings

Now to make sure IPSEC works, execute the following command:

ipsec verify

My output looks like this:

 Checking if IPsec got installed and started correctly:Version check and ipsec on-path                     [OK]Openswan U2.6.39/K3.10.25-1-ARCH (netkey)See `ipsec --copyright' for copyright information.Checking for IPsec support in kernel                [OK] NETKEY: Testing XFRM related proc values         ICMP default/send_redirects                [OK]         ICMP default/accept_redirects              [OK]         XFRM larval drop                           [OK]Hardware random device check                        [N/A]Two or more interfaces found, checking IP forwarding    [OK]Checking rp_filter                                  [ENABLED] /proc/sys/net/ipv4/conf/default/rp_filter          [ENABLED] /proc/sys/net/ipv4/conf/eth0/rp_filter             [ENABLED] /proc/sys/net/ipv4/conf/ifb0/rp_filter             [ENABLED] /proc/sys/net/ipv4/conf/ifb1/rp_filter             [ENABLED]Checking that pluto is running                      [OK] Pluto listening for IKE on udp 500               fail in else:State      Recv-Q Send-Q        Local Address:Port          Peer Address:Port    [FAILED] Pluto listening for IKE on tcp 500                 [NOT IMPLEMENTED] Pluto listening for IKE/NAT-T on udp 4500          [DISABLED] Pluto listening for IKE/NAT-T on tcp 4500          [NOT IMPLEMENTED] Pluto listening for IKE on tcp 10000 (cisco)       [NOT IMPLEMENTED]Checking NAT and MASQUERADEing                      [TEST INCOMPLETE]Checking 'ip' command                               [OK]Checking 'iptables' command                         [OK]ipsec verify: encountered errors

However, a netstat -tulpan shows that pluto is listening on the ports thatgive errors:

Active Internet connections (servers and established)Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name[...]udp        0      0 10.0.0.10:4500          0.0.0.0:*                           4624/plutoudp        0      0 0.0.0.0:1701            0.0.0.0:*                           4443/xl2tpdudp        0      0 10.0.0.10:500           0.0.0.0:*                           4624/pluto[...]

Enable Openswan:

systemctl enable openswan

Configure xl2tpd

Use your favorite editor to edit the following file:

/etc/xl2tpd/xl2tpd.conf  

Replace the contents with the following:

[global]ipsec saref = yessaref refinfo = 30[lns default]ip range = 172.16.1.30-172.16.1.100local ip = 172.16.1.1refuse pap = yesrequire authentication = yesppp debug = yespppoptfile = /etc/ppp/options.xl2tpdlength bit = yes

Also create the following folder for xl2tpd's control file:

mkdir /var/run/xl2tpd/

Local user (PAM//etc/passwd) authentication

To use local user accounts via pam (or /etc/passwd), and thus not having plaintext user passwords in a text file you have to do a few extra steps. Huge thanksto Sascha Scandella for the hard work and troubleshooting.

In your /etc/xl2tpd/xl2tpd.conf add the following line:

unix authentication = yes

and remove the following line:

refuse pap = yes

In the file /etc/ppp/options.xl2tpd make sure you do not add the followingline (below it states to add it, but not if you want to use UNIXauthentication):

require-mschap-v2

Also in that file (/etc/ppp/options.xl2tpd) add the following extra line:

login

Change /etc/pam.d/ppp to this:

auth    required        pam_nologin.soauth    required        pam_unix.soaccount required        pam_unix.sosession required        pam_unix.so

Add the following to /etc/ppp/pap-secrets:

*       l2tpd           ""              *

(And, skip the chap-secrets file below (adding users).)

Configuring PPP

Use your favorite editor to edit the following file:

/etc/ppp/options.xl2tpd  

Replace the contents with the following:

require-mschap-v2ms-dns 8.8.8.8ms-dns 8.8.4.4authmtu 1200mru 1000crtsctshide-passwordmodemname l2tpdproxyarplcp-echo-interval 30lcp-echo-failure 4

Adding users

Every user should be defined in the /etc/ppp/chap-secrets file. Below is anexample file.

# Secrets for authentication using CHAP# client       server  secret                  IP addressesalice          l2tpd   0F92E5FC2414101EA            *bob            l2tpd   DF98F09F74C06A2F             *

Testing it

To make sure everything has the newest config files restart openswan and xl2tpd:

systemctl restart openswansystemctl restart xl2tpd

On the client connect to the server IP address (or add a DNS name) with a validuser, password and the shared secret. Test if you have internet access and whichIP you have (via for example http://whatsmyip.org. If it is the VPN servers IPthen it works.

If you experience problems make sure to check the client log files. Also, onArch Linux, the system log can be viewed by using journalctl -f (that emulatestail -f /var/log/syslog). Arch Linux uses systemd logging. For more info aboutsystemd services, see this page

If you have your Raspberry Pi behind a NAT router, you might need to change your%SERVERIP% to the internal IP of your Raspberry Pi (like 192.168.1.101) insteadof your external IP address.

If you google the error messages you most of the time get a good answer.

Thanks to Keith's article for help with boot persistency.

Tags: arch, ipsec, l2tp, openvpn, pptp, raspberry-pi, systemd, tutorials, vpn