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/dns/dns.h>
18 #include <vnet/vnet.h>
19 #include <vnet/fib/fib.h>
20 #include <vlibmemory/api.h>
22 #include <vnet/udp/udp.h>
24 #include <vnet/vnet_msg_enum.h>
26 #define vl_typedefs /* define message structures */
27 #include <vnet/vnet_all_api_h.h>
30 #define vl_endianfun /* define message structures */
31 #include <vnet/vnet_all_api_h.h>
34 /* instantiate all the print functions we know about */
35 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
37 #include <vnet/vnet_all_api_h.h>
40 #include <vlibapi/api_helper_macros.h>
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;
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 dm->cache_lock = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
107 CLIB_CACHE_LINE_BYTES);
109 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
116 dns_cache_clear (dm);
122 static void vl_api_dns_enable_disable_t_handler
123 (vl_api_dns_enable_disable_t * mp)
125 vl_api_dns_enable_disable_reply_t *rmp;
126 dns_main_t *dm = &dns_main;
129 rv = dns_enable_disable (dm, mp->enable);
131 REPLY_MACRO (VL_API_DNS_ENABLE_DISABLE_REPLY);
135 dns6_name_server_add_del (dns_main_t * dm,
136 u8 * server_address_as_u8, int is_add)
143 /* Already there? done... */
144 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
146 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
147 sizeof (ip6_address_t)))
151 vec_add2 (dm->ip6_name_servers, ap, 1);
152 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
156 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
158 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
159 sizeof (ip6_address_t)))
161 vec_delete (dm->ip6_name_servers, 1, i);
165 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
171 dns4_name_server_add_del (dns_main_t * dm,
172 u8 * server_address_as_u8, int is_add)
179 /* Already there? done... */
180 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
182 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
183 sizeof (ip4_address_t)))
187 vec_add2 (dm->ip4_name_servers, ap, 1);
188 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
192 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
194 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
195 sizeof (ip4_address_t)))
197 vec_delete (dm->ip4_name_servers, 1, i);
201 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
206 static void vl_api_dns_name_server_add_del_t_handler
207 (vl_api_dns_name_server_add_del_t * mp)
209 dns_main_t *dm = &dns_main;
210 vl_api_dns_name_server_add_del_reply_t *rmp;
214 rv = dns6_name_server_add_del (dm, mp->server_address, mp->is_add);
216 rv = dns4_name_server_add_del (dm, mp->server_address, mp->is_add);
218 REPLY_MACRO (VL_API_DNS_NAME_SERVER_ADD_DEL_REPLY);
222 vnet_dns_send_dns4_request (dns_main_t * dm,
223 dns_cache_entry_t * ep, ip4_address_t * server)
225 vlib_main_t *vm = dm->vlib_main;
226 f64 now = vlib_time_now (vm);
231 fib_node_index_t fei;
232 u32 sw_if_index, fib_index;
234 ip4_main_t *im4 = &ip4_main;
235 ip_lookup_main_t *lm4 = &im4->lookup_main;
236 ip_interface_address_t *ia = 0;
237 ip4_address_t *src_address;
242 ASSERT (ep->dns_request);
244 /* Find a FIB path to the server */
245 clib_memcpy (&prefix.fp_addr.ip4, server, sizeof (*server));
246 prefix.fp_proto = FIB_PROTOCOL_IP4;
249 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
250 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)
261 clib_warning ("no route to DNS server");
265 sw_if_index = fib_entry_get_resolving_interface (fei);
267 if (sw_if_index == ~0)
270 ("route to %U exists, fei %d, get_resolving_interface returned"
271 " ~0", format_ip4_address, &prefix.fp_addr, fei);
276 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnumbered */,
278 src_address = ip_interface_address_get_address (lm4, ia);
279 goto found_src_address;
283 clib_warning ("FIB BUG");
288 /* Go get a buffer */
289 if (vlib_buffer_alloc (dm->vlib_main, &bi, 1) != 1)
292 b = vlib_get_buffer (vm, bi);
293 b->current_length = sizeof (ip4_header_t) + sizeof (udp_header_t) +
294 vec_len (ep->dns_request);
295 b->total_length_not_including_first_buffer = 0;
297 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
298 vnet_buffer (b)->sw_if_index[VLIB_RX] = 0; /* "local0" */
299 vnet_buffer (b)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
301 ip = vlib_buffer_get_current (b);
302 clib_memset (ip, 0, sizeof (*ip));
303 udp = (udp_header_t *) (ip + 1);
304 clib_memset (udp, 0, sizeof (*udp));
306 dns_request = (u8 *) (udp + 1);
309 ip->ip_version_and_header_length = 0x45;
310 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b));
312 ip->protocol = IP_PROTOCOL_UDP;
313 ip->src_address.as_u32 = src_address->as_u32;
314 ip->dst_address.as_u32 = server->as_u32;
315 ip->checksum = ip4_header_checksum (ip);
318 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
319 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
320 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
321 vec_len (ep->dns_request));
324 /* The actual DNS request */
325 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
327 /* Ship it to ip4_lookup */
328 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
329 to_next = vlib_frame_vector_args (f);
332 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
334 ep->retry_timer = now + 2.0;
338 vnet_dns_send_dns6_request (dns_main_t * dm,
339 dns_cache_entry_t * ep, ip6_address_t * server)
341 vlib_main_t *vm = dm->vlib_main;
342 f64 now = vlib_time_now (vm);
347 fib_node_index_t fei;
348 u32 sw_if_index, fib_index;
350 ip6_main_t *im6 = &ip6_main;
351 ip_lookup_main_t *lm6 = &im6->lookup_main;
352 ip_interface_address_t *ia = 0;
353 ip6_address_t *src_address;
357 int junk __attribute__ ((unused));
359 ASSERT (ep->dns_request);
361 /* Find a FIB path to the server */
362 clib_memcpy (&prefix.fp_addr, server, sizeof (*server));
363 prefix.fp_proto = FIB_PROTOCOL_IP6;
366 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
367 if (fib_index == (u32) ~ 0)
369 clib_warning ("no fib table");
373 fei = fib_table_lookup (fib_index, &prefix);
375 /* Couldn't find route to destination. Bail out. */
376 if (fei == FIB_NODE_INDEX_INVALID)
378 clib_warning ("no route to DNS server");
381 sw_if_index = fib_entry_get_resolving_interface (fei);
384 foreach_ip_interface_address(lm6, ia, sw_if_index, 1 /* honor unnumbered */,
386 src_address = ip_interface_address_get_address (lm6, ia);
387 goto found_src_address;
391 clib_warning ("FIB BUG");
396 /* Go get a buffer */
397 if (vlib_buffer_alloc (dm->vlib_main, &bi, 1) != 1)
400 b = vlib_get_buffer (vm, bi);
401 b->current_length = sizeof (ip6_header_t) + sizeof (udp_header_t) +
402 vec_len (ep->dns_request);
403 b->total_length_not_including_first_buffer = 0;
405 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
407 ip = vlib_buffer_get_current (b);
408 clib_memset (ip, 0, sizeof (*ip));
409 udp = (udp_header_t *) (ip + 1);
410 clib_memset (udp, 0, sizeof (*udp));
412 dns_request = (u8 *) (udp + 1);
415 ip->ip_version_traffic_class_and_flow_label =
416 clib_host_to_net_u32 (0x6 << 28);
419 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b)
420 - sizeof (ip6_header_t));
422 ip->protocol = IP_PROTOCOL_UDP;
423 clib_memcpy (&ip->src_address, src_address, sizeof (ip6_address_t));
424 clib_memcpy (&ip->dst_address, server, sizeof (ip6_address_t));
427 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
428 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
429 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
430 vec_len (ep->dns_request));
432 udp->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ip, &junk);
434 /* The actual DNS request */
435 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
437 /* Ship it to ip6_lookup */
438 f = vlib_get_frame_to_node (vm, ip6_lookup_node.index);
439 to_next = vlib_frame_vector_args (f);
443 ep->retry_timer = now + 2.0;
447 * Translate "foo.com" into "0x3 f o o 0x3 c o m 0x0"
448 * A historical / hysterical micro-TLV scheme. DGMS.
451 name_to_labels (u8 * name)
454 int last_label_index;
459 /* punch in space for the first length */
460 vec_insert (rv, 1, 0);
461 last_label_index = 0;
464 while (i < vec_len (rv))
468 rv[last_label_index] = (i - last_label_index) - 1;
469 if ((i - last_label_index) > 63)
470 clib_warning ("stupid name, label length %d",
471 i - last_label_index);
472 last_label_index = i;
477 /* Set the last real label length */
478 rv[last_label_index] = (i - last_label_index) - 1;
481 * Add a [sic] NULL root label. Otherwise, the name parser can't figure out
489 * arc-function for the above.
490 * Translate "0x3 f o o 0x3 c o m 0x0" into "foo.com"
491 * Produces a non-NULL-terminated u8 *vector. %v format is your friend.
494 vnet_dns_labels_to_name (u8 * label, u8 * full_text, u8 ** parse_from_here)
501 *parse_from_here = 0;
503 /* chase initial pointer? */
504 if ((label[0] & 0xC0) == 0xC0)
506 *parse_from_here = label + 2;
507 offset = ((label[0] & 0x3f) << 8) + label[1];
508 label = full_text + offset;
515 for (i = 0; i < len; i++)
516 vec_add1 (reply, *label++);
519 if ((label[0] & 0xC0) == 0xC0)
521 *parse_from_here = label + 2;
522 offset = ((label[0] & 0x3f) << 8) + label[1];
523 label = full_text + offset;
528 vec_add1 (reply, '.');
530 if (*parse_from_here == 0)
531 *parse_from_here = label;
536 vnet_send_dns_request (dns_main_t * dm, dns_cache_entry_t * ep)
541 u8 *request, *name_copy;
544 /* This can easily happen if sitting in GDB, etc. */
545 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID || ep->server_fails > 1)
548 /* Construct the dns request, if we haven't been here already */
549 if (vec_len (ep->dns_request) == 0)
552 * Start with the variadic portion of the exercise.
553 * Turn the name into a set of DNS "labels". Max length
554 * per label is 63, enforce that.
556 request = name_to_labels (ep->name);
557 name_copy = vec_dup (request);
558 qp_offset = vec_len (request);
561 * At least when testing against "known good" DNS servers:
562 * it turns out that sending 2x requests - one for an A-record
563 * and another for a AAAA-record - seems to work better than
564 * sending a DNS_TYPE_ALL request.
567 /* Add space for the query header */
568 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
570 qp = (dns_query_t *) (request + qp_offset);
572 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
573 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
575 clib_memcpy (qp, name_copy, vec_len (name_copy));
576 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
577 vec_free (name_copy);
579 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
580 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
582 /* Punch in space for the dns_header_t */
583 vec_insert (request, sizeof (dns_header_t), 0);
585 h = (dns_header_t *) request;
587 /* Transaction ID = pool index */
588 h->id = clib_host_to_net_u16 (ep - dm->entries);
590 /* Ask for a recursive lookup */
591 tmp = DNS_RD | DNS_OPCODE_QUERY;
592 h->flags = clib_host_to_net_u16 (tmp);
593 h->qdcount = clib_host_to_net_u16 (2);
597 ep->dns_request = request;
600 /* Work out which server / address family we're going to use */
602 /* Retry using current server */
603 if (ep->retry_count++ < DNS_RETRIES_PER_SERVER)
605 if (ep->server_af == 1 /* ip6 */ )
607 if (vec_len (dm->ip6_name_servers))
609 vnet_dns_send_dns6_request
610 (dm, ep, dm->ip6_name_servers + ep->server_rotor);
616 if (vec_len (dm->ip4_name_servers))
618 vnet_dns_send_dns4_request
619 (dm, ep, dm->ip4_name_servers + ep->server_rotor);
623 else /* switch to a new server */
627 if (ep->server_af == 1 /* ip6 */ )
629 if (ep->server_rotor >= vec_len (dm->ip6_name_servers))
631 ep->server_rotor = 0;
632 ep->server_af = vec_len (dm->ip4_name_servers) > 0 ? 0 : 1;
637 if (ep->server_rotor >= vec_len (dm->ip4_name_servers))
639 ep->server_rotor = 0;
640 ep->server_af = vec_len (dm->ip6_name_servers) > 0 ? 1 : 0;
645 if (ep->server_af == 1 /* ip6 */ )
646 vnet_dns_send_dns6_request
647 (dm, ep, dm->ip6_name_servers + ep->server_rotor);
649 vnet_dns_send_dns4_request
650 (dm, ep, dm->ip4_name_servers + ep->server_rotor);
654 vlib_process_signal_event_mt (dm->vlib_main, dns_resolver_node.index,
655 DNS_RESOLVER_EVENT_PENDING, 0);
659 vnet_dns_delete_entry_by_index_nolock (dns_main_t * dm, u32 index)
661 dns_cache_entry_t *ep;
664 if (dm->is_enabled == 0)
665 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
667 if (pool_is_free_index (dm->entries, index))
668 return VNET_API_ERROR_NO_SUCH_ENTRY;
670 ep = pool_elt_at_index (dm->entries, index);
671 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_VALID))
673 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
674 if (index == dm->unresolved_entries[i])
676 vec_delete (dm->unresolved_entries, 1, i);
679 clib_warning ("pool elt %d supposedly pending, but not found...",
684 hash_unset_mem (dm->cache_entry_by_name, ep->name);
686 vec_free (ep->pending_requests);
687 pool_put (dm->entries, ep);
693 dns_delete_by_name (dns_main_t * dm, u8 * name)
698 if (dm->is_enabled == 0)
699 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
702 p = hash_get_mem (dm->cache_entry_by_name, name);
705 dns_cache_unlock (dm);
706 return VNET_API_ERROR_NO_SUCH_ENTRY;
708 rv = vnet_dns_delete_entry_by_index_nolock (dm, p[0]);
710 dns_cache_unlock (dm);
716 delete_random_entry (dns_main_t * dm)
719 u32 victim_index, start_index, i;
721 dns_cache_entry_t *ep;
723 if (dm->is_enabled == 0)
724 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
727 * Silence spurious coverity warning. We know pool_elts >> 0, or
728 * we wouldn't be here...
731 if (pool_elts (dm->entries) == 0)
732 return VNET_API_ERROR_UNSPECIFIED;
736 limit = pool_elts (dm->entries);
737 start_index = random_u32 (&dm->random_seed) % limit;
739 for (i = 0; i < limit; i++)
741 victim_index = (start_index + i) % limit;
743 if (!pool_is_free_index (dm->entries, victim_index))
745 ep = pool_elt_at_index (dm->entries, victim_index);
746 /* Delete only valid, non-static entries */
747 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
748 && ((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0))
750 rv = vnet_dns_delete_entry_by_index_nolock (dm, victim_index);
751 dns_cache_unlock (dm);
756 dns_cache_unlock (dm);
758 clib_warning ("Couldn't find an entry to delete?");
759 return VNET_API_ERROR_UNSPECIFIED;
763 dns_add_static_entry (dns_main_t * dm, u8 * name, u8 * dns_reply_data)
765 dns_cache_entry_t *ep;
769 if (dm->is_enabled == 0)
770 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
773 p = hash_get_mem (dm->cache_entry_by_name, name);
776 dns_cache_unlock (dm);
777 return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
780 if (pool_elts (dm->entries) == dm->name_cache_size)
782 /* Will only fail if the cache is totally filled w/ static entries... */
783 rv = delete_random_entry (dm);
786 dns_cache_unlock (dm);
791 pool_get (dm->entries, ep);
792 clib_memset (ep, 0, sizeof (*ep));
794 /* Note: consumes the name vector */
796 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
797 ep->flags = DNS_CACHE_ENTRY_FLAG_VALID | DNS_CACHE_ENTRY_FLAG_STATIC;
798 ep->dns_response = dns_reply_data;
800 dns_cache_unlock (dm);
805 vnet_dns_resolve_name (dns_main_t * dm, u8 * name, dns_pending_request_t * t,
806 dns_cache_entry_t ** retp)
808 dns_cache_entry_t *ep;
812 dns_pending_request_t *pr;
815 now = vlib_time_now (dm->vlib_main);
817 /* In case we can't actually answer the question right now... */
822 p = hash_get_mem (dm->cache_entry_by_name, name);
825 ep = pool_elt_at_index (dm->entries, p[0]);
826 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
828 /* Has the entry expired? */
829 if (((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0)
830 && (now > ep->expiration_time))
833 u32 *indices_to_delete = 0;
836 * Take out the rest of the resolution chain
837 * This isn't optimal, but it won't happen very often.
841 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME))
843 vec_add1 (indices_to_delete, ep - dm->entries);
845 p = hash_get_mem (dm->cache_entry_by_name, ep->cname);
848 ep = pool_elt_at_index (dm->entries, p[0]);
852 vec_add1 (indices_to_delete, ep - dm->entries);
856 for (i = 0; i < vec_len (indices_to_delete); i++)
858 /* Reenable to watch re-resolutions */
861 ep = pool_elt_at_index (dm->entries,
862 indices_to_delete[i]);
863 clib_warning ("Re-resolve %s", ep->name);
866 vnet_dns_delete_entry_by_index_nolock
867 (dm, indices_to_delete[i]);
869 vec_free (indices_to_delete);
870 /* Yes, kill it... */
874 if (ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
880 /* Note: caller must drop the lock! */
887 * Resolution pending. Add request to the pending vector
888 * by copying the template request
890 vec_add2 (ep->pending_requests, pr, 1);
891 memcpy (pr, t, sizeof (*pr));
892 dns_cache_unlock (dm);
898 if (pool_elts (dm->entries) == dm->name_cache_size)
900 /* Will only fail if the cache is totally filled w/ static entries... */
901 rv = delete_random_entry (dm);
904 dns_cache_unlock (dm);
909 /* add new hash table entry */
910 pool_get (dm->entries, ep);
911 clib_memset (ep, 0, sizeof (*ep));
913 ep->name = format (0, "%s%c", name, 0);
914 _vec_len (ep->name) = vec_len (ep->name) - 1;
916 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
918 vec_add1 (dm->unresolved_entries, ep - dm->entries);
919 vec_add2 (ep->pending_requests, pr, 1);
921 pr->request_type = t->request_type;
923 /* Remember details so we can reply later... */
924 if (t->request_type == DNS_API_PENDING_NAME_TO_IP ||
925 t->request_type == DNS_API_PENDING_IP_TO_NAME)
927 pr->client_index = t->client_index;
928 pr->client_context = t->client_context;
932 pr->client_index = ~0;
933 pr->is_ip6 = t->is_ip6;
934 pr->dst_port = t->dst_port;
941 clib_memcpy (pr->dst_address, t->dst_address, count);
944 vnet_send_dns_request (dm, ep);
945 dns_cache_unlock (dm);
949 #define foreach_notification_to_move \
953 * Handle cname indirection. JFC. Called with the cache locked.
954 * returns 0 if the reply is not a CNAME.
958 vnet_dns_cname_indirection_nolock (dns_main_t * dm, u32 ep_index, u8 * reply)
973 dns_cache_entry_t *ep, *next_ep;
976 h = (dns_header_t *) reply;
977 flags = clib_net_to_host_u16 (h->flags);
978 rcode = flags & DNS_RCODE_MASK;
980 /* See if the response is OK */
983 case DNS_RCODE_NO_ERROR:
986 case DNS_RCODE_NAME_ERROR:
987 case DNS_RCODE_FORMAT_ERROR:
988 case DNS_RCODE_SERVER_FAILURE:
989 case DNS_RCODE_NOT_IMPLEMENTED:
990 case DNS_RCODE_REFUSED:
994 curpos = (u8 *) (h + 1);
998 /* Skip the questions */
999 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
1006 pos += sizeof (dns_query_t);
1009 /* expect a pointer chase here for a CNAME record */
1010 if ((pos2[0] & 0xC0) == 0xC0)
1015 /* Walk the answer(s) to see what to do next */
1016 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
1018 rr = (dns_rr_t *) pos;
1019 switch (clib_net_to_host_u16 (rr->type))
1021 /* Real address record? Done.. */
1026 * Maybe chase a CNAME pointer?
1027 * It's not unheard-of for name-servers to return
1028 * both CNAME and A/AAAA records...
1030 case DNS_TYPE_CNAME:
1034 /* Some other junk, e.g. a nameserver... */
1038 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1040 if ((pos2[0] & 0xc0) == 0xc0)
1044 /* Neither a CNAME nor a real address. Try another server */
1047 flags &= ~DNS_RCODE_MASK;
1048 flags |= DNS_RCODE_NAME_ERROR;
1049 h->flags = clib_host_to_net_u16 (flags);
1053 /* This is a CNAME record, chase the name chain. */
1056 /* The last request is no longer pending.. */
1057 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
1058 if (ep_index == dm->unresolved_entries[i])
1060 vec_delete (dm->unresolved_entries, 1, i);
1061 goto found_last_request;
1063 clib_warning ("pool elt %d supposedly pending, but not found...", ep_index);
1067 now = vlib_time_now (dm->vlib_main);
1068 cname = vnet_dns_labels_to_name (rr->rdata, reply, &pos2);
1069 /* Save the cname */
1070 vec_add1 (cname, 0);
1071 _vec_len (cname) -= 1;
1072 ep = pool_elt_at_index (dm->entries, ep_index);
1074 ep->flags |= (DNS_CACHE_ENTRY_FLAG_CNAME | DNS_CACHE_ENTRY_FLAG_VALID);
1075 /* Save the response */
1076 if (ep->dns_response)
1077 vec_free (ep->dns_response);
1078 ep->dns_response = reply;
1079 /* Set up expiration time */
1080 ep->expiration_time = now + clib_net_to_host_u32 (rr->ttl);
1082 pool_get (dm->entries, next_ep);
1084 /* Need to recompute ep post pool-get */
1085 ep = pool_elt_at_index (dm->entries, ep_index);
1087 clib_memset (next_ep, 0, sizeof (*next_ep));
1088 next_ep->name = vec_dup (cname);
1089 vec_add1 (next_ep->name, 0);
1090 _vec_len (next_ep->name) -= 1;
1092 hash_set_mem (dm->cache_entry_by_name, next_ep->name,
1093 next_ep - dm->entries);
1095 /* Use the same server */
1096 next_ep->server_rotor = ep->server_rotor;
1097 next_ep->server_af = ep->server_af;
1099 /* Move notification data to the next name in the chain */
1100 #define _(a) next_ep->a = ep->a; ep->a = 0;
1101 foreach_notification_to_move;
1104 request = name_to_labels (cname);
1105 name_copy = vec_dup (request);
1107 qp_offset = vec_len (request);
1109 /* Add space for the query header */
1110 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
1112 qp = (dns_query_t *) (request + qp_offset);
1114 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
1115 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1116 clib_memcpy (qp, name_copy, vec_len (name_copy));
1117 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
1118 vec_free (name_copy);
1120 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1121 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1123 /* Punch in space for the dns_header_t */
1124 vec_insert (request, sizeof (dns_header_t), 0);
1126 h = (dns_header_t *) request;
1128 /* Transaction ID = pool index */
1129 h->id = clib_host_to_net_u16 (next_ep - dm->entries);
1131 /* Ask for a recursive lookup */
1132 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
1133 h->qdcount = clib_host_to_net_u16 (2);
1137 next_ep->dns_request = request;
1138 next_ep->retry_timer = now + 2.0;
1139 next_ep->retry_count = 0;
1142 * Enable this to watch recursive resolution happen...
1143 * fformat (stdout, "%U", format_dns_reply, request, 2);
1146 vec_add1 (dm->unresolved_entries, next_ep - dm->entries);
1147 vnet_send_dns_request (dm, next_ep);
1152 vnet_dns_response_to_reply (u8 * response,
1153 vl_api_dns_resolve_name_reply_t * rmp,
1161 u8 *curpos, *pos, *pos2;
1167 h = (dns_header_t *) response;
1168 flags = clib_net_to_host_u16 (h->flags);
1169 rcode = flags & DNS_RCODE_MASK;
1171 /* See if the response is OK, etc. */
1175 case DNS_RCODE_NO_ERROR:
1178 case DNS_RCODE_NAME_ERROR:
1179 case DNS_RCODE_FORMAT_ERROR:
1180 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1182 case DNS_RCODE_SERVER_FAILURE:
1183 case DNS_RCODE_NOT_IMPLEMENTED:
1184 case DNS_RCODE_REFUSED:
1185 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1188 /* No answers? Loser... */
1189 if (clib_net_to_host_u16 (h->anscount) < 1)
1190 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1192 curpos = (u8 *) (h + 1);
1194 /* Skip the name we asked about */
1197 /* Should never happen, but stil... */
1198 if ((len & 0xC0) == 0xC0)
1202 /* skip the name / label-set */
1211 limit = clib_net_to_host_u16 (h->qdcount);
1212 qp = (dns_query_t *) curpos;
1217 limit = clib_net_to_host_u16 (h->anscount);
1219 for (i = 0; i < limit; i++)
1221 pos = pos2 = curpos;
1224 /* Expect pointer chases in the answer section... */
1225 if ((pos2[0] & 0xC0) == 0xC0)
1228 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1237 if ((pos2[0] & 0xc0) == 0xc0)
1240 * If we've already done one pointer chase,
1241 * do not move the pos pointer.
1243 if (pointer_chase == 0)
1245 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1253 if (pointer_chase == 0)
1256 rr = (dns_rr_t *) pos;
1258 switch (clib_net_to_host_u16 (rr->type))
1261 /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1262 memcpy (rmp->ip4_address, rr->rdata, sizeof (ip4_address_t));
1264 ttl = clib_net_to_host_u32 (rr->ttl);
1265 if (min_ttlp && *min_ttlp > ttl)
1269 /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1270 memcpy (rmp->ip6_address, rr->rdata, sizeof (ip6_address_t));
1271 ttl = clib_net_to_host_u32 (rr->ttl);
1272 if (min_ttlp && *min_ttlp > ttl)
1280 /* Might as well stop ASAP */
1281 if (rmp->ip4_set && rmp->ip6_set)
1283 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1287 if ((rmp->ip4_set + rmp->ip6_set) == 0)
1288 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1293 vnet_dns_response_to_name (u8 * response,
1294 vl_api_dns_resolve_ip_reply_t * rmp,
1302 u8 *curpos, *pos, *pos2;
1307 u8 *junk __attribute__ ((unused));
1311 h = (dns_header_t *) response;
1312 flags = clib_net_to_host_u16 (h->flags);
1313 rcode = flags & DNS_RCODE_MASK;
1315 /* See if the response is OK, etc. */
1319 case DNS_RCODE_NO_ERROR:
1322 case DNS_RCODE_NAME_ERROR:
1323 case DNS_RCODE_FORMAT_ERROR:
1324 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1326 case DNS_RCODE_SERVER_FAILURE:
1327 case DNS_RCODE_NOT_IMPLEMENTED:
1328 case DNS_RCODE_REFUSED:
1329 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1332 /* No answers? Loser... */
1333 if (clib_net_to_host_u16 (h->anscount) < 1)
1334 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1336 curpos = (u8 *) (h + 1);
1338 /* Skip the name we asked about */
1341 /* Should never happen, but stil... */
1342 if ((len & 0xC0) == 0xC0)
1346 /* skip the name / label-set */
1355 limit = clib_net_to_host_u16 (h->qdcount);
1356 qp = (dns_query_t *) curpos;
1361 limit = clib_net_to_host_u16 (h->anscount);
1363 for (i = 0; i < limit; i++)
1365 pos = pos2 = curpos;
1368 /* Expect pointer chases in the answer section... */
1369 if ((pos2[0] & 0xC0) == 0xC0)
1372 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1381 if ((pos2[0] & 0xc0) == 0xc0)
1384 * If we've already done one pointer chase,
1385 * do not move the pos pointer.
1387 if (pointer_chase == 0)
1389 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1397 if (pointer_chase == 0)
1400 rr = (dns_rr_t *) pos;
1402 switch (clib_net_to_host_u16 (rr->type))
1405 name = vnet_dns_labels_to_name (rr->rdata, response, &junk);
1406 memcpy (rmp->name, name, vec_len (name));
1407 ttl = clib_net_to_host_u32 (rr->ttl);
1410 rmp->name[vec_len (name)] = 0;
1416 /* Might as well stop ASAP */
1419 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1424 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1429 vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1431 dns_main_t *dm = &dns_main;
1432 vl_api_dns_resolve_name_reply_t *rmp;
1433 dns_cache_entry_t *ep;
1434 dns_pending_request_t _t0, *t0 = &_t0;
1437 /* Sanitize the name slightly */
1438 mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1440 t0->request_type = DNS_API_PENDING_NAME_TO_IP;
1441 t0->client_index = mp->client_index;
1442 t0->client_context = mp->context;
1444 rv = vnet_dns_resolve_name (dm, mp->name, t0, &ep);
1446 /* Error, e.g. not enabled? Tell the user */
1449 REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1453 /* Resolution pending? Don't reply... */
1458 REPLY_MACRO2(VL_API_DNS_RESOLVE_NAME_REPLY,
1460 rv = vnet_dns_response_to_reply (ep->dns_response, rmp, 0 /* ttl-ptr */);
1461 rmp->retval = clib_host_to_net_u32 (rv);
1466 * dns_resolve_name leaves the cache locked when it returns
1467 * a cached result, so unlock it here.
1469 dns_cache_unlock (dm);
1473 vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
1475 dns_main_t *dm = &dns_main;
1476 vl_api_dns_resolve_ip_reply_t *rmp;
1477 dns_cache_entry_t *ep;
1480 u8 *lookup_name = 0;
1482 dns_pending_request_t _t0, *t0 = &_t0;
1486 for (i = 15; i >= 0; i--)
1488 digit = mp->address[i];
1489 nybble = (digit & 0x0F);
1491 vec_add1 (lookup_name, (nybble - 10) + 'a');
1493 vec_add1 (lookup_name, nybble + '0');
1494 vec_add1 (lookup_name, '.');
1495 nybble = (digit & 0xF0) >> 4;
1497 vec_add1 (lookup_name, (nybble - 10) + 'a');
1499 vec_add1 (lookup_name, nybble + '0');
1500 vec_add1 (lookup_name, '.');
1502 len = vec_len (lookup_name);
1503 vec_validate (lookup_name, len + 8);
1504 memcpy (lookup_name + len, "ip6.arpa", 8);
1508 for (i = 3; i >= 0; i--)
1510 digit = mp->address[i];
1511 lookup_name = format (lookup_name, "%d.", digit);
1513 lookup_name = format (lookup_name, "in-addr.arpa");
1516 vec_add1 (lookup_name, 0);
1518 t0->request_type = DNS_API_PENDING_IP_TO_NAME;
1519 t0->client_index = mp->client_index;
1520 t0->client_context = mp->context;
1522 rv = vnet_dns_resolve_name (dm, lookup_name, t0, &ep);
1524 vec_free (lookup_name);
1526 /* Error, e.g. not enabled? Tell the user */
1529 REPLY_MACRO (VL_API_DNS_RESOLVE_IP_REPLY);
1533 /* Resolution pending? Don't reply... */
1538 REPLY_MACRO2(VL_API_DNS_RESOLVE_IP_REPLY,
1540 rv = vnet_dns_response_to_name (ep->dns_response, rmp, 0 /* ttl-ptr */);
1541 rmp->retval = clib_host_to_net_u32 (rv);
1546 * vnet_dns_resolve_name leaves the cache locked when it returns
1547 * a cached result, so unlock it here.
1549 dns_cache_unlock (dm);
1552 #define vl_msg_name_crc_list
1553 #include <vpp/api/vpe_all_api_h.h>
1554 #undef vl_msg_name_crc_list
1557 setup_message_id_table (api_main_t * am)
1559 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1560 foreach_vl_msg_name_crc_dns;
1564 #define foreach_dns_api_msg \
1565 _(DNS_ENABLE_DISABLE, dns_enable_disable) \
1566 _(DNS_NAME_SERVER_ADD_DEL, dns_name_server_add_del) \
1567 _(DNS_RESOLVE_NAME, dns_resolve_name) \
1568 _(DNS_RESOLVE_IP, dns_resolve_ip)
1570 static clib_error_t *
1571 dns_api_hookup (vlib_main_t * vm)
1574 vl_msg_api_set_handlers(VL_API_##N, #n, \
1575 vl_api_##n##_t_handler, \
1577 vl_api_##n##_t_endian, \
1578 vl_api_##n##_t_print, \
1579 sizeof(vl_api_##n##_t), 1);
1580 foreach_dns_api_msg;
1583 setup_message_id_table (&api_main);
1587 VLIB_API_INIT_FUNCTION (dns_api_hookup);
1590 static clib_error_t *
1591 dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1593 dns_main_t *dm = &dns_main;
1595 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1597 if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1599 else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1602 return clib_error_return (0, "unknown input `%U'",
1603 format_unformat_error, input);
1608 VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1610 static clib_error_t *
1611 dns_init (vlib_main_t * vm)
1613 dns_main_t *dm = &dns_main;
1616 dm->vnet_main = vnet_get_main ();
1617 dm->name_cache_size = 65535;
1618 dm->max_ttl_in_seconds = 86400;
1619 dm->random_seed = 0xDEADDABE;
1624 VLIB_INIT_FUNCTION (dns_init);
1627 unformat_dns_reply (unformat_input_t * input, va_list * args)
1629 u8 **result = va_arg (*args, u8 **);
1630 u8 **namep = va_arg (*args, u8 **);
1644 if (unformat (input, "%v", &name))
1647 if (unformat (input, "%U", unformat_ip4_address, &a4))
1650 if (unformat (input, "%U", unformat_ip6_address, &a6))
1654 if (unformat (input, "%U", unformat_ip6_address, &a6))
1657 if (unformat (input, "%U", unformat_ip4_address, &a6))
1661 /* Must have a name */
1665 /* Must have at least one address */
1666 if (!(a4_set + a6_set))
1669 /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1670 ce = name_to_labels (name);
1671 qp_offset = vec_len (ce);
1673 /* Add space for the query header */
1674 vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1675 qp = (dns_query_t *) (ce + qp_offset);
1677 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1678 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1680 /* Punch in space for the dns_header_t */
1681 vec_insert (ce, sizeof (dns_header_t), 0);
1683 h = (dns_header_t *) ce;
1685 /* Fake Transaction ID */
1688 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1689 h->qdcount = clib_host_to_net_u16 (1);
1690 h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1694 /* Now append one or two A/AAAA RR's... */
1697 /* Pointer to the name (DGMS) */
1698 vec_add1 (ce, 0xC0);
1699 vec_add1 (ce, 0x0C);
1700 vec_add2 (ce, rru8, sizeof (*rr) + 4);
1702 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1703 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1704 rr->ttl = clib_host_to_net_u32 (86400);
1705 rr->rdlength = clib_host_to_net_u16 (4);
1706 memcpy (rr->rdata, &a4, sizeof (a4));
1710 /* Pointer to the name (DGMS) */
1711 vec_add1 (ce, 0xC0);
1712 vec_add1 (ce, 0x0C);
1713 vec_add2 (ce, rru8, sizeof (*rr) + 16);
1715 rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1716 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1717 rr->ttl = clib_host_to_net_u32 (86400);
1718 rr->rdlength = clib_host_to_net_u16 (16);
1719 memcpy (rr->rdata, &a6, sizeof (a6));
1731 format_dns_query (u8 * s, va_list * args)
1733 u8 **curpos = va_arg (*args, u8 **);
1734 int verbose = va_arg (*args, int);
1739 s = format (s, " Name: ");
1741 /* Unwind execrated counted-label sheit */
1747 for (i = 0; i < len; i++)
1748 vec_add1 (s, *pos++);
1760 qp = (dns_query_t *) pos;
1763 switch (clib_net_to_host_u16 (qp->type))
1766 s = format (s, "type A\n");
1769 s = format (s, "type AAAA\n");
1772 s = format (s, "type ALL\n");
1776 s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1781 pos += sizeof (*qp);
1788 * format dns reply data
1789 * verbose > 1, dump everything
1790 * verbose == 1, dump all A and AAAA records
1791 * verbose == 0, dump one A record, and one AAAA record
1795 format_dns_reply_data (u8 * s, va_list * args)
1797 u8 *reply = va_arg (*args, u8 *);
1798 u8 **curpos = va_arg (*args, u8 **);
1799 int verbose = va_arg (*args, int);
1800 int *print_ip4 = va_arg (*args, int *);
1801 int *print_ip6 = va_arg (*args, int *);
1806 int pointer_chase = 0;
1808 u16 rrtype_host_byte_order;
1810 pos = pos2 = *curpos;
1813 s = format (s, " ");
1815 /* chase pointer? almost always yes here... */
1816 if ((pos2[0] & 0xc0) == 0xc0)
1819 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1827 for (i = 0; i < len; i++)
1830 vec_add1 (s, *pos2);
1833 if ((pos2[0] & 0xc0) == 0xc0)
1836 * If we've already done one pointer chase,
1837 * do not move the pos pointer.
1839 if (pointer_chase == 0)
1841 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1859 if (pointer_chase == 0)
1862 rr = (dns_rr_t *) pos;
1863 rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
1865 switch (rrtype_host_byte_order)
1870 s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1871 format_ip4_address, rr->rdata);
1876 s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1877 clib_net_to_host_u32 (rr->ttl));
1882 pos += sizeof (*rr) + 4;
1888 s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1889 format_ip6_address, rr->rdata);
1894 s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1895 clib_net_to_host_u32 (rr->ttl));
1899 pos += sizeof (*rr) + 16;
1905 s = format (s, "TEXT: ");
1906 for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1907 vec_add1 (s, rr->rdata[i]);
1910 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1913 case DNS_TYPE_HINFO:
1915 /* Two counted strings. DGMS */
1921 s = format (s, "HINFO: ");
1924 for (i = 0; i < *len; i++)
1925 vec_add1 (s, *curpos++);
1929 for (i = 0; i < *len; i++)
1930 vec_add1 (s, *curpos++);
1935 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1938 case DNS_TYPE_NAMESERVER:
1941 s = format (s, "Nameserver: ");
1944 /* chase pointer? */
1945 if ((pos2[0] & 0xc0) == 0xc0)
1948 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1955 for (i = 0; i < len; i++)
1956 vec_add1 (s, *pos2++);
1958 /* chase pointer, typically to offset 12... */
1959 if (pos2[0] == 0xC0)
1960 pos2 = reply + pos2[1];
1969 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1972 case DNS_TYPE_MAIL_EXCHANGE:
1975 tp = (u16 *) rr->rdata;
1977 s = format (s, "Mail Exchange: Preference %d ", (u32)
1978 clib_net_to_host_u16 (*tp));
1980 pos2 = rr->rdata + 2;
1982 /* chase pointer? */
1983 if (pos2[0] == 0xc0)
1984 pos2 = reply + pos2[1];
1990 for (i = 0; i < len; i++)
1991 vec_add1 (s, *pos2++);
1994 if (pos2[0] == 0xC0)
1995 pos2 = reply + pos2[1];
2005 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2009 case DNS_TYPE_CNAME:
2012 tp = (u16 *) rr->rdata;
2014 if (rrtype_host_byte_order == DNS_TYPE_CNAME)
2015 s = format (s, "CNAME: ");
2017 s = format (s, "PTR: ");
2021 /* chase pointer? */
2022 if (pos2[0] == 0xc0)
2023 pos2 = reply + pos2[1];
2029 for (i = 0; i < len; i++)
2030 vec_add1 (s, *pos2++);
2033 if (pos2[0] == 0xC0)
2034 pos2 = reply + pos2[1];
2043 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2048 s = format (s, "type %d: len %d\n",
2049 (int) clib_net_to_host_u16 (rr->type),
2050 sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
2051 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2061 format_dns_reply (u8 * s, va_list * args)
2063 u8 *reply_as_u8 = va_arg (*args, u8 *);
2064 int verbose = va_arg (*args, int);
2072 h = (dns_header_t *) reply_as_u8;
2073 id = clib_net_to_host_u16 (h->id);
2074 flags = clib_net_to_host_u16 (h->flags);
2078 s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
2080 s = format (s, " %s %s %s %s\n",
2081 (flags & DNS_RA) ? "recur" : "no-recur",
2082 (flags & DNS_RD) ? "recur-des" : "no-recur-des",
2083 (flags & DNS_TC) ? "trunc" : "no-trunc",
2084 (flags & DNS_AA) ? "auth" : "non-auth");
2085 s = format (s, " %d queries, %d answers, %d name-servers,"
2087 clib_net_to_host_u16 (h->qdcount),
2088 clib_net_to_host_u16 (h->anscount),
2089 clib_net_to_host_u16 (h->nscount),
2090 clib_net_to_host_u16 (h->arcount));
2093 curpos = (u8 *) (h + 1);
2098 s = format (s, " Queries:\n");
2099 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
2101 /* The query is variable-length, so curpos is a value-result parm */
2102 s = format (s, "%U", format_dns_query, &curpos, verbose);
2108 s = format (s, " Replies:\n");
2110 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
2112 /* curpos is a value-result parm */
2113 s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
2114 verbose, &print_ip4, &print_ip6);
2121 format_dns_cache (u8 * s, va_list * args)
2123 dns_main_t *dm = va_arg (*args, dns_main_t *);
2124 f64 now = va_arg (*args, f64);
2125 int verbose = va_arg (*args, int);
2126 u8 *name = va_arg (*args, u8 *);
2127 dns_cache_entry_t *ep;
2131 if (dm->is_enabled == 0)
2133 s = format (s, "The DNS cache is disabled...");
2137 if (pool_elts (dm->entries) == 0)
2139 s = format (s, "The DNS cache is empty...");
2143 dns_cache_lock (dm);
2147 p = hash_get_mem (dm->cache_entry_by_name, name);
2150 s = format (s, "%s is not in the cache...", name);
2151 dns_cache_unlock (dm);
2155 ep = pool_elt_at_index (dm->entries, p[0]);
2156 /* Magic to spit out a C-initializer to research hemorrhoids... */
2160 s = format (s, "static u8 dns_reply_data_initializer[] =\n");
2161 s = format (s, "{\n");
2163 for (i = 0; i < vec_len (ep->dns_response); i++)
2170 s = format (s, "0x%02x, ", ep->dns_response[i]);
2172 s = format (s, "};\n");
2176 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2178 ASSERT (ep->dns_response);
2179 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2184 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2185 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2187 s = format (s, "%s%s -> %U", ss, ep->name,
2188 format_dns_reply, ep->dns_response, verbose);
2189 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2191 f64 time_left = ep->expiration_time - now;
2192 if (time_left > 0.0)
2193 s = format (s, " TTL left %.1f", time_left);
2195 s = format (s, " EXPIRED");
2200 ASSERT (ep->dns_request);
2201 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2210 pool_foreach (ep, dm->entries,
2212 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2214 ASSERT (ep->dns_response);
2215 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2220 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2221 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2223 s = format (s, "%s%s -> %U", ss, ep->name,
2227 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2229 f64 time_left = ep->expiration_time - now;
2230 if (time_left > 0.0)
2231 s = format (s, " TTL left %.1f", time_left);
2233 s = format (s, " EXPIRED");
2236 s = format (s, " %d client notifications pending\n",
2237 vec_len(ep->pending_requests));
2242 ASSERT (ep->dns_request);
2243 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2250 dns_cache_unlock (dm);
2255 static clib_error_t *
2256 show_dns_cache_command_fn (vlib_main_t * vm,
2257 unformat_input_t * input, vlib_cli_command_t * cmd)
2259 dns_main_t *dm = &dns_main;
2262 f64 now = vlib_time_now (vm);
2264 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2266 if (unformat (input, "verbose %d", &verbose))
2268 else if (unformat (input, "verbose"))
2270 else if (unformat (input, "name %s", &name))
2273 return clib_error_return (0, "unknown input `%U'",
2274 format_unformat_error, input);
2277 vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
2283 VLIB_CLI_COMMAND (show_dns_cache_command) =
2285 .path = "show dns cache",
2286 .short_help = "show dns cache [verbose [nn]]",
2287 .function = show_dns_cache_command_fn,
2291 static clib_error_t *
2292 dns_cache_add_del_command_fn (vlib_main_t * vm,
2293 unformat_input_t * input,
2294 vlib_cli_command_t * cmd)
2296 dns_main_t *dm = &dns_main;
2302 clib_error_t *error;
2304 if (unformat (input, "add"))
2306 if (unformat (input, "del"))
2308 if (unformat (input, "clear"))
2311 if (is_add == -1 && is_clear == -1)
2312 return clib_error_return (0, "add / del / clear required...");
2316 rv = dns_cache_clear (dm);
2322 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2323 error = clib_error_return (0, "Name resolution not enabled");
2328 /* Delete (by name)? */
2331 if (unformat (input, "%v", &name))
2333 rv = dns_delete_by_name (dm, name);
2336 case VNET_API_ERROR_NO_SUCH_ENTRY:
2337 error = clib_error_return (0, "%v not in the cache...", name);
2341 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2342 error = clib_error_return (0, "Name resolution not enabled");
2351 error = clib_error_return (0, "dns_delete_by_name returned %d",
2357 return clib_error_return (0, "unknown input `%U'",
2358 format_unformat_error, input);
2361 /* Note: dns_add_static_entry consumes the name vector if OK... */
2362 if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2364 rv = dns_add_static_entry (dm, name, dns_reply_data);
2367 case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2369 vec_free (dns_reply_data);
2370 return clib_error_return (0, "%v already in the cache...", name);
2375 return clib_error_return (0, "dns_add_static_entry returned %d",
2384 VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2386 .path = "dns cache",
2387 .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2388 .function = dns_cache_add_del_command_fn,
2392 #define DNS_FORMAT_TEST 1
2394 #if DNS_FORMAT_TEST > 0
2397 static u8 dns_reply_data_initializer[] =
2398 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2399 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2401 0x0, 0xff, /* type ALL */
2402 0x0, 0x1, /* class IN */
2403 0xc0, 0xc, /* pointer to yahoo.com name */
2404 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2405 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2406 0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2407 0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2408 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2409 0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2410 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2411 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2412 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2413 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2414 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2415 0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2416 0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2418 0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2419 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2420 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2421 0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2422 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2424 0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2425 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2426 0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2427 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2429 0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2430 0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2432 0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2434 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2436 0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2438 0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2439 0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2440 0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2444 /* www.cisco.com, has no addresses in reply */
2445 static u8 dns_reply_data_initializer[] = {
2446 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2447 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2448 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2450 0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2451 0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2452 0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2453 0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2454 0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2457 /* bind8 (linux widget, w/ nasty double pointer chasees */
2458 static u8 dns_reply_data_initializer[] = {
2460 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08,
2462 0x00, 0x06, 0x00, 0x06, 0x0a, 0x6f, 0x72, 0x69,
2464 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77, 0x77, 0x05,
2466 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f,
2468 0x6d, 0x00, 0x00, 0xff, 0x00, 0x01, 0x0a, 0x6f,
2470 0x72, 0x69, 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77,
2472 0x77, 0x05, 0x43, 0x49, 0x53, 0x43, 0x4f, 0xc0,
2475 0x1d, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2478 0x9a, 0x00, 0x18, 0x15, 0x72, 0x63, 0x64,
2479 0x6e, 0x39, 0x2d, 0x31, 0x34, 0x70, 0x2d, 0x64, 0x63,
2480 0x7a, 0x30, 0x35, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31,
2481 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00, 0x01, 0x00,
2482 0x00, 0x05, 0x9a, 0x00, 0x1a, 0x17, 0x61, 0x6c, 0x6c,
2483 0x6e, 0x30, 0x31, 0x2d, 0x61, 0x67, 0x30, 0x39, 0x2d,
2484 0x64, 0x63, 0x7a, 0x30, 0x33, 0x6e, 0x2d, 0x67, 0x73,
2485 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00,
2486 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x10, 0x0d, 0x72,
2487 0x74, 0x70, 0x35, 0x2d, 0x64, 0x6d, 0x7a, 0x2d, 0x67,
2488 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2489 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x18, 0x15,
2490 0x6d, 0x74, 0x76, 0x35, 0x2d, 0x61, 0x70, 0x31, 0x30,
2491 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x36, 0x6e, 0x2d, 0x67,
2492 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2493 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x1b, 0x18,
2494 0x73, 0x6e, 0x67, 0x64, 0x63, 0x30, 0x31, 0x2d, 0x61,
2495 0x62, 0x30, 0x37, 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x31,
2496 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0,
2497 0x26, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a,
2498 0x00, 0x1a, 0x17, 0x61, 0x65, 0x72, 0x30, 0x31, 0x2d,
2499 0x72, 0x34, 0x63, 0x32, 0x35, 0x2d, 0x64, 0x63, 0x7a,
2500 0x30, 0x31, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0,
2501 0x17, 0xc0, 0x26, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2502 0x00, 0x81, 0x00, 0x04, 0x48, 0xa3, 0x04, 0xa1, 0xc0,
2503 0x26, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82,
2504 0x00, 0x10, 0x20, 0x01, 0x04, 0x20, 0x12, 0x01, 0x00,
2505 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
2506 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2507 0x9a, 0x00, 0x02, 0xc0, 0xf4, 0xc0, 0x0c, 0x00, 0x02,
2508 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0,
2509 0xcd, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00,
2510 0x05, 0x9a, 0x00, 0x02, 0xc0, 0x8d, 0xc0, 0x0c, 0x00,
2511 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02,
2512 0xc0, 0x43, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00,
2513 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0, 0xa9, 0xc0, 0x0c,
2514 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00,
2515 0x02, 0xc0, 0x67, 0xc0, 0x8d, 0x00, 0x01, 0x00, 0x01,
2516 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0x40, 0x66, 0xf6,
2517 0x05, 0xc0, 0xa9, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2518 0x07, 0x08, 0x00, 0x04, 0xad, 0x24, 0xe0, 0x64, 0xc0,
2519 0x43, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08,
2520 0x00, 0x04, 0x48, 0xa3, 0x04, 0x1c, 0xc0, 0xf4, 0x00,
2521 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04,
2522 0xad, 0x26, 0xd4, 0x6c, 0xc0, 0x67, 0x00, 0x01, 0x00,
2523 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x25,
2524 0x90, 0x64, 0xc0, 0xcd, 0x00, 0x01, 0x00, 0x01, 0x00,
2525 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x27, 0x70, 0x44,
2529 static u8 dns_reply_data_initializer[] =
2530 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
2531 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
2532 0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
2533 0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
2535 0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
2536 0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
2537 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
2538 0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
2539 0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
2540 0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
2541 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
2542 0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
2543 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
2544 0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
2545 0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
2546 0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
2547 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
2548 0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
2549 0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
2550 0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
2551 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2552 0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
2553 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
2554 0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
2555 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
2556 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
2557 0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
2559 0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2563 /* www.weatherlink.com */
2564 static u8 dns_reply_data_initializer[] = {
2565 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2566 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x0b,
2567 0x77, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x6c, 0x69,
2568 0x6e, 0x6b, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0xff,
2569 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00,
2570 0x00, 0x0c, 0x9e, 0x00, 0x1f, 0x0e, 0x64, 0x33, 0x6b,
2571 0x72, 0x30, 0x67, 0x75, 0x62, 0x61, 0x31, 0x64, 0x76,
2572 0x77, 0x66, 0x0a, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x66,
2573 0x72, 0x6f, 0x6e, 0x74, 0x03, 0x6e, 0x65, 0x74, 0x00,
2578 static clib_error_t *
2579 test_dns_fmt_command_fn (vlib_main_t * vm,
2580 unformat_input_t * input, vlib_cli_command_t * cmd)
2582 u8 *dns_reply_data = 0;
2585 vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2587 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2589 if (unformat (input, "verbose %d", &verbose))
2591 else if (unformat (input, "verbose"))
2594 return clib_error_return (0, "unknown input `%U'",
2595 format_unformat_error, input);
2598 vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2600 memcpy (dns_reply_data, dns_reply_data_initializer,
2601 ARRAY_LEN (dns_reply_data_initializer));
2603 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2605 clib_memset (rmp, 0, sizeof (*rmp));
2607 rv = vnet_dns_response_to_reply (dns_reply_data, rmp, 0 /* ttl-ptr */ );
2611 case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2612 vlib_cli_output (vm, "no addresses found...");
2616 vlib_cli_output (vm, "response to reply returned %d", rv);
2621 vlib_cli_output (vm, "ip4 address: %U", format_ip4_address,
2622 (ip4_address_t *) rmp->ip4_address);
2624 vlib_cli_output (vm, "ip6 address: %U", format_ip6_address,
2625 (ip6_address_t *) rmp->ip6_address);
2629 vec_free (dns_reply_data);
2636 VLIB_CLI_COMMAND (test_dns_fmt_command) =
2638 .path = "test dns format",
2639 .short_help = "test dns format",
2640 .function = test_dns_fmt_command_fn,
2644 static clib_error_t *
2645 test_dns_unfmt_command_fn (vlib_main_t * vm,
2646 unformat_input_t * input, vlib_cli_command_t * cmd)
2648 u8 *dns_reply_data = 0;
2652 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2654 if (unformat (input, "verbose %d", &verbose))
2656 else if (unformat (input, "verbose"))
2658 else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2661 return clib_error_return (0, "unknown input `%U'",
2662 format_unformat_error, input);
2666 return clib_error_return (0, "dns data not set...");
2668 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2670 vec_free (dns_reply_data);
2676 VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2678 .path = "test dns unformat",
2679 .short_help = "test dns unformat <name> [ip4][ip6]",
2680 .function = test_dns_unfmt_command_fn,
2684 static clib_error_t *
2685 test_dns_expire_command_fn (vlib_main_t * vm,
2686 unformat_input_t * input,
2687 vlib_cli_command_t * cmd)
2689 dns_main_t *dm = &dns_main;
2693 dns_cache_entry_t *ep;
2695 if (unformat (input, "%v", &name))
2698 _vec_len (name) -= 1;
2701 return clib_error_return (0, "no name provided");
2703 dns_cache_lock (dm);
2705 p = hash_get_mem (dm->cache_entry_by_name, name);
2708 dns_cache_unlock (dm);
2709 e = clib_error_return (0, "%s is not in the cache...", name);
2714 ep = pool_elt_at_index (dm->entries, p[0]);
2716 ep->expiration_time = 0;
2722 VLIB_CLI_COMMAND (test_dns_expire_command) =
2724 .path = "test dns expire",
2725 .short_help = "test dns expire <name>",
2726 .function = test_dns_expire_command_fn,
2732 vnet_send_dns6_reply (dns_main_t * dm, dns_pending_request_t * pr,
2733 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2735 clib_warning ("Unimplemented...");
2740 vnet_send_dns4_reply (dns_main_t * dm, dns_pending_request_t * pr,
2741 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2743 vlib_main_t *vm = dm->vlib_main;
2745 fib_prefix_t prefix;
2746 fib_node_index_t fei;
2747 u32 sw_if_index, fib_index;
2748 ip4_main_t *im4 = &ip4_main;
2749 ip_lookup_main_t *lm4 = &im4->lookup_main;
2750 ip_interface_address_t *ia = 0;
2751 ip4_address_t *src_address;
2759 vl_api_dns_resolve_name_reply_t _rnr, *rnr = &_rnr;
2760 vl_api_dns_resolve_ip_reply_t _rir, *rir = &_rir;
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);
2808 if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
2809 vlib_buffer_free_one (vm, b0->next_buffer);
2812 * Reset the buffer. We recycle the DNS request packet in the cache
2813 * hit case, and reply immediately from the request node.
2815 * In the resolution-required / deferred case, resetting a freshly-allocated
2816 * buffer won't hurt. We hope.
2818 b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
2819 | VLIB_BUFFER_TOTAL_LENGTH_VALID);
2820 b0->current_data = 0;
2821 b0->current_length = 0;
2822 b0->total_length_not_including_first_buffer = 0;
2823 vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; /* "local0" */
2824 vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
2826 /* Find a FIB path to the peer we're trying to answer */
2827 clib_memcpy (&prefix.fp_addr.ip4, pr->dst_address, sizeof (ip4_address_t));
2828 prefix.fp_proto = FIB_PROTOCOL_IP4;
2831 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
2832 if (fib_index == (u32) ~ 0)
2834 clib_warning ("no fib table");
2838 fei = fib_table_lookup (fib_index, &prefix);
2840 /* Couldn't find route to destination. Bail out. */
2841 if (fei == FIB_NODE_INDEX_INVALID)
2843 clib_warning ("no route to DNS server");
2847 sw_if_index = fib_entry_get_resolving_interface (fei);
2849 if (sw_if_index == ~0)
2852 ("route to %U exists, fei %d, get_resolving_interface returned"
2853 " ~0", fei, format_ip4_address, &prefix.fp_addr);
2858 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnumbered */,
2860 src_address = ip_interface_address_get_address (lm4, ia);
2861 goto found_src_address;
2865 clib_warning ("FIB BUG");
2870 ip = vlib_buffer_get_current (b0);
2871 udp = (udp_header_t *) (ip + 1);
2872 dns_response = (u8 *) (udp + 1);
2873 clib_memset (ip, 0, sizeof (*ip) + sizeof (*udp));
2876 * Start with the variadic portion of the exercise.
2877 * Turn the name into a set of DNS "labels". Max length
2878 * per label is 63, enforce that.
2880 reply = name_to_labels (pr->name);
2881 vec_free (pr->name);
2883 qp_offset = vec_len (reply);
2885 /* Add space for the query header */
2886 vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
2888 qp = (dns_query_t *) (reply + qp_offset);
2890 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2891 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
2893 qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2895 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
2897 /* Punch in space for the dns_header_t */
2898 vec_insert (reply, sizeof (dns_header_t), 0);
2900 dh = (dns_header_t *) reply;
2902 /* Transaction ID = pool index */
2905 /* Announce that we did a recursive lookup */
2906 tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
2908 tmp |= DNS_RCODE_NAME_ERROR;
2909 dh->flags = clib_host_to_net_u16 (tmp);
2910 dh->qdcount = clib_host_to_net_u16 (1);
2911 dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
2915 /* If the name resolution worked, cough up an appropriate RR */
2918 /* Add the answer. First, a name pointer (0xC00C) */
2919 vec_add1 (reply, 0xC0);
2920 vec_add1 (reply, 0x0C);
2922 /* Now, add single A-rec RR */
2923 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2925 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
2926 rr = (dns_rr_t *) rrptr;
2928 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
2929 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2930 rr->ttl = clib_host_to_net_u32 (ttl);
2931 rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
2932 clib_memcpy (rr->rdata, rnr->ip4_address, sizeof (ip4_address_t));
2936 /* Or a single PTR RR */
2937 u8 *vecname = format (0, "%s", rir->name);
2938 u8 *label_vec = name_to_labels (vecname);
2941 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
2942 rr = (dns_rr_t *) rrptr;
2943 rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2944 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2945 rr->ttl = clib_host_to_net_u32 (ttl);
2946 rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
2947 clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
2948 vec_free (label_vec);
2951 clib_memcpy (dns_response, reply, vec_len (reply));
2953 /* Set the packet length */
2954 b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
2957 ip->ip_version_and_header_length = 0x45;
2958 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
2960 ip->protocol = IP_PROTOCOL_UDP;
2961 ip->src_address.as_u32 = src_address->as_u32;
2962 clib_memcpy (ip->dst_address.as_u8, pr->dst_address,
2963 sizeof (ip4_address_t));
2964 ip->checksum = ip4_header_checksum (ip);
2967 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
2968 udp->dst_port = pr->dst_port;
2969 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
2974 /* Ship it to ip4_lookup */
2975 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
2976 to_next = vlib_frame_vector_args (f);
2979 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
2983 * fd.io coding-style-patch-verification: ON
2986 * eval: (c-set-style "gnu")