strongSwan in Linux Network Namespaces
Normally, the network stack (interfaces, routing tables, firewall rules etc.) is
shared by all processes running on an operating system. With Linux network namespaces
(netns) it’s possible to have multiple separate instances of the network stack.
| While basic support for network namespaces was added to the Linux kernel a long time ago some features (e.g. CLUSTERIP support) might require a recent kernel. |
The easiest way to work with network namespaces is to use the ip command of the
iproute2 package. These commands will have to be executed as root (i.e. with
sudo on most distros).
Network Namespace Basics
To create a new netns use the following command:
# ip netns add <network namespace name>
A list of all currently defined netns is provided by ip netns list.
Interfaces can be assigned to a netns with the ip link command:
# ip link set <interface name> netns <netns name>
If you run ip link list afterwards, such an interface won’t be seen as it is
only available in the configured netns. So to actually list the interface in
a specific netns it is required to be able to run commands in a specific
netns. This can be done with the ip netns exec command. Thus to get a list
of interfaces defined in a specific netns use:
# ip netns exec <netns name> ip link list
If only one physical interface is available or if you don’t want to assign physical
interfaces to the netns for other reasons, it’s possible to create virtual
Ethernet interface pairs (veth provided via CONFIG_VETH). These are like a
bi-directional pipe (i.e. what’s written to one end comes out the other end and
vice-versa) of which one end is placed inside the netns and the other stays
outside in the default or global namespace.
To create such a pair use:
# ip link add <interface name 1> type veth peer name <interface name 2>
This creates two connected Enthernet interfaces with the given names. One is
assigned to a netns (via ip link) the other is not (it doesn’t matter which
one and it’s also possible to assign both interfaces to two different netns
to connect them). How the outer interface is used depends on the use case: it may
be put inside a bridge or used in routing rules to route traffic to and from a
netns.
Since interfaces assigned to a netns are disabled they have to be enabled first
and they will probably also require an IP address, which can be done with:
# ip netns exec <netns name> ip addr add x.x.x.x/x dev <iface name> # ip netns exec <netns name> ip link set dev <iface name> up
Similar to these commands, routes or firewall rules may be added by running
ip route or iptables inside a specific netns via
# ip netns exec <command>
Running strongSwan Inside a Network Namespace
Running a single instance of strongSwan inside a netns is straight-forward.
Simply run swanctl commands via
# ip netns exec ipsec <command>
But more interesting is running multiple instances of strongSwan in separate
namespaces. Because all netns share the same file system this is a bit tricky.
Luckily, the ip netns exec command provides a helpful feature: Every file found
in /etc/netns/<name>/ for a given netns is bind-mounted over its corresponding
counterpart in /etc/ (so it has to exist there). This can be used to provide
different config files for each instance but may also be used to redirect the so
called piddir where the charon daemon creates its
PID file and UNIX sockets. The default is to use /var/run which would conflict
if multiple instances would use it.
In order to fix this, make sure strongSwan is
configured with --sysconfdir=/etc and e.g.
--with-piddir=/etc/ipsec.d/run. Then after
building and installing strongSwan
the piddirs can be created as follows:
# mkdir -p /etc/ipsec.d/run # mkdir -p /etc/netns/<netns name 1>/ipsec.d/run # mkdir -p /etc/netns/<netns name 2>/ipsec.d/run
For config files that differ between netns, a modified copy of the original
may be placed in /etc/netns/<name>/ or a subdirectory.