ipsec: separate UDP and UDP-encapsulated ESP packet processing
This fix differentiates UDP and UDP-encapsulated ESP packets processing.
While UDP-encapsulated ESP traffic is processed as IPsec traffic, UDP as
other plain-text protocols is NOT dispatched against SPD policies.
Key logic is taken from RFC 3948, and is based on the fact
that the checksum of UDP packet encapsulating ESP packet must be zero.
Type: fix
Signed-off-by: vinay tripathi <vinayx.tripathi@intel.com>
Change-Id: Ib1b4d240eea8e89f2daf17ec833905f26cdb31bd
diff --git a/src/vnet/ipsec/ipsec_input.c b/src/vnet/ipsec/ipsec_input.c
index 0e92ae9..8f9eb20 100644
--- a/src/vnet/ipsec/ipsec_input.c
+++ b/src/vnet/ipsec/ipsec_input.c
@@ -299,6 +299,15 @@
search_flow_cache = im->input_flow_cache_flag;
udp_or_esp:
+ /* SPI ID field in the ESP header MUST NOT be a zero value */
+ if (esp0->spi == 0)
+ {
+ /* Drop the packet if SPI ID is zero */
+ *ipsec_unprocessed += 1;
+ next[0] = IPSEC_INPUT_NEXT_DROP;
+ return;
+ }
+
if (im->fp_spd_ipv4_in_is_enabled &&
PREDICT_TRUE (INDEX_INVALID != spd0->fp_spd.ip4_in_lookup_hash_idx))
{
@@ -538,20 +547,36 @@
ip0 = vlib_buffer_get_current (b[0]);
- if (PREDICT_TRUE
- (ip0->protocol == IP_PROTOCOL_IPSEC_ESP
- || ip0->protocol == IP_PROTOCOL_UDP))
+ if (ip0->protocol == IP_PROTOCOL_UDP)
{
+ udp_header_t *udp0 = NULL;
+ udp0 = (udp_header_t *) ((u8 *) ip0 + ip4_header_bytes (ip0));
- esp0 = (esp_header_t *) ((u8 *) ip0 + ip4_header_bytes (ip0));
- if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_UDP))
+ /* As per rfc3948 in UDP Encapsulated Header, UDP checksum must be
+ * Zero, and receivers must not depen upon UPD checksum.
+ * inside ESP header , SPI ID value MUST NOT be a zero value
+ * */
+
+ if (udp0->checksum == 0)
{
- /* FIXME Skip, if not a UDP encapsulated packet */
- esp0 = (esp_header_t *) ((u8 *) esp0 + sizeof (udp_header_t));
+ 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;
}
+ }
+ 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);
+ if (ipsec_bypassed > 0)
+ goto ipsec_bypassed;
}
else if (ip0->protocol == IP_PROTOCOL_IPSEC_AH)
{
@@ -694,6 +719,7 @@
}
else
{
+ ipsec_bypassed:
ipsec_unprocessed += 1;
}
n_left_from -= 1;
@@ -725,7 +751,6 @@
return frame->n_vectors;
}
-
/* *INDENT-OFF* */
VLIB_REGISTER_NODE (ipsec4_input_node) = {
.name = "ipsec4-input-feature",