LCOV - code coverage report
Current view: top level - plugins/dns - dns.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 490 1288 38.0 %
Date: 2023-07-05 22:20:52 Functions: 40 54 74.1 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2017 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : 
      16             : #include <vnet/vnet.h>
      17             : #include <vnet/udp/udp_local.h>
      18             : #include <vnet/plugin/plugin.h>
      19             : #include <dns/dns.h>
      20             : #include <vnet/ip/ip_sas.h>
      21             : #include <vlibapi/api.h>
      22             : #include <vlibmemory/api.h>
      23             : #include <vpp/app/version.h>
      24             : #include <stdbool.h>
      25             : 
      26             : /* define message IDs */
      27             : #include <dns/dns.api_enum.h>
      28             : #include <dns/dns.api_types.h>
      29             : 
      30             : #define REPLY_MSG_ID_BASE dm->msg_id_base
      31             : #include <vlibapi/api_helper_macros.h>
      32             : 
      33             : #define FINISH                                                                \
      34             :   vec_add1 (s, 0);                                                            \
      35             :   vlib_cli_output (handle, (char *) s);                                       \
      36             :   vec_free (s);                                                               \
      37             :   return handle;
      38             : 
      39             : dns_main_t dns_main;
      40             : 
      41             : /* the cache hashtable expects a NULL-terminated C-string but everywhere else
      42             :  * expects a non-NULL terminated vector... The pattern of adding \0 but hiding
      43             :  * it away drives AddressSanitizer crazy, this helper tries to bring some of
      44             :  * its sanity back
      45             :  */
      46             : static_always_inline void
      47           1 : dns_terminate_c_string (u8 **v)
      48             : {
      49           1 :   vec_add1 (*v, 0);
      50           1 :   vec_dec_len (*v, 1);
      51           1 :   clib_mem_unpoison (vec_end (*v), 1);
      52           1 : }
      53             : 
      54             : static int
      55           0 : dns_cache_clear (dns_main_t * dm)
      56             : {
      57             :   dns_cache_entry_t *ep;
      58             : 
      59           0 :   if (dm->is_enabled == 0)
      60           0 :     return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
      61             : 
      62           0 :   dns_cache_lock (dm, 1);
      63             : 
      64             :   /* *INDENT-OFF* */
      65           0 :   pool_foreach (ep, dm->entries)
      66             :    {
      67           0 :     vec_free (ep->name);
      68           0 :     vec_free (ep->pending_requests);
      69             :   }
      70             :   /* *INDENT-ON* */
      71             : 
      72           0 :   pool_free (dm->entries);
      73           0 :   hash_free (dm->cache_entry_by_name);
      74           0 :   dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
      75           0 :   vec_free (dm->unresolved_entries);
      76           0 :   dns_cache_unlock (dm);
      77           0 :   return 0;
      78             : }
      79             : 
      80             : static int
      81           5 : dns_enable_disable (vlib_main_t * vm, dns_main_t * dm, int is_enable)
      82             : {
      83           5 :   vlib_thread_main_t *tm = &vlib_thread_main;
      84           5 :   u32 n_vlib_mains = tm->n_vlib_mains;
      85             : 
      86             :   /* Create the resolver process if not done already */
      87           5 :   vnet_dns_create_resolver_process (vm, dm);
      88             : 
      89           5 :   if (is_enable)
      90             :     {
      91           5 :       if (vec_len (dm->ip4_name_servers) == 0
      92           0 :           && (vec_len (dm->ip6_name_servers) == 0))
      93           0 :         return VNET_API_ERROR_NO_NAME_SERVERS;
      94             : 
      95           5 :       if (dm->udp_ports_registered == 0)
      96             :         {
      97           5 :           udp_register_dst_port (vm, UDP_DST_PORT_dns_reply,
      98             :                                  dns46_reply_node.index, 1 /* is_ip4 */ );
      99             : 
     100           5 :           udp_register_dst_port (vm, UDP_DST_PORT_dns_reply6,
     101             :                                  dns46_reply_node.index, 0 /* is_ip4 */ );
     102             : 
     103           5 :           udp_register_dst_port (vm, UDP_DST_PORT_dns,
     104             :                                  dns4_request_node.index, 1 /* is_ip4 */ );
     105             : 
     106           5 :           udp_register_dst_port (vm, UDP_DST_PORT_dns6,
     107             :                                  dns6_request_node.index, 0 /* is_ip4 */ );
     108             : 
     109           5 :           dm->udp_ports_registered = 1;
     110             :         }
     111             : 
     112           5 :       if (dm->cache_entry_by_name == 0)
     113             :         {
     114           5 :           if (n_vlib_mains > 1)
     115           0 :             clib_spinlock_init (&dm->cache_lock);
     116             : 
     117           5 :           dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
     118             :         }
     119             : 
     120           5 :       dm->is_enabled = 1;
     121             :     }
     122             :   else
     123             :     {
     124           0 :       dns_cache_clear (dm);
     125           0 :       dm->is_enabled = 0;
     126             :     }
     127           5 :   return 0;
     128             : }
     129             : 
     130           5 : static void vl_api_dns_enable_disable_t_handler
     131             :   (vl_api_dns_enable_disable_t * mp)
     132             : {
     133             :   vl_api_dns_enable_disable_reply_t *rmp;
     134           5 :   vlib_main_t *vm = vlib_get_main ();
     135           5 :   dns_main_t *dm = &dns_main;
     136             :   int rv;
     137             : 
     138           5 :   rv = dns_enable_disable (vm, dm, mp->enable);
     139             : 
     140           5 :   REPLY_MACRO (VL_API_DNS_ENABLE_DISABLE_REPLY);
     141             : }
     142             : 
     143             : static int
     144           0 : dns6_name_server_add_del (dns_main_t * dm,
     145             :                           u8 * server_address_as_u8, int is_add)
     146             : {
     147             :   int i;
     148             :   ip6_address_t *ap;
     149             : 
     150           0 :   if (is_add)
     151             :     {
     152             :       /* Already there? done... */
     153           0 :       for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
     154             :         {
     155           0 :           if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
     156             :                        sizeof (ip6_address_t)))
     157           0 :             return 0;
     158             :         }
     159             : 
     160           0 :       vec_add2 (dm->ip6_name_servers, ap, 1);
     161           0 :       clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
     162             :     }
     163             :   else
     164             :     {
     165           0 :       for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
     166             :         {
     167           0 :           if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
     168             :                        sizeof (ip6_address_t)))
     169             :             {
     170           0 :               vec_delete (dm->ip6_name_servers, 1, i);
     171           0 :               return 0;
     172             :             }
     173             :         }
     174           0 :       return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
     175             :     }
     176           0 :   return 0;
     177             : }
     178             : 
     179             : static int
     180           5 : dns4_name_server_add_del (dns_main_t * dm,
     181             :                           u8 * server_address_as_u8, int is_add)
     182             : {
     183             :   int i;
     184             :   ip4_address_t *ap;
     185             : 
     186           5 :   if (is_add)
     187             :     {
     188             :       /* Already there? done... */
     189           5 :       for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
     190             :         {
     191           0 :           if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
     192             :                        sizeof (ip4_address_t)))
     193           0 :             return 0;
     194             :         }
     195             : 
     196           5 :       vec_add2 (dm->ip4_name_servers, ap, 1);
     197           5 :       clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
     198             :     }
     199             :   else
     200             :     {
     201           0 :       for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
     202             :         {
     203           0 :           if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
     204             :                        sizeof (ip4_address_t)))
     205             :             {
     206           0 :               vec_delete (dm->ip4_name_servers, 1, i);
     207           0 :               return 0;
     208             :             }
     209             :         }
     210           0 :       return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
     211             :     }
     212           5 :   return 0;
     213             : }
     214             : 
     215           5 : static void vl_api_dns_name_server_add_del_t_handler
     216             :   (vl_api_dns_name_server_add_del_t * mp)
     217             : {
     218           5 :   dns_main_t *dm = &dns_main;
     219             :   vl_api_dns_name_server_add_del_reply_t *rmp;
     220             :   int rv;
     221             : 
     222           5 :   if (mp->is_ip6)
     223           0 :     rv = dns6_name_server_add_del (dm, mp->server_address, mp->is_add);
     224             :   else
     225           5 :     rv = dns4_name_server_add_del (dm, mp->server_address, mp->is_add);
     226             : 
     227           5 :   REPLY_MACRO (VL_API_DNS_NAME_SERVER_ADD_DEL_REPLY);
     228             : }
     229             : 
     230             : void
     231           1 : vnet_dns_send_dns4_request (vlib_main_t * vm, dns_main_t * dm,
     232             :                             dns_cache_entry_t * ep, ip4_address_t * server)
     233             : {
     234           1 :   f64 now = vlib_time_now (vm);
     235             :   u32 bi;
     236             :   vlib_buffer_t *b;
     237             :   ip4_header_t *ip;
     238             :   udp_header_t *udp;
     239             :   ip4_address_t src_address;
     240             :   u8 *dns_request;
     241             :   vlib_frame_t *f;
     242             :   u32 *to_next;
     243             : 
     244           1 :   ASSERT (ep->dns_request);
     245             : 
     246           1 :   if (!ip4_sas (0 /* default VRF for now */, ~0, server, &src_address))
     247           1 :     return;
     248             : 
     249             :   /* Go get a buffer */
     250           0 :   if (vlib_buffer_alloc (vm, &bi, 1) != 1)
     251           0 :     return;
     252             : 
     253           0 :   b = vlib_get_buffer (vm, bi);
     254           0 :   b->current_length = sizeof (ip4_header_t) + sizeof (udp_header_t) +
     255           0 :     vec_len (ep->dns_request);
     256           0 :   b->total_length_not_including_first_buffer = 0;
     257           0 :   b->flags =
     258             :     VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
     259           0 :   vnet_buffer (b)->sw_if_index[VLIB_RX] = 0; /* "local0" */
     260           0 :   vnet_buffer (b)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
     261             : 
     262           0 :   ip = vlib_buffer_get_current (b);
     263           0 :   clib_memset (ip, 0, sizeof (*ip));
     264           0 :   udp = (udp_header_t *) (ip + 1);
     265           0 :   clib_memset (udp, 0, sizeof (*udp));
     266             : 
     267           0 :   dns_request = (u8 *) (udp + 1);
     268             : 
     269             :   /* IP header */
     270           0 :   ip->ip_version_and_header_length = 0x45;
     271           0 :   ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b));
     272           0 :   ip->ttl = 255;
     273           0 :   ip->protocol = IP_PROTOCOL_UDP;
     274           0 :   ip->src_address.as_u32 = src_address.as_u32;
     275           0 :   ip->dst_address.as_u32 = server->as_u32;
     276           0 :   ip->checksum = ip4_header_checksum (ip);
     277             : 
     278             :   /* UDP header */
     279           0 :   udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
     280           0 :   udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
     281           0 :   udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
     282           0 :                                       vec_len (ep->dns_request));
     283           0 :   udp->checksum = 0;
     284             : 
     285             :   /* The actual DNS request */
     286           0 :   clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
     287             : 
     288             :   /* Ship it to ip4_lookup */
     289           0 :   f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
     290           0 :   to_next = vlib_frame_vector_args (f);
     291           0 :   to_next[0] = bi;
     292           0 :   f->n_vectors = 1;
     293           0 :   vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
     294             : 
     295           0 :   ep->retry_timer = now + 2.0;
     296             : }
     297             : 
     298             : void
     299           0 : vnet_dns_send_dns6_request (vlib_main_t * vm, dns_main_t * dm,
     300             :                             dns_cache_entry_t * ep, ip6_address_t * server)
     301             : {
     302           0 :   f64 now = vlib_time_now (vm);
     303             :   u32 bi;
     304             :   vlib_buffer_t *b;
     305             :   ip6_header_t *ip;
     306             :   udp_header_t *udp;
     307             :   ip6_address_t src_address;
     308             :   u8 *dns_request;
     309             :   vlib_frame_t *f;
     310             :   u32 *to_next;
     311             :   int junk __attribute__ ((unused));
     312             : 
     313           0 :   ASSERT (ep->dns_request);
     314             : 
     315           0 :   if (!ip6_sas (0 /* default VRF for now */, ~0, server, &src_address))
     316           0 :     return;
     317             : 
     318             :   /* Go get a buffer */
     319           0 :   if (vlib_buffer_alloc (vm, &bi, 1) != 1)
     320           0 :     return;
     321             : 
     322           0 :   b = vlib_get_buffer (vm, bi);
     323           0 :   b->current_length = sizeof (ip6_header_t) + sizeof (udp_header_t) +
     324           0 :     vec_len (ep->dns_request);
     325           0 :   b->total_length_not_including_first_buffer = 0;
     326           0 :   b->flags =
     327             :     VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
     328             : 
     329           0 :   ip = vlib_buffer_get_current (b);
     330           0 :   clib_memset (ip, 0, sizeof (*ip));
     331           0 :   udp = (udp_header_t *) (ip + 1);
     332           0 :   clib_memset (udp, 0, sizeof (*udp));
     333             : 
     334           0 :   dns_request = (u8 *) (udp + 1);
     335             : 
     336             :   /* IP header */
     337           0 :   ip->ip_version_traffic_class_and_flow_label =
     338           0 :     clib_host_to_net_u32 (0x6 << 28);
     339             : 
     340           0 :   ip->payload_length =
     341           0 :     clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b)
     342           0 :                           - sizeof (ip6_header_t));
     343           0 :   ip->hop_limit = 255;
     344           0 :   ip->protocol = IP_PROTOCOL_UDP;
     345           0 :   ip6_address_copy (&ip->src_address, &src_address);
     346           0 :   clib_memcpy (&ip->dst_address, server, sizeof (ip6_address_t));
     347             : 
     348             :   /* UDP header */
     349           0 :   udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
     350           0 :   udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
     351           0 :   udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
     352           0 :                                       vec_len (ep->dns_request));
     353           0 :   udp->checksum = 0;
     354           0 :   udp->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ip, &junk);
     355             : 
     356             :   /* The actual DNS request */
     357           0 :   clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
     358             : 
     359             :   /* Ship it to ip6_lookup */
     360           0 :   f = vlib_get_frame_to_node (vm, ip6_lookup_node.index);
     361           0 :   to_next = vlib_frame_vector_args (f);
     362           0 :   to_next[0] = bi;
     363           0 :   f->n_vectors = 1;
     364             : 
     365           0 :   ep->retry_timer = now + 2.0;
     366             : }
     367             : 
     368             : /**
     369             :  * Translate "foo.com" into "0x3 f o o 0x3 c o m 0x0"
     370             :  * A historical / hysterical micro-TLV scheme. DGMS.
     371             :  */
     372             : u8 *
     373           7 : name_to_labels (u8 * name)
     374             : {
     375             :   int i;
     376             :   int last_label_index;
     377             :   u8 *rv;
     378             : 
     379           7 :   rv = vec_dup (name);
     380             : 
     381             :   /* punch in space for the first length */
     382           7 :   vec_insert (rv, 1, 0);
     383           7 :   last_label_index = 0;
     384           7 :   i = 1;
     385             : 
     386         116 :   while (i < vec_len (rv))
     387             :     {
     388         109 :       if (rv[i] == '.')
     389             :         {
     390          14 :           rv[last_label_index] = (i - last_label_index) - 1;
     391          14 :           if ((i - last_label_index) > 63)
     392           0 :             clib_warning ("stupid name, label length %d",
     393             :                           i - last_label_index);
     394          14 :           last_label_index = i;
     395          14 :           rv[i] = 0;
     396             :         }
     397         109 :       i++;
     398             :     }
     399             :   /* Set the last real label length */
     400           7 :   rv[last_label_index] = (i - last_label_index) - 1;
     401             : 
     402             :   /*
     403             :    * Add a [sic] NULL root label. Otherwise, the name parser can't figure out
     404             :    * where to stop.
     405             :    */
     406           7 :   vec_add1 (rv, 0);
     407           7 :   return rv;
     408             : }
     409             : 
     410             : /**
     411             :  * arc-function for the above.
     412             :  * Translate "0x3 f o o 0x3 c o m 0x0" into "foo.com"
     413             :  * Produces a non-NULL-terminated u8 *vector. %v format is your friend.
     414             :  */
     415             : u8 *
     416           2 : vnet_dns_labels_to_name (u8 * label, u8 * full_text, u8 ** parse_from_here)
     417             : {
     418           2 :   u8 *reply = 0;
     419             :   u16 offset;
     420             :   u8 len;
     421             :   int i;
     422             : 
     423           2 :   *parse_from_here = 0;
     424             : 
     425             :   /* chase initial pointer? */
     426           2 :   if ((label[0] & 0xC0) == 0xC0)
     427             :     {
     428           0 :       *parse_from_here = label + 2;
     429           0 :       offset = ((label[0] & 0x3f) << 8) + label[1];
     430           0 :       label = full_text + offset;
     431             :     }
     432             : 
     433           2 :   len = *label++;
     434             : 
     435           8 :   while (len)
     436             :     {
     437          28 :       for (i = 0; i < len; i++)
     438          22 :         vec_add1 (reply, *label++);
     439             : 
     440             :       /* chase pointer? */
     441           6 :       if ((label[0] & 0xC0) == 0xC0)
     442             :         {
     443           0 :           *parse_from_here = label + 2;
     444           0 :           offset = ((label[0] & 0x3f) << 8) + label[1];
     445           0 :           label = full_text + offset;
     446             :         }
     447             : 
     448           6 :       len = *label++;
     449           6 :       if (len)
     450           4 :         vec_add1 (reply, '.');
     451             :     }
     452           2 :   if (*parse_from_here == 0)
     453           2 :     *parse_from_here = label;
     454           2 :   return reply;
     455             : }
     456             : 
     457             : void
     458           1 : vnet_send_dns_request (vlib_main_t * vm, dns_main_t * dm,
     459             :                        dns_cache_entry_t * ep)
     460             : {
     461             :   dns_header_t *h;
     462             :   dns_query_t *qp;
     463             :   u16 tmp;
     464             :   u8 *request, *name_copy;
     465             :   u32 qp_offset;
     466             : 
     467             :   /* This can easily happen if sitting in GDB, etc. */
     468           1 :   if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID || ep->server_fails > 1)
     469           0 :     return;
     470             : 
     471             :   /* Construct the dns request, if we haven't been here already */
     472           1 :   if (vec_len (ep->dns_request) == 0)
     473             :     {
     474             :       /*
     475             :        * Start with the variadic portion of the exercise.
     476             :        * Turn the name into a set of DNS "labels". Max length
     477             :        * per label is 63, enforce that.
     478             :        */
     479           1 :       request = name_to_labels (ep->name);
     480           1 :       name_copy = vec_dup (request);
     481           1 :       qp_offset = vec_len (request);
     482             : 
     483             :       /*
     484             :        * At least when testing against "known good" DNS servers:
     485             :        * it turns out that sending 2x requests - one for an A-record
     486             :        * and another for a AAAA-record - seems to work better than
     487             :        * sending a DNS_TYPE_ALL request.
     488             :        */
     489             : 
     490             :       /* Add space for the query header */
     491           1 :       vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
     492             : 
     493           1 :       qp = (dns_query_t *) (request + qp_offset);
     494             : 
     495           1 :       qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
     496           1 :       qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
     497           1 :       qp++;
     498           1 :       clib_memcpy (qp, name_copy, vec_len (name_copy));
     499           1 :       qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
     500           1 :       vec_free (name_copy);
     501             : 
     502           1 :       qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
     503           1 :       qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
     504             : 
     505             :       /* Punch in space for the dns_header_t */
     506           1 :       vec_insert (request, sizeof (dns_header_t), 0);
     507             : 
     508           1 :       h = (dns_header_t *) request;
     509             : 
     510             :       /* Transaction ID = pool index */
     511           1 :       h->id = clib_host_to_net_u16 (ep - dm->entries);
     512             : 
     513             :       /* Ask for a recursive lookup */
     514           1 :       tmp = DNS_RD | DNS_OPCODE_QUERY;
     515           1 :       h->flags = clib_host_to_net_u16 (tmp);
     516           1 :       h->qdcount = clib_host_to_net_u16 (2);
     517           1 :       h->nscount = 0;
     518           1 :       h->arcount = 0;
     519             : 
     520           1 :       ep->dns_request = request;
     521             :     }
     522             : 
     523             :   /* Work out which server / address family we're going to use */
     524             : 
     525             :   /* Retry using current server */
     526           1 :   if (ep->retry_count++ < DNS_RETRIES_PER_SERVER)
     527             :     {
     528           1 :       if (ep->server_af == 1 /* ip6 */ )
     529             :         {
     530           0 :           if (vec_len (dm->ip6_name_servers))
     531             :             {
     532           0 :               vnet_dns_send_dns6_request
     533           0 :                 (vm, dm, ep, dm->ip6_name_servers + ep->server_rotor);
     534           0 :               goto out;
     535             :             }
     536             :           else
     537           0 :             ep->server_af = 0;
     538             :         }
     539           1 :       if (vec_len (dm->ip4_name_servers))
     540             :         {
     541           1 :           vnet_dns_send_dns4_request
     542           1 :             (vm, dm, ep, dm->ip4_name_servers + ep->server_rotor);
     543           1 :           goto out;
     544             :         }
     545             :     }
     546             :   else                          /* switch to a new server */
     547             :     {
     548           0 :       ep->retry_count = 1;
     549           0 :       ep->server_rotor++;
     550           0 :       if (ep->server_af == 1 /* ip6 */ )
     551             :         {
     552           0 :           if (ep->server_rotor >= vec_len (dm->ip6_name_servers))
     553             :             {
     554           0 :               ep->server_rotor = 0;
     555           0 :               ep->server_af = vec_len (dm->ip4_name_servers) > 0 ? 0 : 1;
     556             :             }
     557             :         }
     558             :       else
     559             :         {
     560           0 :           if (ep->server_rotor >= vec_len (dm->ip4_name_servers))
     561             :             {
     562           0 :               ep->server_rotor = 0;
     563           0 :               ep->server_af = vec_len (dm->ip6_name_servers) > 0 ? 1 : 0;
     564             :             }
     565             :         }
     566             :     }
     567             : 
     568           0 :   if (ep->server_af == 1 /* ip6 */ )
     569           0 :     vnet_dns_send_dns6_request
     570           0 :       (vm, dm, ep, dm->ip6_name_servers + ep->server_rotor);
     571             :   else
     572           0 :     vnet_dns_send_dns4_request
     573           0 :       (vm, dm, ep, dm->ip4_name_servers + ep->server_rotor);
     574             : 
     575           1 : out:
     576             : 
     577           1 :   vlib_process_signal_event_mt (vm,
     578           1 :                                 dm->resolver_process_node_index,
     579             :                                 DNS_RESOLVER_EVENT_PENDING, 0);
     580             : }
     581             : 
     582             : int
     583           0 : vnet_dns_delete_entry_by_index_nolock (dns_main_t * dm, u32 index)
     584             : {
     585             :   dns_cache_entry_t *ep;
     586             :   int i;
     587             : 
     588           0 :   if (dm->is_enabled == 0)
     589           0 :     return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
     590             : 
     591           0 :   if (pool_is_free_index (dm->entries, index))
     592           0 :     return VNET_API_ERROR_NO_SUCH_ENTRY;
     593             : 
     594           0 :   ep = pool_elt_at_index (dm->entries, index);
     595           0 :   if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_VALID))
     596             :     {
     597           0 :       for (i = 0; i < vec_len (dm->unresolved_entries); i++)
     598           0 :         if (index == dm->unresolved_entries[i])
     599             :           {
     600           0 :             vec_delete (dm->unresolved_entries, 1, i);
     601           0 :             goto found;
     602             :           }
     603           0 :       clib_warning ("pool elt %d supposedly pending, but not found...",
     604             :                     index);
     605             :     }
     606             : 
     607           0 : found:
     608           0 :   hash_unset_mem (dm->cache_entry_by_name, ep->name);
     609           0 :   vec_free (ep->name);
     610           0 :   vec_free (ep->pending_requests);
     611           0 :   pool_put (dm->entries, ep);
     612             : 
     613           0 :   return 0;
     614             : }
     615             : 
     616             : static int
     617           0 : dns_delete_by_name (dns_main_t * dm, u8 * name)
     618             : {
     619             :   int rv;
     620             :   uword *p;
     621             : 
     622           0 :   if (dm->is_enabled == 0)
     623           0 :     return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
     624             : 
     625           0 :   dns_cache_lock (dm, 2);
     626           0 :   p = hash_get_mem (dm->cache_entry_by_name, name);
     627           0 :   if (!p)
     628             :     {
     629           0 :       dns_cache_unlock (dm);
     630           0 :       return VNET_API_ERROR_NO_SUCH_ENTRY;
     631             :     }
     632           0 :   rv = vnet_dns_delete_entry_by_index_nolock (dm, p[0]);
     633             : 
     634           0 :   dns_cache_unlock (dm);
     635             : 
     636           0 :   return rv;
     637             : }
     638             : 
     639             : static int
     640           0 : delete_random_entry (dns_main_t * dm)
     641             : {
     642             :   int rv;
     643             :   u32 victim_index, start_index, i;
     644             :   u32 limit;
     645             :   dns_cache_entry_t *ep;
     646             : 
     647           0 :   if (dm->is_enabled == 0)
     648           0 :     return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
     649             : 
     650             :   /*
     651             :    * Silence spurious coverity warning. We know pool_elts >> 0, or
     652             :    * we wouldn't be here...
     653             :    */
     654             : #ifdef __COVERITY__
     655             :   if (pool_elts (dm->entries) == 0)
     656             :     return VNET_API_ERROR_UNSPECIFIED;
     657             : #endif
     658             : 
     659           0 :   dns_cache_lock (dm, 3);
     660           0 :   limit = pool_elts (dm->entries);
     661           0 :   start_index = random_u32 (&dm->random_seed) % limit;
     662             : 
     663           0 :   for (i = 0; i < limit; i++)
     664             :     {
     665           0 :       victim_index = (start_index + i) % limit;
     666             : 
     667           0 :       if (!pool_is_free_index (dm->entries, victim_index))
     668             :         {
     669           0 :           ep = pool_elt_at_index (dm->entries, victim_index);
     670             :           /* Delete only valid, non-static entries */
     671           0 :           if ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
     672           0 :               && ((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0))
     673             :             {
     674           0 :               rv = vnet_dns_delete_entry_by_index_nolock (dm, victim_index);
     675           0 :               dns_cache_unlock (dm);
     676           0 :               return rv;
     677             :             }
     678             :         }
     679             :     }
     680           0 :   dns_cache_unlock (dm);
     681             : 
     682           0 :   clib_warning ("Couldn't find an entry to delete?");
     683           0 :   return VNET_API_ERROR_UNSPECIFIED;
     684             : }
     685             : 
     686             : static int
     687           5 : dns_add_static_entry (dns_main_t * dm, u8 * name, u8 * dns_reply_data)
     688             : {
     689             :   dns_cache_entry_t *ep;
     690             :   uword *p;
     691             :   int rv;
     692             : 
     693           5 :   if (dm->is_enabled == 0)
     694           0 :     return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
     695             : 
     696           5 :   dns_cache_lock (dm, 4);
     697           5 :   p = hash_get_mem (dm->cache_entry_by_name, name);
     698           5 :   if (p)
     699             :     {
     700           0 :       dns_cache_unlock (dm);
     701           0 :       return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
     702             :     }
     703             : 
     704           5 :   if (pool_elts (dm->entries) == dm->name_cache_size)
     705             :     {
     706             :       /* Will only fail if the cache is totally filled w/ static entries... */
     707           0 :       rv = delete_random_entry (dm);
     708           0 :       if (rv)
     709             :         {
     710           0 :           dns_cache_unlock (dm);
     711           0 :           return rv;
     712             :         }
     713             :     }
     714             : 
     715           5 :   pool_get (dm->entries, ep);
     716           5 :   clib_memset (ep, 0, sizeof (*ep));
     717             : 
     718             :   /* Note: consumes the name vector */
     719           5 :   ep->name = name;
     720             :   /* make sure it NULL-terminated as hash_set_mem will use strlen() */
     721           5 :   vec_terminate_c_string (ep->name);
     722          10 :   hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
     723           5 :   ep->flags = DNS_CACHE_ENTRY_FLAG_VALID | DNS_CACHE_ENTRY_FLAG_STATIC;
     724           5 :   ep->dns_response = dns_reply_data;
     725             : 
     726           5 :   dns_cache_unlock (dm);
     727           5 :   return 0;
     728             : }
     729             : 
     730             : int
     731           7 : vnet_dns_resolve_name (vlib_main_t * vm, dns_main_t * dm, u8 * name,
     732             :                        dns_pending_request_t * t, dns_cache_entry_t ** retp)
     733             : {
     734             :   dns_cache_entry_t *ep;
     735             :   int rv;
     736             :   f64 now;
     737             :   uword *p;
     738             :   dns_pending_request_t *pr;
     739             :   int count;
     740             : 
     741           7 :   now = vlib_time_now (vm);
     742             : 
     743             :   /* In case we can't actually answer the question right now... */
     744           7 :   *retp = 0;
     745             : 
     746             :   /* binary API caller might forget to set the name. Guess how we know. */
     747           7 :   if (name[0] == 0)
     748           0 :     return VNET_API_ERROR_INVALID_VALUE;
     749             : 
     750           7 :   dns_cache_lock (dm, 5);
     751           7 : search_again:
     752           7 :   p = hash_get_mem (dm->cache_entry_by_name, name);
     753           7 :   if (p)
     754             :     {
     755           6 :       ep = pool_elt_at_index (dm->entries, p[0]);
     756           6 :       if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
     757             :         {
     758             :           /* Has the entry expired? */
     759           6 :           if (((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0)
     760           0 :               && (now > ep->expiration_time))
     761             :             {
     762             :               int i;
     763           0 :               u32 *indices_to_delete = 0;
     764             : 
     765             :               /*
     766             :                * Take out the rest of the resolution chain
     767             :                * This isn't optimal, but it won't happen very often.
     768             :                */
     769           0 :               while (ep)
     770             :                 {
     771           0 :                   if ((ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME))
     772             :                     {
     773           0 :                       vec_add1 (indices_to_delete, ep - dm->entries);
     774             : 
     775           0 :                       p = hash_get_mem (dm->cache_entry_by_name, ep->cname);
     776           0 :                       if (!p)
     777           0 :                         break;
     778           0 :                       ep = pool_elt_at_index (dm->entries, p[0]);
     779             :                     }
     780             :                   else
     781             :                     {
     782           0 :                       vec_add1 (indices_to_delete, ep - dm->entries);
     783           0 :                       break;
     784             :                     }
     785             :                 }
     786           0 :               for (i = 0; i < vec_len (indices_to_delete); i++)
     787             :                 {
     788             :                   /* Reenable to watch re-resolutions */
     789             :                   if (0)
     790             :                     {
     791             :                       ep = pool_elt_at_index (dm->entries,
     792             :                                               indices_to_delete[i]);
     793             :                       clib_warning ("Re-resolve %s", ep->name);
     794             :                     }
     795             : 
     796           0 :                   vnet_dns_delete_entry_by_index_nolock
     797           0 :                     (dm, indices_to_delete[i]);
     798             :                 }
     799           0 :               vec_free (indices_to_delete);
     800             :               /* Yes, kill it... */
     801           0 :               goto re_resolve;
     802             :             }
     803             : 
     804           6 :           if (ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
     805             :             {
     806           0 :               name = ep->cname;
     807           0 :               goto search_again;
     808             :             }
     809           6 :           *retp = ep;
     810           6 :           dns_cache_unlock (dm);
     811           6 :           return (0);
     812             :         }
     813             :       else
     814             :         {
     815             :           /*
     816             :            * Resolution pending. Add request to the pending vector
     817             :            * by copying the template request
     818             :            */
     819           0 :           vec_add2 (ep->pending_requests, pr, 1);
     820           0 :           memcpy (pr, t, sizeof (*pr));
     821           0 :           dns_cache_unlock (dm);
     822           0 :           return (0);
     823             :         }
     824             :     }
     825             : 
     826           1 : re_resolve:
     827           1 :   if (pool_elts (dm->entries) == dm->name_cache_size)
     828             :     {
     829             :       /* Will only fail if the cache is totally filled w/ static entries... */
     830           0 :       rv = delete_random_entry (dm);
     831           0 :       if (rv)
     832             :         {
     833           0 :           dns_cache_unlock (dm);
     834           0 :           return rv;
     835             :         }
     836             :     }
     837             : 
     838             :   /* add new hash table entry */
     839           1 :   pool_get (dm->entries, ep);
     840           1 :   clib_memset (ep, 0, sizeof (*ep));
     841             : 
     842           1 :   ep->name = format (0, "%s", name);
     843           1 :   dns_terminate_c_string (&ep->name);
     844             : 
     845           2 :   hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
     846             : 
     847           1 :   vec_add1 (dm->unresolved_entries, ep - dm->entries);
     848           1 :   vec_add2 (ep->pending_requests, pr, 1);
     849             : 
     850           1 :   pr->request_type = t->request_type;
     851             : 
     852             :   /* Remember details so we can reply later... */
     853           1 :   if (t->request_type == DNS_API_PENDING_NAME_TO_IP ||
     854           1 :       t->request_type == DNS_API_PENDING_IP_TO_NAME)
     855             :     {
     856           0 :       pr->client_index = t->client_index;
     857           0 :       pr->client_context = t->client_context;
     858             :     }
     859             :   else
     860             :     {
     861           1 :       pr->client_index = ~0;
     862           1 :       pr->is_ip6 = t->is_ip6;
     863           1 :       pr->dst_port = t->dst_port;
     864           1 :       pr->id = t->id;
     865           1 :       pr->name = t->name;
     866           1 :       if (t->is_ip6)
     867           0 :         count = 16;
     868             :       else
     869           1 :         count = 4;
     870           1 :       clib_memcpy (pr->dst_address, t->dst_address, count);
     871             :     }
     872             : 
     873           1 :   vnet_send_dns_request (vm, dm, ep);
     874           1 :   dns_cache_unlock (dm);
     875           1 :   return 0;
     876             : }
     877             : 
     878             : #define foreach_notification_to_move            \
     879             : _(pending_requests)
     880             : 
     881             : /**
     882             :  * Handle cname indirection. JFC. Called with the cache locked.
     883             :  * returns 0 if the reply is not a CNAME.
     884             :  */
     885             : 
     886             : int
     887           0 : vnet_dns_cname_indirection_nolock (vlib_main_t * vm, dns_main_t * dm,
     888             :                                    u32 ep_index, u8 * reply)
     889             : {
     890             :   dns_header_t *h;
     891             :   dns_query_t *qp;
     892             :   dns_rr_t *rr;
     893             :   u8 *curpos;
     894             :   u8 *pos, *pos2;
     895           0 :   u8 *cname_pos = 0;
     896             :   int len, i;
     897           0 :   u8 *cname = 0;
     898           0 :   u8 *request = 0;
     899             :   u8 *name_copy;
     900             :   u32 qp_offset;
     901             :   u16 flags;
     902             :   u16 rcode;
     903             :   dns_cache_entry_t *ep, *next_ep;
     904             :   f64 now;
     905             : 
     906           0 :   h = (dns_header_t *) reply;
     907           0 :   flags = clib_net_to_host_u16 (h->flags);
     908           0 :   rcode = flags & DNS_RCODE_MASK;
     909             : 
     910             :   /* See if the response is OK */
     911           0 :   switch (rcode)
     912             :     {
     913           0 :     case DNS_RCODE_NO_ERROR:
     914           0 :       break;
     915             : 
     916           0 :     case DNS_RCODE_NAME_ERROR:
     917             :     case DNS_RCODE_FORMAT_ERROR:
     918             :     case DNS_RCODE_SERVER_FAILURE:
     919             :     case DNS_RCODE_NOT_IMPLEMENTED:
     920             :     case DNS_RCODE_REFUSED:
     921           0 :       return -1;
     922             :     }
     923             : 
     924           0 :   curpos = (u8 *) (h + 1);
     925           0 :   pos = curpos;
     926           0 :   len = *pos++;
     927             : 
     928             :   /* Skip the questions */
     929           0 :   for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
     930             :     {
     931           0 :       while (len)
     932             :         {
     933           0 :           pos += len;
     934           0 :           len = *pos++;
     935             :         }
     936           0 :       pos += sizeof (dns_query_t);
     937             :     }
     938           0 :   pos2 = pos;
     939             :   /* expect a pointer chase here for a CNAME record */
     940           0 :   if ((pos2[0] & 0xC0) == 0xC0)
     941           0 :     pos += 2;
     942             :   else
     943           0 :     return 0;
     944             : 
     945             :   /* Walk the answer(s) to see what to do next */
     946           0 :   for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
     947             :     {
     948           0 :       rr = (dns_rr_t *) pos;
     949           0 :       switch (clib_net_to_host_u16 (rr->type))
     950             :         {
     951             :           /* Real address record? Done.. */
     952           0 :         case DNS_TYPE_A:
     953             :         case DNS_TYPE_AAAA:
     954           0 :           return 0;
     955             :           /*
     956             :            * Maybe chase a CNAME pointer?
     957             :            * It's not unheard-of for name-servers to return
     958             :            * both CNAME and A/AAAA records...
     959             :            */
     960           0 :         case DNS_TYPE_CNAME:
     961           0 :           cname_pos = pos;
     962           0 :           break;
     963             : 
     964             :           /* Some other junk, e.g. a nameserver... */
     965           0 :         default:
     966           0 :           break;
     967             :         }
     968           0 :       pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
     969             :       /* Skip name... */
     970           0 :       if ((pos2[0] & 0xc0) == 0xc0)
     971           0 :         pos += 2;
     972             :     }
     973             : 
     974             :   /* Neither a CNAME nor a real address. Try another server */
     975           0 :   if (cname_pos == 0)
     976             :     {
     977           0 :       flags &= ~DNS_RCODE_MASK;
     978           0 :       flags |= DNS_RCODE_NAME_ERROR;
     979           0 :       h->flags = clib_host_to_net_u16 (flags);
     980           0 :       return -1;
     981             :     }
     982             : 
     983             :   /* This is a CNAME record, chase the name chain. */
     984           0 :   pos = cname_pos;
     985             : 
     986             :   /* The last request is no longer pending.. */
     987           0 :   for (i = 0; i < vec_len (dm->unresolved_entries); i++)
     988           0 :     if (ep_index == dm->unresolved_entries[i])
     989             :       {
     990           0 :         vec_delete (dm->unresolved_entries, 1, i);
     991           0 :         goto found_last_request;
     992             :       }
     993           0 :   clib_warning ("pool elt %d supposedly pending, but not found...", ep_index);
     994           0 :   return -1;
     995             : 
     996           0 : found_last_request:
     997             : 
     998           0 :   now = vlib_time_now (vm);
     999           0 :   cname = vnet_dns_labels_to_name (rr->rdata, reply, &pos2);
    1000             :   /* Save the cname */
    1001           0 :   dns_terminate_c_string (&cname);
    1002           0 :   ep = pool_elt_at_index (dm->entries, ep_index);
    1003           0 :   ep->cname = cname;
    1004           0 :   ep->flags |= (DNS_CACHE_ENTRY_FLAG_CNAME | DNS_CACHE_ENTRY_FLAG_VALID);
    1005             :   /* Save the response */
    1006           0 :   if (ep->dns_response)
    1007           0 :     vec_free (ep->dns_response);
    1008           0 :   ep->dns_response = reply;
    1009             :   /* Set up expiration time */
    1010           0 :   ep->expiration_time = now + clib_net_to_host_u32 (rr->ttl);
    1011             : 
    1012           0 :   pool_get (dm->entries, next_ep);
    1013             : 
    1014             :   /* Need to recompute ep post pool-get */
    1015           0 :   ep = pool_elt_at_index (dm->entries, ep_index);
    1016             : 
    1017           0 :   clib_memset (next_ep, 0, sizeof (*next_ep));
    1018           0 :   next_ep->name = vec_dup (cname);
    1019           0 :   dns_terminate_c_string (&next_ep->name);
    1020             : 
    1021           0 :   hash_set_mem (dm->cache_entry_by_name, next_ep->name,
    1022             :                 next_ep - dm->entries);
    1023             : 
    1024             :   /* Use the same server */
    1025           0 :   next_ep->server_rotor = ep->server_rotor;
    1026           0 :   next_ep->server_af = ep->server_af;
    1027             : 
    1028             :   /* Move notification data to the next name in the chain */
    1029             : #define _(a) next_ep->a = ep->a; ep->a = 0;
    1030           0 :   foreach_notification_to_move;
    1031             : #undef _
    1032             : 
    1033           0 :   request = name_to_labels (cname);
    1034           0 :   name_copy = vec_dup (request);
    1035             : 
    1036           0 :   qp_offset = vec_len (request);
    1037             : 
    1038             :   /* Add space for the query header */
    1039           0 :   vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
    1040             : 
    1041           0 :   qp = (dns_query_t *) (request + qp_offset);
    1042             : 
    1043           0 :   qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
    1044           0 :   qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
    1045           0 :   clib_memcpy (qp, name_copy, vec_len (name_copy));
    1046           0 :   qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
    1047           0 :   vec_free (name_copy);
    1048             : 
    1049           0 :   qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
    1050           0 :   qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
    1051             : 
    1052             :   /* Punch in space for the dns_header_t */
    1053           0 :   vec_insert (request, sizeof (dns_header_t), 0);
    1054             : 
    1055           0 :   h = (dns_header_t *) request;
    1056             : 
    1057             :   /* Transaction ID = pool index */
    1058           0 :   h->id = clib_host_to_net_u16 (next_ep - dm->entries);
    1059             : 
    1060             :   /* Ask for a recursive lookup */
    1061           0 :   h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
    1062           0 :   h->qdcount = clib_host_to_net_u16 (2);
    1063           0 :   h->nscount = 0;
    1064           0 :   h->arcount = 0;
    1065             : 
    1066           0 :   next_ep->dns_request = request;
    1067           0 :   next_ep->retry_timer = now + 2.0;
    1068           0 :   next_ep->retry_count = 0;
    1069             : 
    1070             :   /*
    1071             :    * Enable this to watch recursive resolution happen...
    1072             :    * fformat (stdout, "%U", format_dns_reply, request, 2);
    1073             :    */
    1074             : 
    1075           0 :   vec_add1 (dm->unresolved_entries, next_ep - dm->entries);
    1076           0 :   vnet_send_dns_request (vm, dm, next_ep);
    1077           0 :   return (1);
    1078             : }
    1079             : 
    1080             : int
    1081           6 : vnet_dns_response_to_reply (u8 *response, dns_resolve_name_t *rn,
    1082             :                             u32 *min_ttlp)
    1083             : {
    1084             :   dns_header_t *h;
    1085             :   dns_query_t *qp;
    1086             :   dns_rr_t *rr;
    1087             :   int i, limit;
    1088             :   u8 len;
    1089             :   u8 *curpos, *pos, *pos2;
    1090             :   u16 flags;
    1091             :   u16 rcode;
    1092             :   u32 ttl;
    1093           6 :   int pointer_chase, addr_set = 0;
    1094             : 
    1095           6 :   h = (dns_header_t *) response;
    1096           6 :   flags = clib_net_to_host_u16 (h->flags);
    1097           6 :   rcode = flags & DNS_RCODE_MASK;
    1098             : 
    1099             :   /* See if the response is OK, etc. */
    1100           6 :   switch (rcode)
    1101             :     {
    1102           6 :     default:
    1103             :     case DNS_RCODE_NO_ERROR:
    1104           6 :       break;
    1105             : 
    1106           0 :     case DNS_RCODE_NAME_ERROR:
    1107             :     case DNS_RCODE_FORMAT_ERROR:
    1108           0 :       return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
    1109             : 
    1110           0 :     case DNS_RCODE_SERVER_FAILURE:
    1111             :     case DNS_RCODE_NOT_IMPLEMENTED:
    1112             :     case DNS_RCODE_REFUSED:
    1113           0 :       return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
    1114             :     }
    1115             : 
    1116             :   /* No answers? Loser... */
    1117           6 :   if (clib_net_to_host_u16 (h->anscount) < 1)
    1118           0 :     return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
    1119             : 
    1120           6 :   curpos = (u8 *) (h + 1);
    1121             : 
    1122             :   /* Skip the name we asked about */
    1123           6 :   pos = curpos;
    1124           6 :   len = *pos++;
    1125             :   /* Should never happen, but stil... */
    1126           6 :   if ((len & 0xC0) == 0xC0)
    1127           0 :     curpos += 2;
    1128             :   else
    1129             :     {
    1130             :       /* skip the name / label-set */
    1131          24 :       while (len)
    1132             :         {
    1133          18 :           pos += len;
    1134          18 :           len = *pos++;
    1135             :         }
    1136           6 :       curpos = pos;
    1137             :     }
    1138             :   /* Skip queries */
    1139           6 :   limit = clib_net_to_host_u16 (h->qdcount);
    1140           6 :   qp = (dns_query_t *) curpos;
    1141           6 :   qp += limit;
    1142           6 :   curpos = (u8 *) qp;
    1143             : 
    1144             :   /* Parse answers */
    1145           6 :   limit = clib_net_to_host_u16 (h->anscount);
    1146             : 
    1147          12 :   for (i = 0; i < limit; i++)
    1148             :     {
    1149           6 :       pos = pos2 = curpos;
    1150           6 :       pointer_chase = 0;
    1151             : 
    1152             :       /* Expect pointer chases in the answer section... */
    1153           6 :       if ((pos2[0] & 0xC0) == 0xC0)
    1154             :         {
    1155           6 :           pos = pos2 + 2;
    1156           6 :           pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
    1157           6 :           pointer_chase = 1;
    1158             :         }
    1159             : 
    1160           6 :       len = *pos2++;
    1161             : 
    1162          24 :       while (len)
    1163             :         {
    1164          18 :           pos2 += len;
    1165          18 :           if ((pos2[0] & 0xc0) == 0xc0)
    1166             :             {
    1167             :               /*
    1168             :                * If we've already done one pointer chase,
    1169             :                * do not move the pos pointer.
    1170             :                */
    1171           0 :               if (pointer_chase == 0)
    1172           0 :                 pos = pos2 + 2;
    1173           0 :               pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
    1174           0 :               len = *pos2++;
    1175           0 :               pointer_chase = 1;
    1176             :             }
    1177             :           else
    1178          18 :             len = *pos2++;
    1179             :         }
    1180             : 
    1181           6 :       if (pointer_chase == 0)
    1182           0 :         pos = pos2;
    1183             : 
    1184           6 :       rr = (dns_rr_t *) pos;
    1185             : 
    1186           6 :       switch (clib_net_to_host_u16 (rr->type))
    1187             :         {
    1188           6 :         case DNS_TYPE_A:
    1189             :           /* Collect an ip4 address. Do not pass go. Do not collect $200 */
    1190           6 :           ip_address_set (&rn->address, rr->rdata, AF_IP4);
    1191           6 :           ttl = clib_net_to_host_u32 (rr->ttl);
    1192           6 :           addr_set += 1;
    1193           6 :           if (min_ttlp && *min_ttlp > ttl)
    1194           0 :             *min_ttlp = ttl;
    1195           6 :           break;
    1196           0 :         case DNS_TYPE_AAAA:
    1197             :           /* Collect an ip6 address. Do not pass go. Do not collect $200 */
    1198           0 :           ip_address_set (&rn->address, rr->rdata, AF_IP6);
    1199           0 :           ttl = clib_net_to_host_u32 (rr->ttl);
    1200           0 :           if (min_ttlp && *min_ttlp > ttl)
    1201           0 :             *min_ttlp = ttl;
    1202           0 :           addr_set += 1;
    1203           0 :           break;
    1204             : 
    1205           0 :         default:
    1206           0 :           break;
    1207             :         }
    1208             :       /* Might as well stop ASAP */
    1209           6 :       if (addr_set > 1)
    1210           0 :         break;
    1211           6 :       pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
    1212           6 :       curpos = pos;
    1213             :     }
    1214             : 
    1215           6 :   if (addr_set == 0)
    1216           0 :     return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
    1217           6 :   return 0;
    1218             : }
    1219             : 
    1220             : int
    1221           0 : vnet_dns_response_to_name (u8 * response,
    1222             :                            vl_api_dns_resolve_ip_reply_t * rmp,
    1223             :                            u32 * min_ttlp)
    1224             : {
    1225             :   dns_header_t *h;
    1226             :   dns_query_t *qp;
    1227             :   dns_rr_t *rr;
    1228             :   int i, limit;
    1229             :   u8 len;
    1230             :   u8 *curpos, *pos, *pos2;
    1231             :   u16 flags;
    1232             :   u16 rcode;
    1233             :   u8 *name;
    1234             :   u32 ttl;
    1235             :   u8 *junk __attribute__ ((unused));
    1236           0 :   int name_set = 0;
    1237             :   int pointer_chase;
    1238             : 
    1239           0 :   h = (dns_header_t *) response;
    1240           0 :   flags = clib_net_to_host_u16 (h->flags);
    1241           0 :   rcode = flags & DNS_RCODE_MASK;
    1242             : 
    1243             :   /* See if the response is OK, etc. */
    1244           0 :   switch (rcode)
    1245             :     {
    1246           0 :     default:
    1247             :     case DNS_RCODE_NO_ERROR:
    1248           0 :       break;
    1249             : 
    1250           0 :     case DNS_RCODE_NAME_ERROR:
    1251             :     case DNS_RCODE_FORMAT_ERROR:
    1252           0 :       return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
    1253             : 
    1254           0 :     case DNS_RCODE_SERVER_FAILURE:
    1255             :     case DNS_RCODE_NOT_IMPLEMENTED:
    1256             :     case DNS_RCODE_REFUSED:
    1257           0 :       return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
    1258             :     }
    1259             : 
    1260             :   /* No answers? Loser... */
    1261           0 :   if (clib_net_to_host_u16 (h->anscount) < 1)
    1262           0 :     return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
    1263             : 
    1264           0 :   curpos = (u8 *) (h + 1);
    1265             : 
    1266             :   /* Skip the name we asked about */
    1267           0 :   pos = curpos;
    1268           0 :   len = *pos++;
    1269             :   /* Should never happen, but stil... */
    1270           0 :   if ((len & 0xC0) == 0xC0)
    1271           0 :     curpos += 2;
    1272             :   else
    1273             :     {
    1274             :       /* skip the name / label-set */
    1275           0 :       while (len)
    1276             :         {
    1277           0 :           pos += len;
    1278           0 :           len = *pos++;
    1279             :         }
    1280           0 :       curpos = pos;
    1281             :     }
    1282             :   /* Skip queries */
    1283           0 :   limit = clib_net_to_host_u16 (h->qdcount);
    1284           0 :   qp = (dns_query_t *) curpos;
    1285           0 :   qp += limit;
    1286           0 :   curpos = (u8 *) qp;
    1287             : 
    1288             :   /* Parse answers */
    1289           0 :   limit = clib_net_to_host_u16 (h->anscount);
    1290             : 
    1291           0 :   for (i = 0; i < limit; i++)
    1292             :     {
    1293           0 :       pos = pos2 = curpos;
    1294           0 :       pointer_chase = 0;
    1295             : 
    1296             :       /* Expect pointer chases in the answer section... */
    1297           0 :       if ((pos2[0] & 0xC0) == 0xC0)
    1298             :         {
    1299           0 :           pos = pos2 + 2;
    1300           0 :           pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
    1301           0 :           pointer_chase = 1;
    1302             :         }
    1303             : 
    1304           0 :       len = *pos2++;
    1305             : 
    1306           0 :       while (len)
    1307             :         {
    1308           0 :           pos2 += len;
    1309           0 :           if ((pos2[0] & 0xc0) == 0xc0)
    1310             :             {
    1311             :               /*
    1312             :                * If we've already done one pointer chase,
    1313             :                * do not move the pos pointer.
    1314             :                */
    1315           0 :               if (pointer_chase == 0)
    1316           0 :                 pos = pos2 + 2;
    1317           0 :               pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
    1318           0 :               len = *pos2++;
    1319           0 :               pointer_chase = 1;
    1320             :             }
    1321             :           else
    1322           0 :             len = *pos2++;
    1323             :         }
    1324             : 
    1325           0 :       if (pointer_chase == 0)
    1326           0 :         pos = pos2;
    1327             : 
    1328           0 :       rr = (dns_rr_t *) pos;
    1329             : 
    1330           0 :       switch (clib_net_to_host_u16 (rr->type))
    1331             :         {
    1332           0 :         case DNS_TYPE_PTR:
    1333           0 :           name = vnet_dns_labels_to_name (rr->rdata, response, &junk);
    1334           0 :           memcpy (rmp->name, name, vec_len (name));
    1335           0 :           ttl = clib_net_to_host_u32 (rr->ttl);
    1336           0 :           if (min_ttlp)
    1337           0 :             *min_ttlp = ttl;
    1338           0 :           rmp->name[vec_len (name)] = 0;
    1339           0 :           name_set = 1;
    1340           0 :           break;
    1341           0 :         default:
    1342           0 :           break;
    1343             :         }
    1344             :       /* Might as well stop ASAP */
    1345           0 :       if (name_set == 1)
    1346           0 :         break;
    1347           0 :       pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
    1348           0 :       curpos = pos;
    1349             :     }
    1350             : 
    1351           0 :   if (name_set == 0)
    1352           0 :     return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
    1353           0 :   return 0;
    1354             : }
    1355             : 
    1356             : __clib_export int
    1357           5 : dns_resolve_name (u8 *name, dns_cache_entry_t **ep, dns_pending_request_t *t0,
    1358             :                   dns_resolve_name_t *rn)
    1359             : {
    1360           5 :   dns_main_t *dm = &dns_main;
    1361           5 :   vlib_main_t *vm = vlib_get_main ();
    1362             : 
    1363           5 :   int rv = vnet_dns_resolve_name (vm, dm, name, t0, ep);
    1364             : 
    1365             :   /* Error, e.g. not enabled? Tell the user */
    1366           5 :   if (rv < 0)
    1367           0 :     return rv;
    1368             : 
    1369             :   /* Resolution pending? Don't reply... */
    1370           5 :   if (ep[0] == 0)
    1371           0 :     return 0;
    1372             : 
    1373           5 :   return vnet_dns_response_to_reply (ep[0]->dns_response, rn, 0 /* ttl-ptr */);
    1374             : }
    1375             : 
    1376             : static void
    1377           1 : vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
    1378             : {
    1379           1 :   dns_main_t *dm = &dns_main;
    1380             :   vl_api_dns_resolve_name_reply_t *rmp;
    1381           1 :   dns_cache_entry_t *ep = 0;
    1382           1 :   dns_pending_request_t _t0 = { 0 }, *t0 = &_t0;
    1383             :   int rv;
    1384             :   dns_resolve_name_t rn;
    1385             : 
    1386             :   /* Sanitize the name slightly */
    1387           1 :   mp->name[ARRAY_LEN (mp->name) - 1] = 0;
    1388             : 
    1389           1 :   t0->request_type = DNS_API_PENDING_NAME_TO_IP;
    1390           1 :   t0->client_index = mp->client_index;
    1391           1 :   t0->client_context = mp->context;
    1392             : 
    1393           1 :   rv = dns_resolve_name (mp->name, &ep, t0, &rn);
    1394             : 
    1395             :   /* Error, e.g. not enabled? Tell the user */
    1396           1 :   if (rv < 0)
    1397             :     {
    1398           0 :       REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
    1399           0 :       return;
    1400             :     }
    1401             : 
    1402             :   /* Resolution pending? Don't reply... */
    1403           1 :   if (ep == 0)
    1404           0 :     return;
    1405             : 
    1406             :   /* *INDENT-OFF* */
    1407           1 :   REPLY_MACRO2 (VL_API_DNS_RESOLVE_NAME_REPLY, ({
    1408             :                   ip_address_copy_addr (rmp->ip4_address, &rn.address);
    1409             :                   if (ip_addr_version (&rn.address) == AF_IP4)
    1410             :                     rmp->ip4_set = 1;
    1411             :                   else
    1412             :                     rmp->ip6_set = 1;
    1413             :                 }));
    1414             :   /* *INDENT-ON* */
    1415             : }
    1416             : 
    1417             : static void
    1418           0 : vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
    1419             : {
    1420           0 :   vlib_main_t *vm = vlib_get_main ();
    1421           0 :   dns_main_t *dm = &dns_main;
    1422             :   vl_api_dns_resolve_ip_reply_t *rmp;
    1423             :   dns_cache_entry_t *ep;
    1424             :   int rv;
    1425             :   int i, len;
    1426           0 :   u8 *lookup_name = 0;
    1427             :   u8 digit, nybble;
    1428           0 :   dns_pending_request_t _t0 = { 0 }, *t0 = &_t0;
    1429             : 
    1430           0 :   if (mp->is_ip6)
    1431             :     {
    1432           0 :       for (i = 15; i >= 0; i--)
    1433             :         {
    1434           0 :           digit = mp->address[i];
    1435           0 :           nybble = (digit & 0x0F);
    1436           0 :           if (nybble > 9)
    1437           0 :             vec_add1 (lookup_name, (nybble - 10) + 'a');
    1438             :           else
    1439           0 :             vec_add1 (lookup_name, nybble + '0');
    1440           0 :           vec_add1 (lookup_name, '.');
    1441           0 :           nybble = (digit & 0xF0) >> 4;
    1442           0 :           if (nybble > 9)
    1443           0 :             vec_add1 (lookup_name, (nybble - 10) + 'a');
    1444             :           else
    1445           0 :             vec_add1 (lookup_name, nybble + '0');
    1446           0 :           vec_add1 (lookup_name, '.');
    1447             :         }
    1448           0 :       len = vec_len (lookup_name);
    1449           0 :       vec_validate (lookup_name, len + 8);
    1450           0 :       memcpy (lookup_name + len, "ip6.arpa", 8);
    1451             :     }
    1452             :   else
    1453             :     {
    1454           0 :       for (i = 3; i >= 0; i--)
    1455             :         {
    1456           0 :           digit = mp->address[i];
    1457           0 :           lookup_name = format (lookup_name, "%d.", digit);
    1458             :         }
    1459           0 :       lookup_name = format (lookup_name, "in-addr.arpa");
    1460             :     }
    1461             : 
    1462           0 :   vec_add1 (lookup_name, 0);
    1463             : 
    1464           0 :   t0->request_type = DNS_API_PENDING_IP_TO_NAME;
    1465           0 :   t0->client_index = mp->client_index;
    1466           0 :   t0->client_context = mp->context;
    1467             : 
    1468           0 :   rv = vnet_dns_resolve_name (vm, dm, lookup_name, t0, &ep);
    1469             : 
    1470           0 :   vec_free (lookup_name);
    1471             : 
    1472             :   /* Error, e.g. not enabled? Tell the user */
    1473           0 :   if (rv < 0)
    1474             :     {
    1475           0 :       REPLY_MACRO (VL_API_DNS_RESOLVE_IP_REPLY);
    1476           0 :       return;
    1477             :     }
    1478             : 
    1479             :   /* Resolution pending? Don't reply... */
    1480           0 :   if (ep == 0)
    1481           0 :     return;
    1482             : 
    1483             :   /* *INDENT-OFF* */
    1484           0 :   REPLY_MACRO2(VL_API_DNS_RESOLVE_IP_REPLY,
    1485             :   ({
    1486             :     rv = vnet_dns_response_to_name (ep->dns_response, rmp, 0 /* ttl-ptr */);
    1487             :     rmp->retval = clib_host_to_net_u32 (rv);
    1488             :   }));
    1489             :   /* *INDENT-ON* */
    1490             : }
    1491             : 
    1492             : static clib_error_t *
    1493         559 : dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
    1494             : {
    1495         559 :   dns_main_t *dm = &dns_main;
    1496             : 
    1497         559 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    1498             :     {
    1499           0 :       if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
    1500             :         ;
    1501           0 :       else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
    1502             :         ;
    1503             :       else
    1504           0 :         return clib_error_return (0, "unknown input `%U'",
    1505             :                                   format_unformat_error, input);
    1506             :     }
    1507         559 :   return 0;
    1508             : }
    1509             : 
    1510        4506 : VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
    1511             : 
    1512             : uword
    1513           5 : unformat_dns_reply (unformat_input_t * input, va_list * args)
    1514             : {
    1515           5 :   u8 **result = va_arg (*args, u8 **);
    1516           5 :   u8 **namep = va_arg (*args, u8 **);
    1517             :   ip4_address_t a4;
    1518             :   ip6_address_t a6;
    1519           5 :   int a4_set = 0;
    1520           5 :   int a6_set = 0;
    1521             :   u8 *name;
    1522           5 :   int name_set = 0;
    1523             :   u8 *ce;
    1524             :   u32 qp_offset;
    1525             :   dns_header_t *h;
    1526             :   dns_query_t *qp;
    1527             :   dns_rr_t *rr;
    1528             :   u8 *rru8;
    1529             : 
    1530           5 :   if (unformat (input, "%v", &name))
    1531           5 :     name_set = 1;
    1532             : 
    1533           5 :   if (unformat (input, "%U", unformat_ip4_address, &a4))
    1534             :     {
    1535           5 :       a4_set = 1;
    1536           5 :       if (unformat (input, "%U", unformat_ip6_address, &a6))
    1537           0 :         a6_set = 1;
    1538             :     }
    1539             : 
    1540           5 :   if (unformat (input, "%U", unformat_ip6_address, &a6))
    1541             :     {
    1542           0 :       a6_set = 1;
    1543           0 :       if (unformat (input, "%U", unformat_ip4_address, &a6))
    1544           0 :         a4_set = 1;
    1545             :     }
    1546             : 
    1547             :   /* Must have a name */
    1548           5 :   if (!name_set)
    1549           0 :     return 0;
    1550             : 
    1551             :   /* Must have at least one address */
    1552           5 :   if (!(a4_set + a6_set))
    1553           0 :     return 0;
    1554             : 
    1555             :   /* Build a fake DNS cache entry string, one hemorrhoid at a time */
    1556           5 :   ce = name_to_labels (name);
    1557           5 :   qp_offset = vec_len (ce);
    1558             : 
    1559             :   /* Add space for the query header */
    1560           5 :   vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
    1561           5 :   qp = (dns_query_t *) (ce + qp_offset);
    1562             : 
    1563           5 :   qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
    1564           5 :   qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
    1565             : 
    1566             :   /* Punch in space for the dns_header_t */
    1567           5 :   vec_insert (ce, sizeof (dns_header_t), 0);
    1568             : 
    1569           5 :   h = (dns_header_t *) ce;
    1570             : 
    1571             :   /* Fake Transaction ID */
    1572           5 :   h->id = 0xFFFF;
    1573             : 
    1574           5 :   h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
    1575           5 :   h->qdcount = clib_host_to_net_u16 (1);
    1576           5 :   h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
    1577           5 :   h->nscount = 0;
    1578           5 :   h->arcount = 0;
    1579             : 
    1580             :   /* Now append one or two A/AAAA RR's... */
    1581           5 :   if (a4_set)
    1582             :     {
    1583             :       /* Pointer to the name (DGMS) */
    1584           5 :       vec_add1 (ce, 0xC0);
    1585           5 :       vec_add1 (ce, 0x0C);
    1586           5 :       vec_add2 (ce, rru8, sizeof (*rr) + 4);
    1587           5 :       rr = (void *) rru8;
    1588           5 :       rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
    1589           5 :       rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
    1590           5 :       rr->ttl = clib_host_to_net_u32 (86400);
    1591           5 :       rr->rdlength = clib_host_to_net_u16 (4);
    1592           5 :       memcpy (rr->rdata, &a4, sizeof (a4));
    1593             :     }
    1594           5 :   if (a6_set)
    1595             :     {
    1596             :       /* Pointer to the name (DGMS) */
    1597           0 :       vec_add1 (ce, 0xC0);
    1598           0 :       vec_add1 (ce, 0x0C);
    1599           0 :       vec_add2 (ce, rru8, sizeof (*rr) + 16);
    1600           0 :       rr = (void *) rru8;
    1601           0 :       rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
    1602           0 :       rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
    1603           0 :       rr->ttl = clib_host_to_net_u32 (86400);
    1604           0 :       rr->rdlength = clib_host_to_net_u16 (16);
    1605           0 :       memcpy (rr->rdata, &a6, sizeof (a6));
    1606             :     }
    1607           5 :   *result = ce;
    1608           5 :   if (namep)
    1609           5 :     *namep = name;
    1610             :   else
    1611           0 :     vec_free (name);
    1612             : 
    1613           5 :   return 1;
    1614             : }
    1615             : 
    1616             : u8 *
    1617           3 : format_dns_query (u8 * s, va_list * args)
    1618             : {
    1619           3 :   u8 **curpos = va_arg (*args, u8 **);
    1620           3 :   int verbose = va_arg (*args, int);
    1621             :   u8 *pos;
    1622             :   dns_query_t *qp;
    1623             :   int len, i;
    1624           3 :   if (verbose > 1)
    1625           0 :     s = format (s, "    Name: ");
    1626             : 
    1627             :   /* Unwind execrated counted-label sheit */
    1628           3 :   pos = *curpos;
    1629           3 :   len = *pos++;
    1630             : 
    1631          12 :   while (len)
    1632             :     {
    1633          41 :       for (i = 0; i < len; i++)
    1634          32 :         vec_add1 (s, *pos++);
    1635             : 
    1636           9 :       len = *pos++;
    1637           9 :       if (len)
    1638           6 :         vec_add1 (s, '.');
    1639             :       else
    1640             :         {
    1641           3 :           vec_add1 (s, ':');
    1642           3 :           vec_add1 (s, ' ');
    1643             :         }
    1644             :     }
    1645             : 
    1646           3 :   qp = (dns_query_t *) pos;
    1647           3 :   if (verbose > 1)
    1648             :     {
    1649           0 :       switch (clib_net_to_host_u16 (qp->type))
    1650             :         {
    1651           0 :         case DNS_TYPE_A:
    1652           0 :           s = format (s, "type A\n");
    1653           0 :           break;
    1654           0 :         case DNS_TYPE_AAAA:
    1655           0 :           s = format (s, "type AAAA\n");
    1656           0 :           break;
    1657           0 :         case DNS_TYPE_ALL:
    1658           0 :           s = format (s, "type ALL\n");
    1659           0 :           break;
    1660             : 
    1661           0 :         default:
    1662           0 :           s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
    1663           0 :           break;
    1664             :         }
    1665           3 :     }
    1666             : 
    1667           3 :   pos += sizeof (*qp);
    1668             : 
    1669           3 :   *curpos = pos;
    1670           3 :   return s;
    1671             : }
    1672             : 
    1673             : /**
    1674             :  * format dns reply data
    1675             :  * verbose > 1, dump everything
    1676             :  * verbose == 1, dump all A and AAAA records
    1677             :  * verbose == 0, dump one A record, and one AAAA record
    1678             :  */
    1679             : 
    1680             : u8 *
    1681           1 : format_dns_reply_data (u8 * s, va_list * args)
    1682             : {
    1683           1 :   u8 *reply = va_arg (*args, u8 *);
    1684           1 :   u8 **curpos = va_arg (*args, u8 **);
    1685           1 :   int verbose = va_arg (*args, int);
    1686           1 :   int *print_ip4 = va_arg (*args, int *);
    1687           1 :   int *print_ip6 = va_arg (*args, int *);
    1688             :   int len;
    1689             :   u8 *pos, *pos2;
    1690             :   dns_rr_t *rr;
    1691             :   int i;
    1692           1 :   int pointer_chase = 0;
    1693             :   u16 *tp;
    1694             :   u16 rrtype_host_byte_order;
    1695             : 
    1696           1 :   pos = pos2 = *curpos;
    1697             : 
    1698           1 :   if (verbose > 1)
    1699           0 :     s = format (s, "    ");
    1700             : 
    1701             :   /* chase pointer? almost always yes here... */
    1702           1 :   if ((pos2[0] & 0xc0) == 0xc0)
    1703             :     {
    1704           1 :       pos = pos2 + 2;
    1705           1 :       pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
    1706           1 :       pointer_chase = 1;
    1707             :     }
    1708             : 
    1709           1 :   len = *pos2++;
    1710             : 
    1711           4 :   while (len)
    1712             :     {
    1713          15 :       for (i = 0; i < len; i++)
    1714             :         {
    1715          12 :           if (verbose > 1)
    1716           0 :             vec_add1 (s, *pos2);
    1717          12 :           pos2++;
    1718             :         }
    1719           3 :       if ((pos2[0] & 0xc0) == 0xc0)
    1720             :         {
    1721             :           /*
    1722             :            * If we've already done one pointer chase,
    1723             :            * do not move the pos pointer.
    1724             :            */
    1725           0 :           if (pointer_chase == 0)
    1726           0 :             pos = pos2 + 2;
    1727           0 :           pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
    1728           0 :           len = *pos2++;
    1729           0 :           pointer_chase = 1;
    1730             :         }
    1731             :       else
    1732           3 :         len = *pos2++;
    1733           3 :       if (len)
    1734             :         {
    1735           2 :           if (verbose > 1)
    1736           0 :             vec_add1 (s, '.');
    1737             :         }
    1738             :       else
    1739             :         {
    1740           1 :           if (verbose > 1)
    1741           0 :             vec_add1 (s, ' ');
    1742             :         }
    1743             :     }
    1744             : 
    1745           1 :   if (pointer_chase == 0)
    1746           0 :     pos = pos2;
    1747             : 
    1748           1 :   rr = (dns_rr_t *) pos;
    1749           1 :   rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
    1750             : 
    1751           1 :   switch (rrtype_host_byte_order)
    1752             :     {
    1753           1 :     case DNS_TYPE_A:
    1754           1 :       if (verbose > 1)
    1755             :         {
    1756           0 :           s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
    1757           0 :                       format_ip4_address, rr->rdata);
    1758             :         }
    1759             :       else
    1760             :         {
    1761           1 :           if (*print_ip4)
    1762           1 :             s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
    1763             :                         clib_net_to_host_u32 (rr->ttl));
    1764           1 :           if (verbose == 0)
    1765           0 :             *print_ip4 = 0;
    1766             : 
    1767             :         }
    1768           1 :       pos += sizeof (*rr) + 4;
    1769           1 :       break;
    1770             : 
    1771           0 :     case DNS_TYPE_AAAA:
    1772           0 :       if (verbose > 1)
    1773             :         {
    1774           0 :           s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
    1775           0 :                       format_ip6_address, rr->rdata);
    1776             :         }
    1777             :       else
    1778             :         {
    1779           0 :           if (*print_ip6)
    1780           0 :             s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
    1781             :                         clib_net_to_host_u32 (rr->ttl));
    1782           0 :           if (verbose == 0)
    1783           0 :             *print_ip6 = 0;
    1784             :         }
    1785           0 :       pos += sizeof (*rr) + 16;
    1786           0 :       break;
    1787             : 
    1788           0 :     case DNS_TYPE_TEXT:
    1789           0 :       if (verbose > 1)
    1790             :         {
    1791           0 :           s = format (s, "TEXT: ");
    1792           0 :           for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
    1793           0 :             vec_add1 (s, rr->rdata[i]);
    1794           0 :           vec_add1 (s, '\n');
    1795             :         }
    1796           0 :       pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
    1797           0 :       break;
    1798             : 
    1799           0 :     case DNS_TYPE_HINFO:
    1800             :       {
    1801             :         /* Two counted strings. DGMS */
    1802             :         u8 *len;
    1803             :         u8 *curpos;
    1804             :         int i;
    1805           0 :         if (verbose > 1)
    1806             :           {
    1807           0 :             s = format (s, "HINFO: ");
    1808           0 :             len = rr->rdata;
    1809           0 :             curpos = len + 1;
    1810           0 :             for (i = 0; i < *len; i++)
    1811           0 :               vec_add1 (s, *curpos++);
    1812             : 
    1813           0 :             vec_add1 (s, ' ');
    1814           0 :             len = curpos++;
    1815           0 :             for (i = 0; i < *len; i++)
    1816           0 :               vec_add1 (s, *curpos++);
    1817             : 
    1818           0 :             vec_add1 (s, '\n');
    1819             :           }
    1820             :       }
    1821           0 :       pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
    1822           0 :       break;
    1823             : 
    1824           0 :     case DNS_TYPE_NAMESERVER:
    1825           0 :       if (verbose > 1)
    1826             :         {
    1827           0 :           s = format (s, "Nameserver: ");
    1828           0 :           pos2 = rr->rdata;
    1829             : 
    1830             :           /* chase pointer? */
    1831           0 :           if ((pos2[0] & 0xc0) == 0xc0)
    1832             :             {
    1833           0 :               pos = pos2 + 2;
    1834           0 :               pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
    1835             :             }
    1836             : 
    1837           0 :           len = *pos2++;
    1838             : 
    1839           0 :           while (len)
    1840             :             {
    1841           0 :               for (i = 0; i < len; i++)
    1842           0 :                 vec_add1 (s, *pos2++);
    1843             : 
    1844             :               /* chase pointer, typically to offset 12... */
    1845           0 :               if (pos2[0] == 0xC0)
    1846           0 :                 pos2 = reply + pos2[1];
    1847             : 
    1848           0 :               len = *pos2++;
    1849           0 :               if (len)
    1850           0 :                 vec_add1 (s, '.');
    1851             :               else
    1852           0 :                 vec_add1 (s, '\n');
    1853             :             }
    1854             :         }
    1855           0 :       pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
    1856           0 :       break;
    1857             : 
    1858           0 :     case DNS_TYPE_MAIL_EXCHANGE:
    1859           0 :       if (verbose > 1)
    1860             :         {
    1861           0 :           tp = (u16 *) rr->rdata;
    1862             : 
    1863           0 :           s = format (s, "Mail Exchange: Preference %d ", (u32)
    1864           0 :                       clib_net_to_host_u16 (*tp));
    1865             : 
    1866           0 :           pos2 = rr->rdata + 2;
    1867             : 
    1868             :           /* chase pointer? */
    1869           0 :           if (pos2[0] == 0xc0)
    1870           0 :             pos2 = reply + pos2[1];
    1871             : 
    1872           0 :           len = *pos2++;
    1873             : 
    1874           0 :           while (len)
    1875             :             {
    1876           0 :               for (i = 0; i < len; i++)
    1877           0 :                 vec_add1 (s, *pos2++);
    1878             : 
    1879             :               /* chase pointer */
    1880           0 :               if (pos2[0] == 0xC0)
    1881           0 :                 pos2 = reply + pos2[1];
    1882             : 
    1883           0 :               len = *pos2++;
    1884           0 :               if (len)
    1885           0 :                 vec_add1 (s, '.');
    1886             :               else
    1887           0 :                 vec_add1 (s, '\n');
    1888             :             }
    1889             :         }
    1890             : 
    1891           0 :       pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
    1892           0 :       break;
    1893             : 
    1894           0 :     case DNS_TYPE_PTR:
    1895             :     case DNS_TYPE_CNAME:
    1896           0 :       if (verbose > 1)
    1897             :         {
    1898           0 :           tp = (u16 *) rr->rdata;
    1899             : 
    1900           0 :           if (rrtype_host_byte_order == DNS_TYPE_CNAME)
    1901           0 :             s = format (s, "CNAME: ");
    1902             :           else
    1903           0 :             s = format (s, "PTR: ");
    1904             : 
    1905           0 :           pos2 = rr->rdata;
    1906             : 
    1907             :           /* chase pointer? */
    1908           0 :           if (pos2[0] == 0xc0)
    1909           0 :             pos2 = reply + pos2[1];
    1910             : 
    1911           0 :           len = *pos2++;
    1912             : 
    1913           0 :           while (len)
    1914             :             {
    1915           0 :               for (i = 0; i < len; i++)
    1916           0 :                 vec_add1 (s, *pos2++);
    1917             : 
    1918             :               /* chase pointer */
    1919           0 :               if (pos2[0] == 0xC0)
    1920           0 :                 pos2 = reply + pos2[1];
    1921             : 
    1922           0 :               len = *pos2++;
    1923           0 :               if (len)
    1924           0 :                 vec_add1 (s, '.');
    1925             :               else
    1926           0 :                 vec_add1 (s, '\n');
    1927             :             }
    1928             :         }
    1929           0 :       pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
    1930           0 :       break;
    1931             : 
    1932           0 :     default:
    1933           0 :       if (verbose > 1)
    1934           0 :         s = format (s, "type %d: len %d\n",
    1935           0 :                     (int) clib_net_to_host_u16 (rr->type),
    1936           0 :                     sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
    1937           0 :       pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
    1938           0 :       break;
    1939             :     }
    1940             : 
    1941           1 :   *curpos = pos;
    1942             : 
    1943           1 :   return s;
    1944             : }
    1945             : 
    1946             : u8 *
    1947           2 : format_dns_reply (u8 * s, va_list * args)
    1948             : {
    1949           2 :   u8 *reply_as_u8 = va_arg (*args, u8 *);
    1950           2 :   int verbose = va_arg (*args, int);
    1951             :   dns_header_t *h;
    1952             :   u16 id, flags;
    1953             :   u8 *curpos;
    1954             :   int i;
    1955           2 :   int print_ip4 = 1;
    1956           2 :   int print_ip6 = 1;
    1957             : 
    1958           2 :   h = (dns_header_t *) reply_as_u8;
    1959           2 :   id = clib_net_to_host_u16 (h->id);
    1960           2 :   flags = clib_net_to_host_u16 (h->flags);
    1961             : 
    1962           2 :   if (verbose > 1)
    1963             :     {
    1964           0 :       s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
    1965             :                   id);
    1966           0 :       s = format (s, "  %s %s %s %s\n",
    1967           0 :                   (flags & DNS_RA) ? "recur" : "no-recur",
    1968           0 :                   (flags & DNS_RD) ? "recur-des" : "no-recur-des",
    1969           0 :                   (flags & DNS_TC) ? "trunc" : "no-trunc",
    1970           0 :                   (flags & DNS_AA) ? "auth" : "non-auth");
    1971           0 :       s = format (s, "  %d queries, %d answers, %d name-servers,"
    1972             :                   " %d add'l recs\n",
    1973           0 :                   clib_net_to_host_u16 (h->qdcount),
    1974           0 :                   clib_net_to_host_u16 (h->anscount),
    1975           0 :                   clib_net_to_host_u16 (h->nscount),
    1976           0 :                   clib_net_to_host_u16 (h->arcount));
    1977             :     }
    1978             : 
    1979           2 :   curpos = (u8 *) (h + 1);
    1980             : 
    1981           2 :   if (h->qdcount)
    1982             :     {
    1983           2 :       if (verbose > 1)
    1984           0 :         s = format (s, "  Queries:\n");
    1985           5 :       for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
    1986             :         {
    1987             :           /* The query is variable-length, so curpos is a value-result parm */
    1988           3 :           s = format (s, "%U", format_dns_query, &curpos, verbose);
    1989             :         }
    1990             :     }
    1991           2 :   if (h->anscount)
    1992             :     {
    1993           1 :       if (verbose > 1)
    1994           0 :         s = format (s, "  Replies:\n");
    1995             : 
    1996           2 :       for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
    1997             :         {
    1998             :           /* curpos is a value-result parm */
    1999           1 :           s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
    2000             :                       verbose, &print_ip4, &print_ip6);
    2001             :         }
    2002             :     }
    2003           2 :   return s;
    2004             : }
    2005             : 
    2006             : u8 *
    2007           1 : format_dns_cache (u8 * s, va_list * args)
    2008             : {
    2009           1 :   dns_main_t *dm = va_arg (*args, dns_main_t *);
    2010           1 :   f64 now = va_arg (*args, f64);
    2011           1 :   int verbose = va_arg (*args, int);
    2012           1 :   u8 *name = va_arg (*args, u8 *);
    2013             :   dns_cache_entry_t *ep;
    2014             :   char *ss;
    2015             :   uword *p;
    2016             : 
    2017           1 :   if (dm->is_enabled == 0)
    2018             :     {
    2019           0 :       s = format (s, "The DNS cache is disabled...");
    2020           0 :       return s;
    2021             :     }
    2022             : 
    2023           1 :   if (pool_elts (dm->entries) == 0)
    2024             :     {
    2025           0 :       s = format (s, "The DNS cache is empty...");
    2026           0 :       return s;
    2027             :     }
    2028             : 
    2029           1 :   dns_cache_lock (dm, 6);
    2030             : 
    2031           1 :   if (name)
    2032             :     {
    2033           0 :       p = hash_get_mem (dm->cache_entry_by_name, name);
    2034           0 :       if (!p)
    2035             :         {
    2036           0 :           s = format (s, "%s is not in the cache...", name);
    2037           0 :           dns_cache_unlock (dm);
    2038           0 :           return (s);
    2039             :         }
    2040             : 
    2041           0 :       ep = pool_elt_at_index (dm->entries, p[0]);
    2042             :       /* Magic to spit out a C-initializer to research hemorrhoids... */
    2043           0 :       if (verbose == 3)
    2044             :         {
    2045             :           int i, j;
    2046           0 :           s = format (s, "static u8 dns_reply_data_initializer[] =\n");
    2047           0 :           s = format (s, "{\n");
    2048           0 :           j = 0;
    2049           0 :           for (i = 0; i < vec_len (ep->dns_response); i++)
    2050             :             {
    2051           0 :               if (j++ == 8)
    2052             :                 {
    2053           0 :                   j = 0;
    2054           0 :                   vec_add1 (s, '\n');
    2055             :                 }
    2056           0 :               s = format (s, "0x%02x, ", ep->dns_response[i]);
    2057             :             }
    2058           0 :           s = format (s, "};\n");
    2059             :         }
    2060             :       else
    2061             :         {
    2062           0 :           if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
    2063             :             {
    2064           0 :               ASSERT (ep->dns_response);
    2065           0 :               if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
    2066           0 :                 ss = "[S] ";
    2067             :               else
    2068           0 :                 ss = "    ";
    2069             : 
    2070           0 :               if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
    2071           0 :                 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
    2072             :               else
    2073           0 :                 s = format (s, "%s%s -> %U", ss, ep->name,
    2074             :                             format_dns_reply, ep->dns_response, verbose);
    2075           0 :               if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
    2076             :                 {
    2077           0 :                   f64 time_left = ep->expiration_time - now;
    2078           0 :                   if (time_left > 0.0)
    2079           0 :                     s = format (s, "  TTL left %.1f", time_left);
    2080             :                   else
    2081           0 :                     s = format (s, "  EXPIRED");
    2082             :                 }
    2083             :             }
    2084             :           else
    2085             :             {
    2086           0 :               ASSERT (ep->dns_request);
    2087           0 :               s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
    2088             :                           verbose);
    2089             :             }
    2090           0 :           vec_add1 (s, '\n');
    2091             :         }
    2092           0 :       return s;
    2093             :     }
    2094             : 
    2095           1 :   s = format (s, "DNS cache contains %d entries\n", pool_elts (dm->entries));
    2096             : 
    2097           1 :   if (verbose > 0)
    2098             :     {
    2099             :       /* *INDENT-OFF* */
    2100           3 :       pool_foreach (ep, dm->entries)
    2101             :        {
    2102           2 :         if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
    2103             :           {
    2104           1 :             ASSERT (ep->dns_response);
    2105           1 :             if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
    2106           1 :               ss = "[S] ";
    2107             :             else
    2108           0 :               ss = "    ";
    2109             : 
    2110           1 :             if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
    2111           0 :               s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
    2112             :             else
    2113           1 :               s = format (s, "%s%s -> %U", ss, ep->name,
    2114             :                           format_dns_reply,
    2115             :                           ep->dns_response,
    2116             :                           verbose);
    2117           1 :             if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
    2118             :               {
    2119           0 :                 f64 time_left = ep->expiration_time - now;
    2120           0 :                 if (time_left > 0.0)
    2121           0 :                   s = format (s, "  TTL left %.1f", time_left);
    2122             :                 else
    2123           0 :                   s = format (s, "  EXPIRED");
    2124             : 
    2125           0 :                 if (verbose > 2)
    2126           0 :                   s = format (s, "    %d client notifications pending\n",
    2127           0 :                               vec_len(ep->pending_requests));
    2128             :               }
    2129             :           }
    2130             :         else
    2131             :           {
    2132           1 :             ASSERT (ep->dns_request);
    2133           1 :             s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
    2134             :                         verbose);
    2135             :           }
    2136           2 :         vec_add1 (s, '\n');
    2137             :       }
    2138             :       /* *INDENT-ON* */
    2139             :     }
    2140             : 
    2141           1 :   dns_cache_unlock (dm);
    2142             : 
    2143           1 :   return s;
    2144             : }
    2145             : 
    2146             : static clib_error_t *
    2147           1 : show_dns_cache_command_fn (vlib_main_t * vm,
    2148             :                            unformat_input_t * input, vlib_cli_command_t * cmd)
    2149             : {
    2150           1 :   dns_main_t *dm = &dns_main;
    2151           1 :   int verbose = 0;
    2152           1 :   u8 *name = 0;
    2153           1 :   f64 now = vlib_time_now (vm);
    2154             : 
    2155           2 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    2156             :     {
    2157           1 :       if (unformat (input, "verbose %d", &verbose))
    2158             :         ;
    2159           1 :       else if (unformat (input, "verbose"))
    2160           1 :         verbose = 1;
    2161           0 :       else if (unformat (input, "name %s", &name))
    2162             :         ;
    2163             :       else
    2164           0 :         return clib_error_return (0, "unknown input `%U'",
    2165             :                                   format_unformat_error, input);
    2166             :     }
    2167             : 
    2168           1 :   vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
    2169             : 
    2170           1 :   return 0;
    2171             : }
    2172             : 
    2173             : /* *INDENT-OFF* */
    2174      220807 : VLIB_CLI_COMMAND (show_dns_cache_command) =
    2175             : {
    2176             :   .path = "show dns cache",
    2177             :   .short_help = "show dns cache [verbose [nn]]",
    2178             :   .function = show_dns_cache_command_fn,
    2179             : };
    2180             : /* *INDENT-ON* */
    2181             : 
    2182             : static clib_error_t *
    2183           0 : show_dns_servers_command_fn (vlib_main_t * vm,
    2184             :                              unformat_input_t * input,
    2185             :                              vlib_cli_command_t * cmd)
    2186             : {
    2187           0 :   dns_main_t *dm = &dns_main;
    2188             :   int i;
    2189             : 
    2190           0 :   if ((vec_len (dm->ip4_name_servers) + vec_len (dm->ip6_name_servers)) == 0)
    2191           0 :     return clib_error_return (0, "No name servers configured...");
    2192             : 
    2193           0 :   if (vec_len (dm->ip4_name_servers))
    2194             :     {
    2195           0 :       vlib_cli_output (vm, "ip4 name servers:");
    2196           0 :       for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
    2197           0 :         vlib_cli_output (vm, "%U", format_ip4_address,
    2198           0 :                          dm->ip4_name_servers + i);
    2199             :     }
    2200           0 :   if (vec_len (dm->ip6_name_servers))
    2201             :     {
    2202           0 :       vlib_cli_output (vm, "ip6 name servers:");
    2203           0 :       for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
    2204           0 :         vlib_cli_output (vm, "%U", format_ip6_address,
    2205           0 :                          dm->ip4_name_servers + i);
    2206             :     }
    2207           0 :   return 0;
    2208             : }
    2209             : 
    2210             : /* *INDENT-OFF* */
    2211      220807 : VLIB_CLI_COMMAND (show_dns_server_command) =
    2212             : {
    2213             :   .path = "show dns servers",
    2214             :   .short_help = "show dns servers",
    2215             :   .function = show_dns_servers_command_fn,
    2216             : };
    2217             : /* *INDENT-ON* */
    2218             : 
    2219             : 
    2220             : static clib_error_t *
    2221           5 : dns_cache_add_del_command_fn (vlib_main_t * vm,
    2222             :                               unformat_input_t * input,
    2223             :                               vlib_cli_command_t * cmd)
    2224             : {
    2225           5 :   dns_main_t *dm = &dns_main;
    2226             :   u8 *dns_reply_data;
    2227             :   u8 *name;
    2228           5 :   int is_add = -1;
    2229           5 :   int is_clear = -1;
    2230             :   int rv;
    2231             :   clib_error_t *error;
    2232             : 
    2233           5 :   if (unformat (input, "add"))
    2234           5 :     is_add = 1;
    2235           5 :   if (unformat (input, "del"))
    2236           0 :     is_add = 0;
    2237           5 :   if (unformat (input, "clear"))
    2238           0 :     is_clear = 1;
    2239             : 
    2240           5 :   if (is_add == -1 && is_clear == -1)
    2241           0 :     return clib_error_return (0, "add / del / clear required...");
    2242             : 
    2243           5 :   if (is_clear == 1)
    2244             :     {
    2245           0 :       rv = dns_cache_clear (dm);
    2246           0 :       switch (rv)
    2247             :         {
    2248           0 :         case 0:
    2249           0 :           return 0;
    2250             : 
    2251           0 :         case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
    2252           0 :           error = clib_error_return (0, "Name resolution not enabled");
    2253           0 :           return error;
    2254             :         }
    2255             :     }
    2256             : 
    2257             :   /* Delete (by name)? */
    2258           5 :   if (is_add == 0)
    2259             :     {
    2260           0 :       if (unformat (input, "%v", &name))
    2261             :         {
    2262           0 :           rv = dns_delete_by_name (dm, name);
    2263           0 :           switch (rv)
    2264             :             {
    2265           0 :             case VNET_API_ERROR_NO_SUCH_ENTRY:
    2266           0 :               error = clib_error_return (0, "%v not in the cache...", name);
    2267           0 :               vec_free (name);
    2268           0 :               return error;
    2269             : 
    2270           0 :             case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
    2271           0 :               error = clib_error_return (0, "Name resolution not enabled");
    2272           0 :               vec_free (name);
    2273           0 :               return error;
    2274             : 
    2275           0 :             case 0:
    2276           0 :               vec_free (name);
    2277           0 :               return 0;
    2278             : 
    2279           0 :             default:
    2280           0 :               error = clib_error_return (0, "dns_delete_by_name returned %d",
    2281             :                                          rv);
    2282           0 :               vec_free (name);
    2283           0 :               return error;
    2284             :             }
    2285             :         }
    2286           0 :       return clib_error_return (0, "unknown input `%U'",
    2287             :                                 format_unformat_error, input);
    2288             :     }
    2289             : 
    2290             :   /* Note: dns_add_static_entry consumes the name vector if OK... */
    2291           5 :   if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
    2292             :     {
    2293           5 :       rv = dns_add_static_entry (dm, name, dns_reply_data);
    2294           5 :       switch (rv)
    2295             :         {
    2296           0 :         case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
    2297           0 :           vec_free (name);
    2298           0 :           vec_free (dns_reply_data);
    2299           0 :           return clib_error_return (0, "%v already in the cache...", name);
    2300           5 :         case 0:
    2301           5 :           return 0;
    2302             : 
    2303           0 :         default:
    2304           0 :           return clib_error_return (0, "dns_add_static_entry returned %d",
    2305             :                                     rv);
    2306             :         }
    2307             :     }
    2308             : 
    2309           0 :   return 0;
    2310             : }
    2311             : 
    2312             : /* *INDENT-OFF* */
    2313      220807 : VLIB_CLI_COMMAND (dns_cache_add_del_command) =
    2314             : {
    2315             :   .path = "dns cache",
    2316             :   .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
    2317             :   .function = dns_cache_add_del_command_fn,
    2318             : };
    2319             : /* *INDENT-ON* */
    2320             : 
    2321             : #define DNS_FORMAT_TEST 1
    2322             : 
    2323             : #if DNS_FORMAT_TEST > 0
    2324             : #if 0
    2325             : /* yahoo.com */
    2326             : static u8 dns_reply_data_initializer[] =
    2327             :   { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
    2328             :   0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
    2329             :   0x0,                          /* null lbl */
    2330             :   0x0, 0xff,                    /* type ALL */
    2331             :   0x0, 0x1,                     /* class IN */
    2332             :   0xc0, 0xc,                    /* pointer to yahoo.com name */
    2333             :   0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
    2334             :   0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
    2335             :   0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
    2336             :   0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
    2337             :   0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
    2338             :   0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
    2339             :   0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
    2340             :   0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
    2341             :   0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
    2342             :   0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
    2343             :   0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
    2344             :   0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
    2345             :   0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
    2346             :   0x6e,
    2347             :   0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
    2348             :   0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
    2349             :   0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
    2350             :   0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
    2351             :   0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
    2352             :   0x0,
    2353             :   0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
    2354             :   0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
    2355             :   0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
    2356             :   0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
    2357             :   0x0,
    2358             :   0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
    2359             :   0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
    2360             :   0x0,
    2361             :   0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
    2362             :   0x0,
    2363             :   0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
    2364             :   0x0,
    2365             :   0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
    2366             :   0x6f,
    2367             :   0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
    2368             :   0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
    2369             :   0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
    2370             :   0x2, 0x58
    2371             : };
    2372             : 
    2373             : /* www.cisco.com, has no addresses in reply */
    2374             : static u8 dns_reply_data_initializer[] = {
    2375             :   0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
    2376             :   0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
    2377             :   0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
    2378             : 
    2379             :   0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
    2380             :   0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
    2381             :   0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
    2382             :   0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
    2383             :   0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
    2384             : };
    2385             : 
    2386             : /* bind8 (linux widget, w/ nasty double pointer chasees */
    2387             : static u8 dns_reply_data_initializer[] = {
    2388             :   /* 0 */
    2389             :   0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08,
    2390             :   /* 8 */
    2391             :   0x00, 0x06, 0x00, 0x06, 0x0a, 0x6f, 0x72, 0x69,
    2392             :   /* 16 */
    2393             :   0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77, 0x77, 0x05,
    2394             :   /* 24 */
    2395             :   0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f,
    2396             :   /* 32 */
    2397             :   0x6d, 0x00, 0x00, 0xff, 0x00, 0x01, 0x0a, 0x6f,
    2398             :   /* 40 */
    2399             :   0x72, 0x69, 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77,
    2400             :   /* 48 */
    2401             :   0x77, 0x05, 0x43, 0x49, 0x53, 0x43, 0x4f, 0xc0,
    2402             : 
    2403             :   /* 56 */
    2404             :   0x1d, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
    2405             : 
    2406             :   /* 64 */
    2407             :   0x9a, 0x00, 0x18, 0x15, 0x72, 0x63, 0x64,
    2408             :   0x6e, 0x39, 0x2d, 0x31, 0x34, 0x70, 0x2d, 0x64, 0x63,
    2409             :   0x7a, 0x30, 0x35, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31,
    2410             :   0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00, 0x01, 0x00,
    2411             :   0x00, 0x05, 0x9a, 0x00, 0x1a, 0x17, 0x61, 0x6c, 0x6c,
    2412             :   0x6e, 0x30, 0x31, 0x2d, 0x61, 0x67, 0x30, 0x39, 0x2d,
    2413             :   0x64, 0x63, 0x7a, 0x30, 0x33, 0x6e, 0x2d, 0x67, 0x73,
    2414             :   0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00,
    2415             :   0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x10, 0x0d, 0x72,
    2416             :   0x74, 0x70, 0x35, 0x2d, 0x64, 0x6d, 0x7a, 0x2d, 0x67,
    2417             :   0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
    2418             :   0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x18, 0x15,
    2419             :   0x6d, 0x74, 0x76, 0x35, 0x2d, 0x61, 0x70, 0x31, 0x30,
    2420             :   0x2d, 0x64, 0x63, 0x7a, 0x30, 0x36, 0x6e, 0x2d, 0x67,
    2421             :   0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
    2422             :   0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x1b, 0x18,
    2423             :   0x73, 0x6e, 0x67, 0x64, 0x63, 0x30, 0x31, 0x2d, 0x61,
    2424             :   0x62, 0x30, 0x37, 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x31,
    2425             :   0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0,
    2426             :   0x26, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a,
    2427             :   0x00, 0x1a, 0x17, 0x61, 0x65, 0x72, 0x30, 0x31, 0x2d,
    2428             :   0x72, 0x34, 0x63, 0x32, 0x35, 0x2d, 0x64, 0x63, 0x7a,
    2429             :   0x30, 0x31, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0,
    2430             :   0x17, 0xc0, 0x26, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
    2431             :   0x00, 0x81, 0x00, 0x04, 0x48, 0xa3, 0x04, 0xa1, 0xc0,
    2432             :   0x26, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82,
    2433             :   0x00, 0x10, 0x20, 0x01, 0x04, 0x20, 0x12, 0x01, 0x00,
    2434             :   0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
    2435             :   0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
    2436             :   0x9a, 0x00, 0x02, 0xc0, 0xf4, 0xc0, 0x0c, 0x00, 0x02,
    2437             :   0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0,
    2438             :   0xcd, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00,
    2439             :   0x05, 0x9a, 0x00, 0x02, 0xc0, 0x8d, 0xc0, 0x0c, 0x00,
    2440             :   0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02,
    2441             :   0xc0, 0x43, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00,
    2442             :   0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0, 0xa9, 0xc0, 0x0c,
    2443             :   0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00,
    2444             :   0x02, 0xc0, 0x67, 0xc0, 0x8d, 0x00, 0x01, 0x00, 0x01,
    2445             :   0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0x40, 0x66, 0xf6,
    2446             :   0x05, 0xc0, 0xa9, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
    2447             :   0x07, 0x08, 0x00, 0x04, 0xad, 0x24, 0xe0, 0x64, 0xc0,
    2448             :   0x43, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08,
    2449             :   0x00, 0x04, 0x48, 0xa3, 0x04, 0x1c, 0xc0, 0xf4, 0x00,
    2450             :   0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04,
    2451             :   0xad, 0x26, 0xd4, 0x6c, 0xc0, 0x67, 0x00, 0x01, 0x00,
    2452             :   0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x25,
    2453             :   0x90, 0x64, 0xc0, 0xcd, 0x00, 0x01, 0x00, 0x01, 0x00,
    2454             :   0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x27, 0x70, 0x44,
    2455             : };
    2456             : 
    2457             : /* google.com */
    2458             : static u8 dns_reply_data_initializer[] =
    2459             :   { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
    2460             :   0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
    2461             :   0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
    2462             :   0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
    2463             :   0x2b,
    2464             :   0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
    2465             :   0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
    2466             :   0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
    2467             :   0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
    2468             :   0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
    2469             :   0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
    2470             :   0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
    2471             :   0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
    2472             :   0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
    2473             :   0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
    2474             :   0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
    2475             :   0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
    2476             :   0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
    2477             :   0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
    2478             :   0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
    2479             :   0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
    2480             :   0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
    2481             :   0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
    2482             :   0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
    2483             :   0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
    2484             :   0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
    2485             :   0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
    2486             :   0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
    2487             :   0x57,
    2488             :   0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
    2489             : };
    2490             : 
    2491             : #else
    2492             : /* www.weatherlink.com */
    2493             : static u8 dns_reply_data_initializer[] = {
    2494             :   0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
    2495             :   0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x0b,
    2496             :   0x77, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x6c, 0x69,
    2497             :   0x6e, 0x6b, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0xff,
    2498             :   0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00,
    2499             :   0x00, 0x0c, 0x9e, 0x00, 0x1f, 0x0e, 0x64, 0x33, 0x6b,
    2500             :   0x72, 0x30, 0x67, 0x75, 0x62, 0x61, 0x31, 0x64, 0x76,
    2501             :   0x77, 0x66, 0x0a, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x66,
    2502             :   0x72, 0x6f, 0x6e, 0x74, 0x03, 0x6e, 0x65, 0x74, 0x00,
    2503             : };
    2504             : 
    2505             : #endif
    2506             : 
    2507             : static clib_error_t *
    2508           0 : test_dns_fmt_command_fn (vlib_main_t * vm,
    2509             :                          unformat_input_t * input, vlib_cli_command_t * cmd)
    2510             : {
    2511           0 :   dns_resolve_name_t _rn, *rn = &_rn;
    2512           0 :   u8 *dns_reply_data = 0;
    2513           0 :   int verbose = 0;
    2514             :   int rv;
    2515           0 :   vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
    2516             : 
    2517           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    2518             :     {
    2519           0 :       if (unformat (input, "verbose %d", &verbose))
    2520             :         ;
    2521           0 :       else if (unformat (input, "verbose"))
    2522           0 :         verbose = 1;
    2523             :       else
    2524           0 :         return clib_error_return (0, "unknown input `%U'",
    2525             :                                   format_unformat_error, input);
    2526             :     }
    2527             : 
    2528           0 :   vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
    2529             : 
    2530           0 :   memcpy (dns_reply_data, dns_reply_data_initializer,
    2531             :           ARRAY_LEN (dns_reply_data_initializer));
    2532             : 
    2533           0 :   vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
    2534             : 
    2535           0 :   clib_memset (rmp, 0, sizeof (*rmp));
    2536             : 
    2537           0 :   rv = vnet_dns_response_to_reply (dns_reply_data, rn, 0 /* ttl-ptr */);
    2538             : 
    2539           0 :   switch (rv)
    2540             :     {
    2541           0 :     case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
    2542           0 :       vlib_cli_output (vm, "no addresses found...");
    2543           0 :       break;
    2544             : 
    2545           0 :     default:
    2546           0 :       vlib_cli_output (vm, "response to reply returned %d", rv);
    2547           0 :       break;
    2548             : 
    2549           0 :     case 0:
    2550           0 :       vlib_cli_output (vm, "ip address: %U", format_ip_address, &rn->address);
    2551           0 :       break;
    2552             :     }
    2553             : 
    2554           0 :   vec_free (dns_reply_data);
    2555             : 
    2556           0 :   return 0;
    2557             : }
    2558             : 
    2559             : 
    2560             : /* *INDENT-OFF* */
    2561      220807 : VLIB_CLI_COMMAND (test_dns_fmt_command) =
    2562             : {
    2563             :   .path = "test dns format",
    2564             :   .short_help = "test dns format",
    2565             :   .function = test_dns_fmt_command_fn,
    2566             : };
    2567             : /* *INDENT-ON* */
    2568             : 
    2569             : static clib_error_t *
    2570           0 : test_dns_unfmt_command_fn (vlib_main_t * vm,
    2571             :                            unformat_input_t * input, vlib_cli_command_t * cmd)
    2572             : {
    2573           0 :   u8 *dns_reply_data = 0;
    2574           0 :   int verbose = 0;
    2575           0 :   int reply_set = 0;
    2576             : 
    2577           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    2578             :     {
    2579           0 :       if (unformat (input, "verbose %d", &verbose))
    2580             :         ;
    2581           0 :       else if (unformat (input, "verbose"))
    2582           0 :         verbose = 1;
    2583           0 :       else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
    2584           0 :         reply_set = 1;
    2585             :       else
    2586           0 :         return clib_error_return (0, "unknown input `%U'",
    2587             :                                   format_unformat_error, input);
    2588             :     }
    2589             : 
    2590           0 :   if (reply_set == 0)
    2591           0 :     return clib_error_return (0, "dns data not set...");
    2592             : 
    2593           0 :   vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
    2594             : 
    2595           0 :   vec_free (dns_reply_data);
    2596             : 
    2597           0 :   return 0;
    2598             : }
    2599             : 
    2600             : /* *INDENT-OFF* */
    2601      220807 : VLIB_CLI_COMMAND (test_dns_unfmt_command) =
    2602             : {
    2603             :   .path = "test dns unformat",
    2604             :   .short_help = "test dns unformat <name> [ip4][ip6]",
    2605             :   .function = test_dns_unfmt_command_fn,
    2606             : };
    2607             : /* *INDENT-ON* */
    2608             : 
    2609             : static clib_error_t *
    2610           0 : test_dns_expire_command_fn (vlib_main_t * vm,
    2611             :                             unformat_input_t * input,
    2612             :                             vlib_cli_command_t * cmd)
    2613             : {
    2614           0 :   dns_main_t *dm = &dns_main;
    2615           0 :   u8 *name = 0;
    2616             :   uword *p;
    2617             :   clib_error_t *e;
    2618             :   dns_cache_entry_t *ep;
    2619             : 
    2620           0 :   if (unformat (input, "%v", &name))
    2621           0 :     dns_terminate_c_string (&name);
    2622             :   else
    2623           0 :     return clib_error_return (0, "no name provided");
    2624             : 
    2625           0 :   dns_cache_lock (dm, 7);
    2626             : 
    2627           0 :   p = hash_get_mem (dm->cache_entry_by_name, name);
    2628           0 :   if (!p)
    2629             :     {
    2630           0 :       dns_cache_unlock (dm);
    2631           0 :       e = clib_error_return (0, "%s is not in the cache...", name);
    2632           0 :       vec_free (name);
    2633           0 :       return e;
    2634             :     }
    2635             : 
    2636           0 :   ep = pool_elt_at_index (dm->entries, p[0]);
    2637             : 
    2638           0 :   ep->expiration_time = 0;
    2639             : 
    2640           0 :   return 0;
    2641             : }
    2642             : 
    2643             : /* *INDENT-OFF* */
    2644      220807 : VLIB_CLI_COMMAND (test_dns_expire_command) =
    2645             : {
    2646             :   .path = "test dns expire",
    2647             :   .short_help = "test dns expire <name>",
    2648             :   .function = test_dns_expire_command_fn,
    2649             : };
    2650             : /* *INDENT-ON* */
    2651             : #endif
    2652             : 
    2653             : void
    2654           0 : vnet_send_dns6_reply (vlib_main_t * vm, dns_main_t * dm,
    2655             :                       dns_pending_request_t * pr, dns_cache_entry_t * ep,
    2656             :                       vlib_buffer_t * b0)
    2657             : {
    2658           0 :   clib_warning ("Unimplemented...");
    2659           0 : }
    2660             : 
    2661             : 
    2662             : void
    2663           1 : vnet_send_dns4_reply (vlib_main_t * vm, dns_main_t * dm,
    2664             :                       dns_pending_request_t * pr, dns_cache_entry_t * ep,
    2665             :                       vlib_buffer_t * b0)
    2666             : {
    2667           1 :   u32 bi = 0;
    2668             :   ip4_address_t src_address;
    2669             :   ip4_header_t *ip;
    2670             :   udp_header_t *udp;
    2671             :   dns_header_t *dh;
    2672             :   vlib_frame_t *f;
    2673             :   u32 *to_next;
    2674             :   u8 *dns_response;
    2675             :   u8 *reply;
    2676             :   /* vl_api_dns_resolve_name_reply_t _rnr, *rnr = &_rnr; */
    2677           1 :   dns_resolve_name_t _rn, *rn = &_rn;
    2678           1 :   vl_api_dns_resolve_ip_reply_t _rir, *rir = &_rir;
    2679           1 :   u32 ttl = 64, tmp;
    2680             :   u32 qp_offset;
    2681             :   dns_query_t *qp;
    2682             :   dns_rr_t *rr;
    2683             :   u8 *rrptr;
    2684           1 :   int is_fail = 0;
    2685           1 :   int is_recycle = (b0 != 0);
    2686             : 
    2687           1 :   ASSERT (ep && ep->dns_response);
    2688             : 
    2689           1 :   if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
    2690             :     {
    2691             :       /* Quick and dirty way to dig up the A-record address. $$ FIXME */
    2692           1 :       clib_memset (rn, 0, sizeof (*rn));
    2693           1 :       if (vnet_dns_response_to_reply (ep->dns_response, rn, &ttl))
    2694             :         {
    2695             :           /* clib_warning ("response_to_reply failed..."); */
    2696           0 :           is_fail = 1;
    2697             :         }
    2698           1 :       else if (ip_addr_version (&rn->address) != AF_IP4)
    2699             :         {
    2700             :           /* clib_warning ("No A-record..."); */
    2701           0 :           is_fail = 1;
    2702             :         }
    2703             :     }
    2704           0 :   else if (pr->request_type == DNS_PEER_PENDING_IP_TO_NAME)
    2705             :     {
    2706           0 :       clib_memset (rir, 0, sizeof (*rir));
    2707           0 :       if (vnet_dns_response_to_name (ep->dns_response, rir, &ttl))
    2708             :         {
    2709             :           /* clib_warning ("response_to_name failed..."); */
    2710           0 :           is_fail = 1;
    2711             :         }
    2712             :     }
    2713             :   else
    2714             :     {
    2715           0 :       clib_warning ("Unknown request type %d", pr->request_type);
    2716           0 :       return;
    2717             :     }
    2718             : 
    2719             :   /* Initialize a buffer */
    2720           1 :   if (b0 == 0)
    2721             :     {
    2722           0 :       if (vlib_buffer_alloc (vm, &bi, 1) != 1)
    2723           0 :         return;
    2724           0 :       b0 = vlib_get_buffer (vm, bi);
    2725             :     }
    2726             :   else
    2727             :     {
    2728             :       /* Use the buffer we were handed. Reinitialize it... */
    2729           1 :       vlib_buffer_t bt = { };
    2730             :       /* push/pop the reference count */
    2731           1 :       u8 save_ref_count = b0->ref_count;
    2732           1 :       vlib_buffer_copy_template (b0, &bt);
    2733           1 :       b0->ref_count = save_ref_count;
    2734           1 :       bi = vlib_get_buffer_index (vm, b0);
    2735             :     }
    2736             : 
    2737           1 :   if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
    2738           0 :     vlib_buffer_free_one (vm, b0->next_buffer);
    2739             : 
    2740             :   /*
    2741             :    * Reset the buffer. We recycle the DNS request packet in the cache
    2742             :    * hit case, and reply immediately from the request node.
    2743             :    *
    2744             :    * In the resolution-required / deferred case, resetting a freshly-allocated
    2745             :    * buffer won't hurt. We hope.
    2746             :    */
    2747           1 :   b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
    2748             :                 | VLIB_BUFFER_TOTAL_LENGTH_VALID);
    2749           1 :   vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;        /* "local0" */
    2750           1 :   vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0;        /* default VRF for now */
    2751             : 
    2752           1 :   if (!ip4_sas (0 /* default VRF for now */, ~0,
    2753           1 :                 (const ip4_address_t *) &pr->dst_address, &src_address))
    2754           0 :     return;
    2755             : 
    2756           1 :   ip = vlib_buffer_get_current (b0);
    2757           1 :   udp = (udp_header_t *) (ip + 1);
    2758           1 :   dns_response = (u8 *) (udp + 1);
    2759           1 :   clib_memset (ip, 0, sizeof (*ip) + sizeof (*udp));
    2760             : 
    2761             :   /*
    2762             :    * Start with the variadic portion of the exercise.
    2763             :    * Turn the name into a set of DNS "labels". Max length
    2764             :    * per label is 63, enforce that.
    2765             :    */
    2766           1 :   reply = name_to_labels (pr->name);
    2767           1 :   vec_free (pr->name);
    2768             : 
    2769           1 :   qp_offset = vec_len (reply);
    2770             : 
    2771             :   /* Add space for the query header */
    2772           1 :   vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
    2773             : 
    2774           1 :   qp = (dns_query_t *) (reply + qp_offset);
    2775             : 
    2776           1 :   if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
    2777           1 :     qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
    2778             :   else
    2779           0 :     qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
    2780             : 
    2781           1 :   qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
    2782             : 
    2783             :   /* Punch in space for the dns_header_t */
    2784           1 :   vec_insert (reply, sizeof (dns_header_t), 0);
    2785             : 
    2786           1 :   dh = (dns_header_t *) reply;
    2787             : 
    2788             :   /* Transaction ID = pool index */
    2789           1 :   dh->id = pr->id;
    2790             : 
    2791             :   /* Announce that we did a recursive lookup */
    2792           1 :   tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
    2793           1 :   if (is_fail)
    2794           0 :     tmp |= DNS_RCODE_NAME_ERROR;
    2795           1 :   dh->flags = clib_host_to_net_u16 (tmp);
    2796           1 :   dh->qdcount = clib_host_to_net_u16 (1);
    2797           1 :   dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
    2798           1 :   dh->nscount = 0;
    2799           1 :   dh->arcount = 0;
    2800             : 
    2801             :   /* If the name resolution worked, cough up an appropriate RR */
    2802           1 :   if (is_fail == 0)
    2803             :     {
    2804             :       /* Add the answer. First, a name pointer (0xC00C) */
    2805           1 :       vec_add1 (reply, 0xC0);
    2806           1 :       vec_add1 (reply, 0x0C);
    2807             : 
    2808             :       /* Now, add single A-rec RR */
    2809           1 :       if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
    2810             :         {
    2811           1 :           vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
    2812           1 :           rr = (dns_rr_t *) rrptr;
    2813             : 
    2814           1 :           rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
    2815           1 :           rr->class = clib_host_to_net_u16 (1 /* internet */ );
    2816           1 :           rr->ttl = clib_host_to_net_u32 (ttl);
    2817           1 :           rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
    2818           1 :           ip_address_copy_addr (rr->rdata, &rn->address);
    2819             :         }
    2820             :       else
    2821             :         {
    2822             :           /* Or a single PTR RR */
    2823           0 :           u8 *vecname = format (0, "%s", rir->name);
    2824           0 :           u8 *label_vec = name_to_labels (vecname);
    2825           0 :           vec_free (vecname);
    2826             : 
    2827           0 :           vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
    2828           0 :           rr = (dns_rr_t *) rrptr;
    2829           0 :           rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
    2830           0 :           rr->class = clib_host_to_net_u16 (1 /* internet */ );
    2831           0 :           rr->ttl = clib_host_to_net_u32 (ttl);
    2832           0 :           rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
    2833           0 :           clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
    2834           0 :           vec_free (label_vec);
    2835             :         }
    2836             :     }
    2837           1 :   clib_memcpy (dns_response, reply, vec_len (reply));
    2838             : 
    2839             :   /* Set the packet length */
    2840           1 :   b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
    2841             : 
    2842             :   /* IP header */
    2843           1 :   ip->ip_version_and_header_length = 0x45;
    2844           1 :   ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
    2845           1 :   ip->ttl = 255;
    2846           1 :   ip->protocol = IP_PROTOCOL_UDP;
    2847           1 :   ip->src_address.as_u32 = src_address.as_u32;
    2848           1 :   clib_memcpy (ip->dst_address.as_u8, pr->dst_address,
    2849             :                sizeof (ip4_address_t));
    2850           1 :   ip->checksum = ip4_header_checksum (ip);
    2851             : 
    2852             :   /* UDP header */
    2853           1 :   udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
    2854           1 :   udp->dst_port = pr->dst_port;
    2855           1 :   udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
    2856           1 :                                       vec_len (reply));
    2857           1 :   udp->checksum = 0;
    2858           1 :   vec_free (reply);
    2859             : 
    2860             :   /*
    2861             :    * Ship pkts made out of whole cloth to ip4_lookup
    2862             :    * Caller will ship recycled dns reply packets to ip4_lookup
    2863             :    */
    2864           1 :   if (is_recycle == 0)
    2865             :     {
    2866           0 :       f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
    2867           0 :       to_next = vlib_frame_vector_args (f);
    2868           0 :       to_next[0] = bi;
    2869           0 :       f->n_vectors = 1;
    2870           0 :       vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
    2871             :     }
    2872             : }
    2873             : 
    2874             : #include <dns/dns.api.c>
    2875             : static clib_error_t *
    2876         559 : dns_init (vlib_main_t * vm)
    2877             : {
    2878         559 :   dns_main_t *dm = &dns_main;
    2879             : 
    2880         559 :   dm->vnet_main = vnet_get_main ();
    2881         559 :   dm->name_cache_size = 1000;
    2882         559 :   dm->max_ttl_in_seconds = 86400;
    2883         559 :   dm->random_seed = 0xDEADDABE;
    2884         559 :   dm->api_main = vlibapi_get_main ();
    2885             : 
    2886             :   /* Ask for a correctly-sized block of API message decode slots */
    2887         559 :   dm->msg_id_base = setup_message_id_table ();
    2888             : 
    2889         559 :   return 0;
    2890             : }
    2891             : 
    2892             : /* *INDENT-OFF* */
    2893        1119 : VLIB_INIT_FUNCTION (dns_init) = {
    2894             :   .init_order = VLIB_INITS ("flow_classify_init", "dns_init"),
    2895             : };
    2896             : 
    2897             : VLIB_PLUGIN_REGISTER () =
    2898             : {
    2899             :   .version = VPP_BUILD_VER,
    2900             :   .description = "Simple DNS name resolver",
    2901             : };
    2902             : /* *INDENT-ON* */
    2903             : 
    2904             : 
    2905             : /*
    2906             :  * fd.io coding-style-patch-verification: ON
    2907             :  *
    2908             :  * Local Variables:
    2909             :  * eval: (c-set-style "gnu")
    2910             :  * End:
    2911             :  */

Generated by: LCOV version 1.14