IPsec on Linux – Strongswan Configuration w/Cisco IOSv (IKEv2, Route-Based VTI, PSK)

IPsec is a cool tool for encrypting connections between network nodes, usually over the Internet (but not always). There are many different ways to configure an IPsec tunnel. Many tunnels use a policy-based approach which means the traffic that is sent through the tunnel is pre-defined using a “policy” that is part of the configuration. That doesn’t always work, you may need to dynamically change what traffic goes through using a routing protocol like OSPF or EIGRP without having to bring the tunnel down and reconfigure it . Thus there is another option, a “route-based” tunnel.

There are two different methods for creating a route-based IPsec tunnel, the first using GRE, which inserts a second GRE IP header into packets going into the tunnel. The second is VTI, which operates in a similar manner to GRE but under the hood it’s quite a different implementation.

VTI was originally way to save IP space on point-to-point links in the early networking days before subnetting. It was adapted as a way to assign routes to an IPsec tunnel. Part of its legacy is a “numbered” or “unnumbered” mode. Originally, VTI could inherit an IP from another interface and save IP address space. This unnumbered mode is pretty strange, so today we’ll take a look at numbered mode to keep things familiar.

Topology

Pretty simple, we’re trying to get the Window10 box at the bottom left to ping the Ubuntu Server 18.04 at the bottom right to ping each other. We’ll configure a tunnel between the Ubuntu box at the top left and the Cisco IOSv router at the top right. The underlying 1.1.1.0/30 network serves to look like a WAN network, while the network inside the VTI tunnel will be 10.0.0.0/30.

Installation

Ubuntu18.04-FRR-1


Strongswan on Ubuntu 18.04 is pretty easy with apt-get:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
apt-get install strongswan
apt-get install strongswan
apt-get install strongswan

Configuration

Ubuntu18.04-FRR-1

First you need to add a config to /etc/ipsec.conf, something that looks like this:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
conn tunnel
leftupdown=/usr/local/sbin/ipsec-notify.sh #run this script on start
left=166.0.0.5
leftsubnet=0.0.0.0/0 #all traffic
right=166.0.0.1
rightsubnet=0.0.0.0/0 #all traffic
ike=aes256-sha2_256-modp1024!
esp=aes-sha2_256!
authby=secret
auto=start
keyexchange=ikev2
mark=32 # only accepts packets with this mark
type=transport
conn tunnel leftupdown=/usr/local/sbin/ipsec-notify.sh #run this script on start left=166.0.0.5 leftsubnet=0.0.0.0/0 #all traffic right=166.0.0.1 rightsubnet=0.0.0.0/0 #all traffic ike=aes256-sha2_256-modp1024! esp=aes-sha2_256! authby=secret auto=start keyexchange=ikev2 mark=32 # only accepts packets with this mark type=transport
conn tunnel 
        leftupdown=/usr/local/sbin/ipsec-notify.sh #run this script on start
        left=166.0.0.5
        leftsubnet=0.0.0.0/0 #all traffic
        right=166.0.0.1
        rightsubnet=0.0.0.0/0 #all traffic
        ike=aes256-sha2_256-modp1024!
        esp=aes-sha2_256!
        authby=secret
        auto=start
        keyexchange=ikev2
        mark=32 # only accepts packets with this mark
        type=transport

Then configure the PSK in /etc/ipsec.secrets:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
1.1.1.2 1.1.1.1 : PSK '12345'
1.1.1.2 1.1.1.1 : PSK '12345'
1.1.1.2 1.1.1.1 : PSK '12345'

Then create the tunnel script that is referenced in the config. For me the file will be located at /home/james/ipsec-notify.sh:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
ip link add vti0 type vti local 1.1.1.2 remote 1.1.1.1 key 32
ip link set vti0 up
ip addr add 10.0.0.2/30 dev vti0
ip lin set dev vti0 mtu 1400
ip link add vti0 type vti local 1.1.1.2 remote 1.1.1.1 key 32 ip link set vti0 up ip addr add 10.0.0.2/30 dev vti0 ip lin set dev vti0 mtu 1400
ip link add vti0 type vti local 1.1.1.2 remote 1.1.1.1 key 32
ip link set vti0 up
ip addr add 10.0.0.2/30 dev vti0
ip lin set dev vti0 mtu 1400

Note the “key 32” in the first line above. That identifies what traffic strongswan should encrypt and corresponds to the “mark” in the strongswan config. It’s important.

Next you need to add a line for your VTI interface in /etc/sysctl.conf that looks like this to disable kernel policy lookups, this is a routed interface:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
net.ipv4.conf.vti0.disable_policy=1
net.ipv4.conf.vti0.disable_policy=1
net.ipv4.conf.vti0.disable_policy=1

