api: missing support for dumping of neighbours (VPP-333)
[vpp.git] / vnet / vnet / ip / ip_frag.c
index 2217618..8aa21a0 100644 (file)
@@ -37,9 +37,8 @@ static u8 * format_ip_frag_trace (u8 * s, va_list * args)
   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
   ip_frag_trace_t * t = va_arg (*args, ip_frag_trace_t *);
-  s = format(s, "IPv%s offset: %u mtu: %u fragments: %u next: %s",
-             t->ipv6?"6":"4",
-             t->header_offset, t->mtu, t->n_fragments, node->next_node_names[t->next]);
+  s = format(s, "IPv%s offset: %u mtu: %u fragments: %u",
+             t->ipv6?"6":"4", t->header_offset, t->mtu, t->n_fragments);
   return s;
 }
 
@@ -115,9 +114,9 @@ ip4_frag_do_fragment(vlib_main_t *vm, u32 pi, u32 **buffer, ip_frag_error_t *err
       fip4 = (ip4_header_t *)(vlib_buffer_get_current(b) + offset);
 
       //Copy offset and ip4 header
-      memcpy(b->data, packet, offset + sizeof(*ip4));
+      clib_memcpy(b->data, packet, offset + sizeof(*ip4));
       //Copy data
-      memcpy(((u8*)(fip4)) + sizeof(*fip4),
+      clib_memcpy(((u8*)(fip4)) + sizeof(*fip4),
              packet + offset + sizeof(*fip4) + ptr, len);
     }
     b->current_length = offset + len + sizeof(*fip4);
@@ -146,6 +145,14 @@ ip4_frag_do_fragment(vlib_main_t *vm, u32 pi, u32 **buffer, ip_frag_error_t *err
   }
 }
 
+void
+ip_frag_set_vnet_buffer (vlib_buffer_t *b, u16 offset, u16 mtu, u8 next_index, u8 flags)
+{
+  vnet_buffer(b)->ip_frag.header_offset = offset;
+  vnet_buffer(b)->ip_frag.mtu = mtu;
+  vnet_buffer(b)->ip_frag.next_index = next_index;
+  vnet_buffer(b)->ip_frag.flags = flags;
+}
 
 static uword
 ip4_frag (vlib_main_t *vm,
@@ -189,13 +196,25 @@ ip4_frag (vlib_main_t *vm,
         tr->next = vnet_buffer(p0)->ip_frag.next_index;
       }
 
-      next0 = (error0 == IP_FRAG_ERROR_NONE) ? vnet_buffer(p0)->ip_frag.next_index : IP4_FRAG_NEXT_DROP;
-      frag_sent += vec_len(buffer);
-      small_packets += (vec_len(buffer) == 1);
+      if (error0 == IP_FRAG_ERROR_DONT_FRAGMENT_SET) {
+       icmp4_error_set_vnet_buffer(p0, ICMP4_destination_unreachable,
+                                   ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
+                                   vnet_buffer(p0)->ip_frag.mtu);
+       vlib_buffer_advance(p0, vnet_buffer(p0)->ip_frag.header_offset);
+       next0 = IP4_FRAG_NEXT_ICMP_ERROR;
+      } else
+       next0 = (error0 == IP_FRAG_ERROR_NONE) ? vnet_buffer(p0)->ip_frag.next_index : IP4_FRAG_NEXT_DROP;
+
+      if (error0 == IP_FRAG_ERROR_NONE) {
+       frag_sent += vec_len(buffer);
+       small_packets += (vec_len(buffer) == 1);
+      } else
+       vlib_error_count(vm, ip4_frag_node.index, error0, 1);
 
       //Send fragments that were added in the frame
       frag_from = buffer;
       frag_left = vec_len(buffer);
+
       while (frag_left > 0) {
         while (frag_left > 0 && n_left_to_next > 0) {
           u32 i;
@@ -218,6 +237,7 @@ ip4_frag (vlib_main_t *vm,
     vlib_put_next_frame(vm, node, next_index, n_left_to_next);
   }
   vec_free(buffer);
+
   vlib_node_increment_counter(vm, ip4_frag_node.index, IP_FRAG_ERROR_FRAGMENT_SENT, frag_sent);
   vlib_node_increment_counter(vm, ip4_frag_node.index, IP_FRAG_ERROR_SMALL_PACKET, small_packets);
 
@@ -254,6 +274,13 @@ ip6_frag_do_fragment(vlib_main_t *vm, u32 pi, u32 **buffer, ip_frag_error_t *err
     payload += payload[1] * 8;
   }
 
+  if (PREDICT_FALSE(payload >= (u8 *)vlib_buffer_get_current(p) + p->current_length)) {
+       //A malicious packet could set an extension header with a too big size
+       //and make us modify another vlib_buffer
+       *error = IP_FRAG_ERROR_MALFORMED;
+       return;
+  }
+
   u8 has_more;
   u16 initial_offset;
   if (*next_header == IP_PROTOCOL_IPV6_FRAGMENTATION) {
@@ -301,8 +328,8 @@ ip6_frag_do_fragment(vlib_main_t *vm, u32 pi, u32 **buffer, ip_frag_error_t *err
       b = vlib_get_buffer(vm, bi);
       vnet_buffer(b)->sw_if_index[VLIB_RX] = vnet_buffer(p)->sw_if_index[VLIB_RX];
       vnet_buffer(b)->sw_if_index[VLIB_TX] = vnet_buffer(p)->sw_if_index[VLIB_TX];
-      memcpy(vlib_buffer_get_current(b), vlib_buffer_get_current(p), headers_len);
-      memcpy(vlib_buffer_get_current(b) + headers_len, payload + ptr, len);
+      clib_memcpy(vlib_buffer_get_current(b), vlib_buffer_get_current(p), headers_len);
+      clib_memcpy(vlib_buffer_get_current(b) + headers_len, payload + ptr, len);
       frag_hdr = vlib_buffer_get_current(b) + headers_len - sizeof(*frag_hdr);
     } else {
       bi = pi;
@@ -426,6 +453,7 @@ VLIB_REGISTER_NODE (ip4_frag_node) = {
   .next_nodes = {
     [IP4_FRAG_NEXT_IP4_LOOKUP] = "ip4-lookup",
     [IP4_FRAG_NEXT_IP6_LOOKUP] = "ip6-lookup",
+    [IP4_FRAG_NEXT_ICMP_ERROR] = "ip4-icmp-error",
     [IP4_FRAG_NEXT_DROP] = "error-drop"
   },
 };