diff options
author | Alexander Chernavin <achernavin@netgate.com> | 2020-03-25 10:56:52 -0400 |
---|---|---|
committer | Neale Ranns <nranns@cisco.com> | 2020-03-31 09:06:43 +0000 |
commit | b0d2eda75a268f6afc2b08080a3e00b0a3295702 (patch) | |
tree | a090fe622389428cd3db319ea783e8e66416fc09 /src/vnet | |
parent | 5484daa001ccbbbf8773b273f428dbcddc4750cc (diff) |
ipsec: fix udp-encap in transport mode
Now UDP enacapsulation doesn't work in transport mode with crypto
algorithms that have iv_sz=8 like AES GCM or 3DES CBC. That happens
because the inserted UDP header overlaps with the old IP header and
gets filled before the information from the old IP header can be
copied to a new IP header. The result is a broken packet:
00:03:39:620863: esp4-encrypt-tun
esp: sa-index 3 spi 3464048590 (0xce792fce) seq 31 sa-seq-hi 0
crypto aes-gcm-128 integrity none udp-encap-enabled
00:03:39:620867: adj-midchain-tx
...
00:03:39:620868: ip4-rewrite
...
00:03:39:620869: GigabitEthernet0/8/0-output
GigabitEthernet0/8/0
IP4: 08:00:27:a9:6b:d6 -> 08:00:27:5a:dd:0c
UDP: 10.255.0.10 -> 10.255.0.20
version 0, header length 0
tos 0x80, ttl 63, length 0, checksum 0x653e (should be 0xffff)
dscp CS4 ecn NON_ECN
fragment id 0x0000
UDP: 128 -> 0
length 0, checksum 0x0000
00:03:39:620870: GigabitEthernet0/8/0-tx
GigabitEthernet0/8/0 tx queue 0
...
IP4: 08:00:27:a9:6b:d6 -> 08:00:27:5a:dd:0c
UDP: 10.255.0.10 -> 10.255.0.20
version 0, header length 0
tos 0x80, ttl 63, length 0, checksum 0x653e (should be 0xffff)
dscp CS4 ecn NON_ECN
fragment id 0x0000
UDP: 128 -> 0
length 0, checksum 0x0000
With this commit, fill UDP header after copying the IP headers in
transport mode.
Type: fix
Change-Id: Ie9a6e562aa05a8378114329d6a9ff395189fa6a8
Signed-off-by: Alexander Chernavin <achernavin@netgate.com>
Diffstat (limited to 'src/vnet')
-rw-r--r-- | src/vnet/ipsec/esp_encrypt.c | 8 |
1 files changed, 7 insertions, 1 deletions
diff --git a/src/vnet/ipsec/esp_encrypt.c b/src/vnet/ipsec/esp_encrypt.c index e06babd92ef..4793fddcd5a 100644 --- a/src/vnet/ipsec/esp_encrypt.c +++ b/src/vnet/ipsec/esp_encrypt.c @@ -463,6 +463,7 @@ esp_encrypt_inline (vlib_main_t * vm, vlib_node_runtime_t * node, u8 *l2_hdr, l2_len, *ip_hdr, ip_len; ip6_ext_header_t *ext_hdr; udp_header_t *udp = 0; + u16 udp_len = 0; u8 *old_ip_hdr = vlib_buffer_get_current (b[0]); ip_len = is_ip6 ? @@ -537,7 +538,7 @@ esp_encrypt_inline (vlib_main_t * vm, vlib_node_runtime_t * node, if (udp) { esp_update_ip4_hdr (ip4, len, /* is_transport */ 1, 1); - esp_fill_udp_hdr (sa0, udp, len - ip_len); + udp_len = len - ip_len; } else esp_update_ip4_hdr (ip4, len, /* is_transport */ 1, 0); @@ -545,6 +546,11 @@ esp_encrypt_inline (vlib_main_t * vm, vlib_node_runtime_t * node, clib_memcpy_le64 (ip_hdr, old_ip_hdr, ip_len); + if (udp) + { + esp_fill_udp_hdr (sa0, udp, udp_len); + } + if (!is_tun) next[0] = ESP_ENCRYPT_NEXT_INTERFACE_OUTPUT; } |