FD.io VPP  v19.08.3-2-gbabecb413
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  /* make sure it NULL-terminated as hash_set_mem will use strlen() */
821  hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
823  ep->dns_response = dns_reply_data;
824 
825  dns_cache_unlock (dm);
826  return 0;
827 }
828 
829 int
831  dns_cache_entry_t ** retp)
832 {
833  dns_cache_entry_t *ep;
834  int rv;
835  f64 now;
836  uword *p;
838  int count;
839 
840  now = vlib_time_now (dm->vlib_main);
841 
842  /* In case we can't actually answer the question right now... */
843  *retp = 0;
844 
845  /* binary API caller might forget to set the name. Guess how we know. */
846  if (name[0] == 0)
847  return VNET_API_ERROR_INVALID_VALUE;
848 
849  dns_cache_lock (dm, 5);
850 search_again:
851  p = hash_get_mem (dm->cache_entry_by_name, name);
852  if (p)
853  {
854  ep = pool_elt_at_index (dm->entries, p[0]);
856  {
857  /* Has the entry expired? */
858  if (((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0)
859  && (now > ep->expiration_time))
860  {
861  int i;
862  u32 *indices_to_delete = 0;
863 
864  /*
865  * Take out the rest of the resolution chain
866  * This isn't optimal, but it won't happen very often.
867  */
868  while (ep)
869  {
870  if ((ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME))
871  {
872  vec_add1 (indices_to_delete, ep - dm->entries);
873 
874  p = hash_get_mem (dm->cache_entry_by_name, ep->cname);
875  if (!p)
876  break;
877  ep = pool_elt_at_index (dm->entries, p[0]);
878  }
879  else
880  {
881  vec_add1 (indices_to_delete, ep - dm->entries);
882  break;
883  }
884  }
885  for (i = 0; i < vec_len (indices_to_delete); i++)
886  {
887  /* Reenable to watch re-resolutions */
888  if (0)
889  {
890  ep = pool_elt_at_index (dm->entries,
891  indices_to_delete[i]);
892  clib_warning ("Re-resolve %s", ep->name);
893  }
894 
896  (dm, indices_to_delete[i]);
897  }
898  vec_free (indices_to_delete);
899  /* Yes, kill it... */
900  goto re_resolve;
901  }
902 
904  {
905  name = ep->cname;
906  goto search_again;
907  }
908  *retp = ep;
909  dns_cache_unlock (dm);
910  return (0);
911  }
912  else
913  {
914  /*
915  * Resolution pending. Add request to the pending vector
916  * by copying the template request
917  */
918  vec_add2 (ep->pending_requests, pr, 1);
919  memcpy (pr, t, sizeof (*pr));
920  dns_cache_unlock (dm);
921  return (0);
922  }
923  }
924 
925 re_resolve:
926  if (pool_elts (dm->entries) == dm->name_cache_size)
927  {
928  /* Will only fail if the cache is totally filled w/ static entries... */
929  rv = delete_random_entry (dm);
930  if (rv)
931  {
932  dns_cache_unlock (dm);
933  return rv;
934  }
935  }
936 
937  /* add new hash table entry */
938  pool_get (dm->entries, ep);
939  clib_memset (ep, 0, sizeof (*ep));
940 
941  ep->name = format (0, "%s%c", name, 0);
942  _vec_len (ep->name) = vec_len (ep->name) - 1;
943 
944  hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
945 
946  vec_add1 (dm->unresolved_entries, ep - dm->entries);
947  vec_add2 (ep->pending_requests, pr, 1);
948 
949  pr->request_type = t->request_type;
950 
951  /* Remember details so we can reply later... */
954  {
955  pr->client_index = t->client_index;
957  }
958  else
959  {
960  pr->client_index = ~0;
961  pr->is_ip6 = t->is_ip6;
962  pr->dst_port = t->dst_port;
963  pr->id = t->id;
964  pr->name = t->name;
965  if (t->is_ip6)
966  count = 16;
967  else
968  count = 4;
969  clib_memcpy (pr->dst_address, t->dst_address, count);
970  }
971 
972  vnet_send_dns_request (dm, ep);
973  dns_cache_unlock (dm);
974  return 0;
975 }
976 
977 #define foreach_notification_to_move \
978 _(pending_requests)
979 
980 /**
981  * Handle cname indirection. JFC. Called with the cache locked.
982  * returns 0 if the reply is not a CNAME.
983  */
984 
985 int
987 {
988  dns_header_t *h;
989  dns_query_t *qp;
990  dns_rr_t *rr;
991  u8 *curpos;
992  u8 *pos, *pos2;
993  u8 *cname_pos = 0;
994  int len, i;
995  u8 *cname = 0;
996  u8 *request = 0;
997  u8 *name_copy;
998  u32 qp_offset;
999  u16 flags;
1000  u16 rcode;
1001  dns_cache_entry_t *ep, *next_ep;
1002  f64 now;
1003 
1004  h = (dns_header_t *) reply;
1005  flags = clib_net_to_host_u16 (h->flags);
1006  rcode = flags & DNS_RCODE_MASK;
1007 
1008  /* See if the response is OK */
1009  switch (rcode)
1010  {
1011  case DNS_RCODE_NO_ERROR:
1012  break;
1013 
1014  case DNS_RCODE_NAME_ERROR:
1018  case DNS_RCODE_REFUSED:
1019  return -1;
1020  }
1021 
1022  curpos = (u8 *) (h + 1);
1023  pos = curpos;
1024  len = *pos++;
1025 
1026  /* Skip the questions */
1027  for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
1028  {
1029  while (len)
1030  {
1031  pos += len;
1032  len = *pos++;
1033  }
1034  pos += sizeof (dns_query_t);
1035  }
1036  pos2 = pos;
1037  /* expect a pointer chase here for a CNAME record */
1038  if ((pos2[0] & 0xC0) == 0xC0)
1039  pos += 2;
1040  else
1041  return 0;
1042 
1043  /* Walk the answer(s) to see what to do next */
1044  for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
1045  {
1046  rr = (dns_rr_t *) pos;
1047  switch (clib_net_to_host_u16 (rr->type))
1048  {
1049  /* Real address record? Done.. */
1050  case DNS_TYPE_A:
1051  case DNS_TYPE_AAAA:
1052  return 0;
1053  /*
1054  * Maybe chase a CNAME pointer?
1055  * It's not unheard-of for name-servers to return
1056  * both CNAME and A/AAAA records...
1057  */
1058  case DNS_TYPE_CNAME:
1059  cname_pos = pos;
1060  break;
1061 
1062  /* Some other junk, e.g. a nameserver... */
1063  default:
1064  break;
1065  }
1066  pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1067  /* Skip name... */
1068  if ((pos2[0] & 0xc0) == 0xc0)
1069  pos += 2;
1070  }
1071 
1072  /* Neither a CNAME nor a real address. Try another server */
1073  if (cname_pos == 0)
1074  {
1075  flags &= ~DNS_RCODE_MASK;
1076  flags |= DNS_RCODE_NAME_ERROR;
1077  h->flags = clib_host_to_net_u16 (flags);
1078  return -1;
1079  }
1080 
1081  /* This is a CNAME record, chase the name chain. */
1082  pos = cname_pos;
1083 
1084  /* The last request is no longer pending.. */
1085  for (i = 0; i < vec_len (dm->unresolved_entries); i++)
1086  if (ep_index == dm->unresolved_entries[i])
1087  {
1088  vec_delete (dm->unresolved_entries, 1, i);
1089  goto found_last_request;
1090  }
1091  clib_warning ("pool elt %d supposedly pending, but not found...", ep_index);
1092  return -1;
1093 
1094 found_last_request:
1095 
1096  now = vlib_time_now (dm->vlib_main);
1097  cname = vnet_dns_labels_to_name (rr->rdata, reply, &pos2);
1098  /* Save the cname */
1099  vec_add1 (cname, 0);
1100  _vec_len (cname) -= 1;
1101  ep = pool_elt_at_index (dm->entries, ep_index);
1102  ep->cname = cname;
1104  /* Save the response */
1105  if (ep->dns_response)
1106  vec_free (ep->dns_response);
1107  ep->dns_response = reply;
1108  /* Set up expiration time */
1109  ep->expiration_time = now + clib_net_to_host_u32 (rr->ttl);
1110 
1111  pool_get (dm->entries, next_ep);
1112 
1113  /* Need to recompute ep post pool-get */
1114  ep = pool_elt_at_index (dm->entries, ep_index);
1115 
1116  clib_memset (next_ep, 0, sizeof (*next_ep));
1117  next_ep->name = vec_dup (cname);
1118  vec_add1 (next_ep->name, 0);
1119  _vec_len (next_ep->name) -= 1;
1120 
1121  hash_set_mem (dm->cache_entry_by_name, next_ep->name,
1122  next_ep - dm->entries);
1123 
1124  /* Use the same server */
1125  next_ep->server_rotor = ep->server_rotor;
1126  next_ep->server_af = ep->server_af;
1127 
1128  /* Move notification data to the next name in the chain */
1129 #define _(a) next_ep->a = ep->a; ep->a = 0;
1131 #undef _
1132 
1133  request = name_to_labels (cname);
1134  name_copy = vec_dup (request);
1135 
1136  qp_offset = vec_len (request);
1137 
1138  /* Add space for the query header */
1139  vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
1140 
1141  qp = (dns_query_t *) (request + qp_offset);
1142 
1143  qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
1144  qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1145  clib_memcpy (qp, name_copy, vec_len (name_copy));
1146  qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
1147  vec_free (name_copy);
1148 
1149  qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1150  qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1151 
1152  /* Punch in space for the dns_header_t */
1153  vec_insert (request, sizeof (dns_header_t), 0);
1154 
1155  h = (dns_header_t *) request;
1156 
1157  /* Transaction ID = pool index */
1158  h->id = clib_host_to_net_u16 (next_ep - dm->entries);
1159 
1160  /* Ask for a recursive lookup */
1161  h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
1162  h->qdcount = clib_host_to_net_u16 (2);
1163  h->nscount = 0;
1164  h->arcount = 0;
1165 
1166  next_ep->dns_request = request;
1167  next_ep->retry_timer = now + 2.0;
1168  next_ep->retry_count = 0;
1169 
1170  /*
1171  * Enable this to watch recursive resolution happen...
1172  * fformat (stdout, "%U", format_dns_reply, request, 2);
1173  */
1174 
1175  vec_add1 (dm->unresolved_entries, next_ep - dm->entries);
1176  vnet_send_dns_request (dm, next_ep);
1177  return (1);
1178 }
1179 
1180 int
1183  u32 * min_ttlp)
1184 {
1185  dns_header_t *h;
1186  dns_query_t *qp;
1187  dns_rr_t *rr;
1188  int i, limit;
1189  u8 len;
1190  u8 *curpos, *pos, *pos2;
1191  u16 flags;
1192  u16 rcode;
1193  u32 ttl;
1194  int pointer_chase;
1195 
1196  h = (dns_header_t *) response;
1197  flags = clib_net_to_host_u16 (h->flags);
1198  rcode = flags & DNS_RCODE_MASK;
1199 
1200  /* See if the response is OK, etc. */
1201  switch (rcode)
1202  {
1203  default:
1204  case DNS_RCODE_NO_ERROR:
1205  break;
1206 
1207  case DNS_RCODE_NAME_ERROR:
1209  return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1210 
1213  case DNS_RCODE_REFUSED:
1214  return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1215  }
1216 
1217  /* No answers? Loser... */
1218  if (clib_net_to_host_u16 (h->anscount) < 1)
1219  return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1220 
1221  curpos = (u8 *) (h + 1);
1222 
1223  /* Skip the name we asked about */
1224  pos = curpos;
1225  len = *pos++;
1226  /* Should never happen, but stil... */
1227  if ((len & 0xC0) == 0xC0)
1228  curpos += 2;
1229  else
1230  {
1231  /* skip the name / label-set */
1232  while (len)
1233  {
1234  pos += len;
1235  len = *pos++;
1236  }
1237  curpos = pos;
1238  }
1239  /* Skip queries */
1240  limit = clib_net_to_host_u16 (h->qdcount);
1241  qp = (dns_query_t *) curpos;
1242  qp += limit;
1243  curpos = (u8 *) qp;
1244 
1245  /* Parse answers */
1246  limit = clib_net_to_host_u16 (h->anscount);
1247 
1248  for (i = 0; i < limit; i++)
1249  {
1250  pos = pos2 = curpos;
1251  pointer_chase = 0;
1252 
1253  /* Expect pointer chases in the answer section... */
1254  if ((pos2[0] & 0xC0) == 0xC0)
1255  {
1256  pos = pos2 + 2;
1257  pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1258  pointer_chase = 1;
1259  }
1260 
1261  len = *pos2++;
1262 
1263  while (len)
1264  {
1265  pos2 += len;
1266  if ((pos2[0] & 0xc0) == 0xc0)
1267  {
1268  /*
1269  * If we've already done one pointer chase,
1270  * do not move the pos pointer.
1271  */
1272  if (pointer_chase == 0)
1273  pos = pos2 + 2;
1274  pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1275  len = *pos2++;
1276  pointer_chase = 1;
1277  }
1278  else
1279  len = *pos2++;
1280  }
1281 
1282  if (pointer_chase == 0)
1283  pos = pos2;
1284 
1285  rr = (dns_rr_t *) pos;
1286 
1287  switch (clib_net_to_host_u16 (rr->type))
1288  {
1289  case DNS_TYPE_A:
1290  /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1291  memcpy (rmp->ip4_address, rr->rdata, sizeof (ip4_address_t));
1292  rmp->ip4_set = 1;
1293  ttl = clib_net_to_host_u32 (rr->ttl);
1294  if (min_ttlp && *min_ttlp > ttl)
1295  *min_ttlp = ttl;
1296  break;
1297  case DNS_TYPE_AAAA:
1298  /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1299  memcpy (rmp->ip6_address, rr->rdata, sizeof (ip6_address_t));
1300  ttl = clib_net_to_host_u32 (rr->ttl);
1301  if (min_ttlp && *min_ttlp > ttl)
1302  *min_ttlp = ttl;
1303  rmp->ip6_set = 1;
1304  break;
1305 
1306  default:
1307  break;
1308  }
1309  /* Might as well stop ASAP */
1310  if (rmp->ip4_set && rmp->ip6_set)
1311  break;
1312  pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1313  curpos = pos;
1314  }
1315 
1316  if ((rmp->ip4_set + rmp->ip6_set) == 0)
1317  return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1318  return 0;
1319 }
1320 
1321 int
1324  u32 * min_ttlp)
1325 {
1326  dns_header_t *h;
1327  dns_query_t *qp;
1328  dns_rr_t *rr;
1329  int i, limit;
1330  u8 len;
1331  u8 *curpos, *pos, *pos2;
1332  u16 flags;
1333  u16 rcode;
1334  u8 *name;
1335  u32 ttl;
1336  u8 *junk __attribute__ ((unused));
1337  int name_set = 0;
1338  int pointer_chase;
1339 
1340  h = (dns_header_t *) response;
1341  flags = clib_net_to_host_u16 (h->flags);
1342  rcode = flags & DNS_RCODE_MASK;
1343 
1344  /* See if the response is OK, etc. */
1345  switch (rcode)
1346  {
1347  default:
1348  case DNS_RCODE_NO_ERROR:
1349  break;
1350 
1351  case DNS_RCODE_NAME_ERROR:
1353  return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1354 
1357  case DNS_RCODE_REFUSED:
1358  return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1359  }
1360 
1361  /* No answers? Loser... */
1362  if (clib_net_to_host_u16 (h->anscount) < 1)
1363  return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1364 
1365  curpos = (u8 *) (h + 1);
1366 
1367  /* Skip the name we asked about */
1368  pos = curpos;
1369  len = *pos++;
1370  /* Should never happen, but stil... */
1371  if ((len & 0xC0) == 0xC0)
1372  curpos += 2;
1373  else
1374  {
1375  /* skip the name / label-set */
1376  while (len)
1377  {
1378  pos += len;
1379  len = *pos++;
1380  }
1381  curpos = pos;
1382  }
1383  /* Skip queries */
1384  limit = clib_net_to_host_u16 (h->qdcount);
1385  qp = (dns_query_t *) curpos;
1386  qp += limit;
1387  curpos = (u8 *) qp;
1388 
1389  /* Parse answers */
1390  limit = clib_net_to_host_u16 (h->anscount);
1391 
1392  for (i = 0; i < limit; i++)
1393  {
1394  pos = pos2 = curpos;
1395  pointer_chase = 0;
1396 
1397  /* Expect pointer chases in the answer section... */
1398  if ((pos2[0] & 0xC0) == 0xC0)
1399  {
1400  pos = pos2 + 2;
1401  pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1402  pointer_chase = 1;
1403  }
1404 
1405  len = *pos2++;
1406 
1407  while (len)
1408  {
1409  pos2 += len;
1410  if ((pos2[0] & 0xc0) == 0xc0)
1411  {
1412  /*
1413  * If we've already done one pointer chase,
1414  * do not move the pos pointer.
1415  */
1416  if (pointer_chase == 0)
1417  pos = pos2 + 2;
1418  pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1419  len = *pos2++;
1420  pointer_chase = 1;
1421  }
1422  else
1423  len = *pos2++;
1424  }
1425 
1426  if (pointer_chase == 0)
1427  pos = pos2;
1428 
1429  rr = (dns_rr_t *) pos;
1430 
1431  switch (clib_net_to_host_u16 (rr->type))
1432  {
1433  case DNS_TYPE_PTR:
1434  name = vnet_dns_labels_to_name (rr->rdata, response, &junk);
1435  memcpy (rmp->name, name, vec_len (name));
1436  ttl = clib_net_to_host_u32 (rr->ttl);
1437  if (min_ttlp)
1438  *min_ttlp = ttl;
1439  rmp->name[vec_len (name)] = 0;
1440  name_set = 1;
1441  break;
1442  default:
1443  break;
1444  }
1445  /* Might as well stop ASAP */
1446  if (name_set == 1)
1447  break;
1448  pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1449  curpos = pos;
1450  }
1451 
1452  if (name_set == 0)
1453  return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1454  return 0;
1455 }
1456 
1457 static void
1459 {
1460  dns_main_t *dm = &dns_main;
1462  dns_cache_entry_t *ep;
1463  dns_pending_request_t _t0, *t0 = &_t0;
1464  int rv;
1465 
1466  /* Sanitize the name slightly */
1467  mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1468 
1470  t0->client_index = mp->client_index;
1471  t0->client_context = mp->context;
1472 
1473  rv = vnet_dns_resolve_name (dm, mp->name, t0, &ep);
1474 
1475  /* Error, e.g. not enabled? Tell the user */
1476  if (rv < 0)
1477  {
1478  REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1479  return;
1480  }
1481 
1482  /* Resolution pending? Don't reply... */
1483  if (ep == 0)
1484  return;
1485 
1486  /* *INDENT-OFF* */
1487  REPLY_MACRO2(VL_API_DNS_RESOLVE_NAME_REPLY,
1488  ({
1489  rv = vnet_dns_response_to_reply (ep->dns_response, rmp, 0 /* ttl-ptr */);
1490  rmp->retval = clib_host_to_net_u32 (rv);
1491  }));
1492  /* *INDENT-ON* */
1493 
1494  /*
1495  * dns_resolve_name leaves the cache locked when it returns
1496  * a cached result, so unlock it here.
1497  */
1498  dns_cache_unlock (dm);
1499 }
1500 
1501 static void
1503 {
1504  dns_main_t *dm = &dns_main;
1506  dns_cache_entry_t *ep;
1507  int rv;
1508  int i, len;
1509  u8 *lookup_name = 0;
1510  u8 digit, nybble;
1511  dns_pending_request_t _t0, *t0 = &_t0;
1512 
1513  if (mp->is_ip6)
1514  {
1515  for (i = 15; i >= 0; i--)
1516  {
1517  digit = mp->address[i];
1518  nybble = (digit & 0x0F);
1519  if (nybble > 9)
1520  vec_add1 (lookup_name, (nybble - 10) + 'a');
1521  else
1522  vec_add1 (lookup_name, nybble + '0');
1523  vec_add1 (lookup_name, '.');
1524  nybble = (digit & 0xF0) >> 4;
1525  if (nybble > 9)
1526  vec_add1 (lookup_name, (nybble - 10) + 'a');
1527  else
1528  vec_add1 (lookup_name, nybble + '0');
1529  vec_add1 (lookup_name, '.');
1530  }
1531  len = vec_len (lookup_name);
1532  vec_validate (lookup_name, len + 8);
1533  memcpy (lookup_name + len, "ip6.arpa", 8);
1534  }
1535  else
1536  {
1537  for (i = 3; i >= 0; i--)
1538  {
1539  digit = mp->address[i];
1540  lookup_name = format (lookup_name, "%d.", digit);
1541  }
1542  lookup_name = format (lookup_name, "in-addr.arpa");
1543  }
1544 
1545  vec_add1 (lookup_name, 0);
1546 
1548  t0->client_index = mp->client_index;
1549  t0->client_context = mp->context;
1550 
1551  rv = vnet_dns_resolve_name (dm, lookup_name, t0, &ep);
1552 
1553  vec_free (lookup_name);
1554 
1555  /* Error, e.g. not enabled? Tell the user */
1556  if (rv < 0)
1557  {
1558  REPLY_MACRO (VL_API_DNS_RESOLVE_IP_REPLY);
1559  return;
1560  }
1561 
1562  /* Resolution pending? Don't reply... */
1563  if (ep == 0)
1564  return;
1565 
1566  /* *INDENT-OFF* */
1567  REPLY_MACRO2(VL_API_DNS_RESOLVE_IP_REPLY,
1568  ({
1569  rv = vnet_dns_response_to_name (ep->dns_response, rmp, 0 /* ttl-ptr */);
1570  rmp->retval = clib_host_to_net_u32 (rv);
1571  }));
1572  /* *INDENT-ON* */
1573 
1574  /*
1575  * vnet_dns_resolve_name leaves the cache locked when it returns
1576  * a cached result, so unlock it here.
1577  */
1578  dns_cache_unlock (dm);
1579 }
1580 
1581 #define vl_msg_name_crc_list
1582 #include <dns/dns_all_api_h.h>
1583 #undef vl_msg_name_crc_list
1584 
1585 static void
1587 {
1588 #define _(id,n,crc) \
1589  vl_msg_api_add_msg_name_crc (dm->api_main, #n "_" #crc, dm->msg_id_base + id);
1590  foreach_vl_msg_name_crc_dns;
1591 #undef _
1592 }
1593 
1594 #define foreach_dns_plugin_api_msg \
1595 _(DNS_ENABLE_DISABLE, dns_enable_disable) \
1596 _(DNS_NAME_SERVER_ADD_DEL, dns_name_server_add_del) \
1597 _(DNS_RESOLVE_NAME, dns_resolve_name) \
1598 _(DNS_RESOLVE_IP, dns_resolve_ip)
1599 
1600 static clib_error_t *
1602 {
1603  dns_main_t *dm = &dns_main;
1604 
1605  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1606  {
1607  if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1608  ;
1609  else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1610  ;
1611  else
1612  return clib_error_return (0, "unknown input `%U'",
1613  format_unformat_error, input);
1614  }
1615  return 0;
1616 }
1617 
1619 
1620 uword
1621 unformat_dns_reply (unformat_input_t * input, va_list * args)
1622 {
1623  u8 **result = va_arg (*args, u8 **);
1624  u8 **namep = va_arg (*args, u8 **);
1625  ip4_address_t a4;
1626  ip6_address_t a6;
1627  int a4_set = 0;
1628  int a6_set = 0;
1629  u8 *name;
1630  int name_set = 0;
1631  u8 *ce;
1632  u32 qp_offset;
1633  dns_header_t *h;
1634  dns_query_t *qp;
1635  dns_rr_t *rr;
1636  u8 *rru8;
1637 
1638  if (unformat (input, "%v", &name))
1639  name_set = 1;
1640 
1641  if (unformat (input, "%U", unformat_ip4_address, &a4))
1642  {
1643  a4_set = 1;
1644  if (unformat (input, "%U", unformat_ip6_address, &a6))
1645  a6_set = 1;
1646  }
1647 
1648  if (unformat (input, "%U", unformat_ip6_address, &a6))
1649  {
1650  a6_set = 1;
1651  if (unformat (input, "%U", unformat_ip4_address, &a6))
1652  a4_set = 1;
1653  }
1654 
1655  /* Must have a name */
1656  if (!name_set)
1657  return 0;
1658 
1659  /* Must have at least one address */
1660  if (!(a4_set + a6_set))
1661  return 0;
1662 
1663  /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1664  ce = name_to_labels (name);
1665  qp_offset = vec_len (ce);
1666 
1667  /* Add space for the query header */
1668  vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1669  qp = (dns_query_t *) (ce + qp_offset);
1670 
1671  qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1672  qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1673 
1674  /* Punch in space for the dns_header_t */
1675  vec_insert (ce, sizeof (dns_header_t), 0);
1676 
1677  h = (dns_header_t *) ce;
1678 
1679  /* Fake Transaction ID */
1680  h->id = 0xFFFF;
1681 
1682  h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1683  h->qdcount = clib_host_to_net_u16 (1);
1684  h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1685  h->nscount = 0;
1686  h->arcount = 0;
1687 
1688  /* Now append one or two A/AAAA RR's... */
1689  if (a4_set)
1690  {
1691  /* Pointer to the name (DGMS) */
1692  vec_add1 (ce, 0xC0);
1693  vec_add1 (ce, 0x0C);
1694  vec_add2 (ce, rru8, sizeof (*rr) + 4);
1695  rr = (void *) rru8;
1696  rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1697  rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1698  rr->ttl = clib_host_to_net_u32 (86400);
1699  rr->rdlength = clib_host_to_net_u16 (4);
1700  memcpy (rr->rdata, &a4, sizeof (a4));
1701  }
1702  if (a6_set)
1703  {
1704  /* Pointer to the name (DGMS) */
1705  vec_add1 (ce, 0xC0);
1706  vec_add1 (ce, 0x0C);
1707  vec_add2 (ce, rru8, sizeof (*rr) + 16);
1708  rr = (void *) rru8;
1709  rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1710  rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1711  rr->ttl = clib_host_to_net_u32 (86400);
1712  rr->rdlength = clib_host_to_net_u16 (16);
1713  memcpy (rr->rdata, &a6, sizeof (a6));
1714  }
1715  *result = ce;
1716  if (namep)
1717  *namep = name;
1718  else
1719  vec_free (name);
1720 
1721  return 1;
1722 }
1723 
1724 u8 *
1725 format_dns_query (u8 * s, va_list * args)
1726 {
1727  u8 **curpos = va_arg (*args, u8 **);
1728  int verbose = va_arg (*args, int);
1729  u8 *pos;
1730  dns_query_t *qp;
1731  int len, i;
1732  if (verbose > 1)
1733  s = format (s, " Name: ");
1734 
1735  /* Unwind execrated counted-label sheit */
1736  pos = *curpos;
1737  len = *pos++;
1738 
1739  while (len)
1740  {
1741  for (i = 0; i < len; i++)
1742  vec_add1 (s, *pos++);
1743 
1744  len = *pos++;
1745  if (len)
1746  vec_add1 (s, '.');
1747  else
1748  {
1749  vec_add1 (s, ':');
1750  vec_add1 (s, ' ');
1751  }
1752  }
1753 
1754  qp = (dns_query_t *) pos;
1755  if (verbose > 1)
1756  {
1757  switch (clib_net_to_host_u16 (qp->type))
1758  {
1759  case DNS_TYPE_A:
1760  s = format (s, "type A\n");
1761  break;
1762  case DNS_TYPE_AAAA:
1763  s = format (s, "type AAAA\n");
1764  break;
1765  case DNS_TYPE_ALL:
1766  s = format (s, "type ALL\n");
1767  break;
1768 
1769  default:
1770  s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1771  break;
1772  }
1773  }
1774 
1775  pos += sizeof (*qp);
1776 
1777  *curpos = pos;
1778  return s;
1779 }
1780 
1781 /**
1782  * format dns reply data
1783  * verbose > 1, dump everything
1784  * verbose == 1, dump all A and AAAA records
1785  * verbose == 0, dump one A record, and one AAAA record
1786  */
1787 
1788 u8 *
1789 format_dns_reply_data (u8 * s, va_list * args)
1790 {
1791  u8 *reply = va_arg (*args, u8 *);
1792  u8 **curpos = va_arg (*args, u8 **);
1793  int verbose = va_arg (*args, int);
1794  int *print_ip4 = va_arg (*args, int *);
1795  int *print_ip6 = va_arg (*args, int *);
1796  int len;
1797  u8 *pos, *pos2;
1798  dns_rr_t *rr;
1799  int i;
1800  int pointer_chase = 0;
1801  u16 *tp;
1802  u16 rrtype_host_byte_order;
1803 
1804  pos = pos2 = *curpos;
1805 
1806  if (verbose > 1)
1807  s = format (s, " ");
1808 
1809  /* chase pointer? almost always yes here... */
1810  if ((pos2[0] & 0xc0) == 0xc0)
1811  {
1812  pos = pos2 + 2;
1813  pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1814  pointer_chase = 1;
1815  }
1816 
1817  len = *pos2++;
1818 
1819  while (len)
1820  {
1821  for (i = 0; i < len; i++)
1822  {
1823  if (verbose > 1)
1824  vec_add1 (s, *pos2);
1825  pos2++;
1826  }
1827  if ((pos2[0] & 0xc0) == 0xc0)
1828  {
1829  /*
1830  * If we've already done one pointer chase,
1831  * do not move the pos pointer.
1832  */
1833  if (pointer_chase == 0)
1834  pos = pos2 + 2;
1835  pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1836  len = *pos2++;
1837  pointer_chase = 1;
1838  }
1839  else
1840  len = *pos2++;
1841  if (len)
1842  {
1843  if (verbose > 1)
1844  vec_add1 (s, '.');
1845  }
1846  else
1847  {
1848  if (verbose > 1)
1849  vec_add1 (s, ' ');
1850  }
1851  }
1852 
1853  if (pointer_chase == 0)
1854  pos = pos2;
1855 
1856  rr = (dns_rr_t *) pos;
1857  rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
1858 
1859  switch (rrtype_host_byte_order)
1860  {
1861  case DNS_TYPE_A:
1862  if (verbose > 1)
1863  {
1864  s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1865  format_ip4_address, rr->rdata);
1866  }
1867  else
1868  {
1869  if (*print_ip4)
1870  s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1871  clib_net_to_host_u32 (rr->ttl));
1872  if (verbose == 0)
1873  *print_ip4 = 0;
1874 
1875  }
1876  pos += sizeof (*rr) + 4;
1877  break;
1878 
1879  case DNS_TYPE_AAAA:
1880  if (verbose > 1)
1881  {
1882  s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1883  format_ip6_address, rr->rdata);
1884  }
1885  else
1886  {
1887  if (*print_ip6)
1888  s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1889  clib_net_to_host_u32 (rr->ttl));
1890  if (verbose == 0)
1891  *print_ip6 = 0;
1892  }
1893  pos += sizeof (*rr) + 16;
1894  break;
1895 
1896  case DNS_TYPE_TEXT:
1897  if (verbose > 1)
1898  {
1899  s = format (s, "TEXT: ");
1900  for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1901  vec_add1 (s, rr->rdata[i]);
1902  vec_add1 (s, '\n');
1903  }
1904  pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1905  break;
1906 
1907  case DNS_TYPE_HINFO:
1908  {
1909  /* Two counted strings. DGMS */
1910  u8 *len;
1911  u8 *curpos;
1912  int i;
1913  if (verbose > 1)
1914  {
1915  s = format (s, "HINFO: ");
1916  len = rr->rdata;
1917  curpos = len + 1;
1918  for (i = 0; i < *len; i++)
1919  vec_add1 (s, *curpos++);
1920 
1921  vec_add1 (s, ' ');
1922  len = curpos++;
1923  for (i = 0; i < *len; i++)
1924  vec_add1 (s, *curpos++);
1925 
1926  vec_add1 (s, '\n');
1927  }
1928  }
1929  pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1930  break;
1931 
1932  case DNS_TYPE_NAMESERVER:
1933  if (verbose > 1)
1934  {
1935  s = format (s, "Nameserver: ");
1936  pos2 = rr->rdata;
1937 
1938  /* chase pointer? */
1939  if ((pos2[0] & 0xc0) == 0xc0)
1940  {
1941  pos = pos2 + 2;
1942  pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1943  }
1944 
1945  len = *pos2++;
1946 
1947  while (len)
1948  {
1949  for (i = 0; i < len; i++)
1950  vec_add1 (s, *pos2++);
1951 
1952  /* chase pointer, typically to offset 12... */
1953  if (pos2[0] == 0xC0)
1954  pos2 = reply + pos2[1];
1955 
1956  len = *pos2++;
1957  if (len)
1958  vec_add1 (s, '.');
1959  else
1960  vec_add1 (s, '\n');
1961  }
1962  }
1963  pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1964  break;
1965 
1966  case DNS_TYPE_MAIL_EXCHANGE:
1967  if (verbose > 1)
1968  {
1969  tp = (u16 *) rr->rdata;
1970 
1971  s = format (s, "Mail Exchange: Preference %d ", (u32)
1972  clib_net_to_host_u16 (*tp));
1973 
1974  pos2 = rr->rdata + 2;
1975 
1976  /* chase pointer? */
1977  if (pos2[0] == 0xc0)
1978  pos2 = reply + pos2[1];
1979 
1980  len = *pos2++;
1981 
1982  while (len)
1983  {
1984  for (i = 0; i < len; i++)
1985  vec_add1 (s, *pos2++);
1986 
1987  /* chase pointer */
1988  if (pos2[0] == 0xC0)
1989  pos2 = reply + pos2[1];
1990 
1991  len = *pos2++;
1992  if (len)
1993  vec_add1 (s, '.');
1994  else
1995  vec_add1 (s, '\n');
1996  }
1997  }
1998 
1999  pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2000  break;
2001 
2002  case DNS_TYPE_PTR:
2003  case DNS_TYPE_CNAME:
2004  if (verbose > 1)
2005  {
2006  tp = (u16 *) rr->rdata;
2007 
2008  if (rrtype_host_byte_order == DNS_TYPE_CNAME)
2009  s = format (s, "CNAME: ");
2010  else
2011  s = format (s, "PTR: ");
2012 
2013  pos2 = rr->rdata;
2014 
2015  /* chase pointer? */
2016  if (pos2[0] == 0xc0)
2017  pos2 = reply + pos2[1];
2018 
2019  len = *pos2++;
2020 
2021  while (len)
2022  {
2023  for (i = 0; i < len; i++)
2024  vec_add1 (s, *pos2++);
2025 
2026  /* chase pointer */
2027  if (pos2[0] == 0xC0)
2028  pos2 = reply + pos2[1];
2029 
2030  len = *pos2++;
2031  if (len)
2032  vec_add1 (s, '.');
2033  else
2034  vec_add1 (s, '\n');
2035  }
2036  }
2037  pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2038  break;
2039 
2040  default:
2041  if (verbose > 1)
2042  s = format (s, "type %d: len %d\n",
2043  (int) clib_net_to_host_u16 (rr->type),
2044  sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
2045  pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2046  break;
2047  }
2048 
2049  *curpos = pos;
2050 
2051  return s;
2052 }
2053 
2054 u8 *
2055 format_dns_reply (u8 * s, va_list * args)
2056 {
2057  u8 *reply_as_u8 = va_arg (*args, u8 *);
2058  int verbose = va_arg (*args, int);
2059  dns_header_t *h;
2060  u16 id, flags;
2061  u8 *curpos;
2062  int i;
2063  int print_ip4 = 1;
2064  int print_ip6 = 1;
2065 
2066  h = (dns_header_t *) reply_as_u8;
2067  id = clib_net_to_host_u16 (h->id);
2068  flags = clib_net_to_host_u16 (h->flags);
2069 
2070  if (verbose > 1)
2071  {
2072  s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
2073  id);
2074  s = format (s, " %s %s %s %s\n",
2075  (flags & DNS_RA) ? "recur" : "no-recur",
2076  (flags & DNS_RD) ? "recur-des" : "no-recur-des",
2077  (flags & DNS_TC) ? "trunc" : "no-trunc",
2078  (flags & DNS_AA) ? "auth" : "non-auth");
2079  s = format (s, " %d queries, %d answers, %d name-servers,"
2080  " %d add'l recs\n",
2081  clib_net_to_host_u16 (h->qdcount),
2082  clib_net_to_host_u16 (h->anscount),
2083  clib_net_to_host_u16 (h->nscount),
2084  clib_net_to_host_u16 (h->arcount));
2085  }
2086 
2087  curpos = (u8 *) (h + 1);
2088 
2089  if (h->qdcount)
2090  {
2091  if (verbose > 1)
2092  s = format (s, " Queries:\n");
2093  for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
2094  {
2095  /* The query is variable-length, so curpos is a value-result parm */
2096  s = format (s, "%U", format_dns_query, &curpos, verbose);
2097  }
2098  }
2099  if (h->anscount)
2100  {
2101  if (verbose > 1)
2102  s = format (s, " Replies:\n");
2103 
2104  for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
2105  {
2106  /* curpos is a value-result parm */
2107  s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
2108  verbose, &print_ip4, &print_ip6);
2109  }
2110  }
2111  return s;
2112 }
2113 
2114 u8 *
2115 format_dns_cache (u8 * s, va_list * args)
2116 {
2117  dns_main_t *dm = va_arg (*args, dns_main_t *);
2118  f64 now = va_arg (*args, f64);
2119  int verbose = va_arg (*args, int);
2120  u8 *name = va_arg (*args, u8 *);
2121  dns_cache_entry_t *ep;
2122  char *ss;
2123  uword *p;
2124 
2125  if (dm->is_enabled == 0)
2126  {
2127  s = format (s, "The DNS cache is disabled...");
2128  return s;
2129  }
2130 
2131  if (pool_elts (dm->entries) == 0)
2132  {
2133  s = format (s, "The DNS cache is empty...");
2134  return s;
2135  }
2136 
2137  dns_cache_lock (dm, 6);
2138 
2139  if (name)
2140  {
2141  p = hash_get_mem (dm->cache_entry_by_name, name);
2142  if (!p)
2143  {
2144  s = format (s, "%s is not in the cache...", name);
2145  dns_cache_unlock (dm);
2146  return (s);
2147  }
2148 
2149  ep = pool_elt_at_index (dm->entries, p[0]);
2150  /* Magic to spit out a C-initializer to research hemorrhoids... */
2151  if (verbose == 3)
2152  {
2153  int i, j;
2154  s = format (s, "static u8 dns_reply_data_initializer[] =\n");
2155  s = format (s, "{\n");
2156  j = 0;
2157  for (i = 0; i < vec_len (ep->dns_response); i++)
2158  {
2159  if (j++ == 8)
2160  {
2161  j = 0;
2162  vec_add1 (s, '\n');
2163  }
2164  s = format (s, "0x%02x, ", ep->dns_response[i]);
2165  }
2166  s = format (s, "};\n");
2167  }
2168  else
2169  {
2171  {
2172  ASSERT (ep->dns_response);
2174  ss = "[S] ";
2175  else
2176  ss = " ";
2177 
2178  if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2179  s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2180  else
2181  s = format (s, "%s%s -> %U", ss, ep->name,
2182  format_dns_reply, ep->dns_response, verbose);
2183  if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2184  {
2185  f64 time_left = ep->expiration_time - now;
2186  if (time_left > 0.0)
2187  s = format (s, " TTL left %.1f", time_left);
2188  else
2189  s = format (s, " EXPIRED");
2190  }
2191  }
2192  else
2193  {
2194  ASSERT (ep->dns_request);
2195  s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2196  verbose);
2197  }
2198  vec_add1 (s, '\n');
2199  }
2200  return s;
2201  }
2202 
2203  s = format (s, "DNS cache contains %d entries\n", pool_elts (dm->entries));
2204 
2205  if (verbose > 0)
2206  {
2207  /* *INDENT-OFF* */
2208  pool_foreach (ep, dm->entries,
2209  ({
2210  if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2211  {
2212  ASSERT (ep->dns_response);
2213  if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2214  ss = "[S] ";
2215  else
2216  ss = " ";
2217 
2218  if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2219  s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2220  else
2221  s = format (s, "%s%s -> %U", ss, ep->name,
2222  format_dns_reply,
2223  ep->dns_response,
2224  verbose);
2225  if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2226  {
2227  f64 time_left = ep->expiration_time - now;
2228  if (time_left > 0.0)
2229  s = format (s, " TTL left %.1f", time_left);
2230  else
2231  s = format (s, " EXPIRED");
2232 
2233  if (verbose > 2)
2234  s = format (s, " %d client notifications pending\n",
2235  vec_len(ep->pending_requests));
2236  }
2237  }
2238  else
2239  {
2240  ASSERT (ep->dns_request);
2241  s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2242  verbose);
2243  }
2244  vec_add1 (s, '\n');
2245  }));
2246  /* *INDENT-ON* */
2247  }
2248 
2249  dns_cache_unlock (dm);
2250 
2251  return s;
2252 }
2253 
2254 static clib_error_t *
2256  unformat_input_t * input, vlib_cli_command_t * cmd)
2257 {
2258  dns_main_t *dm = &dns_main;
2259  int verbose = 0;
2260  u8 *name = 0;
2261  f64 now = vlib_time_now (vm);
2262 
2263  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2264  {
2265  if (unformat (input, "verbose %d", &verbose))
2266  ;
2267  else if (unformat (input, "verbose"))
2268  verbose = 1;
2269  else if (unformat (input, "name %s", &name))
2270  ;
2271  else
2272  return clib_error_return (0, "unknown input `%U'",
2273  format_unformat_error, input);
2274  }
2275 
2276  vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
2277 
2278  return 0;
2279 }
2280 
2281 /* *INDENT-OFF* */
2282 VLIB_CLI_COMMAND (show_dns_cache_command) =
2283 {
2284  .path = "show dns cache",
2285  .short_help = "show dns cache [verbose [nn]]",
2286  .function = show_dns_cache_command_fn,
2287 };
2288 /* *INDENT-ON* */
2289 
2290 static clib_error_t *
2292  unformat_input_t * input,
2293  vlib_cli_command_t * cmd)
2294 {
2295  dns_main_t *dm = &dns_main;
2296  int i;
2297 
2298  if ((vec_len (dm->ip4_name_servers) + vec_len (dm->ip6_name_servers)) == 0)
2299  return clib_error_return (0, "No name servers configured...");
2300 
2301  if (vec_len (dm->ip4_name_servers))
2302  {
2303  vlib_cli_output (vm, "ip4 name servers:");
2304  for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
2306  dm->ip4_name_servers + i);
2307  }
2308  if (vec_len (dm->ip6_name_servers))
2309  {
2310  vlib_cli_output (vm, "ip6 name servers:");
2311  for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
2313  dm->ip4_name_servers + i);
2314  }
2315  return 0;
2316 }
2317 
2318 /* *INDENT-OFF* */
2319 VLIB_CLI_COMMAND (show_dns_server_command) =
2320 {
2321  .path = "show dns servers",
2322  .short_help = "show dns servers",
2323  .function = show_dns_servers_command_fn,
2324 };
2325 /* *INDENT-ON* */
2326 
2327 
2328 static clib_error_t *
2330  unformat_input_t * input,
2331  vlib_cli_command_t * cmd)
2332 {
2333  dns_main_t *dm = &dns_main;
2334  u8 *dns_reply_data;
2335  u8 *name;
2336  int is_add = -1;
2337  int is_clear = -1;
2338  int rv;
2339  clib_error_t *error;
2340 
2341  if (unformat (input, "add"))
2342  is_add = 1;
2343  if (unformat (input, "del"))
2344  is_add = 0;
2345  if (unformat (input, "clear"))
2346  is_clear = 1;
2347 
2348  if (is_add == -1 && is_clear == -1)
2349  return clib_error_return (0, "add / del / clear required...");
2350 
2351  if (is_clear == 1)
2352  {
2353  rv = dns_cache_clear (dm);
2354  switch (rv)
2355  {
2356  case 0:
2357  return 0;
2358 
2359  case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2360  error = clib_error_return (0, "Name resolution not enabled");
2361  return error;
2362  }
2363  }
2364 
2365  /* Delete (by name)? */
2366  if (is_add == 0)
2367  {
2368  if (unformat (input, "%v", &name))
2369  {
2370  rv = dns_delete_by_name (dm, name);
2371  switch (rv)
2372  {
2373  case VNET_API_ERROR_NO_SUCH_ENTRY:
2374  error = clib_error_return (0, "%v not in the cache...", name);
2375  vec_free (name);
2376  return error;
2377 
2378  case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2379  error = clib_error_return (0, "Name resolution not enabled");
2380  vec_free (name);
2381  return error;
2382 
2383  case 0:
2384  vec_free (name);
2385  return 0;
2386 
2387  default:
2388  error = clib_error_return (0, "dns_delete_by_name returned %d",
2389  rv);
2390  vec_free (name);
2391  return error;
2392  }
2393  }
2394  return clib_error_return (0, "unknown input `%U'",
2395  format_unformat_error, input);
2396  }
2397 
2398  /* Note: dns_add_static_entry consumes the name vector if OK... */
2399  if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2400  {
2401  rv = dns_add_static_entry (dm, name, dns_reply_data);
2402  switch (rv)
2403  {
2404  case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2405  vec_free (name);
2406  vec_free (dns_reply_data);
2407  return clib_error_return (0, "%v already in the cache...", name);
2408  case 0:
2409  return 0;
2410 
2411  default:
2412  return clib_error_return (0, "dns_add_static_entry returned %d",
2413  rv);
2414  }
2415  }
2416 
2417  return 0;
2418 }
2419 
2420 /* *INDENT-OFF* */
2421 VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2422 {
2423  .path = "dns cache",
2424  .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2425  .function = dns_cache_add_del_command_fn,
2426 };
2427 /* *INDENT-ON* */
2428 
2429 #define DNS_FORMAT_TEST 1
2430 
2431 #if DNS_FORMAT_TEST > 0
2432 #if 0
2433 /* yahoo.com */
2434 static u8 dns_reply_data_initializer[] =
2435  { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2436  0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2437  0x0, /* null lbl */
2438  0x0, 0xff, /* type ALL */
2439  0x0, 0x1, /* class IN */
2440  0xc0, 0xc, /* pointer to yahoo.com name */
2441  0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2442  0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2443  0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2444  0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2445  0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2446  0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2447  0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2448  0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2449  0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2450  0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2451  0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2452  0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2453  0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2454  0x6e,
2455  0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2456  0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2457  0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2458  0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2459  0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2460  0x0,
2461  0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2462  0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2463  0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2464  0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2465  0x0,
2466  0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2467  0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2468  0x0,
2469  0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2470  0x0,
2471  0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2472  0x0,
2473  0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2474  0x6f,
2475  0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2476  0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2477  0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2478  0x2, 0x58
2479 };
2480 
2481 /* www.cisco.com, has no addresses in reply */
2482 static u8 dns_reply_data_initializer[] = {
2483  0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2484  0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2485  0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2486 
2487  0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2488  0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2489  0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2490  0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2491  0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2492 };
2493 
2494 /* bind8 (linux widget, w/ nasty double pointer chasees */
2495 static u8 dns_reply_data_initializer[] = {
2496  /* 0 */
2497  0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08,
2498  /* 8 */
2499  0x00, 0x06, 0x00, 0x06, 0x0a, 0x6f, 0x72, 0x69,
2500  /* 16 */
2501  0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77, 0x77, 0x05,
2502  /* 24 */
2503  0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f,
2504  /* 32 */
2505  0x6d, 0x00, 0x00, 0xff, 0x00, 0x01, 0x0a, 0x6f,
2506  /* 40 */
2507  0x72, 0x69, 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77,
2508  /* 48 */
2509  0x77, 0x05, 0x43, 0x49, 0x53, 0x43, 0x4f, 0xc0,
2510 
2511  /* 56 */
2512  0x1d, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2513 
2514  /* 64 */
2515  0x9a, 0x00, 0x18, 0x15, 0x72, 0x63, 0x64,
2516  0x6e, 0x39, 0x2d, 0x31, 0x34, 0x70, 0x2d, 0x64, 0x63,
2517  0x7a, 0x30, 0x35, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31,
2518  0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00, 0x01, 0x00,
2519  0x00, 0x05, 0x9a, 0x00, 0x1a, 0x17, 0x61, 0x6c, 0x6c,
2520  0x6e, 0x30, 0x31, 0x2d, 0x61, 0x67, 0x30, 0x39, 0x2d,
2521  0x64, 0x63, 0x7a, 0x30, 0x33, 0x6e, 0x2d, 0x67, 0x73,
2522  0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00,
2523  0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x10, 0x0d, 0x72,
2524  0x74, 0x70, 0x35, 0x2d, 0x64, 0x6d, 0x7a, 0x2d, 0x67,
2525  0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2526  0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x18, 0x15,
2527  0x6d, 0x74, 0x76, 0x35, 0x2d, 0x61, 0x70, 0x31, 0x30,
2528  0x2d, 0x64, 0x63, 0x7a, 0x30, 0x36, 0x6e, 0x2d, 0x67,
2529  0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2530  0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x1b, 0x18,
2531  0x73, 0x6e, 0x67, 0x64, 0x63, 0x30, 0x31, 0x2d, 0x61,
2532  0x62, 0x30, 0x37, 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x31,
2533  0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0,
2534  0x26, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a,
2535  0x00, 0x1a, 0x17, 0x61, 0x65, 0x72, 0x30, 0x31, 0x2d,
2536  0x72, 0x34, 0x63, 0x32, 0x35, 0x2d, 0x64, 0x63, 0x7a,
2537  0x30, 0x31, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0,
2538  0x17, 0xc0, 0x26, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2539  0x00, 0x81, 0x00, 0x04, 0x48, 0xa3, 0x04, 0xa1, 0xc0,
2540  0x26, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82,
2541  0x00, 0x10, 0x20, 0x01, 0x04, 0x20, 0x12, 0x01, 0x00,
2542  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
2543  0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2544  0x9a, 0x00, 0x02, 0xc0, 0xf4, 0xc0, 0x0c, 0x00, 0x02,
2545  0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0,
2546  0xcd, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00,
2547  0x05, 0x9a, 0x00, 0x02, 0xc0, 0x8d, 0xc0, 0x0c, 0x00,
2548  0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02,
2549  0xc0, 0x43, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00,
2550  0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0, 0xa9, 0xc0, 0x0c,
2551  0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00,
2552  0x02, 0xc0, 0x67, 0xc0, 0x8d, 0x00, 0x01, 0x00, 0x01,
2553  0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0x40, 0x66, 0xf6,
2554  0x05, 0xc0, 0xa9, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2555  0x07, 0x08, 0x00, 0x04, 0xad, 0x24, 0xe0, 0x64, 0xc0,
2556  0x43, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08,
2557  0x00, 0x04, 0x48, 0xa3, 0x04, 0x1c, 0xc0, 0xf4, 0x00,
2558  0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04,
2559  0xad, 0x26, 0xd4, 0x6c, 0xc0, 0x67, 0x00, 0x01, 0x00,
2560  0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x25,
2561  0x90, 0x64, 0xc0, 0xcd, 0x00, 0x01, 0x00, 0x01, 0x00,
2562  0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x27, 0x70, 0x44,
2563 };
2564 
2565 /* google.com */
2566 static u8 dns_reply_data_initializer[] =
2567  { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
2568  0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
2569  0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
2570  0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
2571  0x2b,
2572  0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
2573  0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
2574  0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
2575  0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
2576  0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
2577  0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
2578  0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
2579  0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
2580  0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
2581  0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
2582  0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
2583  0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
2584  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
2585  0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
2586  0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
2587  0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
2588  0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2589  0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
2590  0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
2591  0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
2592  0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
2593  0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
2594  0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
2595  0x57,
2596  0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2597 };
2598 
2599 #else
2600 /* www.weatherlink.com */
2601 static u8 dns_reply_data_initializer[] = {
2602  0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2603  0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x0b,
2604  0x77, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x6c, 0x69,
2605  0x6e, 0x6b, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0xff,
2606  0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00,
2607  0x00, 0x0c, 0x9e, 0x00, 0x1f, 0x0e, 0x64, 0x33, 0x6b,
2608  0x72, 0x30, 0x67, 0x75, 0x62, 0x61, 0x31, 0x64, 0x76,
2609  0x77, 0x66, 0x0a, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x66,
2610  0x72, 0x6f, 0x6e, 0x74, 0x03, 0x6e, 0x65, 0x74, 0x00,
2611 };
2612 
2613 #endif
2614 
2615 static clib_error_t *
2617  unformat_input_t * input, vlib_cli_command_t * cmd)
2618 {
2619  u8 *dns_reply_data = 0;
2620  int verbose = 0;
2621  int rv;
2622  vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2623 
2624  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2625  {
2626  if (unformat (input, "verbose %d", &verbose))
2627  ;
2628  else if (unformat (input, "verbose"))
2629  verbose = 1;
2630  else
2631  return clib_error_return (0, "unknown input `%U'",
2632  format_unformat_error, input);
2633  }
2634 
2635  vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2636 
2637  memcpy (dns_reply_data, dns_reply_data_initializer,
2638  ARRAY_LEN (dns_reply_data_initializer));
2639 
2640  vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2641 
2642  clib_memset (rmp, 0, sizeof (*rmp));
2643 
2644  rv = vnet_dns_response_to_reply (dns_reply_data, rmp, 0 /* ttl-ptr */ );
2645 
2646  switch (rv)
2647  {
2648  case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2649  vlib_cli_output (vm, "no addresses found...");
2650  break;
2651 
2652  default:
2653  vlib_cli_output (vm, "response to reply returned %d", rv);
2654  break;
2655 
2656  case 0:
2657  if (rmp->ip4_set)
2658  vlib_cli_output (vm, "ip4 address: %U", format_ip4_address,
2659  (ip4_address_t *) rmp->ip4_address);
2660  if (rmp->ip6_set)
2661  vlib_cli_output (vm, "ip6 address: %U", format_ip6_address,
2662  (ip6_address_t *) rmp->ip6_address);
2663  break;
2664  }
2665 
2666  vec_free (dns_reply_data);
2667 
2668  return 0;
2669 }
2670 
2671 
2672 /* *INDENT-OFF* */
2673 VLIB_CLI_COMMAND (test_dns_fmt_command) =
2674 {
2675  .path = "test dns format",
2676  .short_help = "test dns format",
2677  .function = test_dns_fmt_command_fn,
2678 };
2679 /* *INDENT-ON* */
2680 
2681 static clib_error_t *
2683  unformat_input_t * input, vlib_cli_command_t * cmd)
2684 {
2685  u8 *dns_reply_data = 0;
2686  int verbose = 0;
2687  int reply_set = 0;
2688 
2689  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2690  {
2691  if (unformat (input, "verbose %d", &verbose))
2692  ;
2693  else if (unformat (input, "verbose"))
2694  verbose = 1;
2695  else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2696  reply_set = 1;
2697  else
2698  return clib_error_return (0, "unknown input `%U'",
2699  format_unformat_error, input);
2700  }
2701 
2702  if (reply_set == 0)
2703  return clib_error_return (0, "dns data not set...");
2704 
2705  vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2706 
2707  vec_free (dns_reply_data);
2708 
2709  return 0;
2710 }
2711 
2712 /* *INDENT-OFF* */
2713 VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2714 {
2715  .path = "test dns unformat",
2716  .short_help = "test dns unformat <name> [ip4][ip6]",
2717  .function = test_dns_unfmt_command_fn,
2718 };
2719 /* *INDENT-ON* */
2720 
2721 static clib_error_t *
2723  unformat_input_t * input,
2724  vlib_cli_command_t * cmd)
2725 {
2726  dns_main_t *dm = &dns_main;
2727  u8 *name = 0;
2728  uword *p;
2729  clib_error_t *e;
2730  dns_cache_entry_t *ep;
2731 
2732  if (unformat (input, "%v", &name))
2733  {
2734  vec_add1 (name, 0);
2735  _vec_len (name) -= 1;
2736  }
2737  else
2738  return clib_error_return (0, "no name provided");
2739 
2740  dns_cache_lock (dm, 7);
2741 
2742  p = hash_get_mem (dm->cache_entry_by_name, name);
2743  if (!p)
2744  {
2745  dns_cache_unlock (dm);
2746  e = clib_error_return (0, "%s is not in the cache...", name);
2747  vec_free (name);
2748  return e;
2749  }
2750 
2751  ep = pool_elt_at_index (dm->entries, p[0]);
2752 
2753  ep->expiration_time = 0;
2754 
2755  return 0;
2756 }
2757 
2758 /* *INDENT-OFF* */
2759 VLIB_CLI_COMMAND (test_dns_expire_command) =
2760 {
2761  .path = "test dns expire",
2762  .short_help = "test dns expire <name>",
2763  .function = test_dns_expire_command_fn,
2764 };
2765 /* *INDENT-ON* */
2766 #endif
2767 
2768 void
2770  dns_cache_entry_t * ep, vlib_buffer_t * b0)
2771 {
2772  clib_warning ("Unimplemented...");
2773 }
2774 
2775 
2776 void
2778  dns_cache_entry_t * ep, vlib_buffer_t * b0)
2779 {
2780  vlib_main_t *vm = dm->vlib_main;
2781  u32 bi = 0;
2783  fib_node_index_t fei;
2784  u32 sw_if_index, fib_index;
2785  ip4_main_t *im4 = &ip4_main;
2786  ip_lookup_main_t *lm4 = &im4->lookup_main;
2787  ip_interface_address_t *ia = 0;
2789  ip4_header_t *ip;
2790  udp_header_t *udp;
2791  dns_header_t *dh;
2792  vlib_frame_t *f;
2793  u32 *to_next;
2794  u8 *dns_response;
2795  u8 *reply;
2796  vl_api_dns_resolve_name_reply_t _rnr, *rnr = &_rnr;
2797  vl_api_dns_resolve_ip_reply_t _rir, *rir = &_rir;
2798  u32 ttl = 64, tmp;
2799  u32 qp_offset;
2800  dns_query_t *qp;
2801  dns_rr_t *rr;
2802  u8 *rrptr;
2803  int is_fail = 0;
2804  int is_recycle = (b0 != 0);
2805 
2806  ASSERT (ep && ep->dns_response);
2807 
2809  {
2810  /* Quick and dirty way to dig up the A-record address. $$ FIXME */
2811  clib_memset (rnr, 0, sizeof (*rnr));
2812  if (vnet_dns_response_to_reply (ep->dns_response, rnr, &ttl))
2813  {
2814  /* clib_warning ("response_to_reply failed..."); */
2815  is_fail = 1;
2816  }
2817  if (rnr->ip4_set == 0)
2818  {
2819  /* clib_warning ("No A-record..."); */
2820  is_fail = 1;
2821  }
2822  }
2823  else if (pr->request_type == DNS_PEER_PENDING_IP_TO_NAME)
2824  {
2825  clib_memset (rir, 0, sizeof (*rir));
2826  if (vnet_dns_response_to_name (ep->dns_response, rir, &ttl))
2827  {
2828  /* clib_warning ("response_to_name failed..."); */
2829  is_fail = 1;
2830  }
2831  }
2832  else
2833  {
2834  clib_warning ("Unknown request type %d", pr->request_type);
2835  return;
2836  }
2837 
2838  /* Initialize a buffer */
2839  if (b0 == 0)
2840  {
2841  if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2842  return;
2843  b0 = vlib_get_buffer (vm, bi);
2844  }
2845  else
2846  {
2847  /* Use the buffer we were handed. Reinitialize it... */
2848  vlib_buffer_t bt = { };
2849  /* push/pop the reference count */
2850  u8 save_ref_count = b0->ref_count;
2851  vlib_buffer_copy_template (b0, &bt);
2852  b0->ref_count = save_ref_count;
2853  bi = vlib_get_buffer_index (vm, b0);
2854  }
2855 
2856  if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
2858 
2859  /*
2860  * Reset the buffer. We recycle the DNS request packet in the cache
2861  * hit case, and reply immediately from the request node.
2862  *
2863  * In the resolution-required / deferred case, resetting a freshly-allocated
2864  * buffer won't hurt. We hope.
2865  */
2866  b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
2867  | VLIB_BUFFER_TOTAL_LENGTH_VALID);
2868  vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; /* "local0" */
2869  vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
2870 
2871  /* Find a FIB path to the peer we're trying to answer */
2872  clib_memcpy (&prefix.fp_addr.ip4, pr->dst_address, sizeof (ip4_address_t));
2873  prefix.fp_proto = FIB_PROTOCOL_IP4;
2874  prefix.fp_len = 32;
2875 
2876  fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
2877  if (fib_index == (u32) ~ 0)
2878  {
2879  clib_warning ("no fib table");
2880  return;
2881  }
2882 
2883  fei = fib_table_lookup (fib_index, &prefix);
2884 
2885  /* Couldn't find route to destination. Bail out. */
2886  if (fei == FIB_NODE_INDEX_INVALID)
2887  {
2888  clib_warning ("no route to DNS server");
2889  return;
2890  }
2891 
2892  sw_if_index = fib_entry_get_resolving_interface (fei);
2893 
2894  if (sw_if_index == ~0)
2895  {
2896  clib_warning
2897  ("route to %U exists, fei %d, get_resolving_interface returned"
2898  " ~0", fei, format_ip4_address, &prefix.fp_addr);
2899  return;
2900  }
2901 
2902  /* *INDENT-OFF* */
2903  foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnumbered */,
2904  ({
2905  src_address = ip_interface_address_get_address (lm4, ia);
2906  goto found_src_address;
2907  }));
2908  /* *INDENT-ON* */
2909 
2910  clib_warning ("FIB BUG");
2911  return;
2912 
2913 found_src_address:
2914 
2915  ip = vlib_buffer_get_current (b0);
2916  udp = (udp_header_t *) (ip + 1);
2917  dns_response = (u8 *) (udp + 1);
2918  clib_memset (ip, 0, sizeof (*ip) + sizeof (*udp));
2919 
2920  /*
2921  * Start with the variadic portion of the exercise.
2922  * Turn the name into a set of DNS "labels". Max length
2923  * per label is 63, enforce that.
2924  */
2925  reply = name_to_labels (pr->name);
2926  vec_free (pr->name);
2927 
2928  qp_offset = vec_len (reply);
2929 
2930  /* Add space for the query header */
2931  vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
2932 
2933  qp = (dns_query_t *) (reply + qp_offset);
2934 
2936  qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
2937  else
2938  qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2939 
2940  qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
2941 
2942  /* Punch in space for the dns_header_t */
2943  vec_insert (reply, sizeof (dns_header_t), 0);
2944 
2945  dh = (dns_header_t *) reply;
2946 
2947  /* Transaction ID = pool index */
2948  dh->id = pr->id;
2949 
2950  /* Announce that we did a recursive lookup */
2951  tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
2952  if (is_fail)
2953  tmp |= DNS_RCODE_NAME_ERROR;
2954  dh->flags = clib_host_to_net_u16 (tmp);
2955  dh->qdcount = clib_host_to_net_u16 (1);
2956  dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
2957  dh->nscount = 0;
2958  dh->arcount = 0;
2959 
2960  /* If the name resolution worked, cough up an appropriate RR */
2961  if (is_fail == 0)
2962  {
2963  /* Add the answer. First, a name pointer (0xC00C) */
2964  vec_add1 (reply, 0xC0);
2965  vec_add1 (reply, 0x0C);
2966 
2967  /* Now, add single A-rec RR */
2969  {
2970  vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
2971  rr = (dns_rr_t *) rrptr;
2972 
2973  rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
2974  rr->class = clib_host_to_net_u16 (1 /* internet */ );
2975  rr->ttl = clib_host_to_net_u32 (ttl);
2976  rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
2977  clib_memcpy (rr->rdata, rnr->ip4_address, sizeof (ip4_address_t));
2978  }
2979  else
2980  {
2981  /* Or a single PTR RR */
2982  u8 *vecname = format (0, "%s", rir->name);
2983  u8 *label_vec = name_to_labels (vecname);
2984  vec_free (vecname);
2985 
2986  vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
2987  rr = (dns_rr_t *) rrptr;
2988  rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2989  rr->class = clib_host_to_net_u16 (1 /* internet */ );
2990  rr->ttl = clib_host_to_net_u32 (ttl);
2991  rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
2992  clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
2993  vec_free (label_vec);
2994  }
2995  }
2996  clib_memcpy (dns_response, reply, vec_len (reply));
2997 
2998  /* Set the packet length */
2999  b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
3000 
3001  /* IP header */
3002  ip->ip_version_and_header_length = 0x45;
3003  ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
3004  ip->ttl = 255;
3005  ip->protocol = IP_PROTOCOL_UDP;
3006  ip->src_address.as_u32 = src_address->as_u32;
3008  sizeof (ip4_address_t));
3009  ip->checksum = ip4_header_checksum (ip);
3010 
3011  /* UDP header */
3012  udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
3013  udp->dst_port = pr->dst_port;
3014  udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
3015  vec_len (reply));
3016  udp->checksum = 0;
3017  vec_free (reply);
3018 
3019  /*
3020  * Ship pkts made out of whole cloth to ip4_lookup
3021  * Caller will ship recycled dns reply packets to ip4_lookup
3022  */
3023  if (is_recycle == 0)
3024  {
3025  f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
3026  to_next = vlib_frame_vector_args (f);
3027  to_next[0] = bi;
3028  f->n_vectors = 1;
3029  vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
3030  }
3031 }
3032 
3034  (vl_api_dns_enable_disable_t * mp, void *handle)
3035 {
3036  u8 *s;
3037 
3038  s = format (0, "SCRIPT: dns_enable_disable ");
3039  s = format (s, "%s ", mp->enable ? "enable" : "disable");
3040 
3041  FINISH;
3042 }
3043 
3046 {
3047  u8 *s;
3048 
3049  s = format (0, "SCRIPT: dns_name_server_add_del ");
3050  if (mp->is_ip6)
3051  s = format (s, "%U ", format_ip6_address,
3052  (ip6_address_t *) mp->server_address);
3053  else
3054  s = format (s, "%U ", format_ip4_address,
3055  (ip4_address_t *) mp->server_address);
3056 
3057  if (mp->is_add == 0)
3058  s = format (s, "del ");
3059 
3060  FINISH;
3061 }
3062 
3064  (vl_api_dns_resolve_name_t * mp, void *handle)
3065 {
3066  u8 *s;
3067 
3068  s = format (0, "SCRIPT: dns_resolve_name ");
3069  s = format (s, "%s ", mp->name);
3070  FINISH;
3071 }
3072 
3073 static void *vl_api_dns_resolve_ip_t_print
3074  (vl_api_dns_resolve_ip_t * mp, void *handle)
3075 {
3076  u8 *s;
3077 
3078  s = format (0, "SCRIPT: dns_resolve_ip ");
3079  if (mp->is_ip6)
3080  s = format (s, "%U ", format_ip6_address, mp->address);
3081  else
3082  s = format (s, "%U ", format_ip4_address, mp->address);
3083  FINISH;
3084 }
3085 
3086 static void
3088 {
3089 #define _(n,f) dm->api_main->msg_print_handlers \
3090  [VL_API_##n + dm->msg_id_base] \
3091  = (void *) vl_api_##f##_t_print;
3093 #undef _
3094 }
3095 
3096 /* Set up the API message handling tables */
3097 static clib_error_t *
3099 {
3100  dns_main_t *dmp = &dns_main;
3101 #define _(N,n) \
3102  vl_msg_api_set_handlers((VL_API_##N + dmp->msg_id_base), \
3103  #n, \
3104  vl_api_##n##_t_handler, \
3105  vl_noop_handler, \
3106  vl_api_##n##_t_endian, \
3107  vl_api_##n##_t_print, \
3108  sizeof(vl_api_##n##_t), 1);
3110 #undef _
3111 
3112  return 0;
3113 }
3114 
3115 static clib_error_t *
3117 {
3118  dns_main_t *dm = &dns_main;
3119  u8 *name;
3120 
3121  dm->vlib_main = vm;
3122  dm->vnet_main = vnet_get_main ();
3123  dm->name_cache_size = 1000;
3124  dm->max_ttl_in_seconds = 86400;
3125  dm->random_seed = 0xDEADDABE;
3126  dm->api_main = &api_main;
3127 
3128  name = format (0, "dns_%08x%c", api_version, 0);
3129 
3130  /* Ask for a correctly-sized block of API message decode slots */
3132  ((char *) name, VL_MSG_FIRST_AVAILABLE);
3133 
3134  (void) dns_plugin_api_hookup (vm);
3135 
3136  /* Add our API messages to the global name_crc hash table */
3138 
3140 
3141  vec_free (name);
3142 
3143  return 0;
3144 }
3145 
3147 
3148 /* *INDENT-OFF* */
3150 {
3151  .version = VPP_BUILD_VER,
3152  .description = "Simple DNS name resolver",
3153 };
3154 /* *INDENT-ON* */
3155 
3156 
3157 /*
3158  * fd.io coding-style-patch-verification: ON
3159  *
3160  * Local Variables:
3161  * eval: (c-set-style "gnu")
3162  * End:
3163  */
#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:213
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:977
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:2616
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:3034
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:986
#define REPLY_MACRO2(t, body)
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:279
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:1322
#define vec_terminate_c_string(V)
(If necessary) NULL terminate a vector containing a c-string.
Definition: vec.h:1018
#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:1586
int i
#define hash_set_mem(h, key, value)
Definition: hash.h:275
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:1594
#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:1181
#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:2291
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:1502
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
Aggregate type for a prefix.
Definition: fib_types.h:203
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:185
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:3045
#define clib_error_return(e, args...)
Definition: error.h:99
static void dns_custom_dump_configure(dns_main_t *dm)
Definition: dns.c:3087
u8 * format_dns_reply(u8 *s, va_list *args)
Definition: dns.c:2055
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:2777
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:1080
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:3074
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:63
#define DNS_RA
recursion available
Definition: dns_packet.h:42
u8 * cname
For CNAME records, the "next name" to resolve.
Definition: dns.h:59
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h: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:194
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:2329
#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:1789
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:3116
static void vl_api_dns_resolve_name_t_handler(vl_api_dns_resolve_name_t *mp)
Definition: dns.c:1458
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:2255
u8 len
Definition: ip_types.api:90
u32 fib_entry_get_resolving_interface(fib_node_index_t entry_index)
Definition: fib_entry.c:1466
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:397
format_function_t format_ip6_address
Definition: format.h:93
vlib_main_t * vm
Definition: buffer.c:323
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:3098
#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:830
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:63
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:2722
#define DNS_AA
authoritative answer
Definition: dns_packet.h:45
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:161
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:1010
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:656
#define ASSERT(truth)
volatile u8 flags
flags
Definition: dns.h:53
ip6_main_t ip6_main
Definition: ip6_forward.c:2805
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:1601
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:1621
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:2769
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:365
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:1076
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:2682
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:468
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:199
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:2115
api_main_t api_main
Definition: api_shared.c:35
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:772
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:1725
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:3064
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