Strongswan IPSec Mediation – Both Ubuntu Linux 20.04 Peers Behind Cisco NAT

Background

Strongswan is an open source project that implements the IKE protocol which is used for cryptographic key negotiation in the IPSec standard protocol. IPSec is used to build an encrypted network connection between two points on a network, usually the Internet but not always.

Most often, the two points where the encryption and decryption are happening know about each other’s IP address, on the Internet that means they have publicly routable IP addresses. IPSec has a built-in mechanism to handle the scenario if one of these points does not have an a public routable IP address, this is called NAT-Traversal. It looks something like this:

POINT A —> NAT ROUTER —> INTERNET —> POINT B

Point A must initiate the connection to Point B because it has a private IP address (10.x and the like) and that’s the only way the NAT router will let the connection through.

But what if BOTH peers are behind NAT routers with private IP addresses? Something like this:

POINT A —> NAT ROUTER —> INTERNET —> NAT ROUTER —> POINT B

Private-peer-to-private-peer connectivity is established in other network protocols such as VoIP using some sort of 3rd party mediator that performs a trick called UDP hole-punching, where both peers are told by the mediator the public IP address of the NAT Router that is in front of the peer they are trying to connect to. For VoIP this is usually a STUN server. Both peers attempt a connection at the same time, the NAT Routers write translations for the peers, and a connection is built.

While this technique is pretty ancient and many applications implement it, there is not a standard way to do it for IPSec. Strongswan, it seems, has a little known feature for IPSec peer mediation that allows for peer to peer NAT Traversal similar to STUN in VoIP. This feature requires that a third device have a public IP (can’t escape a public IP somewhere in the equation) and running the Strongswan mediation service. It only works with strongswan, although an RFC draft was created back in 2008 in the hopes that mediation for IPSec would be standardized.

Topology

The two Ubuntu 20.04 IPSec peers are both behind Cisco IOSv routers running a basic NAT in Port Address Translation (PAT) mode, which is a tcp/udp port-based one-to-many NAT that is running by default on many consumer routers and is the way the many devices today connect to the Internet. In other words, 192.168.0.3 can not ping 172.16.0.3, and vice versa. But they can both ping 13.0.0.2, where our secret weapon is located, the Strongswan IKE Mediator.

Installation

Installing Strongswan on Ubuntu 20.04 is easy as pie:

apt-get install strongswan

Configuration

UbuntuServer20.04-1

First edit /etc/ipsec.conf

config setup
conn %default
        ikelifetime=60m
        keylife=20m
        rekeymargin=3m
        keyingtries=1
        keyexchange=ikev2
        mobike=no
        dpdaction=restart
        dpddelay=60s
        left=%defaultroute
        leftfirewall=yes

conn medsrv
        leftid=bob@questioncomputer.com
        leftauth=psk
        right=13.0.0.2
        rightid=mediator@questioncomputer.com
        rightauth=psk
        mediation=yes
        authby=secret
        auto=start

conn peer
        leftid=bob@questioncomputer.com
        leftauth=psk
        leftsubnet=192.168.0.0/24
        right=%any
        rightid=alice@questioncomputer.com
        rightsubnet=172.16.0.0/24
        rightauth=psk
        authby=secret
        mediated_by=medsrv
        auto=start

Then edit /etc/ipsec.secrets to put your PSK in there:

mediator@questioncomputer.com : PSK "james"
bob@questioncomputer.com : PSK "james"
alice@questioncomputer.com : PSK "james"

UbuntuServer20.04-2

First edit /etc/ipsec.conf

conn %default
        ikelifetime=60m
        keylife=20m
        rekeymargin=3m
        keyingtries=1
        keyexchange=ikev2
        mobike=no
        dpdaction=restart
        dpddelay=60s
        left=%defaultroute
        leftfirewall=yes
conn medsrv
        leftid=alice@questioncomputer.com
        leftauth=psk
        right=13.0.0.2
        rightid=mediator@questioncomputer.com
        rightauth=psk
        mediation=yes
        auto=add

conn peer
        leftid=alice@questioncomputer.com
        leftauth=psk
        leftsubnet=172.16.0.0/24
        right=%any
        rightid=bob@questioncomputer.com
        rightsubnet=192.168.0.0/24
        rightauth=psk
        mediated_by=medsrv
        authby=secret
        auto=start

Then edit /etc/ipsec.secrets to put your PSK in there:

mediator@questioncomputer.com : PSK "james"
bob@questioncomputer.com : PSK "james"
alice@questioncomputer.com : PSK "james"

