StrongSwan is a VPN (Virtual Private Network) implementation based on IPsec, open source, multiplatform, complete and widely used. It works on operating systems such as Linux, FreeBSD, OS X, Windows, Android and iOS. Mainly, it is a key exchange demon that supports Internet Key Exchange protocols (IKEv1 and IKEv2) to establish security associations (SA) between two pairs.

[NOTE] I will start from the VPN post remote access with OpenVPN, so you may refer to this during this article. If you want to have the same scenario go first to this.

Remember that for the configuration we are going to do you have to activate the forwardbit in the Servidor1 and Servidor2 machines.

StrongSwan installation

We will start by installing the StrongSwan package in both machines:

debian@servidor1:~$ sudo apt install strongswan -y
debian@servidor2:~$ sudo apt install strongswan -y

StrongSwan configuration

Server 1

Next we will set up server 1, I will give you a comment so you know what each option means:

debian@servidor1:~$  sudo cat /etc/ipsec.conf
#Configuración global de strongSwan
config setup
       charondebug="ike 2, knl 2, cfg 2, net 2, esp 2, dmn 2,  mgr 2"

#Configuración por defecto para conexiones VPN
conn %default
       ikelifetime=1h            # Tiempo de vida de la negociación de intercambio de claves y SA.
       keylife=1h                # Tiempo de vida de la llave del cifrado.
       rekeymargin=5m            # Margen de tiempo antes de la expiración para la renovación.
       keyingtries=3             # Número máximo de intentos de renegociación.
       keyexchange=ikev2         # Versión del protocolo IKE.
       authby=secret             # Uso de autenticación con clave precompartida (PSK).
       ike=aes256-sha1-modp1024  # Configuración de algoritmos para la fase IKE.
       esp=aes256-sha1           # Configuración de algoritmos para la fase ESP.

conn servidor2a1
       left=90.0.0.2              # Dirección IP publica de la maquina (servidor1).
       leftsubnet=192.168.0.0/24   # Subred privada de la maquina servidor 1.
       right=100.0.0.2             # Dirección IP publica del otro extremo (servidor2).
       rightsubnet=192.168.1.0/24  # Subred privada del otro extremo (servidor 2).
       auto=start                  # Iniciar la conexión automáticamente al arrancar strongSwan.

# Server 2

Next we will set up server 2, I will put you a comment so you know what each option means:

debian@servidor2:~$ sudo cat /etc/ipsec.conf
#Configuración global de strongSwan
config setup
       charondebug="ike 2, knl 2, cfg 2, net 2, esp 2, dmn 2,  mgr 2"

#Configuración por defecto para conexiones VPN
conn %default
       ikelifetime=1h            # Tiempo de vida de la negociación de intercambio de claves y SA.
       keylife=1h                # Tiempo de vida de la llave del cifrado.
       rekeymargin=5m            # Margen de tiempo antes de la expiración para la renovación.
       keyingtries=3             # Número máximo de intentos de renegociación.
       keyexchange=ikev2         # Versión del protocolo IKE.
       authby=secret             # Uso de autenticación con clave precompartida (PSK).
       ike=aes256-sha1-modp1024  # Configuración de algoritmos para la fase IKE.
       esp=aes256-sha1           # Configuración de algoritmos para la fase ESP.

conn servidor2a1
       left=100.0.0.2            # Dirección IP publica de la maquina.
       leftsubnet=192.168.1.0/24  # Subred privada de la maquina.
       right=90.0.0.2            # Dirección IP publica del servidor1.
       rightsubnet=192.168.0.0/24 # Subred privada del servidor 1.
       auto=start                # Iniciar la conexión automáticamente al arrancar strongSwan.

Generation of the shared key

Once you have configured both machines, it is necessary to agree on the use of a shared key called PSK (Pre-Shared Key). You can generate a PSK randomly to improve connection security. Here is an example of how to generate a random key:

debian@servidor1:~$ head -c 24 /dev/urandom | base64
cXPeOAcKIVszFHp68CcGX6dLXcWcbrIl

Now in the / etc / ipsec.secrets file we will configure the PSK key, which at both ends has to be the same:

debian@servidor1:~$ sudo cat /etc/ipsec.secrets 
#Ip publica de la maquina servidor 1
90.0.0.2 : PSK "cXPeOAcKIVszFHp68CcGX6dLXcWcbrIl"

debian@servidor2:~$ sudo cat /etc/ipsec.secrets 
#Ip publica de la maquina servidor 2
100.0.0.2 : PSK "cXPeOAcKIVszFHp68CcGX6dLXcWcbrIl"

Once configured, we will restart the service at both ends:

debian@servidor1:~$ sudo ipsec restart 
debian@servidor2:~$ sudo ipsec restart 

Operating check

We will now see that the tunnel has been lifted at both ends:

debian@servidor1:~$ sudo ipsec status
Security Associations (1 up, 0 connecting):
 servidor1a2[1]: ESTABLISHED 62 seconds ago, 90.0.0.2[90.0.0.2]...100.0.0.2[100.0.0.2]
 servidor1a2{1}:  INSTALLED, TUNNEL, reqid 1, ESP SPIs: ccb4e51d_i c186cf93_o
 servidor1a2{1}:   192.168.0.0/24 === 192.168.1.0/24

