Tiny experiments — 1: Exploring IPsec tunnels using veth pairs and strongSwan in a Standalone Linux…
I recently set up my Raspberry Pi 4 with the latest Raspbian OS to try out some tiny experiments.

“Sometimes the smallest things take up the most room in your heart.” — A.A. Milne (Winnie the Pooh)
Tiny experiments — 1: Exploring IPsec tunnels using veth pairs and strongSwan in a Standalone Linux Namespace architecture.
I recently set up my Raspberry Pi 4 with the latest Raspbian OS to try out some tiny experiments.

A Raspberry Pi 4 provides the essential compute infrastructure — Gigabit Ethernet, Wi-Fi for networking, and USB 3.0 for storage — yet costs only a fraction of a traditional network testbed. It runs standard Linux (Debian-based Raspberry Pi OS), providing complete control over namespaces, routing tables, firewall (nftables/iptables), veth pairs and bridges. This is well suited for experimenting a Mini edge network node — Security, Firewall, running microservices etc.
Following are the primary software configuration elements used:
- Veth — A veth is a Virtual Ethernet device in Linux that acts like a network cable. When a packet enters one end, it immediately appears at the other.
- A veth-pair is two interconnected virtual interfaces; veth0 ← → veth1 — Acts like a Point to Point link.
- Linux namespaces — Lightweight Linux kernel feature that provides isolation for processes. Veth’s when paired with Linux Network Namespaces, allows simulation of network nodes on a Single machine.
- **strongSwan** —A widely used, open-source implementation of the IPsec (Internet Protocol Security) and IKE (Internet Key Exchange) standards. Couple of key functional elements that strongSwan provides:
- *charon-systemd*: The keying daemon, that manages IKE sessions, rekeying, and negotiation of SAs (Security Associations).
- *swanctl*: The central command-line interface for interacting with strongSwan, offering a unified and modern approach to managing IPsec tunnels. It communicates with the
[charon](https://docs.strongswan.org/docs/latest/daemons/charon.html)daemon using the Versatile IKE Configuration Interface (VICI) protocol.
Install strongSwan
sudo apt install -y strongswan strongswan-swanctl charon-systemd
sudo apt install libcharon-extra-plugins libstrongswan-extra-plugins
Verify strongSwan installation
RaspbiLab: /mnt/usb/veth_test/ipsec_test$ dpkg -l | grep strongswan
ii libstrongswan 6.0.1-6+deb13u2 arm64 strongSwan utility and crypto library
ii libstrongswan-extra-plugins 6.0.1-6+deb13u2 arm64 strongSwan utility and crypto library (extra plugins)
ii libstrongswan-standard-plugins 6.0.1-6+deb13u2 arm64 strongSwan utility and crypto library (standard plugins)
ii strongswan 6.0.1-6+deb13u2 all IPsec VPN solution metapackage
rc strongswan-charon 6.0.1-6+deb13u1 arm64 strongSwan Internet Key Exchange daemon
ii strongswan-libcharon 6.0.1-6+deb13u2 arm64 strongSwan charon library
ii strongswan-starter 6.0.1-6+deb13u2 arm64 strongSwan daemon starter and configuration file parser
ii strongswan-swanctl 6.0.1-6+deb13u2 arm64 strongSwan IPsec client, swanctl command
RaspbiLab: /mnt/usb/veth_test/ipsec_test$ dpkg -l | grep charon
ii charon-systemd 6.0.1-6+deb13u2 arm64 strongSwan IPsec client, systemd support
ii libcharon-extauth-plugins 6.0.1-6+deb13u2 arm64 strongSwan charon library (extended authentication plugins)
ii libcharon-extra-plugins 6.0.1-6+deb13u2 arm64 strongSwan charon library (extra plugins)
rc strongswan-charon 6.0.1-6+deb13u1 arm64 strongSwan Internet Key Exchange daemon
ii strongswan-libcharon 6.0.1-6+deb13u2 arm64 strongSwan charon library
A multi node topology utilizing the veths and the Network Namespace:

Setting up the veth, namespace configurations for basic connectivity
#Create namespaces
ip netns add hostA
ip netns add router
ip netns add hostB
#Create veth Pairs
ip link add vethA-hostA type veth peer name vethA-router
ip link add vethB-router type veth peer name vethB-hostB
# Associate veth interfaces to namespaces
ip link set vethA-hostA netns hostA
ip link set vethA-router netns router
ip link set vethB-router netns router
ip link set vethB-hostB netns hostB
# Assign IP address to the interfaces
ip netns exec hostA ip addr add 10.200.1.10/24 dev vethA-hostA
ip netns exec router ip addr add 10.200.1.1/24 dev vethA-router
ip netns exec router ip addr add 10.200.2.1/24 dev vethB-router
ip netns exec hostB ip addr add 10.200.2.20/24 dev vethB-hostB
#Add for loopback interface on hostA, hostB
ip -n hostA addr add 10.10.0.1/32 dev lo
ip -n hostB addr add 10.10.1.1/32 dev lo
#Bring up all the interfaces
ip netns exec hostA ip link set lo up
ip netns exec hostA ip link set vethA-hostA up
..
# Enable forwarding in router
ip netns exec router sysctl -w net.ipv4.ip_forward=1
Check the basic connectivity between the veth’s configured on the hostA and hostB namespace.

Now with the basic network topology setup, time to tie it up with strongSwan.
strongSwan/swanctl utilizes the Linux’s standard file system hierarchy such as /etc and /var for its configuration and logging respectively. For a multi namespace topology like the one above, it would certainly impact the way strongSwan where it expects its configurations files to be. The Linux’s network namespace provides isolation of networking resources but shares the host’s mount namespace, the same hosts file system. Two key aspects that needs to followed are:
- Separate per-namespace directories for configuration and mount them appropriately.
sudo mkdir -p /etc/ipsec-ns/hostA
sudo mkdir -p /etc/ipsec-ns/hostB
- Ensure strongSwan’s configuration (**strongswan.conf*) gets picked from the correct paths (Configuration files for hostA are shown below, similar configuration to be replicated *for hostB as well). Important to note the path’s for charon —
/var/log/charon-hostA.logand/etc/ipsec.d/run/charon-hostA.vici:
#Ensure Strongswan's configuration gets picked from the correct paths:
cat /etc/ipsec-ns/hostA/strongswan.conf
charon {
#basic logging setup
filelog {
my_log_file {
path = /var/log/charon-hostA.log
time_format = %b %e %T
append = yes
default = 1
flush_line = yes
}
}
#load all default plugins
plugins {
vici {
socket = unix:///etc/ipsec.d/run/charon-hostA.vici
}
}
}
[**swanctl.conf](https://docs.strongswan.org/docs/latest/swanctl/swanctlConf.html)* to be set with the Parent SA (Tunnel endpoint IP addresses, IKE SA) and the Child SA* (Internal IP address, IPsec SA)
cat /etc/ipsec-ns/hostA/swanctl/swanctl.conf
connections {
net-test {
local_addrs = 10.200.1.10
remote_addrs = 10.200.2.20
local {
auth = psk
id = hostA
}
remote {
auth = psk
id = hostB
}
children {
net {
local_ts = 10.10.0.1/28
remote_ts = 10.10.1.1/28
esp_proposals = aes128-sha256
start_action = trap
}
}
version = 2
proposals = aes128-sha256-modp2048
}
}
secrets {
ike-hostA-hostB {
id-1 = hostA
id-2 = hostB
secret = "strongsecret"
}
}
- Bind-mount the
/etcfilesystem for the namespace (e.g.,/etc/ipsec-ns/hostA) so that strongSwan inside that namespace uses the correct config.
With the configuration file setup with parameters to run the strongSwan; time to access the host namespace and load them.
Start the charon-systemd daemon on both the namespaces:


Load the strongSwan/swanctl configuration on both the namespaces; Parses through the strongswan.conf under /etc


Parent SA “net-test” is loaded
Initiate the IKE and Child SA connection between the hosts, run on hostA:

Parent SA “net-test” is setup, followed by the Child SA “net”
With the Parent and Child SA connections successful, as a final step: Test the child SA — with a ping between the loopback interfaces on hostA and hostB:

Ping between the loopback interfaces on hostA and hostB
tcpdump’s on the router namespace’s interfaces: The router interfaces passes through the IKE exchanges initiated from hostA and responded by hostB.

tcpdump on the vethA-router interface

tcpdump on the vethB-router interface
IKE and Child SA’s SPI values identified using the swanctl’s list-sas command:

A modest setup utilizing a Small Board Computer with virtual ethernet interfaces and namespaces to explore strongSwan’s capabilities!
The setup and configuration discussed above can be accessed here.
The setup, configuration discussed above can be accessed here.
메타데이터
- post_id
- af46a47d5e97
- slug
- tiny-experiments-1-exploring-ipsec-tunnels-using-veth-pairs-and-strongswan-in-a-standalone-linux-af46a47d5e97
- url
- https://medium.com/@prasanth.swaminathan/tiny-experiments-1-exploring-ipsec-tunnels-using-veth-pairs-and-strongswan-in-a-standalone-linux-af46a47d5e97
- canonical_url
- https://medium.com/@prasanth.swaminathan/tiny-experiments-1-exploring-ipsec-tunnels-using-veth-pairs-and-strongswan-in-a-standalone-linux-af46a47d5e97
- author_url
- https://medium.com/@prasanth.swaminathan
- status
- ok
- fetched_at
- 2026-06-18 07:02:39