Mediator (UbuntuServer20.04-4)

First edit /etc/ipsec.conf

conn %default
        ikelifetime=60m
        keylife=20m
        rekeymargin=3m
        keyingtries=1
        keyexchange=ikev2
        mobike=no
        dpdaction=clear
        dpddelay=60s

conn medsrv
        left=13.0.0.2
        leftid=mediator@questioncomputer.com
        leftauth=psk
        leftfirewall=yes
        right=%any
        rightauth=psk
        mediation=yes
        authby=secret
        auto=add

Then edit /etc/ipsec.secrets

mediator@questioncomputer.com : PSK "james"<br>bob@questioncomputer.com : PSK "james"<br>alice@questioncomputer.com : PSK "james"

Make sure to issue this on all three to load your configs:

ipsec restart

Verification

A healthy connection can be checked with the ‘ipsec’ command:

root@u2004:/home/james/strongswan# ipsec statusall
Status of IKE charon daemon (strongSwan 5.9.0, Linux 5.4.0-29-generic, x86_64):
  uptime: 103 minutes, since Oct 08 19:38:24 2020
  malloc: sbrk 1748992, mmap 0, used 902656, free 846336
  worker threads: 11 of 16 idle, 5/0/0/0 working, job queue: 0/0/0/0, scheduled: 14
  loaded plugins: charon agent connmark eap-mschapv2 aes des rc2 sha2 sha3 sha1 md5 mgf1 random nonce x509 revocation constraints pubkey pkcs1 pkcs7 pkcs8 pkcs12 pgp dnskey sshkey pem openssl fips-prf gmp curve25519 chapoly xcbc cmac hmac gcm drbg attr kernel-netlink resolve socket-default socket-dynamic stroke vici updown xauth-generic lookip error-notify addrblock unity counters
Listening IP addresses:
  192.168.0.3
Connections:
      medsrv:  %any...13.0.0.2  IKEv2, dpddelay=60s
      medsrv:   local:  [left@questioncomputer.com] uses pre-shared key authentication
      medsrv:   remote: [mediator@questioncomputer.com] uses pre-shared key authentication
      medsrv:   child:  dynamic === dynamic TUNNEL, dpdaction=restart
        peer:  %any...%any  IKEv2, dpddelay=60s
        peer:   local:  [left@questioncomputer.com] uses pre-shared key authentication
        peer:   remote: [right@questioncomputer.com] uses pre-shared key authentication
        peer:   child:  192.168.0.0/24 === 172.16.0.0/24 TUNNEL, dpdaction=restart
Security Associations (2 up, 0 connecting):
        peer[6]: ESTABLISHED 2 minutes ago, 192.168.0.3[left@questioncomputer.com]...12.0.0.2[right@questioncomputer.com]
        peer[6]: IKEv2 SPIs: 400da3c783ad093d_i 35869903e6803225_r*, pre-shared key reauthentication in 52 minutes
        peer[6]: IKE proposal: AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/ECP_256
        peer{10}:  INSTALLED, TUNNEL, reqid 1, ESP in UDP SPIs: c01b6c68_i c56e26d5_o
        peer{10}:  AES_CBC_128/HMAC_SHA2_256_128, 0 bytes_i, 0 bytes_o, rekeying in 12 minutes
        peer{10}:   192.168.0.0/24 === 172.16.0.0/24
      medsrv[3]: ESTABLISHED 49 minutes ago, 192.168.0.3[left@questioncomputer.com]...13.0.0.2[mediator@questioncomputer.com]
      medsrv[3]: IKEv2 SPIs: 127a15068a32e07f_i* 703cba84aa11f49e_r, pre-shared key reauthentication in 2 minutes
      medsrv[3]: IKE proposal: AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/ECP_256

You’ll be looking to see that both the “medsrv” and “peer” connections are in an “Established” state.

And of course as always, make sure you ping across the tunnel to make sure it works.

As an added bonus, I was able to ping through the tunnel from l92.168.0.3 to the Cisco NAT Router at 172.16.0.1, I just need to add a route on the Cisco NAT Router by issuing “ip route 192.168.0.0 255.255.255.0 172.16.0.3”.

Troubleshooting

The log file where most logs go in Ubuntu is at ‘/var/log/syslog’, grepping for “charon” will help you sort them:

