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