debian@servidor2:~$ sudo ipsec status
Security Associations (1 up, 0 connecting):
 servidor2a1[2]: ESTABLISHED 45 seconds ago, 100.0.0.2[100.0.0.2]...90.0.0.2[90.0.0.2]
 servidor2a1{2}:  INSTALLED, TUNNEL, reqid 1, ESP SPIs: c186cf93_i ccb4e51d_o
 servidor2a1{2}:   192.168.1.0/24 === 192.168.0.0/24

It is true that, unlike OpenVPN and WireGuard, StrongSwan does not automatically create a virtual interface for the VPN connection. Instead, it uses the operating system routes to direct traffic through the IPSec tunnel.

Rupture tables

We can see these routes as follows, these are stored in table 220:

debian@servidor1:~$ ip r show table 220
192.168.1.0/24 via 90.0.0.1 dev ens3 proto static src 192.168.0.1 

debian@servidor2:~$ ip route list table 220
192.168.0.0/24 via 100.0.0.1 dev ens3 proto static src 192.168.1.1 

Connectivity check

Once this has been done, we will check that the service machine 2 can reach the machines of the network 192.168.0.0 / 24:

debian@servidor2:~$ ping -c 1 192.168.0.1
PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data.
64 bytes from 192.168.0.1: icmp_seq=1 ttl=64 time=12.7 ms

--- 192.168.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 12.721/12.721/12.721/0.000 ms

debian@servidor2:~$ ping -c 1 192.168.0.2
PING 192.168.0.2 (192.168.0.2) 56(84) bytes of data.
64 bytes from 192.168.0.2: icmp_seq=1 ttl=63 time=11.5 ms

--- 192.168.0.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 11.485/11.485/11.485/0.000 ms

Tunnel statistics

If you want to see if the traffic has passed through the tunnel, you can make a statusol and see the statistics:

debian@servidor1:~$ sudo ipsec statusall 
Status of IKE charon daemon (strongSwan 5.9.8, Linux 6.1.0-17-cloud-amd64, x86_64):
  uptime: 9 minutes, since Jan 28 10:44:01 2024
  malloc: sbrk 2166784, mmap 0, used 1242160, free 924624
  worker threads: 11 of 16 idle, 5/0/0/0 working, job queue: 0/0/0/0, scheduled: 2
  loaded plugins: charon test-vectors ldap pkcs11 aes rc2 sha2 sha1 md5 mgf1 random nonce x509 revocation constraints pubkey pkcs1 pkcs7 pkcs12 pgp dnskey sshkey pem openssl gcrypt pkcs8 af-alg fips-prf gmp curve25519 agent chapoly xcbc cmac hmac kdf ctr ccm gcm drbg curl attr kernel-netlink resolve socket-default connmark forecast farp stroke updown eap-identity eap-aka eap-md5 eap-gtc eap-mschapv2 eap-radius eap-tls eap-ttls eap-tnc xauth-generic xauth-eap xauth-pam tnc-tnccs dhcp lookip error-notify certexpire led addrblock unity counters
Listening IP addresses:
  90.0.0.2
  192.168.0.1
Connections:
 servidor1a2:  90.0.0.2...100.0.0.2  IKEv2
 servidor1a2:   local:  [90.0.0.2] uses pre-shared key authentication
 servidor1a2:   remote: [100.0.0.2] uses pre-shared key authentication
 servidor1a2:   child:  192.168.0.0/24 === 192.168.1.0/24 TUNNEL
Security Associations (1 up, 0 connecting):
 servidor1a2[1]: ESTABLISHED 9 minutes ago, 90.0.0.2[90.0.0.2]...100.0.0.2[100.0.0.2]
 servidor1a2[1]: IKEv2 SPIs: 80b3e1894dc769f5_i* 92c50ec8c2dedde7_r, pre-shared key reauthentication in 
43 minutes
 servidor1a2[1]: IKE proposal: AES_CBC_256/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_1024
 servidor1a2{1}:  INSTALLED, TUNNEL, reqid 1, ESP SPIs: ccb4e51d_i c186cf93_o
 servidor1a2{1}:  AES_CBC_256/HMAC_SHA1_96, 252 bytes_i (3 pkts, 358s ago), 280 bytes_o (3 pkts, 355s ag
o), rekeying in 41 minutes
 servidor1a2{1}:   192.168.0.0/24 === 192.168.1.0/24

Catch with Wireshark

You can also capture the traffic and make sure the messages are encrypted:

Traceroute check

It is also curious because if you make a traceroute the first jump it gives is to the interface 192.168.0.1 of the service1:

debian@servidor2:~$ traceroute 192.168.0.2
traceroute to 192.168.0.2 (192.168.0.2), 30 hops max, 60 byte packets
 1  192.168.0.1 (192.168.0.1)  13.695 ms  13.658 ms  13.712 ms
 2  192.168.0.2 (192.168.0.2)  13.704 ms  13.695 ms  13.678 ms