root@u2004:/home/james/strongswan# tail /var/log/syslog | grep charon
Oct  8 21:28:41 u2004 charon: 13[NET] sending packet: from 192.168.0.3[4500] to 12.0.0.2[4500] (80 bytes)
Oct  8 21:28:41 u2004 charon: 16[NET] received packet: from 12.0.0.2[4500] to 192.168.0.3[4500] (80 bytes)
Oct  8 21:28:41 u2004 charon: 16[ENC] parsed INFORMATIONAL response 8 [ ]

And as usual, do a packet capture to see if the two peers are trying to build a connection to each other. If packets are not being generated or dropped somewhere, you’ll know where to look for a problem. You can filter for “isakmp” packets to narrow things down:

In the above image you can see there is a connection between the NAT routers 11.0.0.2 and 12.0.0.2, but also connections to the mediator at 13.0.0.2.

IPsec on Linux – Strongswan Configuration (IKEv2, Route-Based GRE, PSK)

Background

IPsec is a handy tool for encryption connections on networks, but it can be a bit complicated to configure, especially when you’re dealing with multiple vendors. On Linux, the protocol that encrypts connections is built-in to the kernel, it’s called Encapsulating Security Payload. However there are many security parameters that need to be configured, so a tool is usually needed to handle the task of figuring that out. That’s where the IKE protocol comes in to handle negotiation of cryptographic keys and parameters between the two IPsec tunnel endpoints.

There are several projects that implement the IKE protocol on Linux, my personal favorite is Strongswan, due to its active development on Github and comprehensive implementation of IPsec’s features. You can check out the Strongswan website and their Github page for more information and open source code.

A “standard” IPsec tunnel usually has the two LAN subnets that the tunnel will be connecting configured into the tunnel “policy”, and is negotiated when bringing up the tunnel. Changing those subnets requires bringing down the tunnel and manually re-configuring it by hand. A solution to this is a “route-based” tunnel. instead of a policy, a logical or “virtual” interface (a network interface with no physical counterpart) exists with an IP address on it. Once the tunnel interface is up and encryption is working, you can treat it like any other interface and apply policies, shaping, routing protocols, etc. It’s like an Ethernet cable made out of math. There are two kinds (that I know of) of route-based tunneling, GRE and VTI. Today I’m going to configure GRE.

Ubuntu 18.04 Server

Ubuntu Linux 18.04 makes installation of Strongswan nice and easy with its package manager:

apt-get install strongswan

This can be out of date, though. If you want a really new version of Strongswan, you can try compiling from source using Github. Ubuntu 18.04 repositories have Strongswan 5.6.2, which is pretty feature-complete.

Topology

We’re trying to get Host1 (Ubuntu 18.04 Server) to be able to reach Host2 (Ubuntu 18.04 Server). You can think of the top of the topology as an Internet-like network, where the private networks that Host1 and Host2 are attached to cannot directly reach other, and wouldn’t want to even if they could since the Internet is not such a friendly place. Encryption and authentication are needed, which the IPsec tunnel provides.

Inside the tunnel there is a another set of IP-headers encapsulating packets, which is the essence of a tunnel in networking. There are virtual interfaces on either side, in this case I’ve randomly chosen 100.0.0.1/30 for the Ubuntu side and 100.0.0.2/30 for the Cisco side. The Ubuntu box has a tunnel interface name “james_gre”, while the Cisco box has an interface name of “tunnel0”.

Router1 (Ubuntu18.04)

The first order of business is to create a GRE virtual interface. It’s pretty straightforward on Ubuntu 18.04:

#Add the interface
ip tunnel add james_gre local 10.10.10.1 remote 30.30.30.2 mode gre

#Activate it
ip link set james_gre up

#Add an IP address
ip addr add 100.0.0.1/30 dev james_gre

#Set the MTU, to account for GRE/ESP protocol overhead
ip link set dev james_gre mtu 1440

Second, we configure Strongswan. First edit the text file /etc/ipsec.conf in you favorite text editor, I use Vim. It should look something like this:

config setup
 strictctlpolicy=yes
 uniqueids=no

conn james_tunnel
 left=10.10.10.1         #Outside interface of this router
 leftprotoport=47        #IP protocol 47 for GRE
 right=30.30.30.2        #Outside interface of the cisco router
 rightprotoport=47       #IP protocol 47 for GRE
 ike=aes256-sha2_256-modp1024! #Corresponds to cisco ikev2 proposal
 esp=aes-sha2_256!       #Corresponds to cisco transform set
 keyingtries=0
 ikelifetime=1h
 lifetime=8h
 authby=secret
 auto=start
 keyexchange=ikev2
 type=transport          #Corresponds to cisco transform set "mode"

