ipsec: separate UDP and UDP-encapsulated ESP packet processing
[vpp.git] / src / vnet / ipsec / ipsec_input.c
index 0e92ae9..8f9eb20 100644 (file)
@@ -299,6 +299,15 @@ ipsec_esp_packet_process (vlib_main_t *vm, ipsec_main_t *im, ip4_header_t *ip0,
   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 @@ VLIB_NODE_FN (ipsec4_input_node) (vlib_main_t * vm,
 
       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 @@ VLIB_NODE_FN (ipsec4_input_node) (vlib_main_t * vm,
        }
       else
        {
+       ipsec_bypassed:
          ipsec_unprocessed += 1;
        }
       n_left_from -= 1;
@@ -725,7 +751,6 @@ VLIB_NODE_FN (ipsec4_input_node) (vlib_main_t * vm,
   return frame->n_vectors;
 }
 
-
 /* *INDENT-OFF* */
 VLIB_REGISTER_NODE (ipsec4_input_node) = {
   .name = "ipsec4-input-feature",