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