I use transport mode for less overhead, although you can use tunnel mode if you want. Just make sure all parameters on both sides match. Notice there is no policy to specify subnets to traverse the tunnel, the routing table determines that. Hence, route-based tunnel.

Then edit the /etc/ipsec.secrets text file, it should look like this:

10.10.10.1 30.30.30.2 : PSK '12345'

Finally, restart strongswan to load your configuration.

ipsec restart

Router4 (Cisco IOSv, 15.4)

The Cisco IOS configuration is much like a policy-based tunnel except in place of a crypto-map there is an “ipsec profile”. This profile is attached to the GRE tunnel interface. Make sure to specify “mode transport” in your transform set. Your configuration will look like this, I’ve edited for brevity:

crypto ikev2 proposal james-proposal 
 encryption aes-cbc-256
 integrity sha256
 group 2
!
crypto ikev2 policy james-policy 
 proposal james-proposal
!
crypto ikev2 keyring james-ring
 peer remote-router-james
  address 10.10.10.1
  pre-shared-key 12345
 !
!
crypto ikev2 profile james-profile
 match identity remote address 10.10.10.1 255.255.255.255 
 authentication remote pre-share
 authentication local pre-share
 keyring local james-ring
!
crypto ipsec transform-set james-trans esp-aes esp-sha256-hmac 
 mode transport
!
crypto ipsec profile james-protect-gre
 set transform-set james-trans 
 set ikev2-profile james-profile
!
interface Tunnel0
 ip address 100.0.0.2 255.255.255.252
 ip mtu 1440
 tunnel source 30.30.30.2
 tunnel destination 10.10.10.1
 tunnel protection ipsec profile james-protect-gre
!
interface Ethernet0/0
 ip address 30.30.30.2 255.255.255.252
!
interface Ethernet0/1
 ip address 172.16.0.1 255.255.255.0

Verification

Router1 (Ubuntu18.04)

You can check to see the status of a particular tunnel with:

root@uvm1804:ipsec status james_tunnel

#Produces the following output:
Security Associations (1 up, 0 connecting):
james_tunnel[9]: ESTABLISHED 42 minutes ago, 10.10.10.1[10.10.10.1]...30.30.30.2[30.30.30.2]
james_tunnel{9}:  INSTALLED, TRANSPORT, reqid 6, ESP SPIs: c4f61431_i b854a518_o
james_tunnel{9}:   10.10.10.1/32[gre] === 30.30.30.2/32[gre]

The above output shows an established tunnel. Also try pinging across the tunnel, that’s always a surefire way to tell if things are working well.

Router4 (Cisco IOSv, 15.4)

On a Cisco IOS device, you can always use this command to show tunnel status:

Router4#show crypto session
Crypto session current status
Interface: Tunnel0
Profile: james-profile
Session status: UP-ACTIVE     
Peer: 10.10.10.1 port 4500 
  Session ID: 13  
  IKEv2 SA: local 30.30.30.2/4500 remote 10.10.10.1/4500 Active 
  IPSEC FLOW: permit 47 host 30.30.30.2 host 10.10.10.1 
        Active SAs: 2, origin: crypto map
Router4#

Don’t forget you’ll also need to install routes, either statically or with a protocol, to get traffic other than pings across. Did I mention this is a route-based VPN?

Troubleshooting

Router1 (Ubuntu18.04)

My favorite command to troubleshoot Strongswan is this one:

cat /var/log/syslog | grep charon

Which produces the logs of Charon, the Strongswan IKE daemon. If there’s something wrong, you’ll probably notice it in here. The system log file is different on different Linux distributions, check yours to be sure which one.

Router4 (Cisco IOSv, 15.4)

In addition to “show crypto session”, you can run debugs for IPsec and ISAKMP on a Cisco IOS device:

