map: ip4-map-t more RFC compliant 42/24342/6
authorVladimir Ratnikov <vratnikov@netgate.com>
Tue, 14 Jan 2020 14:48:31 +0000 (09:48 -0500)
committerOle Trøan <otroan@employees.org>
Tue, 28 Jan 2020 08:14:36 +0000 (08:14 +0000)
When MTU is not set, ignore_df and mtu check
always returns true and packets are dropped.
This patch puts MTU checks after it was
compared with 0 and set to maximum if not set.
Added trace node.

If MTU is less than the total length value of
the IPv4 packet plus 20, the translator MUST
send an ICMPv4 "Fragmentation Needed" error message
to the IPv4 source address

Type: fix
Fixes: 87663cdf644fb7c94c0fec9460829b7e4e7c35ca

Signed-off-by: Vladimir Ratnikov <vratnikov@netgate.com>
Change-Id: I35b99bc2648984cdbf5b6a57ddec91c586b15bef

src/plugins/map/ip4_map_t.c

index dca3284..d243a45 100644 (file)
@@ -22,6 +22,7 @@ typedef enum
   IP4_MAPT_NEXT_MAPT_TCP_UDP,
   IP4_MAPT_NEXT_MAPT_ICMP,
   IP4_MAPT_NEXT_MAPT_FRAGMENTED,
+  IP4_MAPT_NEXT_ICMP_ERROR,
   IP4_MAPT_NEXT_DROP,
   IP4_MAPT_N_NEXT
 } ip4_mapt_next_t;
@@ -575,21 +576,31 @@ ip4_map_t (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
              goto exit;
            }
 
+         dst_port0 = -1;
+
          bool df0 =
            ip40->flags_and_fragment_offset &
            clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT);
 
+         vnet_buffer (p0)->map_t.mtu = d0->mtu ? d0->mtu : ~0;
+
          if (PREDICT_FALSE
-             (df0 && !map_main.frag_ignore_df && (ip4_len0 > d0->mtu)))
+             (df0 && !map_main.frag_ignore_df
+              &&
+              ((ip4_len0 +
+                (sizeof (ip6_header_t) - sizeof (ip4_header_t))) >
+               vnet_buffer (p0)->map_t.mtu)))
            {
-             p0->error = error_node->errors[MAP_ERROR_FRAGMENT_DROPPED];
-             next0 = IP4_MAPT_NEXT_DROP;
-             goto exit;
+             icmp4_error_set_vnet_buffer (p0, ICMP4_destination_unreachable,
+                                          ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
+                                          vnet_buffer (p0)->map_t.mtu -
+                                          (sizeof (ip6_header_t) -
+                                           sizeof (ip4_header_t)));
+             p0->error = error_node->errors[MAP_ERROR_DF_SET];
+             next0 = IP4_MAPT_NEXT_ICMP_ERROR;
+             goto trace;
            }
 
-         vnet_buffer (p0)->map_t.mtu = d0->mtu ? d0->mtu : ~0;
-
-         dst_port0 = -1;
          ip4_map_t_classify (p0, d0, ip40, ip4_len0, &dst_port0, &error0,
                              &next0, l4_dst_port);
 
@@ -626,7 +637,7 @@ ip4_map_t (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
 
          next0 = (error0 != MAP_ERROR_NONE) ? IP4_MAPT_NEXT_DROP : next0;
          p0->error = error_node->errors[error0];
-
+       trace:
          if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
            {
              map_add_trace (vm, node, p0, d0 - map_main.domains, dst_port0);
@@ -730,6 +741,7 @@ VLIB_REGISTER_NODE(ip4_map_t_node) = {
       [IP4_MAPT_NEXT_MAPT_TCP_UDP] = "ip4-map-t-tcp-udp",
       [IP4_MAPT_NEXT_MAPT_ICMP] = "ip4-map-t-icmp",
       [IP4_MAPT_NEXT_MAPT_FRAGMENTED] = "ip4-map-t-fragmented",
+      [IP4_MAPT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
       [IP4_MAPT_NEXT_DROP] = "error-drop",
   },
 };