I have read many comparisons of IPsec Transport vs. Tunnel mode, and there is a clear understanding that when two gateways are exchanging routed traffic they should use Tunnel mode. In other words, Transport mode should be used only between two hosts (or two gateways if they are communicating between each other, not routing traffic). What I try to understand is if Transport mode can be used in a gateway-to-gateway setting, even if not recommended.

My setting is as follows:

LAN1 <-> GW1 <-> GW2 <-> LAN2

In my case I want to protect the link between GW1 and GW2 (containing IP traffic from/to LAN1 to/from LAN2). It is a direct connection, no routing involved, no NAT, nothing. All the reasons for which Tunnel mode is recommended (and Transport mode is not) do not apply to my case - I am OK to leave the IP headers unencrypted and so on. I want to spare overhead bytes, so I would like to use Transport mode even if it is not recommended in this case.

I am using Ubuntu Linux with Strongswan package and IPsec in ESP mode.

My question is: is it at all possible ?

Is there a "fundamental" reason that makes it impossible, or is it just "not recommended / not usually done / not in the Cisco manual" but doable ?

Does anybody have a configuration file that works ?

  • Regarding the connection between the two routers you say "It is a direct connection, no routing involved, no NAT, nothing." But how do you know this will be true in the future?
    – hft
    Aug 30, 2018 at 19:06
  • @hft: in my setting this is a single satellite link that I control. So, although I am trying to use IPsec, an alternative could be to use a point-to-point link-layer encryption.
    – Danielik
    Sep 3, 2018 at 9:36

1 Answer 1


The problem is applying IPsec transparently.

The SPIs used to identify Security Associations (SA) are not globally unique, they are allocated by the receiving host, so to uniquely identify an SA in the Security Association Database (SAD) the tuple SPI, protocol (ESP or AH) and destination IP address is used. This is also how a host processes an inbound IPsec packet, by default, it simply searches for an SAD entry with a tuple matching the data from the received packet (it's also possible to first check if the destination address is local and then do the lookup in the SAD with just the SPI and protocol, that's what section 5.2 of RFC 4301 describes).

However, in the described scenario the destination is not a single known IP address that's local to the host (as is the case in tunnel mode and host-to-host transport mode) instead it could take a whole range of values as it might be the address of any of the hosts behind the receiving gateway. So the default lookup can't be used.

What's required is either a lookup that ignores the destination address (which could potentially lead to mismatches if a host behind the gateway uses IPsec itself and it allocated the same SPI), or some kind of subnet/range match for the IP addresses.

Now as far as the Linux kernel is concerned neither of these options is available. The code that searches an SAD entry for an inbound IPsec packet (__xfrm_state_lookup) insists on matching the destination address stored in the SAD entry. So unless you modify the kernel's source code in a way that changes how the destination address is treated, you can't avoid using tunnel mode.

For single IP addresses behind each gateway there exists what's called BEET mode, which the Linux kernel (and strongSwan) supports. In this mode the packets are sent in transport mode (between the gateway addresses) but before/after processing, the addresses in the IP header are changed according to the mapping addresses (the negotiated single-address traffic selectors, see draft-nikander-esp-beet-mode for details).

Side note: There is actually a flag for SAs in the Linux kernel called XFRM_STATE_WILDRECV that does allow some wildcard address matching for IPv6 but is only used for Mobile IPv6 via a separate lookup function (to process packets with Destination Options and Type 2 Routing extension headers it seems).

  • @ecda Thanks for the detailed answer. So I understand that there is no "fundamental" problem in the IPsec standard to cope with my use case, and it would be "sufficient" to add wildcards in the SA selection. This solution (1) would not work in cases where there could be a conflict/ambiguity in the SA selection; and (2) is not implemented in the Linux kernel. So, theoretically, I could modify the code of __xfrm_state_lookup so as to accept wildcards, recompile the kernel in the two gateways, and it could work...
    – Danielik
    Sep 5, 2018 at 17:02
  • Sounds about right, but the use case does violate RFC 4301, which, of course, was designed to avoid such ambiguities. But as far as implementing it goes, the actual protocols (ESP, IKEv2) don't technically prevent it (although IKEv2 implementations will probably have issues negotiating non-host-to-host traffic selectors for transport mode SAs). By the way, the kernel allows setting a single selector on an SA, which might be used for wildcard matching for simple, i.e. single-subnet, scenarios (this selector is already used for BEET mode to configure the inner addresses).
    – ecdsa
    Sep 6, 2018 at 9:54

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .