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.