Building a L2TP/IPSec server with OSPF routing capability

The need for more

As you may already know, we've only a few sites in jumpNet where static IPs are available and of course, that's where the VPN servers are located. Unfortunatelly, the upstream on these (two) sites isn't great.

That was the motivation to think a minute or two about an alternative. The only viable solution seemed renting a VPS (virtual private server) and implementing all the L2TP/IPSec and OSPF funtionality on it. That's what I did:

Operating system

As I'm very familiar with Ubuntu, I chose Ubuntu 16.4 LTS server as foundation for this new jumpNet router.

Libreswan

For IPSec, I asked in #dn42 at hackin.org for some advice and someone proposed to "use libreswan over enything else". As these are the guys who should know, I willingly followed their advice.

Installing libreswan is surprisingly easy. The sources can be downloaded from libreswan.org. Afterwards, you have to install the dependencies:

apt-get install -y libnss3-dev libnspr4-dev pkg-config libpam-dev libcap-ng-dev libcap-ng-utils \
  libselinux-dev libcurl4-nss-dev libgmp3-dev flex bison gcc make libunbound-dev libnss3-tools \
libsystemd-dev libevent-dev libldns-dev xmlto

Finally, you can extract and compile libreswan:

tar xvzf libreswan-3.23.tar.gz
cd libreswan-3.23
make programs
make install

A working config looks like that:

# /etc/ipsec.d/l2tp-psk.conf
conn L2TP-PSK-NAT
        rightsubnet=vhost:%priv
        also=L2TP-PSK-noNAT

conn L2TP-PSK-noNAT
        authby=secret
        pfs=no
        auto=add
        keyingtries=3
        rekey=no
        dpddelay=10
        dpdtimeout=90
        dpdaction=clear
        ikelifetime=8h
        keylife=30m
        type=transport
        left=%defaultroute
        leftprotoport=17/1701
        right=%any
        rightprotoport=17/%any

Create another file:

#/etc/ipsec.d/my.secrets
%any: PSK "this.is.my.pre.shared.key"

Make sure that your config is included in /etc/ipsec.conf and your secret is included in /etc/ipsec.secrets thats already the case on Ubuntu 16.4 LTS.

That's it with IPSec configuration. Please note: This isn't a really good setup as it uses a pre-shared key and no PFS (perfect forward secrecy).

Last step to do regarding IPSec:

ipsec setup start
ipsec verify

Lastly, you should enable the systemd unit to startup IPSec automatically. The unit-file is located at /lib/systemd/system/ipsec.service.

L2TP with xl2tpd

Installation of xl2tpd is as easy as

apt-get install xl2tpd

The configuration is pretty straight forward:

# /etc/xl2tpd/xl2tpd.conf
[global]
ipsec saref = yes
access control = no
listen-addr = 203.0.113.7
port = 1701
debug network = no
debug tunnel = no

[lns default]
local ip = 10.10.20.1
assign ip = no
require authentication = yes
pppoptfile = /etc/ppp/xl2tpd-options
length bit = yes
ppp debug = yes

That's the L2TP part, next, we adjust some settings in the pppoptfile:

#/etc/ppp/xl2tpd-options
# we only accept ms-chap v2
require-mschap-v2

Next step is to define user credentials and, if you wish to, static IP addresses for the peers. This is done in /etc/ppp/chap-secrets. There are four columns in this file: username, server, secret and IP address:

# /etc/ppp/chap-secrets
# client          server          secret                IP address
user01             *                super.secret        10.10.1.1
user02             *                next.scret          10.10.3.1

and so on. xl2tpd comes with an old init-script which get's imported from systemd once you do

systemctl daemon-reload
systemctl enable xl2tpd.service

To start xl2tpd, do:

systemctl start xl2tpd

BIRD - internet routing daemon

First, install all the dependencies. For bird 2.0.1, these are the dependencies:

apt-get install build-essential flex bison libncurses-dev libreadline-dev

Next, download the bird sources (http://bird.network.cz/?download), unpack and compile them:

tar xvzf bird-2.0.1.tar.gz
cd bird-2.0.1
./configure
make
make install

Finally, you need some configuration for bird. This is the configuration I use for the jumpNet router:

# /usr/local/etc/bird.conf
define OWNIP = 10.10.20.1;
define OWNNET = 10.10.20.0/24;

log syslog all;

router id OWNIP;

function is_default()
{
        return net ~ [0.0.0.0/0];
}

function is_dn42()
{
        return net ~ [ 172.20.0.0/14+ ];
}

function is_jn()
{
        return net ~ [ 172.16.1.0/24+, 10.10.0.0/16{24,30} ];
}

filter kernel_in
{
        if net ~ [ 0.0.0.0/0 ] then reject;
        accept;
}

filter kernel_out
{
        if is_jn() || is_dn42() then accept;
        reject;
}

filter ospf_in
{
        if is_jn() || is_dn42() then accept;
        reject;
}

filter ospf_out
{
        if is_jn() || is_dn42() then accept;
        reject;
}

protocol kernel {
        scan time 15;
        ipv4 {
                import filter kernel_in;
                export filter kernel_out;
        };
        learn;
}

protocol device {
        scan time 30;
        interface "loopback";
}
protocol static {
        ipv4;
        route 10.10.20.0/24 unreachable { ospf_metric1 = 10; ospf_metric2 = 100; };
}

protocol ospf v2 {
        ipv4 {
                import filter ospf_in;
                export filter ospf_out;
        };
        area 0.0.0.0 {
                networks {
                        10.10.0.0/16;
                };
                interface "ppp*" {
                        cost 50;
                        hello 10;
                        retransmit 5;
                        dead 40;
                        type broadcast;
                        authentication cryptographic;
                        password "your-own-ospf-auth-secret";
                };
        };
}

Of course you need to adapt IP addresses and filters to your own needs. You may wonder about the "unreachable" route, I configured in bird's configuration. That is just an easy way to define a route which bird should propagate via OSPF. As I used ppp* as interface name, all ppp-connections, which are in fact our L2TP/IPsec connections will be included in OSPF route propagation.

Least but not last, you may find this unit file for bird useful:

# /etc/systemd/system/bird.service
[Unit]
Description=bird - Internet Routing Daemon
After=networking.service

[Service]
TimeoutStartSec=0
Restart=always
ExecStart=/usr/local/sbin/bird -d -c /usr/local/etc/bird.conf
ExecReload=/usr/local/sbin/birdc configure check
ExecReload=/usr/local/sbin/birdc configure

[Install]
WantedBy=multi-user.target

Security considerations

I won't provide any specific firewall configuration, but of course you need to set up proper firewalling on a VPS. Especially for forwarding traffic, which your VPS should only do for your VPN peers. Make sure, the VPS is accepting OSPF packets (protocol 89) only from your internal IP range!

Use ssh-keys for accessing ssh on your VPS - don't use passwords.

Re-generate the ssh host-keys. (rm /etc/ssh/ssh_host* && dpkg-reconfigure openssh-server)

Virtual private server

I rent my VPS from OVH. That's my first project I realise with their services, so I cannot tell anything bad or good about them.

You can chose to have your server in Frankfunkt Germany, so you can assume, they're connected to DECIX. Myself, I experience very low latency (<20ms) from various locations. Besides the low latency, the server has unmetered 100MBit/s access to the internet and is really affordable (<60 EUR/year).

Conclusion

Of course, the IPSec setup can be optimized, but for now, it will do.

At least, the main goal - to retire one of the less powerful VPN routers of the jumpNet is done.

If you think I missed something or in case you've questions, feel free to drop me an e-mail! Thank you!

Go back