Router4#debug crypto ipsec
Crypto IPSEC debugging is on
Router4#debug crypto isakmp
Crypto ISAKMP debugging is on
Router4#
*Feb  1 06:51:20.425: IPSEC(key_engine): got a queue event with 1 KMI message(s)
*Feb  1 06:51:20.425: IDB is NULL : in crypto_ipsec_key_engine_delete_sas (), 5101
*Feb  1 06:51:20.425: IPSEC(key_engine_delete_sas): rec'd delete notify from ISAKMP
*Feb  1 06:51:20.425: IPSEC:(SESSION ID = 13) still in use sa: 0xF5222CE4
*Feb  1 06:51:20.425: IPSEC:(SESSION ID = 13) (key_engine_delete_sas) delete SA with spi 0xD0337743 proto 50 for 30.30.30.2
*Feb  1 06:51:20.425: IPSEC:(SESSION ID = 13) (delete_sa) deleting SA,
  (sa) sa_dest= 30.30.30.2, sa_proto= 50, 
    sa_spi= 0xD0337743(3493033795), 
    sa_trans= esp-aes esp-sha256-hmac , sa_conn_id= 14
    sa_lifetime(k/sec)= (4608000/3600),
  (identity) local= 30.30.30.2:0, remote= 10.10.10.1:0,
    local_proxy= 30.30.30.2/255.255.255.255/47/0,
    remote_proxy= 10.10.10.1/255.255.255.255/47/0
*Feb  1 06:51:20.425: IPSEC:(SESSION ID = 13) (delete_sa) deleting SA,

Be ready for some pretty funky output, and a lot of it. Generally you should be able to find some clues in the debug, though.

You’ll also want to do a packet capture, if possible. You’ll be looking for ISAKMP (a subset of IKE) messages attempting to establish the tunnel first:

Then when the tunnel is established, you’ll only see ESP packets where data should be. If you’re seeing unencrypted, something is definitely wrong:

Hit me up if you have a question or a tunnel you’re troubleshooting. I’m happy to help.

IPsec on Linux – Strongswan Configuration (IKEv2, Policy-Based, PSK)

Background

The idea behind a VPN is to create a tunnel, that is to say, packets that have IP packets embedded inside IP packets. The private part means the this tunnel is encrypted so that an attacker listening along the path between the two tunnel endpoints will not be able to steal any meaningful data.

Some info about Strongswan – it’s an implementation of the IKE protocol (Internet Key Exchange) which is designed to secure exchange cryptographic key information across an untrusted network, usually the Internet, but not always. The actual encrypting of packets and sending them using a protocol called ESP (Encapsulating Security Payload) is already built into Linux, but Strongswan is needed to give ESP the correct key information to build the tunnel.

There are other IKE implementations, but I find Strongswan the be the best and most actively updated as of this writing in January 2020. You can find the Strongswan website and their documentation at https://www.strongswan.org/, as well as their Github page with the most recent code at https://github.com/strongswan/strongswan.

There are lots of ways to configure IPsec, but for this lab we’ll be using IKE version 2 with a policy-based configuration. The policy-based part means a policy negotiated by the two tunnel endpoints (routers) determines what traffic is allowed or not allowed into the tunnel. Another way to do this is route-based, where the routing tables determine tunneled traffic, allowing for more flexibility. But that’s a story for another day.

Installation

Strongswan can be installed with relative ease on a number of Linux distributions that have package managers, on Ubuntu this is pretty simple:

Ubuntu 18.04 Server

apt-get install strongswan

You can also build from source to get a more recent version, although you’ll probably want to get the instructions from their Github page, as building from source is more involved.

Topology

The idea here is to get UbuntuServer18.04-1 on the bottom left to be able to reach UbuntuServer18.04-2 on the bottom right. You can think of the U_18Router and CiscoIOSv15.6(2)T-3 as being connected to an Internet-like network, for this lab’s purposes. Needless to say, the subnet 192.168.0.0/24 on the left can’t reach 172.16.0.0/24 on the right without some sort of tunnel mechanism, and traffic needs to be encrypted as someone is capturing packets in the middle. A man in the middle, if you will 😛

I’ll be configuring Strongswan on an Ubuntu18.04 Server (U18_Router) on one end and a Cisco IOSv router on the other end. That way we can see that it actually works with other vendors.

Configuration

U18_Router (Ubuntu18.04)

First edit the text file /etc/ipsec.conf using your favorite text editor, I use vim. It should look something like this:

config setup
 strictctlpolicy=yes
 uniqueids=no

conn &default
 ikelifetime=1440m
 keylife=60m

conn james_tunnel
 left=1.1.1.1  #Outside interface of this router
 leftsubnet=192.168.0.0/24  #Inside network behind this router
 right=3.3.3.2  #Outside interface of the cisco router
 rightsubnet=172.16.0.0/24  #Inside network of the cisco router
 ike=aes256-sha2_256-modp1024!  #Corresponds to cisco ikev2 proposal
 esp=aes-sha2_256!  #Corresponds to cisco transform set
 keyingtries=0
 ikelifetime=1h
 lifetime=8h
 authby=secret
 auto=start
 keyexchange=ikev2
 type=tunnel  #Corresponds to transform set "mode"

