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