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