Then edit /etc/ipsec.secrets, and put your pre-shared key in there along with tunnel endpoint IP addresses:

1.1.1.1 3.3.3.2 : PSK '12345'

Then restart strongswan to load your configuration

ipsec restart

CiscoIOSv15.6(2)T-3

This is an abbreviated version of the Cisco IOS router configuration, as they tend to include a lot of info that’s not relevant here:

crypto ikev2 proposal james-proposal 
 encryption aes-cbc-256
 integrity sha256
 group 2
!
crypto ikev2 policy james-policy 
 proposal james-proposal
!
crypto ikev2 keyring james-ring
 peer remote-router-james
  address 1.1.1.1
  pre-shared-key 12345
 !
!         
crypto ikev2 profile james-profile
 match identity remote address 1.1.1.1 255.255.255.255 
 authentication local pre-share
 authentication remote pre-share
 keyring local james-ring
!
crypto ipsec transform-set james-trans esp-aes esp-sha256-hmac 
 mode tunnel
!
crypto map james-map 1 ipsec-isakmp 
 set peer 1.1.1.1
 set transform-set james-trans 
 set ikev2-profile james-profile
 match address james-vpn
!         
interface GigabitEthernet0/0
 ip address 3.3.3.2 255.255.255.0
 duplex auto
 speed auto
 media-type rj45
 crypto map james-map
!
interface GigabitEthernet0/1
 ip address 172.16.0.1 255.255.255.0
 duplex auto
 speed auto
 media-type rj45
!
ip route 0.0.0.0 0.0.0.0 3.3.3.1
!
ip access-list extended james-vpn
 permit ip 172.16.0.0 0.0.0.255 192.168.0.0 0.0.0.255

Verification

U18_Router (Ubuntu18.04)

Verifying the status of your tunnel is fairly simple, just issue the command ‘ipsec statusall’. Below is an example of a tunnel that’s up an running:

root@uvm1804:/var/log# ipsec statusall
Status of IKE charon daemon (strongSwan 5.6.2, Linux 4.15.0-20-generic, x86_64):
  uptime: 19 hours, since Jan 15 21:48:59 2020
  malloc: sbrk 1626112, mmap 0, used 861840, free 764272
  worker threads: 11 of 16 idle, 5/0/0/0 working, job queue: 0/0/0/0, scheduled: 5
  loaded plugins: charon aes rc2 sha2 sha1 md4 md5 mgf1 random nonce x509 revocation constraints pubkey pkcs1 pkcs7 pkcs8 pkcs12 pgp dnskey sshkey pem openssl fips-prf gmp agent xcbc hmac gcm attr kernel-netlink resolve socket-default connmark stroke updown eap-mschapv2 xauth-generic counters
Listening IP addresses:
  1.1.1.1
  192.168.0.1
Connections:
      tunnel:  1.1.1.1...3.3.3.2  IKEv2
      tunnel:   local:  [1.1.1.1] uses pre-shared key authentication
      tunnel:   remote: [3.3.3.2] uses pre-shared key authentication
      tunnel:   child:  192.168.0.0/24 === 172.16.0.0/24 TUNNEL
Security Associations (1 up, 0 connecting):
      tunnel[26]: ESTABLISHED 6 minutes ago, 1.1.1.1[1.1.1.1]...3.3.3.2[3.3.3.2]
      tunnel[26]: IKEv2 SPIs: 8c847c9fa74fd6f6_i 5158e0ac789bebb4_r*, pre-shared key reauthentication in 40 minutes
      tunnel[26]: IKE proposal: AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_1024
      tunnel{42}:  INSTALLED, TUNNEL, reqid 25, ESP SPIs: cda62364_i bb016c85_o
      tunnel{42}:  AES_CBC_128/HMAC_SHA2_256_128, 8400 bytes_i (100 pkts, 271s ago), 8400 bytes_o (100 pkts, 271s ago), rekeying in 36 minutes
      tunnel{42}:   192.168.0.0/24 === 172.16.0.0/24

CiscoIOSv15.6(2)T-3

On an Cisco IOS device, there are a few different show commands you can use to verify tunnel status however I find ‘show crypto session’ to quickly get you the info you need. You can get more info by adding ‘detail’ on the end:

Router#show crypto session
Crypto session current status

