Building a l2tp/IPsec VPN based around a OpenBSD head-end – Part 1

This is the first in a series of posts to cover building a l2tp/IPsec VPN service which remote users (road warriors) connect to.
In this post I will begin with getting OpenBSD setup as the head-end & follow up with subsequent posts to cover configuration of various platforms as clients which compose the road warriors.
Undeadly featured an article on configuring OpenBSD in 2012, things have improved since this article was posted and some of the steps are no longer required, hence I will go over the process again here.

It’s assumed you have an install of OpenBSD running that’s setup as a gateway and communicating on the network, we will continue from there.

The following snippet of config needs to be added to your PF config (/etc/pf.conf by default). It unconditionally permits the IPsec ESP & AH protocols intended for the OpenBSD host, as well as any UDP traffic for ISAKMP and to support NAT traversal.
pass quick proto { esp, ah } from any to self
pass quick proto udp from any to self port {isakmp, ipsec-nat-t} keep state
pass on enc0 from any to self keep state (if-bound)

A minimal PF config which just permits the establishment of a VPN tunnel might look like the following

set skip lo
block return
pass quick proto { esp, ah } from any to self
pass quick proto udp from any to self port {isakmp, ipsec-nat-t} keep state
pass on enc0 from any to self keep state (if-bound)

By only permitting isakmp, it enforces having a working IPsec config before anything else happens whereas permitting UDP port 1701 would permit the establishment of a l2tp tunnel without IPsec which in this scenario would likely be undesired.

A basic IPsec config to use a pre-shared key.The default ciphers used for main & quick mode are documented in ipsec.conf(5). The IP address 1.2.3.4 is configured on the OpenBSD host which connections will be accepted on.

ike passive esp transport proto udp from 1.2.3.4 to any port 1701 psk "password"

Note, the OpenBSD defaults are too high for establishing a connection using the networking preferences on Apple devices and so would need to be restricted down to auth "hmac-sha1" enc "3des" group modp1024 which is not recommended, configuring Apple systems will be covered as a separate article.

The default npppd config (/etc/npppd/nppd.conf) works as-is, without any further changes required. That is unless you prefer to use RADIUS for accounting, instead of local user accounts.

myuser:\
    :password=mypass:\
    :framed-ip-address=10.0.0.111:

npppd is set to use pppx(4) interfaces for established sessions, in order for these interfaces to work correctly, pipex(4) needs to be enabled.

sysctl net.pipex.enable=1

and adding net.pipex.enable=1 to /etc/sysctl.conf so it’s set on boot.

Note, hosts missing this commit (5.8-RELEASE and snapshots from today & prior) will suffer a panic on the OpenBSD host upon establishment of a session by clients, if pipex(4) is not enabled.

Start isakmpd & npppd with

isakmpd -K
npppd

Load your ipsec.conf with
ipsecctl -f /etc/ipsec.conf

Your host should be ready to accept VPN connections, set this services to be started on boot by adding the following to /etc/rc.conf.local
isakmpd_flags="-K"
ipsec=YES
npppd_flags=""

L2TP/IPsec VPN clients unable to authenticate after 10.7.3 update

If you’re finding users are unable to dial-in via L2TP/IPsec VPN after upgrading Lion Server to 10.7.3 then check /var/log/ppp/vpnd.log
If you’re seeing DSAuth plugin: Failed to retrieve MPPE encryption keys from the password server: errno -14484, ctxt 4 logged on dial-in attempts then you’ll need to adjust your password policy.
There is an Apple support article HT4748 which covers how to make this change.
Thanks to the user bobgeo on the Apple discussion forums for the pointer.

Connecting to a Windows PPTP based VPN through a OpenBSD / PF firewall

To be able to connect to a Windows based PPTP VPN through a OpenBSD firewall you’ll need to make a couple of changes to allow GRE traffic through.
first add the following to /etc/sysctl.conf:
net.inet.gre.allow=1
net.inet.gre.wccp=1
net.inet.mobileip.allow=1

then add the following to the filter section in your /etc/pf.conf:
pass in on $ext_if proto gre all keep state
pass out on $ext_if proto gre all keep state

To make the changes effective without having to reboot issue the following as root:

sysctl net.inet.gre.allow=1
sysctl net.inet.gre.wccp=1
sysctl net.inet.mobileip.allow=1
pfctl -f /etc/pf.conf