Finally, you need to tell Charon (Strongswan’s IKE daemon) to not handle routing. We’ll handle routing on our own. In /etc/strongswan.d/charon.conf, find this line:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
install_routes = no
install_routes = no
install_routes = no

Make sure it’s set to no. Tell strongswan to restart and the tunnel should attempt a connection:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
ipsec restart
ipsec restart
ipsec restart

CiscoIOSv15.6(2)T-1

Static routing

Ubuntu18.04-FRR-1

Pretty simple, just add a route for 172.16.0.0/24 pointing to 10.0.0.1

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
ip route add 172.16.0.0/24 via 10.0.0.1
ip route add 172.16.0.0/24 via 10.0.0.1
ip route add 172.16.0.0/24 via 10.0.0.1

CiscoIOSv15.6(2)T-1

Optional – EIGRP Routing

Remove those static routes and we’ll try a protocol to achieve the aforementioned dynamic routing.

Ubuntu18.04-FRR-1

Checkout my post on setting up EIGRP with Free Range Routing on Linux for the installation. Assuming you have that done, just log into the FRR shell on Ubuntu, it’s in /snap/bin, or just use the full path:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
/snap/bin/frr.vtysh
Hello, this is FRRouting (version 7.2.1).
Copyright 1996-2005 Kunihiro Ishiguro, et al.
james#
james# conf t
james(config)# router eigrp 10
james(config-router)# network 192.168.0.0/24
james(config-router)# network 10.0.0.0/30
james(config-router)# end
james#
/snap/bin/frr.vtysh Hello, this is FRRouting (version 7.2.1). Copyright 1996-2005 Kunihiro Ishiguro, et al. james# james# conf t james(config)# router eigrp 10 james(config-router)# network 192.168.0.0/24 james(config-router)# network 10.0.0.0/30 james(config-router)# end james#
/snap/bin/frr.vtysh
Hello, this is FRRouting (version 7.2.1).
Copyright 1996-2005 Kunihiro Ishiguro, et al.
james# 
james# conf t
james(config)# router eigrp 10
james(config-router)# network 192.168.0.0/24
james(config-router)# network 10.0.0.0/30
james(config-router)# end
james# 

CiscoIOSv15.6(2)T-1

Verification

Ubuntu18.04-FRR-1

Verifying the tunnel on Ubuntu is done with “ipsec statusall”, although there are more specific commands. This will do since we only have one tunnel. I’ve abbreviated the output, but these lines say it all:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Security Associations (1 up, 0 connecting):
tunnel[1]: ESTABLISHED 58 minutes ago, 1.1.1.2[1.1.1.2]...1.1.1.1[1.1.1.1]
tunnel[1]: IKEv2 SPIs: 9a137e96ee332b6b_i* 1599c6291be65825_r, pre-shared key reauthentication in 110 minutes
tunnel[1]: IKE proposal: AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_1024
tunnel{11}: INSTALLED, TRANSPORT, reqid 1, ESP SPIs: c72f4e27_i de8fcbc0_o
tunnel{11}: AES_CBC_128/HMAC_SHA2_256_128, 0 bytes_i, 0 bytes_o, rekeying in 30 minutes
tunnel{11}: 1.1.1.2/32 === 1.1.1.1/32
Security Associations (1 up, 0 connecting): tunnel[1]: ESTABLISHED 58 minutes ago, 1.1.1.2[1.1.1.2]...1.1.1.1[1.1.1.1] tunnel[1]: IKEv2 SPIs: 9a137e96ee332b6b_i* 1599c6291be65825_r, pre-shared key reauthentication in 110 minutes tunnel[1]: IKE proposal: AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_1024 tunnel{11}: INSTALLED, TRANSPORT, reqid 1, ESP SPIs: c72f4e27_i de8fcbc0_o tunnel{11}: AES_CBC_128/HMAC_SHA2_256_128, 0 bytes_i, 0 bytes_o, rekeying in 30 minutes tunnel{11}: 1.1.1.2/32 === 1.1.1.1/32
Security Associations (1 up, 0 connecting):
      tunnel[1]: ESTABLISHED 58 minutes ago, 1.1.1.2[1.1.1.2]...1.1.1.1[1.1.1.1]
      tunnel[1]: IKEv2 SPIs: 9a137e96ee332b6b_i* 1599c6291be65825_r, pre-shared key reauthentication in 110 minutes
      tunnel[1]: IKE proposal: AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_1024
      tunnel{11}:  INSTALLED, TRANSPORT, reqid 1, ESP SPIs: c72f4e27_i de8fcbc0_o
      tunnel{11}:  AES_CBC_128/HMAC_SHA2_256_128, 0 bytes_i, 0 bytes_o, rekeying in 30 minutes
      tunnel{11}:   1.1.1.2/32 === 1.1.1.1/32

For routing, just issue “ip route” and you’ll see your static or EIGRP routes:

