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.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);
1476 * dns_resolve_name leaves the cache locked when it returns
1477 * a cached result, so unlock it here.
1479 dns_cache_unlock (dm);
1483 vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
1485 dns_main_t *dm = &dns_main;
1486 vl_api_dns_resolve_ip_reply_t *rmp;
1487 dns_cache_entry_t *ep;
1490 u8 *lookup_name = 0;
1492 dns_pending_request_t _t0, *t0 = &_t0;
1496 for (i = 15; i >= 0; i--)
1498 digit = mp->address[i];
1499 nybble = (digit & 0x0F);
1501 vec_add1 (lookup_name, (nybble - 10) + 'a');
1503 vec_add1 (lookup_name, nybble + '0');
1504 vec_add1 (lookup_name, '.');
1505 nybble = (digit & 0xF0) >> 4;
1507 vec_add1 (lookup_name, (nybble - 10) + 'a');
1509 vec_add1 (lookup_name, nybble + '0');
1510 vec_add1 (lookup_name, '.');
1512 len = vec_len (lookup_name);
1513 vec_validate (lookup_name, len + 8);
1514 memcpy (lookup_name + len, "ip6.arpa", 8);
1518 for (i = 3; i >= 0; i--)
1520 digit = mp->address[i];
1521 lookup_name = format (lookup_name, "%d.", digit);
1523 lookup_name = format (lookup_name, "in-addr.arpa");
1526 vec_add1 (lookup_name, 0);
1528 t0->request_type = DNS_API_PENDING_IP_TO_NAME;
1529 t0->client_index = mp->client_index;
1530 t0->client_context = mp->context;
1532 rv = vnet_dns_resolve_name (dm, lookup_name, t0, &ep);
1534 vec_free (lookup_name);
1536 /* Error, e.g. not enabled? Tell the user */
1539 REPLY_MACRO (VL_API_DNS_RESOLVE_IP_REPLY);
1543 /* Resolution pending? Don't reply... */
1548 REPLY_MACRO2(VL_API_DNS_RESOLVE_IP_REPLY,
1550 rv = vnet_dns_response_to_name (ep->dns_response, rmp, 0 /* ttl-ptr */);
1551 rmp->retval = clib_host_to_net_u32 (rv);
1556 * vnet_dns_resolve_name leaves the cache locked when it returns
1557 * a cached result, so unlock it here.
1559 dns_cache_unlock (dm);
1562 static clib_error_t *
1563 dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1565 dns_main_t *dm = &dns_main;
1567 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1569 if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1571 else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1574 return clib_error_return (0, "unknown input `%U'",
1575 format_unformat_error, input);
1580 VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1583 unformat_dns_reply (unformat_input_t * input, va_list * args)
1585 u8 **result = va_arg (*args, u8 **);
1586 u8 **namep = va_arg (*args, u8 **);
1600 if (unformat (input, "%v", &name))
1603 if (unformat (input, "%U", unformat_ip4_address, &a4))
1606 if (unformat (input, "%U", unformat_ip6_address, &a6))
1610 if (unformat (input, "%U", unformat_ip6_address, &a6))
1613 if (unformat (input, "%U", unformat_ip4_address, &a6))
1617 /* Must have a name */
1621 /* Must have at least one address */
1622 if (!(a4_set + a6_set))
1625 /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1626 ce = name_to_labels (name);
1627 qp_offset = vec_len (ce);
1629 /* Add space for the query header */
1630 vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1631 qp = (dns_query_t *) (ce + qp_offset);
1633 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1634 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1636 /* Punch in space for the dns_header_t */
1637 vec_insert (ce, sizeof (dns_header_t), 0);
1639 h = (dns_header_t *) ce;
1641 /* Fake Transaction ID */
1644 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1645 h->qdcount = clib_host_to_net_u16 (1);
1646 h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1650 /* Now append one or two A/AAAA RR's... */
1653 /* Pointer to the name (DGMS) */
1654 vec_add1 (ce, 0xC0);
1655 vec_add1 (ce, 0x0C);
1656 vec_add2 (ce, rru8, sizeof (*rr) + 4);
1658 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1659 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1660 rr->ttl = clib_host_to_net_u32 (86400);
1661 rr->rdlength = clib_host_to_net_u16 (4);
1662 memcpy (rr->rdata, &a4, sizeof (a4));
1666 /* Pointer to the name (DGMS) */
1667 vec_add1 (ce, 0xC0);
1668 vec_add1 (ce, 0x0C);
1669 vec_add2 (ce, rru8, sizeof (*rr) + 16);
1671 rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1672 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1673 rr->ttl = clib_host_to_net_u32 (86400);
1674 rr->rdlength = clib_host_to_net_u16 (16);
1675 memcpy (rr->rdata, &a6, sizeof (a6));
1687 format_dns_query (u8 * s, va_list * args)
1689 u8 **curpos = va_arg (*args, u8 **);
1690 int verbose = va_arg (*args, int);
1695 s = format (s, " Name: ");
1697 /* Unwind execrated counted-label sheit */
1703 for (i = 0; i < len; i++)
1704 vec_add1 (s, *pos++);
1716 qp = (dns_query_t *) pos;
1719 switch (clib_net_to_host_u16 (qp->type))
1722 s = format (s, "type A\n");
1725 s = format (s, "type AAAA\n");
1728 s = format (s, "type ALL\n");
1732 s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1737 pos += sizeof (*qp);
1744 * format dns reply data
1745 * verbose > 1, dump everything
1746 * verbose == 1, dump all A and AAAA records
1747 * verbose == 0, dump one A record, and one AAAA record
1751 format_dns_reply_data (u8 * s, va_list * args)
1753 u8 *reply = va_arg (*args, u8 *);
1754 u8 **curpos = va_arg (*args, u8 **);
1755 int verbose = va_arg (*args, int);
1756 int *print_ip4 = va_arg (*args, int *);
1757 int *print_ip6 = va_arg (*args, int *);
1762 int pointer_chase = 0;
1764 u16 rrtype_host_byte_order;
1766 pos = pos2 = *curpos;
1769 s = format (s, " ");
1771 /* chase pointer? almost always yes here... */
1772 if ((pos2[0] & 0xc0) == 0xc0)
1775 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1783 for (i = 0; i < len; i++)
1786 vec_add1 (s, *pos2);
1789 if ((pos2[0] & 0xc0) == 0xc0)
1792 * If we've already done one pointer chase,
1793 * do not move the pos pointer.
1795 if (pointer_chase == 0)
1797 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1815 if (pointer_chase == 0)
1818 rr = (dns_rr_t *) pos;
1819 rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
1821 switch (rrtype_host_byte_order)
1826 s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1827 format_ip4_address, rr->rdata);
1832 s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1833 clib_net_to_host_u32 (rr->ttl));
1838 pos += sizeof (*rr) + 4;
1844 s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1845 format_ip6_address, rr->rdata);
1850 s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1851 clib_net_to_host_u32 (rr->ttl));
1855 pos += sizeof (*rr) + 16;
1861 s = format (s, "TEXT: ");
1862 for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1863 vec_add1 (s, rr->rdata[i]);
1866 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1869 case DNS_TYPE_HINFO:
1871 /* Two counted strings. DGMS */
1877 s = format (s, "HINFO: ");
1880 for (i = 0; i < *len; i++)
1881 vec_add1 (s, *curpos++);
1885 for (i = 0; i < *len; i++)
1886 vec_add1 (s, *curpos++);
1891 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1894 case DNS_TYPE_NAMESERVER:
1897 s = format (s, "Nameserver: ");
1900 /* chase pointer? */
1901 if ((pos2[0] & 0xc0) == 0xc0)
1904 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1911 for (i = 0; i < len; i++)
1912 vec_add1 (s, *pos2++);
1914 /* chase pointer, typically to offset 12... */
1915 if (pos2[0] == 0xC0)
1916 pos2 = reply + pos2[1];
1925 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1928 case DNS_TYPE_MAIL_EXCHANGE:
1931 tp = (u16 *) rr->rdata;
1933 s = format (s, "Mail Exchange: Preference %d ", (u32)
1934 clib_net_to_host_u16 (*tp));
1936 pos2 = rr->rdata + 2;
1938 /* chase pointer? */
1939 if (pos2[0] == 0xc0)
1940 pos2 = reply + pos2[1];
1946 for (i = 0; i < len; i++)
1947 vec_add1 (s, *pos2++);
1950 if (pos2[0] == 0xC0)
1951 pos2 = reply + pos2[1];
1961 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1965 case DNS_TYPE_CNAME:
1968 tp = (u16 *) rr->rdata;
1970 if (rrtype_host_byte_order == DNS_TYPE_CNAME)
1971 s = format (s, "CNAME: ");
1973 s = format (s, "PTR: ");
1977 /* chase pointer? */
1978 if (pos2[0] == 0xc0)
1979 pos2 = reply + pos2[1];
1985 for (i = 0; i < len; i++)
1986 vec_add1 (s, *pos2++);
1989 if (pos2[0] == 0xC0)
1990 pos2 = reply + pos2[1];
1999 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2004 s = format (s, "type %d: len %d\n",
2005 (int) clib_net_to_host_u16 (rr->type),
2006 sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
2007 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2017 format_dns_reply (u8 * s, va_list * args)
2019 u8 *reply_as_u8 = va_arg (*args, u8 *);
2020 int verbose = va_arg (*args, int);
2028 h = (dns_header_t *) reply_as_u8;
2029 id = clib_net_to_host_u16 (h->id);
2030 flags = clib_net_to_host_u16 (h->flags);
2034 s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
2036 s = format (s, " %s %s %s %s\n",
2037 (flags & DNS_RA) ? "recur" : "no-recur",
2038 (flags & DNS_RD) ? "recur-des" : "no-recur-des",
2039 (flags & DNS_TC) ? "trunc" : "no-trunc",
2040 (flags & DNS_AA) ? "auth" : "non-auth");
2041 s = format (s, " %d queries, %d answers, %d name-servers,"
2043 clib_net_to_host_u16 (h->qdcount),
2044 clib_net_to_host_u16 (h->anscount),
2045 clib_net_to_host_u16 (h->nscount),
2046 clib_net_to_host_u16 (h->arcount));
2049 curpos = (u8 *) (h + 1);
2054 s = format (s, " Queries:\n");
2055 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
2057 /* The query is variable-length, so curpos is a value-result parm */
2058 s = format (s, "%U", format_dns_query, &curpos, verbose);
2064 s = format (s, " Replies:\n");
2066 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
2068 /* curpos is a value-result parm */
2069 s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
2070 verbose, &print_ip4, &print_ip6);
2077 format_dns_cache (u8 * s, va_list * args)
2079 dns_main_t *dm = va_arg (*args, dns_main_t *);
2080 f64 now = va_arg (*args, f64);
2081 int verbose = va_arg (*args, int);
2082 u8 *name = va_arg (*args, u8 *);
2083 dns_cache_entry_t *ep;
2087 if (dm->is_enabled == 0)
2089 s = format (s, "The DNS cache is disabled...");
2093 if (pool_elts (dm->entries) == 0)
2095 s = format (s, "The DNS cache is empty...");
2099 dns_cache_lock (dm, 6);
2103 p = hash_get_mem (dm->cache_entry_by_name, name);
2106 s = format (s, "%s is not in the cache...", name);
2107 dns_cache_unlock (dm);
2111 ep = pool_elt_at_index (dm->entries, p[0]);
2112 /* Magic to spit out a C-initializer to research hemorrhoids... */
2116 s = format (s, "static u8 dns_reply_data_initializer[] =\n");
2117 s = format (s, "{\n");
2119 for (i = 0; i < vec_len (ep->dns_response); i++)
2126 s = format (s, "0x%02x, ", ep->dns_response[i]);
2128 s = format (s, "};\n");
2132 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2134 ASSERT (ep->dns_response);
2135 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2140 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2141 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2143 s = format (s, "%s%s -> %U", ss, ep->name,
2144 format_dns_reply, ep->dns_response, verbose);
2145 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2147 f64 time_left = ep->expiration_time - now;
2148 if (time_left > 0.0)
2149 s = format (s, " TTL left %.1f", time_left);
2151 s = format (s, " EXPIRED");
2156 ASSERT (ep->dns_request);
2157 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2165 s = format (s, "DNS cache contains %d entries\n", pool_elts (dm->entries));
2170 pool_foreach (ep, dm->entries,
2172 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2174 ASSERT (ep->dns_response);
2175 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2180 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2181 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2183 s = format (s, "%s%s -> %U", ss, ep->name,
2187 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2189 f64 time_left = ep->expiration_time - now;
2190 if (time_left > 0.0)
2191 s = format (s, " TTL left %.1f", time_left);
2193 s = format (s, " EXPIRED");
2196 s = format (s, " %d client notifications pending\n",
2197 vec_len(ep->pending_requests));
2202 ASSERT (ep->dns_request);
2203 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2211 dns_cache_unlock (dm);
2216 static clib_error_t *
2217 show_dns_cache_command_fn (vlib_main_t * vm,
2218 unformat_input_t * input, vlib_cli_command_t * cmd)
2220 dns_main_t *dm = &dns_main;
2223 f64 now = vlib_time_now (vm);
2225 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2227 if (unformat (input, "verbose %d", &verbose))
2229 else if (unformat (input, "verbose"))
2231 else if (unformat (input, "name %s", &name))
2234 return clib_error_return (0, "unknown input `%U'",
2235 format_unformat_error, input);
2238 vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
2244 VLIB_CLI_COMMAND (show_dns_cache_command) =
2246 .path = "show dns cache",
2247 .short_help = "show dns cache [verbose [nn]]",
2248 .function = show_dns_cache_command_fn,
2252 static clib_error_t *
2253 show_dns_servers_command_fn (vlib_main_t * vm,
2254 unformat_input_t * input,
2255 vlib_cli_command_t * cmd)
2257 dns_main_t *dm = &dns_main;
2260 if ((vec_len (dm->ip4_name_servers) + vec_len (dm->ip6_name_servers)) == 0)
2261 return clib_error_return (0, "No name servers configured...");
2263 if (vec_len (dm->ip4_name_servers))
2265 vlib_cli_output (vm, "ip4 name servers:");
2266 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
2267 vlib_cli_output (vm, "%U", format_ip4_address,
2268 dm->ip4_name_servers + i);
2270 if (vec_len (dm->ip6_name_servers))
2272 vlib_cli_output (vm, "ip6 name servers:");
2273 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
2274 vlib_cli_output (vm, "%U", format_ip6_address,
2275 dm->ip4_name_servers + i);
2281 VLIB_CLI_COMMAND (show_dns_server_command) =
2283 .path = "show dns servers",
2284 .short_help = "show dns servers",
2285 .function = show_dns_servers_command_fn,
2290 static clib_error_t *
2291 dns_cache_add_del_command_fn (vlib_main_t * vm,
2292 unformat_input_t * input,
2293 vlib_cli_command_t * cmd)
2295 dns_main_t *dm = &dns_main;
2301 clib_error_t *error;
2303 if (unformat (input, "add"))
2305 if (unformat (input, "del"))
2307 if (unformat (input, "clear"))
2310 if (is_add == -1 && is_clear == -1)
2311 return clib_error_return (0, "add / del / clear required...");
2315 rv = dns_cache_clear (dm);
2321 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2322 error = clib_error_return (0, "Name resolution not enabled");
2327 /* Delete (by name)? */
2330 if (unformat (input, "%v", &name))
2332 rv = dns_delete_by_name (dm, name);
2335 case VNET_API_ERROR_NO_SUCH_ENTRY:
2336 error = clib_error_return (0, "%v not in the cache...", name);
2340 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2341 error = clib_error_return (0, "Name resolution not enabled");
2350 error = clib_error_return (0, "dns_delete_by_name returned %d",
2356 return clib_error_return (0, "unknown input `%U'",
2357 format_unformat_error, input);
2360 /* Note: dns_add_static_entry consumes the name vector if OK... */
2361 if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2363 rv = dns_add_static_entry (dm, name, dns_reply_data);
2366 case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2368 vec_free (dns_reply_data);
2369 return clib_error_return (0, "%v already in the cache...", name);
2374 return clib_error_return (0, "dns_add_static_entry returned %d",
2383 VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2385 .path = "dns cache",
2386 .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2387 .function = dns_cache_add_del_command_fn,
2391 #define DNS_FORMAT_TEST 1
2393 #if DNS_FORMAT_TEST > 0
2396 static u8 dns_reply_data_initializer[] =
2397 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2398 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2400 0x0, 0xff, /* type ALL */
2401 0x0, 0x1, /* class IN */
2402 0xc0, 0xc, /* pointer to yahoo.com name */
2403 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2404 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2405 0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2406 0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2407 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2408 0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2409 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2410 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2411 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2412 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2413 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2414 0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2415 0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2417 0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2418 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2419 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2420 0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2421 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2423 0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2424 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2425 0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2426 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2428 0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2429 0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2431 0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2433 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2435 0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2437 0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2438 0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2439 0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2443 /* www.cisco.com, has no addresses in reply */
2444 static u8 dns_reply_data_initializer[] = {
2445 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2446 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2447 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2449 0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2450 0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2451 0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2452 0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2453 0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2456 /* bind8 (linux widget, w/ nasty double pointer chasees */
2457 static u8 dns_reply_data_initializer[] = {
2459 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08,
2461 0x00, 0x06, 0x00, 0x06, 0x0a, 0x6f, 0x72, 0x69,
2463 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77, 0x77, 0x05,
2465 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f,
2467 0x6d, 0x00, 0x00, 0xff, 0x00, 0x01, 0x0a, 0x6f,
2469 0x72, 0x69, 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77,
2471 0x77, 0x05, 0x43, 0x49, 0x53, 0x43, 0x4f, 0xc0,
2474 0x1d, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2477 0x9a, 0x00, 0x18, 0x15, 0x72, 0x63, 0x64,
2478 0x6e, 0x39, 0x2d, 0x31, 0x34, 0x70, 0x2d, 0x64, 0x63,
2479 0x7a, 0x30, 0x35, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31,
2480 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00, 0x01, 0x00,
2481 0x00, 0x05, 0x9a, 0x00, 0x1a, 0x17, 0x61, 0x6c, 0x6c,
2482 0x6e, 0x30, 0x31, 0x2d, 0x61, 0x67, 0x30, 0x39, 0x2d,
2483 0x64, 0x63, 0x7a, 0x30, 0x33, 0x6e, 0x2d, 0x67, 0x73,
2484 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00,
2485 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x10, 0x0d, 0x72,
2486 0x74, 0x70, 0x35, 0x2d, 0x64, 0x6d, 0x7a, 0x2d, 0x67,
2487 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2488 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x18, 0x15,
2489 0x6d, 0x74, 0x76, 0x35, 0x2d, 0x61, 0x70, 0x31, 0x30,
2490 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x36, 0x6e, 0x2d, 0x67,
2491 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2492 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x1b, 0x18,
2493 0x73, 0x6e, 0x67, 0x64, 0x63, 0x30, 0x31, 0x2d, 0x61,
2494 0x62, 0x30, 0x37, 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x31,
2495 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0,
2496 0x26, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a,
2497 0x00, 0x1a, 0x17, 0x61, 0x65, 0x72, 0x30, 0x31, 0x2d,
2498 0x72, 0x34, 0x63, 0x32, 0x35, 0x2d, 0x64, 0x63, 0x7a,
2499 0x30, 0x31, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0,
2500 0x17, 0xc0, 0x26, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2501 0x00, 0x81, 0x00, 0x04, 0x48, 0xa3, 0x04, 0xa1, 0xc0,
2502 0x26, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82,
2503 0x00, 0x10, 0x20, 0x01, 0x04, 0x20, 0x12, 0x01, 0x00,
2504 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
2505 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2506 0x9a, 0x00, 0x02, 0xc0, 0xf4, 0xc0, 0x0c, 0x00, 0x02,
2507 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0,
2508 0xcd, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00,
2509 0x05, 0x9a, 0x00, 0x02, 0xc0, 0x8d, 0xc0, 0x0c, 0x00,
2510 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02,
2511 0xc0, 0x43, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00,
2512 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0, 0xa9, 0xc0, 0x0c,
2513 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00,
2514 0x02, 0xc0, 0x67, 0xc0, 0x8d, 0x00, 0x01, 0x00, 0x01,
2515 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0x40, 0x66, 0xf6,
2516 0x05, 0xc0, 0xa9, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2517 0x07, 0x08, 0x00, 0x04, 0xad, 0x24, 0xe0, 0x64, 0xc0,
2518 0x43, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08,
2519 0x00, 0x04, 0x48, 0xa3, 0x04, 0x1c, 0xc0, 0xf4, 0x00,
2520 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04,
2521 0xad, 0x26, 0xd4, 0x6c, 0xc0, 0x67, 0x00, 0x01, 0x00,
2522 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x25,
2523 0x90, 0x64, 0xc0, 0xcd, 0x00, 0x01, 0x00, 0x01, 0x00,
2524 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x27, 0x70, 0x44,
2528 static u8 dns_reply_data_initializer[] =
2529 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
2530 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
2531 0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
2532 0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
2534 0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
2535 0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
2536 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
2537 0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
2538 0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
2539 0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
2540 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
2541 0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
2542 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
2543 0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
2544 0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
2545 0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
2546 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
2547 0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
2548 0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
2549 0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
2550 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2551 0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
2552 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
2553 0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
2554 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
2555 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
2556 0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
2558 0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2562 /* www.weatherlink.com */
2563 static u8 dns_reply_data_initializer[] = {
2564 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2565 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x0b,
2566 0x77, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x6c, 0x69,
2567 0x6e, 0x6b, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0xff,
2568 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00,
2569 0x00, 0x0c, 0x9e, 0x00, 0x1f, 0x0e, 0x64, 0x33, 0x6b,
2570 0x72, 0x30, 0x67, 0x75, 0x62, 0x61, 0x31, 0x64, 0x76,
2571 0x77, 0x66, 0x0a, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x66,
2572 0x72, 0x6f, 0x6e, 0x74, 0x03, 0x6e, 0x65, 0x74, 0x00,
2577 static clib_error_t *
2578 test_dns_fmt_command_fn (vlib_main_t * vm,
2579 unformat_input_t * input, vlib_cli_command_t * cmd)
2581 u8 *dns_reply_data = 0;
2584 vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2586 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2588 if (unformat (input, "verbose %d", &verbose))
2590 else if (unformat (input, "verbose"))
2593 return clib_error_return (0, "unknown input `%U'",
2594 format_unformat_error, input);
2597 vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2599 memcpy (dns_reply_data, dns_reply_data_initializer,
2600 ARRAY_LEN (dns_reply_data_initializer));
2602 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2604 clib_memset (rmp, 0, sizeof (*rmp));
2606 rv = vnet_dns_response_to_reply (dns_reply_data, rmp, 0 /* ttl-ptr */ );
2610 case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2611 vlib_cli_output (vm, "no addresses found...");
2615 vlib_cli_output (vm, "response to reply returned %d", rv);
2620 vlib_cli_output (vm, "ip4 address: %U", format_ip4_address,
2621 (ip4_address_t *) rmp->ip4_address);
2623 vlib_cli_output (vm, "ip6 address: %U", format_ip6_address,
2624 (ip6_address_t *) rmp->ip6_address);
2628 vec_free (dns_reply_data);
2635 VLIB_CLI_COMMAND (test_dns_fmt_command) =
2637 .path = "test dns format",
2638 .short_help = "test dns format",
2639 .function = test_dns_fmt_command_fn,
2643 static clib_error_t *
2644 test_dns_unfmt_command_fn (vlib_main_t * vm,
2645 unformat_input_t * input, vlib_cli_command_t * cmd)
2647 u8 *dns_reply_data = 0;
2651 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2653 if (unformat (input, "verbose %d", &verbose))
2655 else if (unformat (input, "verbose"))
2657 else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2660 return clib_error_return (0, "unknown input `%U'",
2661 format_unformat_error, input);
2665 return clib_error_return (0, "dns data not set...");
2667 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2669 vec_free (dns_reply_data);
2675 VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2677 .path = "test dns unformat",
2678 .short_help = "test dns unformat <name> [ip4][ip6]",
2679 .function = test_dns_unfmt_command_fn,
2683 static clib_error_t *
2684 test_dns_expire_command_fn (vlib_main_t * vm,
2685 unformat_input_t * input,
2686 vlib_cli_command_t * cmd)
2688 dns_main_t *dm = &dns_main;
2692 dns_cache_entry_t *ep;
2694 if (unformat (input, "%v", &name))
2697 _vec_len (name) -= 1;
2700 return clib_error_return (0, "no name provided");
2702 dns_cache_lock (dm, 7);
2704 p = hash_get_mem (dm->cache_entry_by_name, name);
2707 dns_cache_unlock (dm);
2708 e = clib_error_return (0, "%s is not in the cache...", name);
2713 ep = pool_elt_at_index (dm->entries, p[0]);
2715 ep->expiration_time = 0;
2721 VLIB_CLI_COMMAND (test_dns_expire_command) =
2723 .path = "test dns expire",
2724 .short_help = "test dns expire <name>",
2725 .function = test_dns_expire_command_fn,
2731 vnet_send_dns6_reply (dns_main_t * dm, dns_pending_request_t * pr,
2732 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2734 clib_warning ("Unimplemented...");
2739 vnet_send_dns4_reply (dns_main_t * dm, dns_pending_request_t * pr,
2740 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2742 vlib_main_t *vm = dm->vlib_main;
2744 fib_prefix_t prefix;
2745 fib_node_index_t fei;
2746 u32 sw_if_index, fib_index;
2747 ip4_main_t *im4 = &ip4_main;
2748 ip_lookup_main_t *lm4 = &im4->lookup_main;
2749 ip_interface_address_t *ia = 0;
2750 ip4_address_t *src_address;
2758 vl_api_dns_resolve_name_reply_t _rnr, *rnr = &_rnr;
2759 vl_api_dns_resolve_ip_reply_t _rir, *rir = &_rir;
2766 int is_recycle = (b0 != 0);
2768 ASSERT (ep && ep->dns_response);
2770 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2772 /* Quick and dirty way to dig up the A-record address. $$ FIXME */
2773 clib_memset (rnr, 0, sizeof (*rnr));
2774 if (vnet_dns_response_to_reply (ep->dns_response, rnr, &ttl))
2776 /* clib_warning ("response_to_reply failed..."); */
2779 if (rnr->ip4_set == 0)
2781 /* clib_warning ("No A-record..."); */
2785 else if (pr->request_type == DNS_PEER_PENDING_IP_TO_NAME)
2787 clib_memset (rir, 0, sizeof (*rir));
2788 if (vnet_dns_response_to_name (ep->dns_response, rir, &ttl))
2790 /* clib_warning ("response_to_name failed..."); */
2796 clib_warning ("Unknown request type %d", pr->request_type);
2800 /* Initialize a buffer */
2803 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2805 b0 = vlib_get_buffer (vm, bi);
2809 /* Use the buffer we were handed. Reinitialize it... */
2810 vlib_buffer_t bt = { };
2811 /* push/pop the reference count */
2812 u8 save_ref_count = b0->ref_count;
2813 vlib_buffer_copy_template (b0, &bt);
2814 b0->ref_count = save_ref_count;
2815 bi = vlib_get_buffer_index (vm, b0);
2818 if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
2819 vlib_buffer_free_one (vm, b0->next_buffer);
2822 * Reset the buffer. We recycle the DNS request packet in the cache
2823 * hit case, and reply immediately from the request node.
2825 * In the resolution-required / deferred case, resetting a freshly-allocated
2826 * buffer won't hurt. We hope.
2828 b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
2829 | VLIB_BUFFER_TOTAL_LENGTH_VALID);
2830 vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; /* "local0" */
2831 vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
2833 /* Find a FIB path to the peer we're trying to answer */
2834 clib_memcpy (&prefix.fp_addr.ip4, pr->dst_address, sizeof (ip4_address_t));
2835 prefix.fp_proto = FIB_PROTOCOL_IP4;
2838 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
2839 if (fib_index == (u32) ~ 0)
2841 clib_warning ("no fib table");
2845 fei = fib_table_lookup (fib_index, &prefix);
2847 /* Couldn't find route to destination. Bail out. */
2848 if (fei == FIB_NODE_INDEX_INVALID)
2850 clib_warning ("no route to DNS server");
2854 sw_if_index = fib_entry_get_resolving_interface (fei);
2856 if (sw_if_index == ~0)
2859 ("route to %U exists, fei %d, get_resolving_interface returned"
2860 " ~0", fei, format_ip4_address, &prefix.fp_addr);
2865 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnumbered */,
2867 src_address = ip_interface_address_get_address (lm4, ia);
2868 goto found_src_address;
2872 clib_warning ("FIB BUG");
2877 ip = vlib_buffer_get_current (b0);
2878 udp = (udp_header_t *) (ip + 1);
2879 dns_response = (u8 *) (udp + 1);
2880 clib_memset (ip, 0, sizeof (*ip) + sizeof (*udp));
2883 * Start with the variadic portion of the exercise.
2884 * Turn the name into a set of DNS "labels". Max length
2885 * per label is 63, enforce that.
2887 reply = name_to_labels (pr->name);
2888 vec_free (pr->name);
2890 qp_offset = vec_len (reply);
2892 /* Add space for the query header */
2893 vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
2895 qp = (dns_query_t *) (reply + qp_offset);
2897 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2898 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
2900 qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2902 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
2904 /* Punch in space for the dns_header_t */
2905 vec_insert (reply, sizeof (dns_header_t), 0);
2907 dh = (dns_header_t *) reply;
2909 /* Transaction ID = pool index */
2912 /* Announce that we did a recursive lookup */
2913 tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
2915 tmp |= DNS_RCODE_NAME_ERROR;
2916 dh->flags = clib_host_to_net_u16 (tmp);
2917 dh->qdcount = clib_host_to_net_u16 (1);
2918 dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
2922 /* If the name resolution worked, cough up an appropriate RR */
2925 /* Add the answer. First, a name pointer (0xC00C) */
2926 vec_add1 (reply, 0xC0);
2927 vec_add1 (reply, 0x0C);
2929 /* Now, add single A-rec RR */
2930 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2932 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
2933 rr = (dns_rr_t *) rrptr;
2935 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
2936 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2937 rr->ttl = clib_host_to_net_u32 (ttl);
2938 rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
2939 clib_memcpy (rr->rdata, rnr->ip4_address, sizeof (ip4_address_t));
2943 /* Or a single PTR RR */
2944 u8 *vecname = format (0, "%s", rir->name);
2945 u8 *label_vec = name_to_labels (vecname);
2948 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
2949 rr = (dns_rr_t *) rrptr;
2950 rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2951 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2952 rr->ttl = clib_host_to_net_u32 (ttl);
2953 rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
2954 clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
2955 vec_free (label_vec);
2958 clib_memcpy (dns_response, reply, vec_len (reply));
2960 /* Set the packet length */
2961 b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
2964 ip->ip_version_and_header_length = 0x45;
2965 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
2967 ip->protocol = IP_PROTOCOL_UDP;
2968 ip->src_address.as_u32 = src_address->as_u32;
2969 clib_memcpy (ip->dst_address.as_u8, pr->dst_address,
2970 sizeof (ip4_address_t));
2971 ip->checksum = ip4_header_checksum (ip);
2974 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
2975 udp->dst_port = pr->dst_port;
2976 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
2982 * Ship pkts made out of whole cloth to ip4_lookup
2983 * Caller will ship recycled dns reply packets to ip4_lookup
2985 if (is_recycle == 0)
2987 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
2988 to_next = vlib_frame_vector_args (f);
2991 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
2995 static void *vl_api_dns_enable_disable_t_print
2996 (vl_api_dns_enable_disable_t * mp, void *handle)
3000 s = format (0, "SCRIPT: dns_enable_disable ");
3001 s = format (s, "%s ", mp->enable ? "enable" : "disable");
3006 static void *vl_api_dns_name_server_add_del_t_print
3007 (vl_api_dns_name_server_add_del_t * mp, void *handle)
3011 s = format (0, "SCRIPT: dns_name_server_add_del ");
3013 s = format (s, "%U ", format_ip6_address,
3014 (ip6_address_t *) mp->server_address);
3016 s = format (s, "%U ", format_ip4_address,
3017 (ip4_address_t *) mp->server_address);
3019 if (mp->is_add == 0)
3020 s = format (s, "del ");
3025 static void *vl_api_dns_resolve_name_t_print
3026 (vl_api_dns_resolve_name_t * mp, void *handle)
3030 s = format (0, "SCRIPT: dns_resolve_name ");
3031 s = format (s, "%s ", mp->name);
3035 static void *vl_api_dns_resolve_ip_t_print
3036 (vl_api_dns_resolve_ip_t * mp, void *handle)
3040 s = format (0, "SCRIPT: dns_resolve_ip ");
3042 s = format (s, "%U ", format_ip6_address, mp->address);
3044 s = format (s, "%U ", format_ip4_address, mp->address);
3048 #include <dns/dns.api.c>
3049 static clib_error_t *
3050 dns_init (vlib_main_t * vm)
3052 dns_main_t *dm = &dns_main;
3055 dm->vnet_main = vnet_get_main ();
3056 dm->name_cache_size = 1000;
3057 dm->max_ttl_in_seconds = 86400;
3058 dm->random_seed = 0xDEADDABE;
3059 dm->api_main = vlibapi_get_main ();
3061 /* Ask for a correctly-sized block of API message decode slots */
3062 dm->msg_id_base = setup_message_id_table ();
3067 VLIB_INIT_FUNCTION (dns_init);
3070 VLIB_PLUGIN_REGISTER () =
3072 .version = VPP_BUILD_VER,
3073 .description = "Simple DNS name resolver",
3079 * fd.io coding-style-patch-verification: ON
3082 * eval: (c-set-style "gnu")