Interface: GigabitEthernet0/0
Profile: james-profile
Session status: UP-ACTIVE     
Peer: 1.1.1.1 port 500 
  Session ID: 95  
  IKEv2 SA: local 3.3.3.2/500 remote 1.1.1.1/500 Active 
  IPSEC FLOW: permit ip 172.16.0.0/255.255.255.0 192.168.0.0/255.255.255.0 
        Active SAs: 2, origin: crypto map

Router#

Packet Capture

A packet capture can really help you figure out how far you have progressed and what next steps should be taken to solve a configuration issue or troubleshoot a problem. After you configure Strongswan on Linux and Crypto map on your Cisco, you should be seeing ISAKMP (an extension of IKE) protocol messages in the packet capture that are negotiating tunnel parameters:

Finally, when you have a tunnel established, you should see ESP packets carrying the actual data when UbuntuServer18.04-1 and UbuntuServer18.04-2 ping each other. You should NOT see ICMP (ping) packets in your capture.

Troubleshooting

U18_Router (Ubuntu18.04)

The Strongswan IKE daemon is called “charon”, and it deposits its log messages in the system syslog file. On different distributions this is in different locations or uses a different name, in Ubuntu 18.04 it’s in /var/log/syslog. You can search this file for clues as to what’s going wrong, I suggest using grep to find what you’re looking for. A useful starting point would be to issue ‘cat /var/log/syslog | grep charon’ to show only charon messages. The following example is an example of a typo in the Strongswan configuration resulting in the charon exiting and not attempting to bring up the tunnel. You would not see any ISAKMP packets in your packet capture:

Jan 16 18:00:22 uvm1804 charon: 00[DMN] Starting IKE charon daemon (strongSwan 5.6.2, Linux 4.15.0-20-generic, x86_64)
Jan 16 18:00:22 uvm1804 charon: 00[CFG] loading ca certificates from '/etc/ipsec.d/cacerts'
Jan 16 18:00:22 uvm1804 charon: 00[CFG] loading aa certificates from '/etc/ipsec.d/aacerts'
Jan 16 18:00:22 uvm1804 charon: 00[CFG] loading ocsp signer certificates from '/etc/ipsec.d/ocspcerts'
Jan 16 18:00:22 uvm1804 charon: 00[CFG] loading attribute certificates from '/etc/ipsec.d/acerts'
Jan 16 18:00:22 uvm1804 charon: 00[CFG] loading crls from '/etc/ipsec.d/crls'
Jan 16 18:00:22 uvm1804 charon: 00[CFG] loading secrets from '/etc/ipsec.secrets'
Jan 16 18:00:22 uvm1804 charon: 00[CFG]   loaded IKE secret for 1.1.1.1 3.3.3.2
Jan 16 18:00:22 uvm1804 charon: 00[LIB] loaded plugins: charon aes rc2 sha2 sha1 md4 md5 mgf1 random nonce x509 revocation constraints pubkey pkcs1 pkcs7 pkcs8 pkcs12 pgp dnskey sshkey pem openssl fips-prf gmp agent xcbc hmac gcm attr kernel-netlink resolve socket-default connmark stroke updown eap-mschapv2 xauth-generic counters
Jan 16 18:00:22 uvm1804 charon: 00[LIB] dropped capabilities, running as uid 0, gid 0
Jan 16 18:00:22 uvm1804 charon: 00[JOB] spawning 16 worker threads
Jan 16 18:00:22 uvm1804 charon: 05[CFG] received stroke: add connection 'tunnel'
Jan 16 18:00:22 uvm1804 charon: 05[CFG] algorithm 'aes265' not recognized
Jan 16 18:00:22 uvm1804 charon: 05[CFG] skipped invalid proposal string: aes265-sha2_256-modp1024
Jan 16 18:00:22 uvm1804 charon: 07[CFG] received stroke: initiate 'tunnel'
Jan 16 18:00:22 uvm1804 charon: 07[CFG] no config named 'tunnel'
root@uvm1804:/var/log# 

You’ll notice on line 13 it says “algorithm ‘aes265’ not recognized”. That’s because AES265 isn’t a thing. It’s AES256.

Another example that may be harder to detect and requires some good “stare and compare” skills, would be mismatched encryption/authentication parameters. Your configurations may be valid but if parameters don’t match up, your tunnel won’t come up. The following is an example of when ESP parameters aren’t matching. On the Ubuntu side I’ve specified AES256 for ESP but the Cisco’s transform set calls for AES, which is short for AES128:

