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 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
801 ep->flags = DNS_CACHE_ENTRY_FLAG_VALID | DNS_CACHE_ENTRY_FLAG_STATIC;
802 ep->dns_response = dns_reply_data;
804 dns_cache_unlock (dm);
809 vnet_dns_resolve_name (dns_main_t * dm, u8 * name, dns_pending_request_t * t,
810 dns_cache_entry_t ** retp)
812 dns_cache_entry_t *ep;
816 dns_pending_request_t *pr;
819 now = vlib_time_now (dm->vlib_main);
821 /* In case we can't actually answer the question right now... */
824 /* binary API caller might forget to set the name. Guess how we know. */
826 return VNET_API_ERROR_INVALID_VALUE;
828 dns_cache_lock (dm, 5);
830 p = hash_get_mem (dm->cache_entry_by_name, name);
833 ep = pool_elt_at_index (dm->entries, p[0]);
834 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
836 /* Has the entry expired? */
837 if (((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0)
838 && (now > ep->expiration_time))
841 u32 *indices_to_delete = 0;
844 * Take out the rest of the resolution chain
845 * This isn't optimal, but it won't happen very often.
849 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME))
851 vec_add1 (indices_to_delete, ep - dm->entries);
853 p = hash_get_mem (dm->cache_entry_by_name, ep->cname);
856 ep = pool_elt_at_index (dm->entries, p[0]);
860 vec_add1 (indices_to_delete, ep - dm->entries);
864 for (i = 0; i < vec_len (indices_to_delete); i++)
866 /* Reenable to watch re-resolutions */
869 ep = pool_elt_at_index (dm->entries,
870 indices_to_delete[i]);
871 clib_warning ("Re-resolve %s", ep->name);
874 vnet_dns_delete_entry_by_index_nolock
875 (dm, indices_to_delete[i]);
877 vec_free (indices_to_delete);
878 /* Yes, kill it... */
882 if (ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
888 dns_cache_unlock (dm);
894 * Resolution pending. Add request to the pending vector
895 * by copying the template request
897 vec_add2 (ep->pending_requests, pr, 1);
898 memcpy (pr, t, sizeof (*pr));
899 dns_cache_unlock (dm);
905 if (pool_elts (dm->entries) == dm->name_cache_size)
907 /* Will only fail if the cache is totally filled w/ static entries... */
908 rv = delete_random_entry (dm);
911 dns_cache_unlock (dm);
916 /* add new hash table entry */
917 pool_get (dm->entries, ep);
918 clib_memset (ep, 0, sizeof (*ep));
920 ep->name = format (0, "%s%c", name, 0);
921 _vec_len (ep->name) = vec_len (ep->name) - 1;
923 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
925 vec_add1 (dm->unresolved_entries, ep - dm->entries);
926 vec_add2 (ep->pending_requests, pr, 1);
928 pr->request_type = t->request_type;
930 /* Remember details so we can reply later... */
931 if (t->request_type == DNS_API_PENDING_NAME_TO_IP ||
932 t->request_type == DNS_API_PENDING_IP_TO_NAME)
934 pr->client_index = t->client_index;
935 pr->client_context = t->client_context;
939 pr->client_index = ~0;
940 pr->is_ip6 = t->is_ip6;
941 pr->dst_port = t->dst_port;
948 clib_memcpy (pr->dst_address, t->dst_address, count);
951 vnet_send_dns_request (dm, ep);
952 dns_cache_unlock (dm);
956 #define foreach_notification_to_move \
960 * Handle cname indirection. JFC. Called with the cache locked.
961 * returns 0 if the reply is not a CNAME.
965 vnet_dns_cname_indirection_nolock (dns_main_t * dm, u32 ep_index, u8 * reply)
980 dns_cache_entry_t *ep, *next_ep;
983 h = (dns_header_t *) reply;
984 flags = clib_net_to_host_u16 (h->flags);
985 rcode = flags & DNS_RCODE_MASK;
987 /* See if the response is OK */
990 case DNS_RCODE_NO_ERROR:
993 case DNS_RCODE_NAME_ERROR:
994 case DNS_RCODE_FORMAT_ERROR:
995 case DNS_RCODE_SERVER_FAILURE:
996 case DNS_RCODE_NOT_IMPLEMENTED:
997 case DNS_RCODE_REFUSED:
1001 curpos = (u8 *) (h + 1);
1005 /* Skip the questions */
1006 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
1013 pos += sizeof (dns_query_t);
1016 /* expect a pointer chase here for a CNAME record */
1017 if ((pos2[0] & 0xC0) == 0xC0)
1022 /* Walk the answer(s) to see what to do next */
1023 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
1025 rr = (dns_rr_t *) pos;
1026 switch (clib_net_to_host_u16 (rr->type))
1028 /* Real address record? Done.. */
1033 * Maybe chase a CNAME pointer?
1034 * It's not unheard-of for name-servers to return
1035 * both CNAME and A/AAAA records...
1037 case DNS_TYPE_CNAME:
1041 /* Some other junk, e.g. a nameserver... */
1045 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1047 if ((pos2[0] & 0xc0) == 0xc0)
1051 /* Neither a CNAME nor a real address. Try another server */
1054 flags &= ~DNS_RCODE_MASK;
1055 flags |= DNS_RCODE_NAME_ERROR;
1056 h->flags = clib_host_to_net_u16 (flags);
1060 /* This is a CNAME record, chase the name chain. */
1063 /* The last request is no longer pending.. */
1064 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
1065 if (ep_index == dm->unresolved_entries[i])
1067 vec_delete (dm->unresolved_entries, 1, i);
1068 goto found_last_request;
1070 clib_warning ("pool elt %d supposedly pending, but not found...", ep_index);
1075 now = vlib_time_now (dm->vlib_main);
1076 cname = vnet_dns_labels_to_name (rr->rdata, reply, &pos2);
1077 /* Save the cname */
1078 vec_add1 (cname, 0);
1079 _vec_len (cname) -= 1;
1080 ep = pool_elt_at_index (dm->entries, ep_index);
1082 ep->flags |= (DNS_CACHE_ENTRY_FLAG_CNAME | DNS_CACHE_ENTRY_FLAG_VALID);
1083 /* Save the response */
1084 if (ep->dns_response)
1085 vec_free (ep->dns_response);
1086 ep->dns_response = reply;
1087 /* Set up expiration time */
1088 ep->expiration_time = now + clib_net_to_host_u32 (rr->ttl);
1090 pool_get (dm->entries, next_ep);
1092 /* Need to recompute ep post pool-get */
1093 ep = pool_elt_at_index (dm->entries, ep_index);
1095 clib_memset (next_ep, 0, sizeof (*next_ep));
1096 next_ep->name = vec_dup (cname);
1097 vec_add1 (next_ep->name, 0);
1098 _vec_len (next_ep->name) -= 1;
1100 hash_set_mem (dm->cache_entry_by_name, next_ep->name,
1101 next_ep - dm->entries);
1103 /* Use the same server */
1104 next_ep->server_rotor = ep->server_rotor;
1105 next_ep->server_af = ep->server_af;
1107 /* Move notification data to the next name in the chain */
1108 #define _(a) next_ep->a = ep->a; ep->a = 0;
1109 foreach_notification_to_move;
1112 request = name_to_labels (cname);
1113 name_copy = vec_dup (request);
1115 qp_offset = vec_len (request);
1117 /* Add space for the query header */
1118 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
1120 qp = (dns_query_t *) (request + qp_offset);
1122 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
1123 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1124 clib_memcpy (qp, name_copy, vec_len (name_copy));
1125 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
1126 vec_free (name_copy);
1128 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1129 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1131 /* Punch in space for the dns_header_t */
1132 vec_insert (request, sizeof (dns_header_t), 0);
1134 h = (dns_header_t *) request;
1136 /* Transaction ID = pool index */
1137 h->id = clib_host_to_net_u16 (next_ep - dm->entries);
1139 /* Ask for a recursive lookup */
1140 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
1141 h->qdcount = clib_host_to_net_u16 (2);
1145 next_ep->dns_request = request;
1146 next_ep->retry_timer = now + 2.0;
1147 next_ep->retry_count = 0;
1150 * Enable this to watch recursive resolution happen...
1151 * fformat (stdout, "%U", format_dns_reply, request, 2);
1154 vec_add1 (dm->unresolved_entries, next_ep - dm->entries);
1155 vnet_send_dns_request (dm, next_ep);
1160 vnet_dns_response_to_reply (u8 * response,
1161 vl_api_dns_resolve_name_reply_t * rmp,
1169 u8 *curpos, *pos, *pos2;
1175 h = (dns_header_t *) response;
1176 flags = clib_net_to_host_u16 (h->flags);
1177 rcode = flags & DNS_RCODE_MASK;
1179 /* See if the response is OK, etc. */
1183 case DNS_RCODE_NO_ERROR:
1186 case DNS_RCODE_NAME_ERROR:
1187 case DNS_RCODE_FORMAT_ERROR:
1188 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1190 case DNS_RCODE_SERVER_FAILURE:
1191 case DNS_RCODE_NOT_IMPLEMENTED:
1192 case DNS_RCODE_REFUSED:
1193 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1196 /* No answers? Loser... */
1197 if (clib_net_to_host_u16 (h->anscount) < 1)
1198 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1200 curpos = (u8 *) (h + 1);
1202 /* Skip the name we asked about */
1205 /* Should never happen, but stil... */
1206 if ((len & 0xC0) == 0xC0)
1210 /* skip the name / label-set */
1219 limit = clib_net_to_host_u16 (h->qdcount);
1220 qp = (dns_query_t *) curpos;
1225 limit = clib_net_to_host_u16 (h->anscount);
1227 for (i = 0; i < limit; i++)
1229 pos = pos2 = curpos;
1232 /* Expect pointer chases in the answer section... */
1233 if ((pos2[0] & 0xC0) == 0xC0)
1236 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1245 if ((pos2[0] & 0xc0) == 0xc0)
1248 * If we've already done one pointer chase,
1249 * do not move the pos pointer.
1251 if (pointer_chase == 0)
1253 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1261 if (pointer_chase == 0)
1264 rr = (dns_rr_t *) pos;
1266 switch (clib_net_to_host_u16 (rr->type))
1269 /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1270 memcpy (rmp->ip4_address, rr->rdata, sizeof (ip4_address_t));
1272 ttl = clib_net_to_host_u32 (rr->ttl);
1273 if (min_ttlp && *min_ttlp > ttl)
1277 /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1278 memcpy (rmp->ip6_address, rr->rdata, sizeof (ip6_address_t));
1279 ttl = clib_net_to_host_u32 (rr->ttl);
1280 if (min_ttlp && *min_ttlp > ttl)
1288 /* Might as well stop ASAP */
1289 if (rmp->ip4_set && rmp->ip6_set)
1291 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1295 if ((rmp->ip4_set + rmp->ip6_set) == 0)
1296 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1301 vnet_dns_response_to_name (u8 * response,
1302 vl_api_dns_resolve_ip_reply_t * rmp,
1310 u8 *curpos, *pos, *pos2;
1315 u8 *junk __attribute__ ((unused));
1319 h = (dns_header_t *) response;
1320 flags = clib_net_to_host_u16 (h->flags);
1321 rcode = flags & DNS_RCODE_MASK;
1323 /* See if the response is OK, etc. */
1327 case DNS_RCODE_NO_ERROR:
1330 case DNS_RCODE_NAME_ERROR:
1331 case DNS_RCODE_FORMAT_ERROR:
1332 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1334 case DNS_RCODE_SERVER_FAILURE:
1335 case DNS_RCODE_NOT_IMPLEMENTED:
1336 case DNS_RCODE_REFUSED:
1337 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1340 /* No answers? Loser... */
1341 if (clib_net_to_host_u16 (h->anscount) < 1)
1342 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1344 curpos = (u8 *) (h + 1);
1346 /* Skip the name we asked about */
1349 /* Should never happen, but stil... */
1350 if ((len & 0xC0) == 0xC0)
1354 /* skip the name / label-set */
1363 limit = clib_net_to_host_u16 (h->qdcount);
1364 qp = (dns_query_t *) curpos;
1369 limit = clib_net_to_host_u16 (h->anscount);
1371 for (i = 0; i < limit; i++)
1373 pos = pos2 = curpos;
1376 /* Expect pointer chases in the answer section... */
1377 if ((pos2[0] & 0xC0) == 0xC0)
1380 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1389 if ((pos2[0] & 0xc0) == 0xc0)
1392 * If we've already done one pointer chase,
1393 * do not move the pos pointer.
1395 if (pointer_chase == 0)
1397 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1405 if (pointer_chase == 0)
1408 rr = (dns_rr_t *) pos;
1410 switch (clib_net_to_host_u16 (rr->type))
1413 name = vnet_dns_labels_to_name (rr->rdata, response, &junk);
1414 memcpy (rmp->name, name, vec_len (name));
1415 ttl = clib_net_to_host_u32 (rr->ttl);
1418 rmp->name[vec_len (name)] = 0;
1424 /* Might as well stop ASAP */
1427 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1432 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1437 vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1439 dns_main_t *dm = &dns_main;
1440 vl_api_dns_resolve_name_reply_t *rmp;
1441 dns_cache_entry_t *ep;
1442 dns_pending_request_t _t0, *t0 = &_t0;
1445 /* Sanitize the name slightly */
1446 mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1448 t0->request_type = DNS_API_PENDING_NAME_TO_IP;
1449 t0->client_index = mp->client_index;
1450 t0->client_context = mp->context;
1452 rv = vnet_dns_resolve_name (dm, mp->name, t0, &ep);
1454 /* Error, e.g. not enabled? Tell the user */
1457 REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1461 /* Resolution pending? Don't reply... */
1466 REPLY_MACRO2(VL_API_DNS_RESOLVE_NAME_REPLY,
1468 rv = vnet_dns_response_to_reply (ep->dns_response, rmp, 0 /* ttl-ptr */);
1469 rmp->retval = clib_host_to_net_u32 (rv);
1474 * dns_resolve_name leaves the cache locked when it returns
1475 * a cached result, so unlock it here.
1477 dns_cache_unlock (dm);
1481 vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
1483 dns_main_t *dm = &dns_main;
1484 vl_api_dns_resolve_ip_reply_t *rmp;
1485 dns_cache_entry_t *ep;
1488 u8 *lookup_name = 0;
1490 dns_pending_request_t _t0, *t0 = &_t0;
1494 for (i = 15; i >= 0; i--)
1496 digit = mp->address[i];
1497 nybble = (digit & 0x0F);
1499 vec_add1 (lookup_name, (nybble - 10) + 'a');
1501 vec_add1 (lookup_name, nybble + '0');
1502 vec_add1 (lookup_name, '.');
1503 nybble = (digit & 0xF0) >> 4;
1505 vec_add1 (lookup_name, (nybble - 10) + 'a');
1507 vec_add1 (lookup_name, nybble + '0');
1508 vec_add1 (lookup_name, '.');
1510 len = vec_len (lookup_name);
1511 vec_validate (lookup_name, len + 8);
1512 memcpy (lookup_name + len, "ip6.arpa", 8);
1516 for (i = 3; i >= 0; i--)
1518 digit = mp->address[i];
1519 lookup_name = format (lookup_name, "%d.", digit);
1521 lookup_name = format (lookup_name, "in-addr.arpa");
1524 vec_add1 (lookup_name, 0);
1526 t0->request_type = DNS_API_PENDING_IP_TO_NAME;
1527 t0->client_index = mp->client_index;
1528 t0->client_context = mp->context;
1530 rv = vnet_dns_resolve_name (dm, lookup_name, t0, &ep);
1532 vec_free (lookup_name);
1534 /* Error, e.g. not enabled? Tell the user */
1537 REPLY_MACRO (VL_API_DNS_RESOLVE_IP_REPLY);
1541 /* Resolution pending? Don't reply... */
1546 REPLY_MACRO2(VL_API_DNS_RESOLVE_IP_REPLY,
1548 rv = vnet_dns_response_to_name (ep->dns_response, rmp, 0 /* ttl-ptr */);
1549 rmp->retval = clib_host_to_net_u32 (rv);
1554 * vnet_dns_resolve_name leaves the cache locked when it returns
1555 * a cached result, so unlock it here.
1557 dns_cache_unlock (dm);
1560 static clib_error_t *
1561 dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1563 dns_main_t *dm = &dns_main;
1565 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1567 if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1569 else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1572 return clib_error_return (0, "unknown input `%U'",
1573 format_unformat_error, input);
1578 VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1581 unformat_dns_reply (unformat_input_t * input, va_list * args)
1583 u8 **result = va_arg (*args, u8 **);
1584 u8 **namep = va_arg (*args, u8 **);
1598 if (unformat (input, "%v", &name))
1601 if (unformat (input, "%U", unformat_ip4_address, &a4))
1604 if (unformat (input, "%U", unformat_ip6_address, &a6))
1608 if (unformat (input, "%U", unformat_ip6_address, &a6))
1611 if (unformat (input, "%U", unformat_ip4_address, &a6))
1615 /* Must have a name */
1619 /* Must have at least one address */
1620 if (!(a4_set + a6_set))
1623 /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1624 ce = name_to_labels (name);
1625 qp_offset = vec_len (ce);
1627 /* Add space for the query header */
1628 vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1629 qp = (dns_query_t *) (ce + qp_offset);
1631 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1632 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1634 /* Punch in space for the dns_header_t */
1635 vec_insert (ce, sizeof (dns_header_t), 0);
1637 h = (dns_header_t *) ce;
1639 /* Fake Transaction ID */
1642 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1643 h->qdcount = clib_host_to_net_u16 (1);
1644 h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1648 /* Now append one or two A/AAAA RR's... */
1651 /* Pointer to the name (DGMS) */
1652 vec_add1 (ce, 0xC0);
1653 vec_add1 (ce, 0x0C);
1654 vec_add2 (ce, rru8, sizeof (*rr) + 4);
1656 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1657 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1658 rr->ttl = clib_host_to_net_u32 (86400);
1659 rr->rdlength = clib_host_to_net_u16 (4);
1660 memcpy (rr->rdata, &a4, sizeof (a4));
1664 /* Pointer to the name (DGMS) */
1665 vec_add1 (ce, 0xC0);
1666 vec_add1 (ce, 0x0C);
1667 vec_add2 (ce, rru8, sizeof (*rr) + 16);
1669 rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1670 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1671 rr->ttl = clib_host_to_net_u32 (86400);
1672 rr->rdlength = clib_host_to_net_u16 (16);
1673 memcpy (rr->rdata, &a6, sizeof (a6));
1685 format_dns_query (u8 * s, va_list * args)
1687 u8 **curpos = va_arg (*args, u8 **);
1688 int verbose = va_arg (*args, int);
1693 s = format (s, " Name: ");
1695 /* Unwind execrated counted-label sheit */
1701 for (i = 0; i < len; i++)
1702 vec_add1 (s, *pos++);
1714 qp = (dns_query_t *) pos;
1717 switch (clib_net_to_host_u16 (qp->type))
1720 s = format (s, "type A\n");
1723 s = format (s, "type AAAA\n");
1726 s = format (s, "type ALL\n");
1730 s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1735 pos += sizeof (*qp);
1742 * format dns reply data
1743 * verbose > 1, dump everything
1744 * verbose == 1, dump all A and AAAA records
1745 * verbose == 0, dump one A record, and one AAAA record
1749 format_dns_reply_data (u8 * s, va_list * args)
1751 u8 *reply = va_arg (*args, u8 *);
1752 u8 **curpos = va_arg (*args, u8 **);
1753 int verbose = va_arg (*args, int);
1754 int *print_ip4 = va_arg (*args, int *);
1755 int *print_ip6 = va_arg (*args, int *);
1760 int pointer_chase = 0;
1762 u16 rrtype_host_byte_order;
1764 pos = pos2 = *curpos;
1767 s = format (s, " ");
1769 /* chase pointer? almost always yes here... */
1770 if ((pos2[0] & 0xc0) == 0xc0)
1773 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1781 for (i = 0; i < len; i++)
1784 vec_add1 (s, *pos2);
1787 if ((pos2[0] & 0xc0) == 0xc0)
1790 * If we've already done one pointer chase,
1791 * do not move the pos pointer.
1793 if (pointer_chase == 0)
1795 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1813 if (pointer_chase == 0)
1816 rr = (dns_rr_t *) pos;
1817 rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
1819 switch (rrtype_host_byte_order)
1824 s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1825 format_ip4_address, rr->rdata);
1830 s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1831 clib_net_to_host_u32 (rr->ttl));
1836 pos += sizeof (*rr) + 4;
1842 s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1843 format_ip6_address, rr->rdata);
1848 s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1849 clib_net_to_host_u32 (rr->ttl));
1853 pos += sizeof (*rr) + 16;
1859 s = format (s, "TEXT: ");
1860 for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1861 vec_add1 (s, rr->rdata[i]);
1864 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1867 case DNS_TYPE_HINFO:
1869 /* Two counted strings. DGMS */
1875 s = format (s, "HINFO: ");
1878 for (i = 0; i < *len; i++)
1879 vec_add1 (s, *curpos++);
1883 for (i = 0; i < *len; i++)
1884 vec_add1 (s, *curpos++);
1889 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1892 case DNS_TYPE_NAMESERVER:
1895 s = format (s, "Nameserver: ");
1898 /* chase pointer? */
1899 if ((pos2[0] & 0xc0) == 0xc0)
1902 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1909 for (i = 0; i < len; i++)
1910 vec_add1 (s, *pos2++);
1912 /* chase pointer, typically to offset 12... */
1913 if (pos2[0] == 0xC0)
1914 pos2 = reply + pos2[1];
1923 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1926 case DNS_TYPE_MAIL_EXCHANGE:
1929 tp = (u16 *) rr->rdata;
1931 s = format (s, "Mail Exchange: Preference %d ", (u32)
1932 clib_net_to_host_u16 (*tp));
1934 pos2 = rr->rdata + 2;
1936 /* chase pointer? */
1937 if (pos2[0] == 0xc0)
1938 pos2 = reply + pos2[1];
1944 for (i = 0; i < len; i++)
1945 vec_add1 (s, *pos2++);
1948 if (pos2[0] == 0xC0)
1949 pos2 = reply + pos2[1];
1959 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1963 case DNS_TYPE_CNAME:
1966 tp = (u16 *) rr->rdata;
1968 if (rrtype_host_byte_order == DNS_TYPE_CNAME)
1969 s = format (s, "CNAME: ");
1971 s = format (s, "PTR: ");
1975 /* chase pointer? */
1976 if (pos2[0] == 0xc0)
1977 pos2 = reply + pos2[1];
1983 for (i = 0; i < len; i++)
1984 vec_add1 (s, *pos2++);
1987 if (pos2[0] == 0xC0)
1988 pos2 = reply + pos2[1];
1997 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2002 s = format (s, "type %d: len %d\n",
2003 (int) clib_net_to_host_u16 (rr->type),
2004 sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
2005 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2015 format_dns_reply (u8 * s, va_list * args)
2017 u8 *reply_as_u8 = va_arg (*args, u8 *);
2018 int verbose = va_arg (*args, int);
2026 h = (dns_header_t *) reply_as_u8;
2027 id = clib_net_to_host_u16 (h->id);
2028 flags = clib_net_to_host_u16 (h->flags);
2032 s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
2034 s = format (s, " %s %s %s %s\n",
2035 (flags & DNS_RA) ? "recur" : "no-recur",
2036 (flags & DNS_RD) ? "recur-des" : "no-recur-des",
2037 (flags & DNS_TC) ? "trunc" : "no-trunc",
2038 (flags & DNS_AA) ? "auth" : "non-auth");
2039 s = format (s, " %d queries, %d answers, %d name-servers,"
2041 clib_net_to_host_u16 (h->qdcount),
2042 clib_net_to_host_u16 (h->anscount),
2043 clib_net_to_host_u16 (h->nscount),
2044 clib_net_to_host_u16 (h->arcount));
2047 curpos = (u8 *) (h + 1);
2052 s = format (s, " Queries:\n");
2053 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
2055 /* The query is variable-length, so curpos is a value-result parm */
2056 s = format (s, "%U", format_dns_query, &curpos, verbose);
2062 s = format (s, " Replies:\n");
2064 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
2066 /* curpos is a value-result parm */
2067 s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
2068 verbose, &print_ip4, &print_ip6);
2075 format_dns_cache (u8 * s, va_list * args)
2077 dns_main_t *dm = va_arg (*args, dns_main_t *);
2078 f64 now = va_arg (*args, f64);
2079 int verbose = va_arg (*args, int);
2080 u8 *name = va_arg (*args, u8 *);
2081 dns_cache_entry_t *ep;
2085 if (dm->is_enabled == 0)
2087 s = format (s, "The DNS cache is disabled...");
2091 if (pool_elts (dm->entries) == 0)
2093 s = format (s, "The DNS cache is empty...");
2097 dns_cache_lock (dm, 6);
2101 p = hash_get_mem (dm->cache_entry_by_name, name);
2104 s = format (s, "%s is not in the cache...", name);
2105 dns_cache_unlock (dm);
2109 ep = pool_elt_at_index (dm->entries, p[0]);
2110 /* Magic to spit out a C-initializer to research hemorrhoids... */
2114 s = format (s, "static u8 dns_reply_data_initializer[] =\n");
2115 s = format (s, "{\n");
2117 for (i = 0; i < vec_len (ep->dns_response); i++)
2124 s = format (s, "0x%02x, ", ep->dns_response[i]);
2126 s = format (s, "};\n");
2130 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2132 ASSERT (ep->dns_response);
2133 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2138 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2139 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2141 s = format (s, "%s%s -> %U", ss, ep->name,
2142 format_dns_reply, ep->dns_response, verbose);
2143 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2145 f64 time_left = ep->expiration_time - now;
2146 if (time_left > 0.0)
2147 s = format (s, " TTL left %.1f", time_left);
2149 s = format (s, " EXPIRED");
2154 ASSERT (ep->dns_request);
2155 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2163 s = format (s, "DNS cache contains %d entries\n", pool_elts (dm->entries));
2168 pool_foreach (ep, dm->entries,
2170 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2172 ASSERT (ep->dns_response);
2173 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2178 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2179 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2181 s = format (s, "%s%s -> %U", ss, ep->name,
2185 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2187 f64 time_left = ep->expiration_time - now;
2188 if (time_left > 0.0)
2189 s = format (s, " TTL left %.1f", time_left);
2191 s = format (s, " EXPIRED");
2194 s = format (s, " %d client notifications pending\n",
2195 vec_len(ep->pending_requests));
2200 ASSERT (ep->dns_request);
2201 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2209 dns_cache_unlock (dm);
2214 static clib_error_t *
2215 show_dns_cache_command_fn (vlib_main_t * vm,
2216 unformat_input_t * input, vlib_cli_command_t * cmd)
2218 dns_main_t *dm = &dns_main;
2221 f64 now = vlib_time_now (vm);
2223 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2225 if (unformat (input, "verbose %d", &verbose))
2227 else if (unformat (input, "verbose"))
2229 else if (unformat (input, "name %s", &name))
2232 return clib_error_return (0, "unknown input `%U'",
2233 format_unformat_error, input);
2236 vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
2242 VLIB_CLI_COMMAND (show_dns_cache_command) =
2244 .path = "show dns cache",
2245 .short_help = "show dns cache [verbose [nn]]",
2246 .function = show_dns_cache_command_fn,
2250 static clib_error_t *
2251 show_dns_servers_command_fn (vlib_main_t * vm,
2252 unformat_input_t * input,
2253 vlib_cli_command_t * cmd)
2255 dns_main_t *dm = &dns_main;
2258 if ((vec_len (dm->ip4_name_servers) + vec_len (dm->ip6_name_servers)) == 0)
2259 return clib_error_return (0, "No name servers configured...");
2261 if (vec_len (dm->ip4_name_servers))
2263 vlib_cli_output (vm, "ip4 name servers:");
2264 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
2265 vlib_cli_output (vm, "%U", format_ip4_address,
2266 dm->ip4_name_servers + i);
2268 if (vec_len (dm->ip6_name_servers))
2270 vlib_cli_output (vm, "ip6 name servers:");
2271 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
2272 vlib_cli_output (vm, "%U", format_ip6_address,
2273 dm->ip4_name_servers + i);
2279 VLIB_CLI_COMMAND (show_dns_server_command) =
2281 .path = "show dns servers",
2282 .short_help = "show dns servers",
2283 .function = show_dns_servers_command_fn,
2288 static clib_error_t *
2289 dns_cache_add_del_command_fn (vlib_main_t * vm,
2290 unformat_input_t * input,
2291 vlib_cli_command_t * cmd)
2293 dns_main_t *dm = &dns_main;
2299 clib_error_t *error;
2301 if (unformat (input, "add"))
2303 if (unformat (input, "del"))
2305 if (unformat (input, "clear"))
2308 if (is_add == -1 && is_clear == -1)
2309 return clib_error_return (0, "add / del / clear required...");
2313 rv = dns_cache_clear (dm);
2319 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2320 error = clib_error_return (0, "Name resolution not enabled");
2325 /* Delete (by name)? */
2328 if (unformat (input, "%v", &name))
2330 rv = dns_delete_by_name (dm, name);
2333 case VNET_API_ERROR_NO_SUCH_ENTRY:
2334 error = clib_error_return (0, "%v not in the cache...", name);
2338 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2339 error = clib_error_return (0, "Name resolution not enabled");
2348 error = clib_error_return (0, "dns_delete_by_name returned %d",
2354 return clib_error_return (0, "unknown input `%U'",
2355 format_unformat_error, input);
2358 /* Note: dns_add_static_entry consumes the name vector if OK... */
2359 if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2361 rv = dns_add_static_entry (dm, name, dns_reply_data);
2364 case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2366 vec_free (dns_reply_data);
2367 return clib_error_return (0, "%v already in the cache...", name);
2372 return clib_error_return (0, "dns_add_static_entry returned %d",
2381 VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2383 .path = "dns cache",
2384 .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2385 .function = dns_cache_add_del_command_fn,
2389 #define DNS_FORMAT_TEST 1
2391 #if DNS_FORMAT_TEST > 0
2394 static u8 dns_reply_data_initializer[] =
2395 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2396 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2398 0x0, 0xff, /* type ALL */
2399 0x0, 0x1, /* class IN */
2400 0xc0, 0xc, /* pointer to yahoo.com name */
2401 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2402 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2403 0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2404 0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2405 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2406 0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2407 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2408 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2409 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2410 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2411 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2412 0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2413 0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2415 0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2416 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2417 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2418 0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2419 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2421 0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2422 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2423 0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2424 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2426 0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2427 0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2429 0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2431 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2433 0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2435 0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2436 0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2437 0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2441 /* www.cisco.com, has no addresses in reply */
2442 static u8 dns_reply_data_initializer[] = {
2443 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2444 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2445 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2447 0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2448 0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2449 0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2450 0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2451 0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2454 /* bind8 (linux widget, w/ nasty double pointer chasees */
2455 static u8 dns_reply_data_initializer[] = {
2457 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08,
2459 0x00, 0x06, 0x00, 0x06, 0x0a, 0x6f, 0x72, 0x69,
2461 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77, 0x77, 0x05,
2463 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f,
2465 0x6d, 0x00, 0x00, 0xff, 0x00, 0x01, 0x0a, 0x6f,
2467 0x72, 0x69, 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77,
2469 0x77, 0x05, 0x43, 0x49, 0x53, 0x43, 0x4f, 0xc0,
2472 0x1d, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2475 0x9a, 0x00, 0x18, 0x15, 0x72, 0x63, 0x64,
2476 0x6e, 0x39, 0x2d, 0x31, 0x34, 0x70, 0x2d, 0x64, 0x63,
2477 0x7a, 0x30, 0x35, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31,
2478 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00, 0x01, 0x00,
2479 0x00, 0x05, 0x9a, 0x00, 0x1a, 0x17, 0x61, 0x6c, 0x6c,
2480 0x6e, 0x30, 0x31, 0x2d, 0x61, 0x67, 0x30, 0x39, 0x2d,
2481 0x64, 0x63, 0x7a, 0x30, 0x33, 0x6e, 0x2d, 0x67, 0x73,
2482 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00,
2483 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x10, 0x0d, 0x72,
2484 0x74, 0x70, 0x35, 0x2d, 0x64, 0x6d, 0x7a, 0x2d, 0x67,
2485 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2486 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x18, 0x15,
2487 0x6d, 0x74, 0x76, 0x35, 0x2d, 0x61, 0x70, 0x31, 0x30,
2488 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x36, 0x6e, 0x2d, 0x67,
2489 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2490 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x1b, 0x18,
2491 0x73, 0x6e, 0x67, 0x64, 0x63, 0x30, 0x31, 0x2d, 0x61,
2492 0x62, 0x30, 0x37, 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x31,
2493 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0,
2494 0x26, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a,
2495 0x00, 0x1a, 0x17, 0x61, 0x65, 0x72, 0x30, 0x31, 0x2d,
2496 0x72, 0x34, 0x63, 0x32, 0x35, 0x2d, 0x64, 0x63, 0x7a,
2497 0x30, 0x31, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0,
2498 0x17, 0xc0, 0x26, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2499 0x00, 0x81, 0x00, 0x04, 0x48, 0xa3, 0x04, 0xa1, 0xc0,
2500 0x26, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82,
2501 0x00, 0x10, 0x20, 0x01, 0x04, 0x20, 0x12, 0x01, 0x00,
2502 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
2503 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2504 0x9a, 0x00, 0x02, 0xc0, 0xf4, 0xc0, 0x0c, 0x00, 0x02,
2505 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0,
2506 0xcd, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00,
2507 0x05, 0x9a, 0x00, 0x02, 0xc0, 0x8d, 0xc0, 0x0c, 0x00,
2508 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02,
2509 0xc0, 0x43, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00,
2510 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0, 0xa9, 0xc0, 0x0c,
2511 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00,
2512 0x02, 0xc0, 0x67, 0xc0, 0x8d, 0x00, 0x01, 0x00, 0x01,
2513 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0x40, 0x66, 0xf6,
2514 0x05, 0xc0, 0xa9, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2515 0x07, 0x08, 0x00, 0x04, 0xad, 0x24, 0xe0, 0x64, 0xc0,
2516 0x43, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08,
2517 0x00, 0x04, 0x48, 0xa3, 0x04, 0x1c, 0xc0, 0xf4, 0x00,
2518 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04,
2519 0xad, 0x26, 0xd4, 0x6c, 0xc0, 0x67, 0x00, 0x01, 0x00,
2520 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x25,
2521 0x90, 0x64, 0xc0, 0xcd, 0x00, 0x01, 0x00, 0x01, 0x00,
2522 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x27, 0x70, 0x44,
2526 static u8 dns_reply_data_initializer[] =
2527 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
2528 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
2529 0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
2530 0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
2532 0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
2533 0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
2534 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
2535 0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
2536 0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
2537 0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
2538 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
2539 0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
2540 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
2541 0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
2542 0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
2543 0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
2544 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
2545 0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
2546 0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
2547 0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
2548 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2549 0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
2550 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
2551 0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
2552 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
2553 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
2554 0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
2556 0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2560 /* www.weatherlink.com */
2561 static u8 dns_reply_data_initializer[] = {
2562 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2563 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x0b,
2564 0x77, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x6c, 0x69,
2565 0x6e, 0x6b, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0xff,
2566 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00,
2567 0x00, 0x0c, 0x9e, 0x00, 0x1f, 0x0e, 0x64, 0x33, 0x6b,
2568 0x72, 0x30, 0x67, 0x75, 0x62, 0x61, 0x31, 0x64, 0x76,
2569 0x77, 0x66, 0x0a, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x66,
2570 0x72, 0x6f, 0x6e, 0x74, 0x03, 0x6e, 0x65, 0x74, 0x00,
2575 static clib_error_t *
2576 test_dns_fmt_command_fn (vlib_main_t * vm,
2577 unformat_input_t * input, vlib_cli_command_t * cmd)
2579 u8 *dns_reply_data = 0;
2582 vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2584 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2586 if (unformat (input, "verbose %d", &verbose))
2588 else if (unformat (input, "verbose"))
2591 return clib_error_return (0, "unknown input `%U'",
2592 format_unformat_error, input);
2595 vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2597 memcpy (dns_reply_data, dns_reply_data_initializer,
2598 ARRAY_LEN (dns_reply_data_initializer));
2600 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2602 clib_memset (rmp, 0, sizeof (*rmp));
2604 rv = vnet_dns_response_to_reply (dns_reply_data, rmp, 0 /* ttl-ptr */ );
2608 case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2609 vlib_cli_output (vm, "no addresses found...");
2613 vlib_cli_output (vm, "response to reply returned %d", rv);
2618 vlib_cli_output (vm, "ip4 address: %U", format_ip4_address,
2619 (ip4_address_t *) rmp->ip4_address);
2621 vlib_cli_output (vm, "ip6 address: %U", format_ip6_address,
2622 (ip6_address_t *) rmp->ip6_address);
2626 vec_free (dns_reply_data);
2633 VLIB_CLI_COMMAND (test_dns_fmt_command) =
2635 .path = "test dns format",
2636 .short_help = "test dns format",
2637 .function = test_dns_fmt_command_fn,
2641 static clib_error_t *
2642 test_dns_unfmt_command_fn (vlib_main_t * vm,
2643 unformat_input_t * input, vlib_cli_command_t * cmd)
2645 u8 *dns_reply_data = 0;
2649 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2651 if (unformat (input, "verbose %d", &verbose))
2653 else if (unformat (input, "verbose"))
2655 else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2658 return clib_error_return (0, "unknown input `%U'",
2659 format_unformat_error, input);
2663 return clib_error_return (0, "dns data not set...");
2665 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2667 vec_free (dns_reply_data);
2673 VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2675 .path = "test dns unformat",
2676 .short_help = "test dns unformat <name> [ip4][ip6]",
2677 .function = test_dns_unfmt_command_fn,
2681 static clib_error_t *
2682 test_dns_expire_command_fn (vlib_main_t * vm,
2683 unformat_input_t * input,
2684 vlib_cli_command_t * cmd)
2686 dns_main_t *dm = &dns_main;
2690 dns_cache_entry_t *ep;
2692 if (unformat (input, "%v", &name))
2695 _vec_len (name) -= 1;
2698 return clib_error_return (0, "no name provided");
2700 dns_cache_lock (dm, 7);
2702 p = hash_get_mem (dm->cache_entry_by_name, name);
2705 dns_cache_unlock (dm);
2706 e = clib_error_return (0, "%s is not in the cache...", name);
2711 ep = pool_elt_at_index (dm->entries, p[0]);
2713 ep->expiration_time = 0;
2719 VLIB_CLI_COMMAND (test_dns_expire_command) =
2721 .path = "test dns expire",
2722 .short_help = "test dns expire <name>",
2723 .function = test_dns_expire_command_fn,
2729 vnet_send_dns6_reply (dns_main_t * dm, dns_pending_request_t * pr,
2730 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2732 clib_warning ("Unimplemented...");
2737 vnet_send_dns4_reply (dns_main_t * dm, dns_pending_request_t * pr,
2738 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2740 vlib_main_t *vm = dm->vlib_main;
2742 fib_prefix_t prefix;
2743 fib_node_index_t fei;
2744 u32 sw_if_index, fib_index;
2745 ip4_main_t *im4 = &ip4_main;
2746 ip_lookup_main_t *lm4 = &im4->lookup_main;
2747 ip_interface_address_t *ia = 0;
2748 ip4_address_t *src_address;
2756 vl_api_dns_resolve_name_reply_t _rnr, *rnr = &_rnr;
2757 vl_api_dns_resolve_ip_reply_t _rir, *rir = &_rir;
2764 int is_recycle = (b0 != 0);
2766 ASSERT (ep && ep->dns_response);
2768 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2770 /* Quick and dirty way to dig up the A-record address. $$ FIXME */
2771 clib_memset (rnr, 0, sizeof (*rnr));
2772 if (vnet_dns_response_to_reply (ep->dns_response, rnr, &ttl))
2774 /* clib_warning ("response_to_reply failed..."); */
2777 if (rnr->ip4_set == 0)
2779 /* clib_warning ("No A-record..."); */
2783 else if (pr->request_type == DNS_PEER_PENDING_IP_TO_NAME)
2785 clib_memset (rir, 0, sizeof (*rir));
2786 if (vnet_dns_response_to_name (ep->dns_response, rir, &ttl))
2788 /* clib_warning ("response_to_name failed..."); */
2794 clib_warning ("Unknown request type %d", pr->request_type);
2798 /* Initialize a buffer */
2801 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2803 b0 = vlib_get_buffer (vm, bi);
2807 /* Use the buffer we were handed. Reinitialize it... */
2808 vlib_buffer_t bt = { };
2809 /* push/pop the reference count */
2810 u8 save_ref_count = b0->ref_count;
2811 vlib_buffer_copy_template (b0, &bt);
2812 b0->ref_count = save_ref_count;
2813 bi = vlib_get_buffer_index (vm, b0);
2816 if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
2817 vlib_buffer_free_one (vm, b0->next_buffer);
2820 * Reset the buffer. We recycle the DNS request packet in the cache
2821 * hit case, and reply immediately from the request node.
2823 * In the resolution-required / deferred case, resetting a freshly-allocated
2824 * buffer won't hurt. We hope.
2826 b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
2827 | VLIB_BUFFER_TOTAL_LENGTH_VALID);
2828 vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; /* "local0" */
2829 vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
2831 /* Find a FIB path to the peer we're trying to answer */
2832 clib_memcpy (&prefix.fp_addr.ip4, pr->dst_address, sizeof (ip4_address_t));
2833 prefix.fp_proto = FIB_PROTOCOL_IP4;
2836 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
2837 if (fib_index == (u32) ~ 0)
2839 clib_warning ("no fib table");
2843 fei = fib_table_lookup (fib_index, &prefix);
2845 /* Couldn't find route to destination. Bail out. */
2846 if (fei == FIB_NODE_INDEX_INVALID)
2848 clib_warning ("no route to DNS server");
2852 sw_if_index = fib_entry_get_resolving_interface (fei);
2854 if (sw_if_index == ~0)
2857 ("route to %U exists, fei %d, get_resolving_interface returned"
2858 " ~0", fei, format_ip4_address, &prefix.fp_addr);
2863 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnumbered */,
2865 src_address = ip_interface_address_get_address (lm4, ia);
2866 goto found_src_address;
2870 clib_warning ("FIB BUG");
2875 ip = vlib_buffer_get_current (b0);
2876 udp = (udp_header_t *) (ip + 1);
2877 dns_response = (u8 *) (udp + 1);
2878 clib_memset (ip, 0, sizeof (*ip) + sizeof (*udp));
2881 * Start with the variadic portion of the exercise.
2882 * Turn the name into a set of DNS "labels". Max length
2883 * per label is 63, enforce that.
2885 reply = name_to_labels (pr->name);
2886 vec_free (pr->name);
2888 qp_offset = vec_len (reply);
2890 /* Add space for the query header */
2891 vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
2893 qp = (dns_query_t *) (reply + qp_offset);
2895 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2896 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
2898 qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2900 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
2902 /* Punch in space for the dns_header_t */
2903 vec_insert (reply, sizeof (dns_header_t), 0);
2905 dh = (dns_header_t *) reply;
2907 /* Transaction ID = pool index */
2910 /* Announce that we did a recursive lookup */
2911 tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
2913 tmp |= DNS_RCODE_NAME_ERROR;
2914 dh->flags = clib_host_to_net_u16 (tmp);
2915 dh->qdcount = clib_host_to_net_u16 (1);
2916 dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
2920 /* If the name resolution worked, cough up an appropriate RR */
2923 /* Add the answer. First, a name pointer (0xC00C) */
2924 vec_add1 (reply, 0xC0);
2925 vec_add1 (reply, 0x0C);
2927 /* Now, add single A-rec RR */
2928 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2930 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
2931 rr = (dns_rr_t *) rrptr;
2933 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
2934 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2935 rr->ttl = clib_host_to_net_u32 (ttl);
2936 rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
2937 clib_memcpy (rr->rdata, rnr->ip4_address, sizeof (ip4_address_t));
2941 /* Or a single PTR RR */
2942 u8 *vecname = format (0, "%s", rir->name);
2943 u8 *label_vec = name_to_labels (vecname);
2946 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
2947 rr = (dns_rr_t *) rrptr;
2948 rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2949 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2950 rr->ttl = clib_host_to_net_u32 (ttl);
2951 rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
2952 clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
2953 vec_free (label_vec);
2956 clib_memcpy (dns_response, reply, vec_len (reply));
2958 /* Set the packet length */
2959 b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
2962 ip->ip_version_and_header_length = 0x45;
2963 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
2965 ip->protocol = IP_PROTOCOL_UDP;
2966 ip->src_address.as_u32 = src_address->as_u32;
2967 clib_memcpy (ip->dst_address.as_u8, pr->dst_address,
2968 sizeof (ip4_address_t));
2969 ip->checksum = ip4_header_checksum (ip);
2972 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
2973 udp->dst_port = pr->dst_port;
2974 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
2980 * Ship pkts made out of whole cloth to ip4_lookup
2981 * Caller will ship recycled dns reply packets to ip4_lookup
2983 if (is_recycle == 0)
2985 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
2986 to_next = vlib_frame_vector_args (f);
2989 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
2993 static void *vl_api_dns_enable_disable_t_print
2994 (vl_api_dns_enable_disable_t * mp, void *handle)
2998 s = format (0, "SCRIPT: dns_enable_disable ");
2999 s = format (s, "%s ", mp->enable ? "enable" : "disable");
3004 static void *vl_api_dns_name_server_add_del_t_print
3005 (vl_api_dns_name_server_add_del_t * mp, void *handle)
3009 s = format (0, "SCRIPT: dns_name_server_add_del ");
3011 s = format (s, "%U ", format_ip6_address,
3012 (ip6_address_t *) mp->server_address);
3014 s = format (s, "%U ", format_ip4_address,
3015 (ip4_address_t *) mp->server_address);
3017 if (mp->is_add == 0)
3018 s = format (s, "del ");
3023 static void *vl_api_dns_resolve_name_t_print
3024 (vl_api_dns_resolve_name_t * mp, void *handle)
3028 s = format (0, "SCRIPT: dns_resolve_name ");
3029 s = format (s, "%s ", mp->name);
3033 static void *vl_api_dns_resolve_ip_t_print
3034 (vl_api_dns_resolve_ip_t * mp, void *handle)
3038 s = format (0, "SCRIPT: dns_resolve_ip ");
3040 s = format (s, "%U ", format_ip6_address, mp->address);
3042 s = format (s, "%U ", format_ip4_address, mp->address);
3046 #include <dns/dns.api.c>
3047 static clib_error_t *
3048 dns_init (vlib_main_t * vm)
3050 dns_main_t *dm = &dns_main;
3053 dm->vnet_main = vnet_get_main ();
3054 dm->name_cache_size = 1000;
3055 dm->max_ttl_in_seconds = 86400;
3056 dm->random_seed = 0xDEADDABE;
3057 dm->api_main = &api_main;
3059 /* Ask for a correctly-sized block of API message decode slots */
3060 dm->msg_id_base = setup_message_id_table ();
3065 VLIB_INIT_FUNCTION (dns_init);
3068 VLIB_PLUGIN_REGISTER () =
3070 .version = VPP_BUILD_VER,
3071 .description = "Simple DNS name resolver",
3077 * fd.io coding-style-patch-verification: ON
3080 * eval: (c-set-style "gnu")