NAT: Buufer overflow for memcpy()
[vpp.git] / src / plugins / nat / nat64.c
index b04901f..0054310 100644 (file)
@@ -47,12 +47,47 @@ static u8 well_known_prefix[] = {
 
 /* *INDENT-ON* */
 
+static void
+nat64_ip4_add_del_interface_address_cb (ip4_main_t * im, uword opaque,
+                                       u32 sw_if_index,
+                                       ip4_address_t * address,
+                                       u32 address_length,
+                                       u32 if_address_index, u32 is_delete)
+{
+  nat64_main_t *nm = &nat64_main;
+  int i, j;
+
+  for (i = 0; i < vec_len (nm->auto_add_sw_if_indices); i++)
+    {
+      if (sw_if_index == nm->auto_add_sw_if_indices[i])
+       {
+         if (!is_delete)
+           {
+             /* Don't trip over lease renewal, static config */
+             for (j = 0; j < vec_len (nm->addr_pool); j++)
+               if (nm->addr_pool[j].addr.as_u32 == address->as_u32)
+                 return;
+
+             (void) nat64_add_del_pool_addr (address, ~0, 1);
+             return;
+           }
+         else
+           {
+             (void) nat64_add_del_pool_addr (address, ~0, 0);
+             return;
+           }
+       }
+    }
+}
+
 clib_error_t *
 nat64_init (vlib_main_t * vm)
 {
   nat64_main_t *nm = &nat64_main;
   clib_error_t *error = 0;
   vlib_thread_main_t *tm = vlib_get_thread_main ();
+  ip4_add_del_interface_address_callback_t cb4;
+  ip4_main_t *im = &ip4_main;
 
   nm->is_disabled = 0;
 
@@ -75,6 +110,12 @@ nat64_init (vlib_main_t * vm)
   nm->tcp_est_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
   nm->tcp_incoming_syn_timeout = SNAT_TCP_INCOMING_SYN;
 
+  /* Set up the interface address add/del callback */
+  cb4.function = nat64_ip4_add_del_interface_address_cb;
+  cb4.function_opaque = 0;
+  vec_add1 (im->add_del_interface_address_callbacks, cb4);
+  nm->ip4_main = im;
+
 error:
   return error;
 }
@@ -107,7 +148,8 @@ nat64_add_del_pool_addr (ip4_address_t * addr, u32 vrf_id, u8 is_add)
       a->fib_index = 0;
       if (vrf_id != ~0)
        a->fib_index =
-         fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, vrf_id);
+         fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, vrf_id,
+                                            FIB_SOURCE_PLUGIN_HI);
 #define _(N, i, n, s) \
       clib_bitmap_alloc (a->busy_##n##_port_bitmap, 65535);
       foreach_snat_protocol
@@ -119,7 +161,8 @@ nat64_add_del_pool_addr (ip4_address_t * addr, u32 vrf_id, u8 is_add)
        return VNET_API_ERROR_NO_SUCH_ENTRY;
 
       if (a->fib_index)
-       fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP6);
+       fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP6,
+                         FIB_SOURCE_PLUGIN_HI);
 
 #define _(N, id, n, s) \
       clib_bitmap_free (a->busy_##n##_port_bitmap);
@@ -134,7 +177,7 @@ nat64_add_del_pool_addr (ip4_address_t * addr, u32 vrf_id, u8 is_add)
   /* *INDENT-OFF* */
   pool_foreach (interface, nm->interfaces,
   ({
-    if (interface->is_inside)
+    if (nat_interface_is_inside(interface))
       continue;
 
     snat_add_del_addr_to_fib (addr, 32, interface->sw_if_index, is_add);
@@ -160,6 +203,47 @@ nat64_pool_addr_walk (nat64_pool_addr_walk_fn_t fn, void *ctx)
   /* *INDENT-ON* */
 }
 
+int
+nat64_add_interface_address (u32 sw_if_index, int is_add)
+{
+  nat64_main_t *nm = &nat64_main;
+  ip4_main_t *ip4_main = nm->ip4_main;
+  ip4_address_t *first_int_addr;
+  int i;
+
+  first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0);
+
+  for (i = 0; i < vec_len (nm->auto_add_sw_if_indices); i++)
+    {
+      if (nm->auto_add_sw_if_indices[i] == sw_if_index)
+       {
+         if (is_add)
+           return VNET_API_ERROR_VALUE_EXIST;
+         else
+           {
+             /* if have address remove it */
+             if (first_int_addr)
+               (void) nat64_add_del_pool_addr (first_int_addr, ~0, 0);
+
+             vec_del1 (nm->auto_add_sw_if_indices, i);
+             return 0;
+           }
+       }
+    }
+
+  if (!is_add)
+    return VNET_API_ERROR_NO_SUCH_ENTRY;
+
+  /* add to the auto-address list */
+  vec_add1 (nm->auto_add_sw_if_indices, sw_if_index);
+
+  /* If the address is already bound - or static - add it now */
+  if (first_int_addr)
+    (void) nat64_add_del_pool_addr (first_int_addr, ~0, 1);
+
+  return 0;
+}
+
 int
 nat64_add_del_interface (u32 sw_if_index, u8 is_inside, u8 is_add)
 {
@@ -168,7 +252,7 @@ nat64_add_del_interface (u32 sw_if_index, u8 is_inside, u8 is_add)
   snat_address_t *ap;
   const char *feature_name, *arc_name;
 
-  /* Check if address already exists */
+  /* Check if interface already exists */
   /* *INDENT-OFF* */
   pool_foreach (i, nm->interfaces,
   ({
@@ -183,19 +267,29 @@ nat64_add_del_interface (u32 sw_if_index, u8 is_inside, u8 is_add)
   if (is_add)
     {
       if (interface)
-       return VNET_API_ERROR_VALUE_EXIST;
+       goto set_flags;
 
       pool_get (nm->interfaces, interface);
       interface->sw_if_index = sw_if_index;
-      interface->is_inside = is_inside;
-
+      interface->flags = 0;
+    set_flags:
+      if (is_inside)
+       interface->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
+      else
+       interface->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
     }
   else
     {
       if (!interface)
        return VNET_API_ERROR_NO_SUCH_ENTRY;
 
-      pool_put (nm->interfaces, interface);
+      if ((nat_interface_is_inside (interface)
+          && nat_interface_is_outside (interface)))
+       interface->flags &=
+         is_inside ? ~NAT_INTERFACE_FLAG_IS_INSIDE :
+         ~NAT_INTERFACE_FLAG_IS_OUTSIDE;
+      else
+       pool_put (nm->interfaces, interface);
     }
 
   if (!is_inside)
@@ -353,8 +447,8 @@ nat64_add_del_static_bib_entry (ip6_address_t * in_addr,
 {
   nat64_main_t *nm = &nat64_main;
   nat64_db_bib_entry_t *bibe;
-  u32 fib_index =
-    fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, vrf_id);
+  u32 fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, vrf_id,
+                                                    FIB_SOURCE_PLUGIN_HI);
   snat_protocol_t p = ip_proto_to_snat_proto (proto);
   ip46_address_t addr;
   int i;
@@ -644,7 +738,8 @@ nat64_add_del_prefix (ip6_address_t * prefix, u8 plen, u32 vrf_id, u8 is_add)
        {
          vec_add2 (nm->pref64, p, 1);
          p->fib_index =
-           fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, vrf_id);
+           fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, vrf_id,
+                                              FIB_SOURCE_PLUGIN_HI);
          p->vrf_id = vrf_id;
        }
 
@@ -703,8 +798,7 @@ nat64_compose_ip6 (ip6_address_t * ip6, ip4_address_t * ip4, u32 fib_index)
 
   if (prefix)
     {
-      memset (ip6, 0, 16);
-      memcpy (ip6, &p->prefix, p->plen);
+      clib_memcpy (ip6, &p->prefix, sizeof (ip6_address_t));
       switch (p->plen)
        {
        case 32:
@@ -744,7 +838,7 @@ nat64_compose_ip6 (ip6_address_t * ip6, ip4_address_t * ip4, u32 fib_index)
     }
   else
     {
-      memcpy (ip6, well_known_prefix, 16);
+      clib_memcpy (ip6, well_known_prefix, sizeof (ip6_address_t));
       ip6->as_u32[3] = ip4->as_u32;
     }
 }