root@james:/snap/bin# ip route
1.1.1.0/30 dev eth1 proto kernel scope link src 1.1.1.2  
10.0.0.0/30 dev vti0 proto kernel scope link src 10.0.0.2  
172.16.0.0/24 via 10.0.0.1 dev vti0 proto 192 metric 20  
192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.1

CiscoIOSv15.6(2)T-1

Finally, don’t forget to ping from Windows:

Troubleshooting

There are lots of tools here, including the strongswan “ipsec statusall”, Cisco debug commands, and others. But the one that always let’s me know what’s wrong the fastest is a packet capture. Look for IKE negotiation packets (ISAKMP filter in Wireshark) if you’re tunnel isn’t coming up, and make sure traffic goes through the tunnel (ESP filter in Wireshark) when it’s up:

4 Comments IPsec on Linux – Strongswan Configuration w/Cisco IOSv (IKEv2, Route-Based VTI, PSK)

  1. Alex Lukyanov

    HI James McClay ,
    i followed the exact instruction, so far i have ike and ipsec sa, but ping is not going through the tunnel .

    cisco —tunnel— ubuntu

    dump shows nothing.
    could you help me with this? this issue is really something

    root@legacy-vm-1:~# ipsec start
    Starting strongSwan 5.6.2 IPsec [starter]…
    charon is already running (/var/run/charon.pid exists) — skipping daemon start
    starter is already running (/var/run/starter.charon.pid exists) — no fork done
    root@legacy-vm-1:~# ipsec statusall
    Status of IKE charon daemon (strongSwan 5.6.2, Linux 4.15.0-154-generic, x86_64):
    uptime: 21 minutes, since Sep 18 00:29:09 2021
    malloc: sbrk 2568192, mmap 0, used 748624, free 1819568
    worker threads: 11 of 16 idle, 5/0/0/0 working, job queue: 0/0/0/0, scheduled: 2
    loaded plugins: charon aesni 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:
    178.162.213.34
    10.0.0.2
    Connections:
    tunnel: 178.162.213.34…3.70.14.168 IKEv2
    tunnel: local: [178.162.213.34] uses pre-shared key authentication
    tunnel: remote: [3.70.14.168] uses pre-shared key authentication
    tunnel: child: 0.0.0.0/0 === 0.0.0.0/0 TRANSPORT
    Security Associations (1 up, 0 connecting):
    tunnel[1]: ESTABLISHED 21 minutes ago, 178.162.213.34[178.162.213.34]…3.70.14.168[3.70.14.168]
    tunnel[1]: IKEv2 SPIs: a869785602d2e873_i* ab7a1e055efce20d_r, pre-shared key reauthentication in 2 hours
    tunnel[1]: IKE proposal: AES_CBC_128/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_1536
    tunnel{1}: INSTALLED, TRANSPORT, reqid 1, ESP in UDP SPIs: c69b2569_i f062156e_o
    tunnel{1}: AES_CBC_128/HMAC_SHA1_96, 0 bytes_i, 0 bytes_o, rekeying in 23 minutes
    tunnel{1}: 178.162.213.34/32 === 3.70.14.168/32
    tunnel{2}: INSTALLED, TUNNEL, reqid 2, ESP in UDP SPIs: cf90b793_i 60cac349_o
    tunnel{2}: AES_CBC_128/HMAC_SHA1_96, 0 bytes_i, 0 bytes_o, rekeying in 24 minutes
    tunnel{2}: 0.0.0.0/0 === 0.0.0.0/0
    root@legacy-vm-1:~#

    Tunnel666666668 10.0.0.1 YES manual up up

    ficonfig

    vti0: flags=209 mtu 1400
    inet 10.0.0.2 netmask 255.255.255.252 destination 10.0.0.2
    inet6 fe80::200:5efe:b2a2:d522 prefixlen 64 scopeid 0x20
    tunnel txqueuelen 1000 (IPIP Tunnel)
    RX packets 0 bytes 0 (0.0 B)
    RX errors 0 dropped 0 overruns 0 frame 0
    TX packets 0 bytes 0 (0.0 B)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

    csr-eu-backup#ping 10.0.0.2
    Type escape sequence to abort.
    Sending 5, 100-byte ICMP Echos to 10.0.0.2, timeout is 2 seconds:
    .

    both ways doesn’t work

    Reply
    1. James McClay

      Sorry for the slow response – my family and I just recently relocated to Japan. I’d recommend getting a packet capture going between those two devices. You can take a look and see if the proper ikev2 messages are going back and forth, and if data traffic encrypted in ESP packets is in fact leaving either device. That should give you some clues on what to investigate next. Based on your output here, it looks like IKE traffic is going ok and building a tunnel, but packets are not being encrypted and sent through the tunnels. Tough to say why it’s not going through, feel free to send me an invite for a zoom or something, just use my contact form. I’d be happy to help.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *