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.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_msg_enum.h>
30 /* define message structures */
32 #include <dns/dns_all_api_h.h>
35 /* define generated endian-swappers */
37 #include <dns/dns_all_api_h.h>
40 /* instantiate all the print functions we know about */
41 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
43 #include <dns/dns_all_api_h.h>
46 /* Get the API version number */
47 #define vl_api_version(n,v) static u32 api_version=(v);
48 #include <dns/dns_all_api_h.h>
51 #define REPLY_MSG_ID_BASE dm->msg_id_base
52 #include <vlibapi/api_helper_macros.h>
54 /* Macro to finish up custom dump fns */
57 vl_print (handle, (char *)s); \
64 dns_cache_clear (dns_main_t * dm)
66 dns_cache_entry_t *ep;
68 if (dm->is_enabled == 0)
69 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
71 dns_cache_lock (dm, 1);
74 pool_foreach (ep, dm->entries,
77 vec_free (ep->pending_requests);
81 pool_free (dm->entries);
82 hash_free (dm->cache_entry_by_name);
83 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
84 vec_free (dm->unresolved_entries);
85 dns_cache_unlock (dm);
90 dns_enable_disable (dns_main_t * dm, int is_enable)
92 vlib_thread_main_t *tm = &vlib_thread_main;
93 u32 n_vlib_mains = tm->n_vlib_mains;
94 vlib_main_t *vm = dm->vlib_main;
96 /* Create the resolver process if not done already */
97 vnet_dns_create_resolver_process (dm);
101 if (vec_len (dm->ip4_name_servers) == 0
102 && (vec_len (dm->ip6_name_servers) == 0))
103 return VNET_API_ERROR_NO_NAME_SERVERS;
105 if (dm->udp_ports_registered == 0)
107 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply,
108 dns46_reply_node.index, 1 /* is_ip4 */ );
110 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply6,
111 dns46_reply_node.index, 0 /* is_ip4 */ );
113 udp_register_dst_port (vm, UDP_DST_PORT_dns,
114 dns4_request_node.index, 1 /* is_ip4 */ );
116 udp_register_dst_port (vm, UDP_DST_PORT_dns6,
117 dns6_request_node.index, 0 /* is_ip4 */ );
119 dm->udp_ports_registered = 1;
122 if (dm->cache_entry_by_name == 0)
124 if (n_vlib_mains > 1)
125 clib_spinlock_init (&dm->cache_lock);
127 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
134 dns_cache_clear (dm);
140 static void vl_api_dns_enable_disable_t_handler
141 (vl_api_dns_enable_disable_t * mp)
143 vl_api_dns_enable_disable_reply_t *rmp;
144 dns_main_t *dm = &dns_main;
147 rv = dns_enable_disable (dm, mp->enable);
149 REPLY_MACRO (VL_API_DNS_ENABLE_DISABLE_REPLY);
153 dns6_name_server_add_del (dns_main_t * dm,
154 u8 * server_address_as_u8, int is_add)
161 /* Already there? done... */
162 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
164 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
165 sizeof (ip6_address_t)))
169 vec_add2 (dm->ip6_name_servers, ap, 1);
170 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
174 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
176 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
177 sizeof (ip6_address_t)))
179 vec_delete (dm->ip6_name_servers, 1, i);
183 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
189 dns4_name_server_add_del (dns_main_t * dm,
190 u8 * server_address_as_u8, int is_add)
197 /* Already there? done... */
198 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
200 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
201 sizeof (ip4_address_t)))
205 vec_add2 (dm->ip4_name_servers, ap, 1);
206 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
210 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
212 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
213 sizeof (ip4_address_t)))
215 vec_delete (dm->ip4_name_servers, 1, i);
219 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
224 static void vl_api_dns_name_server_add_del_t_handler
225 (vl_api_dns_name_server_add_del_t * mp)
227 dns_main_t *dm = &dns_main;
228 vl_api_dns_name_server_add_del_reply_t *rmp;
232 rv = dns6_name_server_add_del (dm, mp->server_address, mp->is_add);
234 rv = dns4_name_server_add_del (dm, mp->server_address, mp->is_add);
236 REPLY_MACRO (VL_API_DNS_NAME_SERVER_ADD_DEL_REPLY);
240 vnet_dns_send_dns4_request (dns_main_t * dm,
241 dns_cache_entry_t * ep, ip4_address_t * server)
243 vlib_main_t *vm = dm->vlib_main;
244 f64 now = vlib_time_now (vm);
249 fib_node_index_t fei;
250 u32 sw_if_index, fib_index;
252 ip4_main_t *im4 = &ip4_main;
253 ip_lookup_main_t *lm4 = &im4->lookup_main;
254 ip_interface_address_t *ia = 0;
255 ip4_address_t *src_address;
260 ASSERT (ep->dns_request);
262 /* Find a FIB path to the server */
263 clib_memcpy (&prefix.fp_addr.ip4, server, sizeof (*server));
264 prefix.fp_proto = FIB_PROTOCOL_IP4;
267 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
268 if (fib_index == (u32) ~ 0)
271 clib_warning ("no fib table");
275 fei = fib_table_lookup (fib_index, &prefix);
277 /* Couldn't find route to destination. Bail out. */
278 if (fei == FIB_NODE_INDEX_INVALID)
281 clib_warning ("no route to DNS server");
285 sw_if_index = fib_entry_get_resolving_interface (fei);
287 if (sw_if_index == ~0)
291 ("route to %U exists, fei %d, get_resolving_interface returned"
292 " ~0", format_ip4_address, &prefix.fp_addr, fei);
297 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnumbered */,
299 src_address = ip_interface_address_get_address (lm4, ia);
300 goto found_src_address;
304 clib_warning ("FIB BUG");
309 /* Go get a buffer */
310 if (vlib_buffer_alloc (dm->vlib_main, &bi, 1) != 1)
313 b = vlib_get_buffer (vm, bi);
314 b->current_length = sizeof (ip4_header_t) + sizeof (udp_header_t) +
315 vec_len (ep->dns_request);
316 b->total_length_not_including_first_buffer = 0;
318 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
319 vnet_buffer (b)->sw_if_index[VLIB_RX] = 0; /* "local0" */
320 vnet_buffer (b)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
322 ip = vlib_buffer_get_current (b);
323 clib_memset (ip, 0, sizeof (*ip));
324 udp = (udp_header_t *) (ip + 1);
325 clib_memset (udp, 0, sizeof (*udp));
327 dns_request = (u8 *) (udp + 1);
330 ip->ip_version_and_header_length = 0x45;
331 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b));
333 ip->protocol = IP_PROTOCOL_UDP;
334 ip->src_address.as_u32 = src_address->as_u32;
335 ip->dst_address.as_u32 = server->as_u32;
336 ip->checksum = ip4_header_checksum (ip);
339 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
340 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
341 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
342 vec_len (ep->dns_request));
345 /* The actual DNS request */
346 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
348 /* Ship it to ip4_lookup */
349 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
350 to_next = vlib_frame_vector_args (f);
353 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
355 ep->retry_timer = now + 2.0;
359 vnet_dns_send_dns6_request (dns_main_t * dm,
360 dns_cache_entry_t * ep, ip6_address_t * server)
362 vlib_main_t *vm = dm->vlib_main;
363 f64 now = vlib_time_now (vm);
368 fib_node_index_t fei;
369 u32 sw_if_index, fib_index;
371 ip6_main_t *im6 = &ip6_main;
372 ip_lookup_main_t *lm6 = &im6->lookup_main;
373 ip_interface_address_t *ia = 0;
374 ip6_address_t *src_address;
378 int junk __attribute__ ((unused));
380 ASSERT (ep->dns_request);
382 /* Find a FIB path to the server */
383 clib_memcpy (&prefix.fp_addr, server, sizeof (*server));
384 prefix.fp_proto = FIB_PROTOCOL_IP6;
387 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
388 if (fib_index == (u32) ~ 0)
391 clib_warning ("no fib table");
395 fei = fib_table_lookup (fib_index, &prefix);
397 /* Couldn't find route to destination. Bail out. */
398 if (fei == FIB_NODE_INDEX_INVALID)
400 clib_warning ("no route to DNS server");
403 sw_if_index = fib_entry_get_resolving_interface (fei);
406 foreach_ip_interface_address(lm6, ia, sw_if_index, 1 /* honor unnumbered */,
408 src_address = ip_interface_address_get_address (lm6, ia);
409 goto found_src_address;
413 clib_warning ("FIB BUG");
418 /* Go get a buffer */
419 if (vlib_buffer_alloc (dm->vlib_main, &bi, 1) != 1)
422 b = vlib_get_buffer (vm, bi);
423 b->current_length = sizeof (ip6_header_t) + sizeof (udp_header_t) +
424 vec_len (ep->dns_request);
425 b->total_length_not_including_first_buffer = 0;
427 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
429 ip = vlib_buffer_get_current (b);
430 clib_memset (ip, 0, sizeof (*ip));
431 udp = (udp_header_t *) (ip + 1);
432 clib_memset (udp, 0, sizeof (*udp));
434 dns_request = (u8 *) (udp + 1);
437 ip->ip_version_traffic_class_and_flow_label =
438 clib_host_to_net_u32 (0x6 << 28);
441 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b)
442 - sizeof (ip6_header_t));
444 ip->protocol = IP_PROTOCOL_UDP;
445 clib_memcpy (&ip->src_address, src_address, sizeof (ip6_address_t));
446 clib_memcpy (&ip->dst_address, server, sizeof (ip6_address_t));
449 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
450 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
451 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
452 vec_len (ep->dns_request));
454 udp->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ip, &junk);
456 /* The actual DNS request */
457 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
459 /* Ship it to ip6_lookup */
460 f = vlib_get_frame_to_node (vm, ip6_lookup_node.index);
461 to_next = vlib_frame_vector_args (f);
465 ep->retry_timer = now + 2.0;
469 * Translate "foo.com" into "0x3 f o o 0x3 c o m 0x0"
470 * A historical / hysterical micro-TLV scheme. DGMS.
473 name_to_labels (u8 * name)
476 int last_label_index;
481 /* punch in space for the first length */
482 vec_insert (rv, 1, 0);
483 last_label_index = 0;
486 while (i < vec_len (rv))
490 rv[last_label_index] = (i - last_label_index) - 1;
491 if ((i - last_label_index) > 63)
492 clib_warning ("stupid name, label length %d",
493 i - last_label_index);
494 last_label_index = i;
499 /* Set the last real label length */
500 rv[last_label_index] = (i - last_label_index) - 1;
503 * Add a [sic] NULL root label. Otherwise, the name parser can't figure out
511 * arc-function for the above.
512 * Translate "0x3 f o o 0x3 c o m 0x0" into "foo.com"
513 * Produces a non-NULL-terminated u8 *vector. %v format is your friend.
516 vnet_dns_labels_to_name (u8 * label, u8 * full_text, u8 ** parse_from_here)
523 *parse_from_here = 0;
525 /* chase initial pointer? */
526 if ((label[0] & 0xC0) == 0xC0)
528 *parse_from_here = label + 2;
529 offset = ((label[0] & 0x3f) << 8) + label[1];
530 label = full_text + offset;
537 for (i = 0; i < len; i++)
538 vec_add1 (reply, *label++);
541 if ((label[0] & 0xC0) == 0xC0)
543 *parse_from_here = label + 2;
544 offset = ((label[0] & 0x3f) << 8) + label[1];
545 label = full_text + offset;
550 vec_add1 (reply, '.');
552 if (*parse_from_here == 0)
553 *parse_from_here = label;
558 vnet_send_dns_request (dns_main_t * dm, dns_cache_entry_t * ep)
563 u8 *request, *name_copy;
566 /* This can easily happen if sitting in GDB, etc. */
567 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID || ep->server_fails > 1)
570 /* Construct the dns request, if we haven't been here already */
571 if (vec_len (ep->dns_request) == 0)
574 * Start with the variadic portion of the exercise.
575 * Turn the name into a set of DNS "labels". Max length
576 * per label is 63, enforce that.
578 request = name_to_labels (ep->name);
579 name_copy = vec_dup (request);
580 qp_offset = vec_len (request);
583 * At least when testing against "known good" DNS servers:
584 * it turns out that sending 2x requests - one for an A-record
585 * and another for a AAAA-record - seems to work better than
586 * sending a DNS_TYPE_ALL request.
589 /* Add space for the query header */
590 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
592 qp = (dns_query_t *) (request + qp_offset);
594 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
595 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
597 clib_memcpy (qp, name_copy, vec_len (name_copy));
598 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
599 vec_free (name_copy);
601 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
602 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
604 /* Punch in space for the dns_header_t */
605 vec_insert (request, sizeof (dns_header_t), 0);
607 h = (dns_header_t *) request;
609 /* Transaction ID = pool index */
610 h->id = clib_host_to_net_u16 (ep - dm->entries);
612 /* Ask for a recursive lookup */
613 tmp = DNS_RD | DNS_OPCODE_QUERY;
614 h->flags = clib_host_to_net_u16 (tmp);
615 h->qdcount = clib_host_to_net_u16 (2);
619 ep->dns_request = request;
622 /* Work out which server / address family we're going to use */
624 /* Retry using current server */
625 if (ep->retry_count++ < DNS_RETRIES_PER_SERVER)
627 if (ep->server_af == 1 /* ip6 */ )
629 if (vec_len (dm->ip6_name_servers))
631 vnet_dns_send_dns6_request
632 (dm, ep, dm->ip6_name_servers + ep->server_rotor);
638 if (vec_len (dm->ip4_name_servers))
640 vnet_dns_send_dns4_request
641 (dm, ep, dm->ip4_name_servers + ep->server_rotor);
645 else /* switch to a new server */
649 if (ep->server_af == 1 /* ip6 */ )
651 if (ep->server_rotor >= vec_len (dm->ip6_name_servers))
653 ep->server_rotor = 0;
654 ep->server_af = vec_len (dm->ip4_name_servers) > 0 ? 0 : 1;
659 if (ep->server_rotor >= vec_len (dm->ip4_name_servers))
661 ep->server_rotor = 0;
662 ep->server_af = vec_len (dm->ip6_name_servers) > 0 ? 1 : 0;
667 if (ep->server_af == 1 /* ip6 */ )
668 vnet_dns_send_dns6_request
669 (dm, ep, dm->ip6_name_servers + ep->server_rotor);
671 vnet_dns_send_dns4_request
672 (dm, ep, dm->ip4_name_servers + ep->server_rotor);
676 vlib_process_signal_event_mt (dm->vlib_main,
677 dm->resolver_process_node_index,
678 DNS_RESOLVER_EVENT_PENDING, 0);
682 vnet_dns_delete_entry_by_index_nolock (dns_main_t * dm, u32 index)
684 dns_cache_entry_t *ep;
687 if (dm->is_enabled == 0)
688 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
690 if (pool_is_free_index (dm->entries, index))
691 return VNET_API_ERROR_NO_SUCH_ENTRY;
693 ep = pool_elt_at_index (dm->entries, index);
694 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_VALID))
696 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
697 if (index == dm->unresolved_entries[i])
699 vec_delete (dm->unresolved_entries, 1, i);
702 clib_warning ("pool elt %d supposedly pending, but not found...",
707 hash_unset_mem (dm->cache_entry_by_name, ep->name);
709 vec_free (ep->pending_requests);
710 pool_put (dm->entries, ep);
716 dns_delete_by_name (dns_main_t * dm, u8 * name)
721 if (dm->is_enabled == 0)
722 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
724 dns_cache_lock (dm, 2);
725 p = hash_get_mem (dm->cache_entry_by_name, name);
728 dns_cache_unlock (dm);
729 return VNET_API_ERROR_NO_SUCH_ENTRY;
731 rv = vnet_dns_delete_entry_by_index_nolock (dm, p[0]);
733 dns_cache_unlock (dm);
739 delete_random_entry (dns_main_t * dm)
742 u32 victim_index, start_index, i;
744 dns_cache_entry_t *ep;
746 if (dm->is_enabled == 0)
747 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
750 * Silence spurious coverity warning. We know pool_elts >> 0, or
751 * we wouldn't be here...
754 if (pool_elts (dm->entries) == 0)
755 return VNET_API_ERROR_UNSPECIFIED;
758 dns_cache_lock (dm, 3);
759 limit = pool_elts (dm->entries);
760 start_index = random_u32 (&dm->random_seed) % limit;
762 for (i = 0; i < limit; i++)
764 victim_index = (start_index + i) % limit;
766 if (!pool_is_free_index (dm->entries, victim_index))
768 ep = pool_elt_at_index (dm->entries, victim_index);
769 /* Delete only valid, non-static entries */
770 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
771 && ((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0))
773 rv = vnet_dns_delete_entry_by_index_nolock (dm, victim_index);
774 dns_cache_unlock (dm);
779 dns_cache_unlock (dm);
781 clib_warning ("Couldn't find an entry to delete?");
782 return VNET_API_ERROR_UNSPECIFIED;
786 dns_add_static_entry (dns_main_t * dm, u8 * name, u8 * dns_reply_data)
788 dns_cache_entry_t *ep;
792 if (dm->is_enabled == 0)
793 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
795 dns_cache_lock (dm, 4);
796 p = hash_get_mem (dm->cache_entry_by_name, name);
799 dns_cache_unlock (dm);
800 return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
803 if (pool_elts (dm->entries) == dm->name_cache_size)
805 /* Will only fail if the cache is totally filled w/ static entries... */
806 rv = delete_random_entry (dm);
809 dns_cache_unlock (dm);
814 pool_get (dm->entries, ep);
815 clib_memset (ep, 0, sizeof (*ep));
817 /* Note: consumes the name vector */
819 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
820 ep->flags = DNS_CACHE_ENTRY_FLAG_VALID | DNS_CACHE_ENTRY_FLAG_STATIC;
821 ep->dns_response = dns_reply_data;
823 dns_cache_unlock (dm);
828 vnet_dns_resolve_name (dns_main_t * dm, u8 * name, dns_pending_request_t * t,
829 dns_cache_entry_t ** retp)
831 dns_cache_entry_t *ep;
835 dns_pending_request_t *pr;
838 now = vlib_time_now (dm->vlib_main);
840 /* In case we can't actually answer the question right now... */
843 /* binary API caller might forget to set the name. Guess how we know. */
845 return VNET_API_ERROR_INVALID_VALUE;
847 dns_cache_lock (dm, 5);
849 p = hash_get_mem (dm->cache_entry_by_name, name);
852 ep = pool_elt_at_index (dm->entries, p[0]);
853 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
855 /* Has the entry expired? */
856 if (((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0)
857 && (now > ep->expiration_time))
860 u32 *indices_to_delete = 0;
863 * Take out the rest of the resolution chain
864 * This isn't optimal, but it won't happen very often.
868 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME))
870 vec_add1 (indices_to_delete, ep - dm->entries);
872 p = hash_get_mem (dm->cache_entry_by_name, ep->cname);
875 ep = pool_elt_at_index (dm->entries, p[0]);
879 vec_add1 (indices_to_delete, ep - dm->entries);
883 for (i = 0; i < vec_len (indices_to_delete); i++)
885 /* Reenable to watch re-resolutions */
888 ep = pool_elt_at_index (dm->entries,
889 indices_to_delete[i]);
890 clib_warning ("Re-resolve %s", ep->name);
893 vnet_dns_delete_entry_by_index_nolock
894 (dm, indices_to_delete[i]);
896 vec_free (indices_to_delete);
897 /* Yes, kill it... */
901 if (ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
907 dns_cache_unlock (dm);
913 * Resolution pending. Add request to the pending vector
914 * by copying the template request
916 vec_add2 (ep->pending_requests, pr, 1);
917 memcpy (pr, t, sizeof (*pr));
918 dns_cache_unlock (dm);
924 if (pool_elts (dm->entries) == dm->name_cache_size)
926 /* Will only fail if the cache is totally filled w/ static entries... */
927 rv = delete_random_entry (dm);
930 dns_cache_unlock (dm);
935 /* add new hash table entry */
936 pool_get (dm->entries, ep);
937 clib_memset (ep, 0, sizeof (*ep));
939 ep->name = format (0, "%s%c", name, 0);
940 _vec_len (ep->name) = vec_len (ep->name) - 1;
942 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
944 vec_add1 (dm->unresolved_entries, ep - dm->entries);
945 vec_add2 (ep->pending_requests, pr, 1);
947 pr->request_type = t->request_type;
949 /* Remember details so we can reply later... */
950 if (t->request_type == DNS_API_PENDING_NAME_TO_IP ||
951 t->request_type == DNS_API_PENDING_IP_TO_NAME)
953 pr->client_index = t->client_index;
954 pr->client_context = t->client_context;
958 pr->client_index = ~0;
959 pr->is_ip6 = t->is_ip6;
960 pr->dst_port = t->dst_port;
967 clib_memcpy (pr->dst_address, t->dst_address, count);
970 vnet_send_dns_request (dm, ep);
971 dns_cache_unlock (dm);
975 #define foreach_notification_to_move \
979 * Handle cname indirection. JFC. Called with the cache locked.
980 * returns 0 if the reply is not a CNAME.
984 vnet_dns_cname_indirection_nolock (dns_main_t * dm, u32 ep_index, u8 * reply)
999 dns_cache_entry_t *ep, *next_ep;
1002 h = (dns_header_t *) reply;
1003 flags = clib_net_to_host_u16 (h->flags);
1004 rcode = flags & DNS_RCODE_MASK;
1006 /* See if the response is OK */
1009 case DNS_RCODE_NO_ERROR:
1012 case DNS_RCODE_NAME_ERROR:
1013 case DNS_RCODE_FORMAT_ERROR:
1014 case DNS_RCODE_SERVER_FAILURE:
1015 case DNS_RCODE_NOT_IMPLEMENTED:
1016 case DNS_RCODE_REFUSED:
1020 curpos = (u8 *) (h + 1);
1024 /* Skip the questions */
1025 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
1032 pos += sizeof (dns_query_t);
1035 /* expect a pointer chase here for a CNAME record */
1036 if ((pos2[0] & 0xC0) == 0xC0)
1041 /* Walk the answer(s) to see what to do next */
1042 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
1044 rr = (dns_rr_t *) pos;
1045 switch (clib_net_to_host_u16 (rr->type))
1047 /* Real address record? Done.. */
1052 * Maybe chase a CNAME pointer?
1053 * It's not unheard-of for name-servers to return
1054 * both CNAME and A/AAAA records...
1056 case DNS_TYPE_CNAME:
1060 /* Some other junk, e.g. a nameserver... */
1064 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1066 if ((pos2[0] & 0xc0) == 0xc0)
1070 /* Neither a CNAME nor a real address. Try another server */
1073 flags &= ~DNS_RCODE_MASK;
1074 flags |= DNS_RCODE_NAME_ERROR;
1075 h->flags = clib_host_to_net_u16 (flags);
1079 /* This is a CNAME record, chase the name chain. */
1082 /* The last request is no longer pending.. */
1083 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
1084 if (ep_index == dm->unresolved_entries[i])
1086 vec_delete (dm->unresolved_entries, 1, i);
1087 goto found_last_request;
1089 clib_warning ("pool elt %d supposedly pending, but not found...", ep_index);
1094 now = vlib_time_now (dm->vlib_main);
1095 cname = vnet_dns_labels_to_name (rr->rdata, reply, &pos2);
1096 /* Save the cname */
1097 vec_add1 (cname, 0);
1098 _vec_len (cname) -= 1;
1099 ep = pool_elt_at_index (dm->entries, ep_index);
1101 ep->flags |= (DNS_CACHE_ENTRY_FLAG_CNAME | DNS_CACHE_ENTRY_FLAG_VALID);
1102 /* Save the response */
1103 if (ep->dns_response)
1104 vec_free (ep->dns_response);
1105 ep->dns_response = reply;
1106 /* Set up expiration time */
1107 ep->expiration_time = now + clib_net_to_host_u32 (rr->ttl);
1109 pool_get (dm->entries, next_ep);
1111 /* Need to recompute ep post pool-get */
1112 ep = pool_elt_at_index (dm->entries, ep_index);
1114 clib_memset (next_ep, 0, sizeof (*next_ep));
1115 next_ep->name = vec_dup (cname);
1116 vec_add1 (next_ep->name, 0);
1117 _vec_len (next_ep->name) -= 1;
1119 hash_set_mem (dm->cache_entry_by_name, next_ep->name,
1120 next_ep - dm->entries);
1122 /* Use the same server */
1123 next_ep->server_rotor = ep->server_rotor;
1124 next_ep->server_af = ep->server_af;
1126 /* Move notification data to the next name in the chain */
1127 #define _(a) next_ep->a = ep->a; ep->a = 0;
1128 foreach_notification_to_move;
1131 request = name_to_labels (cname);
1132 name_copy = vec_dup (request);
1134 qp_offset = vec_len (request);
1136 /* Add space for the query header */
1137 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
1139 qp = (dns_query_t *) (request + qp_offset);
1141 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
1142 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1143 clib_memcpy (qp, name_copy, vec_len (name_copy));
1144 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
1145 vec_free (name_copy);
1147 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1148 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1150 /* Punch in space for the dns_header_t */
1151 vec_insert (request, sizeof (dns_header_t), 0);
1153 h = (dns_header_t *) request;
1155 /* Transaction ID = pool index */
1156 h->id = clib_host_to_net_u16 (next_ep - dm->entries);
1158 /* Ask for a recursive lookup */
1159 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
1160 h->qdcount = clib_host_to_net_u16 (2);
1164 next_ep->dns_request = request;
1165 next_ep->retry_timer = now + 2.0;
1166 next_ep->retry_count = 0;
1169 * Enable this to watch recursive resolution happen...
1170 * fformat (stdout, "%U", format_dns_reply, request, 2);
1173 vec_add1 (dm->unresolved_entries, next_ep - dm->entries);
1174 vnet_send_dns_request (dm, next_ep);
1179 vnet_dns_response_to_reply (u8 * response,
1180 vl_api_dns_resolve_name_reply_t * rmp,
1188 u8 *curpos, *pos, *pos2;
1194 h = (dns_header_t *) response;
1195 flags = clib_net_to_host_u16 (h->flags);
1196 rcode = flags & DNS_RCODE_MASK;
1198 /* See if the response is OK, etc. */
1202 case DNS_RCODE_NO_ERROR:
1205 case DNS_RCODE_NAME_ERROR:
1206 case DNS_RCODE_FORMAT_ERROR:
1207 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1209 case DNS_RCODE_SERVER_FAILURE:
1210 case DNS_RCODE_NOT_IMPLEMENTED:
1211 case DNS_RCODE_REFUSED:
1212 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1215 /* No answers? Loser... */
1216 if (clib_net_to_host_u16 (h->anscount) < 1)
1217 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1219 curpos = (u8 *) (h + 1);
1221 /* Skip the name we asked about */
1224 /* Should never happen, but stil... */
1225 if ((len & 0xC0) == 0xC0)
1229 /* skip the name / label-set */
1238 limit = clib_net_to_host_u16 (h->qdcount);
1239 qp = (dns_query_t *) curpos;
1244 limit = clib_net_to_host_u16 (h->anscount);
1246 for (i = 0; i < limit; i++)
1248 pos = pos2 = curpos;
1251 /* Expect pointer chases in the answer section... */
1252 if ((pos2[0] & 0xC0) == 0xC0)
1255 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1264 if ((pos2[0] & 0xc0) == 0xc0)
1267 * If we've already done one pointer chase,
1268 * do not move the pos pointer.
1270 if (pointer_chase == 0)
1272 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1280 if (pointer_chase == 0)
1283 rr = (dns_rr_t *) pos;
1285 switch (clib_net_to_host_u16 (rr->type))
1288 /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1289 memcpy (rmp->ip4_address, rr->rdata, sizeof (ip4_address_t));
1291 ttl = clib_net_to_host_u32 (rr->ttl);
1292 if (min_ttlp && *min_ttlp > ttl)
1296 /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1297 memcpy (rmp->ip6_address, rr->rdata, sizeof (ip6_address_t));
1298 ttl = clib_net_to_host_u32 (rr->ttl);
1299 if (min_ttlp && *min_ttlp > ttl)
1307 /* Might as well stop ASAP */
1308 if (rmp->ip4_set && rmp->ip6_set)
1310 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1314 if ((rmp->ip4_set + rmp->ip6_set) == 0)
1315 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1320 vnet_dns_response_to_name (u8 * response,
1321 vl_api_dns_resolve_ip_reply_t * rmp,
1329 u8 *curpos, *pos, *pos2;
1334 u8 *junk __attribute__ ((unused));
1338 h = (dns_header_t *) response;
1339 flags = clib_net_to_host_u16 (h->flags);
1340 rcode = flags & DNS_RCODE_MASK;
1342 /* See if the response is OK, etc. */
1346 case DNS_RCODE_NO_ERROR:
1349 case DNS_RCODE_NAME_ERROR:
1350 case DNS_RCODE_FORMAT_ERROR:
1351 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1353 case DNS_RCODE_SERVER_FAILURE:
1354 case DNS_RCODE_NOT_IMPLEMENTED:
1355 case DNS_RCODE_REFUSED:
1356 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1359 /* No answers? Loser... */
1360 if (clib_net_to_host_u16 (h->anscount) < 1)
1361 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1363 curpos = (u8 *) (h + 1);
1365 /* Skip the name we asked about */
1368 /* Should never happen, but stil... */
1369 if ((len & 0xC0) == 0xC0)
1373 /* skip the name / label-set */
1382 limit = clib_net_to_host_u16 (h->qdcount);
1383 qp = (dns_query_t *) curpos;
1388 limit = clib_net_to_host_u16 (h->anscount);
1390 for (i = 0; i < limit; i++)
1392 pos = pos2 = curpos;
1395 /* Expect pointer chases in the answer section... */
1396 if ((pos2[0] & 0xC0) == 0xC0)
1399 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1408 if ((pos2[0] & 0xc0) == 0xc0)
1411 * If we've already done one pointer chase,
1412 * do not move the pos pointer.
1414 if (pointer_chase == 0)
1416 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1424 if (pointer_chase == 0)
1427 rr = (dns_rr_t *) pos;
1429 switch (clib_net_to_host_u16 (rr->type))
1432 name = vnet_dns_labels_to_name (rr->rdata, response, &junk);
1433 memcpy (rmp->name, name, vec_len (name));
1434 ttl = clib_net_to_host_u32 (rr->ttl);
1437 rmp->name[vec_len (name)] = 0;
1443 /* Might as well stop ASAP */
1446 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1451 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1456 vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1458 dns_main_t *dm = &dns_main;
1459 vl_api_dns_resolve_name_reply_t *rmp;
1460 dns_cache_entry_t *ep;
1461 dns_pending_request_t _t0, *t0 = &_t0;
1464 /* Sanitize the name slightly */
1465 mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1467 t0->request_type = DNS_API_PENDING_NAME_TO_IP;
1468 t0->client_index = mp->client_index;
1469 t0->client_context = mp->context;
1471 rv = vnet_dns_resolve_name (dm, mp->name, t0, &ep);
1473 /* Error, e.g. not enabled? Tell the user */
1476 REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1480 /* Resolution pending? Don't reply... */
1485 REPLY_MACRO2(VL_API_DNS_RESOLVE_NAME_REPLY,
1487 rv = vnet_dns_response_to_reply (ep->dns_response, rmp, 0 /* ttl-ptr */);
1488 rmp->retval = clib_host_to_net_u32 (rv);
1493 * dns_resolve_name leaves the cache locked when it returns
1494 * a cached result, so unlock it here.
1496 dns_cache_unlock (dm);
1500 vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
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 (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 * vnet_dns_resolve_name leaves the cache locked when it returns
1574 * a cached result, so unlock it here.
1576 dns_cache_unlock (dm);
1579 #define vl_msg_name_crc_list
1580 #include <dns/dns_all_api_h.h>
1581 #undef vl_msg_name_crc_list
1584 setup_message_id_table (dns_main_t * dm)
1586 #define _(id,n,crc) \
1587 vl_msg_api_add_msg_name_crc (dm->api_main, #n "_" #crc, dm->msg_id_base + id);
1588 foreach_vl_msg_name_crc_dns;
1592 #define foreach_dns_plugin_api_msg \
1593 _(DNS_ENABLE_DISABLE, dns_enable_disable) \
1594 _(DNS_NAME_SERVER_ADD_DEL, dns_name_server_add_del) \
1595 _(DNS_RESOLVE_NAME, dns_resolve_name) \
1596 _(DNS_RESOLVE_IP, dns_resolve_ip)
1598 static clib_error_t *
1599 dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1601 dns_main_t *dm = &dns_main;
1603 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1605 if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1607 else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1610 return clib_error_return (0, "unknown input `%U'",
1611 format_unformat_error, input);
1616 VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1619 unformat_dns_reply (unformat_input_t * input, va_list * args)
1621 u8 **result = va_arg (*args, u8 **);
1622 u8 **namep = va_arg (*args, u8 **);
1636 if (unformat (input, "%v", &name))
1639 if (unformat (input, "%U", unformat_ip4_address, &a4))
1642 if (unformat (input, "%U", unformat_ip6_address, &a6))
1646 if (unformat (input, "%U", unformat_ip6_address, &a6))
1649 if (unformat (input, "%U", unformat_ip4_address, &a6))
1653 /* Must have a name */
1657 /* Must have at least one address */
1658 if (!(a4_set + a6_set))
1661 /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1662 ce = name_to_labels (name);
1663 qp_offset = vec_len (ce);
1665 /* Add space for the query header */
1666 vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1667 qp = (dns_query_t *) (ce + qp_offset);
1669 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1670 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1672 /* Punch in space for the dns_header_t */
1673 vec_insert (ce, sizeof (dns_header_t), 0);
1675 h = (dns_header_t *) ce;
1677 /* Fake Transaction ID */
1680 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1681 h->qdcount = clib_host_to_net_u16 (1);
1682 h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1686 /* Now append one or two A/AAAA RR's... */
1689 /* Pointer to the name (DGMS) */
1690 vec_add1 (ce, 0xC0);
1691 vec_add1 (ce, 0x0C);
1692 vec_add2 (ce, rru8, sizeof (*rr) + 4);
1694 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1695 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1696 rr->ttl = clib_host_to_net_u32 (86400);
1697 rr->rdlength = clib_host_to_net_u16 (4);
1698 memcpy (rr->rdata, &a4, sizeof (a4));
1702 /* Pointer to the name (DGMS) */
1703 vec_add1 (ce, 0xC0);
1704 vec_add1 (ce, 0x0C);
1705 vec_add2 (ce, rru8, sizeof (*rr) + 16);
1707 rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1708 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1709 rr->ttl = clib_host_to_net_u32 (86400);
1710 rr->rdlength = clib_host_to_net_u16 (16);
1711 memcpy (rr->rdata, &a6, sizeof (a6));
1723 format_dns_query (u8 * s, va_list * args)
1725 u8 **curpos = va_arg (*args, u8 **);
1726 int verbose = va_arg (*args, int);
1731 s = format (s, " Name: ");
1733 /* Unwind execrated counted-label sheit */
1739 for (i = 0; i < len; i++)
1740 vec_add1 (s, *pos++);
1752 qp = (dns_query_t *) pos;
1755 switch (clib_net_to_host_u16 (qp->type))
1758 s = format (s, "type A\n");
1761 s = format (s, "type AAAA\n");
1764 s = format (s, "type ALL\n");
1768 s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1773 pos += sizeof (*qp);
1780 * format dns reply data
1781 * verbose > 1, dump everything
1782 * verbose == 1, dump all A and AAAA records
1783 * verbose == 0, dump one A record, and one AAAA record
1787 format_dns_reply_data (u8 * s, va_list * args)
1789 u8 *reply = va_arg (*args, u8 *);
1790 u8 **curpos = va_arg (*args, u8 **);
1791 int verbose = va_arg (*args, int);
1792 int *print_ip4 = va_arg (*args, int *);
1793 int *print_ip6 = va_arg (*args, int *);
1798 int pointer_chase = 0;
1800 u16 rrtype_host_byte_order;
1802 pos = pos2 = *curpos;
1805 s = format (s, " ");
1807 /* chase pointer? almost always yes here... */
1808 if ((pos2[0] & 0xc0) == 0xc0)
1811 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1819 for (i = 0; i < len; i++)
1822 vec_add1 (s, *pos2);
1825 if ((pos2[0] & 0xc0) == 0xc0)
1828 * If we've already done one pointer chase,
1829 * do not move the pos pointer.
1831 if (pointer_chase == 0)
1833 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1851 if (pointer_chase == 0)
1854 rr = (dns_rr_t *) pos;
1855 rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
1857 switch (rrtype_host_byte_order)
1862 s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1863 format_ip4_address, rr->rdata);
1868 s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1869 clib_net_to_host_u32 (rr->ttl));
1874 pos += sizeof (*rr) + 4;
1880 s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1881 format_ip6_address, rr->rdata);
1886 s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1887 clib_net_to_host_u32 (rr->ttl));
1891 pos += sizeof (*rr) + 16;
1897 s = format (s, "TEXT: ");
1898 for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1899 vec_add1 (s, rr->rdata[i]);
1902 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1905 case DNS_TYPE_HINFO:
1907 /* Two counted strings. DGMS */
1913 s = format (s, "HINFO: ");
1916 for (i = 0; i < *len; i++)
1917 vec_add1 (s, *curpos++);
1921 for (i = 0; i < *len; i++)
1922 vec_add1 (s, *curpos++);
1927 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1930 case DNS_TYPE_NAMESERVER:
1933 s = format (s, "Nameserver: ");
1936 /* chase pointer? */
1937 if ((pos2[0] & 0xc0) == 0xc0)
1940 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1947 for (i = 0; i < len; i++)
1948 vec_add1 (s, *pos2++);
1950 /* chase pointer, typically to offset 12... */
1951 if (pos2[0] == 0xC0)
1952 pos2 = reply + pos2[1];
1961 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1964 case DNS_TYPE_MAIL_EXCHANGE:
1967 tp = (u16 *) rr->rdata;
1969 s = format (s, "Mail Exchange: Preference %d ", (u32)
1970 clib_net_to_host_u16 (*tp));
1972 pos2 = rr->rdata + 2;
1974 /* chase pointer? */
1975 if (pos2[0] == 0xc0)
1976 pos2 = reply + pos2[1];
1982 for (i = 0; i < len; i++)
1983 vec_add1 (s, *pos2++);
1986 if (pos2[0] == 0xC0)
1987 pos2 = reply + pos2[1];
1997 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2001 case DNS_TYPE_CNAME:
2004 tp = (u16 *) rr->rdata;
2006 if (rrtype_host_byte_order == DNS_TYPE_CNAME)
2007 s = format (s, "CNAME: ");
2009 s = format (s, "PTR: ");
2013 /* chase pointer? */
2014 if (pos2[0] == 0xc0)
2015 pos2 = reply + pos2[1];
2021 for (i = 0; i < len; i++)
2022 vec_add1 (s, *pos2++);
2025 if (pos2[0] == 0xC0)
2026 pos2 = reply + pos2[1];
2035 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2040 s = format (s, "type %d: len %d\n",
2041 (int) clib_net_to_host_u16 (rr->type),
2042 sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
2043 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2053 format_dns_reply (u8 * s, va_list * args)
2055 u8 *reply_as_u8 = va_arg (*args, u8 *);
2056 int verbose = va_arg (*args, int);
2064 h = (dns_header_t *) reply_as_u8;
2065 id = clib_net_to_host_u16 (h->id);
2066 flags = clib_net_to_host_u16 (h->flags);
2070 s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
2072 s = format (s, " %s %s %s %s\n",
2073 (flags & DNS_RA) ? "recur" : "no-recur",
2074 (flags & DNS_RD) ? "recur-des" : "no-recur-des",
2075 (flags & DNS_TC) ? "trunc" : "no-trunc",
2076 (flags & DNS_AA) ? "auth" : "non-auth");
2077 s = format (s, " %d queries, %d answers, %d name-servers,"
2079 clib_net_to_host_u16 (h->qdcount),
2080 clib_net_to_host_u16 (h->anscount),
2081 clib_net_to_host_u16 (h->nscount),
2082 clib_net_to_host_u16 (h->arcount));
2085 curpos = (u8 *) (h + 1);
2090 s = format (s, " Queries:\n");
2091 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
2093 /* The query is variable-length, so curpos is a value-result parm */
2094 s = format (s, "%U", format_dns_query, &curpos, verbose);
2100 s = format (s, " Replies:\n");
2102 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
2104 /* curpos is a value-result parm */
2105 s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
2106 verbose, &print_ip4, &print_ip6);
2113 format_dns_cache (u8 * s, va_list * args)
2115 dns_main_t *dm = va_arg (*args, dns_main_t *);
2116 f64 now = va_arg (*args, f64);
2117 int verbose = va_arg (*args, int);
2118 u8 *name = va_arg (*args, u8 *);
2119 dns_cache_entry_t *ep;
2123 if (dm->is_enabled == 0)
2125 s = format (s, "The DNS cache is disabled...");
2129 if (pool_elts (dm->entries) == 0)
2131 s = format (s, "The DNS cache is empty...");
2135 dns_cache_lock (dm, 6);
2139 p = hash_get_mem (dm->cache_entry_by_name, name);
2142 s = format (s, "%s is not in the cache...", name);
2143 dns_cache_unlock (dm);
2147 ep = pool_elt_at_index (dm->entries, p[0]);
2148 /* Magic to spit out a C-initializer to research hemorrhoids... */
2152 s = format (s, "static u8 dns_reply_data_initializer[] =\n");
2153 s = format (s, "{\n");
2155 for (i = 0; i < vec_len (ep->dns_response); i++)
2162 s = format (s, "0x%02x, ", ep->dns_response[i]);
2164 s = format (s, "};\n");
2168 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2170 ASSERT (ep->dns_response);
2171 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2176 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2177 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2179 s = format (s, "%s%s -> %U", ss, ep->name,
2180 format_dns_reply, ep->dns_response, verbose);
2181 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2183 f64 time_left = ep->expiration_time - now;
2184 if (time_left > 0.0)
2185 s = format (s, " TTL left %.1f", time_left);
2187 s = format (s, " EXPIRED");
2192 ASSERT (ep->dns_request);
2193 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2201 s = format (s, "DNS cache contains %d entries\n", pool_elts (dm->entries));
2206 pool_foreach (ep, dm->entries,
2208 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2210 ASSERT (ep->dns_response);
2211 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2216 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2217 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2219 s = format (s, "%s%s -> %U", ss, ep->name,
2223 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2225 f64 time_left = ep->expiration_time - now;
2226 if (time_left > 0.0)
2227 s = format (s, " TTL left %.1f", time_left);
2229 s = format (s, " EXPIRED");
2232 s = format (s, " %d client notifications pending\n",
2233 vec_len(ep->pending_requests));
2238 ASSERT (ep->dns_request);
2239 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2247 dns_cache_unlock (dm);
2252 static clib_error_t *
2253 show_dns_cache_command_fn (vlib_main_t * vm,
2254 unformat_input_t * input, vlib_cli_command_t * cmd)
2256 dns_main_t *dm = &dns_main;
2259 f64 now = vlib_time_now (vm);
2261 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2263 if (unformat (input, "verbose %d", &verbose))
2265 else if (unformat (input, "verbose"))
2267 else if (unformat (input, "name %s", &name))
2270 return clib_error_return (0, "unknown input `%U'",
2271 format_unformat_error, input);
2274 vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
2280 VLIB_CLI_COMMAND (show_dns_cache_command) =
2282 .path = "show dns cache",
2283 .short_help = "show dns cache [verbose [nn]]",
2284 .function = show_dns_cache_command_fn,
2288 static clib_error_t *
2289 show_dns_servers_command_fn (vlib_main_t * vm,
2290 unformat_input_t * input,
2291 vlib_cli_command_t * cmd)
2293 dns_main_t *dm = &dns_main;
2296 if ((vec_len (dm->ip4_name_servers) + vec_len (dm->ip6_name_servers)) == 0)
2297 return clib_error_return (0, "No name servers configured...");
2299 if (vec_len (dm->ip4_name_servers))
2301 vlib_cli_output (vm, "ip4 name servers:");
2302 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
2303 vlib_cli_output (vm, "%U", format_ip4_address,
2304 dm->ip4_name_servers + i);
2306 if (vec_len (dm->ip6_name_servers))
2308 vlib_cli_output (vm, "ip6 name servers:");
2309 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
2310 vlib_cli_output (vm, "%U", format_ip6_address,
2311 dm->ip4_name_servers + i);
2317 VLIB_CLI_COMMAND (show_dns_server_command) =
2319 .path = "show dns servers",
2320 .short_help = "show dns servers",
2321 .function = show_dns_servers_command_fn,
2326 static clib_error_t *
2327 dns_cache_add_del_command_fn (vlib_main_t * vm,
2328 unformat_input_t * input,
2329 vlib_cli_command_t * cmd)
2331 dns_main_t *dm = &dns_main;
2337 clib_error_t *error;
2339 if (unformat (input, "add"))
2341 if (unformat (input, "del"))
2343 if (unformat (input, "clear"))
2346 if (is_add == -1 && is_clear == -1)
2347 return clib_error_return (0, "add / del / clear required...");
2351 rv = dns_cache_clear (dm);
2357 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2358 error = clib_error_return (0, "Name resolution not enabled");
2363 /* Delete (by name)? */
2366 if (unformat (input, "%v", &name))
2368 rv = dns_delete_by_name (dm, name);
2371 case VNET_API_ERROR_NO_SUCH_ENTRY:
2372 error = clib_error_return (0, "%v not in the cache...", name);
2376 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2377 error = clib_error_return (0, "Name resolution not enabled");
2386 error = clib_error_return (0, "dns_delete_by_name returned %d",
2392 return clib_error_return (0, "unknown input `%U'",
2393 format_unformat_error, input);
2396 /* Note: dns_add_static_entry consumes the name vector if OK... */
2397 if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2399 rv = dns_add_static_entry (dm, name, dns_reply_data);
2402 case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2404 vec_free (dns_reply_data);
2405 return clib_error_return (0, "%v already in the cache...", name);
2410 return clib_error_return (0, "dns_add_static_entry returned %d",
2419 VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2421 .path = "dns cache",
2422 .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2423 .function = dns_cache_add_del_command_fn,
2427 #define DNS_FORMAT_TEST 1
2429 #if DNS_FORMAT_TEST > 0
2432 static u8 dns_reply_data_initializer[] =
2433 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2434 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2436 0x0, 0xff, /* type ALL */
2437 0x0, 0x1, /* class IN */
2438 0xc0, 0xc, /* pointer to yahoo.com name */
2439 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2440 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2441 0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2442 0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2443 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2444 0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2445 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2446 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2447 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2448 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2449 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2450 0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2451 0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2453 0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2454 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2455 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2456 0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2457 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2459 0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2460 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2461 0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2462 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2464 0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2465 0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2467 0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2469 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2471 0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2473 0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2474 0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2475 0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2479 /* www.cisco.com, has no addresses in reply */
2480 static u8 dns_reply_data_initializer[] = {
2481 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2482 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2483 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2485 0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2486 0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2487 0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2488 0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2489 0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2492 /* bind8 (linux widget, w/ nasty double pointer chasees */
2493 static u8 dns_reply_data_initializer[] = {
2495 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08,
2497 0x00, 0x06, 0x00, 0x06, 0x0a, 0x6f, 0x72, 0x69,
2499 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77, 0x77, 0x05,
2501 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f,
2503 0x6d, 0x00, 0x00, 0xff, 0x00, 0x01, 0x0a, 0x6f,
2505 0x72, 0x69, 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77,
2507 0x77, 0x05, 0x43, 0x49, 0x53, 0x43, 0x4f, 0xc0,
2510 0x1d, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2513 0x9a, 0x00, 0x18, 0x15, 0x72, 0x63, 0x64,
2514 0x6e, 0x39, 0x2d, 0x31, 0x34, 0x70, 0x2d, 0x64, 0x63,
2515 0x7a, 0x30, 0x35, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31,
2516 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00, 0x01, 0x00,
2517 0x00, 0x05, 0x9a, 0x00, 0x1a, 0x17, 0x61, 0x6c, 0x6c,
2518 0x6e, 0x30, 0x31, 0x2d, 0x61, 0x67, 0x30, 0x39, 0x2d,
2519 0x64, 0x63, 0x7a, 0x30, 0x33, 0x6e, 0x2d, 0x67, 0x73,
2520 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00,
2521 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x10, 0x0d, 0x72,
2522 0x74, 0x70, 0x35, 0x2d, 0x64, 0x6d, 0x7a, 0x2d, 0x67,
2523 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2524 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x18, 0x15,
2525 0x6d, 0x74, 0x76, 0x35, 0x2d, 0x61, 0x70, 0x31, 0x30,
2526 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x36, 0x6e, 0x2d, 0x67,
2527 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2528 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x1b, 0x18,
2529 0x73, 0x6e, 0x67, 0x64, 0x63, 0x30, 0x31, 0x2d, 0x61,
2530 0x62, 0x30, 0x37, 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x31,
2531 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0,
2532 0x26, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a,
2533 0x00, 0x1a, 0x17, 0x61, 0x65, 0x72, 0x30, 0x31, 0x2d,
2534 0x72, 0x34, 0x63, 0x32, 0x35, 0x2d, 0x64, 0x63, 0x7a,
2535 0x30, 0x31, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0,
2536 0x17, 0xc0, 0x26, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2537 0x00, 0x81, 0x00, 0x04, 0x48, 0xa3, 0x04, 0xa1, 0xc0,
2538 0x26, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82,
2539 0x00, 0x10, 0x20, 0x01, 0x04, 0x20, 0x12, 0x01, 0x00,
2540 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
2541 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2542 0x9a, 0x00, 0x02, 0xc0, 0xf4, 0xc0, 0x0c, 0x00, 0x02,
2543 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0,
2544 0xcd, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00,
2545 0x05, 0x9a, 0x00, 0x02, 0xc0, 0x8d, 0xc0, 0x0c, 0x00,
2546 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02,
2547 0xc0, 0x43, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00,
2548 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0, 0xa9, 0xc0, 0x0c,
2549 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00,
2550 0x02, 0xc0, 0x67, 0xc0, 0x8d, 0x00, 0x01, 0x00, 0x01,
2551 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0x40, 0x66, 0xf6,
2552 0x05, 0xc0, 0xa9, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2553 0x07, 0x08, 0x00, 0x04, 0xad, 0x24, 0xe0, 0x64, 0xc0,
2554 0x43, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08,
2555 0x00, 0x04, 0x48, 0xa3, 0x04, 0x1c, 0xc0, 0xf4, 0x00,
2556 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04,
2557 0xad, 0x26, 0xd4, 0x6c, 0xc0, 0x67, 0x00, 0x01, 0x00,
2558 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x25,
2559 0x90, 0x64, 0xc0, 0xcd, 0x00, 0x01, 0x00, 0x01, 0x00,
2560 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x27, 0x70, 0x44,
2564 static u8 dns_reply_data_initializer[] =
2565 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
2566 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
2567 0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
2568 0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
2570 0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
2571 0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
2572 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
2573 0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
2574 0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
2575 0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
2576 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
2577 0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
2578 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
2579 0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
2580 0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
2581 0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
2582 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
2583 0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
2584 0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
2585 0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
2586 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2587 0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
2588 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
2589 0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
2590 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
2591 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
2592 0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
2594 0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2598 /* www.weatherlink.com */
2599 static u8 dns_reply_data_initializer[] = {
2600 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2601 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x0b,
2602 0x77, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x6c, 0x69,
2603 0x6e, 0x6b, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0xff,
2604 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00,
2605 0x00, 0x0c, 0x9e, 0x00, 0x1f, 0x0e, 0x64, 0x33, 0x6b,
2606 0x72, 0x30, 0x67, 0x75, 0x62, 0x61, 0x31, 0x64, 0x76,
2607 0x77, 0x66, 0x0a, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x66,
2608 0x72, 0x6f, 0x6e, 0x74, 0x03, 0x6e, 0x65, 0x74, 0x00,
2613 static clib_error_t *
2614 test_dns_fmt_command_fn (vlib_main_t * vm,
2615 unformat_input_t * input, vlib_cli_command_t * cmd)
2617 u8 *dns_reply_data = 0;
2620 vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2622 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2624 if (unformat (input, "verbose %d", &verbose))
2626 else if (unformat (input, "verbose"))
2629 return clib_error_return (0, "unknown input `%U'",
2630 format_unformat_error, input);
2633 vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2635 memcpy (dns_reply_data, dns_reply_data_initializer,
2636 ARRAY_LEN (dns_reply_data_initializer));
2638 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2640 clib_memset (rmp, 0, sizeof (*rmp));
2642 rv = vnet_dns_response_to_reply (dns_reply_data, rmp, 0 /* ttl-ptr */ );
2646 case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2647 vlib_cli_output (vm, "no addresses found...");
2651 vlib_cli_output (vm, "response to reply returned %d", rv);
2656 vlib_cli_output (vm, "ip4 address: %U", format_ip4_address,
2657 (ip4_address_t *) rmp->ip4_address);
2659 vlib_cli_output (vm, "ip6 address: %U", format_ip6_address,
2660 (ip6_address_t *) rmp->ip6_address);
2664 vec_free (dns_reply_data);
2671 VLIB_CLI_COMMAND (test_dns_fmt_command) =
2673 .path = "test dns format",
2674 .short_help = "test dns format",
2675 .function = test_dns_fmt_command_fn,
2679 static clib_error_t *
2680 test_dns_unfmt_command_fn (vlib_main_t * vm,
2681 unformat_input_t * input, vlib_cli_command_t * cmd)
2683 u8 *dns_reply_data = 0;
2687 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2689 if (unformat (input, "verbose %d", &verbose))
2691 else if (unformat (input, "verbose"))
2693 else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2696 return clib_error_return (0, "unknown input `%U'",
2697 format_unformat_error, input);
2701 return clib_error_return (0, "dns data not set...");
2703 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2705 vec_free (dns_reply_data);
2711 VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2713 .path = "test dns unformat",
2714 .short_help = "test dns unformat <name> [ip4][ip6]",
2715 .function = test_dns_unfmt_command_fn,
2719 static clib_error_t *
2720 test_dns_expire_command_fn (vlib_main_t * vm,
2721 unformat_input_t * input,
2722 vlib_cli_command_t * cmd)
2724 dns_main_t *dm = &dns_main;
2728 dns_cache_entry_t *ep;
2730 if (unformat (input, "%v", &name))
2733 _vec_len (name) -= 1;
2736 return clib_error_return (0, "no name provided");
2738 dns_cache_lock (dm, 7);
2740 p = hash_get_mem (dm->cache_entry_by_name, name);
2743 dns_cache_unlock (dm);
2744 e = clib_error_return (0, "%s is not in the cache...", name);
2749 ep = pool_elt_at_index (dm->entries, p[0]);
2751 ep->expiration_time = 0;
2757 VLIB_CLI_COMMAND (test_dns_expire_command) =
2759 .path = "test dns expire",
2760 .short_help = "test dns expire <name>",
2761 .function = test_dns_expire_command_fn,
2767 vnet_send_dns6_reply (dns_main_t * dm, dns_pending_request_t * pr,
2768 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2770 clib_warning ("Unimplemented...");
2775 vnet_send_dns4_reply (dns_main_t * dm, dns_pending_request_t * pr,
2776 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2778 vlib_main_t *vm = dm->vlib_main;
2780 fib_prefix_t prefix;
2781 fib_node_index_t fei;
2782 u32 sw_if_index, fib_index;
2783 ip4_main_t *im4 = &ip4_main;
2784 ip_lookup_main_t *lm4 = &im4->lookup_main;
2785 ip_interface_address_t *ia = 0;
2786 ip4_address_t *src_address;
2794 vl_api_dns_resolve_name_reply_t _rnr, *rnr = &_rnr;
2795 vl_api_dns_resolve_ip_reply_t _rir, *rir = &_rir;
2802 int is_recycle = (b0 != 0);
2804 ASSERT (ep && ep->dns_response);
2806 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2808 /* Quick and dirty way to dig up the A-record address. $$ FIXME */
2809 clib_memset (rnr, 0, sizeof (*rnr));
2810 if (vnet_dns_response_to_reply (ep->dns_response, rnr, &ttl))
2812 /* clib_warning ("response_to_reply failed..."); */
2815 if (rnr->ip4_set == 0)
2817 /* clib_warning ("No A-record..."); */
2821 else if (pr->request_type == DNS_PEER_PENDING_IP_TO_NAME)
2823 clib_memset (rir, 0, sizeof (*rir));
2824 if (vnet_dns_response_to_name (ep->dns_response, rir, &ttl))
2826 /* clib_warning ("response_to_name failed..."); */
2832 clib_warning ("Unknown request type %d", pr->request_type);
2836 /* Initialize a buffer */
2839 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2841 b0 = vlib_get_buffer (vm, bi);
2845 /* Use the buffer we were handed. Reinitialize it... */
2846 vlib_buffer_t bt = { };
2847 /* push/pop the reference count */
2848 u8 save_ref_count = b0->ref_count;
2849 vlib_buffer_copy_template (b0, &bt);
2850 b0->ref_count = save_ref_count;
2851 bi = vlib_get_buffer_index (vm, b0);
2854 if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
2855 vlib_buffer_free_one (vm, b0->next_buffer);
2858 * Reset the buffer. We recycle the DNS request packet in the cache
2859 * hit case, and reply immediately from the request node.
2861 * In the resolution-required / deferred case, resetting a freshly-allocated
2862 * buffer won't hurt. We hope.
2864 b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
2865 | VLIB_BUFFER_TOTAL_LENGTH_VALID);
2866 vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; /* "local0" */
2867 vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
2869 /* Find a FIB path to the peer we're trying to answer */
2870 clib_memcpy (&prefix.fp_addr.ip4, pr->dst_address, sizeof (ip4_address_t));
2871 prefix.fp_proto = FIB_PROTOCOL_IP4;
2874 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
2875 if (fib_index == (u32) ~ 0)
2877 clib_warning ("no fib table");
2881 fei = fib_table_lookup (fib_index, &prefix);
2883 /* Couldn't find route to destination. Bail out. */
2884 if (fei == FIB_NODE_INDEX_INVALID)
2886 clib_warning ("no route to DNS server");
2890 sw_if_index = fib_entry_get_resolving_interface (fei);
2892 if (sw_if_index == ~0)
2895 ("route to %U exists, fei %d, get_resolving_interface returned"
2896 " ~0", fei, format_ip4_address, &prefix.fp_addr);
2901 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnumbered */,
2903 src_address = ip_interface_address_get_address (lm4, ia);
2904 goto found_src_address;
2908 clib_warning ("FIB BUG");
2913 ip = vlib_buffer_get_current (b0);
2914 udp = (udp_header_t *) (ip + 1);
2915 dns_response = (u8 *) (udp + 1);
2916 clib_memset (ip, 0, sizeof (*ip) + sizeof (*udp));
2919 * Start with the variadic portion of the exercise.
2920 * Turn the name into a set of DNS "labels". Max length
2921 * per label is 63, enforce that.
2923 reply = name_to_labels (pr->name);
2924 vec_free (pr->name);
2926 qp_offset = vec_len (reply);
2928 /* Add space for the query header */
2929 vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
2931 qp = (dns_query_t *) (reply + qp_offset);
2933 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2934 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
2936 qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2938 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
2940 /* Punch in space for the dns_header_t */
2941 vec_insert (reply, sizeof (dns_header_t), 0);
2943 dh = (dns_header_t *) reply;
2945 /* Transaction ID = pool index */
2948 /* Announce that we did a recursive lookup */
2949 tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
2951 tmp |= DNS_RCODE_NAME_ERROR;
2952 dh->flags = clib_host_to_net_u16 (tmp);
2953 dh->qdcount = clib_host_to_net_u16 (1);
2954 dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
2958 /* If the name resolution worked, cough up an appropriate RR */
2961 /* Add the answer. First, a name pointer (0xC00C) */
2962 vec_add1 (reply, 0xC0);
2963 vec_add1 (reply, 0x0C);
2965 /* Now, add single A-rec RR */
2966 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2968 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
2969 rr = (dns_rr_t *) rrptr;
2971 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
2972 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2973 rr->ttl = clib_host_to_net_u32 (ttl);
2974 rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
2975 clib_memcpy (rr->rdata, rnr->ip4_address, sizeof (ip4_address_t));
2979 /* Or a single PTR RR */
2980 u8 *vecname = format (0, "%s", rir->name);
2981 u8 *label_vec = name_to_labels (vecname);
2984 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
2985 rr = (dns_rr_t *) rrptr;
2986 rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2987 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2988 rr->ttl = clib_host_to_net_u32 (ttl);
2989 rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
2990 clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
2991 vec_free (label_vec);
2994 clib_memcpy (dns_response, reply, vec_len (reply));
2996 /* Set the packet length */
2997 b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
3000 ip->ip_version_and_header_length = 0x45;
3001 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
3003 ip->protocol = IP_PROTOCOL_UDP;
3004 ip->src_address.as_u32 = src_address->as_u32;
3005 clib_memcpy (ip->dst_address.as_u8, pr->dst_address,
3006 sizeof (ip4_address_t));
3007 ip->checksum = ip4_header_checksum (ip);
3010 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
3011 udp->dst_port = pr->dst_port;
3012 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
3018 * Ship pkts made out of whole cloth to ip4_lookup
3019 * Caller will ship recycled dns reply packets to ip4_lookup
3021 if (is_recycle == 0)
3023 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
3024 to_next = vlib_frame_vector_args (f);
3027 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
3031 static void *vl_api_dns_enable_disable_t_print
3032 (vl_api_dns_enable_disable_t * mp, void *handle)
3036 s = format (0, "SCRIPT: dns_enable_disable ");
3037 s = format (s, "%s ", mp->enable ? "enable" : "disable");
3042 static void *vl_api_dns_name_server_add_del_t_print
3043 (vl_api_dns_name_server_add_del_t * mp, void *handle)
3047 s = format (0, "SCRIPT: dns_name_server_add_del ");
3049 s = format (s, "%U ", format_ip6_address,
3050 (ip6_address_t *) mp->server_address);
3052 s = format (s, "%U ", format_ip4_address,
3053 (ip4_address_t *) mp->server_address);
3055 if (mp->is_add == 0)
3056 s = format (s, "del ");
3061 static void *vl_api_dns_resolve_name_t_print
3062 (vl_api_dns_resolve_name_t * mp, void *handle)
3066 s = format (0, "SCRIPT: dns_resolve_name ");
3067 s = format (s, "%s ", mp->name);
3071 static void *vl_api_dns_resolve_ip_t_print
3072 (vl_api_dns_resolve_ip_t * mp, void *handle)
3076 s = format (0, "SCRIPT: dns_resolve_ip ");
3078 s = format (s, "%U ", format_ip6_address, mp->address);
3080 s = format (s, "%U ", format_ip4_address, mp->address);
3085 dns_custom_dump_configure (dns_main_t * dm)
3087 #define _(n,f) dm->api_main->msg_print_handlers \
3088 [VL_API_##n + dm->msg_id_base] \
3089 = (void *) vl_api_##f##_t_print;
3090 foreach_dns_plugin_api_msg;
3094 /* Set up the API message handling tables */
3095 static clib_error_t *
3096 dns_plugin_api_hookup (vlib_main_t * vm)
3098 dns_main_t *dmp = &dns_main;
3100 vl_msg_api_set_handlers((VL_API_##N + dmp->msg_id_base), \
3102 vl_api_##n##_t_handler, \
3104 vl_api_##n##_t_endian, \
3105 vl_api_##n##_t_print, \
3106 sizeof(vl_api_##n##_t), 1);
3107 foreach_dns_plugin_api_msg;
3113 static clib_error_t *
3114 dns_init (vlib_main_t * vm)
3116 dns_main_t *dm = &dns_main;
3120 dm->vnet_main = vnet_get_main ();
3121 dm->name_cache_size = 1000;
3122 dm->max_ttl_in_seconds = 86400;
3123 dm->random_seed = 0xDEADDABE;
3124 dm->api_main = &api_main;
3126 name = format (0, "dns_%08x%c", api_version, 0);
3128 /* Ask for a correctly-sized block of API message decode slots */
3129 dm->msg_id_base = vl_msg_api_get_msg_ids
3130 ((char *) name, VL_MSG_FIRST_AVAILABLE);
3132 (void) dns_plugin_api_hookup (vm);
3134 /* Add our API messages to the global name_crc hash table */
3135 setup_message_id_table (dm);
3137 dns_custom_dump_configure (dm);
3144 VLIB_INIT_FUNCTION (dns_init);
3147 VLIB_PLUGIN_REGISTER () =
3149 .version = VPP_BUILD_VER,
3150 .description = "Simple DNS name resolver",
3156 * fd.io coding-style-patch-verification: ON
3159 * eval: (c-set-style "gnu")