RaspberryPi IPSEC server04 February 2021
Due to circumstances much of my equipment is now at my parents' place in the UK but because of increasingly haphazard travel restrictions I needed to setup remote access just in case I get stuck somewhere else for longer than I plan. For reason of space I decided the best thing was to setup a Strongswan VPN server on a RaspberryPi 4 board, so this article will cover both the process of installing Strongswan and Slackware ARM onto the RaspberryPi, and the setting up of IPSec itself.
Setting up BT InternetBT is not my favoured ISP but it is the one I have to work with in this instance, and one particular irritation with them is setting up the hub's firewall to pass in all the required traffic. Back in the days I used PowerNet with my own ADSL modem there was no filtering at all, but BT seems to cater for the very non-technical so they have a very expert-unfriendly (i.e. inflexible) offering. UDP/IP ports
4500need to be opened up — BT does not seem to support opening up non-TCP/UDP ports but Strongswan's NAT-traversal code should be able to detect this and encapsulate things as-needed.
22222 is there purely for non-IPSec testing purposes.
Even thougn the RaspberryPi itself was able to access external IPv6 sites I gave up trying to coax the BT hub into detecting it in order to open up IPv6 ports under pinholes.
Installing Slackware on RaspberryPiI favour Slackware because it is by any measure a conservative distribution where you could take a setup guide from 15 years ago and most of the information would still be correct with the latest release. The Slackware ARM project has decided not to bother with a build of Slackware 14.2 for the RaspberryPi 4 and instead only provide one for
slackware-currentwhich is the development branch — I am not really surprised as Slackware- 14.2 was released back in July 2016 and noises are that the development branch is in some sort of release-candidate stage. The instructions here are based on those from the SARPi guide and mostly just notes where installation deviates from that of normal workstation Slackware.
Getting the filesFor simplicity I decided to simply mirror the entire distribution from the UK mirror using the following two commands. I did not bother passing the
-zparameter to rsync because most of the files are already compressed.
wget https://slackware.uk/sarpi/rpi4/current/img/sarpi4-installer_slackcurrent_22Jan21_sp1.img.xz \ https://slackware.uk/sarpi/rpi4/current/pkg/kernel_sarpi4-5.10.9-armv7l-1_slackcurrent_22Jan21_sp1.txz \ https://slackware.uk/sarpi/rpi4/current/pkg/kernel-headers-sarpi4-5.10.9-armv7l-1_slackcurrent_22Jan21_sp1.txz \ https://slackware.uk/sarpi/rpi4/current/pkg/kernel-modules-sarpi4-5.10.9-armv7l-1_slackcurrent_22Jan21_sp1.txz \ https://slackware.uk/sarpi/rpi4/current/pkg/sarpi4-boot-firmware-armv7l-1_slackcurrent_22Jan21_sp1.txz \ https://slackware.uk/sarpi/rpi4/current/pkg/sarpi4-hacks-4.0-armv7l-1_slackcurrent_22Jan21_sp1.txz rsync -av ftp.arm.slackware.com::slackwarearm/slackwarearm-current .
Setting up the MicroSDIf the MicroSD is one that has anything on it stop now — this step will erase everything on it. Using a flash adapter connect the MicroSD card to your system, then unpack and flash the provided installer image to the MicroSD using the following command, replacing
fdisk -lindicates is the block device for the flash card. Take care to use the correct device unless you want a very bad day.
xz -dc sarpi4-installer_slackcurrent_22Jan21_sp1.img.xz | dd of=/dev/sdX bs=65536
Get a network connectionIn my case I decided to do a network install, which can be setup using the commands below, replacing the IP addresses with ones appropriate for your ISP. The nameserver
188.8.131.52is Google's nameserver, which can suually be left as-is.
ifconfig eth0 192.168.1.16 netmask 255.255.255.0 up route add default gw 192.168.1.254 echo nameserver 184.108.40.206 > /etc/resolv.conf
May as well update the clock as well while here:
ntpd -p pool.ntp.org
Creating & setting up partitionsNothing particularly special here — using
cfdiskto create swap and root partitions, and any others like
/homedepending on taste. I decided to make the swap partition of 1GB although I doubt that it will ever be used in practice so it probably could be made smaller or omitted entirely. One thing to watch out for in the partition part of the setup program is mounting the W32 FAT32 parition as
/bootas things will screw up sooner or later down the line if you omit to do this.
Choosing packagesThe general idea is to connect to the RasapberryPi using SSH rather than having a physical display connected once it has been boot-strapped, so only four disk-sets are required:
N. With a 16GB SD card there will be ample space to do a full install of these four, but with an 8GB one things will be a bit tight — in this latter case some large individual packages such as MariaDB and Rust will have to be individually deselected.
Completing the installationWhen the setup program reaches the
SETUP COMPLETEstage and it is time to exit the installer, Do Not Reboot. At this stage a bit of manual work is needed to remove some redundant packages and install some critial RaspberryPi-specific ones. In short the following, replacing
/dev/mmcblk0p1with whatever the block device for the W32 FAT32 boot parititon is on, if it is different:
ROOT=/mnt removepkg kernel_armv7 kernel-modules-armv7 mount -t vfat /dev/mmcblk0p1 /mnt/boot rm /mnt/boot/initrd.gz ROOT=/mnt installpkg /rpi-extra/kernel* /rpi-extra/sarpi4-*
Now you can reboot.
At this stage you should have a newly-provisioned Slackware ARM install.
Building Strongswan for SlackwareOriginally I planned to cross-compile Strongswan but parameters such as
--with-sysrootthat are supposed to aid cross-compiling are basically broken, and I decided the effort needed to get around complications was not worth it. To build and install Strongswan directly on the RaspberryPi itself is relatively straightforward:
./configure --prefix=/opt/strongswan \ --enable-eap-identity --enable-eap-md5 --enable-eap-mschapv2 --enable-eap-tls \ --enable-eap-ttls --enable-eap-peap --enable-eap-tnc --enable-eap-dynamic \ --enable-eap-radius --enable-farp make -j4 make install
Using all four CPU cores building should only take a few minutes and use about 200MB or so of storage.
Strongswan setupUnlike with my previous IKEv2 VPN guide from 2017 I have opted to use client certificates, as I am rather averse to using passwords to secure important assets. If you want certificates for just server verification and use username/password pairs for client authentication have a look at EAP Hybrid Mode in the previous IKEv2 VPN guide.
Creating certificatesFor creating the certificate and keys the following makefile will do the task, although values given by
--sanparameters will need to be changed to match your own systems:
IPSEC=/usr/sbin/ipsec all: server.cert.pem client.cert.pem cakey.pem: $(IPSEC) pki --gen --outform pem > $@ cacert.pem: cakey.pem $(IPSEC) pki --self --in $< \ --dn "C=UK, OU=VPN, O=MyVPN, CN=Mine VPN CA" \ --ca --outform pem > $@ server.key.pem: $(IPSEC) pki --gen --outform pem > $@ server.key.pub: server.key.pem $(IPSEC) pki --pub --in $< --outform pem > $@ server.cert.pem: cacert.pem cakey.pem server.key.pub $(IPSEC) pki --issue --cacert cacert.pem --cakey cakey.pem \ --dn "C=UK, OU=VPN, O=MyVPN, CN=VPN" \ --san "vpn.example.com" \ --flag serverAuth --flag ikeIntermediate \ --in server.key.pub --outform pem > $@ client.key.pem: $(IPSEC) pki --gen > $@ client.key.pub: client.key.pem $(IPSEC) pki --pub --in $< --outform pem > $@ client.cert.pem: client.key.pub $(IPSEC) pki --issue --cacert cacert.pem --cakey cakey.pem \ --dn "C=UK, OU=VPN, O=MyVPN, CN=Client" \ --in $< --outform pem > $@ client.p12: client.cert.pem client.key.pem cacert.pem openssl pkcs12 -in client.cert.pem -inkey client.key.pem \ -certfile cacert.pem -export -out $@
client.p12 on to an Android mobile the easiest thing I found was to out it onto an internal web-server then download it.
Android seems to be smart enough to ask if you want to place it into the certificate store, although at least some earlier versions will require you to have a certain level of lock screen security before imporitng them.
As for the server certificates & keys copy them to where Strongswan will pick them up:
cp cacert.pem /opt/strongswan/etc/ipsec.d/cacerts/ cp server.key.pem /opt/strongswan/etc/ipsec.d/private/ cp server.cert.pem /opt/strongswan/etc/ipsec.d/certs/
Authentication setupIn order to setup the VPN configuration put the following into
leftidand IP address parameters as needed. Most required parameters have the required values as default, so they can be omitted.
config setup conn certvpn auto=add type=transport keyexchange=ikev2 leftsubnet=0.0.0.0/0,::/0 leftauth=pubkey leftcert=server.cert.pem leftid="C=UK, OU=VPN, O=MyVPN, CN=VPN" right=%any rightsourceip=192.168.1.128/28 # rightsubnet=10.0.0.0/8 # If used, would route 10.x.x.x thru client..
To instead get an IPv6 address within the LAN change
rightsourceip to something like
Specifying both an IPv4 and IPV6 subnet seems to result in virtual IP addresses for both being created, but only one of them is pingable for some reason.
ipsec.secrets the following specifies the server's private key:
: RSA server.key.pem
Running Strongswan serverTo run Strongswan server in the foreground use the following:
/opt/strongswan/sbin/ipsec start --nofork --debug-all
For normal background running, omit
Stopping the sever can be done using:
You may want to put the above commands into
/etc/rc.d/rc.local_shutdown so that Strongswan is started and shut down when the system is bought up and taken down.
Client setupOn the client machine use the following
config setup conn VPNconn keyexchange=ikev2 auto=add left=%any leftsourceip=%config leftcert=client.cert.pem leftfirewall=yes right=vpn.example.com rightid="C=UK, OU=VPN, O=MyVPN, CN=VPN" rightauth=pubkey rightsubnet=0.0.0.0/0,::/0
The client private key is specified in
/etc/ipsec.secrets as shown below.
If this key is encrypted the passphrase would also be specified here.
: RSA client.key.pem
The VPN connection can then be controlled using the following commands:
ipsec start ipsec up VPNconn ipsec down VPNconn ipsec stop
Potential issues & loose ends
Adding second IP addressIf for whatever reason you need to attach extra IP addresses to an interface, commands such as the following can be placed into
/etc/rc.d/rc.localwhere they will be run towards the end of the boot process. Slackware does not really provide for static IPv6 addresses in its traditional
/etc/rc.d/rc.inet1.confand I have a long-standing dislike of NetworkManager, so any required IPv6 addresses not assigned via DHCP will need to go into here as well.
ifconfig eth0:1 192.168.1.16 netmask 255.255.255.0 up
Stroke vs. VICI based configurationsEven though Strongswan considers the
ipseccommand as legacy and instead prefers the
swanctlinterface which at a glance looks more intuitive in its choice of nomenclature, I am not entirely convinced it is worth the effort of rewriting everything into the new configuration format having worked out how to get the old format to do what I want. This is a bullet I will have to bite at some point, but for the time being the old interface seems to be fully supported, at least for the functionality I require.
Routing issuesWhen Strongswan is built with the
--enable-farpoption it will sniff for ARP requests for client addresses and emit a fake ARP response so that other machines on the LAN can be communicated with. If the address pool for client IPs is not within the LAN subnet and Strongswan is not running on the default gateway, then somehow these other machines need to have a routing table entry that forwards to the VPN server. Also, if the remote client can be pinged from the VPN gateway but no traffic is being passed between the VPN server and other machines, the odd are that Fake ARP was not enabled and instead NAT Masquerading will need to be used instead with a firewall rule along the lines of:
iptables -t nat -A POSTROUTING -s 192.168.64.128/24 -o eth0 -j MASQUERADE
DNS issuesIf you are having problems with name resolution you might want to use Google's public DNS servers which are
220.127.116.11, as these will always be useable regardless of which ISP and/or VPN server is in use.