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;
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;
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;
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;
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;
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 /* Note: caller must drop the lock! */
914 * Resolution pending. Add request to the pending vector
915 * by copying the template request
917 vec_add2 (ep->pending_requests, pr, 1);
918 memcpy (pr, t, sizeof (*pr));
919 dns_cache_unlock (dm);
925 if (pool_elts (dm->entries) == dm->name_cache_size)
927 /* Will only fail if the cache is totally filled w/ static entries... */
928 rv = delete_random_entry (dm);
931 dns_cache_unlock (dm);
936 /* add new hash table entry */
937 pool_get (dm->entries, ep);
938 clib_memset (ep, 0, sizeof (*ep));
940 ep->name = format (0, "%s%c", name, 0);
941 _vec_len (ep->name) = vec_len (ep->name) - 1;
943 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
945 vec_add1 (dm->unresolved_entries, ep - dm->entries);
946 vec_add2 (ep->pending_requests, pr, 1);
948 pr->request_type = t->request_type;
950 /* Remember details so we can reply later... */
951 if (t->request_type == DNS_API_PENDING_NAME_TO_IP ||
952 t->request_type == DNS_API_PENDING_IP_TO_NAME)
954 pr->client_index = t->client_index;
955 pr->client_context = t->client_context;
959 pr->client_index = ~0;
960 pr->is_ip6 = t->is_ip6;
961 pr->dst_port = t->dst_port;
968 clib_memcpy (pr->dst_address, t->dst_address, count);
971 vnet_send_dns_request (dm, ep);
972 dns_cache_unlock (dm);
976 #define foreach_notification_to_move \
980 * Handle cname indirection. JFC. Called with the cache locked.
981 * returns 0 if the reply is not a CNAME.
985 vnet_dns_cname_indirection_nolock (dns_main_t * dm, u32 ep_index, u8 * reply)
1000 dns_cache_entry_t *ep, *next_ep;
1003 h = (dns_header_t *) reply;
1004 flags = clib_net_to_host_u16 (h->flags);
1005 rcode = flags & DNS_RCODE_MASK;
1007 /* See if the response is OK */
1010 case DNS_RCODE_NO_ERROR:
1013 case DNS_RCODE_NAME_ERROR:
1014 case DNS_RCODE_FORMAT_ERROR:
1015 case DNS_RCODE_SERVER_FAILURE:
1016 case DNS_RCODE_NOT_IMPLEMENTED:
1017 case DNS_RCODE_REFUSED:
1021 curpos = (u8 *) (h + 1);
1025 /* Skip the questions */
1026 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
1033 pos += sizeof (dns_query_t);
1036 /* expect a pointer chase here for a CNAME record */
1037 if ((pos2[0] & 0xC0) == 0xC0)
1042 /* Walk the answer(s) to see what to do next */
1043 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
1045 rr = (dns_rr_t *) pos;
1046 switch (clib_net_to_host_u16 (rr->type))
1048 /* Real address record? Done.. */
1053 * Maybe chase a CNAME pointer?
1054 * It's not unheard-of for name-servers to return
1055 * both CNAME and A/AAAA records...
1057 case DNS_TYPE_CNAME:
1061 /* Some other junk, e.g. a nameserver... */
1065 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1067 if ((pos2[0] & 0xc0) == 0xc0)
1071 /* Neither a CNAME nor a real address. Try another server */
1074 flags &= ~DNS_RCODE_MASK;
1075 flags |= DNS_RCODE_NAME_ERROR;
1076 h->flags = clib_host_to_net_u16 (flags);
1080 /* This is a CNAME record, chase the name chain. */
1083 /* The last request is no longer pending.. */
1084 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
1085 if (ep_index == dm->unresolved_entries[i])
1087 vec_delete (dm->unresolved_entries, 1, i);
1088 goto found_last_request;
1090 clib_warning ("pool elt %d supposedly pending, but not found...", ep_index);
1095 now = vlib_time_now (dm->vlib_main);
1096 cname = vnet_dns_labels_to_name (rr->rdata, reply, &pos2);
1097 /* Save the cname */
1098 vec_add1 (cname, 0);
1099 _vec_len (cname) -= 1;
1100 ep = pool_elt_at_index (dm->entries, ep_index);
1102 ep->flags |= (DNS_CACHE_ENTRY_FLAG_CNAME | DNS_CACHE_ENTRY_FLAG_VALID);
1103 /* Save the response */
1104 if (ep->dns_response)
1105 vec_free (ep->dns_response);
1106 ep->dns_response = reply;
1107 /* Set up expiration time */
1108 ep->expiration_time = now + clib_net_to_host_u32 (rr->ttl);
1110 pool_get (dm->entries, next_ep);
1112 /* Need to recompute ep post pool-get */
1113 ep = pool_elt_at_index (dm->entries, ep_index);
1115 clib_memset (next_ep, 0, sizeof (*next_ep));
1116 next_ep->name = vec_dup (cname);
1117 vec_add1 (next_ep->name, 0);
1118 _vec_len (next_ep->name) -= 1;
1120 hash_set_mem (dm->cache_entry_by_name, next_ep->name,
1121 next_ep - dm->entries);
1123 /* Use the same server */
1124 next_ep->server_rotor = ep->server_rotor;
1125 next_ep->server_af = ep->server_af;
1127 /* Move notification data to the next name in the chain */
1128 #define _(a) next_ep->a = ep->a; ep->a = 0;
1129 foreach_notification_to_move;
1132 request = name_to_labels (cname);
1133 name_copy = vec_dup (request);
1135 qp_offset = vec_len (request);
1137 /* Add space for the query header */
1138 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
1140 qp = (dns_query_t *) (request + qp_offset);
1142 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
1143 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1144 clib_memcpy (qp, name_copy, vec_len (name_copy));
1145 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
1146 vec_free (name_copy);
1148 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1149 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1151 /* Punch in space for the dns_header_t */
1152 vec_insert (request, sizeof (dns_header_t), 0);
1154 h = (dns_header_t *) request;
1156 /* Transaction ID = pool index */
1157 h->id = clib_host_to_net_u16 (next_ep - dm->entries);
1159 /* Ask for a recursive lookup */
1160 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
1161 h->qdcount = clib_host_to_net_u16 (2);
1165 next_ep->dns_request = request;
1166 next_ep->retry_timer = now + 2.0;
1167 next_ep->retry_count = 0;
1170 * Enable this to watch recursive resolution happen...
1171 * fformat (stdout, "%U", format_dns_reply, request, 2);
1174 vec_add1 (dm->unresolved_entries, next_ep - dm->entries);
1175 vnet_send_dns_request (dm, next_ep);
1180 vnet_dns_response_to_reply (u8 * response,
1181 vl_api_dns_resolve_name_reply_t * rmp,
1189 u8 *curpos, *pos, *pos2;
1195 h = (dns_header_t *) response;
1196 flags = clib_net_to_host_u16 (h->flags);
1197 rcode = flags & DNS_RCODE_MASK;
1199 /* See if the response is OK, etc. */
1203 case DNS_RCODE_NO_ERROR:
1206 case DNS_RCODE_NAME_ERROR:
1207 case DNS_RCODE_FORMAT_ERROR:
1208 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1210 case DNS_RCODE_SERVER_FAILURE:
1211 case DNS_RCODE_NOT_IMPLEMENTED:
1212 case DNS_RCODE_REFUSED:
1213 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1216 /* No answers? Loser... */
1217 if (clib_net_to_host_u16 (h->anscount) < 1)
1218 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1220 curpos = (u8 *) (h + 1);
1222 /* Skip the name we asked about */
1225 /* Should never happen, but stil... */
1226 if ((len & 0xC0) == 0xC0)
1230 /* skip the name / label-set */
1239 limit = clib_net_to_host_u16 (h->qdcount);
1240 qp = (dns_query_t *) curpos;
1245 limit = clib_net_to_host_u16 (h->anscount);
1247 for (i = 0; i < limit; i++)
1249 pos = pos2 = curpos;
1252 /* Expect pointer chases in the answer section... */
1253 if ((pos2[0] & 0xC0) == 0xC0)
1256 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1265 if ((pos2[0] & 0xc0) == 0xc0)
1268 * If we've already done one pointer chase,
1269 * do not move the pos pointer.
1271 if (pointer_chase == 0)
1273 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1281 if (pointer_chase == 0)
1284 rr = (dns_rr_t *) pos;
1286 switch (clib_net_to_host_u16 (rr->type))
1289 /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1290 memcpy (rmp->ip4_address, rr->rdata, sizeof (ip4_address_t));
1292 ttl = clib_net_to_host_u32 (rr->ttl);
1293 if (min_ttlp && *min_ttlp > ttl)
1297 /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1298 memcpy (rmp->ip6_address, rr->rdata, sizeof (ip6_address_t));
1299 ttl = clib_net_to_host_u32 (rr->ttl);
1300 if (min_ttlp && *min_ttlp > ttl)
1308 /* Might as well stop ASAP */
1309 if (rmp->ip4_set && rmp->ip6_set)
1311 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1315 if ((rmp->ip4_set + rmp->ip6_set) == 0)
1316 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1321 vnet_dns_response_to_name (u8 * response,
1322 vl_api_dns_resolve_ip_reply_t * rmp,
1330 u8 *curpos, *pos, *pos2;
1335 u8 *junk __attribute__ ((unused));
1339 h = (dns_header_t *) response;
1340 flags = clib_net_to_host_u16 (h->flags);
1341 rcode = flags & DNS_RCODE_MASK;
1343 /* See if the response is OK, etc. */
1347 case DNS_RCODE_NO_ERROR:
1350 case DNS_RCODE_NAME_ERROR:
1351 case DNS_RCODE_FORMAT_ERROR:
1352 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1354 case DNS_RCODE_SERVER_FAILURE:
1355 case DNS_RCODE_NOT_IMPLEMENTED:
1356 case DNS_RCODE_REFUSED:
1357 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1360 /* No answers? Loser... */
1361 if (clib_net_to_host_u16 (h->anscount) < 1)
1362 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1364 curpos = (u8 *) (h + 1);
1366 /* Skip the name we asked about */
1369 /* Should never happen, but stil... */
1370 if ((len & 0xC0) == 0xC0)
1374 /* skip the name / label-set */
1383 limit = clib_net_to_host_u16 (h->qdcount);
1384 qp = (dns_query_t *) curpos;
1389 limit = clib_net_to_host_u16 (h->anscount);
1391 for (i = 0; i < limit; i++)
1393 pos = pos2 = curpos;
1396 /* Expect pointer chases in the answer section... */
1397 if ((pos2[0] & 0xC0) == 0xC0)
1400 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1409 if ((pos2[0] & 0xc0) == 0xc0)
1412 * If we've already done one pointer chase,
1413 * do not move the pos pointer.
1415 if (pointer_chase == 0)
1417 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1425 if (pointer_chase == 0)
1428 rr = (dns_rr_t *) pos;
1430 switch (clib_net_to_host_u16 (rr->type))
1433 name = vnet_dns_labels_to_name (rr->rdata, response, &junk);
1434 memcpy (rmp->name, name, vec_len (name));
1435 ttl = clib_net_to_host_u32 (rr->ttl);
1438 rmp->name[vec_len (name)] = 0;
1444 /* Might as well stop ASAP */
1447 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1452 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1457 vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1459 dns_main_t *dm = &dns_main;
1460 vl_api_dns_resolve_name_reply_t *rmp;
1461 dns_cache_entry_t *ep;
1462 dns_pending_request_t _t0, *t0 = &_t0;
1465 /* Sanitize the name slightly */
1466 mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1468 t0->request_type = DNS_API_PENDING_NAME_TO_IP;
1469 t0->client_index = mp->client_index;
1470 t0->client_context = mp->context;
1472 rv = vnet_dns_resolve_name (dm, mp->name, t0, &ep);
1474 /* Error, e.g. not enabled? Tell the user */
1477 REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1481 /* Resolution pending? Don't reply... */
1486 REPLY_MACRO2(VL_API_DNS_RESOLVE_NAME_REPLY,
1488 rv = vnet_dns_response_to_reply (ep->dns_response, rmp, 0 /* ttl-ptr */);
1489 rmp->retval = clib_host_to_net_u32 (rv);
1494 * dns_resolve_name leaves the cache locked when it returns
1495 * a cached result, so unlock it here.
1497 dns_cache_unlock (dm);
1501 vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
1503 dns_main_t *dm = &dns_main;
1504 vl_api_dns_resolve_ip_reply_t *rmp;
1505 dns_cache_entry_t *ep;
1508 u8 *lookup_name = 0;
1510 dns_pending_request_t _t0, *t0 = &_t0;
1514 for (i = 15; i >= 0; i--)
1516 digit = mp->address[i];
1517 nybble = (digit & 0x0F);
1519 vec_add1 (lookup_name, (nybble - 10) + 'a');
1521 vec_add1 (lookup_name, nybble + '0');
1522 vec_add1 (lookup_name, '.');
1523 nybble = (digit & 0xF0) >> 4;
1525 vec_add1 (lookup_name, (nybble - 10) + 'a');
1527 vec_add1 (lookup_name, nybble + '0');
1528 vec_add1 (lookup_name, '.');
1530 len = vec_len (lookup_name);
1531 vec_validate (lookup_name, len + 8);
1532 memcpy (lookup_name + len, "ip6.arpa", 8);
1536 for (i = 3; i >= 0; i--)
1538 digit = mp->address[i];
1539 lookup_name = format (lookup_name, "%d.", digit);
1541 lookup_name = format (lookup_name, "in-addr.arpa");
1544 vec_add1 (lookup_name, 0);
1546 t0->request_type = DNS_API_PENDING_IP_TO_NAME;
1547 t0->client_index = mp->client_index;
1548 t0->client_context = mp->context;
1550 rv = vnet_dns_resolve_name (dm, lookup_name, t0, &ep);
1552 vec_free (lookup_name);
1554 /* Error, e.g. not enabled? Tell the user */
1557 REPLY_MACRO (VL_API_DNS_RESOLVE_IP_REPLY);
1561 /* Resolution pending? Don't reply... */
1566 REPLY_MACRO2(VL_API_DNS_RESOLVE_IP_REPLY,
1568 rv = vnet_dns_response_to_name (ep->dns_response, rmp, 0 /* ttl-ptr */);
1569 rmp->retval = clib_host_to_net_u32 (rv);
1574 * vnet_dns_resolve_name leaves the cache locked when it returns
1575 * a cached result, so unlock it here.
1577 dns_cache_unlock (dm);
1580 #define vl_msg_name_crc_list
1581 #include <dns/dns_all_api_h.h>
1582 #undef vl_msg_name_crc_list
1585 setup_message_id_table (dns_main_t * dm)
1587 #define _(id,n,crc) \
1588 vl_msg_api_add_msg_name_crc (dm->api_main, #n "_" #crc, dm->msg_id_base + id);
1589 foreach_vl_msg_name_crc_dns;
1593 #define foreach_dns_plugin_api_msg \
1594 _(DNS_ENABLE_DISABLE, dns_enable_disable) \
1595 _(DNS_NAME_SERVER_ADD_DEL, dns_name_server_add_del) \
1596 _(DNS_RESOLVE_NAME, dns_resolve_name) \
1597 _(DNS_RESOLVE_IP, dns_resolve_ip)
1599 static clib_error_t *
1600 dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1602 dns_main_t *dm = &dns_main;
1604 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1606 if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1608 else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1611 return clib_error_return (0, "unknown input `%U'",
1612 format_unformat_error, input);
1617 VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1620 unformat_dns_reply (unformat_input_t * input, va_list * args)
1622 u8 **result = va_arg (*args, u8 **);
1623 u8 **namep = va_arg (*args, u8 **);
1637 if (unformat (input, "%v", &name))
1640 if (unformat (input, "%U", unformat_ip4_address, &a4))
1643 if (unformat (input, "%U", unformat_ip6_address, &a6))
1647 if (unformat (input, "%U", unformat_ip6_address, &a6))
1650 if (unformat (input, "%U", unformat_ip4_address, &a6))
1654 /* Must have a name */
1658 /* Must have at least one address */
1659 if (!(a4_set + a6_set))
1662 /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1663 ce = name_to_labels (name);
1664 qp_offset = vec_len (ce);
1666 /* Add space for the query header */
1667 vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1668 qp = (dns_query_t *) (ce + qp_offset);
1670 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1671 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1673 /* Punch in space for the dns_header_t */
1674 vec_insert (ce, sizeof (dns_header_t), 0);
1676 h = (dns_header_t *) ce;
1678 /* Fake Transaction ID */
1681 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1682 h->qdcount = clib_host_to_net_u16 (1);
1683 h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1687 /* Now append one or two A/AAAA RR's... */
1690 /* Pointer to the name (DGMS) */
1691 vec_add1 (ce, 0xC0);
1692 vec_add1 (ce, 0x0C);
1693 vec_add2 (ce, rru8, sizeof (*rr) + 4);
1695 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1696 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1697 rr->ttl = clib_host_to_net_u32 (86400);
1698 rr->rdlength = clib_host_to_net_u16 (4);
1699 memcpy (rr->rdata, &a4, sizeof (a4));
1703 /* Pointer to the name (DGMS) */
1704 vec_add1 (ce, 0xC0);
1705 vec_add1 (ce, 0x0C);
1706 vec_add2 (ce, rru8, sizeof (*rr) + 16);
1708 rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1709 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1710 rr->ttl = clib_host_to_net_u32 (86400);
1711 rr->rdlength = clib_host_to_net_u16 (16);
1712 memcpy (rr->rdata, &a6, sizeof (a6));
1724 format_dns_query (u8 * s, va_list * args)
1726 u8 **curpos = va_arg (*args, u8 **);
1727 int verbose = va_arg (*args, int);
1732 s = format (s, " Name: ");
1734 /* Unwind execrated counted-label sheit */
1740 for (i = 0; i < len; i++)
1741 vec_add1 (s, *pos++);
1753 qp = (dns_query_t *) pos;
1756 switch (clib_net_to_host_u16 (qp->type))
1759 s = format (s, "type A\n");
1762 s = format (s, "type AAAA\n");
1765 s = format (s, "type ALL\n");
1769 s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1774 pos += sizeof (*qp);
1781 * format dns reply data
1782 * verbose > 1, dump everything
1783 * verbose == 1, dump all A and AAAA records
1784 * verbose == 0, dump one A record, and one AAAA record
1788 format_dns_reply_data (u8 * s, va_list * args)
1790 u8 *reply = va_arg (*args, u8 *);
1791 u8 **curpos = va_arg (*args, u8 **);
1792 int verbose = va_arg (*args, int);
1793 int *print_ip4 = va_arg (*args, int *);
1794 int *print_ip6 = va_arg (*args, int *);
1799 int pointer_chase = 0;
1801 u16 rrtype_host_byte_order;
1803 pos = pos2 = *curpos;
1806 s = format (s, " ");
1808 /* chase pointer? almost always yes here... */
1809 if ((pos2[0] & 0xc0) == 0xc0)
1812 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1820 for (i = 0; i < len; i++)
1823 vec_add1 (s, *pos2);
1826 if ((pos2[0] & 0xc0) == 0xc0)
1829 * If we've already done one pointer chase,
1830 * do not move the pos pointer.
1832 if (pointer_chase == 0)
1834 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1852 if (pointer_chase == 0)
1855 rr = (dns_rr_t *) pos;
1856 rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
1858 switch (rrtype_host_byte_order)
1863 s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1864 format_ip4_address, rr->rdata);
1869 s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1870 clib_net_to_host_u32 (rr->ttl));
1875 pos += sizeof (*rr) + 4;
1881 s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1882 format_ip6_address, rr->rdata);
1887 s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1888 clib_net_to_host_u32 (rr->ttl));
1892 pos += sizeof (*rr) + 16;
1898 s = format (s, "TEXT: ");
1899 for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1900 vec_add1 (s, rr->rdata[i]);
1903 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1906 case DNS_TYPE_HINFO:
1908 /* Two counted strings. DGMS */
1914 s = format (s, "HINFO: ");
1917 for (i = 0; i < *len; i++)
1918 vec_add1 (s, *curpos++);
1922 for (i = 0; i < *len; i++)
1923 vec_add1 (s, *curpos++);
1928 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1931 case DNS_TYPE_NAMESERVER:
1934 s = format (s, "Nameserver: ");
1937 /* chase pointer? */
1938 if ((pos2[0] & 0xc0) == 0xc0)
1941 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1948 for (i = 0; i < len; i++)
1949 vec_add1 (s, *pos2++);
1951 /* chase pointer, typically to offset 12... */
1952 if (pos2[0] == 0xC0)
1953 pos2 = reply + pos2[1];
1962 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1965 case DNS_TYPE_MAIL_EXCHANGE:
1968 tp = (u16 *) rr->rdata;
1970 s = format (s, "Mail Exchange: Preference %d ", (u32)
1971 clib_net_to_host_u16 (*tp));
1973 pos2 = rr->rdata + 2;
1975 /* chase pointer? */
1976 if (pos2[0] == 0xc0)
1977 pos2 = reply + pos2[1];
1983 for (i = 0; i < len; i++)
1984 vec_add1 (s, *pos2++);
1987 if (pos2[0] == 0xC0)
1988 pos2 = reply + pos2[1];
1998 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2002 case DNS_TYPE_CNAME:
2005 tp = (u16 *) rr->rdata;
2007 if (rrtype_host_byte_order == DNS_TYPE_CNAME)
2008 s = format (s, "CNAME: ");
2010 s = format (s, "PTR: ");
2014 /* chase pointer? */
2015 if (pos2[0] == 0xc0)
2016 pos2 = reply + pos2[1];
2022 for (i = 0; i < len; i++)
2023 vec_add1 (s, *pos2++);
2026 if (pos2[0] == 0xC0)
2027 pos2 = reply + pos2[1];
2036 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2041 s = format (s, "type %d: len %d\n",
2042 (int) clib_net_to_host_u16 (rr->type),
2043 sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
2044 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2054 format_dns_reply (u8 * s, va_list * args)
2056 u8 *reply_as_u8 = va_arg (*args, u8 *);
2057 int verbose = va_arg (*args, int);
2065 h = (dns_header_t *) reply_as_u8;
2066 id = clib_net_to_host_u16 (h->id);
2067 flags = clib_net_to_host_u16 (h->flags);
2071 s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
2073 s = format (s, " %s %s %s %s\n",
2074 (flags & DNS_RA) ? "recur" : "no-recur",
2075 (flags & DNS_RD) ? "recur-des" : "no-recur-des",
2076 (flags & DNS_TC) ? "trunc" : "no-trunc",
2077 (flags & DNS_AA) ? "auth" : "non-auth");
2078 s = format (s, " %d queries, %d answers, %d name-servers,"
2080 clib_net_to_host_u16 (h->qdcount),
2081 clib_net_to_host_u16 (h->anscount),
2082 clib_net_to_host_u16 (h->nscount),
2083 clib_net_to_host_u16 (h->arcount));
2086 curpos = (u8 *) (h + 1);
2091 s = format (s, " Queries:\n");
2092 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
2094 /* The query is variable-length, so curpos is a value-result parm */
2095 s = format (s, "%U", format_dns_query, &curpos, verbose);
2101 s = format (s, " Replies:\n");
2103 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
2105 /* curpos is a value-result parm */
2106 s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
2107 verbose, &print_ip4, &print_ip6);
2114 format_dns_cache (u8 * s, va_list * args)
2116 dns_main_t *dm = va_arg (*args, dns_main_t *);
2117 f64 now = va_arg (*args, f64);
2118 int verbose = va_arg (*args, int);
2119 u8 *name = va_arg (*args, u8 *);
2120 dns_cache_entry_t *ep;
2124 if (dm->is_enabled == 0)
2126 s = format (s, "The DNS cache is disabled...");
2130 if (pool_elts (dm->entries) == 0)
2132 s = format (s, "The DNS cache is empty...");
2136 dns_cache_lock (dm);
2140 p = hash_get_mem (dm->cache_entry_by_name, name);
2143 s = format (s, "%s is not in the cache...", name);
2144 dns_cache_unlock (dm);
2148 ep = pool_elt_at_index (dm->entries, p[0]);
2149 /* Magic to spit out a C-initializer to research hemorrhoids... */
2153 s = format (s, "static u8 dns_reply_data_initializer[] =\n");
2154 s = format (s, "{\n");
2156 for (i = 0; i < vec_len (ep->dns_response); i++)
2163 s = format (s, "0x%02x, ", ep->dns_response[i]);
2165 s = format (s, "};\n");
2169 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2171 ASSERT (ep->dns_response);
2172 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2177 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2178 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2180 s = format (s, "%s%s -> %U", ss, ep->name,
2181 format_dns_reply, ep->dns_response, verbose);
2182 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2184 f64 time_left = ep->expiration_time - now;
2185 if (time_left > 0.0)
2186 s = format (s, " TTL left %.1f", time_left);
2188 s = format (s, " EXPIRED");
2193 ASSERT (ep->dns_request);
2194 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2202 s = format (s, "DNS cache contains %d entries\n", pool_elts (dm->entries));
2207 pool_foreach (ep, dm->entries,
2209 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2211 ASSERT (ep->dns_response);
2212 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2217 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2218 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2220 s = format (s, "%s%s -> %U", ss, ep->name,
2224 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2226 f64 time_left = ep->expiration_time - now;
2227 if (time_left > 0.0)
2228 s = format (s, " TTL left %.1f", time_left);
2230 s = format (s, " EXPIRED");
2233 s = format (s, " %d client notifications pending\n",
2234 vec_len(ep->pending_requests));
2239 ASSERT (ep->dns_request);
2240 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2248 dns_cache_unlock (dm);
2253 static clib_error_t *
2254 show_dns_cache_command_fn (vlib_main_t * vm,
2255 unformat_input_t * input, vlib_cli_command_t * cmd)
2257 dns_main_t *dm = &dns_main;
2260 f64 now = vlib_time_now (vm);
2262 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2264 if (unformat (input, "verbose %d", &verbose))
2266 else if (unformat (input, "verbose"))
2268 else if (unformat (input, "name %s", &name))
2271 return clib_error_return (0, "unknown input `%U'",
2272 format_unformat_error, input);
2275 vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
2281 VLIB_CLI_COMMAND (show_dns_cache_command) =
2283 .path = "show dns cache",
2284 .short_help = "show dns cache [verbose [nn]]",
2285 .function = show_dns_cache_command_fn,
2289 static clib_error_t *
2290 show_dns_servers_command_fn (vlib_main_t * vm,
2291 unformat_input_t * input,
2292 vlib_cli_command_t * cmd)
2294 dns_main_t *dm = &dns_main;
2297 if ((vec_len (dm->ip4_name_servers) + vec_len (dm->ip6_name_servers)) == 0)
2298 return clib_error_return (0, "No name servers configured...");
2300 if (vec_len (dm->ip4_name_servers))
2302 vlib_cli_output (vm, "ip4 name servers:");
2303 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
2304 vlib_cli_output (vm, "%U", format_ip4_address,
2305 dm->ip4_name_servers + i);
2307 if (vec_len (dm->ip6_name_servers))
2309 vlib_cli_output (vm, "ip6 name servers:");
2310 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
2311 vlib_cli_output (vm, "%U", format_ip6_address,
2312 dm->ip4_name_servers + i);
2318 VLIB_CLI_COMMAND (show_dns_server_command) =
2320 .path = "show dns servers",
2321 .short_help = "show dns servers",
2322 .function = show_dns_servers_command_fn,
2327 static clib_error_t *
2328 dns_cache_add_del_command_fn (vlib_main_t * vm,
2329 unformat_input_t * input,
2330 vlib_cli_command_t * cmd)
2332 dns_main_t *dm = &dns_main;
2338 clib_error_t *error;
2340 if (unformat (input, "add"))
2342 if (unformat (input, "del"))
2344 if (unformat (input, "clear"))
2347 if (is_add == -1 && is_clear == -1)
2348 return clib_error_return (0, "add / del / clear required...");
2352 rv = dns_cache_clear (dm);
2358 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2359 error = clib_error_return (0, "Name resolution not enabled");
2364 /* Delete (by name)? */
2367 if (unformat (input, "%v", &name))
2369 rv = dns_delete_by_name (dm, name);
2372 case VNET_API_ERROR_NO_SUCH_ENTRY:
2373 error = clib_error_return (0, "%v not in the cache...", name);
2377 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2378 error = clib_error_return (0, "Name resolution not enabled");
2387 error = clib_error_return (0, "dns_delete_by_name returned %d",
2393 return clib_error_return (0, "unknown input `%U'",
2394 format_unformat_error, input);
2397 /* Note: dns_add_static_entry consumes the name vector if OK... */
2398 if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2400 rv = dns_add_static_entry (dm, name, dns_reply_data);
2403 case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2405 vec_free (dns_reply_data);
2406 return clib_error_return (0, "%v already in the cache...", name);
2411 return clib_error_return (0, "dns_add_static_entry returned %d",
2420 VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2422 .path = "dns cache",
2423 .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2424 .function = dns_cache_add_del_command_fn,
2428 #define DNS_FORMAT_TEST 1
2430 #if DNS_FORMAT_TEST > 0
2433 static u8 dns_reply_data_initializer[] =
2434 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2435 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2437 0x0, 0xff, /* type ALL */
2438 0x0, 0x1, /* class IN */
2439 0xc0, 0xc, /* pointer to yahoo.com name */
2440 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2441 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2442 0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2443 0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2444 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2445 0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2446 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2447 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2448 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2449 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2450 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2451 0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2452 0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2454 0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2455 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2456 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2457 0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2458 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2460 0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2461 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2462 0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2463 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2465 0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2466 0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2468 0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2470 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2472 0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2474 0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2475 0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2476 0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2480 /* www.cisco.com, has no addresses in reply */
2481 static u8 dns_reply_data_initializer[] = {
2482 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2483 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2484 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2486 0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2487 0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2488 0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2489 0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2490 0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2493 /* bind8 (linux widget, w/ nasty double pointer chasees */
2494 static u8 dns_reply_data_initializer[] = {
2496 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08,
2498 0x00, 0x06, 0x00, 0x06, 0x0a, 0x6f, 0x72, 0x69,
2500 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77, 0x77, 0x05,
2502 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f,
2504 0x6d, 0x00, 0x00, 0xff, 0x00, 0x01, 0x0a, 0x6f,
2506 0x72, 0x69, 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77,
2508 0x77, 0x05, 0x43, 0x49, 0x53, 0x43, 0x4f, 0xc0,
2511 0x1d, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2514 0x9a, 0x00, 0x18, 0x15, 0x72, 0x63, 0x64,
2515 0x6e, 0x39, 0x2d, 0x31, 0x34, 0x70, 0x2d, 0x64, 0x63,
2516 0x7a, 0x30, 0x35, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31,
2517 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00, 0x01, 0x00,
2518 0x00, 0x05, 0x9a, 0x00, 0x1a, 0x17, 0x61, 0x6c, 0x6c,
2519 0x6e, 0x30, 0x31, 0x2d, 0x61, 0x67, 0x30, 0x39, 0x2d,
2520 0x64, 0x63, 0x7a, 0x30, 0x33, 0x6e, 0x2d, 0x67, 0x73,
2521 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00,
2522 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x10, 0x0d, 0x72,
2523 0x74, 0x70, 0x35, 0x2d, 0x64, 0x6d, 0x7a, 0x2d, 0x67,
2524 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2525 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x18, 0x15,
2526 0x6d, 0x74, 0x76, 0x35, 0x2d, 0x61, 0x70, 0x31, 0x30,
2527 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x36, 0x6e, 0x2d, 0x67,
2528 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2529 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x1b, 0x18,
2530 0x73, 0x6e, 0x67, 0x64, 0x63, 0x30, 0x31, 0x2d, 0x61,
2531 0x62, 0x30, 0x37, 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x31,
2532 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0,
2533 0x26, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a,
2534 0x00, 0x1a, 0x17, 0x61, 0x65, 0x72, 0x30, 0x31, 0x2d,
2535 0x72, 0x34, 0x63, 0x32, 0x35, 0x2d, 0x64, 0x63, 0x7a,
2536 0x30, 0x31, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0,
2537 0x17, 0xc0, 0x26, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2538 0x00, 0x81, 0x00, 0x04, 0x48, 0xa3, 0x04, 0xa1, 0xc0,
2539 0x26, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82,
2540 0x00, 0x10, 0x20, 0x01, 0x04, 0x20, 0x12, 0x01, 0x00,
2541 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
2542 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2543 0x9a, 0x00, 0x02, 0xc0, 0xf4, 0xc0, 0x0c, 0x00, 0x02,
2544 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0,
2545 0xcd, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00,
2546 0x05, 0x9a, 0x00, 0x02, 0xc0, 0x8d, 0xc0, 0x0c, 0x00,
2547 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02,
2548 0xc0, 0x43, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00,
2549 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0, 0xa9, 0xc0, 0x0c,
2550 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00,
2551 0x02, 0xc0, 0x67, 0xc0, 0x8d, 0x00, 0x01, 0x00, 0x01,
2552 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0x40, 0x66, 0xf6,
2553 0x05, 0xc0, 0xa9, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2554 0x07, 0x08, 0x00, 0x04, 0xad, 0x24, 0xe0, 0x64, 0xc0,
2555 0x43, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08,
2556 0x00, 0x04, 0x48, 0xa3, 0x04, 0x1c, 0xc0, 0xf4, 0x00,
2557 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04,
2558 0xad, 0x26, 0xd4, 0x6c, 0xc0, 0x67, 0x00, 0x01, 0x00,
2559 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x25,
2560 0x90, 0x64, 0xc0, 0xcd, 0x00, 0x01, 0x00, 0x01, 0x00,
2561 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x27, 0x70, 0x44,
2565 static u8 dns_reply_data_initializer[] =
2566 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
2567 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
2568 0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
2569 0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
2571 0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
2572 0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
2573 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
2574 0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
2575 0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
2576 0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
2577 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
2578 0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
2579 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
2580 0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
2581 0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
2582 0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
2583 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
2584 0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
2585 0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
2586 0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
2587 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2588 0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
2589 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
2590 0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
2591 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
2592 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
2593 0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
2595 0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2599 /* www.weatherlink.com */
2600 static u8 dns_reply_data_initializer[] = {
2601 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2602 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x0b,
2603 0x77, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x6c, 0x69,
2604 0x6e, 0x6b, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0xff,
2605 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00,
2606 0x00, 0x0c, 0x9e, 0x00, 0x1f, 0x0e, 0x64, 0x33, 0x6b,
2607 0x72, 0x30, 0x67, 0x75, 0x62, 0x61, 0x31, 0x64, 0x76,
2608 0x77, 0x66, 0x0a, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x66,
2609 0x72, 0x6f, 0x6e, 0x74, 0x03, 0x6e, 0x65, 0x74, 0x00,
2614 static clib_error_t *
2615 test_dns_fmt_command_fn (vlib_main_t * vm,
2616 unformat_input_t * input, vlib_cli_command_t * cmd)
2618 u8 *dns_reply_data = 0;
2621 vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2623 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2625 if (unformat (input, "verbose %d", &verbose))
2627 else if (unformat (input, "verbose"))
2630 return clib_error_return (0, "unknown input `%U'",
2631 format_unformat_error, input);
2634 vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2636 memcpy (dns_reply_data, dns_reply_data_initializer,
2637 ARRAY_LEN (dns_reply_data_initializer));
2639 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2641 clib_memset (rmp, 0, sizeof (*rmp));
2643 rv = vnet_dns_response_to_reply (dns_reply_data, rmp, 0 /* ttl-ptr */ );
2647 case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2648 vlib_cli_output (vm, "no addresses found...");
2652 vlib_cli_output (vm, "response to reply returned %d", rv);
2657 vlib_cli_output (vm, "ip4 address: %U", format_ip4_address,
2658 (ip4_address_t *) rmp->ip4_address);
2660 vlib_cli_output (vm, "ip6 address: %U", format_ip6_address,
2661 (ip6_address_t *) rmp->ip6_address);
2665 vec_free (dns_reply_data);
2672 VLIB_CLI_COMMAND (test_dns_fmt_command) =
2674 .path = "test dns format",
2675 .short_help = "test dns format",
2676 .function = test_dns_fmt_command_fn,
2680 static clib_error_t *
2681 test_dns_unfmt_command_fn (vlib_main_t * vm,
2682 unformat_input_t * input, vlib_cli_command_t * cmd)
2684 u8 *dns_reply_data = 0;
2688 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2690 if (unformat (input, "verbose %d", &verbose))
2692 else if (unformat (input, "verbose"))
2694 else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2697 return clib_error_return (0, "unknown input `%U'",
2698 format_unformat_error, input);
2702 return clib_error_return (0, "dns data not set...");
2704 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2706 vec_free (dns_reply_data);
2712 VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2714 .path = "test dns unformat",
2715 .short_help = "test dns unformat <name> [ip4][ip6]",
2716 .function = test_dns_unfmt_command_fn,
2720 static clib_error_t *
2721 test_dns_expire_command_fn (vlib_main_t * vm,
2722 unformat_input_t * input,
2723 vlib_cli_command_t * cmd)
2725 dns_main_t *dm = &dns_main;
2729 dns_cache_entry_t *ep;
2731 if (unformat (input, "%v", &name))
2734 _vec_len (name) -= 1;
2737 return clib_error_return (0, "no name provided");
2739 dns_cache_lock (dm);
2741 p = hash_get_mem (dm->cache_entry_by_name, name);
2744 dns_cache_unlock (dm);
2745 e = clib_error_return (0, "%s is not in the cache...", name);
2750 ep = pool_elt_at_index (dm->entries, p[0]);
2752 ep->expiration_time = 0;
2758 VLIB_CLI_COMMAND (test_dns_expire_command) =
2760 .path = "test dns expire",
2761 .short_help = "test dns expire <name>",
2762 .function = test_dns_expire_command_fn,
2768 vnet_send_dns6_reply (dns_main_t * dm, dns_pending_request_t * pr,
2769 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2771 clib_warning ("Unimplemented...");
2776 vnet_send_dns4_reply (dns_main_t * dm, dns_pending_request_t * pr,
2777 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2779 vlib_main_t *vm = dm->vlib_main;
2781 fib_prefix_t prefix;
2782 fib_node_index_t fei;
2783 u32 sw_if_index, fib_index;
2784 ip4_main_t *im4 = &ip4_main;
2785 ip_lookup_main_t *lm4 = &im4->lookup_main;
2786 ip_interface_address_t *ia = 0;
2787 ip4_address_t *src_address;
2795 vl_api_dns_resolve_name_reply_t _rnr, *rnr = &_rnr;
2796 vl_api_dns_resolve_ip_reply_t _rir, *rir = &_rir;
2803 int is_recycle = (b0 != 0);
2805 ASSERT (ep && ep->dns_response);
2807 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2809 /* Quick and dirty way to dig up the A-record address. $$ FIXME */
2810 clib_memset (rnr, 0, sizeof (*rnr));
2811 if (vnet_dns_response_to_reply (ep->dns_response, rnr, &ttl))
2813 /* clib_warning ("response_to_reply failed..."); */
2816 if (rnr->ip4_set == 0)
2818 /* clib_warning ("No A-record..."); */
2822 else if (pr->request_type == DNS_PEER_PENDING_IP_TO_NAME)
2824 clib_memset (rir, 0, sizeof (*rir));
2825 if (vnet_dns_response_to_name (ep->dns_response, rir, &ttl))
2827 /* clib_warning ("response_to_name failed..."); */
2833 clib_warning ("Unknown request type %d", pr->request_type);
2837 /* Initialize a buffer */
2840 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2842 b0 = vlib_get_buffer (vm, bi);
2846 /* Use the buffer we were handed. Reinitialize it... */
2847 vlib_buffer_t bt = { };
2848 /* push/pop the reference count */
2849 u8 save_ref_count = b0->ref_count;
2850 vlib_buffer_copy_template (b0, &bt);
2851 b0->ref_count = save_ref_count;
2852 bi = vlib_get_buffer_index (vm, b0);
2855 if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
2856 vlib_buffer_free_one (vm, b0->next_buffer);
2859 * Reset the buffer. We recycle the DNS request packet in the cache
2860 * hit case, and reply immediately from the request node.
2862 * In the resolution-required / deferred case, resetting a freshly-allocated
2863 * buffer won't hurt. We hope.
2865 b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
2866 | VLIB_BUFFER_TOTAL_LENGTH_VALID);
2867 vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; /* "local0" */
2868 vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
2870 /* Find a FIB path to the peer we're trying to answer */
2871 clib_memcpy (&prefix.fp_addr.ip4, pr->dst_address, sizeof (ip4_address_t));
2872 prefix.fp_proto = FIB_PROTOCOL_IP4;
2875 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
2876 if (fib_index == (u32) ~ 0)
2878 clib_warning ("no fib table");
2882 fei = fib_table_lookup (fib_index, &prefix);
2884 /* Couldn't find route to destination. Bail out. */
2885 if (fei == FIB_NODE_INDEX_INVALID)
2887 clib_warning ("no route to DNS server");
2891 sw_if_index = fib_entry_get_resolving_interface (fei);
2893 if (sw_if_index == ~0)
2896 ("route to %U exists, fei %d, get_resolving_interface returned"
2897 " ~0", fei, format_ip4_address, &prefix.fp_addr);
2902 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnumbered */,
2904 src_address = ip_interface_address_get_address (lm4, ia);
2905 goto found_src_address;
2909 clib_warning ("FIB BUG");
2914 ip = vlib_buffer_get_current (b0);
2915 udp = (udp_header_t *) (ip + 1);
2916 dns_response = (u8 *) (udp + 1);
2917 clib_memset (ip, 0, sizeof (*ip) + sizeof (*udp));
2920 * Start with the variadic portion of the exercise.
2921 * Turn the name into a set of DNS "labels". Max length
2922 * per label is 63, enforce that.
2924 reply = name_to_labels (pr->name);
2925 vec_free (pr->name);
2927 qp_offset = vec_len (reply);
2929 /* Add space for the query header */
2930 vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
2932 qp = (dns_query_t *) (reply + qp_offset);
2934 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2935 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
2937 qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2939 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
2941 /* Punch in space for the dns_header_t */
2942 vec_insert (reply, sizeof (dns_header_t), 0);
2944 dh = (dns_header_t *) reply;
2946 /* Transaction ID = pool index */
2949 /* Announce that we did a recursive lookup */
2950 tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
2952 tmp |= DNS_RCODE_NAME_ERROR;
2953 dh->flags = clib_host_to_net_u16 (tmp);
2954 dh->qdcount = clib_host_to_net_u16 (1);
2955 dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
2959 /* If the name resolution worked, cough up an appropriate RR */
2962 /* Add the answer. First, a name pointer (0xC00C) */
2963 vec_add1 (reply, 0xC0);
2964 vec_add1 (reply, 0x0C);
2966 /* Now, add single A-rec RR */
2967 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2969 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
2970 rr = (dns_rr_t *) rrptr;
2972 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
2973 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2974 rr->ttl = clib_host_to_net_u32 (ttl);
2975 rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
2976 clib_memcpy (rr->rdata, rnr->ip4_address, sizeof (ip4_address_t));
2980 /* Or a single PTR RR */
2981 u8 *vecname = format (0, "%s", rir->name);
2982 u8 *label_vec = name_to_labels (vecname);
2985 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
2986 rr = (dns_rr_t *) rrptr;
2987 rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2988 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2989 rr->ttl = clib_host_to_net_u32 (ttl);
2990 rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
2991 clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
2992 vec_free (label_vec);
2995 clib_memcpy (dns_response, reply, vec_len (reply));
2997 /* Set the packet length */
2998 b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
3001 ip->ip_version_and_header_length = 0x45;
3002 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
3004 ip->protocol = IP_PROTOCOL_UDP;
3005 ip->src_address.as_u32 = src_address->as_u32;
3006 clib_memcpy (ip->dst_address.as_u8, pr->dst_address,
3007 sizeof (ip4_address_t));
3008 ip->checksum = ip4_header_checksum (ip);
3011 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
3012 udp->dst_port = pr->dst_port;
3013 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
3019 * Ship pkts made out of whole cloth to ip4_lookup
3020 * Caller will ship recycled dns reply packets to ip4_lookup
3022 if (is_recycle == 0)
3024 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
3025 to_next = vlib_frame_vector_args (f);
3028 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
3032 static void *vl_api_dns_enable_disable_t_print
3033 (vl_api_dns_enable_disable_t * mp, void *handle)
3037 s = format (0, "SCRIPT: dns_enable_disable ");
3038 s = format (s, "%s ", mp->enable ? "enable" : "disable");
3043 static void *vl_api_dns_name_server_add_del_t_print
3044 (vl_api_dns_name_server_add_del_t * mp, void *handle)
3048 s = format (0, "SCRIPT: dns_name_server_add_del ");
3050 s = format (s, "%U ", format_ip6_address,
3051 (ip6_address_t *) mp->server_address);
3053 s = format (s, "%U ", format_ip4_address,
3054 (ip4_address_t *) mp->server_address);
3056 if (mp->is_add == 0)
3057 s = format (s, "del ");
3062 static void *vl_api_dns_resolve_name_t_print
3063 (vl_api_dns_resolve_name_t * mp, void *handle)
3067 s = format (0, "SCRIPT: dns_resolve_name ");
3068 s = format (s, "%s ", mp->name);
3072 static void *vl_api_dns_resolve_ip_t_print
3073 (vl_api_dns_resolve_ip_t * mp, void *handle)
3077 s = format (0, "SCRIPT: dns_resolve_ip ");
3079 s = format (s, "%U ", format_ip6_address, mp->address);
3081 s = format (s, "%U ", format_ip4_address, mp->address);
3086 dns_custom_dump_configure (dns_main_t * dm)
3088 #define _(n,f) dm->api_main->msg_print_handlers \
3089 [VL_API_##n + dm->msg_id_base] \
3090 = (void *) vl_api_##f##_t_print;
3091 foreach_dns_plugin_api_msg;
3095 /* Set up the API message handling tables */
3096 static clib_error_t *
3097 dns_plugin_api_hookup (vlib_main_t * vm)
3099 dns_main_t *dmp = &dns_main;
3101 vl_msg_api_set_handlers((VL_API_##N + dmp->msg_id_base), \
3103 vl_api_##n##_t_handler, \
3105 vl_api_##n##_t_endian, \
3106 vl_api_##n##_t_print, \
3107 sizeof(vl_api_##n##_t), 1);
3108 foreach_dns_plugin_api_msg;
3114 static clib_error_t *
3115 dns_init (vlib_main_t * vm)
3117 dns_main_t *dm = &dns_main;
3121 dm->vnet_main = vnet_get_main ();
3122 dm->name_cache_size = 1000;
3123 dm->max_ttl_in_seconds = 86400;
3124 dm->random_seed = 0xDEADDABE;
3125 dm->api_main = &api_main;
3127 name = format (0, "dns_%08x%c", api_version, 0);
3129 /* Ask for a correctly-sized block of API message decode slots */
3130 dm->msg_id_base = vl_msg_api_get_msg_ids
3131 ((char *) name, VL_MSG_FIRST_AVAILABLE);
3133 (void) dns_plugin_api_hookup (vm);
3135 /* Add our API messages to the global name_crc hash table */
3136 setup_message_id_table (dm);
3138 dns_custom_dump_configure (dm);
3145 VLIB_INIT_FUNCTION (dns_init);
3148 VLIB_PLUGIN_REGISTER () =
3150 .version = VPP_BUILD_VER,
3151 .description = "Simple DNS name resolver",
3157 * fd.io coding-style-patch-verification: ON
3160 * eval: (c-set-style "gnu")