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