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