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