FD.io VPP  v21.01.1
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)
213  rv = dns6_name_server_add_del (dm, mp->server_address, mp->is_add);
214  else
215  rv = dns4_name_server_add_del (dm, mp->server_address, mp->is_add);
216 
217  REPLY_MACRO (VL_API_DNS_NAME_SERVER_ADD_DEL_REPLY);
218 }
219 
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 
265  sw_if_index = fib_entry_get_resolving_interface (fei);
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  ({
279  src_address = ip_interface_address_get_address (lm4, ia);
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 
302  ip = vlib_buffer_get_current (b);
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 */
329  f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
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 
382  sw_if_index = fib_entry_get_resolving_interface (fei);
383 
384  /* *INDENT-OFF* */
385  foreach_ip_interface_address(lm6, ia, sw_if_index, 1 /* honor unnumbered */,
386  ({
387  src_address = ip_interface_address_get_address (lm6, ia);
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 
408  ip = vlib_buffer_get_current (b);
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 */
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;
433  udp->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ip, &junk);
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 */
439  f = vlib_get_frame_to_node (vm, ip6_lookup_node.index);
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 */
593  tmp = DNS_RD | DNS_OPCODE_QUERY;
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);
705  p = hash_get_mem (dm->cache_entry_by_name, name);
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);
776  p = hash_get_mem (dm->cache_entry_by_name, name);
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:
831  p = hash_get_mem (dm->cache_entry_by_name, name);
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;
949  clib_memcpy (pr->dst_address, t->dst_address, count);
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;
1057  flags |= DNS_RCODE_NAME_ERROR;
1058  h->flags = clib_host_to_net_u16 (flags);
1059  return -1;
1060  }
1061 
1062  /* This is a CNAME record, chase the name chain. */
1063  pos = cname_pos;
1064 
1065  /* The last request is no longer pending.. */
1066  for (i = 0; i < vec_len (dm->unresolved_entries); i++)
1067  if (ep_index == dm->unresolved_entries[i])
1068  {
1069  vec_delete (dm->unresolved_entries, 1, i);
1070  goto found_last_request;
1071  }
1072  clib_warning ("pool elt %d supposedly pending, but not found...", ep_index);
1073  return -1;
1074 
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
1164  u32 * min_ttlp)
1165 {
1166  dns_header_t *h;
1167  dns_query_t *qp;
1168  dns_rr_t *rr;
1169  int i, limit;
1170  u8 len;
1171  u8 *curpos, *pos, *pos2;
1172  u16 flags;
1173  u16 rcode;
1174  u32 ttl;
1175  int pointer_chase;
1176 
1177  h = (dns_header_t *) response;
1178  flags = clib_net_to_host_u16 (h->flags);
1179  rcode = flags & DNS_RCODE_MASK;
1180 
1181  /* See if the response is OK, etc. */
1182  switch (rcode)
1183  {
1184  default:
1185  case DNS_RCODE_NO_ERROR:
1186  break;
1187 
1188  case DNS_RCODE_NAME_ERROR:
1190  return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1191 
1194  case DNS_RCODE_REFUSED:
1195  return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1196  }
1197 
1198  /* No answers? Loser... */
1199  if (clib_net_to_host_u16 (h->anscount) < 1)
1200  return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1201 
1202  curpos = (u8 *) (h + 1);
1203 
1204  /* Skip the name we asked about */
1205  pos = curpos;
1206  len = *pos++;
1207  /* Should never happen, but stil... */
1208  if ((len & 0xC0) == 0xC0)
1209  curpos += 2;
1210  else
1211  {
1212  /* skip the name / label-set */
1213  while (len)
1214  {
1215  pos += len;
1216  len = *pos++;
1217  }
1218  curpos = pos;
1219  }
1220  /* Skip queries */
1221  limit = clib_net_to_host_u16 (h->qdcount);
1222  qp = (dns_query_t *) curpos;
1223  qp += limit;
1224  curpos = (u8 *) qp;
1225 
1226  /* Parse answers */
1227  limit = clib_net_to_host_u16 (h->anscount);
1228 
1229  for (i = 0; i < limit; i++)
1230  {
1231  pos = pos2 = curpos;
1232  pointer_chase = 0;
1233 
1234  /* Expect pointer chases in the answer section... */
1235  if ((pos2[0] & 0xC0) == 0xC0)
1236  {
1237  pos = pos2 + 2;
1238  pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1239  pointer_chase = 1;
1240  }
1241 
1242  len = *pos2++;
1243 
1244  while (len)
1245  {
1246  pos2 += len;
1247  if ((pos2[0] & 0xc0) == 0xc0)
1248  {
1249  /*
1250  * If we've already done one pointer chase,
1251  * do not move the pos pointer.
1252  */
1253  if (pointer_chase == 0)
1254  pos = pos2 + 2;
1255  pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1256  len = *pos2++;
1257  pointer_chase = 1;
1258  }
1259  else
1260  len = *pos2++;
1261  }
1262 
1263  if (pointer_chase == 0)
1264  pos = pos2;
1265 
1266  rr = (dns_rr_t *) pos;
1267 
1268  switch (clib_net_to_host_u16 (rr->type))
1269  {
1270  case DNS_TYPE_A:
1271  /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1272  memcpy (rmp->ip4_address, rr->rdata, sizeof (ip4_address_t));
1273  rmp->ip4_set = 1;
1274  ttl = clib_net_to_host_u32 (rr->ttl);
1275  if (min_ttlp && *min_ttlp > ttl)
1276  *min_ttlp = ttl;
1277  break;
1278  case DNS_TYPE_AAAA:
1279  /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1280  memcpy (rmp->ip6_address, rr->rdata, sizeof (ip6_address_t));
1281  ttl = clib_net_to_host_u32 (rr->ttl);
1282  if (min_ttlp && *min_ttlp > ttl)
1283  *min_ttlp = ttl;
1284  rmp->ip6_set = 1;
1285  break;
1286 
1287  default:
1288  break;
1289  }
1290  /* Might as well stop ASAP */
1291  if (rmp->ip4_set && rmp->ip6_set)
1292  break;
1293  pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1294  curpos = pos;
1295  }
1296 
1297  if ((rmp->ip4_set + rmp->ip6_set) == 0)
1298  return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1299  return 0;
1300 }
1301 
1302 int
1305  u32 * min_ttlp)
1306 {
1307  dns_header_t *h;
1308  dns_query_t *qp;
1309  dns_rr_t *rr;
1310  int i, limit;
1311  u8 len;
1312  u8 *curpos, *pos, *pos2;
1313  u16 flags;
1314  u16 rcode;
1315  u8 *name;
1316  u32 ttl;
1317  u8 *junk __attribute__ ((unused));
1318  int name_set = 0;
1319  int pointer_chase;
1320 
1321  h = (dns_header_t *) response;
1322  flags = clib_net_to_host_u16 (h->flags);
1323  rcode = flags & DNS_RCODE_MASK;
1324 
1325  /* See if the response is OK, etc. */
1326  switch (rcode)
1327  {
1328  default:
1329  case DNS_RCODE_NO_ERROR:
1330  break;
1331 
1332  case DNS_RCODE_NAME_ERROR:
1334  return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1335 
1338  case DNS_RCODE_REFUSED:
1339  return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1340  }
1341 
1342  /* No answers? Loser... */
1343  if (clib_net_to_host_u16 (h->anscount) < 1)
1344  return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1345 
1346  curpos = (u8 *) (h + 1);
1347 
1348  /* Skip the name we asked about */
1349  pos = curpos;
1350  len = *pos++;
1351  /* Should never happen, but stil... */
1352  if ((len & 0xC0) == 0xC0)
1353  curpos += 2;
1354  else
1355  {
1356  /* skip the name / label-set */
1357  while (len)
1358  {
1359  pos += len;
1360  len = *pos++;
1361  }
1362  curpos = pos;
1363  }
1364  /* Skip queries */
1365  limit = clib_net_to_host_u16 (h->qdcount);
1366  qp = (dns_query_t *) curpos;
1367  qp += limit;
1368  curpos = (u8 *) qp;
1369 
1370  /* Parse answers */
1371  limit = clib_net_to_host_u16 (h->anscount);
1372 
1373  for (i = 0; i < limit; i++)
1374  {
1375  pos = pos2 = curpos;
1376  pointer_chase = 0;
1377 
1378  /* Expect pointer chases in the answer section... */
1379  if ((pos2[0] & 0xC0) == 0xC0)
1380  {
1381  pos = pos2 + 2;
1382  pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1383  pointer_chase = 1;
1384  }
1385 
1386  len = *pos2++;
1387 
1388  while (len)
1389  {
1390  pos2 += len;
1391  if ((pos2[0] & 0xc0) == 0xc0)
1392  {
1393  /*
1394  * If we've already done one pointer chase,
1395  * do not move the pos pointer.
1396  */
1397  if (pointer_chase == 0)
1398  pos = pos2 + 2;
1399  pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1400  len = *pos2++;
1401  pointer_chase = 1;
1402  }
1403  else
1404  len = *pos2++;
1405  }
1406 
1407  if (pointer_chase == 0)
1408  pos = pos2;
1409 
1410  rr = (dns_rr_t *) pos;
1411 
1412  switch (clib_net_to_host_u16 (rr->type))
1413  {
1414  case DNS_TYPE_PTR:
1415  name = vnet_dns_labels_to_name (rr->rdata, response, &junk);
1416  memcpy (rmp->name, name, vec_len (name));
1417  ttl = clib_net_to_host_u32 (rr->ttl);
1418  if (min_ttlp)
1419  *min_ttlp = ttl;
1420  rmp->name[vec_len (name)] = 0;
1421  name_set = 1;
1422  break;
1423  default:
1424  break;
1425  }
1426  /* Might as well stop ASAP */
1427  if (name_set == 1)
1428  break;
1429  pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1430  curpos = pos;
1431  }
1432 
1433  if (name_set == 0)
1434  return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1435  return 0;
1436 }
1437 
1438 static void
1440 {
1442  dns_main_t *dm = &dns_main;
1444  dns_cache_entry_t *ep;
1445  dns_pending_request_t _t0, *t0 = &_t0;
1446  int rv;
1447 
1448  /* Sanitize the name slightly */
1449  mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1450 
1452  t0->client_index = mp->client_index;
1453  t0->client_context = mp->context;
1454 
1455  rv = vnet_dns_resolve_name (vm, dm, mp->name, t0, &ep);
1456 
1457  /* Error, e.g. not enabled? Tell the user */
1458  if (rv < 0)
1459  {
1460  REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1461  return;
1462  }
1463 
1464  /* Resolution pending? Don't reply... */
1465  if (ep == 0)
1466  return;
1467 
1468  /* *INDENT-OFF* */
1469  REPLY_MACRO2(VL_API_DNS_RESOLVE_NAME_REPLY,
1470  ({
1471  rv = vnet_dns_response_to_reply (ep->dns_response, rmp, 0 /* ttl-ptr */);
1472  rmp->retval = clib_host_to_net_u32 (rv);
1473  }));
1474  /* *INDENT-ON* */
1475 }
1476 
1477 static void
1479 {
1481  dns_main_t *dm = &dns_main;
1483  dns_cache_entry_t *ep;
1484  int rv;
1485  int i, len;
1486  u8 *lookup_name = 0;
1487  u8 digit, nybble;
1488  dns_pending_request_t _t0, *t0 = &_t0;
1489 
1490  if (mp->is_ip6)
1491  {
1492  for (i = 15; i >= 0; i--)
1493  {
1494  digit = mp->address[i];
1495  nybble = (digit & 0x0F);
1496  if (nybble > 9)
1497  vec_add1 (lookup_name, (nybble - 10) + 'a');
1498  else
1499  vec_add1 (lookup_name, nybble + '0');
1500  vec_add1 (lookup_name, '.');
1501  nybble = (digit & 0xF0) >> 4;
1502  if (nybble > 9)
1503  vec_add1 (lookup_name, (nybble - 10) + 'a');
1504  else
1505  vec_add1 (lookup_name, nybble + '0');
1506  vec_add1 (lookup_name, '.');
1507  }
1508  len = vec_len (lookup_name);
1509  vec_validate (lookup_name, len + 8);
1510  memcpy (lookup_name + len, "ip6.arpa", 8);
1511  }
1512  else
1513  {
1514  for (i = 3; i >= 0; i--)
1515  {
1516  digit = mp->address[i];
1517  lookup_name = format (lookup_name, "%d.", digit);
1518  }
1519  lookup_name = format (lookup_name, "in-addr.arpa");
1520  }
1521 
1522  vec_add1 (lookup_name, 0);
1523 
1525  t0->client_index = mp->client_index;
1526  t0->client_context = mp->context;
1527 
1528  rv = vnet_dns_resolve_name (vm, dm, lookup_name, t0, &ep);
1529 
1530  vec_free (lookup_name);
1531 
1532  /* Error, e.g. not enabled? Tell the user */
1533  if (rv < 0)
1534  {
1535  REPLY_MACRO (VL_API_DNS_RESOLVE_IP_REPLY);
1536  return;
1537  }
1538 
1539  /* Resolution pending? Don't reply... */
1540  if (ep == 0)
1541  return;
1542 
1543  /* *INDENT-OFF* */
1544  REPLY_MACRO2(VL_API_DNS_RESOLVE_IP_REPLY,
1545  ({
1546  rv = vnet_dns_response_to_name (ep->dns_response, rmp, 0 /* ttl-ptr */);
1547  rmp->retval = clib_host_to_net_u32 (rv);
1548  }));
1549  /* *INDENT-ON* */
1550 }
1551 
1552 static clib_error_t *
1554 {
1555  dns_main_t *dm = &dns_main;
1556 
1557  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1558  {
1559  if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1560  ;
1561  else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1562  ;
1563  else
1564  return clib_error_return (0, "unknown input `%U'",
1565  format_unformat_error, input);
1566  }
1567  return 0;
1568 }
1569 
1571 
1572 uword
1573 unformat_dns_reply (unformat_input_t * input, va_list * args)
1574 {
1575  u8 **result = va_arg (*args, u8 **);
1576  u8 **namep = va_arg (*args, u8 **);
1577  ip4_address_t a4;
1578  ip6_address_t a6;
1579  int a4_set = 0;
1580  int a6_set = 0;
1581  u8 *name;
1582  int name_set = 0;
1583  u8 *ce;
1584  u32 qp_offset;
1585  dns_header_t *h;
1586  dns_query_t *qp;
1587  dns_rr_t *rr;
1588  u8 *rru8;
1589 
1590  if (unformat (input, "%v", &name))
1591  name_set = 1;
1592 
1593  if (unformat (input, "%U", unformat_ip4_address, &a4))
1594  {
1595  a4_set = 1;
1596  if (unformat (input, "%U", unformat_ip6_address, &a6))
1597  a6_set = 1;
1598  }
1599 
1600  if (unformat (input, "%U", unformat_ip6_address, &a6))
1601  {
1602  a6_set = 1;
1603  if (unformat (input, "%U", unformat_ip4_address, &a6))
1604  a4_set = 1;
1605  }
1606 
1607  /* Must have a name */
1608  if (!name_set)
1609  return 0;
1610 
1611  /* Must have at least one address */
1612  if (!(a4_set + a6_set))
1613  return 0;
1614 
1615  /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1616  ce = name_to_labels (name);
1617  qp_offset = vec_len (ce);
1618 
1619  /* Add space for the query header */
1620  vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1621  qp = (dns_query_t *) (ce + qp_offset);
1622 
1623  qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1624  qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1625 
1626  /* Punch in space for the dns_header_t */
1627  vec_insert (ce, sizeof (dns_header_t), 0);
1628 
1629  h = (dns_header_t *) ce;
1630 
1631  /* Fake Transaction ID */
1632  h->id = 0xFFFF;
1633 
1634  h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1635  h->qdcount = clib_host_to_net_u16 (1);
1636  h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1637  h->nscount = 0;
1638  h->arcount = 0;
1639 
1640  /* Now append one or two A/AAAA RR's... */
1641  if (a4_set)
1642  {
1643  /* Pointer to the name (DGMS) */
1644  vec_add1 (ce, 0xC0);
1645  vec_add1 (ce, 0x0C);
1646  vec_add2 (ce, rru8, sizeof (*rr) + 4);
1647  rr = (void *) rru8;
1648  rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1649  rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1650  rr->ttl = clib_host_to_net_u32 (86400);
1651  rr->rdlength = clib_host_to_net_u16 (4);
1652  memcpy (rr->rdata, &a4, sizeof (a4));
1653  }
1654  if (a6_set)
1655  {
1656  /* Pointer to the name (DGMS) */
1657  vec_add1 (ce, 0xC0);
1658  vec_add1 (ce, 0x0C);
1659  vec_add2 (ce, rru8, sizeof (*rr) + 16);
1660  rr = (void *) rru8;
1661  rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1662  rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1663  rr->ttl = clib_host_to_net_u32 (86400);
1664  rr->rdlength = clib_host_to_net_u16 (16);
1665  memcpy (rr->rdata, &a6, sizeof (a6));
1666  }
1667  *result = ce;
1668  if (namep)
1669  *namep = name;
1670  else
1671  vec_free (name);
1672 
1673  return 1;
1674 }
1675 
1676 u8 *
1677 format_dns_query (u8 * s, va_list * args)
1678 {
1679  u8 **curpos = va_arg (*args, u8 **);
1680  int verbose = va_arg (*args, int);
1681  u8 *pos;
1682  dns_query_t *qp;
1683  int len, i;
1684  if (verbose > 1)
1685  s = format (s, " Name: ");
1686 
1687  /* Unwind execrated counted-label sheit */
1688  pos = *curpos;
1689  len = *pos++;
1690 
1691  while (len)
1692  {
1693  for (i = 0; i < len; i++)
1694  vec_add1 (s, *pos++);
1695 
1696  len = *pos++;
1697  if (len)
1698  vec_add1 (s, '.');
1699  else
1700  {
1701  vec_add1 (s, ':');
1702  vec_add1 (s, ' ');
1703  }
1704  }
1705 
1706  qp = (dns_query_t *) pos;
1707  if (verbose > 1)
1708  {
1709  switch (clib_net_to_host_u16 (qp->type))
1710  {
1711  case DNS_TYPE_A:
1712  s = format (s, "type A\n");
1713  break;
1714  case DNS_TYPE_AAAA:
1715  s = format (s, "type AAAA\n");
1716  break;
1717  case DNS_TYPE_ALL:
1718  s = format (s, "type ALL\n");
1719  break;
1720 
1721  default:
1722  s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1723  break;
1724  }
1725  }
1726 
1727  pos += sizeof (*qp);
1728 
1729  *curpos = pos;
1730  return s;
1731 }
1732 
1733 /**
1734  * format dns reply data
1735  * verbose > 1, dump everything
1736  * verbose == 1, dump all A and AAAA records
1737  * verbose == 0, dump one A record, and one AAAA record
1738  */
1739 
1740 u8 *
1741 format_dns_reply_data (u8 * s, va_list * args)
1742 {
1743  u8 *reply = va_arg (*args, u8 *);
1744  u8 **curpos = va_arg (*args, u8 **);
1745  int verbose = va_arg (*args, int);
1746  int *print_ip4 = va_arg (*args, int *);
1747  int *print_ip6 = va_arg (*args, int *);
1748  int len;
1749  u8 *pos, *pos2;
1750  dns_rr_t *rr;
1751  int i;
1752  int pointer_chase = 0;
1753  u16 *tp;
1754  u16 rrtype_host_byte_order;
1755 
1756  pos = pos2 = *curpos;
1757 
1758  if (verbose > 1)
1759  s = format (s, " ");
1760 
1761  /* chase pointer? almost always yes here... */
1762  if ((pos2[0] & 0xc0) == 0xc0)
1763  {
1764  pos = pos2 + 2;
1765  pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1766  pointer_chase = 1;
1767  }
1768 
1769  len = *pos2++;
1770 
1771  while (len)
1772  {
1773  for (i = 0; i < len; i++)
1774  {
1775  if (verbose > 1)
1776  vec_add1 (s, *pos2);
1777  pos2++;
1778  }
1779  if ((pos2[0] & 0xc0) == 0xc0)
1780  {
1781  /*
1782  * If we've already done one pointer chase,
1783  * do not move the pos pointer.
1784  */
1785  if (pointer_chase == 0)
1786  pos = pos2 + 2;
1787  pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1788  len = *pos2++;
1789  pointer_chase = 1;
1790  }
1791  else
1792  len = *pos2++;
1793  if (len)
1794  {
1795  if (verbose > 1)
1796  vec_add1 (s, '.');
1797  }
1798  else
1799  {
1800  if (verbose > 1)
1801  vec_add1 (s, ' ');
1802  }
1803  }
1804 
1805  if (pointer_chase == 0)
1806  pos = pos2;
1807 
1808  rr = (dns_rr_t *) pos;
1809  rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
1810 
1811  switch (rrtype_host_byte_order)
1812  {
1813  case DNS_TYPE_A:
1814  if (verbose > 1)
1815  {
1816  s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1817  format_ip4_address, rr->rdata);
1818  }
1819  else
1820  {
1821  if (*print_ip4)
1822  s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1823  clib_net_to_host_u32 (rr->ttl));
1824  if (verbose == 0)
1825  *print_ip4 = 0;
1826 
1827  }
1828  pos += sizeof (*rr) + 4;
1829  break;
1830 
1831  case DNS_TYPE_AAAA:
1832  if (verbose > 1)
1833  {
1834  s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1835  format_ip6_address, rr->rdata);
1836  }
1837  else
1838  {
1839  if (*print_ip6)
1840  s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1841  clib_net_to_host_u32 (rr->ttl));
1842  if (verbose == 0)
1843  *print_ip6 = 0;
1844  }
1845  pos += sizeof (*rr) + 16;
1846  break;
1847 
1848  case DNS_TYPE_TEXT:
1849  if (verbose > 1)
1850  {
1851  s = format (s, "TEXT: ");
1852  for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1853  vec_add1 (s, rr->rdata[i]);
1854  vec_add1 (s, '\n');
1855  }
1856  pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1857  break;
1858 
1859  case DNS_TYPE_HINFO:
1860  {
1861  /* Two counted strings. DGMS */
1862  u8 *len;
1863  u8 *curpos;
1864  int i;
1865  if (verbose > 1)
1866  {
1867  s = format (s, "HINFO: ");
1868  len = rr->rdata;
1869  curpos = len + 1;
1870  for (i = 0; i < *len; i++)
1871  vec_add1 (s, *curpos++);
1872 
1873  vec_add1 (s, ' ');
1874  len = curpos++;
1875  for (i = 0; i < *len; i++)
1876  vec_add1 (s, *curpos++);
1877 
1878  vec_add1 (s, '\n');
1879  }
1880  }
1881  pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1882  break;
1883 
1884  case DNS_TYPE_NAMESERVER:
1885  if (verbose > 1)
1886  {
1887  s = format (s, "Nameserver: ");
1888  pos2 = rr->rdata;
1889 
1890  /* chase pointer? */
1891  if ((pos2[0] & 0xc0) == 0xc0)
1892  {
1893  pos = pos2 + 2;
1894  pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1895  }
1896 
1897  len = *pos2++;
1898 
1899  while (len)
1900  {
1901  for (i = 0; i < len; i++)
1902  vec_add1 (s, *pos2++);
1903 
1904  /* chase pointer, typically to offset 12... */
1905  if (pos2[0] == 0xC0)
1906  pos2 = reply + pos2[1];
1907 
1908  len = *pos2++;
1909  if (len)
1910  vec_add1 (s, '.');
1911  else
1912  vec_add1 (s, '\n');
1913  }
1914  }
1915  pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1916  break;
1917 
1918  case DNS_TYPE_MAIL_EXCHANGE:
1919  if (verbose > 1)
1920  {
1921  tp = (u16 *) rr->rdata;
1922 
1923  s = format (s, "Mail Exchange: Preference %d ", (u32)
1924  clib_net_to_host_u16 (*tp));
1925 
1926  pos2 = rr->rdata + 2;
1927 
1928  /* chase pointer? */
1929  if (pos2[0] == 0xc0)
1930  pos2 = reply + pos2[1];
1931 
1932  len = *pos2++;
1933 
1934  while (len)
1935  {
1936  for (i = 0; i < len; i++)
1937  vec_add1 (s, *pos2++);
1938 
1939  /* chase pointer */
1940  if (pos2[0] == 0xC0)
1941  pos2 = reply + pos2[1];
1942 
1943  len = *pos2++;
1944  if (len)
1945  vec_add1 (s, '.');
1946  else
1947  vec_add1 (s, '\n');
1948  }
1949  }
1950 
1951  pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1952  break;
1953 
1954  case DNS_TYPE_PTR:
1955  case DNS_TYPE_CNAME:
1956  if (verbose > 1)
1957  {
1958  tp = (u16 *) rr->rdata;
1959 
1960  if (rrtype_host_byte_order == DNS_TYPE_CNAME)
1961  s = format (s, "CNAME: ");
1962  else
1963  s = format (s, "PTR: ");
1964 
1965  pos2 = rr->rdata;
1966 
1967  /* chase pointer? */
1968  if (pos2[0] == 0xc0)
1969  pos2 = reply + pos2[1];
1970 
1971  len = *pos2++;
1972 
1973  while (len)
1974  {
1975  for (i = 0; i < len; i++)
1976  vec_add1 (s, *pos2++);
1977 
1978  /* chase pointer */
1979  if (pos2[0] == 0xC0)
1980  pos2 = reply + pos2[1];
1981 
1982  len = *pos2++;
1983  if (len)
1984  vec_add1 (s, '.');
1985  else
1986  vec_add1 (s, '\n');
1987  }
1988  }
1989  pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1990  break;
1991 
1992  default:
1993  if (verbose > 1)
1994  s = format (s, "type %d: len %d\n",
1995  (int) clib_net_to_host_u16 (rr->type),
1996  sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
1997  pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1998  break;
1999  }
2000 
2001  *curpos = pos;
2002 
2003  return s;
2004 }
2005 
2006 u8 *
2007 format_dns_reply (u8 * s, va_list * args)
2008 {
2009  u8 *reply_as_u8 = va_arg (*args, u8 *);
2010  int verbose = va_arg (*args, int);
2011  dns_header_t *h;
2012  u16 id, flags;
2013  u8 *curpos;
2014  int i;
2015  int print_ip4 = 1;
2016  int print_ip6 = 1;
2017 
2018  h = (dns_header_t *) reply_as_u8;
2019  id = clib_net_to_host_u16 (h->id);
2020  flags = clib_net_to_host_u16 (h->flags);
2021 
2022  if (verbose > 1)
2023  {
2024  s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
2025  id);
2026  s = format (s, " %s %s %s %s\n",
2027  (flags & DNS_RA) ? "recur" : "no-recur",
2028  (flags & DNS_RD) ? "recur-des" : "no-recur-des",
2029  (flags & DNS_TC) ? "trunc" : "no-trunc",
2030  (flags & DNS_AA) ? "auth" : "non-auth");
2031  s = format (s, " %d queries, %d answers, %d name-servers,"
2032  " %d add'l recs\n",
2033  clib_net_to_host_u16 (h->qdcount),
2034  clib_net_to_host_u16 (h->anscount),
2035  clib_net_to_host_u16 (h->nscount),
2036  clib_net_to_host_u16 (h->arcount));
2037  }
2038 
2039  curpos = (u8 *) (h + 1);
2040 
2041  if (h->qdcount)
2042  {
2043  if (verbose > 1)
2044  s = format (s, " Queries:\n");
2045  for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
2046  {
2047  /* The query is variable-length, so curpos is a value-result parm */
2048  s = format (s, "%U", format_dns_query, &curpos, verbose);
2049  }
2050  }
2051  if (h->anscount)
2052  {
2053  if (verbose > 1)
2054  s = format (s, " Replies:\n");
2055 
2056  for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
2057  {
2058  /* curpos is a value-result parm */
2059  s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
2060  verbose, &print_ip4, &print_ip6);
2061  }
2062  }
2063  return s;
2064 }
2065 
2066 u8 *
2067 format_dns_cache (u8 * s, va_list * args)
2068 {
2069  dns_main_t *dm = va_arg (*args, dns_main_t *);
2070  f64 now = va_arg (*args, f64);
2071  int verbose = va_arg (*args, int);
2072  u8 *name = va_arg (*args, u8 *);
2073  dns_cache_entry_t *ep;
2074  char *ss;
2075  uword *p;
2076 
2077  if (dm->is_enabled == 0)
2078  {
2079  s = format (s, "The DNS cache is disabled...");
2080  return s;
2081  }
2082 
2083  if (pool_elts (dm->entries) == 0)
2084  {
2085  s = format (s, "The DNS cache is empty...");
2086  return s;
2087  }
2088 
2089  dns_cache_lock (dm, 6);
2090 
2091  if (name)
2092  {
2093  p = hash_get_mem (dm->cache_entry_by_name, name);
2094  if (!p)
2095  {
2096  s = format (s, "%s is not in the cache...", name);
2097  dns_cache_unlock (dm);
2098  return (s);
2099  }
2100 
2101  ep = pool_elt_at_index (dm->entries, p[0]);
2102  /* Magic to spit out a C-initializer to research hemorrhoids... */
2103  if (verbose == 3)
2104  {
2105  int i, j;
2106  s = format (s, "static u8 dns_reply_data_initializer[] =\n");
2107  s = format (s, "{\n");
2108  j = 0;
2109  for (i = 0; i < vec_len (ep->dns_response); i++)
2110  {
2111  if (j++ == 8)
2112  {
2113  j = 0;
2114  vec_add1 (s, '\n');
2115  }
2116  s = format (s, "0x%02x, ", ep->dns_response[i]);
2117  }
2118  s = format (s, "};\n");
2119  }
2120  else
2121  {
2123  {
2124  ASSERT (ep->dns_response);
2126  ss = "[S] ";
2127  else
2128  ss = " ";
2129 
2130  if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2131  s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2132  else
2133  s = format (s, "%s%s -> %U", ss, ep->name,
2134  format_dns_reply, ep->dns_response, verbose);
2135  if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2136  {
2137  f64 time_left = ep->expiration_time - now;
2138  if (time_left > 0.0)
2139  s = format (s, " TTL left %.1f", time_left);
2140  else
2141  s = format (s, " EXPIRED");
2142  }
2143  }
2144  else
2145  {
2146  ASSERT (ep->dns_request);
2147  s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2148  verbose);
2149  }
2150  vec_add1 (s, '\n');
2151  }
2152  return s;
2153  }
2154 
2155  s = format (s, "DNS cache contains %d entries\n", pool_elts (dm->entries));
2156 
2157  if (verbose > 0)
2158  {
2159  /* *INDENT-OFF* */
2160  pool_foreach (ep, dm->entries)
2161  {
2163  {
2164  ASSERT (ep->dns_response);
2166  ss = "[S] ";
2167  else
2168  ss = " ";
2169 
2170  if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2171  s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2172  else
2173  s = format (s, "%s%s -> %U", ss, ep->name,
2175  ep->dns_response,
2176  verbose);
2177  if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2178  {
2179  f64 time_left = ep->expiration_time - now;
2180  if (time_left > 0.0)
2181  s = format (s, " TTL left %.1f", time_left);
2182  else
2183  s = format (s, " EXPIRED");
2184 
2185  if (verbose > 2)
2186  s = format (s, " %d client notifications pending\n",
2187  vec_len(ep->pending_requests));
2188  }
2189  }
2190  else
2191  {
2192  ASSERT (ep->dns_request);
2193  s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2194  verbose);
2195  }
2196  vec_add1 (s, '\n');
2197  }
2198  /* *INDENT-ON* */
2199  }
2200 
2201  dns_cache_unlock (dm);
2202 
2203  return s;
2204 }
2205 
2206 static clib_error_t *
2208  unformat_input_t * input, vlib_cli_command_t * cmd)
2209 {
2210  dns_main_t *dm = &dns_main;
2211  int verbose = 0;
2212  u8 *name = 0;
2213  f64 now = vlib_time_now (vm);
2214 
2215  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2216  {
2217  if (unformat (input, "verbose %d", &verbose))
2218  ;
2219  else if (unformat (input, "verbose"))
2220  verbose = 1;
2221  else if (unformat (input, "name %s", &name))
2222  ;
2223  else
2224  return clib_error_return (0, "unknown input `%U'",
2225  format_unformat_error, input);
2226  }
2227 
2228  vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
2229 
2230  return 0;
2231 }
2232 
2233 /* *INDENT-OFF* */
2234 VLIB_CLI_COMMAND (show_dns_cache_command) =
2235 {
2236  .path = "show dns cache",
2237  .short_help = "show dns cache [verbose [nn]]",
2238  .function = show_dns_cache_command_fn,
2239 };
2240 /* *INDENT-ON* */
2241 
2242 static clib_error_t *
2244  unformat_input_t * input,
2245  vlib_cli_command_t * cmd)
2246 {
2247  dns_main_t *dm = &dns_main;
2248  int i;
2249 
2250  if ((vec_len (dm->ip4_name_servers) + vec_len (dm->ip6_name_servers)) == 0)
2251  return clib_error_return (0, "No name servers configured...");
2252 
2253  if (vec_len (dm->ip4_name_servers))
2254  {
2255  vlib_cli_output (vm, "ip4 name servers:");
2256  for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
2258  dm->ip4_name_servers + i);
2259  }
2260  if (vec_len (dm->ip6_name_servers))
2261  {
2262  vlib_cli_output (vm, "ip6 name servers:");
2263  for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
2265  dm->ip4_name_servers + i);
2266  }
2267  return 0;
2268 }
2269 
2270 /* *INDENT-OFF* */
2271 VLIB_CLI_COMMAND (show_dns_server_command) =
2272 {
2273  .path = "show dns servers",
2274  .short_help = "show dns servers",
2275  .function = show_dns_servers_command_fn,
2276 };
2277 /* *INDENT-ON* */
2278 
2279 
2280 static clib_error_t *
2282  unformat_input_t * input,
2283  vlib_cli_command_t * cmd)
2284 {
2285  dns_main_t *dm = &dns_main;
2286  u8 *dns_reply_data;
2287  u8 *name;
2288  int is_add = -1;
2289  int is_clear = -1;
2290  int rv;
2292 
2293  if (unformat (input, "add"))
2294  is_add = 1;
2295  if (unformat (input, "del"))
2296  is_add = 0;
2297  if (unformat (input, "clear"))
2298  is_clear = 1;
2299 
2300  if (is_add == -1 && is_clear == -1)
2301  return clib_error_return (0, "add / del / clear required...");
2302 
2303  if (is_clear == 1)
2304  {
2305  rv = dns_cache_clear (dm);
2306  switch (rv)
2307  {
2308  case 0:
2309  return 0;
2310 
2311  case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2312  error = clib_error_return (0, "Name resolution not enabled");
2313  return error;
2314  }
2315  }
2316 
2317  /* Delete (by name)? */
2318  if (is_add == 0)
2319  {
2320  if (unformat (input, "%v", &name))
2321  {
2322  rv = dns_delete_by_name (dm, name);
2323  switch (rv)
2324  {
2325  case VNET_API_ERROR_NO_SUCH_ENTRY:
2326  error = clib_error_return (0, "%v not in the cache...", name);
2327  vec_free (name);
2328  return error;
2329 
2330  case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2331  error = clib_error_return (0, "Name resolution not enabled");
2332  vec_free (name);
2333  return error;
2334 
2335  case 0:
2336  vec_free (name);
2337  return 0;
2338 
2339  default:
2340  error = clib_error_return (0, "dns_delete_by_name returned %d",
2341  rv);
2342  vec_free (name);
2343  return error;
2344  }
2345  }
2346  return clib_error_return (0, "unknown input `%U'",
2347  format_unformat_error, input);
2348  }
2349 
2350  /* Note: dns_add_static_entry consumes the name vector if OK... */
2351  if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2352  {
2353  rv = dns_add_static_entry (dm, name, dns_reply_data);
2354  switch (rv)
2355  {
2356  case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2357  vec_free (name);
2358  vec_free (dns_reply_data);
2359  return clib_error_return (0, "%v already in the cache...", name);
2360  case 0:
2361  return 0;
2362 
2363  default:
2364  return clib_error_return (0, "dns_add_static_entry returned %d",
2365  rv);
2366  }
2367  }
2368 
2369  return 0;
2370 }
2371 
2372 /* *INDENT-OFF* */
2373 VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2374 {
2375  .path = "dns cache",
2376  .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2377  .function = dns_cache_add_del_command_fn,
2378 };
2379 /* *INDENT-ON* */
2380 
2381 #define DNS_FORMAT_TEST 1
2382 
2383 #if DNS_FORMAT_TEST > 0
2384 #if 0
2385 /* yahoo.com */
2386 static u8 dns_reply_data_initializer[] =
2387  { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2388  0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2389  0x0, /* null lbl */
2390  0x0, 0xff, /* type ALL */
2391  0x0, 0x1, /* class IN */
2392  0xc0, 0xc, /* pointer to yahoo.com name */
2393  0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2394  0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2395  0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2396  0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2397  0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2398  0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2399  0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2400  0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2401  0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2402  0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2403  0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2404  0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2405  0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2406  0x6e,
2407  0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2408  0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2409  0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2410  0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2411  0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2412  0x0,
2413  0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2414  0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2415  0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2416  0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2417  0x0,
2418  0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2419  0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2420  0x0,
2421  0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2422  0x0,
2423  0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2424  0x0,
2425  0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2426  0x6f,
2427  0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2428  0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2429  0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2430  0x2, 0x58
2431 };
2432 
2433 /* www.cisco.com, has no addresses in reply */
2434 static u8 dns_reply_data_initializer[] = {
2435  0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2436  0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2437  0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2438 
2439  0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2440  0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2441  0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2442  0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2443  0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2444 };
2445 
2446 /* bind8 (linux widget, w/ nasty double pointer chasees */
2447 static u8 dns_reply_data_initializer[] = {
2448  /* 0 */
2449  0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08,
2450  /* 8 */
2451  0x00, 0x06, 0x00, 0x06, 0x0a, 0x6f, 0x72, 0x69,
2452  /* 16 */
2453  0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77, 0x77, 0x05,
2454  /* 24 */
2455  0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f,
2456  /* 32 */
2457  0x6d, 0x00, 0x00, 0xff, 0x00, 0x01, 0x0a, 0x6f,
2458  /* 40 */
2459  0x72, 0x69, 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77,
2460  /* 48 */
2461  0x77, 0x05, 0x43, 0x49, 0x53, 0x43, 0x4f, 0xc0,
2462 
2463  /* 56 */
2464  0x1d, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2465 
2466  /* 64 */
2467  0x9a, 0x00, 0x18, 0x15, 0x72, 0x63, 0x64,
2468  0x6e, 0x39, 0x2d, 0x31, 0x34, 0x70, 0x2d, 0x64, 0x63,
2469  0x7a, 0x30, 0x35, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31,
2470  0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00, 0x01, 0x00,
2471  0x00, 0x05, 0x9a, 0x00, 0x1a, 0x17, 0x61, 0x6c, 0x6c,
2472  0x6e, 0x30, 0x31, 0x2d, 0x61, 0x67, 0x30, 0x39, 0x2d,
2473  0x64, 0x63, 0x7a, 0x30, 0x33, 0x6e, 0x2d, 0x67, 0x73,
2474  0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00,
2475  0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x10, 0x0d, 0x72,
2476  0x74, 0x70, 0x35, 0x2d, 0x64, 0x6d, 0x7a, 0x2d, 0x67,
2477  0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2478  0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x18, 0x15,
2479  0x6d, 0x74, 0x76, 0x35, 0x2d, 0x61, 0x70, 0x31, 0x30,
2480  0x2d, 0x64, 0x63, 0x7a, 0x30, 0x36, 0x6e, 0x2d, 0x67,
2481  0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2482  0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x1b, 0x18,
2483  0x73, 0x6e, 0x67, 0x64, 0x63, 0x30, 0x31, 0x2d, 0x61,
2484  0x62, 0x30, 0x37, 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x31,
2485  0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0,
2486  0x26, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a,
2487  0x00, 0x1a, 0x17, 0x61, 0x65, 0x72, 0x30, 0x31, 0x2d,
2488  0x72, 0x34, 0x63, 0x32, 0x35, 0x2d, 0x64, 0x63, 0x7a,
2489  0x30, 0x31, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0,
2490  0x17, 0xc0, 0x26, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2491  0x00, 0x81, 0x00, 0x04, 0x48, 0xa3, 0x04, 0xa1, 0xc0,
2492  0x26, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82,
2493  0x00, 0x10, 0x20, 0x01, 0x04, 0x20, 0x12, 0x01, 0x00,
2494  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
2495  0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2496  0x9a, 0x00, 0x02, 0xc0, 0xf4, 0xc0, 0x0c, 0x00, 0x02,
2497  0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0,
2498  0xcd, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00,
2499  0x05, 0x9a, 0x00, 0x02, 0xc0, 0x8d, 0xc0, 0x0c, 0x00,
2500  0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02,
2501  0xc0, 0x43, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00,
2502  0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0, 0xa9, 0xc0, 0x0c,
2503  0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00,
2504  0x02, 0xc0, 0x67, 0xc0, 0x8d, 0x00, 0x01, 0x00, 0x01,
2505  0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0x40, 0x66, 0xf6,
2506  0x05, 0xc0, 0xa9, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2507  0x07, 0x08, 0x00, 0x04, 0xad, 0x24, 0xe0, 0x64, 0xc0,
2508  0x43, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08,
2509  0x00, 0x04, 0x48, 0xa3, 0x04, 0x1c, 0xc0, 0xf4, 0x00,
2510  0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04,
2511  0xad, 0x26, 0xd4, 0x6c, 0xc0, 0x67, 0x00, 0x01, 0x00,
2512  0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x25,
2513  0x90, 0x64, 0xc0, 0xcd, 0x00, 0x01, 0x00, 0x01, 0x00,
2514  0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x27, 0x70, 0x44,
2515 };
2516 
2517 /* google.com */
2518 static u8 dns_reply_data_initializer[] =
2519  { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
2520  0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
2521  0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
2522  0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
2523  0x2b,
2524  0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
2525  0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
2526  0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
2527  0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
2528  0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
2529  0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
2530  0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
2531  0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
2532  0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
2533  0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
2534  0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
2535  0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
2536  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
2537  0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
2538  0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
2539  0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
2540  0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2541  0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
2542  0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
2543  0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
2544  0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
2545  0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
2546  0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
2547  0x57,
2548  0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2549 };
2550 
2551 #else
2552 /* www.weatherlink.com */
2553 static u8 dns_reply_data_initializer[] = {
2554  0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2555  0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x0b,
2556  0x77, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x6c, 0x69,
2557  0x6e, 0x6b, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0xff,
2558  0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00,
2559  0x00, 0x0c, 0x9e, 0x00, 0x1f, 0x0e, 0x64, 0x33, 0x6b,
2560  0x72, 0x30, 0x67, 0x75, 0x62, 0x61, 0x31, 0x64, 0x76,
2561  0x77, 0x66, 0x0a, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x66,
2562  0x72, 0x6f, 0x6e, 0x74, 0x03, 0x6e, 0x65, 0x74, 0x00,
2563 };
2564 
2565 #endif
2566 
2567 static clib_error_t *
2569  unformat_input_t * input, vlib_cli_command_t * cmd)
2570 {
2571  u8 *dns_reply_data = 0;
2572  int verbose = 0;
2573  int rv;
2574  vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2575 
2576  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2577  {
2578  if (unformat (input, "verbose %d", &verbose))
2579  ;
2580  else if (unformat (input, "verbose"))
2581  verbose = 1;
2582  else
2583  return clib_error_return (0, "unknown input `%U'",
2584  format_unformat_error, input);
2585  }
2586 
2587  vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2588 
2589  memcpy (dns_reply_data, dns_reply_data_initializer,
2590  ARRAY_LEN (dns_reply_data_initializer));
2591 
2592  vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2593 
2594  clib_memset (rmp, 0, sizeof (*rmp));
2595 
2596  rv = vnet_dns_response_to_reply (dns_reply_data, rmp, 0 /* ttl-ptr */ );
2597 
2598  switch (rv)
2599  {
2600  case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2601  vlib_cli_output (vm, "no addresses found...");
2602  break;
2603 
2604  default:
2605  vlib_cli_output (vm, "response to reply returned %d", rv);
2606  break;
2607 
2608  case 0:
2609  if (rmp->ip4_set)
2610  vlib_cli_output (vm, "ip4 address: %U", format_ip4_address,
2611  (ip4_address_t *) rmp->ip4_address);
2612  if (rmp->ip6_set)
2613  vlib_cli_output (vm, "ip6 address: %U", format_ip6_address,
2614  (ip6_address_t *) rmp->ip6_address);
2615  break;
2616  }
2617 
2618  vec_free (dns_reply_data);
2619 
2620  return 0;
2621 }
2622 
2623 
2624 /* *INDENT-OFF* */
2625 VLIB_CLI_COMMAND (test_dns_fmt_command) =
2626 {
2627  .path = "test dns format",
2628  .short_help = "test dns format",
2629  .function = test_dns_fmt_command_fn,
2630 };
2631 /* *INDENT-ON* */
2632 
2633 static clib_error_t *
2635  unformat_input_t * input, vlib_cli_command_t * cmd)
2636 {
2637  u8 *dns_reply_data = 0;
2638  int verbose = 0;
2639  int reply_set = 0;
2640 
2641  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2642  {
2643  if (unformat (input, "verbose %d", &verbose))
2644  ;
2645  else if (unformat (input, "verbose"))
2646  verbose = 1;
2647  else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2648  reply_set = 1;
2649  else
2650  return clib_error_return (0, "unknown input `%U'",
2651  format_unformat_error, input);
2652  }
2653 
2654  if (reply_set == 0)
2655  return clib_error_return (0, "dns data not set...");
2656 
2657  vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2658 
2659  vec_free (dns_reply_data);
2660 
2661  return 0;
2662 }
2663 
2664 /* *INDENT-OFF* */
2665 VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2666 {
2667  .path = "test dns unformat",
2668  .short_help = "test dns unformat <name> [ip4][ip6]",
2669  .function = test_dns_unfmt_command_fn,
2670 };
2671 /* *INDENT-ON* */
2672 
2673 static clib_error_t *
2675  unformat_input_t * input,
2676  vlib_cli_command_t * cmd)
2677 {
2678  dns_main_t *dm = &dns_main;
2679  u8 *name = 0;
2680  uword *p;
2681  clib_error_t *e;
2682  dns_cache_entry_t *ep;
2683 
2684  if (unformat (input, "%v", &name))
2685  {
2686  vec_add1 (name, 0);
2687  _vec_len (name) -= 1;
2688  }
2689  else
2690  return clib_error_return (0, "no name provided");
2691 
2692  dns_cache_lock (dm, 7);
2693 
2694  p = hash_get_mem (dm->cache_entry_by_name, name);
2695  if (!p)
2696  {
2697  dns_cache_unlock (dm);
2698  e = clib_error_return (0, "%s is not in the cache...", name);
2699  vec_free (name);
2700  return e;
2701  }
2702 
2703  ep = pool_elt_at_index (dm->entries, p[0]);
2704 
2705  ep->expiration_time = 0;
2706 
2707  return 0;
2708 }
2709 
2710 /* *INDENT-OFF* */
2711 VLIB_CLI_COMMAND (test_dns_expire_command) =
2712 {
2713  .path = "test dns expire",
2714  .short_help = "test dns expire <name>",
2715  .function = test_dns_expire_command_fn,
2716 };
2717 /* *INDENT-ON* */
2718 #endif
2719 
2720 void
2723  vlib_buffer_t * b0)
2724 {
2725  clib_warning ("Unimplemented...");
2726 }
2727 
2728 
2729 void
2732  vlib_buffer_t * b0)
2733 {
2734  u32 bi = 0;
2736  fib_node_index_t fei;
2737  u32 sw_if_index, fib_index;
2738  ip4_main_t *im4 = &ip4_main;
2739  ip_lookup_main_t *lm4 = &im4->lookup_main;
2740  ip_interface_address_t *ia = 0;
2742  ip4_header_t *ip;
2743  udp_header_t *udp;
2744  dns_header_t *dh;
2745  vlib_frame_t *f;
2746  u32 *to_next;
2747  u8 *dns_response;
2748  u8 *reply;
2749  vl_api_dns_resolve_name_reply_t _rnr, *rnr = &_rnr;
2750  vl_api_dns_resolve_ip_reply_t _rir, *rir = &_rir;
2751  u32 ttl = 64, tmp;
2752  u32 qp_offset;
2753  dns_query_t *qp;
2754  dns_rr_t *rr;
2755  u8 *rrptr;
2756  int is_fail = 0;
2757  int is_recycle = (b0 != 0);
2758 
2759  ASSERT (ep && ep->dns_response);
2760 
2762  {
2763  /* Quick and dirty way to dig up the A-record address. $$ FIXME */
2764  clib_memset (rnr, 0, sizeof (*rnr));
2765  if (vnet_dns_response_to_reply (ep->dns_response, rnr, &ttl))
2766  {
2767  /* clib_warning ("response_to_reply failed..."); */
2768  is_fail = 1;
2769  }
2770  if (rnr->ip4_set == 0)
2771  {
2772  /* clib_warning ("No A-record..."); */
2773  is_fail = 1;
2774  }
2775  }
2776  else if (pr->request_type == DNS_PEER_PENDING_IP_TO_NAME)
2777  {
2778  clib_memset (rir, 0, sizeof (*rir));
2779  if (vnet_dns_response_to_name (ep->dns_response, rir, &ttl))
2780  {
2781  /* clib_warning ("response_to_name failed..."); */
2782  is_fail = 1;
2783  }
2784  }
2785  else
2786  {
2787  clib_warning ("Unknown request type %d", pr->request_type);
2788  return;
2789  }
2790 
2791  /* Initialize a buffer */
2792  if (b0 == 0)
2793  {
2794  if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2795  return;
2796  b0 = vlib_get_buffer (vm, bi);
2797  }
2798  else
2799  {
2800  /* Use the buffer we were handed. Reinitialize it... */
2801  vlib_buffer_t bt = { };
2802  /* push/pop the reference count */
2803  u8 save_ref_count = b0->ref_count;
2804  vlib_buffer_copy_template (b0, &bt);
2805  b0->ref_count = save_ref_count;
2806  bi = vlib_get_buffer_index (vm, b0);
2807  }
2808 
2809  if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
2811 
2812  /*
2813  * Reset the buffer. We recycle the DNS request packet in the cache
2814  * hit case, and reply immediately from the request node.
2815  *
2816  * In the resolution-required / deferred case, resetting a freshly-allocated
2817  * buffer won't hurt. We hope.
2818  */
2819  b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
2820  | VLIB_BUFFER_TOTAL_LENGTH_VALID);
2821  vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; /* "local0" */
2822  vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
2823 
2824  /* Find a FIB path to the peer we're trying to answer */
2825  clib_memcpy (&prefix.fp_addr.ip4, pr->dst_address, sizeof (ip4_address_t));
2826  prefix.fp_proto = FIB_PROTOCOL_IP4;
2827  prefix.fp_len = 32;
2828 
2829  fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
2830  if (fib_index == (u32) ~ 0)
2831  {
2832  clib_warning ("no fib table");
2833  return;
2834  }
2835 
2836  fei = fib_table_lookup (fib_index, &prefix);
2837 
2838  /* Couldn't find route to destination. Bail out. */
2839  if (fei == FIB_NODE_INDEX_INVALID)
2840  {
2841  clib_warning ("no route to DNS server");
2842  return;
2843  }
2844 
2845  sw_if_index = fib_entry_get_resolving_interface (fei);
2846 
2847  if (sw_if_index == ~0)
2848  {
2849  clib_warning
2850  ("route to %U exists, fei %d, get_resolving_interface returned"
2851  " ~0", fei, format_ip4_address, &prefix.fp_addr);
2852  return;
2853  }
2854 
2855  /* *INDENT-OFF* */
2856  foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnumbered */,
2857  ({
2858  src_address = ip_interface_address_get_address (lm4, ia);
2859  goto found_src_address;
2860  }));
2861  /* *INDENT-ON* */
2862 
2863  clib_warning ("FIB BUG");
2864  return;
2865 
2866 found_src_address:
2867 
2868  ip = vlib_buffer_get_current (b0);
2869  udp = (udp_header_t *) (ip + 1);
2870  dns_response = (u8 *) (udp + 1);
2871  clib_memset (ip, 0, sizeof (*ip) + sizeof (*udp));
2872 
2873  /*
2874  * Start with the variadic portion of the exercise.
2875  * Turn the name into a set of DNS "labels". Max length
2876  * per label is 63, enforce that.
2877  */
2878  reply = name_to_labels (pr->name);
2879  vec_free (pr->name);
2880 
2881  qp_offset = vec_len (reply);
2882 
2883  /* Add space for the query header */
2884  vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
2885 
2886  qp = (dns_query_t *) (reply + qp_offset);
2887 
2889  qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
2890  else
2891  qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2892 
2893  qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
2894 
2895  /* Punch in space for the dns_header_t */
2896  vec_insert (reply, sizeof (dns_header_t), 0);
2897 
2898  dh = (dns_header_t *) reply;
2899 
2900  /* Transaction ID = pool index */
2901  dh->id = pr->id;
2902 
2903  /* Announce that we did a recursive lookup */
2904  tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
2905  if (is_fail)
2906  tmp |= DNS_RCODE_NAME_ERROR;
2907  dh->flags = clib_host_to_net_u16 (tmp);
2908  dh->qdcount = clib_host_to_net_u16 (1);
2909  dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
2910  dh->nscount = 0;
2911  dh->arcount = 0;
2912 
2913  /* If the name resolution worked, cough up an appropriate RR */
2914  if (is_fail == 0)
2915  {
2916  /* Add the answer. First, a name pointer (0xC00C) */
2917  vec_add1 (reply, 0xC0);
2918  vec_add1 (reply, 0x0C);
2919 
2920  /* Now, add single A-rec RR */
2922  {
2923  vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
2924  rr = (dns_rr_t *) rrptr;
2925 
2926  rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
2927  rr->class = clib_host_to_net_u16 (1 /* internet */ );
2928  rr->ttl = clib_host_to_net_u32 (ttl);
2929  rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
2930  clib_memcpy (rr->rdata, rnr->ip4_address, sizeof (ip4_address_t));
2931  }
2932  else
2933  {
2934  /* Or a single PTR RR */
2935  u8 *vecname = format (0, "%s", rir->name);
2936  u8 *label_vec = name_to_labels (vecname);
2937  vec_free (vecname);
2938 
2939  vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
2940  rr = (dns_rr_t *) rrptr;
2941  rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2942  rr->class = clib_host_to_net_u16 (1 /* internet */ );
2943  rr->ttl = clib_host_to_net_u32 (ttl);
2944  rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
2945  clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
2946  vec_free (label_vec);
2947  }
2948  }
2949  clib_memcpy (dns_response, reply, vec_len (reply));
2950 
2951  /* Set the packet length */
2952  b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
2953 
2954  /* IP header */
2955  ip->ip_version_and_header_length = 0x45;
2956  ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
2957  ip->ttl = 255;
2958  ip->protocol = IP_PROTOCOL_UDP;
2959  ip->src_address.as_u32 = src_address->as_u32;
2961  sizeof (ip4_address_t));
2962  ip->checksum = ip4_header_checksum (ip);
2963 
2964  /* UDP header */
2965  udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
2966  udp->dst_port = pr->dst_port;
2967  udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
2968  vec_len (reply));
2969  udp->checksum = 0;
2970  vec_free (reply);
2971 
2972  /*
2973  * Ship pkts made out of whole cloth to ip4_lookup
2974  * Caller will ship recycled dns reply packets to ip4_lookup
2975  */
2976  if (is_recycle == 0)
2977  {
2978  f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
2979  to_next = vlib_frame_vector_args (f);
2980  to_next[0] = bi;
2981  f->n_vectors = 1;
2982  vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
2983  }
2984 }
2985 
2986 #include <dns/dns.api.c>
2987 static clib_error_t *
2989 {
2990  dns_main_t *dm = &dns_main;
2991 
2992  dm->vnet_main = vnet_get_main ();
2993  dm->name_cache_size = 1000;
2994  dm->max_ttl_in_seconds = 86400;
2995  dm->random_seed = 0xDEADDABE;
2996  dm->api_main = vlibapi_get_main ();
2997 
2998  /* Ask for a correctly-sized block of API message decode slots */
3000 
3001  return 0;
3002 }
3003 
3005 
3006 /* *INDENT-OFF* */
3008 {
3009  .version = VPP_BUILD_VER,
3010  .description = "Simple DNS name resolver",
3011 };
3012 /* *INDENT-ON* */
3013 
3014 
3015 /*
3016  * fd.io coding-style-patch-verification: ON
3017  *
3018  * Local Variables:
3019  * eval: (c-set-style "gnu")
3020  * End:
3021  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:509
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:124
fib_protocol_t fp_proto
protocol type
Definition: fib_types.h:211
#define foreach_notification_to_move
Definition: dns.c:957
Definition: dns.h:50
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:2730
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:2568
ip6_address_t * ip6_name_servers
Definition: dns.h:112
vl_api_wireguard_peer_flags_t flags
Definition: wireguard.api:105
ip4_address_t src_address
Definition: ip4_packet.h:125
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
#define DNS_CACHE_ENTRY_FLAG_VALID
we have Actual Data
Definition: dns.h:81
#define DNS_RD
recursion desired
Definition: dns_packet.h:43
#define pool_foreach(VAR, POOL)
Iterate through pool.
Definition: pool.h:527
vlib_node_registration_t dns46_reply_node
(constructor) VLIB_REGISTER_NODE (dns46_reply_node)
Definition: reply_node.c:42
static void * ip_interface_address_get_address(ip_lookup_main_t *lm, ip_interface_address_t *a)
Definition: ip_interface.h:43
static int delete_random_entry(dns_main_t *dm)
Definition: dns.c:719
#define REPLY_MACRO2(t, body)
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:334
vlib_node_registration_t dns4_request_node
(constructor) VLIB_REGISTER_NODE (dns4_request_node)
Definition: request_node.c:293
#define DNS_RCODE_REFUSED
Definition: dns_packet.h:40
#define DNS_RCODE_NO_ERROR
Definition: dns_packet.h:35
u8 * dns_response
Cached dns response.
Definition: dns.h:75
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:113
int vnet_dns_response_to_name(u8 *response, vl_api_dns_resolve_ip_reply_t *rmp, u32 *min_ttlp)
Definition: dns.c:1303
#define vec_terminate_c_string(V)
(If necessary) NULL terminate a vector containing a c-string.
Definition: vec.h:1090
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:592
int vnet_dns_delete_entry_by_index_nolock(dns_main_t *dm, u32 index)
Definition: dns.c:662
int retry_count
Retry parameters.
Definition: dns.h:68
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:2721
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:630
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
#define hash_set_mem(h, key, value)
Definition: hash.h:275
ip_lookup_main_t lookup_main
Definition: ip4.h:109
#define DNS_CACHE_ENTRY_FLAG_STATIC
static entry
Definition: dns.h:82
vlib_main_t * vm
Definition: in2out_ed.c:1580
u32 client_context
Definition: dns.h:33
vl_api_prefix_t prefix
Definition: ip.api:144
#define DNS_CLASS_IN
The Internet.
Definition: dns_packet.h:145
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:402
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:251
ip6_address_t src_address
Definition: ip6_packet.h:310
DNS IP -> name resolution request.
Definition: dns.api:87
int vnet_dns_response_to_reply(u8 *response, vl_api_dns_resolve_name_reply_t *rmp, u32 *min_ttlp)
Definition: dns.c:1162
#define DNS_RCODE_NOT_IMPLEMENTED
Definition: dns_packet.h:39
unsigned char u8
Definition: types.h:56
u8 id[64]
Definition: dhcp.api:160
double f64
Definition: types.h:142
void vnet_dns_create_resolver_process(vlib_main_t *vm, dns_main_t *dm)
vlib_node_registration_t ip4_lookup_node
(constructor) VLIB_REGISTER_NODE (ip4_lookup_node)
Definition: ip4_forward.c:104
#define clib_memcpy(d, s, n)
Definition: string.h:180
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:2243
format_function_t format_ip4_address
Definition: format.h:73
dns_main_t dns_main
Definition: dns.c:42
clib_spinlock_t cache_lock
Definition: dns.h:101
unformat_function_t unformat_ip4_address
Definition: format.h:68
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
static void vl_api_dns_resolve_ip_t_handler(vl_api_dns_resolve_ip_t *mp)
Definition: dns.c:1478
u8 * dns_request
Cached dns request, for sending retries.
Definition: dns.h:65
f64 retry_timer
Definition: dns.h:72
static void vl_api_dns_enable_disable_t_handler(vl_api_dns_enable_disable_t *mp)
Definition: dns.c:121
ip4_address_t dst_address
Definition: ip4_packet.h:125
description fragment has unexpected format
Definition: map.api:433
Aggregate type for a prefix.
Definition: fib_types.h:202
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:182
#define clib_error_return(e, args...)
Definition: error.h:99
u8 * format_dns_reply(u8 *s, va_list *args)
Definition: dns.c:2007
u32 * unresolved_entries
Pool indices of unresolved entries.
Definition: dns.h:97
const cJSON *const b
Definition: cJSON.h:255
#define DNS_RCODE_MASK
Definition: dns_packet.h:34
unsigned int u32
Definition: types.h:88
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
u16 fp_len
The mask length.
Definition: fib_types.h:206
u32 resolver_process_node_index
resolver process node index
Definition: dns.h:115
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 * pending_requests
Clients / peers awaiting responses.
Definition: dns.h:78
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
VLIB_PLUGIN_REGISTER()
static u32 vlib_get_buffer_index(vlib_main_t *vm, void *p)
Translate buffer pointer into buffer index.
Definition: buffer_funcs.h:293
#define hash_create_string(elts, value_bytes)
Definition: hash.h:690
#define DNS_RETRIES_PER_SERVER
Definition: dns.h:85
ip4_address_t * ip4_name_servers
upstream name servers, e.g.
Definition: dns.h:111
static void clib_spinlock_init(clib_spinlock_t *p)
Definition: lock.h:65
#define DNS_RA
recursion available
Definition: dns_packet.h:42
u8 * cname
For CNAME records, the "next name" to resolve.
Definition: dns.h:59
Definition: cJSON.c:84
static int dns_enable_disable(vlib_main_t *vm, dns_main_t *dm, int is_enable)
Definition: dns.c:71
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:546
#define vec_insert(V, N, M)
Insert N vector elements starting at element M, initialize new elements to zero (no header...
Definition: vec.h:755
#define hash_unset_mem(h, key)
Definition: hash.h:291
u8 * name
The name in "normal human being" notation, e.g.
Definition: dns.h:56
ip46_address_t fp_addr
The address type is not deriveable from the fp_addr member.
Definition: fib_types.h:225
#define DNS_QR
query=0, response=1
Definition: dns_packet.h:50
#define DNS_RCODE_SERVER_FAILURE
Definition: dns_packet.h:37
static_always_inline void vlib_buffer_copy_template(vlib_buffer_t *b, vlib_buffer_t *bt)
Definition: buffer_funcs.h:181
DNS name resolution request.
Definition: dns.api:54
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:677
struct _unformat_input_t unformat_input_t
unsigned short u16
Definition: types.h:57
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
Definition: main.c:216
vec_header_t h
Definition: buffer.c:322
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:233
#define hash_free(h)
Definition: hash.h:310
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:301
#define vec_dup(V)
Return copy of vector (no header, no alignment)
Definition: vec.h:429
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:2281
#define VLIB_CONFIG_FUNCTION(x, n,...)
Definition: init.h:182
#define REPLY_MACRO(t)
ip6_main_t ip6_main
Definition: ip6_forward.c:2785
vl_api_address_union_t src_address
Definition: ip_types.api:122
u32 label
Definition: fib_types.api:25
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:1741
DNS ip->name resolution reply.
Definition: dns.api:102
vlib_thread_main_t vlib_thread_main
Definition: threads.c:35
int server_rotor
Definition: dns.h:69
static clib_error_t * dns_init(vlib_main_t *vm)
Definition: dns.c:2988
static void vl_api_dns_resolve_name_t_handler(vl_api_dns_resolve_name_t *mp)
Definition: dns.c:1439
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:2207
u8 len
Definition: ip_types.api:103
u32 fib_entry_get_resolving_interface(fib_node_index_t entry_index)
Definition: fib_entry.c:1458
unformat_function_t unformat_ip6_address
Definition: format.h:89
#define pool_free(p)
Free a pool.
Definition: pool.h:440
static void setup_message_id_table(api_main_t *am)
Definition: bfd_api.c:409
api_main_t * api_main
Definition: dns.h:127
#define UNFORMAT_END_OF_INPUT
Definition: format.h:144
u16 n_vectors
Definition: node.h:397
void vnet_send_dns_request(vlib_main_t *vm, dns_main_t *dm, dns_cache_entry_t *ep)
Definition: dns.c:537
format_function_t format_ip6_address
Definition: format.h:91
static void dns_cache_unlock(dns_main_t *dm)
Definition: dns.h:216
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:317
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
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:380
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:1039
u8 ttl
Definition: fib_types.api:26
#define clib_warning(format, args...)
Definition: error.h:59
static int dns6_name_server_add_del(dns_main_t *dm, u8 *server_address_as_u8, int is_add)
Definition: dns.c:134
u16 msg_id_base
message-ID base
Definition: dns.h:123
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:29
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:298
#define ARRAY_LEN(x)
Definition: clib.h:67
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:2674
vl_api_ikev2_sa_transform_t dh
string name[64]
Definition: ip.api:44
#define DNS_AA
authoritative answer
Definition: dns_packet.h:45
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:158
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:1099
static int dns_cache_clear(dns_main_t *dm)
Definition: dns.c:45
vlib_node_registration_t ip6_lookup_node
(constructor) VLIB_REGISTER_NODE (ip6_lookup_node)
Definition: ip6_forward.c:742
#define ASSERT(truth)
volatile u8 flags
flags
Definition: dns.h:53
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:696
ip_lookup_main_t lookup_main
Definition: ip6.h:112
#define DNS_RCODE_FORMAT_ERROR
Definition: dns_packet.h:36
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:854
u8 * vnet_dns_labels_to_name(u8 *label, u8 *full_text, u8 **parse_from_here)
arc-function for the above.
Definition: dns.c:495
IPv4 main type.
Definition: ip4.h:107
u8 dst_address[16]
Definition: dns.h:38
#define DNS_OPCODE_QUERY
standard query
Definition: dns_packet.h:47
static clib_error_t * dns_config_fn(vlib_main_t *vm, unformat_input_t *input)
Definition: dns.c:1553
vnet_main_t * vnet_main
Definition: dns.h:126
int udp_ports_registered
udp port registration complete
Definition: dns.h:108
static int dns_add_static_entry(dns_main_t *dm, u8 *name, u8 *dns_reply_data)
Definition: dns.c:766
uword * cache_entry_by_name
Find cached record by name.
Definition: dns.h:100
add or delete an upstream name server
Definition: dns.api:39
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
enable/disable name resolution
Definition: dns.api:24
uword unformat_dns_reply(unformat_input_t *input, va_list *args)
Definition: dns.c:1573
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
vlib_node_registration_t dns6_request_node
(constructor) VLIB_REGISTER_NODE (dns6_request_node)
Definition: request_node.c:320
u32 ip_version_traffic_class_and_flow_label
Definition: ip6_packet.h:297
Definition: defs.h:47
static void dns_cache_lock(dns_main_t *dm, int tag)
Definition: dns.h:204
u16 payload_length
Definition: ip6_packet.h:301
u32 max_ttl_in_seconds
Definition: dns.h:119
static int dns_delete_by_name(dns_main_t *dm, u8 *name)
Definition: dns.c:696
vl_api_address_t ip
Definition: l2.api:501
#define FIB_NODE_INDEX_INVALID
Definition: fib_types.h:30
#define DNS_RCODE_NAME_ERROR
Definition: dns_packet.h:38
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u32 next_buffer
Next buffer for this linked-list of buffers.
Definition: buffer.h:140
u32 name_cache_size
config parameters
Definition: dns.h:118
#define foreach_ip_interface_address(lm, a, sw_if_index, loop, body)
Definition: ip_interface.h:57
VLIB buffer representation.
Definition: buffer.h:102
u64 uword
Definition: types.h:112
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:297
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
u32 index
Definition: flow_types.api:221
static void vl_api_dns_name_server_add_del_t_handler(vl_api_dns_name_server_add_del_t *mp)
Definition: dns.c:206
vhost_user_req_t request
Definition: vhost_user.h:104
Definition: dns.h:91
#define DNS_CACHE_ENTRY_FLAG_CNAME
CNAME (indirect) entry.
Definition: dns.h:83
#define hash_get_mem(h, key)
Definition: hash.h:269
struct clib_bihash_value offset
template key/value backing page structure
static api_main_t * vlibapi_get_main(void)
Definition: api_common.h:389
#define vnet_buffer(b)
Definition: buffer.h:417
static u32 random_u32(u32 *seed)
32-bit random number generator
Definition: random.h:69
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
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
int server_fails
Definition: dns.h:71
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:1105
u32 random_seed
Definition: dns.h:120
static int dns4_name_server_add_del(dns_main_t *dm, u8 *server_address_as_u8, int is_add)
Definition: dns.c:170
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:2634
int server_af
Definition: dns.h:70
u8 count
Definition: dhcp.api:208
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:970
u8 ip_version_and_header_length
Definition: ip4_packet.h:93
f64 expiration_time
Expiration time.
Definition: dns.h:62
u32 total_length_not_including_first_buffer
Only valid for first buffer in chain.
Definition: buffer.h:167
DNS name resolution reply.
Definition: dns.api:71
u8 * format_dns_cache(u8 *s, va_list *args)
Definition: dns.c:2067
volatile u8 ref_count
Reference count for this buffer.
Definition: buffer.h:130
u8 * format_dns_query(u8 *s, va_list *args)
Definition: dns.c:1677
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:85
static u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:314
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
Definition: defs.h:46
#define DNS_RESOLVER_EVENT_PENDING
Definition: dns.h:88
ip6_address_t dst_address
Definition: ip6_packet.h:310
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:170
int is_enabled
enable / disable flag
Definition: dns.h:105
#define DNS_TC
truncation
Definition: dns_packet.h:44
dns_cache_entry_t * entries
Pool of cache entries.
Definition: dns.h:94
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:127