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