Routing-based VPN with StrongSwan (II)

This blog is port of the series of texts that describe the setup of the company VPN with IPsec and dynamic routing. You can find the first part about the setup of strongSwan for the IPsec part here.

This second part describes the setup of the dynamic routing of a route-based VPN with strongSwan and BGP.

bird as a Routing Service

I chose BGP as the dynamic routing protocol for my setup because it a widely used in the internet to connect networks. It is also more and more adopted for internal dynamic routing (iBGP).

There are some routing services for the Linux OS. I will show the setup with bird, since it is very powerful and offers the features needed for the setup.

Basic Setup

In my basic setup I have three routers connected to my lab internet via a central router that simulates the internet. The whole network is described in the first article. In a short summary the used networks are listed here:

Site Transport Net Local Net




Our task will be to connect the local networks at the sites A, B, and C via the dynamically routed network of routers A, B and C. Even of the connection between A and B is lost, the traffic between A and B can be rerouted via site C.

bird as a routing service uses so called protocols to import and export routes. I will utilize the static protocol to add the local networks and the routes to the other routers to bird.

The kernel protocol is used to export the actual routes to the local networks to the kernel. An BGP is used to echange information about the availabilty of routes amongst the routers A, B, and C.

The Static Protocol

Let’s start with the simple static protocol, that imports the local routes and the routes to the other routers into bird. The configuration section of router A in bird.conf looks like:

protocol static {
  check link;
  # local network attached to eth1
  route via "eth1";
  # geteway to the other routers in network
  route via;


The next section of the configuration is the BGP part. I will just show the section of roter A that links to router B. The other sections on the other routers are symmetrical.

First we have to define a filter for the networks that router A can export and wants to import. Router A can export all local networks, not only its own since networks B or C are reachable also via roter A.

Router A wants to import only the networks B and C. Network A is directly attached. So the filters are:

filter exportA {
  if net ~ then accept;
  else reject;

filter importB {
  if net ~ [, ] then {
    ifname = "vti0";
  } else

The import filter importB also modifies the route it learns from its BGP peer router B. If the network is the local network B or C the the import filter adds the iterface vti0 as the next hop. This filter option was added with commit 716b904f on Nov, 5th 2018. So if you want to set up a VPN with dynamic routing be sure to use a version of bird that includes that patch.

With these filters defined it is easy to write the BGP configuration:

protocol bgp {
  local as 65001;
  neighbor as 65002;
  ipv4 {
    export filter exportA;
    import filter importB;

The Kernel

The last part of the bird configuration is the kernel protocol. We don’t want to import anything from the kernel. The local routes are already defined in the static section. But we want to export the routes we learned from BGP to the kernel:

filter export2kernel {
  if net ~ [, ] then {

protocol kernel {
  ipv4 {
    import none;
    export filter export2kernel;

The operation system takes care for the vti interfaces between the routers and strongSwan is responsible for the encryption (and decryption) of the packets that are exchanged between the private networks.

The routing service bird on the routers use the protocol BGP the exchange information about their knowledge to the internal networks. brid then injects the routes via the tunnel interfaces into the kernel routing table.

Michael Schwartzkopff, 22.11.2018