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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include <vnet/vnet.h>
17 #include <vnet/udp/udp_local.h>
18 #include <vnet/plugin/plugin.h>
19 #include <vnet/fib/fib_table.h>
22 #include <vlibapi/api.h>
23 #include <vlibmemory/api.h>
24 #include <vpp/app/version.h>
27 /* define message IDs */
28 #include <dns/dns.api_enum.h>
29 #include <dns/dns.api_types.h>
31 #define REPLY_MSG_ID_BASE dm->msg_id_base
32 #include <vlibapi/api_helper_macros.h>
34 /* Macro to finish up custom dump fns */
35 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
38 vl_print (handle, (char *)s); \
45 dns_cache_clear (dns_main_t * dm)
47 dns_cache_entry_t *ep;
49 if (dm->is_enabled == 0)
50 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
52 dns_cache_lock (dm, 1);
55 pool_foreach (ep, dm->entries)
58 vec_free (ep->pending_requests);
62 pool_free (dm->entries);
63 hash_free (dm->cache_entry_by_name);
64 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
65 vec_free (dm->unresolved_entries);
66 dns_cache_unlock (dm);
71 dns_enable_disable (vlib_main_t * vm, dns_main_t * dm, int is_enable)
73 vlib_thread_main_t *tm = &vlib_thread_main;
74 u32 n_vlib_mains = tm->n_vlib_mains;
76 /* Create the resolver process if not done already */
77 vnet_dns_create_resolver_process (vm, dm);
81 if (vec_len (dm->ip4_name_servers) == 0
82 && (vec_len (dm->ip6_name_servers) == 0))
83 return VNET_API_ERROR_NO_NAME_SERVERS;
85 if (dm->udp_ports_registered == 0)
87 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply,
88 dns46_reply_node.index, 1 /* is_ip4 */ );
90 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply6,
91 dns46_reply_node.index, 0 /* is_ip4 */ );
93 udp_register_dst_port (vm, UDP_DST_PORT_dns,
94 dns4_request_node.index, 1 /* is_ip4 */ );
96 udp_register_dst_port (vm, UDP_DST_PORT_dns6,
97 dns6_request_node.index, 0 /* is_ip4 */ );
99 dm->udp_ports_registered = 1;
102 if (dm->cache_entry_by_name == 0)
104 if (n_vlib_mains > 1)
105 clib_spinlock_init (&dm->cache_lock);
107 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
114 dns_cache_clear (dm);
120 static void vl_api_dns_enable_disable_t_handler
121 (vl_api_dns_enable_disable_t * mp)
123 vl_api_dns_enable_disable_reply_t *rmp;
124 vlib_main_t *vm = vlib_get_main ();
125 dns_main_t *dm = &dns_main;
128 rv = dns_enable_disable (vm, dm, mp->enable);
130 REPLY_MACRO (VL_API_DNS_ENABLE_DISABLE_REPLY);
134 dns6_name_server_add_del (dns_main_t * dm,
135 u8 * server_address_as_u8, int is_add)
142 /* Already there? done... */
143 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
145 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
146 sizeof (ip6_address_t)))
150 vec_add2 (dm->ip6_name_servers, ap, 1);
151 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
155 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
157 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
158 sizeof (ip6_address_t)))
160 vec_delete (dm->ip6_name_servers, 1, i);
164 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
170 dns4_name_server_add_del (dns_main_t * dm,
171 u8 * server_address_as_u8, int is_add)
178 /* Already there? done... */
179 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
181 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
182 sizeof (ip4_address_t)))
186 vec_add2 (dm->ip4_name_servers, ap, 1);
187 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
191 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
193 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
194 sizeof (ip4_address_t)))
196 vec_delete (dm->ip4_name_servers, 1, i);
200 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
205 static void vl_api_dns_name_server_add_del_t_handler
206 (vl_api_dns_name_server_add_del_t * mp)
208 dns_main_t *dm = &dns_main;
209 vl_api_dns_name_server_add_del_reply_t *rmp;
213 rv = dns6_name_server_add_del (dm, mp->server_address, mp->is_add);
215 rv = dns4_name_server_add_del (dm, mp->server_address, mp->is_add);
217 REPLY_MACRO (VL_API_DNS_NAME_SERVER_ADD_DEL_REPLY);
221 vnet_dns_send_dns4_request (vlib_main_t * vm, dns_main_t * dm,
222 dns_cache_entry_t * ep, ip4_address_t * server)
224 f64 now = vlib_time_now (vm);
229 fib_node_index_t fei;
230 u32 sw_if_index, fib_index;
232 ip4_main_t *im4 = &ip4_main;
233 ip_lookup_main_t *lm4 = &im4->lookup_main;
234 ip_interface_address_t *ia = 0;
235 ip4_address_t *src_address;
240 ASSERT (ep->dns_request);
242 /* Find a FIB path to the server */
243 clib_memcpy (&prefix.fp_addr.ip4, server, sizeof (*server));
244 prefix.fp_proto = FIB_PROTOCOL_IP4;
247 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
248 if (fib_index == (u32) ~ 0)
251 clib_warning ("no fib table");
255 fei = fib_table_lookup (fib_index, &prefix);
257 /* Couldn't find route to destination. Bail out. */
258 if (fei == FIB_NODE_INDEX_INVALID)
261 clib_warning ("no route to DNS server");
265 sw_if_index = fib_entry_get_resolving_interface (fei);
267 if (sw_if_index == ~0)
271 ("route to %U exists, fei %d, get_resolving_interface returned"
272 " ~0", format_ip4_address, &prefix.fp_addr, fei);
277 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnumbered */,
279 src_address = ip_interface_address_get_address (lm4, ia);
280 goto found_src_address;
284 clib_warning ("FIB BUG");
289 /* Go get a buffer */
290 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
293 b = vlib_get_buffer (vm, bi);
294 b->current_length = sizeof (ip4_header_t) + sizeof (udp_header_t) +
295 vec_len (ep->dns_request);
296 b->total_length_not_including_first_buffer = 0;
298 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
299 vnet_buffer (b)->sw_if_index[VLIB_RX] = 0; /* "local0" */
300 vnet_buffer (b)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
302 ip = vlib_buffer_get_current (b);
303 clib_memset (ip, 0, sizeof (*ip));
304 udp = (udp_header_t *) (ip + 1);
305 clib_memset (udp, 0, sizeof (*udp));
307 dns_request = (u8 *) (udp + 1);
310 ip->ip_version_and_header_length = 0x45;
311 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b));
313 ip->protocol = IP_PROTOCOL_UDP;
314 ip->src_address.as_u32 = src_address->as_u32;
315 ip->dst_address.as_u32 = server->as_u32;
316 ip->checksum = ip4_header_checksum (ip);
319 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
320 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
321 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
322 vec_len (ep->dns_request));
325 /* The actual DNS request */
326 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
328 /* Ship it to ip4_lookup */
329 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
330 to_next = vlib_frame_vector_args (f);
333 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
335 ep->retry_timer = now + 2.0;
339 vnet_dns_send_dns6_request (vlib_main_t * vm, dns_main_t * dm,
340 dns_cache_entry_t * ep, ip6_address_t * server)
342 f64 now = vlib_time_now (vm);
347 fib_node_index_t fei;
348 u32 sw_if_index, fib_index;
350 ip6_main_t *im6 = &ip6_main;
351 ip_lookup_main_t *lm6 = &im6->lookup_main;
352 ip_interface_address_t *ia = 0;
353 ip6_address_t *src_address;
357 int junk __attribute__ ((unused));
359 ASSERT (ep->dns_request);
361 /* Find a FIB path to the server */
362 clib_memcpy (&prefix.fp_addr, server, sizeof (*server));
363 prefix.fp_proto = FIB_PROTOCOL_IP6;
366 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
367 if (fib_index == (u32) ~ 0)
370 clib_warning ("no fib table");
374 fei = fib_table_lookup (fib_index, &prefix);
376 /* Couldn't find route to destination. Bail out. */
377 if (fei == FIB_NODE_INDEX_INVALID)
379 clib_warning ("no route to DNS server");
382 sw_if_index = fib_entry_get_resolving_interface (fei);
385 foreach_ip_interface_address(lm6, ia, sw_if_index, 1 /* honor unnumbered */,
387 src_address = ip_interface_address_get_address (lm6, ia);
388 goto found_src_address;
392 clib_warning ("FIB BUG");
397 /* Go get a buffer */
398 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
401 b = vlib_get_buffer (vm, bi);
402 b->current_length = sizeof (ip6_header_t) + sizeof (udp_header_t) +
403 vec_len (ep->dns_request);
404 b->total_length_not_including_first_buffer = 0;
406 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
408 ip = vlib_buffer_get_current (b);
409 clib_memset (ip, 0, sizeof (*ip));
410 udp = (udp_header_t *) (ip + 1);
411 clib_memset (udp, 0, sizeof (*udp));
413 dns_request = (u8 *) (udp + 1);
416 ip->ip_version_traffic_class_and_flow_label =
417 clib_host_to_net_u32 (0x6 << 28);
420 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b)
421 - sizeof (ip6_header_t));
423 ip->protocol = IP_PROTOCOL_UDP;
424 clib_memcpy (&ip->src_address, src_address, sizeof (ip6_address_t));
425 clib_memcpy (&ip->dst_address, server, sizeof (ip6_address_t));
428 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
429 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
430 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
431 vec_len (ep->dns_request));
433 udp->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ip, &junk);
435 /* The actual DNS request */
436 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
438 /* Ship it to ip6_lookup */
439 f = vlib_get_frame_to_node (vm, ip6_lookup_node.index);
440 to_next = vlib_frame_vector_args (f);
444 ep->retry_timer = now + 2.0;
448 * Translate "foo.com" into "0x3 f o o 0x3 c o m 0x0"
449 * A historical / hysterical micro-TLV scheme. DGMS.
452 name_to_labels (u8 * name)
455 int last_label_index;
460 /* punch in space for the first length */
461 vec_insert (rv, 1, 0);
462 last_label_index = 0;
465 while (i < vec_len (rv))
469 rv[last_label_index] = (i - last_label_index) - 1;
470 if ((i - last_label_index) > 63)
471 clib_warning ("stupid name, label length %d",
472 i - last_label_index);
473 last_label_index = i;
478 /* Set the last real label length */
479 rv[last_label_index] = (i - last_label_index) - 1;
482 * Add a [sic] NULL root label. Otherwise, the name parser can't figure out
490 * arc-function for the above.
491 * Translate "0x3 f o o 0x3 c o m 0x0" into "foo.com"
492 * Produces a non-NULL-terminated u8 *vector. %v format is your friend.
495 vnet_dns_labels_to_name (u8 * label, u8 * full_text, u8 ** parse_from_here)
502 *parse_from_here = 0;
504 /* chase initial pointer? */
505 if ((label[0] & 0xC0) == 0xC0)
507 *parse_from_here = label + 2;
508 offset = ((label[0] & 0x3f) << 8) + label[1];
509 label = full_text + offset;
516 for (i = 0; i < len; i++)
517 vec_add1 (reply, *label++);
520 if ((label[0] & 0xC0) == 0xC0)
522 *parse_from_here = label + 2;
523 offset = ((label[0] & 0x3f) << 8) + label[1];
524 label = full_text + offset;
529 vec_add1 (reply, '.');
531 if (*parse_from_here == 0)
532 *parse_from_here = label;
537 vnet_send_dns_request (vlib_main_t * vm, dns_main_t * dm,
538 dns_cache_entry_t * ep)
543 u8 *request, *name_copy;
546 /* This can easily happen if sitting in GDB, etc. */
547 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID || ep->server_fails > 1)
550 /* Construct the dns request, if we haven't been here already */
551 if (vec_len (ep->dns_request) == 0)
554 * Start with the variadic portion of the exercise.
555 * Turn the name into a set of DNS "labels". Max length
556 * per label is 63, enforce that.
558 request = name_to_labels (ep->name);
559 name_copy = vec_dup (request);
560 qp_offset = vec_len (request);
563 * At least when testing against "known good" DNS servers:
564 * it turns out that sending 2x requests - one for an A-record
565 * and another for a AAAA-record - seems to work better than
566 * sending a DNS_TYPE_ALL request.
569 /* Add space for the query header */
570 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
572 qp = (dns_query_t *) (request + qp_offset);
574 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
575 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
577 clib_memcpy (qp, name_copy, vec_len (name_copy));
578 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
579 vec_free (name_copy);
581 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
582 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
584 /* Punch in space for the dns_header_t */
585 vec_insert (request, sizeof (dns_header_t), 0);
587 h = (dns_header_t *) request;
589 /* Transaction ID = pool index */
590 h->id = clib_host_to_net_u16 (ep - dm->entries);
592 /* Ask for a recursive lookup */
593 tmp = DNS_RD | DNS_OPCODE_QUERY;
594 h->flags = clib_host_to_net_u16 (tmp);
595 h->qdcount = clib_host_to_net_u16 (2);
599 ep->dns_request = request;
602 /* Work out which server / address family we're going to use */
604 /* Retry using current server */
605 if (ep->retry_count++ < DNS_RETRIES_PER_SERVER)
607 if (ep->server_af == 1 /* ip6 */ )
609 if (vec_len (dm->ip6_name_servers))
611 vnet_dns_send_dns6_request
612 (vm, dm, ep, dm->ip6_name_servers + ep->server_rotor);
618 if (vec_len (dm->ip4_name_servers))
620 vnet_dns_send_dns4_request
621 (vm, dm, ep, dm->ip4_name_servers + ep->server_rotor);
625 else /* switch to a new server */
629 if (ep->server_af == 1 /* ip6 */ )
631 if (ep->server_rotor >= vec_len (dm->ip6_name_servers))
633 ep->server_rotor = 0;
634 ep->server_af = vec_len (dm->ip4_name_servers) > 0 ? 0 : 1;
639 if (ep->server_rotor >= vec_len (dm->ip4_name_servers))
641 ep->server_rotor = 0;
642 ep->server_af = vec_len (dm->ip6_name_servers) > 0 ? 1 : 0;
647 if (ep->server_af == 1 /* ip6 */ )
648 vnet_dns_send_dns6_request
649 (vm, dm, ep, dm->ip6_name_servers + ep->server_rotor);
651 vnet_dns_send_dns4_request
652 (vm, dm, ep, dm->ip4_name_servers + ep->server_rotor);
656 vlib_process_signal_event_mt (vm,
657 dm->resolver_process_node_index,
658 DNS_RESOLVER_EVENT_PENDING, 0);
662 vnet_dns_delete_entry_by_index_nolock (dns_main_t * dm, u32 index)
664 dns_cache_entry_t *ep;
667 if (dm->is_enabled == 0)
668 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
670 if (pool_is_free_index (dm->entries, index))
671 return VNET_API_ERROR_NO_SUCH_ENTRY;
673 ep = pool_elt_at_index (dm->entries, index);
674 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_VALID))
676 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
677 if (index == dm->unresolved_entries[i])
679 vec_delete (dm->unresolved_entries, 1, i);
682 clib_warning ("pool elt %d supposedly pending, but not found...",
687 hash_unset_mem (dm->cache_entry_by_name, ep->name);
689 vec_free (ep->pending_requests);
690 pool_put (dm->entries, ep);
696 dns_delete_by_name (dns_main_t * dm, u8 * name)
701 if (dm->is_enabled == 0)
702 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
704 dns_cache_lock (dm, 2);
705 p = hash_get_mem (dm->cache_entry_by_name, name);
708 dns_cache_unlock (dm);
709 return VNET_API_ERROR_NO_SUCH_ENTRY;
711 rv = vnet_dns_delete_entry_by_index_nolock (dm, p[0]);
713 dns_cache_unlock (dm);
719 delete_random_entry (dns_main_t * dm)
722 u32 victim_index, start_index, i;
724 dns_cache_entry_t *ep;
726 if (dm->is_enabled == 0)
727 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
730 * Silence spurious coverity warning. We know pool_elts >> 0, or
731 * we wouldn't be here...
734 if (pool_elts (dm->entries) == 0)
735 return VNET_API_ERROR_UNSPECIFIED;
738 dns_cache_lock (dm, 3);
739 limit = pool_elts (dm->entries);
740 start_index = random_u32 (&dm->random_seed) % limit;
742 for (i = 0; i < limit; i++)
744 victim_index = (start_index + i) % limit;
746 if (!pool_is_free_index (dm->entries, victim_index))
748 ep = pool_elt_at_index (dm->entries, victim_index);
749 /* Delete only valid, non-static entries */
750 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
751 && ((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0))
753 rv = vnet_dns_delete_entry_by_index_nolock (dm, victim_index);
754 dns_cache_unlock (dm);
759 dns_cache_unlock (dm);
761 clib_warning ("Couldn't find an entry to delete?");
762 return VNET_API_ERROR_UNSPECIFIED;
766 dns_add_static_entry (dns_main_t * dm, u8 * name, u8 * dns_reply_data)
768 dns_cache_entry_t *ep;
772 if (dm->is_enabled == 0)
773 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
775 dns_cache_lock (dm, 4);
776 p = hash_get_mem (dm->cache_entry_by_name, name);
779 dns_cache_unlock (dm);
780 return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
783 if (pool_elts (dm->entries) == dm->name_cache_size)
785 /* Will only fail if the cache is totally filled w/ static entries... */
786 rv = delete_random_entry (dm);
789 dns_cache_unlock (dm);
794 pool_get (dm->entries, ep);
795 clib_memset (ep, 0, sizeof (*ep));
797 /* Note: consumes the name vector */
799 /* make sure it NULL-terminated as hash_set_mem will use strlen() */
800 vec_terminate_c_string (ep->name);
801 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
802 ep->flags = DNS_CACHE_ENTRY_FLAG_VALID | DNS_CACHE_ENTRY_FLAG_STATIC;
803 ep->dns_response = dns_reply_data;
805 dns_cache_unlock (dm);
810 vnet_dns_resolve_name (vlib_main_t * vm, dns_main_t * dm, u8 * name,
811 dns_pending_request_t * t, dns_cache_entry_t ** retp)
813 dns_cache_entry_t *ep;
817 dns_pending_request_t *pr;
820 now = vlib_time_now (vm);
822 /* In case we can't actually answer the question right now... */
825 /* binary API caller might forget to set the name. Guess how we know. */
827 return VNET_API_ERROR_INVALID_VALUE;
829 dns_cache_lock (dm, 5);
831 p = hash_get_mem (dm->cache_entry_by_name, name);
834 ep = pool_elt_at_index (dm->entries, p[0]);
835 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
837 /* Has the entry expired? */
838 if (((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0)
839 && (now > ep->expiration_time))
842 u32 *indices_to_delete = 0;
845 * Take out the rest of the resolution chain
846 * This isn't optimal, but it won't happen very often.
850 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME))
852 vec_add1 (indices_to_delete, ep - dm->entries);
854 p = hash_get_mem (dm->cache_entry_by_name, ep->cname);
857 ep = pool_elt_at_index (dm->entries, p[0]);
861 vec_add1 (indices_to_delete, ep - dm->entries);
865 for (i = 0; i < vec_len (indices_to_delete); i++)
867 /* Reenable to watch re-resolutions */
870 ep = pool_elt_at_index (dm->entries,
871 indices_to_delete[i]);
872 clib_warning ("Re-resolve %s", ep->name);
875 vnet_dns_delete_entry_by_index_nolock
876 (dm, indices_to_delete[i]);
878 vec_free (indices_to_delete);
879 /* Yes, kill it... */
883 if (ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
889 dns_cache_unlock (dm);
895 * Resolution pending. Add request to the pending vector
896 * by copying the template request
898 vec_add2 (ep->pending_requests, pr, 1);
899 memcpy (pr, t, sizeof (*pr));
900 dns_cache_unlock (dm);
906 if (pool_elts (dm->entries) == dm->name_cache_size)
908 /* Will only fail if the cache is totally filled w/ static entries... */
909 rv = delete_random_entry (dm);
912 dns_cache_unlock (dm);
917 /* add new hash table entry */
918 pool_get (dm->entries, ep);
919 clib_memset (ep, 0, sizeof (*ep));
921 ep->name = format (0, "%s%c", name, 0);
922 _vec_len (ep->name) = vec_len (ep->name) - 1;
924 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
926 vec_add1 (dm->unresolved_entries, ep - dm->entries);
927 vec_add2 (ep->pending_requests, pr, 1);
929 pr->request_type = t->request_type;
931 /* Remember details so we can reply later... */
932 if (t->request_type == DNS_API_PENDING_NAME_TO_IP ||
933 t->request_type == DNS_API_PENDING_IP_TO_NAME)
935 pr->client_index = t->client_index;
936 pr->client_context = t->client_context;
940 pr->client_index = ~0;
941 pr->is_ip6 = t->is_ip6;
942 pr->dst_port = t->dst_port;
949 clib_memcpy (pr->dst_address, t->dst_address, count);
952 vnet_send_dns_request (vm, dm, ep);
953 dns_cache_unlock (dm);
957 #define foreach_notification_to_move \
961 * Handle cname indirection. JFC. Called with the cache locked.
962 * returns 0 if the reply is not a CNAME.
966 vnet_dns_cname_indirection_nolock (vlib_main_t * vm, dns_main_t * dm,
967 u32 ep_index, u8 * reply)
982 dns_cache_entry_t *ep, *next_ep;
985 h = (dns_header_t *) reply;
986 flags = clib_net_to_host_u16 (h->flags);
987 rcode = flags & DNS_RCODE_MASK;
989 /* See if the response is OK */
992 case DNS_RCODE_NO_ERROR:
995 case DNS_RCODE_NAME_ERROR:
996 case DNS_RCODE_FORMAT_ERROR:
997 case DNS_RCODE_SERVER_FAILURE:
998 case DNS_RCODE_NOT_IMPLEMENTED:
999 case DNS_RCODE_REFUSED:
1003 curpos = (u8 *) (h + 1);
1007 /* Skip the questions */
1008 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
1015 pos += sizeof (dns_query_t);
1018 /* expect a pointer chase here for a CNAME record */
1019 if ((pos2[0] & 0xC0) == 0xC0)
1024 /* Walk the answer(s) to see what to do next */
1025 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
1027 rr = (dns_rr_t *) pos;
1028 switch (clib_net_to_host_u16 (rr->type))
1030 /* Real address record? Done.. */
1035 * Maybe chase a CNAME pointer?
1036 * It's not unheard-of for name-servers to return
1037 * both CNAME and A/AAAA records...
1039 case DNS_TYPE_CNAME:
1043 /* Some other junk, e.g. a nameserver... */
1047 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1049 if ((pos2[0] & 0xc0) == 0xc0)
1053 /* Neither a CNAME nor a real address. Try another server */
1056 flags &= ~DNS_RCODE_MASK;
1057 flags |= DNS_RCODE_NAME_ERROR;
1058 h->flags = clib_host_to_net_u16 (flags);
1062 /* This is a CNAME record, chase the name chain. */
1065 /* The last request is no longer pending.. */
1066 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
1067 if (ep_index == dm->unresolved_entries[i])
1069 vec_delete (dm->unresolved_entries, 1, i);
1070 goto found_last_request;
1072 clib_warning ("pool elt %d supposedly pending, but not found...", ep_index);
1077 now = vlib_time_now (vm);
1078 cname = vnet_dns_labels_to_name (rr->rdata, reply, &pos2);
1079 /* Save the cname */
1080 vec_add1 (cname, 0);
1081 _vec_len (cname) -= 1;
1082 ep = pool_elt_at_index (dm->entries, ep_index);
1084 ep->flags |= (DNS_CACHE_ENTRY_FLAG_CNAME | DNS_CACHE_ENTRY_FLAG_VALID);
1085 /* Save the response */
1086 if (ep->dns_response)
1087 vec_free (ep->dns_response);
1088 ep->dns_response = reply;
1089 /* Set up expiration time */
1090 ep->expiration_time = now + clib_net_to_host_u32 (rr->ttl);
1092 pool_get (dm->entries, next_ep);
1094 /* Need to recompute ep post pool-get */
1095 ep = pool_elt_at_index (dm->entries, ep_index);
1097 clib_memset (next_ep, 0, sizeof (*next_ep));
1098 next_ep->name = vec_dup (cname);
1099 vec_add1 (next_ep->name, 0);
1100 _vec_len (next_ep->name) -= 1;
1102 hash_set_mem (dm->cache_entry_by_name, next_ep->name,
1103 next_ep - dm->entries);
1105 /* Use the same server */
1106 next_ep->server_rotor = ep->server_rotor;
1107 next_ep->server_af = ep->server_af;
1109 /* Move notification data to the next name in the chain */
1110 #define _(a) next_ep->a = ep->a; ep->a = 0;
1111 foreach_notification_to_move;
1114 request = name_to_labels (cname);
1115 name_copy = vec_dup (request);
1117 qp_offset = vec_len (request);
1119 /* Add space for the query header */
1120 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
1122 qp = (dns_query_t *) (request + qp_offset);
1124 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
1125 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1126 clib_memcpy (qp, name_copy, vec_len (name_copy));
1127 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
1128 vec_free (name_copy);
1130 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1131 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1133 /* Punch in space for the dns_header_t */
1134 vec_insert (request, sizeof (dns_header_t), 0);
1136 h = (dns_header_t *) request;
1138 /* Transaction ID = pool index */
1139 h->id = clib_host_to_net_u16 (next_ep - dm->entries);
1141 /* Ask for a recursive lookup */
1142 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
1143 h->qdcount = clib_host_to_net_u16 (2);
1147 next_ep->dns_request = request;
1148 next_ep->retry_timer = now + 2.0;
1149 next_ep->retry_count = 0;
1152 * Enable this to watch recursive resolution happen...
1153 * fformat (stdout, "%U", format_dns_reply, request, 2);
1156 vec_add1 (dm->unresolved_entries, next_ep - dm->entries);
1157 vnet_send_dns_request (vm, dm, next_ep);
1162 vnet_dns_response_to_reply (u8 * response,
1163 vl_api_dns_resolve_name_reply_t * rmp,
1171 u8 *curpos, *pos, *pos2;
1177 h = (dns_header_t *) response;
1178 flags = clib_net_to_host_u16 (h->flags);
1179 rcode = flags & DNS_RCODE_MASK;
1181 /* See if the response is OK, etc. */
1185 case DNS_RCODE_NO_ERROR:
1188 case DNS_RCODE_NAME_ERROR:
1189 case DNS_RCODE_FORMAT_ERROR:
1190 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1192 case DNS_RCODE_SERVER_FAILURE:
1193 case DNS_RCODE_NOT_IMPLEMENTED:
1194 case DNS_RCODE_REFUSED:
1195 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1198 /* No answers? Loser... */
1199 if (clib_net_to_host_u16 (h->anscount) < 1)
1200 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1202 curpos = (u8 *) (h + 1);
1204 /* Skip the name we asked about */
1207 /* Should never happen, but stil... */
1208 if ((len & 0xC0) == 0xC0)
1212 /* skip the name / label-set */
1221 limit = clib_net_to_host_u16 (h->qdcount);
1222 qp = (dns_query_t *) curpos;
1227 limit = clib_net_to_host_u16 (h->anscount);
1229 for (i = 0; i < limit; i++)
1231 pos = pos2 = curpos;
1234 /* Expect pointer chases in the answer section... */
1235 if ((pos2[0] & 0xC0) == 0xC0)
1238 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1247 if ((pos2[0] & 0xc0) == 0xc0)
1250 * If we've already done one pointer chase,
1251 * do not move the pos pointer.
1253 if (pointer_chase == 0)
1255 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1263 if (pointer_chase == 0)
1266 rr = (dns_rr_t *) pos;
1268 switch (clib_net_to_host_u16 (rr->type))
1271 /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1272 memcpy (rmp->ip4_address, rr->rdata, sizeof (ip4_address_t));
1274 ttl = clib_net_to_host_u32 (rr->ttl);
1275 if (min_ttlp && *min_ttlp > ttl)
1279 /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1280 memcpy (rmp->ip6_address, rr->rdata, sizeof (ip6_address_t));
1281 ttl = clib_net_to_host_u32 (rr->ttl);
1282 if (min_ttlp && *min_ttlp > ttl)
1290 /* Might as well stop ASAP */
1291 if (rmp->ip4_set && rmp->ip6_set)
1293 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1297 if ((rmp->ip4_set + rmp->ip6_set) == 0)
1298 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1303 vnet_dns_response_to_name (u8 * response,
1304 vl_api_dns_resolve_ip_reply_t * rmp,
1312 u8 *curpos, *pos, *pos2;
1317 u8 *junk __attribute__ ((unused));
1321 h = (dns_header_t *) response;
1322 flags = clib_net_to_host_u16 (h->flags);
1323 rcode = flags & DNS_RCODE_MASK;
1325 /* See if the response is OK, etc. */
1329 case DNS_RCODE_NO_ERROR:
1332 case DNS_RCODE_NAME_ERROR:
1333 case DNS_RCODE_FORMAT_ERROR:
1334 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1336 case DNS_RCODE_SERVER_FAILURE:
1337 case DNS_RCODE_NOT_IMPLEMENTED:
1338 case DNS_RCODE_REFUSED:
1339 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1342 /* No answers? Loser... */
1343 if (clib_net_to_host_u16 (h->anscount) < 1)
1344 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1346 curpos = (u8 *) (h + 1);
1348 /* Skip the name we asked about */
1351 /* Should never happen, but stil... */
1352 if ((len & 0xC0) == 0xC0)
1356 /* skip the name / label-set */
1365 limit = clib_net_to_host_u16 (h->qdcount);
1366 qp = (dns_query_t *) curpos;
1371 limit = clib_net_to_host_u16 (h->anscount);
1373 for (i = 0; i < limit; i++)
1375 pos = pos2 = curpos;
1378 /* Expect pointer chases in the answer section... */
1379 if ((pos2[0] & 0xC0) == 0xC0)
1382 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1391 if ((pos2[0] & 0xc0) == 0xc0)
1394 * If we've already done one pointer chase,
1395 * do not move the pos pointer.
1397 if (pointer_chase == 0)
1399 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1407 if (pointer_chase == 0)
1410 rr = (dns_rr_t *) pos;
1412 switch (clib_net_to_host_u16 (rr->type))
1415 name = vnet_dns_labels_to_name (rr->rdata, response, &junk);
1416 memcpy (rmp->name, name, vec_len (name));
1417 ttl = clib_net_to_host_u32 (rr->ttl);
1420 rmp->name[vec_len (name)] = 0;
1426 /* Might as well stop ASAP */
1429 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1434 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1439 vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1441 vlib_main_t *vm = vlib_get_main ();
1442 dns_main_t *dm = &dns_main;
1443 vl_api_dns_resolve_name_reply_t *rmp;
1444 dns_cache_entry_t *ep;
1445 dns_pending_request_t _t0, *t0 = &_t0;
1448 /* Sanitize the name slightly */
1449 mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1451 t0->request_type = DNS_API_PENDING_NAME_TO_IP;
1452 t0->client_index = mp->client_index;
1453 t0->client_context = mp->context;
1455 rv = vnet_dns_resolve_name (vm, dm, mp->name, t0, &ep);
1457 /* Error, e.g. not enabled? Tell the user */
1460 REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1464 /* Resolution pending? Don't reply... */
1469 REPLY_MACRO2(VL_API_DNS_RESOLVE_NAME_REPLY,
1471 rv = vnet_dns_response_to_reply (ep->dns_response, rmp, 0 /* ttl-ptr */);
1472 rmp->retval = clib_host_to_net_u32 (rv);
1478 vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
1480 vlib_main_t *vm = vlib_get_main ();
1481 dns_main_t *dm = &dns_main;
1482 vl_api_dns_resolve_ip_reply_t *rmp;
1483 dns_cache_entry_t *ep;
1486 u8 *lookup_name = 0;
1488 dns_pending_request_t _t0, *t0 = &_t0;
1492 for (i = 15; i >= 0; i--)
1494 digit = mp->address[i];
1495 nybble = (digit & 0x0F);
1497 vec_add1 (lookup_name, (nybble - 10) + 'a');
1499 vec_add1 (lookup_name, nybble + '0');
1500 vec_add1 (lookup_name, '.');
1501 nybble = (digit & 0xF0) >> 4;
1503 vec_add1 (lookup_name, (nybble - 10) + 'a');
1505 vec_add1 (lookup_name, nybble + '0');
1506 vec_add1 (lookup_name, '.');
1508 len = vec_len (lookup_name);
1509 vec_validate (lookup_name, len + 8);
1510 memcpy (lookup_name + len, "ip6.arpa", 8);
1514 for (i = 3; i >= 0; i--)
1516 digit = mp->address[i];
1517 lookup_name = format (lookup_name, "%d.", digit);
1519 lookup_name = format (lookup_name, "in-addr.arpa");
1522 vec_add1 (lookup_name, 0);
1524 t0->request_type = DNS_API_PENDING_IP_TO_NAME;
1525 t0->client_index = mp->client_index;
1526 t0->client_context = mp->context;
1528 rv = vnet_dns_resolve_name (vm, dm, lookup_name, t0, &ep);
1530 vec_free (lookup_name);
1532 /* Error, e.g. not enabled? Tell the user */
1535 REPLY_MACRO (VL_API_DNS_RESOLVE_IP_REPLY);
1539 /* Resolution pending? Don't reply... */
1544 REPLY_MACRO2(VL_API_DNS_RESOLVE_IP_REPLY,
1546 rv = vnet_dns_response_to_name (ep->dns_response, rmp, 0 /* ttl-ptr */);
1547 rmp->retval = clib_host_to_net_u32 (rv);
1552 static clib_error_t *
1553 dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1555 dns_main_t *dm = &dns_main;
1557 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1559 if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1561 else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1564 return clib_error_return (0, "unknown input `%U'",
1565 format_unformat_error, input);
1570 VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1573 unformat_dns_reply (unformat_input_t * input, va_list * args)
1575 u8 **result = va_arg (*args, u8 **);
1576 u8 **namep = va_arg (*args, u8 **);
1590 if (unformat (input, "%v", &name))
1593 if (unformat (input, "%U", unformat_ip4_address, &a4))
1596 if (unformat (input, "%U", unformat_ip6_address, &a6))
1600 if (unformat (input, "%U", unformat_ip6_address, &a6))
1603 if (unformat (input, "%U", unformat_ip4_address, &a6))
1607 /* Must have a name */
1611 /* Must have at least one address */
1612 if (!(a4_set + a6_set))
1615 /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1616 ce = name_to_labels (name);
1617 qp_offset = vec_len (ce);
1619 /* Add space for the query header */
1620 vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1621 qp = (dns_query_t *) (ce + qp_offset);
1623 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1624 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1626 /* Punch in space for the dns_header_t */
1627 vec_insert (ce, sizeof (dns_header_t), 0);
1629 h = (dns_header_t *) ce;
1631 /* Fake Transaction ID */
1634 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1635 h->qdcount = clib_host_to_net_u16 (1);
1636 h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1640 /* Now append one or two A/AAAA RR's... */
1643 /* Pointer to the name (DGMS) */
1644 vec_add1 (ce, 0xC0);
1645 vec_add1 (ce, 0x0C);
1646 vec_add2 (ce, rru8, sizeof (*rr) + 4);
1648 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1649 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1650 rr->ttl = clib_host_to_net_u32 (86400);
1651 rr->rdlength = clib_host_to_net_u16 (4);
1652 memcpy (rr->rdata, &a4, sizeof (a4));
1656 /* Pointer to the name (DGMS) */
1657 vec_add1 (ce, 0xC0);
1658 vec_add1 (ce, 0x0C);
1659 vec_add2 (ce, rru8, sizeof (*rr) + 16);
1661 rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1662 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1663 rr->ttl = clib_host_to_net_u32 (86400);
1664 rr->rdlength = clib_host_to_net_u16 (16);
1665 memcpy (rr->rdata, &a6, sizeof (a6));
1677 format_dns_query (u8 * s, va_list * args)
1679 u8 **curpos = va_arg (*args, u8 **);
1680 int verbose = va_arg (*args, int);
1685 s = format (s, " Name: ");
1687 /* Unwind execrated counted-label sheit */
1693 for (i = 0; i < len; i++)
1694 vec_add1 (s, *pos++);
1706 qp = (dns_query_t *) pos;
1709 switch (clib_net_to_host_u16 (qp->type))
1712 s = format (s, "type A\n");
1715 s = format (s, "type AAAA\n");
1718 s = format (s, "type ALL\n");
1722 s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1727 pos += sizeof (*qp);
1734 * format dns reply data
1735 * verbose > 1, dump everything
1736 * verbose == 1, dump all A and AAAA records
1737 * verbose == 0, dump one A record, and one AAAA record
1741 format_dns_reply_data (u8 * s, va_list * args)
1743 u8 *reply = va_arg (*args, u8 *);
1744 u8 **curpos = va_arg (*args, u8 **);
1745 int verbose = va_arg (*args, int);
1746 int *print_ip4 = va_arg (*args, int *);
1747 int *print_ip6 = va_arg (*args, int *);
1752 int pointer_chase = 0;
1754 u16 rrtype_host_byte_order;
1756 pos = pos2 = *curpos;
1759 s = format (s, " ");
1761 /* chase pointer? almost always yes here... */
1762 if ((pos2[0] & 0xc0) == 0xc0)
1765 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1773 for (i = 0; i < len; i++)
1776 vec_add1 (s, *pos2);
1779 if ((pos2[0] & 0xc0) == 0xc0)
1782 * If we've already done one pointer chase,
1783 * do not move the pos pointer.
1785 if (pointer_chase == 0)
1787 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1805 if (pointer_chase == 0)
1808 rr = (dns_rr_t *) pos;
1809 rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
1811 switch (rrtype_host_byte_order)
1816 s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1817 format_ip4_address, rr->rdata);
1822 s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1823 clib_net_to_host_u32 (rr->ttl));
1828 pos += sizeof (*rr) + 4;
1834 s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1835 format_ip6_address, rr->rdata);
1840 s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1841 clib_net_to_host_u32 (rr->ttl));
1845 pos += sizeof (*rr) + 16;
1851 s = format (s, "TEXT: ");
1852 for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1853 vec_add1 (s, rr->rdata[i]);
1856 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1859 case DNS_TYPE_HINFO:
1861 /* Two counted strings. DGMS */
1867 s = format (s, "HINFO: ");
1870 for (i = 0; i < *len; i++)
1871 vec_add1 (s, *curpos++);
1875 for (i = 0; i < *len; i++)
1876 vec_add1 (s, *curpos++);
1881 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1884 case DNS_TYPE_NAMESERVER:
1887 s = format (s, "Nameserver: ");
1890 /* chase pointer? */
1891 if ((pos2[0] & 0xc0) == 0xc0)
1894 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1901 for (i = 0; i < len; i++)
1902 vec_add1 (s, *pos2++);
1904 /* chase pointer, typically to offset 12... */
1905 if (pos2[0] == 0xC0)
1906 pos2 = reply + pos2[1];
1915 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1918 case DNS_TYPE_MAIL_EXCHANGE:
1921 tp = (u16 *) rr->rdata;
1923 s = format (s, "Mail Exchange: Preference %d ", (u32)
1924 clib_net_to_host_u16 (*tp));
1926 pos2 = rr->rdata + 2;
1928 /* chase pointer? */
1929 if (pos2[0] == 0xc0)
1930 pos2 = reply + pos2[1];
1936 for (i = 0; i < len; i++)
1937 vec_add1 (s, *pos2++);
1940 if (pos2[0] == 0xC0)
1941 pos2 = reply + pos2[1];
1951 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1955 case DNS_TYPE_CNAME:
1958 tp = (u16 *) rr->rdata;
1960 if (rrtype_host_byte_order == DNS_TYPE_CNAME)
1961 s = format (s, "CNAME: ");
1963 s = format (s, "PTR: ");
1967 /* chase pointer? */
1968 if (pos2[0] == 0xc0)
1969 pos2 = reply + pos2[1];
1975 for (i = 0; i < len; i++)
1976 vec_add1 (s, *pos2++);
1979 if (pos2[0] == 0xC0)
1980 pos2 = reply + pos2[1];
1989 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1994 s = format (s, "type %d: len %d\n",
1995 (int) clib_net_to_host_u16 (rr->type),
1996 sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
1997 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2007 format_dns_reply (u8 * s, va_list * args)
2009 u8 *reply_as_u8 = va_arg (*args, u8 *);
2010 int verbose = va_arg (*args, int);
2018 h = (dns_header_t *) reply_as_u8;
2019 id = clib_net_to_host_u16 (h->id);
2020 flags = clib_net_to_host_u16 (h->flags);
2024 s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
2026 s = format (s, " %s %s %s %s\n",
2027 (flags & DNS_RA) ? "recur" : "no-recur",
2028 (flags & DNS_RD) ? "recur-des" : "no-recur-des",
2029 (flags & DNS_TC) ? "trunc" : "no-trunc",
2030 (flags & DNS_AA) ? "auth" : "non-auth");
2031 s = format (s, " %d queries, %d answers, %d name-servers,"
2033 clib_net_to_host_u16 (h->qdcount),
2034 clib_net_to_host_u16 (h->anscount),
2035 clib_net_to_host_u16 (h->nscount),
2036 clib_net_to_host_u16 (h->arcount));
2039 curpos = (u8 *) (h + 1);
2044 s = format (s, " Queries:\n");
2045 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
2047 /* The query is variable-length, so curpos is a value-result parm */
2048 s = format (s, "%U", format_dns_query, &curpos, verbose);
2054 s = format (s, " Replies:\n");
2056 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
2058 /* curpos is a value-result parm */
2059 s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
2060 verbose, &print_ip4, &print_ip6);
2067 format_dns_cache (u8 * s, va_list * args)
2069 dns_main_t *dm = va_arg (*args, dns_main_t *);
2070 f64 now = va_arg (*args, f64);
2071 int verbose = va_arg (*args, int);
2072 u8 *name = va_arg (*args, u8 *);
2073 dns_cache_entry_t *ep;
2077 if (dm->is_enabled == 0)
2079 s = format (s, "The DNS cache is disabled...");
2083 if (pool_elts (dm->entries) == 0)
2085 s = format (s, "The DNS cache is empty...");
2089 dns_cache_lock (dm, 6);
2093 p = hash_get_mem (dm->cache_entry_by_name, name);
2096 s = format (s, "%s is not in the cache...", name);
2097 dns_cache_unlock (dm);
2101 ep = pool_elt_at_index (dm->entries, p[0]);
2102 /* Magic to spit out a C-initializer to research hemorrhoids... */
2106 s = format (s, "static u8 dns_reply_data_initializer[] =\n");
2107 s = format (s, "{\n");
2109 for (i = 0; i < vec_len (ep->dns_response); i++)
2116 s = format (s, "0x%02x, ", ep->dns_response[i]);
2118 s = format (s, "};\n");
2122 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2124 ASSERT (ep->dns_response);
2125 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2130 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2131 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2133 s = format (s, "%s%s -> %U", ss, ep->name,
2134 format_dns_reply, ep->dns_response, verbose);
2135 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2137 f64 time_left = ep->expiration_time - now;
2138 if (time_left > 0.0)
2139 s = format (s, " TTL left %.1f", time_left);
2141 s = format (s, " EXPIRED");
2146 ASSERT (ep->dns_request);
2147 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2155 s = format (s, "DNS cache contains %d entries\n", pool_elts (dm->entries));
2160 pool_foreach (ep, dm->entries)
2162 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2164 ASSERT (ep->dns_response);
2165 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2170 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2171 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2173 s = format (s, "%s%s -> %U", ss, ep->name,
2177 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2179 f64 time_left = ep->expiration_time - now;
2180 if (time_left > 0.0)
2181 s = format (s, " TTL left %.1f", time_left);
2183 s = format (s, " EXPIRED");
2186 s = format (s, " %d client notifications pending\n",
2187 vec_len(ep->pending_requests));
2192 ASSERT (ep->dns_request);
2193 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2201 dns_cache_unlock (dm);
2206 static clib_error_t *
2207 show_dns_cache_command_fn (vlib_main_t * vm,
2208 unformat_input_t * input, vlib_cli_command_t * cmd)
2210 dns_main_t *dm = &dns_main;
2213 f64 now = vlib_time_now (vm);
2215 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2217 if (unformat (input, "verbose %d", &verbose))
2219 else if (unformat (input, "verbose"))
2221 else if (unformat (input, "name %s", &name))
2224 return clib_error_return (0, "unknown input `%U'",
2225 format_unformat_error, input);
2228 vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
2234 VLIB_CLI_COMMAND (show_dns_cache_command) =
2236 .path = "show dns cache",
2237 .short_help = "show dns cache [verbose [nn]]",
2238 .function = show_dns_cache_command_fn,
2242 static clib_error_t *
2243 show_dns_servers_command_fn (vlib_main_t * vm,
2244 unformat_input_t * input,
2245 vlib_cli_command_t * cmd)
2247 dns_main_t *dm = &dns_main;
2250 if ((vec_len (dm->ip4_name_servers) + vec_len (dm->ip6_name_servers)) == 0)
2251 return clib_error_return (0, "No name servers configured...");
2253 if (vec_len (dm->ip4_name_servers))
2255 vlib_cli_output (vm, "ip4 name servers:");
2256 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
2257 vlib_cli_output (vm, "%U", format_ip4_address,
2258 dm->ip4_name_servers + i);
2260 if (vec_len (dm->ip6_name_servers))
2262 vlib_cli_output (vm, "ip6 name servers:");
2263 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
2264 vlib_cli_output (vm, "%U", format_ip6_address,
2265 dm->ip4_name_servers + i);
2271 VLIB_CLI_COMMAND (show_dns_server_command) =
2273 .path = "show dns servers",
2274 .short_help = "show dns servers",
2275 .function = show_dns_servers_command_fn,
2280 static clib_error_t *
2281 dns_cache_add_del_command_fn (vlib_main_t * vm,
2282 unformat_input_t * input,
2283 vlib_cli_command_t * cmd)
2285 dns_main_t *dm = &dns_main;
2291 clib_error_t *error;
2293 if (unformat (input, "add"))
2295 if (unformat (input, "del"))
2297 if (unformat (input, "clear"))
2300 if (is_add == -1 && is_clear == -1)
2301 return clib_error_return (0, "add / del / clear required...");
2305 rv = dns_cache_clear (dm);
2311 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2312 error = clib_error_return (0, "Name resolution not enabled");
2317 /* Delete (by name)? */
2320 if (unformat (input, "%v", &name))
2322 rv = dns_delete_by_name (dm, name);
2325 case VNET_API_ERROR_NO_SUCH_ENTRY:
2326 error = clib_error_return (0, "%v not in the cache...", name);
2330 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2331 error = clib_error_return (0, "Name resolution not enabled");
2340 error = clib_error_return (0, "dns_delete_by_name returned %d",
2346 return clib_error_return (0, "unknown input `%U'",
2347 format_unformat_error, input);
2350 /* Note: dns_add_static_entry consumes the name vector if OK... */
2351 if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2353 rv = dns_add_static_entry (dm, name, dns_reply_data);
2356 case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2358 vec_free (dns_reply_data);
2359 return clib_error_return (0, "%v already in the cache...", name);
2364 return clib_error_return (0, "dns_add_static_entry returned %d",
2373 VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2375 .path = "dns cache",
2376 .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2377 .function = dns_cache_add_del_command_fn,
2381 #define DNS_FORMAT_TEST 1
2383 #if DNS_FORMAT_TEST > 0
2386 static u8 dns_reply_data_initializer[] =
2387 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2388 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2390 0x0, 0xff, /* type ALL */
2391 0x0, 0x1, /* class IN */
2392 0xc0, 0xc, /* pointer to yahoo.com name */
2393 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2394 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2395 0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2396 0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2397 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2398 0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2399 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2400 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2401 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2402 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2403 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2404 0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2405 0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2407 0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2408 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2409 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2410 0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2411 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2413 0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2414 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2415 0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2416 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2418 0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2419 0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2421 0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2423 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2425 0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2427 0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2428 0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2429 0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2433 /* www.cisco.com, has no addresses in reply */
2434 static u8 dns_reply_data_initializer[] = {
2435 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2436 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2437 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2439 0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2440 0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2441 0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2442 0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2443 0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2446 /* bind8 (linux widget, w/ nasty double pointer chasees */
2447 static u8 dns_reply_data_initializer[] = {
2449 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08,
2451 0x00, 0x06, 0x00, 0x06, 0x0a, 0x6f, 0x72, 0x69,
2453 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77, 0x77, 0x05,
2455 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f,
2457 0x6d, 0x00, 0x00, 0xff, 0x00, 0x01, 0x0a, 0x6f,
2459 0x72, 0x69, 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77,
2461 0x77, 0x05, 0x43, 0x49, 0x53, 0x43, 0x4f, 0xc0,
2464 0x1d, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2467 0x9a, 0x00, 0x18, 0x15, 0x72, 0x63, 0x64,
2468 0x6e, 0x39, 0x2d, 0x31, 0x34, 0x70, 0x2d, 0x64, 0x63,
2469 0x7a, 0x30, 0x35, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31,
2470 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00, 0x01, 0x00,
2471 0x00, 0x05, 0x9a, 0x00, 0x1a, 0x17, 0x61, 0x6c, 0x6c,
2472 0x6e, 0x30, 0x31, 0x2d, 0x61, 0x67, 0x30, 0x39, 0x2d,
2473 0x64, 0x63, 0x7a, 0x30, 0x33, 0x6e, 0x2d, 0x67, 0x73,
2474 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00,
2475 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x10, 0x0d, 0x72,
2476 0x74, 0x70, 0x35, 0x2d, 0x64, 0x6d, 0x7a, 0x2d, 0x67,
2477 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2478 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x18, 0x15,
2479 0x6d, 0x74, 0x76, 0x35, 0x2d, 0x61, 0x70, 0x31, 0x30,
2480 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x36, 0x6e, 0x2d, 0x67,
2481 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2482 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x1b, 0x18,
2483 0x73, 0x6e, 0x67, 0x64, 0x63, 0x30, 0x31, 0x2d, 0x61,
2484 0x62, 0x30, 0x37, 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x31,
2485 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0,
2486 0x26, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a,
2487 0x00, 0x1a, 0x17, 0x61, 0x65, 0x72, 0x30, 0x31, 0x2d,
2488 0x72, 0x34, 0x63, 0x32, 0x35, 0x2d, 0x64, 0x63, 0x7a,
2489 0x30, 0x31, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0,
2490 0x17, 0xc0, 0x26, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2491 0x00, 0x81, 0x00, 0x04, 0x48, 0xa3, 0x04, 0xa1, 0xc0,
2492 0x26, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82,
2493 0x00, 0x10, 0x20, 0x01, 0x04, 0x20, 0x12, 0x01, 0x00,
2494 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
2495 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2496 0x9a, 0x00, 0x02, 0xc0, 0xf4, 0xc0, 0x0c, 0x00, 0x02,
2497 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0,
2498 0xcd, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00,
2499 0x05, 0x9a, 0x00, 0x02, 0xc0, 0x8d, 0xc0, 0x0c, 0x00,
2500 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02,
2501 0xc0, 0x43, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00,
2502 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0, 0xa9, 0xc0, 0x0c,
2503 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00,
2504 0x02, 0xc0, 0x67, 0xc0, 0x8d, 0x00, 0x01, 0x00, 0x01,
2505 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0x40, 0x66, 0xf6,
2506 0x05, 0xc0, 0xa9, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2507 0x07, 0x08, 0x00, 0x04, 0xad, 0x24, 0xe0, 0x64, 0xc0,
2508 0x43, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08,
2509 0x00, 0x04, 0x48, 0xa3, 0x04, 0x1c, 0xc0, 0xf4, 0x00,
2510 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04,
2511 0xad, 0x26, 0xd4, 0x6c, 0xc0, 0x67, 0x00, 0x01, 0x00,
2512 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x25,
2513 0x90, 0x64, 0xc0, 0xcd, 0x00, 0x01, 0x00, 0x01, 0x00,
2514 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x27, 0x70, 0x44,
2518 static u8 dns_reply_data_initializer[] =
2519 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
2520 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
2521 0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
2522 0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
2524 0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
2525 0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
2526 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
2527 0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
2528 0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
2529 0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
2530 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
2531 0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
2532 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
2533 0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
2534 0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
2535 0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
2536 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
2537 0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
2538 0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
2539 0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
2540 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2541 0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
2542 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
2543 0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
2544 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
2545 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
2546 0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
2548 0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2552 /* www.weatherlink.com */
2553 static u8 dns_reply_data_initializer[] = {
2554 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2555 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x0b,
2556 0x77, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x6c, 0x69,
2557 0x6e, 0x6b, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0xff,
2558 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00,
2559 0x00, 0x0c, 0x9e, 0x00, 0x1f, 0x0e, 0x64, 0x33, 0x6b,
2560 0x72, 0x30, 0x67, 0x75, 0x62, 0x61, 0x31, 0x64, 0x76,
2561 0x77, 0x66, 0x0a, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x66,
2562 0x72, 0x6f, 0x6e, 0x74, 0x03, 0x6e, 0x65, 0x74, 0x00,
2567 static clib_error_t *
2568 test_dns_fmt_command_fn (vlib_main_t * vm,
2569 unformat_input_t * input, vlib_cli_command_t * cmd)
2571 u8 *dns_reply_data = 0;
2574 vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2576 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2578 if (unformat (input, "verbose %d", &verbose))
2580 else if (unformat (input, "verbose"))
2583 return clib_error_return (0, "unknown input `%U'",
2584 format_unformat_error, input);
2587 vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2589 memcpy (dns_reply_data, dns_reply_data_initializer,
2590 ARRAY_LEN (dns_reply_data_initializer));
2592 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2594 clib_memset (rmp, 0, sizeof (*rmp));
2596 rv = vnet_dns_response_to_reply (dns_reply_data, rmp, 0 /* ttl-ptr */ );
2600 case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2601 vlib_cli_output (vm, "no addresses found...");
2605 vlib_cli_output (vm, "response to reply returned %d", rv);
2610 vlib_cli_output (vm, "ip4 address: %U", format_ip4_address,
2611 (ip4_address_t *) rmp->ip4_address);
2613 vlib_cli_output (vm, "ip6 address: %U", format_ip6_address,
2614 (ip6_address_t *) rmp->ip6_address);
2618 vec_free (dns_reply_data);
2625 VLIB_CLI_COMMAND (test_dns_fmt_command) =
2627 .path = "test dns format",
2628 .short_help = "test dns format",
2629 .function = test_dns_fmt_command_fn,
2633 static clib_error_t *
2634 test_dns_unfmt_command_fn (vlib_main_t * vm,
2635 unformat_input_t * input, vlib_cli_command_t * cmd)
2637 u8 *dns_reply_data = 0;
2641 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2643 if (unformat (input, "verbose %d", &verbose))
2645 else if (unformat (input, "verbose"))
2647 else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2650 return clib_error_return (0, "unknown input `%U'",
2651 format_unformat_error, input);
2655 return clib_error_return (0, "dns data not set...");
2657 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2659 vec_free (dns_reply_data);
2665 VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2667 .path = "test dns unformat",
2668 .short_help = "test dns unformat <name> [ip4][ip6]",
2669 .function = test_dns_unfmt_command_fn,
2673 static clib_error_t *
2674 test_dns_expire_command_fn (vlib_main_t * vm,
2675 unformat_input_t * input,
2676 vlib_cli_command_t * cmd)
2678 dns_main_t *dm = &dns_main;
2682 dns_cache_entry_t *ep;
2684 if (unformat (input, "%v", &name))
2687 _vec_len (name) -= 1;
2690 return clib_error_return (0, "no name provided");
2692 dns_cache_lock (dm, 7);
2694 p = hash_get_mem (dm->cache_entry_by_name, name);
2697 dns_cache_unlock (dm);
2698 e = clib_error_return (0, "%s is not in the cache...", name);
2703 ep = pool_elt_at_index (dm->entries, p[0]);
2705 ep->expiration_time = 0;
2711 VLIB_CLI_COMMAND (test_dns_expire_command) =
2713 .path = "test dns expire",
2714 .short_help = "test dns expire <name>",
2715 .function = test_dns_expire_command_fn,
2721 vnet_send_dns6_reply (vlib_main_t * vm, dns_main_t * dm,
2722 dns_pending_request_t * pr, dns_cache_entry_t * ep,
2725 clib_warning ("Unimplemented...");
2730 vnet_send_dns4_reply (vlib_main_t * vm, dns_main_t * dm,
2731 dns_pending_request_t * pr, dns_cache_entry_t * ep,
2735 fib_prefix_t prefix;
2736 fib_node_index_t fei;
2737 u32 sw_if_index, fib_index;
2738 ip4_main_t *im4 = &ip4_main;
2739 ip_lookup_main_t *lm4 = &im4->lookup_main;
2740 ip_interface_address_t *ia = 0;
2741 ip4_address_t *src_address;
2749 vl_api_dns_resolve_name_reply_t _rnr, *rnr = &_rnr;
2750 vl_api_dns_resolve_ip_reply_t _rir, *rir = &_rir;
2757 int is_recycle = (b0 != 0);
2759 ASSERT (ep && ep->dns_response);
2761 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2763 /* Quick and dirty way to dig up the A-record address. $$ FIXME */
2764 clib_memset (rnr, 0, sizeof (*rnr));
2765 if (vnet_dns_response_to_reply (ep->dns_response, rnr, &ttl))
2767 /* clib_warning ("response_to_reply failed..."); */
2770 if (rnr->ip4_set == 0)
2772 /* clib_warning ("No A-record..."); */
2776 else if (pr->request_type == DNS_PEER_PENDING_IP_TO_NAME)
2778 clib_memset (rir, 0, sizeof (*rir));
2779 if (vnet_dns_response_to_name (ep->dns_response, rir, &ttl))
2781 /* clib_warning ("response_to_name failed..."); */
2787 clib_warning ("Unknown request type %d", pr->request_type);
2791 /* Initialize a buffer */
2794 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2796 b0 = vlib_get_buffer (vm, bi);
2800 /* Use the buffer we were handed. Reinitialize it... */
2801 vlib_buffer_t bt = { };
2802 /* push/pop the reference count */
2803 u8 save_ref_count = b0->ref_count;
2804 vlib_buffer_copy_template (b0, &bt);
2805 b0->ref_count = save_ref_count;
2806 bi = vlib_get_buffer_index (vm, b0);
2809 if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
2810 vlib_buffer_free_one (vm, b0->next_buffer);
2813 * Reset the buffer. We recycle the DNS request packet in the cache
2814 * hit case, and reply immediately from the request node.
2816 * In the resolution-required / deferred case, resetting a freshly-allocated
2817 * buffer won't hurt. We hope.
2819 b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
2820 | VLIB_BUFFER_TOTAL_LENGTH_VALID);
2821 vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; /* "local0" */
2822 vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
2824 /* Find a FIB path to the peer we're trying to answer */
2825 clib_memcpy (&prefix.fp_addr.ip4, pr->dst_address, sizeof (ip4_address_t));
2826 prefix.fp_proto = FIB_PROTOCOL_IP4;
2829 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
2830 if (fib_index == (u32) ~ 0)
2832 clib_warning ("no fib table");
2836 fei = fib_table_lookup (fib_index, &prefix);
2838 /* Couldn't find route to destination. Bail out. */
2839 if (fei == FIB_NODE_INDEX_INVALID)
2841 clib_warning ("no route to DNS server");
2845 sw_if_index = fib_entry_get_resolving_interface (fei);
2847 if (sw_if_index == ~0)
2850 ("route to %U exists, fei %d, get_resolving_interface returned"
2851 " ~0", fei, format_ip4_address, &prefix.fp_addr);
2856 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnumbered */,
2858 src_address = ip_interface_address_get_address (lm4, ia);
2859 goto found_src_address;
2863 clib_warning ("FIB BUG");
2868 ip = vlib_buffer_get_current (b0);
2869 udp = (udp_header_t *) (ip + 1);
2870 dns_response = (u8 *) (udp + 1);
2871 clib_memset (ip, 0, sizeof (*ip) + sizeof (*udp));
2874 * Start with the variadic portion of the exercise.
2875 * Turn the name into a set of DNS "labels". Max length
2876 * per label is 63, enforce that.
2878 reply = name_to_labels (pr->name);
2879 vec_free (pr->name);
2881 qp_offset = vec_len (reply);
2883 /* Add space for the query header */
2884 vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
2886 qp = (dns_query_t *) (reply + qp_offset);
2888 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2889 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
2891 qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2893 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
2895 /* Punch in space for the dns_header_t */
2896 vec_insert (reply, sizeof (dns_header_t), 0);
2898 dh = (dns_header_t *) reply;
2900 /* Transaction ID = pool index */
2903 /* Announce that we did a recursive lookup */
2904 tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
2906 tmp |= DNS_RCODE_NAME_ERROR;
2907 dh->flags = clib_host_to_net_u16 (tmp);
2908 dh->qdcount = clib_host_to_net_u16 (1);
2909 dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
2913 /* If the name resolution worked, cough up an appropriate RR */
2916 /* Add the answer. First, a name pointer (0xC00C) */
2917 vec_add1 (reply, 0xC0);
2918 vec_add1 (reply, 0x0C);
2920 /* Now, add single A-rec RR */
2921 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2923 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
2924 rr = (dns_rr_t *) rrptr;
2926 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
2927 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2928 rr->ttl = clib_host_to_net_u32 (ttl);
2929 rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
2930 clib_memcpy (rr->rdata, rnr->ip4_address, sizeof (ip4_address_t));
2934 /* Or a single PTR RR */
2935 u8 *vecname = format (0, "%s", rir->name);
2936 u8 *label_vec = name_to_labels (vecname);
2939 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
2940 rr = (dns_rr_t *) rrptr;
2941 rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2942 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2943 rr->ttl = clib_host_to_net_u32 (ttl);
2944 rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
2945 clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
2946 vec_free (label_vec);
2949 clib_memcpy (dns_response, reply, vec_len (reply));
2951 /* Set the packet length */
2952 b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
2955 ip->ip_version_and_header_length = 0x45;
2956 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
2958 ip->protocol = IP_PROTOCOL_UDP;
2959 ip->src_address.as_u32 = src_address->as_u32;
2960 clib_memcpy (ip->dst_address.as_u8, pr->dst_address,
2961 sizeof (ip4_address_t));
2962 ip->checksum = ip4_header_checksum (ip);
2965 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
2966 udp->dst_port = pr->dst_port;
2967 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
2973 * Ship pkts made out of whole cloth to ip4_lookup
2974 * Caller will ship recycled dns reply packets to ip4_lookup
2976 if (is_recycle == 0)
2978 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
2979 to_next = vlib_frame_vector_args (f);
2982 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
2986 #include <dns/dns.api.c>
2987 static clib_error_t *
2988 dns_init (vlib_main_t * vm)
2990 dns_main_t *dm = &dns_main;
2992 dm->vnet_main = vnet_get_main ();
2993 dm->name_cache_size = 1000;
2994 dm->max_ttl_in_seconds = 86400;
2995 dm->random_seed = 0xDEADDABE;
2996 dm->api_main = vlibapi_get_main ();
2998 /* Ask for a correctly-sized block of API message decode slots */
2999 dm->msg_id_base = setup_message_id_table ();
3004 VLIB_INIT_FUNCTION (dns_init);
3007 VLIB_PLUGIN_REGISTER () =
3009 .version = VPP_BUILD_VER,
3010 .description = "Simple DNS name resolver",
3016 * fd.io coding-style-patch-verification: ON
3019 * eval: (c-set-style "gnu")