[Swan] IPv4 over IPv6 tunneling

Liam Schönberg liam.ch at outlook.com
Thu May 7 14:57:11 UTC 2020

Dear Community,

Since the most important Telco in Switzerland, Swisscom (Schweiz) AG, is clearly doing some kind of traffic engineering, where tunneling packets (GRE or IP-in-IP) over IPv6 get far less prioritized, resulting that the throughput in conjunction with (clear-text) IPv4 over IPv6 tunnels is dramatically lower than the throughput of regular IPv6 traffic (TCP or UDP), I'm trying to implement GRE over IPsec over IPv6, so that the IPv4 traffic can travel over the IPv6 Internet smoothly.

But I'm having a difficulty setting up the tunnel in the following configuration and was hoping anybody could assist me resolving the issue:

Libreswan 3.25 on Amazon Linux 2

Cisco C897VA-K9 running IOS 15.7(3)M6

Underlying Protocol: IPv6
Main Mode: IKEv2, AES-CBC-128, SHA1-96, MODP2048
Quick Mode: ESP, AES-CBC-128, SHA1-96, MODP2048
Type: Transport (instead of Tunnel)

There's a GRE over IPv6 («ip6gre») tunnel configured on both Site-A and Site-B.

# ip link add type ip6gre local «Site-A» remote «Site-B»
# ip address add dev ip6gre1

! interface Tunnel20
!  ip address
!  tunnel source «Site-B»
!  tunnel destination «Site-A»
!  tunnel mode gre ipv6

Without applying the IPsec policies via Libreswan or Crypto-Map, both sides do have a reachability through the GRE over IPv6 tunnel, when I ping their addresses ( or When I then apply the IPsec policies on both sides, the (IPv4) reachability goes away.

I did make sure that the SPIs are showing up on both sides, when I generate those GRE packets, but the Cisco side looks like having difficulties processing the encrypted packets.

When the Linux side generates a GRE (over IPv6) packet, it adds those «Destination Options», which includes the «Tunnel Encapsulation Limit» and «PadN» options, in the IPv6 header. Since we're running on the «Transport» mode, those IPv6 headers don't get modified, leaving those «Destinations Options» as they are, even after the encryption.

Those packets then arrive on the Cisco side, get decrypted – wrongly. Somehow, after the decryption, the Cisco's code doesn't set the first «Next-Header» option in the IPv6 header to be «Destination Options», but instead, it sets «GRE». Inevitably, it then fails to process those packets as GRE packets, since the payload of those packets actually begin with the «Destination Options» portion, which actually belongs to the IPv6 header, instead of the GRE header. 

Before encryption:
IPv6, next header: Destination Options
IPv6 Destination Options, next header: GRE
GRE (original payload)

After encryption: 
IPv6, next header: Destination Options
IPv6 Destination Options, next header: ESP
ESP, next header: GRE
GRE (original payload)

After decryption:
IPv6, next header: GRE
IPv6 Destination Options, GRE (corrupt payload)

Here are the possibilities I went through:

- Using other encryption algorithms, such as AES-GCM or even Null.
- Trying both IKEv1 and IKEv2.
- Specifying the exact protocol (GRE, IP Protocol 47) as interesting traffic, instead of IPv6 entirely.
- Using other tunnel interface types, such as IP6TNL.
- Using other Linux distributions, such as RHEL and Ubuntu.

Unfortunately, none of them actually worked. Since I took every time a packet capture, decrypted those ESP packets with Wireshark and saw the resulting packets with the wrong «Next-Header» option, I'm almost sure that it is not a configuration issue. 

The only thing that helped was, sadly, to set the IPsec mode to «Tunnel», instead of «Transport». That way, the entire IPv6 header with its payload were to get decrypted without getting corrupted on the Cisco side. But this workaround would be subject to the extra overhead of 40 bytes, which would father reduce the resulting MTU of the inner tunnel. In my case, it would be 1390-48-4=1338. Again, those 4 bytes are the «Destination Options», which I don't understand why it's there in the first place. The Cisco side doesn't add those 4 bytes – Is there any way to prevent the Linux kernel from adding those options, when running GRE over IPv6? Or a way, where the ESP stack can ignore/remove those «Destination Options», when running on Transport mode?

To be honest, I have no clue about which side, either the Linux side, Cisco side or both, is doing it wrong, but I really want to get it working with the Transport mode. Please let me know, if anybody knows how it could be achieved.

Best regards,


More information about the Swan mailing list