map: honor pre-resolve param in map-t
[vpp.git] / src / plugins / map / ip6_map_t.c
index 6e9c0d7..01bf0f9 100644 (file)
@@ -24,12 +24,14 @@ typedef enum
   IP6_MAPT_NEXT_MAPT_ICMP,
   IP6_MAPT_NEXT_MAPT_FRAGMENTED,
   IP6_MAPT_NEXT_DROP,
+  IP6_MAPT_NEXT_ICMP,
   IP6_MAPT_N_NEXT
 } ip6_mapt_next_t;
 
 typedef enum
 {
   IP6_MAPT_ICMP_NEXT_IP4_LOOKUP,
+  IP6_MAPT_ICMP_NEXT_IP4_REWRITE,
   IP6_MAPT_ICMP_NEXT_IP4_FRAG,
   IP6_MAPT_ICMP_NEXT_DROP,
   IP6_MAPT_ICMP_N_NEXT
@@ -38,6 +40,7 @@ typedef enum
 typedef enum
 {
   IP6_MAPT_TCP_UDP_NEXT_IP4_LOOKUP,
+  IP6_MAPT_TCP_UDP_NEXT_IP4_REWRITE,
   IP6_MAPT_TCP_UDP_NEXT_IP4_FRAG,
   IP6_MAPT_TCP_UDP_NEXT_DROP,
   IP6_MAPT_TCP_UDP_N_NEXT
@@ -46,6 +49,7 @@ typedef enum
 typedef enum
 {
   IP6_MAPT_FRAGMENTED_NEXT_IP4_LOOKUP,
+  IP6_MAPT_FRAGMENTED_NEXT_IP4_REWRITE,
   IP6_MAPT_FRAGMENTED_NEXT_IP4_FRAG,
   IP6_MAPT_FRAGMENTED_NEXT_DROP,
   IP6_MAPT_FRAGMENTED_N_NEXT
@@ -66,7 +70,7 @@ ip6_to_ip4_set_icmp_cb (ip6_header_t * ip6, ip4_header_t * ip4, void *arg)
   // Security check
   // Note that this prevents an intermediate IPv6 router from answering
   // the request.
-  ip4_sadr = map_get_ip4 (&ip6->src_address, ctx->d->flags);
+  ip4_sadr = map_get_ip4 (&ip6->src_address, ctx->d->ip6_src_len);
   if (ip6->src_address.as_u64[0] !=
       map_get_pfx_net (ctx->d, ip4_sadr, ctx->sender_port)
       || ip6->src_address.as_u64[1] != map_get_sfx_net (ctx->d, ip4_sadr,
@@ -88,7 +92,7 @@ ip6_to_ip4_set_inner_icmp_cb (ip6_header_t * ip6, ip4_header_t * ip4,
   u32 inner_ip4_dadr;
 
   //Security check of inner packet
-  inner_ip4_dadr = map_get_ip4 (&ip6->dst_address, ctx->d->flags);
+  inner_ip4_dadr = map_get_ip4 (&ip6->dst_address, ctx->d->ip6_src_len);
   if (ip6->dst_address.as_u64[0] !=
       map_get_pfx_net (ctx->d, inner_ip4_dadr, ctx->sender_port)
       || ip6->dst_address.as_u64[1] != map_get_sfx_net (ctx->d,
@@ -145,9 +149,11 @@ ip6_map_t_icmp (vlib_main_t * vm,
          d0 =
            pool_elt_at_index (map_main.domains,
                               vnet_buffer (p0)->map_t.map_domain_index);
-         ctx0.sender_port = ip6_get_port (ip60, 0, p0->current_length);
          ctx0.d = d0;
-         if (ctx0.sender_port == 0)
+         ctx0.sender_port = 0;
+         if (!ip6_get_port
+             (vm, p0, ip60, p0->current_length, NULL, &ctx0.sender_port,
+              NULL, NULL, NULL, NULL))
            {
              // In case of 1:1 mapping, we don't care about the port
              if (!(d0->ea_bits_len == 0 && d0->rules))
@@ -157,9 +163,8 @@ ip6_map_t_icmp (vlib_main_t * vm,
                }
            }
 
-         if (icmp6_to_icmp
-             (p0, ip6_to_ip4_set_icmp_cb, &ctx0,
-              ip6_to_ip4_set_inner_icmp_cb, &ctx0))
+         if (icmp6_to_icmp (vm, p0, ip6_to_ip4_set_icmp_cb, &ctx0,
+                            ip6_to_ip4_set_inner_icmp_cb, &ctx0))
            {
              error0 = MAP_ERROR_ICMP;
              goto err0;
@@ -169,9 +174,14 @@ ip6_map_t_icmp (vlib_main_t * vm,
            {
              // Send to fragmentation node if necessary
              vnet_buffer (p0)->ip_frag.mtu = vnet_buffer (p0)->map_t.mtu;
-             vnet_buffer (p0)->ip_frag.next_index = IP4_FRAG_NEXT_IP4_LOOKUP;
+             vnet_buffer (p0)->ip_frag.next_index = IP_FRAG_NEXT_IP4_LOOKUP;
              next0 = IP6_MAPT_ICMP_NEXT_IP4_FRAG;
            }
+         else
+           {
+             next0 = ip6_map_ip4_lookup_bypass (p0, NULL) ?
+               IP6_MAPT_ICMP_NEXT_IP4_REWRITE : next0;
+           }
        err0:
          if (PREDICT_TRUE (error0 == MAP_ERROR_NONE))
            {
@@ -200,7 +210,7 @@ ip6_map_t_icmp (vlib_main_t * vm,
  * Translate IPv6 fragmented packet to IPv4.
  */
 always_inline int
-map_ip6_to_ip4_fragmented (vlib_buffer_t * p)
+map_ip6_to_ip4_fragmented (vlib_main_t * vm, vlib_buffer_t * p)
 {
   ip6_header_t *ip6;
   ip6_frag_hdr_t *frag;
@@ -214,7 +224,7 @@ map_ip6_to_ip4_fragmented (vlib_buffer_t * p)
   ip6 = vlib_buffer_get_current (p);
 
   if (ip6_parse
-      (ip6, p->current_length, &l4_protocol, &l4_offset, &frag_offset))
+      (vm, p, ip6, p->current_length, &l4_protocol, &l4_offset, &frag_offset))
     return -1;
 
   frag = (ip6_frag_hdr_t *) u8_ptr_add (ip6, frag_offset);
@@ -230,7 +240,7 @@ map_ip6_to_ip4_fragmented (vlib_buffer_t * p)
 
   ip4->ip_version_and_header_length =
     IP4_VERSION_AND_HEADER_LENGTH_NO_OPTIONS;
-  ip4->tos = ip6_translate_tos (ip6);
+  ip4->tos = ip6_translate_tos (ip6->ip_version_traffic_class_and_flow_label);
   ip4->length =
     u16_net_add (ip6->payload_length,
                 sizeof (*ip4) - l4_offset + sizeof (*ip6));
@@ -272,11 +282,10 @@ ip6_map_t_fragmented (vlib_main_t * vm,
          n_left_from -= 1;
          to_next += 1;
          n_left_to_next -= 1;
-
-         next0 = IP6_MAPT_TCP_UDP_NEXT_IP4_LOOKUP;
+         next0 = IP6_MAPT_FRAGMENTED_NEXT_IP4_LOOKUP;
          p0 = vlib_get_buffer (vm, pi0);
 
-         if (map_ip6_to_ip4_fragmented (p0))
+         if (map_ip6_to_ip4_fragmented (vm, p0))
            {
              p0->error = error_node->errors[MAP_ERROR_FRAGMENT_DROPPED];
              next0 = IP6_MAPT_FRAGMENTED_NEXT_DROP;
@@ -288,9 +297,14 @@ ip6_map_t_fragmented (vlib_main_t * vm,
                  // Send to fragmentation node if necessary
                  vnet_buffer (p0)->ip_frag.mtu = vnet_buffer (p0)->map_t.mtu;
                  vnet_buffer (p0)->ip_frag.next_index =
-                   IP4_FRAG_NEXT_IP4_LOOKUP;
+                   IP_FRAG_NEXT_IP4_LOOKUP;
                  next0 = IP6_MAPT_FRAGMENTED_NEXT_IP4_FRAG;
                }
+             else
+               {
+                 next0 = ip6_map_ip4_lookup_bypass (p0, NULL) ?
+                   IP6_MAPT_FRAGMENTED_NEXT_IP4_REWRITE : next0;
+               }
            }
 
          vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
@@ -304,9 +318,12 @@ ip6_map_t_fragmented (vlib_main_t * vm,
 
 /*
  * Translate IPv6 UDP/TCP packet to IPv4.
+ * Returns 0 on success.
+ * Returns a non-zero error code on error.
  */
 always_inline int
-map_ip6_to_ip4_tcp_udp (vlib_buffer_t * p, bool udp_checksum)
+map_ip6_to_ip4_tcp_udp (vlib_main_t * vm, vlib_buffer_t * p,
+                       bool udp_checksum)
 {
   map_main_t *mm = &map_main;
   ip6_header_t *ip6;
@@ -323,7 +340,7 @@ map_ip6_to_ip4_tcp_udp (vlib_buffer_t * p, bool udp_checksum)
   ip6 = vlib_buffer_get_current (p);
 
   if (ip6_parse
-      (ip6, p->current_length, &l4_protocol, &l4_offset, &frag_offset))
+      (vm, p, ip6, p->current_length, &l4_protocol, &l4_offset, &frag_offset))
     return -1;
 
   if (l4_protocol == IP_PROTOCOL_TCP)
@@ -368,9 +385,19 @@ map_ip6_to_ip4_tcp_udp (vlib_buffer_t * p, bool udp_checksum)
   ip4->dst_address.as_u32 = vnet_buffer (p)->map_t.v6.daddr;
   ip4->src_address.as_u32 = vnet_buffer (p)->map_t.v6.saddr;
 
+  /*
+   * Drop spoofed packets that from a known domain source.
+   */
+  u32 map_domain_index = -1;
+  u8 error = 0;
+
+  ip4_map_get_domain (&ip4->src_address, &map_domain_index, &error);
+  if (error)
+    return error;
+
   ip4->ip_version_and_header_length =
     IP4_VERSION_AND_HEADER_LENGTH_NO_OPTIONS;
-  ip4->tos = ip6_translate_tos (ip6);
+  ip4->tos = ip6_translate_tos (ip6->ip_version_traffic_class_and_flow_label);
   ip4->length =
     u16_net_add (ip6->payload_length,
                 sizeof (*ip4) + sizeof (*ip6) - l4_offset);
@@ -429,7 +456,7 @@ ip6_map_t_tcp_udp (vlib_main_t * vm,
 
          p0 = vlib_get_buffer (vm, pi0);
 
-         if (map_ip6_to_ip4_tcp_udp (p0, true))
+         if (map_ip6_to_ip4_tcp_udp (vm, p0, true))
            {
              p0->error = error_node->errors[MAP_ERROR_UNKNOWN];
              next0 = IP6_MAPT_TCP_UDP_NEXT_DROP;
@@ -441,9 +468,14 @@ ip6_map_t_tcp_udp (vlib_main_t * vm,
                  // Send to fragmentation node if necessary
                  vnet_buffer (p0)->ip_frag.mtu = vnet_buffer (p0)->map_t.mtu;
                  vnet_buffer (p0)->ip_frag.next_index =
-                   IP4_FRAG_NEXT_IP4_LOOKUP;
+                   IP_FRAG_NEXT_IP4_LOOKUP;
                  next0 = IP6_MAPT_TCP_UDP_NEXT_IP4_FRAG;
                }
+             else
+               {
+                 next0 = ip6_map_ip4_lookup_bypass (p0, NULL) ?
+                   IP6_MAPT_TCP_UDP_NEXT_IP4_REWRITE : next0;
+               }
            }
 
          vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
@@ -461,6 +493,7 @@ ip6_map_t (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
   u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
   vlib_node_runtime_t *error_node =
     vlib_node_get_runtime (vm, ip6_map_t_node.index);
+  map_main_t *mm = &map_main;
   vlib_combined_counter_main_t *cm = map_main.domain_counters;
   u32 thread_index = vm->thread_index;
 
@@ -491,7 +524,7 @@ ip6_map_t (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
          n_left_to_next -= 1;
          error0 = MAP_ERROR_NONE;
          p0 = vlib_get_buffer (vm, pi0);
-         u16 l4_dst_port = vnet_buffer (p0)->ip.reass.l4_dst_port;
+         u16 l4_src_port = vnet_buffer (p0)->ip.reass.l4_src_port;
 
          ip60 = vlib_buffer_get_current (p0);
 
@@ -512,7 +545,7 @@ ip6_map_t (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
          vnet_buffer (p0)->map_t.mtu = d0->mtu ? d0->mtu : ~0;
 
          if (PREDICT_FALSE
-             (ip6_parse (ip60, p0->current_length,
+             (ip6_parse (vm, p0, ip60, p0->current_length,
                          &(vnet_buffer (p0)->map_t.v6.l4_protocol),
                          &(vnet_buffer (p0)->map_t.v6.l4_offset),
                          &(vnet_buffer (p0)->map_t.v6.frag_offset))))
@@ -534,7 +567,7 @@ ip6_map_t (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
              (vnet_buffer (p0)->map_t.v6.frag_offset
               && ip6_frag_hdr_offset (frag0)))
            {
-             map_port0 = l4_dst_port;
+             map_port0 = l4_src_port;
              next0 = IP6_MAPT_NEXT_MAPT_FRAGMENTED;
            }
          else
@@ -547,7 +580,7 @@ ip6_map_t (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
              vnet_buffer (p0)->map_t.checksum_offset =
                vnet_buffer (p0)->map_t.v6.l4_offset + 16;
              next0 = IP6_MAPT_NEXT_MAPT_TCP_UDP;
-             map_port0 = l4_dst_port;
+             map_port0 = l4_src_port;
            }
          else
            if (PREDICT_TRUE
@@ -559,7 +592,7 @@ ip6_map_t (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
              vnet_buffer (p0)->map_t.checksum_offset =
                vnet_buffer (p0)->map_t.v6.l4_offset + 6;
              next0 = IP6_MAPT_NEXT_MAPT_TCP_UDP;
-             map_port0 = l4_dst_port;
+             map_port0 = l4_src_port;
            }
          else if (vnet_buffer (p0)->map_t.v6.l4_protocol ==
                   IP_PROTOCOL_ICMP6)
@@ -576,7 +609,7 @@ ip6_map_t (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
                      u8_ptr_add (ip60,
                                  vnet_buffer (p0)->map_t.v6.l4_offset))->
                  code == ICMP6_echo_request)
-               map_port0 = l4_dst_port;
+               map_port0 = l4_src_port;
            }
          else
            {
@@ -612,7 +645,19 @@ ip6_map_t (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
                                                                     payload_length));
            }
 
-         next0 = (error0 != MAP_ERROR_NONE) ? IP6_MAPT_NEXT_DROP : next0;
+         if (PREDICT_FALSE
+             (error0 == MAP_ERROR_SEC_CHECK && mm->icmp6_enabled))
+           {
+             icmp6_error_set_vnet_buffer (p0, ICMP6_destination_unreachable,
+                                          ICMP6_destination_unreachable_source_address_failed_policy,
+                                          0);
+             next0 = IP6_MAPT_NEXT_ICMP;
+           }
+         else
+           {
+             next0 = (error0 != MAP_ERROR_NONE) ? IP6_MAPT_NEXT_DROP : next0;
+           }
+
          p0->error = error_node->errors[error0];
          if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
            {
@@ -651,6 +696,7 @@ VLIB_REGISTER_NODE(ip6_map_t_fragmented_node) = {
   .next_nodes =
   {
     [IP6_MAPT_FRAGMENTED_NEXT_IP4_LOOKUP] = "ip4-lookup",
+    [IP6_MAPT_FRAGMENTED_NEXT_IP4_REWRITE] = "ip4-load-balance",
     [IP6_MAPT_FRAGMENTED_NEXT_IP4_FRAG] = IP4_FRAG_NODE_NAME,
     [IP6_MAPT_FRAGMENTED_NEXT_DROP] = "error-drop",
   },
@@ -672,6 +718,7 @@ VLIB_REGISTER_NODE(ip6_map_t_icmp_node) = {
   .next_nodes =
   {
     [IP6_MAPT_ICMP_NEXT_IP4_LOOKUP] = "ip4-lookup",
+    [IP6_MAPT_ICMP_NEXT_IP4_REWRITE] = "ip4-load-balance",
     [IP6_MAPT_ICMP_NEXT_IP4_FRAG] = IP4_FRAG_NODE_NAME,
     [IP6_MAPT_ICMP_NEXT_DROP] = "error-drop",
   },
@@ -693,6 +740,7 @@ VLIB_REGISTER_NODE(ip6_map_t_tcp_udp_node) = {
   .next_nodes =
   {
     [IP6_MAPT_TCP_UDP_NEXT_IP4_LOOKUP] = "ip4-lookup",
+    [IP6_MAPT_TCP_UDP_NEXT_IP4_REWRITE] = "ip4-load-balance",
     [IP6_MAPT_TCP_UDP_NEXT_IP4_FRAG] = IP4_FRAG_NODE_NAME,
     [IP6_MAPT_TCP_UDP_NEXT_DROP] = "error-drop",
   },
@@ -724,6 +772,7 @@ VLIB_REGISTER_NODE(ip6_map_t_node) = {
     [IP6_MAPT_NEXT_MAPT_ICMP] = "ip6-map-t-icmp",
     [IP6_MAPT_NEXT_MAPT_FRAGMENTED] = "ip6-map-t-fragmented",
     [IP6_MAPT_NEXT_DROP] = "error-drop",
+    [IP6_MAPT_NEXT_ICMP] = "ip6-icmp-error",
   },
 };
 /* *INDENT-ON* */