2 * Copyright (c) 2017 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 #include <vnet/vnet.h>
17 #include <vnet/udp/udp_local.h>
18 #include <vnet/plugin/plugin.h>
19 #include <vnet/fib/fib_table.h>
22 #include <vlibapi/api.h>
23 #include <vlibmemory/api.h>
24 #include <vpp/app/version.h>
27 /* define message IDs */
28 #include <dns/dns.api_enum.h>
29 #include <dns/dns.api_types.h>
31 #define REPLY_MSG_ID_BASE dm->msg_id_base
32 #include <vlibapi/api_helper_macros.h>
34 /* Macro to finish up custom dump fns */
35 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
38 vl_print (handle, (char *)s); \
45 dns_cache_clear (dns_main_t * dm)
47 dns_cache_entry_t *ep;
49 if (dm->is_enabled == 0)
50 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
52 dns_cache_lock (dm, 1);
55 pool_foreach (ep, dm->entries,
58 vec_free (ep->pending_requests);
62 pool_free (dm->entries);
63 hash_free (dm->cache_entry_by_name);
64 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
65 vec_free (dm->unresolved_entries);
66 dns_cache_unlock (dm);
71 dns_enable_disable (dns_main_t * dm, int is_enable)
73 vlib_thread_main_t *tm = &vlib_thread_main;
74 u32 n_vlib_mains = tm->n_vlib_mains;
75 vlib_main_t *vm = dm->vlib_main;
77 /* Create the resolver process if not done already */
78 vnet_dns_create_resolver_process (dm);
82 if (vec_len (dm->ip4_name_servers) == 0
83 && (vec_len (dm->ip6_name_servers) == 0))
84 return VNET_API_ERROR_NO_NAME_SERVERS;
86 if (dm->udp_ports_registered == 0)
88 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply,
89 dns46_reply_node.index, 1 /* is_ip4 */ );
91 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply6,
92 dns46_reply_node.index, 0 /* is_ip4 */ );
94 udp_register_dst_port (vm, UDP_DST_PORT_dns,
95 dns4_request_node.index, 1 /* is_ip4 */ );
97 udp_register_dst_port (vm, UDP_DST_PORT_dns6,
98 dns6_request_node.index, 0 /* is_ip4 */ );
100 dm->udp_ports_registered = 1;
103 if (dm->cache_entry_by_name == 0)
105 if (n_vlib_mains > 1)
106 clib_spinlock_init (&dm->cache_lock);
108 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
115 dns_cache_clear (dm);
121 static void vl_api_dns_enable_disable_t_handler
122 (vl_api_dns_enable_disable_t * mp)
124 vl_api_dns_enable_disable_reply_t *rmp;
125 dns_main_t *dm = &dns_main;
128 rv = dns_enable_disable (dm, mp->enable);
130 REPLY_MACRO (VL_API_DNS_ENABLE_DISABLE_REPLY);
134 dns6_name_server_add_del (dns_main_t * dm,
135 u8 * server_address_as_u8, int is_add)
142 /* Already there? done... */
143 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
145 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
146 sizeof (ip6_address_t)))
150 vec_add2 (dm->ip6_name_servers, ap, 1);
151 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
155 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
157 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
158 sizeof (ip6_address_t)))
160 vec_delete (dm->ip6_name_servers, 1, i);
164 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
170 dns4_name_server_add_del (dns_main_t * dm,
171 u8 * server_address_as_u8, int is_add)
178 /* Already there? done... */
179 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
181 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
182 sizeof (ip4_address_t)))
186 vec_add2 (dm->ip4_name_servers, ap, 1);
187 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
191 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
193 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
194 sizeof (ip4_address_t)))
196 vec_delete (dm->ip4_name_servers, 1, i);
200 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
205 static void vl_api_dns_name_server_add_del_t_handler
206 (vl_api_dns_name_server_add_del_t * mp)
208 dns_main_t *dm = &dns_main;
209 vl_api_dns_name_server_add_del_reply_t *rmp;
213 rv = dns6_name_server_add_del (dm, mp->server_address, mp->is_add);
215 rv = dns4_name_server_add_del (dm, mp->server_address, mp->is_add);
217 REPLY_MACRO (VL_API_DNS_NAME_SERVER_ADD_DEL_REPLY);
221 vnet_dns_send_dns4_request (dns_main_t * dm,
222 dns_cache_entry_t * ep, ip4_address_t * server)
224 vlib_main_t *vm = dm->vlib_main;
225 f64 now = vlib_time_now (vm);
230 fib_node_index_t fei;
231 u32 sw_if_index, fib_index;
233 ip4_main_t *im4 = &ip4_main;
234 ip_lookup_main_t *lm4 = &im4->lookup_main;
235 ip_interface_address_t *ia = 0;
236 ip4_address_t *src_address;
241 ASSERT (ep->dns_request);
243 /* Find a FIB path to the server */
244 clib_memcpy (&prefix.fp_addr.ip4, server, sizeof (*server));
245 prefix.fp_proto = FIB_PROTOCOL_IP4;
248 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
249 if (fib_index == (u32) ~ 0)
252 clib_warning ("no fib table");
256 fei = fib_table_lookup (fib_index, &prefix);
258 /* Couldn't find route to destination. Bail out. */
259 if (fei == FIB_NODE_INDEX_INVALID)
262 clib_warning ("no route to DNS server");
266 sw_if_index = fib_entry_get_resolving_interface (fei);
268 if (sw_if_index == ~0)
272 ("route to %U exists, fei %d, get_resolving_interface returned"
273 " ~0", format_ip4_address, &prefix.fp_addr, fei);
278 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnumbered */,
280 src_address = ip_interface_address_get_address (lm4, ia);
281 goto found_src_address;
285 clib_warning ("FIB BUG");
290 /* Go get a buffer */
291 if (vlib_buffer_alloc (dm->vlib_main, &bi, 1) != 1)
294 b = vlib_get_buffer (vm, bi);
295 b->current_length = sizeof (ip4_header_t) + sizeof (udp_header_t) +
296 vec_len (ep->dns_request);
297 b->total_length_not_including_first_buffer = 0;
299 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
300 vnet_buffer (b)->sw_if_index[VLIB_RX] = 0; /* "local0" */
301 vnet_buffer (b)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
303 ip = vlib_buffer_get_current (b);
304 clib_memset (ip, 0, sizeof (*ip));
305 udp = (udp_header_t *) (ip + 1);
306 clib_memset (udp, 0, sizeof (*udp));
308 dns_request = (u8 *) (udp + 1);
311 ip->ip_version_and_header_length = 0x45;
312 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b));
314 ip->protocol = IP_PROTOCOL_UDP;
315 ip->src_address.as_u32 = src_address->as_u32;
316 ip->dst_address.as_u32 = server->as_u32;
317 ip->checksum = ip4_header_checksum (ip);
320 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
321 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
322 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
323 vec_len (ep->dns_request));
326 /* The actual DNS request */
327 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
329 /* Ship it to ip4_lookup */
330 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
331 to_next = vlib_frame_vector_args (f);
334 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
336 ep->retry_timer = now + 2.0;
340 vnet_dns_send_dns6_request (dns_main_t * dm,
341 dns_cache_entry_t * ep, ip6_address_t * server)
343 vlib_main_t *vm = dm->vlib_main;
344 f64 now = vlib_time_now (vm);
349 fib_node_index_t fei;
350 u32 sw_if_index, fib_index;
352 ip6_main_t *im6 = &ip6_main;
353 ip_lookup_main_t *lm6 = &im6->lookup_main;
354 ip_interface_address_t *ia = 0;
355 ip6_address_t *src_address;
359 int junk __attribute__ ((unused));
361 ASSERT (ep->dns_request);
363 /* Find a FIB path to the server */
364 clib_memcpy (&prefix.fp_addr, server, sizeof (*server));
365 prefix.fp_proto = FIB_PROTOCOL_IP6;
368 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
369 if (fib_index == (u32) ~ 0)
372 clib_warning ("no fib table");
376 fei = fib_table_lookup (fib_index, &prefix);
378 /* Couldn't find route to destination. Bail out. */
379 if (fei == FIB_NODE_INDEX_INVALID)
381 clib_warning ("no route to DNS server");
384 sw_if_index = fib_entry_get_resolving_interface (fei);
387 foreach_ip_interface_address(lm6, ia, sw_if_index, 1 /* honor unnumbered */,
389 src_address = ip_interface_address_get_address (lm6, ia);
390 goto found_src_address;
394 clib_warning ("FIB BUG");
399 /* Go get a buffer */
400 if (vlib_buffer_alloc (dm->vlib_main, &bi, 1) != 1)
403 b = vlib_get_buffer (vm, bi);
404 b->current_length = sizeof (ip6_header_t) + sizeof (udp_header_t) +
405 vec_len (ep->dns_request);
406 b->total_length_not_including_first_buffer = 0;
408 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
410 ip = vlib_buffer_get_current (b);
411 clib_memset (ip, 0, sizeof (*ip));
412 udp = (udp_header_t *) (ip + 1);
413 clib_memset (udp, 0, sizeof (*udp));
415 dns_request = (u8 *) (udp + 1);
418 ip->ip_version_traffic_class_and_flow_label =
419 clib_host_to_net_u32 (0x6 << 28);
422 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b)
423 - sizeof (ip6_header_t));
425 ip->protocol = IP_PROTOCOL_UDP;
426 clib_memcpy (&ip->src_address, src_address, sizeof (ip6_address_t));
427 clib_memcpy (&ip->dst_address, server, sizeof (ip6_address_t));
430 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
431 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
432 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
433 vec_len (ep->dns_request));
435 udp->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ip, &junk);
437 /* The actual DNS request */
438 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
440 /* Ship it to ip6_lookup */
441 f = vlib_get_frame_to_node (vm, ip6_lookup_node.index);
442 to_next = vlib_frame_vector_args (f);
446 ep->retry_timer = now + 2.0;
450 * Translate "foo.com" into "0x3 f o o 0x3 c o m 0x0"
451 * A historical / hysterical micro-TLV scheme. DGMS.
454 name_to_labels (u8 * name)
457 int last_label_index;
462 /* punch in space for the first length */
463 vec_insert (rv, 1, 0);
464 last_label_index = 0;
467 while (i < vec_len (rv))
471 rv[last_label_index] = (i - last_label_index) - 1;
472 if ((i - last_label_index) > 63)
473 clib_warning ("stupid name, label length %d",
474 i - last_label_index);
475 last_label_index = i;
480 /* Set the last real label length */
481 rv[last_label_index] = (i - last_label_index) - 1;
484 * Add a [sic] NULL root label. Otherwise, the name parser can't figure out
492 * arc-function for the above.
493 * Translate "0x3 f o o 0x3 c o m 0x0" into "foo.com"
494 * Produces a non-NULL-terminated u8 *vector. %v format is your friend.
497 vnet_dns_labels_to_name (u8 * label, u8 * full_text, u8 ** parse_from_here)
504 *parse_from_here = 0;
506 /* chase initial pointer? */
507 if ((label[0] & 0xC0) == 0xC0)
509 *parse_from_here = label + 2;
510 offset = ((label[0] & 0x3f) << 8) + label[1];
511 label = full_text + offset;
518 for (i = 0; i < len; i++)
519 vec_add1 (reply, *label++);
522 if ((label[0] & 0xC0) == 0xC0)
524 *parse_from_here = label + 2;
525 offset = ((label[0] & 0x3f) << 8) + label[1];
526 label = full_text + offset;
531 vec_add1 (reply, '.');
533 if (*parse_from_here == 0)
534 *parse_from_here = label;
539 vnet_send_dns_request (dns_main_t * dm, dns_cache_entry_t * ep)
544 u8 *request, *name_copy;
547 /* This can easily happen if sitting in GDB, etc. */
548 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID || ep->server_fails > 1)
551 /* Construct the dns request, if we haven't been here already */
552 if (vec_len (ep->dns_request) == 0)
555 * Start with the variadic portion of the exercise.
556 * Turn the name into a set of DNS "labels". Max length
557 * per label is 63, enforce that.
559 request = name_to_labels (ep->name);
560 name_copy = vec_dup (request);
561 qp_offset = vec_len (request);
564 * At least when testing against "known good" DNS servers:
565 * it turns out that sending 2x requests - one for an A-record
566 * and another for a AAAA-record - seems to work better than
567 * sending a DNS_TYPE_ALL request.
570 /* Add space for the query header */
571 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
573 qp = (dns_query_t *) (request + qp_offset);
575 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
576 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
578 clib_memcpy (qp, name_copy, vec_len (name_copy));
579 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
580 vec_free (name_copy);
582 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
583 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
585 /* Punch in space for the dns_header_t */
586 vec_insert (request, sizeof (dns_header_t), 0);
588 h = (dns_header_t *) request;
590 /* Transaction ID = pool index */
591 h->id = clib_host_to_net_u16 (ep - dm->entries);
593 /* Ask for a recursive lookup */
594 tmp = DNS_RD | DNS_OPCODE_QUERY;
595 h->flags = clib_host_to_net_u16 (tmp);
596 h->qdcount = clib_host_to_net_u16 (2);
600 ep->dns_request = request;
603 /* Work out which server / address family we're going to use */
605 /* Retry using current server */
606 if (ep->retry_count++ < DNS_RETRIES_PER_SERVER)
608 if (ep->server_af == 1 /* ip6 */ )
610 if (vec_len (dm->ip6_name_servers))
612 vnet_dns_send_dns6_request
613 (dm, ep, dm->ip6_name_servers + ep->server_rotor);
619 if (vec_len (dm->ip4_name_servers))
621 vnet_dns_send_dns4_request
622 (dm, ep, dm->ip4_name_servers + ep->server_rotor);
626 else /* switch to a new server */
630 if (ep->server_af == 1 /* ip6 */ )
632 if (ep->server_rotor >= vec_len (dm->ip6_name_servers))
634 ep->server_rotor = 0;
635 ep->server_af = vec_len (dm->ip4_name_servers) > 0 ? 0 : 1;
640 if (ep->server_rotor >= vec_len (dm->ip4_name_servers))
642 ep->server_rotor = 0;
643 ep->server_af = vec_len (dm->ip6_name_servers) > 0 ? 1 : 0;
648 if (ep->server_af == 1 /* ip6 */ )
649 vnet_dns_send_dns6_request
650 (dm, ep, dm->ip6_name_servers + ep->server_rotor);
652 vnet_dns_send_dns4_request
653 (dm, ep, dm->ip4_name_servers + ep->server_rotor);
657 vlib_process_signal_event_mt (dm->vlib_main,
658 dm->resolver_process_node_index,
659 DNS_RESOLVER_EVENT_PENDING, 0);
663 vnet_dns_delete_entry_by_index_nolock (dns_main_t * dm, u32 index)
665 dns_cache_entry_t *ep;
668 if (dm->is_enabled == 0)
669 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
671 if (pool_is_free_index (dm->entries, index))
672 return VNET_API_ERROR_NO_SUCH_ENTRY;
674 ep = pool_elt_at_index (dm->entries, index);
675 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_VALID))
677 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
678 if (index == dm->unresolved_entries[i])
680 vec_delete (dm->unresolved_entries, 1, i);
683 clib_warning ("pool elt %d supposedly pending, but not found...",
688 hash_unset_mem (dm->cache_entry_by_name, ep->name);
690 vec_free (ep->pending_requests);
691 pool_put (dm->entries, ep);
697 dns_delete_by_name (dns_main_t * dm, u8 * name)
702 if (dm->is_enabled == 0)
703 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
705 dns_cache_lock (dm, 2);
706 p = hash_get_mem (dm->cache_entry_by_name, name);
709 dns_cache_unlock (dm);
710 return VNET_API_ERROR_NO_SUCH_ENTRY;
712 rv = vnet_dns_delete_entry_by_index_nolock (dm, p[0]);
714 dns_cache_unlock (dm);
720 delete_random_entry (dns_main_t * dm)
723 u32 victim_index, start_index, i;
725 dns_cache_entry_t *ep;
727 if (dm->is_enabled == 0)
728 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
731 * Silence spurious coverity warning. We know pool_elts >> 0, or
732 * we wouldn't be here...
735 if (pool_elts (dm->entries) == 0)
736 return VNET_API_ERROR_UNSPECIFIED;
739 dns_cache_lock (dm, 3);
740 limit = pool_elts (dm->entries);
741 start_index = random_u32 (&dm->random_seed) % limit;
743 for (i = 0; i < limit; i++)
745 victim_index = (start_index + i) % limit;
747 if (!pool_is_free_index (dm->entries, victim_index))
749 ep = pool_elt_at_index (dm->entries, victim_index);
750 /* Delete only valid, non-static entries */
751 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
752 && ((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0))
754 rv = vnet_dns_delete_entry_by_index_nolock (dm, victim_index);
755 dns_cache_unlock (dm);
760 dns_cache_unlock (dm);
762 clib_warning ("Couldn't find an entry to delete?");
763 return VNET_API_ERROR_UNSPECIFIED;
767 dns_add_static_entry (dns_main_t * dm, u8 * name, u8 * dns_reply_data)
769 dns_cache_entry_t *ep;
773 if (dm->is_enabled == 0)
774 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
776 dns_cache_lock (dm, 4);
777 p = hash_get_mem (dm->cache_entry_by_name, name);
780 dns_cache_unlock (dm);
781 return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
784 if (pool_elts (dm->entries) == dm->name_cache_size)
786 /* Will only fail if the cache is totally filled w/ static entries... */
787 rv = delete_random_entry (dm);
790 dns_cache_unlock (dm);
795 pool_get (dm->entries, ep);
796 clib_memset (ep, 0, sizeof (*ep));
798 /* Note: consumes the name vector */
800 /* make sure it NULL-terminated as hash_set_mem will use strlen() */
801 vec_terminate_c_string (ep->name);
802 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
803 ep->flags = DNS_CACHE_ENTRY_FLAG_VALID | DNS_CACHE_ENTRY_FLAG_STATIC;
804 ep->dns_response = dns_reply_data;
806 dns_cache_unlock (dm);
811 vnet_dns_resolve_name (dns_main_t * dm, u8 * name, dns_pending_request_t * t,
812 dns_cache_entry_t ** retp)
814 dns_cache_entry_t *ep;
818 dns_pending_request_t *pr;
821 now = vlib_time_now (dm->vlib_main);
823 /* In case we can't actually answer the question right now... */
826 /* binary API caller might forget to set the name. Guess how we know. */
828 return VNET_API_ERROR_INVALID_VALUE;
830 dns_cache_lock (dm, 5);
832 p = hash_get_mem (dm->cache_entry_by_name, name);
835 ep = pool_elt_at_index (dm->entries, p[0]);
836 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
838 /* Has the entry expired? */
839 if (((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0)
840 && (now > ep->expiration_time))
843 u32 *indices_to_delete = 0;
846 * Take out the rest of the resolution chain
847 * This isn't optimal, but it won't happen very often.
851 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME))
853 vec_add1 (indices_to_delete, ep - dm->entries);
855 p = hash_get_mem (dm->cache_entry_by_name, ep->cname);
858 ep = pool_elt_at_index (dm->entries, p[0]);
862 vec_add1 (indices_to_delete, ep - dm->entries);
866 for (i = 0; i < vec_len (indices_to_delete); i++)
868 /* Reenable to watch re-resolutions */
871 ep = pool_elt_at_index (dm->entries,
872 indices_to_delete[i]);
873 clib_warning ("Re-resolve %s", ep->name);
876 vnet_dns_delete_entry_by_index_nolock
877 (dm, indices_to_delete[i]);
879 vec_free (indices_to_delete);
880 /* Yes, kill it... */
884 if (ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
890 dns_cache_unlock (dm);
896 * Resolution pending. Add request to the pending vector
897 * by copying the template request
899 vec_add2 (ep->pending_requests, pr, 1);
900 memcpy (pr, t, sizeof (*pr));
901 dns_cache_unlock (dm);
907 if (pool_elts (dm->entries) == dm->name_cache_size)
909 /* Will only fail if the cache is totally filled w/ static entries... */
910 rv = delete_random_entry (dm);
913 dns_cache_unlock (dm);
918 /* add new hash table entry */
919 pool_get (dm->entries, ep);
920 clib_memset (ep, 0, sizeof (*ep));
922 ep->name = format (0, "%s%c", name, 0);
923 _vec_len (ep->name) = vec_len (ep->name) - 1;
925 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
927 vec_add1 (dm->unresolved_entries, ep - dm->entries);
928 vec_add2 (ep->pending_requests, pr, 1);
930 pr->request_type = t->request_type;
932 /* Remember details so we can reply later... */
933 if (t->request_type == DNS_API_PENDING_NAME_TO_IP ||
934 t->request_type == DNS_API_PENDING_IP_TO_NAME)
936 pr->client_index = t->client_index;
937 pr->client_context = t->client_context;
941 pr->client_index = ~0;
942 pr->is_ip6 = t->is_ip6;
943 pr->dst_port = t->dst_port;
950 clib_memcpy (pr->dst_address, t->dst_address, count);
953 vnet_send_dns_request (dm, ep);
954 dns_cache_unlock (dm);
958 #define foreach_notification_to_move \
962 * Handle cname indirection. JFC. Called with the cache locked.
963 * returns 0 if the reply is not a CNAME.
967 vnet_dns_cname_indirection_nolock (dns_main_t * dm, u32 ep_index, u8 * reply)
982 dns_cache_entry_t *ep, *next_ep;
985 h = (dns_header_t *) reply;
986 flags = clib_net_to_host_u16 (h->flags);
987 rcode = flags & DNS_RCODE_MASK;
989 /* See if the response is OK */
992 case DNS_RCODE_NO_ERROR:
995 case DNS_RCODE_NAME_ERROR:
996 case DNS_RCODE_FORMAT_ERROR:
997 case DNS_RCODE_SERVER_FAILURE:
998 case DNS_RCODE_NOT_IMPLEMENTED:
999 case DNS_RCODE_REFUSED:
1003 curpos = (u8 *) (h + 1);
1007 /* Skip the questions */
1008 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
1015 pos += sizeof (dns_query_t);
1018 /* expect a pointer chase here for a CNAME record */
1019 if ((pos2[0] & 0xC0) == 0xC0)
1024 /* Walk the answer(s) to see what to do next */
1025 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
1027 rr = (dns_rr_t *) pos;
1028 switch (clib_net_to_host_u16 (rr->type))
1030 /* Real address record? Done.. */
1035 * Maybe chase a CNAME pointer?
1036 * It's not unheard-of for name-servers to return
1037 * both CNAME and A/AAAA records...
1039 case DNS_TYPE_CNAME:
1043 /* Some other junk, e.g. a nameserver... */
1047 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1049 if ((pos2[0] & 0xc0) == 0xc0)
1053 /* Neither a CNAME nor a real address. Try another server */
1056 flags &= ~DNS_RCODE_MASK;
1057 flags |= DNS_RCODE_NAME_ERROR;
1058 h->flags = clib_host_to_net_u16 (flags);
1062 /* This is a CNAME record, chase the name chain. */
1065 /* The last request is no longer pending.. */
1066 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
1067 if (ep_index == dm->unresolved_entries[i])
1069 vec_delete (dm->unresolved_entries, 1, i);
1070 goto found_last_request;
1072 clib_warning ("pool elt %d supposedly pending, but not found...", ep_index);
1077 now = vlib_time_now (dm->vlib_main);
1078 cname = vnet_dns_labels_to_name (rr->rdata, reply, &pos2);
1079 /* Save the cname */
1080 vec_add1 (cname, 0);
1081 _vec_len (cname) -= 1;
1082 ep = pool_elt_at_index (dm->entries, ep_index);
1084 ep->flags |= (DNS_CACHE_ENTRY_FLAG_CNAME | DNS_CACHE_ENTRY_FLAG_VALID);
1085 /* Save the response */
1086 if (ep->dns_response)
1087 vec_free (ep->dns_response);
1088 ep->dns_response = reply;
1089 /* Set up expiration time */
1090 ep->expiration_time = now + clib_net_to_host_u32 (rr->ttl);
1092 pool_get (dm->entries, next_ep);
1094 /* Need to recompute ep post pool-get */
1095 ep = pool_elt_at_index (dm->entries, ep_index);
1097 clib_memset (next_ep, 0, sizeof (*next_ep));
1098 next_ep->name = vec_dup (cname);
1099 vec_add1 (next_ep->name, 0);
1100 _vec_len (next_ep->name) -= 1;
1102 hash_set_mem (dm->cache_entry_by_name, next_ep->name,
1103 next_ep - dm->entries);
1105 /* Use the same server */
1106 next_ep->server_rotor = ep->server_rotor;
1107 next_ep->server_af = ep->server_af;
1109 /* Move notification data to the next name in the chain */
1110 #define _(a) next_ep->a = ep->a; ep->a = 0;
1111 foreach_notification_to_move;
1114 request = name_to_labels (cname);
1115 name_copy = vec_dup (request);
1117 qp_offset = vec_len (request);
1119 /* Add space for the query header */
1120 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
1122 qp = (dns_query_t *) (request + qp_offset);
1124 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
1125 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1126 clib_memcpy (qp, name_copy, vec_len (name_copy));
1127 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
1128 vec_free (name_copy);
1130 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1131 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1133 /* Punch in space for the dns_header_t */
1134 vec_insert (request, sizeof (dns_header_t), 0);
1136 h = (dns_header_t *) request;
1138 /* Transaction ID = pool index */
1139 h->id = clib_host_to_net_u16 (next_ep - dm->entries);
1141 /* Ask for a recursive lookup */
1142 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
1143 h->qdcount = clib_host_to_net_u16 (2);
1147 next_ep->dns_request = request;
1148 next_ep->retry_timer = now + 2.0;
1149 next_ep->retry_count = 0;
1152 * Enable this to watch recursive resolution happen...
1153 * fformat (stdout, "%U", format_dns_reply, request, 2);
1156 vec_add1 (dm->unresolved_entries, next_ep - dm->entries);
1157 vnet_send_dns_request (dm, next_ep);
1162 vnet_dns_response_to_reply (u8 * response,
1163 vl_api_dns_resolve_name_reply_t * rmp,
1171 u8 *curpos, *pos, *pos2;
1177 h = (dns_header_t *) response;
1178 flags = clib_net_to_host_u16 (h->flags);
1179 rcode = flags & DNS_RCODE_MASK;
1181 /* See if the response is OK, etc. */
1185 case DNS_RCODE_NO_ERROR:
1188 case DNS_RCODE_NAME_ERROR:
1189 case DNS_RCODE_FORMAT_ERROR:
1190 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1192 case DNS_RCODE_SERVER_FAILURE:
1193 case DNS_RCODE_NOT_IMPLEMENTED:
1194 case DNS_RCODE_REFUSED:
1195 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1198 /* No answers? Loser... */
1199 if (clib_net_to_host_u16 (h->anscount) < 1)
1200 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1202 curpos = (u8 *) (h + 1);
1204 /* Skip the name we asked about */
1207 /* Should never happen, but stil... */
1208 if ((len & 0xC0) == 0xC0)
1212 /* skip the name / label-set */
1221 limit = clib_net_to_host_u16 (h->qdcount);
1222 qp = (dns_query_t *) curpos;
1227 limit = clib_net_to_host_u16 (h->anscount);
1229 for (i = 0; i < limit; i++)
1231 pos = pos2 = curpos;
1234 /* Expect pointer chases in the answer section... */
1235 if ((pos2[0] & 0xC0) == 0xC0)
1238 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1247 if ((pos2[0] & 0xc0) == 0xc0)
1250 * If we've already done one pointer chase,
1251 * do not move the pos pointer.
1253 if (pointer_chase == 0)
1255 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1263 if (pointer_chase == 0)
1266 rr = (dns_rr_t *) pos;
1268 switch (clib_net_to_host_u16 (rr->type))
1271 /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1272 memcpy (rmp->ip4_address, rr->rdata, sizeof (ip4_address_t));
1274 ttl = clib_net_to_host_u32 (rr->ttl);
1275 if (min_ttlp && *min_ttlp > ttl)
1279 /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1280 memcpy (rmp->ip6_address, rr->rdata, sizeof (ip6_address_t));
1281 ttl = clib_net_to_host_u32 (rr->ttl);
1282 if (min_ttlp && *min_ttlp > ttl)
1290 /* Might as well stop ASAP */
1291 if (rmp->ip4_set && rmp->ip6_set)
1293 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1297 if ((rmp->ip4_set + rmp->ip6_set) == 0)
1298 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1303 vnet_dns_response_to_name (u8 * response,
1304 vl_api_dns_resolve_ip_reply_t * rmp,
1312 u8 *curpos, *pos, *pos2;
1317 u8 *junk __attribute__ ((unused));
1321 h = (dns_header_t *) response;
1322 flags = clib_net_to_host_u16 (h->flags);
1323 rcode = flags & DNS_RCODE_MASK;
1325 /* See if the response is OK, etc. */
1329 case DNS_RCODE_NO_ERROR:
1332 case DNS_RCODE_NAME_ERROR:
1333 case DNS_RCODE_FORMAT_ERROR:
1334 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1336 case DNS_RCODE_SERVER_FAILURE:
1337 case DNS_RCODE_NOT_IMPLEMENTED:
1338 case DNS_RCODE_REFUSED:
1339 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1342 /* No answers? Loser... */
1343 if (clib_net_to_host_u16 (h->anscount) < 1)
1344 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1346 curpos = (u8 *) (h + 1);
1348 /* Skip the name we asked about */
1351 /* Should never happen, but stil... */
1352 if ((len & 0xC0) == 0xC0)
1356 /* skip the name / label-set */
1365 limit = clib_net_to_host_u16 (h->qdcount);
1366 qp = (dns_query_t *) curpos;
1371 limit = clib_net_to_host_u16 (h->anscount);
1373 for (i = 0; i < limit; i++)
1375 pos = pos2 = curpos;
1378 /* Expect pointer chases in the answer section... */
1379 if ((pos2[0] & 0xC0) == 0xC0)
1382 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1391 if ((pos2[0] & 0xc0) == 0xc0)
1394 * If we've already done one pointer chase,
1395 * do not move the pos pointer.
1397 if (pointer_chase == 0)
1399 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1407 if (pointer_chase == 0)
1410 rr = (dns_rr_t *) pos;
1412 switch (clib_net_to_host_u16 (rr->type))
1415 name = vnet_dns_labels_to_name (rr->rdata, response, &junk);
1416 memcpy (rmp->name, name, vec_len (name));
1417 ttl = clib_net_to_host_u32 (rr->ttl);
1420 rmp->name[vec_len (name)] = 0;
1426 /* Might as well stop ASAP */
1429 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1434 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1439 vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1441 dns_main_t *dm = &dns_main;
1442 vl_api_dns_resolve_name_reply_t *rmp;
1443 dns_cache_entry_t *ep;
1444 dns_pending_request_t _t0, *t0 = &_t0;
1447 /* Sanitize the name slightly */
1448 mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1450 t0->request_type = DNS_API_PENDING_NAME_TO_IP;
1451 t0->client_index = mp->client_index;
1452 t0->client_context = mp->context;
1454 rv = vnet_dns_resolve_name (dm, mp->name, t0, &ep);
1456 /* Error, e.g. not enabled? Tell the user */
1459 REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1463 /* Resolution pending? Don't reply... */
1468 REPLY_MACRO2(VL_API_DNS_RESOLVE_NAME_REPLY,
1470 rv = vnet_dns_response_to_reply (ep->dns_response, rmp, 0 /* ttl-ptr */);
1471 rmp->retval = clib_host_to_net_u32 (rv);
1477 vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
1479 dns_main_t *dm = &dns_main;
1480 vl_api_dns_resolve_ip_reply_t *rmp;
1481 dns_cache_entry_t *ep;
1484 u8 *lookup_name = 0;
1486 dns_pending_request_t _t0, *t0 = &_t0;
1490 for (i = 15; i >= 0; i--)
1492 digit = mp->address[i];
1493 nybble = (digit & 0x0F);
1495 vec_add1 (lookup_name, (nybble - 10) + 'a');
1497 vec_add1 (lookup_name, nybble + '0');
1498 vec_add1 (lookup_name, '.');
1499 nybble = (digit & 0xF0) >> 4;
1501 vec_add1 (lookup_name, (nybble - 10) + 'a');
1503 vec_add1 (lookup_name, nybble + '0');
1504 vec_add1 (lookup_name, '.');
1506 len = vec_len (lookup_name);
1507 vec_validate (lookup_name, len + 8);
1508 memcpy (lookup_name + len, "ip6.arpa", 8);
1512 for (i = 3; i >= 0; i--)
1514 digit = mp->address[i];
1515 lookup_name = format (lookup_name, "%d.", digit);
1517 lookup_name = format (lookup_name, "in-addr.arpa");
1520 vec_add1 (lookup_name, 0);
1522 t0->request_type = DNS_API_PENDING_IP_TO_NAME;
1523 t0->client_index = mp->client_index;
1524 t0->client_context = mp->context;
1526 rv = vnet_dns_resolve_name (dm, lookup_name, t0, &ep);
1528 vec_free (lookup_name);
1530 /* Error, e.g. not enabled? Tell the user */
1533 REPLY_MACRO (VL_API_DNS_RESOLVE_IP_REPLY);
1537 /* Resolution pending? Don't reply... */
1542 REPLY_MACRO2(VL_API_DNS_RESOLVE_IP_REPLY,
1544 rv = vnet_dns_response_to_name (ep->dns_response, rmp, 0 /* ttl-ptr */);
1545 rmp->retval = clib_host_to_net_u32 (rv);
1550 static clib_error_t *
1551 dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1553 dns_main_t *dm = &dns_main;
1555 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1557 if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1559 else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1562 return clib_error_return (0, "unknown input `%U'",
1563 format_unformat_error, input);
1568 VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1571 unformat_dns_reply (unformat_input_t * input, va_list * args)
1573 u8 **result = va_arg (*args, u8 **);
1574 u8 **namep = va_arg (*args, u8 **);
1588 if (unformat (input, "%v", &name))
1591 if (unformat (input, "%U", unformat_ip4_address, &a4))
1594 if (unformat (input, "%U", unformat_ip6_address, &a6))
1598 if (unformat (input, "%U", unformat_ip6_address, &a6))
1601 if (unformat (input, "%U", unformat_ip4_address, &a6))
1605 /* Must have a name */
1609 /* Must have at least one address */
1610 if (!(a4_set + a6_set))
1613 /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1614 ce = name_to_labels (name);
1615 qp_offset = vec_len (ce);
1617 /* Add space for the query header */
1618 vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1619 qp = (dns_query_t *) (ce + qp_offset);
1621 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1622 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1624 /* Punch in space for the dns_header_t */
1625 vec_insert (ce, sizeof (dns_header_t), 0);
1627 h = (dns_header_t *) ce;
1629 /* Fake Transaction ID */
1632 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1633 h->qdcount = clib_host_to_net_u16 (1);
1634 h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1638 /* Now append one or two A/AAAA RR's... */
1641 /* Pointer to the name (DGMS) */
1642 vec_add1 (ce, 0xC0);
1643 vec_add1 (ce, 0x0C);
1644 vec_add2 (ce, rru8, sizeof (*rr) + 4);
1646 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1647 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1648 rr->ttl = clib_host_to_net_u32 (86400);
1649 rr->rdlength = clib_host_to_net_u16 (4);
1650 memcpy (rr->rdata, &a4, sizeof (a4));
1654 /* Pointer to the name (DGMS) */
1655 vec_add1 (ce, 0xC0);
1656 vec_add1 (ce, 0x0C);
1657 vec_add2 (ce, rru8, sizeof (*rr) + 16);
1659 rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1660 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1661 rr->ttl = clib_host_to_net_u32 (86400);
1662 rr->rdlength = clib_host_to_net_u16 (16);
1663 memcpy (rr->rdata, &a6, sizeof (a6));
1675 format_dns_query (u8 * s, va_list * args)
1677 u8 **curpos = va_arg (*args, u8 **);
1678 int verbose = va_arg (*args, int);
1683 s = format (s, " Name: ");
1685 /* Unwind execrated counted-label sheit */
1691 for (i = 0; i < len; i++)
1692 vec_add1 (s, *pos++);
1704 qp = (dns_query_t *) pos;
1707 switch (clib_net_to_host_u16 (qp->type))
1710 s = format (s, "type A\n");
1713 s = format (s, "type AAAA\n");
1716 s = format (s, "type ALL\n");
1720 s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1725 pos += sizeof (*qp);
1732 * format dns reply data
1733 * verbose > 1, dump everything
1734 * verbose == 1, dump all A and AAAA records
1735 * verbose == 0, dump one A record, and one AAAA record
1739 format_dns_reply_data (u8 * s, va_list * args)
1741 u8 *reply = va_arg (*args, u8 *);
1742 u8 **curpos = va_arg (*args, u8 **);
1743 int verbose = va_arg (*args, int);
1744 int *print_ip4 = va_arg (*args, int *);
1745 int *print_ip6 = va_arg (*args, int *);
1750 int pointer_chase = 0;
1752 u16 rrtype_host_byte_order;
1754 pos = pos2 = *curpos;
1757 s = format (s, " ");
1759 /* chase pointer? almost always yes here... */
1760 if ((pos2[0] & 0xc0) == 0xc0)
1763 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1771 for (i = 0; i < len; i++)
1774 vec_add1 (s, *pos2);
1777 if ((pos2[0] & 0xc0) == 0xc0)
1780 * If we've already done one pointer chase,
1781 * do not move the pos pointer.
1783 if (pointer_chase == 0)
1785 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1803 if (pointer_chase == 0)
1806 rr = (dns_rr_t *) pos;
1807 rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
1809 switch (rrtype_host_byte_order)
1814 s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1815 format_ip4_address, rr->rdata);
1820 s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1821 clib_net_to_host_u32 (rr->ttl));
1826 pos += sizeof (*rr) + 4;
1832 s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1833 format_ip6_address, rr->rdata);
1838 s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1839 clib_net_to_host_u32 (rr->ttl));
1843 pos += sizeof (*rr) + 16;
1849 s = format (s, "TEXT: ");
1850 for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1851 vec_add1 (s, rr->rdata[i]);
1854 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1857 case DNS_TYPE_HINFO:
1859 /* Two counted strings. DGMS */
1865 s = format (s, "HINFO: ");
1868 for (i = 0; i < *len; i++)
1869 vec_add1 (s, *curpos++);
1873 for (i = 0; i < *len; i++)
1874 vec_add1 (s, *curpos++);
1879 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1882 case DNS_TYPE_NAMESERVER:
1885 s = format (s, "Nameserver: ");
1888 /* chase pointer? */
1889 if ((pos2[0] & 0xc0) == 0xc0)
1892 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1899 for (i = 0; i < len; i++)
1900 vec_add1 (s, *pos2++);
1902 /* chase pointer, typically to offset 12... */
1903 if (pos2[0] == 0xC0)
1904 pos2 = reply + pos2[1];
1913 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1916 case DNS_TYPE_MAIL_EXCHANGE:
1919 tp = (u16 *) rr->rdata;
1921 s = format (s, "Mail Exchange: Preference %d ", (u32)
1922 clib_net_to_host_u16 (*tp));
1924 pos2 = rr->rdata + 2;
1926 /* chase pointer? */
1927 if (pos2[0] == 0xc0)
1928 pos2 = reply + pos2[1];
1934 for (i = 0; i < len; i++)
1935 vec_add1 (s, *pos2++);
1938 if (pos2[0] == 0xC0)
1939 pos2 = reply + pos2[1];
1949 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1953 case DNS_TYPE_CNAME:
1956 tp = (u16 *) rr->rdata;
1958 if (rrtype_host_byte_order == DNS_TYPE_CNAME)
1959 s = format (s, "CNAME: ");
1961 s = format (s, "PTR: ");
1965 /* chase pointer? */
1966 if (pos2[0] == 0xc0)
1967 pos2 = reply + pos2[1];
1973 for (i = 0; i < len; i++)
1974 vec_add1 (s, *pos2++);
1977 if (pos2[0] == 0xC0)
1978 pos2 = reply + pos2[1];
1987 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1992 s = format (s, "type %d: len %d\n",
1993 (int) clib_net_to_host_u16 (rr->type),
1994 sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
1995 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2005 format_dns_reply (u8 * s, va_list * args)
2007 u8 *reply_as_u8 = va_arg (*args, u8 *);
2008 int verbose = va_arg (*args, int);
2016 h = (dns_header_t *) reply_as_u8;
2017 id = clib_net_to_host_u16 (h->id);
2018 flags = clib_net_to_host_u16 (h->flags);
2022 s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
2024 s = format (s, " %s %s %s %s\n",
2025 (flags & DNS_RA) ? "recur" : "no-recur",
2026 (flags & DNS_RD) ? "recur-des" : "no-recur-des",
2027 (flags & DNS_TC) ? "trunc" : "no-trunc",
2028 (flags & DNS_AA) ? "auth" : "non-auth");
2029 s = format (s, " %d queries, %d answers, %d name-servers,"
2031 clib_net_to_host_u16 (h->qdcount),
2032 clib_net_to_host_u16 (h->anscount),
2033 clib_net_to_host_u16 (h->nscount),
2034 clib_net_to_host_u16 (h->arcount));
2037 curpos = (u8 *) (h + 1);
2042 s = format (s, " Queries:\n");
2043 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
2045 /* The query is variable-length, so curpos is a value-result parm */
2046 s = format (s, "%U", format_dns_query, &curpos, verbose);
2052 s = format (s, " Replies:\n");
2054 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
2056 /* curpos is a value-result parm */
2057 s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
2058 verbose, &print_ip4, &print_ip6);
2065 format_dns_cache (u8 * s, va_list * args)
2067 dns_main_t *dm = va_arg (*args, dns_main_t *);
2068 f64 now = va_arg (*args, f64);
2069 int verbose = va_arg (*args, int);
2070 u8 *name = va_arg (*args, u8 *);
2071 dns_cache_entry_t *ep;
2075 if (dm->is_enabled == 0)
2077 s = format (s, "The DNS cache is disabled...");
2081 if (pool_elts (dm->entries) == 0)
2083 s = format (s, "The DNS cache is empty...");
2087 dns_cache_lock (dm, 6);
2091 p = hash_get_mem (dm->cache_entry_by_name, name);
2094 s = format (s, "%s is not in the cache...", name);
2095 dns_cache_unlock (dm);
2099 ep = pool_elt_at_index (dm->entries, p[0]);
2100 /* Magic to spit out a C-initializer to research hemorrhoids... */
2104 s = format (s, "static u8 dns_reply_data_initializer[] =\n");
2105 s = format (s, "{\n");
2107 for (i = 0; i < vec_len (ep->dns_response); i++)
2114 s = format (s, "0x%02x, ", ep->dns_response[i]);
2116 s = format (s, "};\n");
2120 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2122 ASSERT (ep->dns_response);
2123 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2128 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2129 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2131 s = format (s, "%s%s -> %U", ss, ep->name,
2132 format_dns_reply, ep->dns_response, verbose);
2133 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2135 f64 time_left = ep->expiration_time - now;
2136 if (time_left > 0.0)
2137 s = format (s, " TTL left %.1f", time_left);
2139 s = format (s, " EXPIRED");
2144 ASSERT (ep->dns_request);
2145 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2153 s = format (s, "DNS cache contains %d entries\n", pool_elts (dm->entries));
2158 pool_foreach (ep, dm->entries,
2160 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2162 ASSERT (ep->dns_response);
2163 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2168 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2169 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2171 s = format (s, "%s%s -> %U", ss, ep->name,
2175 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2177 f64 time_left = ep->expiration_time - now;
2178 if (time_left > 0.0)
2179 s = format (s, " TTL left %.1f", time_left);
2181 s = format (s, " EXPIRED");
2184 s = format (s, " %d client notifications pending\n",
2185 vec_len(ep->pending_requests));
2190 ASSERT (ep->dns_request);
2191 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2199 dns_cache_unlock (dm);
2204 static clib_error_t *
2205 show_dns_cache_command_fn (vlib_main_t * vm,
2206 unformat_input_t * input, vlib_cli_command_t * cmd)
2208 dns_main_t *dm = &dns_main;
2211 f64 now = vlib_time_now (vm);
2213 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2215 if (unformat (input, "verbose %d", &verbose))
2217 else if (unformat (input, "verbose"))
2219 else if (unformat (input, "name %s", &name))
2222 return clib_error_return (0, "unknown input `%U'",
2223 format_unformat_error, input);
2226 vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
2232 VLIB_CLI_COMMAND (show_dns_cache_command) =
2234 .path = "show dns cache",
2235 .short_help = "show dns cache [verbose [nn]]",
2236 .function = show_dns_cache_command_fn,
2240 static clib_error_t *
2241 show_dns_servers_command_fn (vlib_main_t * vm,
2242 unformat_input_t * input,
2243 vlib_cli_command_t * cmd)
2245 dns_main_t *dm = &dns_main;
2248 if ((vec_len (dm->ip4_name_servers) + vec_len (dm->ip6_name_servers)) == 0)
2249 return clib_error_return (0, "No name servers configured...");
2251 if (vec_len (dm->ip4_name_servers))
2253 vlib_cli_output (vm, "ip4 name servers:");
2254 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
2255 vlib_cli_output (vm, "%U", format_ip4_address,
2256 dm->ip4_name_servers + i);
2258 if (vec_len (dm->ip6_name_servers))
2260 vlib_cli_output (vm, "ip6 name servers:");
2261 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
2262 vlib_cli_output (vm, "%U", format_ip6_address,
2263 dm->ip4_name_servers + i);
2269 VLIB_CLI_COMMAND (show_dns_server_command) =
2271 .path = "show dns servers",
2272 .short_help = "show dns servers",
2273 .function = show_dns_servers_command_fn,
2278 static clib_error_t *
2279 dns_cache_add_del_command_fn (vlib_main_t * vm,
2280 unformat_input_t * input,
2281 vlib_cli_command_t * cmd)
2283 dns_main_t *dm = &dns_main;
2289 clib_error_t *error;
2291 if (unformat (input, "add"))
2293 if (unformat (input, "del"))
2295 if (unformat (input, "clear"))
2298 if (is_add == -1 && is_clear == -1)
2299 return clib_error_return (0, "add / del / clear required...");
2303 rv = dns_cache_clear (dm);
2309 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2310 error = clib_error_return (0, "Name resolution not enabled");
2315 /* Delete (by name)? */
2318 if (unformat (input, "%v", &name))
2320 rv = dns_delete_by_name (dm, name);
2323 case VNET_API_ERROR_NO_SUCH_ENTRY:
2324 error = clib_error_return (0, "%v not in the cache...", name);
2328 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2329 error = clib_error_return (0, "Name resolution not enabled");
2338 error = clib_error_return (0, "dns_delete_by_name returned %d",
2344 return clib_error_return (0, "unknown input `%U'",
2345 format_unformat_error, input);
2348 /* Note: dns_add_static_entry consumes the name vector if OK... */
2349 if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2351 rv = dns_add_static_entry (dm, name, dns_reply_data);
2354 case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2356 vec_free (dns_reply_data);
2357 return clib_error_return (0, "%v already in the cache...", name);
2362 return clib_error_return (0, "dns_add_static_entry returned %d",
2371 VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2373 .path = "dns cache",
2374 .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2375 .function = dns_cache_add_del_command_fn,
2379 #define DNS_FORMAT_TEST 1
2381 #if DNS_FORMAT_TEST > 0
2384 static u8 dns_reply_data_initializer[] =
2385 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2386 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2388 0x0, 0xff, /* type ALL */
2389 0x0, 0x1, /* class IN */
2390 0xc0, 0xc, /* pointer to yahoo.com name */
2391 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2392 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2393 0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2394 0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2395 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2396 0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2397 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2398 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2399 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2400 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2401 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2402 0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2403 0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2405 0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2406 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2407 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2408 0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2409 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2411 0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2412 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2413 0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2414 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2416 0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2417 0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2419 0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2421 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2423 0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2425 0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2426 0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2427 0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2431 /* www.cisco.com, has no addresses in reply */
2432 static u8 dns_reply_data_initializer[] = {
2433 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2434 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2435 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2437 0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2438 0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2439 0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2440 0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2441 0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2444 /* bind8 (linux widget, w/ nasty double pointer chasees */
2445 static u8 dns_reply_data_initializer[] = {
2447 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08,
2449 0x00, 0x06, 0x00, 0x06, 0x0a, 0x6f, 0x72, 0x69,
2451 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77, 0x77, 0x05,
2453 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f,
2455 0x6d, 0x00, 0x00, 0xff, 0x00, 0x01, 0x0a, 0x6f,
2457 0x72, 0x69, 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77,
2459 0x77, 0x05, 0x43, 0x49, 0x53, 0x43, 0x4f, 0xc0,
2462 0x1d, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2465 0x9a, 0x00, 0x18, 0x15, 0x72, 0x63, 0x64,
2466 0x6e, 0x39, 0x2d, 0x31, 0x34, 0x70, 0x2d, 0x64, 0x63,
2467 0x7a, 0x30, 0x35, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31,
2468 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00, 0x01, 0x00,
2469 0x00, 0x05, 0x9a, 0x00, 0x1a, 0x17, 0x61, 0x6c, 0x6c,
2470 0x6e, 0x30, 0x31, 0x2d, 0x61, 0x67, 0x30, 0x39, 0x2d,
2471 0x64, 0x63, 0x7a, 0x30, 0x33, 0x6e, 0x2d, 0x67, 0x73,
2472 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00,
2473 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x10, 0x0d, 0x72,
2474 0x74, 0x70, 0x35, 0x2d, 0x64, 0x6d, 0x7a, 0x2d, 0x67,
2475 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2476 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x18, 0x15,
2477 0x6d, 0x74, 0x76, 0x35, 0x2d, 0x61, 0x70, 0x31, 0x30,
2478 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x36, 0x6e, 0x2d, 0x67,
2479 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2480 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x1b, 0x18,
2481 0x73, 0x6e, 0x67, 0x64, 0x63, 0x30, 0x31, 0x2d, 0x61,
2482 0x62, 0x30, 0x37, 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x31,
2483 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0,
2484 0x26, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a,
2485 0x00, 0x1a, 0x17, 0x61, 0x65, 0x72, 0x30, 0x31, 0x2d,
2486 0x72, 0x34, 0x63, 0x32, 0x35, 0x2d, 0x64, 0x63, 0x7a,
2487 0x30, 0x31, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0,
2488 0x17, 0xc0, 0x26, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2489 0x00, 0x81, 0x00, 0x04, 0x48, 0xa3, 0x04, 0xa1, 0xc0,
2490 0x26, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82,
2491 0x00, 0x10, 0x20, 0x01, 0x04, 0x20, 0x12, 0x01, 0x00,
2492 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
2493 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2494 0x9a, 0x00, 0x02, 0xc0, 0xf4, 0xc0, 0x0c, 0x00, 0x02,
2495 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0,
2496 0xcd, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00,
2497 0x05, 0x9a, 0x00, 0x02, 0xc0, 0x8d, 0xc0, 0x0c, 0x00,
2498 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02,
2499 0xc0, 0x43, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00,
2500 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0, 0xa9, 0xc0, 0x0c,
2501 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00,
2502 0x02, 0xc0, 0x67, 0xc0, 0x8d, 0x00, 0x01, 0x00, 0x01,
2503 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0x40, 0x66, 0xf6,
2504 0x05, 0xc0, 0xa9, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2505 0x07, 0x08, 0x00, 0x04, 0xad, 0x24, 0xe0, 0x64, 0xc0,
2506 0x43, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08,
2507 0x00, 0x04, 0x48, 0xa3, 0x04, 0x1c, 0xc0, 0xf4, 0x00,
2508 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04,
2509 0xad, 0x26, 0xd4, 0x6c, 0xc0, 0x67, 0x00, 0x01, 0x00,
2510 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x25,
2511 0x90, 0x64, 0xc0, 0xcd, 0x00, 0x01, 0x00, 0x01, 0x00,
2512 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x27, 0x70, 0x44,
2516 static u8 dns_reply_data_initializer[] =
2517 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
2518 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
2519 0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
2520 0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
2522 0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
2523 0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
2524 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
2525 0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
2526 0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
2527 0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
2528 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
2529 0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
2530 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
2531 0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
2532 0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
2533 0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
2534 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
2535 0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
2536 0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
2537 0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
2538 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2539 0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
2540 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
2541 0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
2542 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
2543 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
2544 0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
2546 0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2550 /* www.weatherlink.com */
2551 static u8 dns_reply_data_initializer[] = {
2552 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2553 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x0b,
2554 0x77, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x6c, 0x69,
2555 0x6e, 0x6b, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0xff,
2556 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00,
2557 0x00, 0x0c, 0x9e, 0x00, 0x1f, 0x0e, 0x64, 0x33, 0x6b,
2558 0x72, 0x30, 0x67, 0x75, 0x62, 0x61, 0x31, 0x64, 0x76,
2559 0x77, 0x66, 0x0a, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x66,
2560 0x72, 0x6f, 0x6e, 0x74, 0x03, 0x6e, 0x65, 0x74, 0x00,
2565 static clib_error_t *
2566 test_dns_fmt_command_fn (vlib_main_t * vm,
2567 unformat_input_t * input, vlib_cli_command_t * cmd)
2569 u8 *dns_reply_data = 0;
2572 vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2574 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2576 if (unformat (input, "verbose %d", &verbose))
2578 else if (unformat (input, "verbose"))
2581 return clib_error_return (0, "unknown input `%U'",
2582 format_unformat_error, input);
2585 vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2587 memcpy (dns_reply_data, dns_reply_data_initializer,
2588 ARRAY_LEN (dns_reply_data_initializer));
2590 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2592 clib_memset (rmp, 0, sizeof (*rmp));
2594 rv = vnet_dns_response_to_reply (dns_reply_data, rmp, 0 /* ttl-ptr */ );
2598 case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2599 vlib_cli_output (vm, "no addresses found...");
2603 vlib_cli_output (vm, "response to reply returned %d", rv);
2608 vlib_cli_output (vm, "ip4 address: %U", format_ip4_address,
2609 (ip4_address_t *) rmp->ip4_address);
2611 vlib_cli_output (vm, "ip6 address: %U", format_ip6_address,
2612 (ip6_address_t *) rmp->ip6_address);
2616 vec_free (dns_reply_data);
2623 VLIB_CLI_COMMAND (test_dns_fmt_command) =
2625 .path = "test dns format",
2626 .short_help = "test dns format",
2627 .function = test_dns_fmt_command_fn,
2631 static clib_error_t *
2632 test_dns_unfmt_command_fn (vlib_main_t * vm,
2633 unformat_input_t * input, vlib_cli_command_t * cmd)
2635 u8 *dns_reply_data = 0;
2639 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2641 if (unformat (input, "verbose %d", &verbose))
2643 else if (unformat (input, "verbose"))
2645 else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2648 return clib_error_return (0, "unknown input `%U'",
2649 format_unformat_error, input);
2653 return clib_error_return (0, "dns data not set...");
2655 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2657 vec_free (dns_reply_data);
2663 VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2665 .path = "test dns unformat",
2666 .short_help = "test dns unformat <name> [ip4][ip6]",
2667 .function = test_dns_unfmt_command_fn,
2671 static clib_error_t *
2672 test_dns_expire_command_fn (vlib_main_t * vm,
2673 unformat_input_t * input,
2674 vlib_cli_command_t * cmd)
2676 dns_main_t *dm = &dns_main;
2680 dns_cache_entry_t *ep;
2682 if (unformat (input, "%v", &name))
2685 _vec_len (name) -= 1;
2688 return clib_error_return (0, "no name provided");
2690 dns_cache_lock (dm, 7);
2692 p = hash_get_mem (dm->cache_entry_by_name, name);
2695 dns_cache_unlock (dm);
2696 e = clib_error_return (0, "%s is not in the cache...", name);
2701 ep = pool_elt_at_index (dm->entries, p[0]);
2703 ep->expiration_time = 0;
2709 VLIB_CLI_COMMAND (test_dns_expire_command) =
2711 .path = "test dns expire",
2712 .short_help = "test dns expire <name>",
2713 .function = test_dns_expire_command_fn,
2719 vnet_send_dns6_reply (dns_main_t * dm, dns_pending_request_t * pr,
2720 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2722 clib_warning ("Unimplemented...");
2727 vnet_send_dns4_reply (dns_main_t * dm, dns_pending_request_t * pr,
2728 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2730 vlib_main_t *vm = dm->vlib_main;
2732 fib_prefix_t prefix;
2733 fib_node_index_t fei;
2734 u32 sw_if_index, fib_index;
2735 ip4_main_t *im4 = &ip4_main;
2736 ip_lookup_main_t *lm4 = &im4->lookup_main;
2737 ip_interface_address_t *ia = 0;
2738 ip4_address_t *src_address;
2746 vl_api_dns_resolve_name_reply_t _rnr, *rnr = &_rnr;
2747 vl_api_dns_resolve_ip_reply_t _rir, *rir = &_rir;
2754 int is_recycle = (b0 != 0);
2756 ASSERT (ep && ep->dns_response);
2758 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2760 /* Quick and dirty way to dig up the A-record address. $$ FIXME */
2761 clib_memset (rnr, 0, sizeof (*rnr));
2762 if (vnet_dns_response_to_reply (ep->dns_response, rnr, &ttl))
2764 /* clib_warning ("response_to_reply failed..."); */
2767 if (rnr->ip4_set == 0)
2769 /* clib_warning ("No A-record..."); */
2773 else if (pr->request_type == DNS_PEER_PENDING_IP_TO_NAME)
2775 clib_memset (rir, 0, sizeof (*rir));
2776 if (vnet_dns_response_to_name (ep->dns_response, rir, &ttl))
2778 /* clib_warning ("response_to_name failed..."); */
2784 clib_warning ("Unknown request type %d", pr->request_type);
2788 /* Initialize a buffer */
2791 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2793 b0 = vlib_get_buffer (vm, bi);
2797 /* Use the buffer we were handed. Reinitialize it... */
2798 vlib_buffer_t bt = { };
2799 /* push/pop the reference count */
2800 u8 save_ref_count = b0->ref_count;
2801 vlib_buffer_copy_template (b0, &bt);
2802 b0->ref_count = save_ref_count;
2803 bi = vlib_get_buffer_index (vm, b0);
2806 if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
2807 vlib_buffer_free_one (vm, b0->next_buffer);
2810 * Reset the buffer. We recycle the DNS request packet in the cache
2811 * hit case, and reply immediately from the request node.
2813 * In the resolution-required / deferred case, resetting a freshly-allocated
2814 * buffer won't hurt. We hope.
2816 b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
2817 | VLIB_BUFFER_TOTAL_LENGTH_VALID);
2818 vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; /* "local0" */
2819 vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
2821 /* Find a FIB path to the peer we're trying to answer */
2822 clib_memcpy (&prefix.fp_addr.ip4, pr->dst_address, sizeof (ip4_address_t));
2823 prefix.fp_proto = FIB_PROTOCOL_IP4;
2826 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
2827 if (fib_index == (u32) ~ 0)
2829 clib_warning ("no fib table");
2833 fei = fib_table_lookup (fib_index, &prefix);
2835 /* Couldn't find route to destination. Bail out. */
2836 if (fei == FIB_NODE_INDEX_INVALID)
2838 clib_warning ("no route to DNS server");
2842 sw_if_index = fib_entry_get_resolving_interface (fei);
2844 if (sw_if_index == ~0)
2847 ("route to %U exists, fei %d, get_resolving_interface returned"
2848 " ~0", fei, format_ip4_address, &prefix.fp_addr);
2853 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnumbered */,
2855 src_address = ip_interface_address_get_address (lm4, ia);
2856 goto found_src_address;
2860 clib_warning ("FIB BUG");
2865 ip = vlib_buffer_get_current (b0);
2866 udp = (udp_header_t *) (ip + 1);
2867 dns_response = (u8 *) (udp + 1);
2868 clib_memset (ip, 0, sizeof (*ip) + sizeof (*udp));
2871 * Start with the variadic portion of the exercise.
2872 * Turn the name into a set of DNS "labels". Max length
2873 * per label is 63, enforce that.
2875 reply = name_to_labels (pr->name);
2876 vec_free (pr->name);
2878 qp_offset = vec_len (reply);
2880 /* Add space for the query header */
2881 vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
2883 qp = (dns_query_t *) (reply + qp_offset);
2885 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2886 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
2888 qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2890 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
2892 /* Punch in space for the dns_header_t */
2893 vec_insert (reply, sizeof (dns_header_t), 0);
2895 dh = (dns_header_t *) reply;
2897 /* Transaction ID = pool index */
2900 /* Announce that we did a recursive lookup */
2901 tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
2903 tmp |= DNS_RCODE_NAME_ERROR;
2904 dh->flags = clib_host_to_net_u16 (tmp);
2905 dh->qdcount = clib_host_to_net_u16 (1);
2906 dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
2910 /* If the name resolution worked, cough up an appropriate RR */
2913 /* Add the answer. First, a name pointer (0xC00C) */
2914 vec_add1 (reply, 0xC0);
2915 vec_add1 (reply, 0x0C);
2917 /* Now, add single A-rec RR */
2918 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2920 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
2921 rr = (dns_rr_t *) rrptr;
2923 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
2924 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2925 rr->ttl = clib_host_to_net_u32 (ttl);
2926 rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
2927 clib_memcpy (rr->rdata, rnr->ip4_address, sizeof (ip4_address_t));
2931 /* Or a single PTR RR */
2932 u8 *vecname = format (0, "%s", rir->name);
2933 u8 *label_vec = name_to_labels (vecname);
2936 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
2937 rr = (dns_rr_t *) rrptr;
2938 rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2939 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2940 rr->ttl = clib_host_to_net_u32 (ttl);
2941 rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
2942 clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
2943 vec_free (label_vec);
2946 clib_memcpy (dns_response, reply, vec_len (reply));
2948 /* Set the packet length */
2949 b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
2952 ip->ip_version_and_header_length = 0x45;
2953 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
2955 ip->protocol = IP_PROTOCOL_UDP;
2956 ip->src_address.as_u32 = src_address->as_u32;
2957 clib_memcpy (ip->dst_address.as_u8, pr->dst_address,
2958 sizeof (ip4_address_t));
2959 ip->checksum = ip4_header_checksum (ip);
2962 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
2963 udp->dst_port = pr->dst_port;
2964 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
2970 * Ship pkts made out of whole cloth to ip4_lookup
2971 * Caller will ship recycled dns reply packets to ip4_lookup
2973 if (is_recycle == 0)
2975 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
2976 to_next = vlib_frame_vector_args (f);
2979 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
2983 #include <dns/dns.api.c>
2984 static clib_error_t *
2985 dns_init (vlib_main_t * vm)
2987 dns_main_t *dm = &dns_main;
2990 dm->vnet_main = vnet_get_main ();
2991 dm->name_cache_size = 1000;
2992 dm->max_ttl_in_seconds = 86400;
2993 dm->random_seed = 0xDEADDABE;
2994 dm->api_main = vlibapi_get_main ();
2996 /* Ask for a correctly-sized block of API message decode slots */
2997 dm->msg_id_base = setup_message_id_table ();
3002 VLIB_INIT_FUNCTION (dns_init);
3005 VLIB_PLUGIN_REGISTER () =
3007 .version = VPP_BUILD_VER,
3008 .description = "Simple DNS name resolver",
3014 * fd.io coding-style-patch-verification: ON
3017 * eval: (c-set-style "gnu")