← Back to list

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.

Prasanth Swaminathan · 2026-03-05 02:18 · 1 claps · 5.8 min read
#ipsec #strongswan #raspberry-pi-4 #virtual-lab #experimental
Open on Medium ↗
Wiki topics: 📟 · Gadgets & IoT 🔓 · Open Source 🔬 · Science · General

“Sometimes the smallest things take up the most room in your heart.” — A.A. Milne (Winnie the Pooh)

“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:

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:

  1. Separate per-namespace directories for configuration and mount them appropriately.
sudo mkdir -p /etc/ipsec-ns/hostA
sudo mkdir -p /etc/ipsec-ns/hostB
  1. 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.log and /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
        }
    }
}
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"
    }
}
  1. Bind-mount the /etc filesystem 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

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”

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

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 vethA-router interface

tcpdump on the vethB-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