Jan 16 18:08:38 uvm1804 charon: 05[CFG] added configuration 'tunnel'
Jan 16 18:08:38 uvm1804 charon: 07[CFG] received stroke: initiate 'tunnel'
Jan 16 18:08:38 uvm1804 charon: 07[IKE] initiating IKE_SA tunnel[1] to 3.3.3.2
Jan 16 18:08:38 uvm1804 charon: 07[ENC] generating IKE_SA_INIT request 0 [ SA KE No N(NATD_S_IP) N(NATD_D_IP) N(FRAG_SUP) N(HASH_ALG) N(REDIR_SUP) ]
Jan 16 18:08:38 uvm1804 charon: 07[NET] sending packet: from 1.1.1.1[500] to 3.3.3.2[500] (334 bytes)
Jan 16 18:08:38 uvm1804 charon: 09[NET] received packet: from 3.3.3.2[500] to 1.1.1.1[500] (348 bytes)
Jan 16 18:08:38 uvm1804 charon: 09[ENC] parsed IKE_SA_INIT response 0 [ SA KE No V V N(NATD_S_IP) N(NATD_D_IP) ]
Jan 16 18:08:38 uvm1804 charon: 09[IKE] received Cisco Delete Reason vendor ID
Jan 16 18:08:38 uvm1804 charon: 09[IKE] received Cisco FlexVPN Supported vendor ID
Jan 16 18:08:38 uvm1804 charon: 09[IKE] authentication of '1.1.1.1' (myself) with pre-shared key
Jan 16 18:08:38 uvm1804 charon: 09[IKE] establishing CHILD_SA tunnel{1}
Jan 16 18:08:38 uvm1804 charon: 09[ENC] generating IKE_AUTH request 1 [ IDi N(INIT_CONTACT) IDr AUTH SA TSi TSr N(MOBIKE_SUP) N(ADD_4_ADDR) N(EAP_ONLY) N(MSG_ID_SYN_SUP) ]
Jan 16 18:08:38 uvm1804 charon: 09[NET] sending packet: from 1.1.1.1[4500] to 3.3.3.2[4500] (272 bytes)
Jan 16 18:08:38 uvm1804 charon: 10[NET] received packet: from 3.3.3.2[4500] to 1.1.1.1[4500] (160 bytes)
Jan 16 18:08:38 uvm1804 charon: 10[ENC] parsed IKE_AUTH response 1 [ V IDr AUTH N(NO_PROP) ]
Jan 16 18:08:38 uvm1804 charon: 10[IKE] authentication of '3.3.3.2' with pre-shared key successful
Jan 16 18:08:38 uvm1804 charon: 10[IKE] IKE_SA tunnel[1] established between 1.1.1.1[1.1.1.1]...3.3.3.2[3.3.3.2]
Jan 16 18:08:38 uvm1804 charon: 10[IKE] scheduling reauthentication in 2848s
Jan 16 18:08:38 uvm1804 charon: 10[IKE] maximum IKE_SA lifetime 3388s
Jan 16 18:08:38 uvm1804 charon: 10[IKE] received NO_PROPOSAL_CHOSEN notify, no CHILD_SA built
Jan 16 18:08:38 uvm1804 charon: 10[IKE] failed to establish CHILD_SA, keeping IKE_SA
root@uvm1804:/var/log# 

You’ll notice that the last message states “failed to establish CHILD_SA” which generally means your ESP parameters don’t match, on the Cisco side you’ll need to check your transform set. If your IKE proposal doesn’t match, you’ll get a different message about no proposal being chosen. On the Cisco side you’ll need to check your IKE proposal as well.

CiscoIOSv15.6(2)T-3

You’ll notice that when the Ubuntu Strongswan router isn’t trying to bring up it’s tunnel due to an invalid configuration, the Cisco IOS device says it’s tunnel is DOWN:

Router#show crypto session
Crypto session current status

Interface: GigabitEthernet0/0
Session status: DOWN
Peer: 1.1.1.1 port 500 
  IPSEC FLOW: permit ip 172.16.0.0/255.255.255.0 192.168.0.0/255.255.255.0 
        Active SAs: 0, origin: crypto map

Router#

When parameters mismatch, you’ll see an UP-IDLE session status:

Router#show crypto session
Crypto session current status

Interface: GigabitEthernet0/0
Profile: james-profile
Session status: UP-IDLE
Peer: 1.1.1.1 port 4500 
  Session ID: 101  
  IKEv2 SA: local 3.3.3.2/4500 remote 1.1.1.1/4500 Active 

Router#

IPsec is a compex protocol, but when it works it’s pretty cool. Shoot me a message or post a comment if you’re having trouble with a VPN tunnel, I’m always happy to help if I can.