ipsec: fix UDP flow in ipsec inbound policy

This patch fixes handle with UDP packages for UDP-Encapsulated ESP
and IKE traffic in inbound policy.

Orignally IKE traffic on UDP with port 4500 is dropped inside inbound
look-up.

Type: fix
Change-Id: I071adf18cb82da8cd000b93914078e51e393104c
Signed-off-by: Gabriel Oginski <gabrielx.oginski@intel.com>
This commit is contained in:
Gabriel Oginski
2024-10-11 10:47:56 +00:00
committed by Fan Zhang
parent 3b290df57c
commit 1c170f571a

View File

@ -428,11 +428,12 @@ ipsec_ah_packet_process (vlib_main_t *vm, ipsec_main_t *im, ip4_header_t *ip0,
always_inline void
ipsec_esp_packet_process (vlib_main_t *vm, ipsec_main_t *im, ip4_header_t *ip0,
esp_header_t *esp0, u32 thread_index,
ipsec_spd_t *spd0, vlib_buffer_t **b,
vlib_node_runtime_t *node, u64 *ipsec_bypassed,
u64 *ipsec_dropped, u64 *ipsec_matched,
u64 *ipsec_unprocessed, u16 *next)
udp_header_t *udp0, esp_header_t *esp0,
u32 thread_index, ipsec_spd_t *spd0,
vlib_buffer_t **b, vlib_node_runtime_t *node,
u64 *ipsec_bypassed, u64 *ipsec_dropped,
u64 *ipsec_matched, u64 *ipsec_unprocessed,
u16 *next)
{
ipsec_policy_t *p0 = NULL;
@ -445,17 +446,40 @@ ipsec_esp_packet_process (vlib_main_t *vm, ipsec_main_t *im, ip4_header_t *ip0,
/* if flow cache is enabled, first search through flow cache for a
* policy match for either protect, bypass or discard rules, in that
* order. if no match is found search_flow_cache is set to false (1)
* order. if no match is found search_flow_cache is set to false (0)
* and we revert back to linear search
*/
search_flow_cache = im->input_flow_cache_flag;
udp_or_esp:
if (esp0->spi == 0)
/* RFC5996 Section 2.23: "To tunnel IKE packets over UDP port 4500, the IKE
* header has four octets of zero prepended and the result immediately
* follows the UDP header. To tunnel ESP packets over UDP port 4500, the ESP
* header immediately follows the UDP header. Since the first four octets of
* the ESP header contain the SPI, and the SPI cannot validly be zero, it is
* always possible to distinguish ESP and IKE messages."
*/
/* RFC3948 Section 2.1 UDP-Encapsulated ESP Header Format:
* "The UDP header is a standard [RFC0768] header, where
* - the Source Port and Destination Port MUST be the same as that used
* by IKE traffic,
* - the IPv4 UDP Checksum SHOULD be transmitted as a zero value, and
* - receivers MUST NOT depend on the UDP checksum being a zero value.
* The SPI field in the ESP header MUST NOT be a zero value."
*/
/*
* UDP-IKEv2: UDP protocol, checksum != 0, SPI == 0 and port 500/4500
* UDP-ESP: UDP protocol, checksum == 0, SPI != 0 and port 4500
*/
if ((((udp0 != NULL) && (udp0->checksum == 0)) || (udp0 == NULL)) &&
(esp0->spi == 0))
{
/* RFC 4303, section 2.1: The SPI value of zero (0 is reserved for
* local, implementation-specific use and MUST NOT be sent on the wire.
/* RFC4303 Section 2.1: "The SPI value of zero (0 is reserved for
* local, implementation-specific use and MUST NOT be sent on the
* wire."
*/
*ipsec_unprocessed += 1;
next[0] = IPSEC_INPUT_NEXT_DROP;
@ -703,27 +727,30 @@ VLIB_NODE_FN (ipsec4_input_node) (vlib_main_t * vm,
udp_header_t *udp0 = NULL;
udp0 = (udp_header_t *) ((u8 *) ip0 + ip4_header_bytes (ip0));
/* RFC5996 Section 2.23 "Port 4500 is reserved for
/* RFC5996 Section 2.23: "Port 4500 is reserved for
* UDP-encapsulated ESP and IKE."
* RFC5996 Section 3.1: "IKE messages use UDP ports 500 and/or 4500"
*/
if (clib_host_to_net_u16 (4500) == udp0->dst_port)
{
esp0 = (esp_header_t *) ((u8 *) udp0 + sizeof (udp_header_t));
if ((clib_host_to_net_u16 (500) == udp0->dst_port) ||
(clib_host_to_net_u16 (4500) == udp0->dst_port))
{
esp0 = (esp_header_t *) ((u8 *) udp0 + sizeof (udp_header_t));
ipsec_esp_packet_process (vm, im, ip0, esp0, thread_index, spd0,
b, node, &ipsec_bypassed,
&ipsec_dropped, &ipsec_matched,
&ipsec_unprocessed, next);
if (ipsec_bypassed > 0)
goto ipsec_bypassed;
}
ipsec_esp_packet_process (vm, im, ip0, udp0, esp0, thread_index,
spd0, b, node, &ipsec_bypassed,
&ipsec_dropped, &ipsec_matched,
&ipsec_unprocessed, next);
if (ipsec_bypassed > 0)
goto ipsec_bypassed;
}
}
else if (PREDICT_TRUE (ip0->protocol == IP_PROTOCOL_IPSEC_ESP))
{
esp0 = (esp_header_t *) ((u8 *) ip0 + ip4_header_bytes (ip0));
ipsec_esp_packet_process (vm, im, ip0, esp0, thread_index, spd0, b,
node, &ipsec_bypassed, &ipsec_dropped,
&ipsec_matched, &ipsec_unprocessed, next);
ipsec_esp_packet_process (vm, im, ip0, NULL, esp0, thread_index,
spd0, b, node, &ipsec_bypassed,
&ipsec_dropped, &ipsec_matched,
&ipsec_unprocessed, next);
if (ipsec_bypassed > 0)
goto ipsec_bypassed;
}