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, dns_resolve_name_t *rn,
1170 u8 *curpos, *pos, *pos2;
1174 int pointer_chase, addr_set = 0;
1176 h = (dns_header_t *) response;
1177 flags = clib_net_to_host_u16 (h->flags);
1178 rcode = flags & DNS_RCODE_MASK;
1180 /* See if the response is OK, etc. */
1184 case DNS_RCODE_NO_ERROR:
1187 case DNS_RCODE_NAME_ERROR:
1188 case DNS_RCODE_FORMAT_ERROR:
1189 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1191 case DNS_RCODE_SERVER_FAILURE:
1192 case DNS_RCODE_NOT_IMPLEMENTED:
1193 case DNS_RCODE_REFUSED:
1194 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1197 /* No answers? Loser... */
1198 if (clib_net_to_host_u16 (h->anscount) < 1)
1199 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1201 curpos = (u8 *) (h + 1);
1203 /* Skip the name we asked about */
1206 /* Should never happen, but stil... */
1207 if ((len & 0xC0) == 0xC0)
1211 /* skip the name / label-set */
1220 limit = clib_net_to_host_u16 (h->qdcount);
1221 qp = (dns_query_t *) curpos;
1226 limit = clib_net_to_host_u16 (h->anscount);
1228 for (i = 0; i < limit; i++)
1230 pos = pos2 = curpos;
1233 /* Expect pointer chases in the answer section... */
1234 if ((pos2[0] & 0xC0) == 0xC0)
1237 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1246 if ((pos2[0] & 0xc0) == 0xc0)
1249 * If we've already done one pointer chase,
1250 * do not move the pos pointer.
1252 if (pointer_chase == 0)
1254 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1262 if (pointer_chase == 0)
1265 rr = (dns_rr_t *) pos;
1267 switch (clib_net_to_host_u16 (rr->type))
1270 /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1271 ip_address_set (&rn->address, rr->rdata, AF_IP4);
1272 ttl = clib_net_to_host_u32 (rr->ttl);
1274 if (min_ttlp && *min_ttlp > ttl)
1278 /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1279 ip_address_set (&rn->address, rr->rdata, AF_IP6);
1280 ttl = clib_net_to_host_u32 (rr->ttl);
1281 if (min_ttlp && *min_ttlp > ttl)
1289 /* Might as well stop ASAP */
1292 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1297 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1302 vnet_dns_response_to_name (u8 * response,
1303 vl_api_dns_resolve_ip_reply_t * rmp,
1311 u8 *curpos, *pos, *pos2;
1316 u8 *junk __attribute__ ((unused));
1320 h = (dns_header_t *) response;
1321 flags = clib_net_to_host_u16 (h->flags);
1322 rcode = flags & DNS_RCODE_MASK;
1324 /* See if the response is OK, etc. */
1328 case DNS_RCODE_NO_ERROR:
1331 case DNS_RCODE_NAME_ERROR:
1332 case DNS_RCODE_FORMAT_ERROR:
1333 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1335 case DNS_RCODE_SERVER_FAILURE:
1336 case DNS_RCODE_NOT_IMPLEMENTED:
1337 case DNS_RCODE_REFUSED:
1338 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1341 /* No answers? Loser... */
1342 if (clib_net_to_host_u16 (h->anscount) < 1)
1343 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1345 curpos = (u8 *) (h + 1);
1347 /* Skip the name we asked about */
1350 /* Should never happen, but stil... */
1351 if ((len & 0xC0) == 0xC0)
1355 /* skip the name / label-set */
1364 limit = clib_net_to_host_u16 (h->qdcount);
1365 qp = (dns_query_t *) curpos;
1370 limit = clib_net_to_host_u16 (h->anscount);
1372 for (i = 0; i < limit; i++)
1374 pos = pos2 = curpos;
1377 /* Expect pointer chases in the answer section... */
1378 if ((pos2[0] & 0xC0) == 0xC0)
1381 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1390 if ((pos2[0] & 0xc0) == 0xc0)
1393 * If we've already done one pointer chase,
1394 * do not move the pos pointer.
1396 if (pointer_chase == 0)
1398 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1406 if (pointer_chase == 0)
1409 rr = (dns_rr_t *) pos;
1411 switch (clib_net_to_host_u16 (rr->type))
1414 name = vnet_dns_labels_to_name (rr->rdata, response, &junk);
1415 memcpy (rmp->name, name, vec_len (name));
1416 ttl = clib_net_to_host_u32 (rr->ttl);
1419 rmp->name[vec_len (name)] = 0;
1425 /* Might as well stop ASAP */
1428 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1433 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1438 dns_resolve_name (u8 *name, dns_cache_entry_t **ep, dns_pending_request_t *t0,
1439 dns_resolve_name_t *rn)
1441 dns_main_t *dm = &dns_main;
1442 vlib_main_t *vm = vlib_get_main ();
1444 int rv = vnet_dns_resolve_name (vm, dm, name, t0, ep);
1446 /* Error, e.g. not enabled? Tell the user */
1450 /* Resolution pending? Don't reply... */
1454 return vnet_dns_response_to_reply (ep[0]->dns_response, rn, 0 /* ttl-ptr */);
1458 vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1460 dns_main_t *dm = &dns_main;
1461 vl_api_dns_resolve_name_reply_t *rmp;
1462 dns_cache_entry_t *ep = 0;
1463 dns_pending_request_t _t0, *t0 = &_t0;
1465 dns_resolve_name_t rn;
1467 /* Sanitize the name slightly */
1468 mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1470 t0->request_type = DNS_API_PENDING_NAME_TO_IP;
1471 t0->client_index = mp->client_index;
1472 t0->client_context = mp->context;
1474 rv = dns_resolve_name (mp->name, &ep, t0, &rn);
1476 /* Error, e.g. not enabled? Tell the user */
1479 REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1483 /* Resolution pending? Don't reply... */
1488 REPLY_MACRO2 (VL_API_DNS_RESOLVE_NAME_REPLY, ({
1489 ip_address_copy_addr (rmp->ip4_address, &rn.address);
1490 if (ip_addr_version (&rn.address) == AF_IP4)
1499 vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
1501 vlib_main_t *vm = vlib_get_main ();
1502 dns_main_t *dm = &dns_main;
1503 vl_api_dns_resolve_ip_reply_t *rmp;
1504 dns_cache_entry_t *ep;
1507 u8 *lookup_name = 0;
1509 dns_pending_request_t _t0, *t0 = &_t0;
1513 for (i = 15; i >= 0; i--)
1515 digit = mp->address[i];
1516 nybble = (digit & 0x0F);
1518 vec_add1 (lookup_name, (nybble - 10) + 'a');
1520 vec_add1 (lookup_name, nybble + '0');
1521 vec_add1 (lookup_name, '.');
1522 nybble = (digit & 0xF0) >> 4;
1524 vec_add1 (lookup_name, (nybble - 10) + 'a');
1526 vec_add1 (lookup_name, nybble + '0');
1527 vec_add1 (lookup_name, '.');
1529 len = vec_len (lookup_name);
1530 vec_validate (lookup_name, len + 8);
1531 memcpy (lookup_name + len, "ip6.arpa", 8);
1535 for (i = 3; i >= 0; i--)
1537 digit = mp->address[i];
1538 lookup_name = format (lookup_name, "%d.", digit);
1540 lookup_name = format (lookup_name, "in-addr.arpa");
1543 vec_add1 (lookup_name, 0);
1545 t0->request_type = DNS_API_PENDING_IP_TO_NAME;
1546 t0->client_index = mp->client_index;
1547 t0->client_context = mp->context;
1549 rv = vnet_dns_resolve_name (vm, dm, lookup_name, t0, &ep);
1551 vec_free (lookup_name);
1553 /* Error, e.g. not enabled? Tell the user */
1556 REPLY_MACRO (VL_API_DNS_RESOLVE_IP_REPLY);
1560 /* Resolution pending? Don't reply... */
1565 REPLY_MACRO2(VL_API_DNS_RESOLVE_IP_REPLY,
1567 rv = vnet_dns_response_to_name (ep->dns_response, rmp, 0 /* ttl-ptr */);
1568 rmp->retval = clib_host_to_net_u32 (rv);
1573 static clib_error_t *
1574 dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1576 dns_main_t *dm = &dns_main;
1578 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1580 if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1582 else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1585 return clib_error_return (0, "unknown input `%U'",
1586 format_unformat_error, input);
1591 VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1594 unformat_dns_reply (unformat_input_t * input, va_list * args)
1596 u8 **result = va_arg (*args, u8 **);
1597 u8 **namep = va_arg (*args, u8 **);
1611 if (unformat (input, "%v", &name))
1614 if (unformat (input, "%U", unformat_ip4_address, &a4))
1617 if (unformat (input, "%U", unformat_ip6_address, &a6))
1621 if (unformat (input, "%U", unformat_ip6_address, &a6))
1624 if (unformat (input, "%U", unformat_ip4_address, &a6))
1628 /* Must have a name */
1632 /* Must have at least one address */
1633 if (!(a4_set + a6_set))
1636 /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1637 ce = name_to_labels (name);
1638 qp_offset = vec_len (ce);
1640 /* Add space for the query header */
1641 vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1642 qp = (dns_query_t *) (ce + qp_offset);
1644 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1645 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1647 /* Punch in space for the dns_header_t */
1648 vec_insert (ce, sizeof (dns_header_t), 0);
1650 h = (dns_header_t *) ce;
1652 /* Fake Transaction ID */
1655 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1656 h->qdcount = clib_host_to_net_u16 (1);
1657 h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1661 /* Now append one or two A/AAAA RR's... */
1664 /* Pointer to the name (DGMS) */
1665 vec_add1 (ce, 0xC0);
1666 vec_add1 (ce, 0x0C);
1667 vec_add2 (ce, rru8, sizeof (*rr) + 4);
1669 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1670 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1671 rr->ttl = clib_host_to_net_u32 (86400);
1672 rr->rdlength = clib_host_to_net_u16 (4);
1673 memcpy (rr->rdata, &a4, sizeof (a4));
1677 /* Pointer to the name (DGMS) */
1678 vec_add1 (ce, 0xC0);
1679 vec_add1 (ce, 0x0C);
1680 vec_add2 (ce, rru8, sizeof (*rr) + 16);
1682 rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1683 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1684 rr->ttl = clib_host_to_net_u32 (86400);
1685 rr->rdlength = clib_host_to_net_u16 (16);
1686 memcpy (rr->rdata, &a6, sizeof (a6));
1698 format_dns_query (u8 * s, va_list * args)
1700 u8 **curpos = va_arg (*args, u8 **);
1701 int verbose = va_arg (*args, int);
1706 s = format (s, " Name: ");
1708 /* Unwind execrated counted-label sheit */
1714 for (i = 0; i < len; i++)
1715 vec_add1 (s, *pos++);
1727 qp = (dns_query_t *) pos;
1730 switch (clib_net_to_host_u16 (qp->type))
1733 s = format (s, "type A\n");
1736 s = format (s, "type AAAA\n");
1739 s = format (s, "type ALL\n");
1743 s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1748 pos += sizeof (*qp);
1755 * format dns reply data
1756 * verbose > 1, dump everything
1757 * verbose == 1, dump all A and AAAA records
1758 * verbose == 0, dump one A record, and one AAAA record
1762 format_dns_reply_data (u8 * s, va_list * args)
1764 u8 *reply = va_arg (*args, u8 *);
1765 u8 **curpos = va_arg (*args, u8 **);
1766 int verbose = va_arg (*args, int);
1767 int *print_ip4 = va_arg (*args, int *);
1768 int *print_ip6 = va_arg (*args, int *);
1773 int pointer_chase = 0;
1775 u16 rrtype_host_byte_order;
1777 pos = pos2 = *curpos;
1780 s = format (s, " ");
1782 /* chase pointer? almost always yes here... */
1783 if ((pos2[0] & 0xc0) == 0xc0)
1786 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1794 for (i = 0; i < len; i++)
1797 vec_add1 (s, *pos2);
1800 if ((pos2[0] & 0xc0) == 0xc0)
1803 * If we've already done one pointer chase,
1804 * do not move the pos pointer.
1806 if (pointer_chase == 0)
1808 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1826 if (pointer_chase == 0)
1829 rr = (dns_rr_t *) pos;
1830 rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
1832 switch (rrtype_host_byte_order)
1837 s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1838 format_ip4_address, rr->rdata);
1843 s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1844 clib_net_to_host_u32 (rr->ttl));
1849 pos += sizeof (*rr) + 4;
1855 s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1856 format_ip6_address, rr->rdata);
1861 s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1862 clib_net_to_host_u32 (rr->ttl));
1866 pos += sizeof (*rr) + 16;
1872 s = format (s, "TEXT: ");
1873 for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1874 vec_add1 (s, rr->rdata[i]);
1877 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1880 case DNS_TYPE_HINFO:
1882 /* Two counted strings. DGMS */
1888 s = format (s, "HINFO: ");
1891 for (i = 0; i < *len; i++)
1892 vec_add1 (s, *curpos++);
1896 for (i = 0; i < *len; i++)
1897 vec_add1 (s, *curpos++);
1902 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1905 case DNS_TYPE_NAMESERVER:
1908 s = format (s, "Nameserver: ");
1911 /* chase pointer? */
1912 if ((pos2[0] & 0xc0) == 0xc0)
1915 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1922 for (i = 0; i < len; i++)
1923 vec_add1 (s, *pos2++);
1925 /* chase pointer, typically to offset 12... */
1926 if (pos2[0] == 0xC0)
1927 pos2 = reply + pos2[1];
1936 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1939 case DNS_TYPE_MAIL_EXCHANGE:
1942 tp = (u16 *) rr->rdata;
1944 s = format (s, "Mail Exchange: Preference %d ", (u32)
1945 clib_net_to_host_u16 (*tp));
1947 pos2 = rr->rdata + 2;
1949 /* chase pointer? */
1950 if (pos2[0] == 0xc0)
1951 pos2 = reply + pos2[1];
1957 for (i = 0; i < len; i++)
1958 vec_add1 (s, *pos2++);
1961 if (pos2[0] == 0xC0)
1962 pos2 = reply + pos2[1];
1972 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1976 case DNS_TYPE_CNAME:
1979 tp = (u16 *) rr->rdata;
1981 if (rrtype_host_byte_order == DNS_TYPE_CNAME)
1982 s = format (s, "CNAME: ");
1984 s = format (s, "PTR: ");
1988 /* chase pointer? */
1989 if (pos2[0] == 0xc0)
1990 pos2 = reply + pos2[1];
1996 for (i = 0; i < len; i++)
1997 vec_add1 (s, *pos2++);
2000 if (pos2[0] == 0xC0)
2001 pos2 = reply + pos2[1];
2010 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2015 s = format (s, "type %d: len %d\n",
2016 (int) clib_net_to_host_u16 (rr->type),
2017 sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
2018 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2028 format_dns_reply (u8 * s, va_list * args)
2030 u8 *reply_as_u8 = va_arg (*args, u8 *);
2031 int verbose = va_arg (*args, int);
2039 h = (dns_header_t *) reply_as_u8;
2040 id = clib_net_to_host_u16 (h->id);
2041 flags = clib_net_to_host_u16 (h->flags);
2045 s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
2047 s = format (s, " %s %s %s %s\n",
2048 (flags & DNS_RA) ? "recur" : "no-recur",
2049 (flags & DNS_RD) ? "recur-des" : "no-recur-des",
2050 (flags & DNS_TC) ? "trunc" : "no-trunc",
2051 (flags & DNS_AA) ? "auth" : "non-auth");
2052 s = format (s, " %d queries, %d answers, %d name-servers,"
2054 clib_net_to_host_u16 (h->qdcount),
2055 clib_net_to_host_u16 (h->anscount),
2056 clib_net_to_host_u16 (h->nscount),
2057 clib_net_to_host_u16 (h->arcount));
2060 curpos = (u8 *) (h + 1);
2065 s = format (s, " Queries:\n");
2066 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
2068 /* The query is variable-length, so curpos is a value-result parm */
2069 s = format (s, "%U", format_dns_query, &curpos, verbose);
2075 s = format (s, " Replies:\n");
2077 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
2079 /* curpos is a value-result parm */
2080 s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
2081 verbose, &print_ip4, &print_ip6);
2088 format_dns_cache (u8 * s, va_list * args)
2090 dns_main_t *dm = va_arg (*args, dns_main_t *);
2091 f64 now = va_arg (*args, f64);
2092 int verbose = va_arg (*args, int);
2093 u8 *name = va_arg (*args, u8 *);
2094 dns_cache_entry_t *ep;
2098 if (dm->is_enabled == 0)
2100 s = format (s, "The DNS cache is disabled...");
2104 if (pool_elts (dm->entries) == 0)
2106 s = format (s, "The DNS cache is empty...");
2110 dns_cache_lock (dm, 6);
2114 p = hash_get_mem (dm->cache_entry_by_name, name);
2117 s = format (s, "%s is not in the cache...", name);
2118 dns_cache_unlock (dm);
2122 ep = pool_elt_at_index (dm->entries, p[0]);
2123 /* Magic to spit out a C-initializer to research hemorrhoids... */
2127 s = format (s, "static u8 dns_reply_data_initializer[] =\n");
2128 s = format (s, "{\n");
2130 for (i = 0; i < vec_len (ep->dns_response); i++)
2137 s = format (s, "0x%02x, ", ep->dns_response[i]);
2139 s = format (s, "};\n");
2143 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2145 ASSERT (ep->dns_response);
2146 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2151 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2152 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2154 s = format (s, "%s%s -> %U", ss, ep->name,
2155 format_dns_reply, ep->dns_response, verbose);
2156 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2158 f64 time_left = ep->expiration_time - now;
2159 if (time_left > 0.0)
2160 s = format (s, " TTL left %.1f", time_left);
2162 s = format (s, " EXPIRED");
2167 ASSERT (ep->dns_request);
2168 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2176 s = format (s, "DNS cache contains %d entries\n", pool_elts (dm->entries));
2181 pool_foreach (ep, dm->entries)
2183 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2185 ASSERT (ep->dns_response);
2186 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2191 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2192 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2194 s = format (s, "%s%s -> %U", ss, ep->name,
2198 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2200 f64 time_left = ep->expiration_time - now;
2201 if (time_left > 0.0)
2202 s = format (s, " TTL left %.1f", time_left);
2204 s = format (s, " EXPIRED");
2207 s = format (s, " %d client notifications pending\n",
2208 vec_len(ep->pending_requests));
2213 ASSERT (ep->dns_request);
2214 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2222 dns_cache_unlock (dm);
2227 static clib_error_t *
2228 show_dns_cache_command_fn (vlib_main_t * vm,
2229 unformat_input_t * input, vlib_cli_command_t * cmd)
2231 dns_main_t *dm = &dns_main;
2234 f64 now = vlib_time_now (vm);
2236 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2238 if (unformat (input, "verbose %d", &verbose))
2240 else if (unformat (input, "verbose"))
2242 else if (unformat (input, "name %s", &name))
2245 return clib_error_return (0, "unknown input `%U'",
2246 format_unformat_error, input);
2249 vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
2255 VLIB_CLI_COMMAND (show_dns_cache_command) =
2257 .path = "show dns cache",
2258 .short_help = "show dns cache [verbose [nn]]",
2259 .function = show_dns_cache_command_fn,
2263 static clib_error_t *
2264 show_dns_servers_command_fn (vlib_main_t * vm,
2265 unformat_input_t * input,
2266 vlib_cli_command_t * cmd)
2268 dns_main_t *dm = &dns_main;
2271 if ((vec_len (dm->ip4_name_servers) + vec_len (dm->ip6_name_servers)) == 0)
2272 return clib_error_return (0, "No name servers configured...");
2274 if (vec_len (dm->ip4_name_servers))
2276 vlib_cli_output (vm, "ip4 name servers:");
2277 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
2278 vlib_cli_output (vm, "%U", format_ip4_address,
2279 dm->ip4_name_servers + i);
2281 if (vec_len (dm->ip6_name_servers))
2283 vlib_cli_output (vm, "ip6 name servers:");
2284 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
2285 vlib_cli_output (vm, "%U", format_ip6_address,
2286 dm->ip4_name_servers + i);
2292 VLIB_CLI_COMMAND (show_dns_server_command) =
2294 .path = "show dns servers",
2295 .short_help = "show dns servers",
2296 .function = show_dns_servers_command_fn,
2301 static clib_error_t *
2302 dns_cache_add_del_command_fn (vlib_main_t * vm,
2303 unformat_input_t * input,
2304 vlib_cli_command_t * cmd)
2306 dns_main_t *dm = &dns_main;
2312 clib_error_t *error;
2314 if (unformat (input, "add"))
2316 if (unformat (input, "del"))
2318 if (unformat (input, "clear"))
2321 if (is_add == -1 && is_clear == -1)
2322 return clib_error_return (0, "add / del / clear required...");
2326 rv = dns_cache_clear (dm);
2332 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2333 error = clib_error_return (0, "Name resolution not enabled");
2338 /* Delete (by name)? */
2341 if (unformat (input, "%v", &name))
2343 rv = dns_delete_by_name (dm, name);
2346 case VNET_API_ERROR_NO_SUCH_ENTRY:
2347 error = clib_error_return (0, "%v not in the cache...", name);
2351 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2352 error = clib_error_return (0, "Name resolution not enabled");
2361 error = clib_error_return (0, "dns_delete_by_name returned %d",
2367 return clib_error_return (0, "unknown input `%U'",
2368 format_unformat_error, input);
2371 /* Note: dns_add_static_entry consumes the name vector if OK... */
2372 if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2374 rv = dns_add_static_entry (dm, name, dns_reply_data);
2377 case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2379 vec_free (dns_reply_data);
2380 return clib_error_return (0, "%v already in the cache...", name);
2385 return clib_error_return (0, "dns_add_static_entry returned %d",
2394 VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2396 .path = "dns cache",
2397 .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2398 .function = dns_cache_add_del_command_fn,
2402 #define DNS_FORMAT_TEST 1
2404 #if DNS_FORMAT_TEST > 0
2407 static u8 dns_reply_data_initializer[] =
2408 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2409 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2411 0x0, 0xff, /* type ALL */
2412 0x0, 0x1, /* class IN */
2413 0xc0, 0xc, /* pointer to yahoo.com name */
2414 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2415 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2416 0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2417 0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2418 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2419 0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2420 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2421 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2422 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2423 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2424 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2425 0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2426 0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2428 0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2429 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2430 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2431 0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2432 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2434 0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2435 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2436 0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2437 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2439 0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2440 0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2442 0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2444 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2446 0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2448 0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2449 0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2450 0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2454 /* www.cisco.com, has no addresses in reply */
2455 static u8 dns_reply_data_initializer[] = {
2456 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2457 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2458 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2460 0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2461 0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2462 0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2463 0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2464 0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2467 /* bind8 (linux widget, w/ nasty double pointer chasees */
2468 static u8 dns_reply_data_initializer[] = {
2470 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08,
2472 0x00, 0x06, 0x00, 0x06, 0x0a, 0x6f, 0x72, 0x69,
2474 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77, 0x77, 0x05,
2476 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f,
2478 0x6d, 0x00, 0x00, 0xff, 0x00, 0x01, 0x0a, 0x6f,
2480 0x72, 0x69, 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77,
2482 0x77, 0x05, 0x43, 0x49, 0x53, 0x43, 0x4f, 0xc0,
2485 0x1d, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2488 0x9a, 0x00, 0x18, 0x15, 0x72, 0x63, 0x64,
2489 0x6e, 0x39, 0x2d, 0x31, 0x34, 0x70, 0x2d, 0x64, 0x63,
2490 0x7a, 0x30, 0x35, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31,
2491 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00, 0x01, 0x00,
2492 0x00, 0x05, 0x9a, 0x00, 0x1a, 0x17, 0x61, 0x6c, 0x6c,
2493 0x6e, 0x30, 0x31, 0x2d, 0x61, 0x67, 0x30, 0x39, 0x2d,
2494 0x64, 0x63, 0x7a, 0x30, 0x33, 0x6e, 0x2d, 0x67, 0x73,
2495 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00,
2496 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x10, 0x0d, 0x72,
2497 0x74, 0x70, 0x35, 0x2d, 0x64, 0x6d, 0x7a, 0x2d, 0x67,
2498 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2499 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x18, 0x15,
2500 0x6d, 0x74, 0x76, 0x35, 0x2d, 0x61, 0x70, 0x31, 0x30,
2501 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x36, 0x6e, 0x2d, 0x67,
2502 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2503 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x1b, 0x18,
2504 0x73, 0x6e, 0x67, 0x64, 0x63, 0x30, 0x31, 0x2d, 0x61,
2505 0x62, 0x30, 0x37, 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x31,
2506 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0,
2507 0x26, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a,
2508 0x00, 0x1a, 0x17, 0x61, 0x65, 0x72, 0x30, 0x31, 0x2d,
2509 0x72, 0x34, 0x63, 0x32, 0x35, 0x2d, 0x64, 0x63, 0x7a,
2510 0x30, 0x31, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0,
2511 0x17, 0xc0, 0x26, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2512 0x00, 0x81, 0x00, 0x04, 0x48, 0xa3, 0x04, 0xa1, 0xc0,
2513 0x26, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82,
2514 0x00, 0x10, 0x20, 0x01, 0x04, 0x20, 0x12, 0x01, 0x00,
2515 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
2516 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2517 0x9a, 0x00, 0x02, 0xc0, 0xf4, 0xc0, 0x0c, 0x00, 0x02,
2518 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0,
2519 0xcd, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00,
2520 0x05, 0x9a, 0x00, 0x02, 0xc0, 0x8d, 0xc0, 0x0c, 0x00,
2521 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02,
2522 0xc0, 0x43, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00,
2523 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0, 0xa9, 0xc0, 0x0c,
2524 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00,
2525 0x02, 0xc0, 0x67, 0xc0, 0x8d, 0x00, 0x01, 0x00, 0x01,
2526 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0x40, 0x66, 0xf6,
2527 0x05, 0xc0, 0xa9, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2528 0x07, 0x08, 0x00, 0x04, 0xad, 0x24, 0xe0, 0x64, 0xc0,
2529 0x43, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08,
2530 0x00, 0x04, 0x48, 0xa3, 0x04, 0x1c, 0xc0, 0xf4, 0x00,
2531 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04,
2532 0xad, 0x26, 0xd4, 0x6c, 0xc0, 0x67, 0x00, 0x01, 0x00,
2533 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x25,
2534 0x90, 0x64, 0xc0, 0xcd, 0x00, 0x01, 0x00, 0x01, 0x00,
2535 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x27, 0x70, 0x44,
2539 static u8 dns_reply_data_initializer[] =
2540 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
2541 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
2542 0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
2543 0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
2545 0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
2546 0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
2547 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
2548 0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
2549 0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
2550 0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
2551 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
2552 0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
2553 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
2554 0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
2555 0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
2556 0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
2557 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
2558 0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
2559 0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
2560 0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
2561 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2562 0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
2563 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
2564 0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
2565 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
2566 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
2567 0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
2569 0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2573 /* www.weatherlink.com */
2574 static u8 dns_reply_data_initializer[] = {
2575 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2576 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x0b,
2577 0x77, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x6c, 0x69,
2578 0x6e, 0x6b, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0xff,
2579 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00,
2580 0x00, 0x0c, 0x9e, 0x00, 0x1f, 0x0e, 0x64, 0x33, 0x6b,
2581 0x72, 0x30, 0x67, 0x75, 0x62, 0x61, 0x31, 0x64, 0x76,
2582 0x77, 0x66, 0x0a, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x66,
2583 0x72, 0x6f, 0x6e, 0x74, 0x03, 0x6e, 0x65, 0x74, 0x00,
2588 static clib_error_t *
2589 test_dns_fmt_command_fn (vlib_main_t * vm,
2590 unformat_input_t * input, vlib_cli_command_t * cmd)
2592 dns_resolve_name_t _rn, *rn = &_rn;
2593 u8 *dns_reply_data = 0;
2596 vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2598 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2600 if (unformat (input, "verbose %d", &verbose))
2602 else if (unformat (input, "verbose"))
2605 return clib_error_return (0, "unknown input `%U'",
2606 format_unformat_error, input);
2609 vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2611 memcpy (dns_reply_data, dns_reply_data_initializer,
2612 ARRAY_LEN (dns_reply_data_initializer));
2614 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2616 clib_memset (rmp, 0, sizeof (*rmp));
2618 rv = vnet_dns_response_to_reply (dns_reply_data, rn, 0 /* ttl-ptr */);
2622 case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2623 vlib_cli_output (vm, "no addresses found...");
2627 vlib_cli_output (vm, "response to reply returned %d", rv);
2631 vlib_cli_output (vm, "ip address: %U", format_ip_address, &rn->address);
2635 vec_free (dns_reply_data);
2642 VLIB_CLI_COMMAND (test_dns_fmt_command) =
2644 .path = "test dns format",
2645 .short_help = "test dns format",
2646 .function = test_dns_fmt_command_fn,
2650 static clib_error_t *
2651 test_dns_unfmt_command_fn (vlib_main_t * vm,
2652 unformat_input_t * input, vlib_cli_command_t * cmd)
2654 u8 *dns_reply_data = 0;
2658 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2660 if (unformat (input, "verbose %d", &verbose))
2662 else if (unformat (input, "verbose"))
2664 else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2667 return clib_error_return (0, "unknown input `%U'",
2668 format_unformat_error, input);
2672 return clib_error_return (0, "dns data not set...");
2674 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2676 vec_free (dns_reply_data);
2682 VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2684 .path = "test dns unformat",
2685 .short_help = "test dns unformat <name> [ip4][ip6]",
2686 .function = test_dns_unfmt_command_fn,
2690 static clib_error_t *
2691 test_dns_expire_command_fn (vlib_main_t * vm,
2692 unformat_input_t * input,
2693 vlib_cli_command_t * cmd)
2695 dns_main_t *dm = &dns_main;
2699 dns_cache_entry_t *ep;
2701 if (unformat (input, "%v", &name))
2704 _vec_len (name) -= 1;
2707 return clib_error_return (0, "no name provided");
2709 dns_cache_lock (dm, 7);
2711 p = hash_get_mem (dm->cache_entry_by_name, name);
2714 dns_cache_unlock (dm);
2715 e = clib_error_return (0, "%s is not in the cache...", name);
2720 ep = pool_elt_at_index (dm->entries, p[0]);
2722 ep->expiration_time = 0;
2728 VLIB_CLI_COMMAND (test_dns_expire_command) =
2730 .path = "test dns expire",
2731 .short_help = "test dns expire <name>",
2732 .function = test_dns_expire_command_fn,
2738 vnet_send_dns6_reply (vlib_main_t * vm, dns_main_t * dm,
2739 dns_pending_request_t * pr, dns_cache_entry_t * ep,
2742 clib_warning ("Unimplemented...");
2747 vnet_send_dns4_reply (vlib_main_t * vm, dns_main_t * dm,
2748 dns_pending_request_t * pr, dns_cache_entry_t * ep,
2752 fib_prefix_t prefix;
2753 fib_node_index_t fei;
2754 u32 sw_if_index, fib_index;
2755 ip4_main_t *im4 = &ip4_main;
2756 ip_lookup_main_t *lm4 = &im4->lookup_main;
2757 ip_interface_address_t *ia = 0;
2758 ip4_address_t *src_address;
2766 /* vl_api_dns_resolve_name_reply_t _rnr, *rnr = &_rnr; */
2767 dns_resolve_name_t _rn, *rn = &_rn;
2768 vl_api_dns_resolve_ip_reply_t _rir, *rir = &_rir;
2775 int is_recycle = (b0 != 0);
2777 ASSERT (ep && ep->dns_response);
2779 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2781 /* Quick and dirty way to dig up the A-record address. $$ FIXME */
2782 clib_memset (rn, 0, sizeof (*rn));
2783 if (vnet_dns_response_to_reply (ep->dns_response, rn, &ttl))
2785 /* clib_warning ("response_to_reply failed..."); */
2788 else if (ip_addr_version (&rn->address) != AF_IP4)
2790 /* clib_warning ("No A-record..."); */
2794 else if (pr->request_type == DNS_PEER_PENDING_IP_TO_NAME)
2796 clib_memset (rir, 0, sizeof (*rir));
2797 if (vnet_dns_response_to_name (ep->dns_response, rir, &ttl))
2799 /* clib_warning ("response_to_name failed..."); */
2805 clib_warning ("Unknown request type %d", pr->request_type);
2809 /* Initialize a buffer */
2812 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2814 b0 = vlib_get_buffer (vm, bi);
2818 /* Use the buffer we were handed. Reinitialize it... */
2819 vlib_buffer_t bt = { };
2820 /* push/pop the reference count */
2821 u8 save_ref_count = b0->ref_count;
2822 vlib_buffer_copy_template (b0, &bt);
2823 b0->ref_count = save_ref_count;
2824 bi = vlib_get_buffer_index (vm, b0);
2827 if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
2828 vlib_buffer_free_one (vm, b0->next_buffer);
2831 * Reset the buffer. We recycle the DNS request packet in the cache
2832 * hit case, and reply immediately from the request node.
2834 * In the resolution-required / deferred case, resetting a freshly-allocated
2835 * buffer won't hurt. We hope.
2837 b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
2838 | VLIB_BUFFER_TOTAL_LENGTH_VALID);
2839 vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; /* "local0" */
2840 vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
2842 /* Find a FIB path to the peer we're trying to answer */
2843 clib_memcpy (&prefix.fp_addr.ip4, pr->dst_address, sizeof (ip4_address_t));
2844 prefix.fp_proto = FIB_PROTOCOL_IP4;
2847 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
2848 if (fib_index == (u32) ~ 0)
2850 clib_warning ("no fib table");
2854 fei = fib_table_lookup (fib_index, &prefix);
2856 /* Couldn't find route to destination. Bail out. */
2857 if (fei == FIB_NODE_INDEX_INVALID)
2859 clib_warning ("no route to DNS server");
2863 sw_if_index = fib_entry_get_resolving_interface (fei);
2865 if (sw_if_index == ~0)
2868 ("route to %U exists, fei %d, get_resolving_interface returned"
2869 " ~0", fei, format_ip4_address, &prefix.fp_addr);
2874 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnumbered */,
2876 src_address = ip_interface_address_get_address (lm4, ia);
2877 goto found_src_address;
2881 clib_warning ("FIB BUG");
2886 ip = vlib_buffer_get_current (b0);
2887 udp = (udp_header_t *) (ip + 1);
2888 dns_response = (u8 *) (udp + 1);
2889 clib_memset (ip, 0, sizeof (*ip) + sizeof (*udp));
2892 * Start with the variadic portion of the exercise.
2893 * Turn the name into a set of DNS "labels". Max length
2894 * per label is 63, enforce that.
2896 reply = name_to_labels (pr->name);
2897 vec_free (pr->name);
2899 qp_offset = vec_len (reply);
2901 /* Add space for the query header */
2902 vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
2904 qp = (dns_query_t *) (reply + qp_offset);
2906 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2907 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
2909 qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2911 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
2913 /* Punch in space for the dns_header_t */
2914 vec_insert (reply, sizeof (dns_header_t), 0);
2916 dh = (dns_header_t *) reply;
2918 /* Transaction ID = pool index */
2921 /* Announce that we did a recursive lookup */
2922 tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
2924 tmp |= DNS_RCODE_NAME_ERROR;
2925 dh->flags = clib_host_to_net_u16 (tmp);
2926 dh->qdcount = clib_host_to_net_u16 (1);
2927 dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
2931 /* If the name resolution worked, cough up an appropriate RR */
2934 /* Add the answer. First, a name pointer (0xC00C) */
2935 vec_add1 (reply, 0xC0);
2936 vec_add1 (reply, 0x0C);
2938 /* Now, add single A-rec RR */
2939 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2941 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
2942 rr = (dns_rr_t *) rrptr;
2944 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
2945 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2946 rr->ttl = clib_host_to_net_u32 (ttl);
2947 rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
2948 ip_address_copy_addr (rr->rdata, &rn->address);
2952 /* Or a single PTR RR */
2953 u8 *vecname = format (0, "%s", rir->name);
2954 u8 *label_vec = name_to_labels (vecname);
2957 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
2958 rr = (dns_rr_t *) rrptr;
2959 rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2960 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2961 rr->ttl = clib_host_to_net_u32 (ttl);
2962 rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
2963 clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
2964 vec_free (label_vec);
2967 clib_memcpy (dns_response, reply, vec_len (reply));
2969 /* Set the packet length */
2970 b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
2973 ip->ip_version_and_header_length = 0x45;
2974 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
2976 ip->protocol = IP_PROTOCOL_UDP;
2977 ip->src_address.as_u32 = src_address->as_u32;
2978 clib_memcpy (ip->dst_address.as_u8, pr->dst_address,
2979 sizeof (ip4_address_t));
2980 ip->checksum = ip4_header_checksum (ip);
2983 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
2984 udp->dst_port = pr->dst_port;
2985 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
2991 * Ship pkts made out of whole cloth to ip4_lookup
2992 * Caller will ship recycled dns reply packets to ip4_lookup
2994 if (is_recycle == 0)
2996 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
2997 to_next = vlib_frame_vector_args (f);
3000 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
3004 #include <dns/dns.api.c>
3005 static clib_error_t *
3006 dns_init (vlib_main_t * vm)
3008 dns_main_t *dm = &dns_main;
3010 dm->vnet_main = vnet_get_main ();
3011 dm->name_cache_size = 1000;
3012 dm->max_ttl_in_seconds = 86400;
3013 dm->random_seed = 0xDEADDABE;
3014 dm->api_main = vlibapi_get_main ();
3016 /* Ask for a correctly-sized block of API message decode slots */
3017 dm->msg_id_base = setup_message_id_table ();
3022 VLIB_INIT_FUNCTION (dns_init);
3025 VLIB_PLUGIN_REGISTER () =
3027 .version = VPP_BUILD_VER,
3028 .description = "Simple DNS name resolver",
3034 * fd.io coding-style-patch-verification: ON
3037 * eval: (c-set-style "gnu")