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;
79 if (vec_len (dm->ip4_name_servers) == 0
80 && (vec_len (dm->ip6_name_servers) == 0))
81 return VNET_API_ERROR_NO_NAME_SERVERS;
83 if (dm->udp_ports_registered == 0)
85 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply,
86 dns46_reply_node.index, 1 /* is_ip4 */ );
88 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply6,
89 dns46_reply_node.index, 0 /* is_ip4 */ );
91 udp_register_dst_port (vm, UDP_DST_PORT_dns,
92 dns4_request_node.index, 1 /* is_ip4 */ );
94 udp_register_dst_port (vm, UDP_DST_PORT_dns6,
95 dns6_request_node.index, 0 /* is_ip4 */ );
97 dm->udp_ports_registered = 1;
100 if (dm->cache_entry_by_name == 0)
102 if (n_vlib_mains > 1)
103 dm->cache_lock = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
104 CLIB_CACHE_LINE_BYTES);
106 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
113 dns_cache_clear (dm);
119 static void vl_api_dns_enable_disable_t_handler
120 (vl_api_dns_enable_disable_t * mp)
122 vl_api_dns_enable_disable_reply_t *rmp;
123 dns_main_t *dm = &dns_main;
126 rv = dns_enable_disable (dm, mp->enable);
128 REPLY_MACRO (VL_API_DNS_ENABLE_DISABLE_REPLY);
132 dns6_name_server_add_del (dns_main_t * dm,
133 u8 * server_address_as_u8, int is_add)
140 /* Already there? done... */
141 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
143 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
144 sizeof (ip6_address_t)))
148 vec_add2 (dm->ip6_name_servers, ap, 1);
149 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
153 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
155 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
156 sizeof (ip6_address_t)))
158 vec_delete (dm->ip6_name_servers, 1, i);
162 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
168 dns4_name_server_add_del (dns_main_t * dm,
169 u8 * server_address_as_u8, int is_add)
176 /* Already there? done... */
177 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
179 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
180 sizeof (ip4_address_t)))
184 vec_add2 (dm->ip4_name_servers, ap, 1);
185 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
189 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
191 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
192 sizeof (ip4_address_t)))
194 vec_delete (dm->ip4_name_servers, 1, i);
198 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
203 static void vl_api_dns_name_server_add_del_t_handler
204 (vl_api_dns_name_server_add_del_t * mp)
206 dns_main_t *dm = &dns_main;
207 vl_api_dns_name_server_add_del_reply_t *rmp;
211 rv = dns6_name_server_add_del (dm, mp->server_address, mp->is_add);
213 rv = dns4_name_server_add_del (dm, mp->server_address, mp->is_add);
215 REPLY_MACRO (VL_API_DNS_NAME_SERVER_ADD_DEL_REPLY);
219 vnet_dns_send_dns4_request (dns_main_t * dm,
220 dns_cache_entry_t * ep, ip4_address_t * server)
222 vlib_main_t *vm = dm->vlib_main;
223 f64 now = vlib_time_now (vm);
228 fib_node_index_t fei;
229 u32 sw_if_index, fib_index;
231 ip4_main_t *im4 = &ip4_main;
232 ip_lookup_main_t *lm4 = &im4->lookup_main;
233 ip_interface_address_t *ia = 0;
234 ip4_address_t *src_address;
239 ASSERT (ep->dns_request);
241 /* Find a FIB path to the server */
242 clib_memcpy (&prefix.fp_addr.ip4, server, sizeof (*server));
243 prefix.fp_proto = FIB_PROTOCOL_IP4;
246 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
247 if (fib_index == (u32) ~ 0)
249 clib_warning ("no fib table");
253 fei = fib_table_lookup (fib_index, &prefix);
255 /* Couldn't find route to destination. Bail out. */
256 if (fei == FIB_NODE_INDEX_INVALID)
258 clib_warning ("no route to DNS server");
262 sw_if_index = fib_entry_get_resolving_interface (fei);
264 if (sw_if_index == ~0)
267 ("route to %U exists, fei %d, get_resolving_interface returned"
268 " ~0", format_ip4_address, &prefix.fp_addr, fei);
273 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnumbered */,
275 src_address = ip_interface_address_get_address (lm4, ia);
276 goto found_src_address;
280 clib_warning ("FIB BUG");
285 /* Go get a buffer */
286 if (vlib_buffer_alloc (dm->vlib_main, &bi, 1) != 1)
289 b = vlib_get_buffer (vm, bi);
290 b->current_length = sizeof (ip4_header_t) + sizeof (udp_header_t) +
291 vec_len (ep->dns_request);
292 b->total_length_not_including_first_buffer = 0;
294 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
295 vnet_buffer (b)->sw_if_index[VLIB_RX] = 0; /* "local0" */
296 vnet_buffer (b)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
298 ip = vlib_buffer_get_current (b);
299 clib_memset (ip, 0, sizeof (*ip));
300 udp = (udp_header_t *) (ip + 1);
301 clib_memset (udp, 0, sizeof (*udp));
303 dns_request = (u8 *) (udp + 1);
306 ip->ip_version_and_header_length = 0x45;
307 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b));
309 ip->protocol = IP_PROTOCOL_UDP;
310 ip->src_address.as_u32 = src_address->as_u32;
311 ip->dst_address.as_u32 = server->as_u32;
312 ip->checksum = ip4_header_checksum (ip);
315 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
316 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
317 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
318 vec_len (ep->dns_request));
321 /* The actual DNS request */
322 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
324 /* Ship it to ip4_lookup */
325 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
326 to_next = vlib_frame_vector_args (f);
329 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
331 ep->retry_timer = now + 2.0;
335 vnet_dns_send_dns6_request (dns_main_t * dm,
336 dns_cache_entry_t * ep, ip6_address_t * server)
338 vlib_main_t *vm = dm->vlib_main;
339 f64 now = vlib_time_now (vm);
344 fib_node_index_t fei;
345 u32 sw_if_index, fib_index;
347 ip6_main_t *im6 = &ip6_main;
348 ip_lookup_main_t *lm6 = &im6->lookup_main;
349 ip_interface_address_t *ia = 0;
350 ip6_address_t *src_address;
354 int junk __attribute__ ((unused));
356 ASSERT (ep->dns_request);
358 /* Find a FIB path to the server */
359 clib_memcpy (&prefix.fp_addr, server, sizeof (*server));
360 prefix.fp_proto = FIB_PROTOCOL_IP6;
363 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
364 if (fib_index == (u32) ~ 0)
366 clib_warning ("no fib table");
370 fei = fib_table_lookup (fib_index, &prefix);
372 /* Couldn't find route to destination. Bail out. */
373 if (fei == FIB_NODE_INDEX_INVALID)
375 clib_warning ("no route to DNS server");
378 sw_if_index = fib_entry_get_resolving_interface (fei);
381 foreach_ip_interface_address(lm6, ia, sw_if_index, 1 /* honor unnumbered */,
383 src_address = ip_interface_address_get_address (lm6, ia);
384 goto found_src_address;
388 clib_warning ("FIB BUG");
393 /* Go get a buffer */
394 if (vlib_buffer_alloc (dm->vlib_main, &bi, 1) != 1)
397 b = vlib_get_buffer (vm, bi);
398 b->current_length = sizeof (ip6_header_t) + sizeof (udp_header_t) +
399 vec_len (ep->dns_request);
400 b->total_length_not_including_first_buffer = 0;
402 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
404 ip = vlib_buffer_get_current (b);
405 clib_memset (ip, 0, sizeof (*ip));
406 udp = (udp_header_t *) (ip + 1);
407 clib_memset (udp, 0, sizeof (*udp));
409 dns_request = (u8 *) (udp + 1);
412 ip->ip_version_traffic_class_and_flow_label =
413 clib_host_to_net_u32 (0x6 << 28);
416 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b)
417 - sizeof (ip6_header_t));
419 ip->protocol = IP_PROTOCOL_UDP;
420 clib_memcpy (&ip->src_address, src_address, sizeof (ip6_address_t));
421 clib_memcpy (&ip->dst_address, server, sizeof (ip6_address_t));
424 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
425 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
426 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
427 vec_len (ep->dns_request));
429 udp->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ip, &junk);
431 /* The actual DNS request */
432 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
434 /* Ship it to ip6_lookup */
435 f = vlib_get_frame_to_node (vm, ip6_lookup_node.index);
436 to_next = vlib_frame_vector_args (f);
440 ep->retry_timer = now + 2.0;
444 * Translate "foo.com" into "0x3 f o o 0x3 c o m 0x0"
445 * A historical / hysterical micro-TLV scheme. DGMS.
448 name_to_labels (u8 * name)
451 int last_label_index;
456 /* punch in space for the first length */
457 vec_insert (rv, 1, 0);
458 last_label_index = 0;
461 while (i < vec_len (rv))
465 rv[last_label_index] = (i - last_label_index) - 1;
466 if ((i - last_label_index) > 63)
467 clib_warning ("stupid name, label length %d",
468 i - last_label_index);
469 last_label_index = i;
474 /* Set the last real label length */
475 rv[last_label_index] = (i - last_label_index) - 1;
478 * Add a [sic] NULL root label. Otherwise, the name parser can't figure out
486 * arc-function for the above.
487 * Translate "0x3 f o o 0x3 c o m 0x0" into "foo.com"
488 * Produces a non-NULL-terminated u8 *vector. %v format is your friend.
491 vnet_dns_labels_to_name (u8 * label, u8 * full_text, u8 ** parse_from_here)
498 *parse_from_here = 0;
500 /* chase initial pointer? */
501 if ((label[0] & 0xC0) == 0xC0)
503 *parse_from_here = label + 2;
504 offset = ((label[0] & 0x3f) << 8) + label[1];
505 label = full_text + offset;
512 for (i = 0; i < len; i++)
513 vec_add1 (reply, *label++);
516 if ((label[0] & 0xC0) == 0xC0)
518 *parse_from_here = label + 2;
519 offset = ((label[0] & 0x3f) << 8) + label[1];
520 label = full_text + offset;
525 vec_add1 (reply, '.');
527 if (*parse_from_here == 0)
528 *parse_from_here = label;
533 vnet_send_dns_request (dns_main_t * dm, dns_cache_entry_t * ep)
538 u8 *request, *name_copy;
541 /* This can easily happen if sitting in GDB, etc. */
542 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID || ep->server_fails > 1)
545 /* Construct the dns request, if we haven't been here already */
546 if (vec_len (ep->dns_request) == 0)
549 * Start with the variadic portion of the exercise.
550 * Turn the name into a set of DNS "labels". Max length
551 * per label is 63, enforce that.
553 request = name_to_labels (ep->name);
554 name_copy = vec_dup (request);
555 qp_offset = vec_len (request);
558 * At least when testing against "known good" DNS servers:
559 * it turns out that sending 2x requests - one for an A-record
560 * and another for a AAAA-record - seems to work better than
561 * sending a DNS_TYPE_ALL request.
564 /* Add space for the query header */
565 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
567 qp = (dns_query_t *) (request + qp_offset);
569 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
570 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
572 clib_memcpy (qp, name_copy, vec_len (name_copy));
573 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
574 vec_free (name_copy);
576 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
577 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
579 /* Punch in space for the dns_header_t */
580 vec_insert (request, sizeof (dns_header_t), 0);
582 h = (dns_header_t *) request;
584 /* Transaction ID = pool index */
585 h->id = clib_host_to_net_u16 (ep - dm->entries);
587 /* Ask for a recursive lookup */
588 tmp = DNS_RD | DNS_OPCODE_QUERY;
589 h->flags = clib_host_to_net_u16 (tmp);
590 h->qdcount = clib_host_to_net_u16 (2);
594 ep->dns_request = request;
597 /* Work out which server / address family we're going to use */
599 /* Retry using current server */
600 if (ep->retry_count++ < DNS_RETRIES_PER_SERVER)
602 if (ep->server_af == 1 /* ip6 */ )
604 if (vec_len (dm->ip6_name_servers))
606 vnet_dns_send_dns6_request
607 (dm, ep, dm->ip6_name_servers + ep->server_rotor);
613 if (vec_len (dm->ip4_name_servers))
615 vnet_dns_send_dns4_request
616 (dm, ep, dm->ip4_name_servers + ep->server_rotor);
620 else /* switch to a new server */
624 if (ep->server_af == 1 /* ip6 */ )
626 if (ep->server_rotor >= vec_len (dm->ip6_name_servers))
628 ep->server_rotor = 0;
629 ep->server_af = vec_len (dm->ip4_name_servers) > 0 ? 0 : 1;
634 if (ep->server_rotor >= vec_len (dm->ip4_name_servers))
636 ep->server_rotor = 0;
637 ep->server_af = vec_len (dm->ip6_name_servers) > 0 ? 1 : 0;
642 if (ep->server_af == 1 /* ip6 */ )
643 vnet_dns_send_dns6_request
644 (dm, ep, dm->ip6_name_servers + ep->server_rotor);
646 vnet_dns_send_dns4_request
647 (dm, ep, dm->ip4_name_servers + ep->server_rotor);
651 vlib_process_signal_event_mt (dm->vlib_main, dns_resolver_node.index,
652 DNS_RESOLVER_EVENT_PENDING, 0);
656 vnet_dns_delete_entry_by_index_nolock (dns_main_t * dm, u32 index)
658 dns_cache_entry_t *ep;
661 if (dm->is_enabled == 0)
662 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
664 if (pool_is_free_index (dm->entries, index))
665 return VNET_API_ERROR_NO_SUCH_ENTRY;
667 ep = pool_elt_at_index (dm->entries, index);
668 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_VALID))
670 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
671 if (index == dm->unresolved_entries[i])
673 vec_delete (dm->unresolved_entries, 1, i);
676 clib_warning ("pool elt %d supposedly pending, but not found...",
681 hash_unset_mem (dm->cache_entry_by_name, ep->name);
683 vec_free (ep->pending_requests);
684 pool_put (dm->entries, ep);
690 dns_delete_by_name (dns_main_t * dm, u8 * name)
695 if (dm->is_enabled == 0)
696 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
699 p = hash_get_mem (dm->cache_entry_by_name, name);
702 dns_cache_unlock (dm);
703 return VNET_API_ERROR_NO_SUCH_ENTRY;
705 rv = vnet_dns_delete_entry_by_index_nolock (dm, p[0]);
707 dns_cache_unlock (dm);
713 delete_random_entry (dns_main_t * dm)
716 u32 victim_index, start_index, i;
718 dns_cache_entry_t *ep;
720 if (dm->is_enabled == 0)
721 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
724 * Silence spurious coverity warning. We know pool_elts >> 0, or
725 * we wouldn't be here...
728 if (pool_elts (dm->entries) == 0)
729 return VNET_API_ERROR_UNSPECIFIED;
733 limit = pool_elts (dm->entries);
734 start_index = random_u32 (&dm->random_seed) % limit;
736 for (i = 0; i < limit; i++)
738 victim_index = (start_index + i) % limit;
740 if (!pool_is_free_index (dm->entries, victim_index))
742 ep = pool_elt_at_index (dm->entries, victim_index);
743 /* Delete only valid, non-static entries */
744 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
745 && ((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0))
747 rv = vnet_dns_delete_entry_by_index_nolock (dm, victim_index);
748 dns_cache_unlock (dm);
753 dns_cache_unlock (dm);
755 clib_warning ("Couldn't find an entry to delete?");
756 return VNET_API_ERROR_UNSPECIFIED;
760 dns_add_static_entry (dns_main_t * dm, u8 * name, u8 * dns_reply_data)
762 dns_cache_entry_t *ep;
766 if (dm->is_enabled == 0)
767 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
770 p = hash_get_mem (dm->cache_entry_by_name, name);
773 dns_cache_unlock (dm);
774 return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
777 if (pool_elts (dm->entries) == dm->name_cache_size)
779 /* Will only fail if the cache is totally filled w/ static entries... */
780 rv = delete_random_entry (dm);
783 dns_cache_unlock (dm);
788 pool_get (dm->entries, ep);
789 clib_memset (ep, 0, sizeof (*ep));
791 /* Note: consumes the name vector */
793 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
794 ep->flags = DNS_CACHE_ENTRY_FLAG_VALID | DNS_CACHE_ENTRY_FLAG_STATIC;
795 ep->dns_response = dns_reply_data;
797 dns_cache_unlock (dm);
802 vnet_dns_resolve_name (dns_main_t * dm, u8 * name, dns_pending_request_t * t,
803 dns_cache_entry_t ** retp)
805 dns_cache_entry_t *ep;
809 dns_pending_request_t *pr;
812 now = vlib_time_now (dm->vlib_main);
814 /* In case we can't actually answer the question right now... */
819 p = hash_get_mem (dm->cache_entry_by_name, name);
822 ep = pool_elt_at_index (dm->entries, p[0]);
823 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
825 /* Has the entry expired? */
826 if (((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0)
827 && (now > ep->expiration_time))
830 u32 *indices_to_delete = 0;
833 * Take out the rest of the resolution chain
834 * This isn't optimal, but it won't happen very often.
838 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME))
840 vec_add1 (indices_to_delete, ep - dm->entries);
842 p = hash_get_mem (dm->cache_entry_by_name, ep->cname);
845 ep = pool_elt_at_index (dm->entries, p[0]);
849 vec_add1 (indices_to_delete, ep - dm->entries);
853 for (i = 0; i < vec_len (indices_to_delete); i++)
855 /* Reenable to watch re-resolutions */
858 ep = pool_elt_at_index (dm->entries,
859 indices_to_delete[i]);
860 clib_warning ("Re-resolve %s", ep->name);
863 vnet_dns_delete_entry_by_index_nolock
864 (dm, indices_to_delete[i]);
866 vec_free (indices_to_delete);
867 /* Yes, kill it... */
871 if (ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
877 /* Note: caller must drop the lock! */
884 * Resolution pending. Add request to the pending vector
885 * by copying the template request
887 vec_add2 (ep->pending_requests, pr, 1);
888 memcpy (pr, t, sizeof (*pr));
889 dns_cache_unlock (dm);
895 if (pool_elts (dm->entries) == dm->name_cache_size)
897 /* Will only fail if the cache is totally filled w/ static entries... */
898 rv = delete_random_entry (dm);
901 dns_cache_unlock (dm);
906 /* add new hash table entry */
907 pool_get (dm->entries, ep);
908 clib_memset (ep, 0, sizeof (*ep));
910 ep->name = format (0, "%s%c", name, 0);
911 _vec_len (ep->name) = vec_len (ep->name) - 1;
913 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
915 vec_add1 (dm->unresolved_entries, ep - dm->entries);
916 vec_add2 (ep->pending_requests, pr, 1);
918 pr->request_type = t->request_type;
920 /* Remember details so we can reply later... */
921 if (t->request_type == DNS_API_PENDING_NAME_TO_IP ||
922 t->request_type == DNS_API_PENDING_IP_TO_NAME)
924 pr->client_index = t->client_index;
925 pr->client_context = t->client_context;
929 pr->client_index = ~0;
930 pr->is_ip6 = t->is_ip6;
931 pr->dst_port = t->dst_port;
938 clib_memcpy (pr->dst_address, t->dst_address, count);
941 vnet_send_dns_request (dm, ep);
942 dns_cache_unlock (dm);
946 #define foreach_notification_to_move \
950 * Handle cname indirection. JFC. Called with the cache locked.
951 * returns 0 if the reply is not a CNAME.
955 vnet_dns_cname_indirection_nolock (dns_main_t * dm, u32 ep_index, u8 * reply)
970 dns_cache_entry_t *ep, *next_ep;
973 h = (dns_header_t *) reply;
974 flags = clib_net_to_host_u16 (h->flags);
975 rcode = flags & DNS_RCODE_MASK;
977 /* See if the response is OK */
980 case DNS_RCODE_NO_ERROR:
983 case DNS_RCODE_NAME_ERROR:
984 case DNS_RCODE_FORMAT_ERROR:
985 case DNS_RCODE_SERVER_FAILURE:
986 case DNS_RCODE_NOT_IMPLEMENTED:
987 case DNS_RCODE_REFUSED:
991 curpos = (u8 *) (h + 1);
995 /* Skip the questions */
996 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
1003 pos += sizeof (dns_query_t);
1006 /* expect a pointer chase here for a CNAME record */
1007 if ((pos2[0] & 0xC0) == 0xC0)
1012 /* Walk the answer(s) to see what to do next */
1013 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
1015 rr = (dns_rr_t *) pos;
1016 switch (clib_net_to_host_u16 (rr->type))
1018 /* Real address record? Done.. */
1023 * Maybe chase a CNAME pointer?
1024 * It's not unheard-of for name-servers to return
1025 * both CNAME and A/AAAA records...
1027 case DNS_TYPE_CNAME:
1031 /* Some other junk, e.g. a nameserver... */
1035 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1037 if ((pos2[0] & 0xc0) == 0xc0)
1041 /* Neither a CNAME nor a real address. Try another server */
1044 flags &= ~DNS_RCODE_MASK;
1045 flags |= DNS_RCODE_NAME_ERROR;
1046 h->flags = clib_host_to_net_u16 (flags);
1050 /* This is a CNAME record, chase the name chain. */
1053 /* The last request is no longer pending.. */
1054 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
1055 if (ep_index == dm->unresolved_entries[i])
1057 vec_delete (dm->unresolved_entries, 1, i);
1058 goto found_last_request;
1060 clib_warning ("pool elt %d supposedly pending, but not found...", ep_index);
1064 now = vlib_time_now (dm->vlib_main);
1065 cname = vnet_dns_labels_to_name (rr->rdata, reply, &pos2);
1066 /* Save the cname */
1067 vec_add1 (cname, 0);
1068 _vec_len (cname) -= 1;
1069 ep = pool_elt_at_index (dm->entries, ep_index);
1071 ep->flags |= (DNS_CACHE_ENTRY_FLAG_CNAME | DNS_CACHE_ENTRY_FLAG_VALID);
1072 /* Save the response */
1073 if (ep->dns_response)
1074 vec_free (ep->dns_response);
1075 ep->dns_response = reply;
1076 /* Set up expiration time */
1077 ep->expiration_time = now + clib_net_to_host_u32 (rr->ttl);
1079 pool_get (dm->entries, next_ep);
1081 /* Need to recompute ep post pool-get */
1082 ep = pool_elt_at_index (dm->entries, ep_index);
1084 clib_memset (next_ep, 0, sizeof (*next_ep));
1085 next_ep->name = vec_dup (cname);
1086 vec_add1 (next_ep->name, 0);
1087 _vec_len (next_ep->name) -= 1;
1089 hash_set_mem (dm->cache_entry_by_name, next_ep->name,
1090 next_ep - dm->entries);
1092 /* Use the same server */
1093 next_ep->server_rotor = ep->server_rotor;
1094 next_ep->server_af = ep->server_af;
1096 /* Move notification data to the next name in the chain */
1097 #define _(a) next_ep->a = ep->a; ep->a = 0;
1098 foreach_notification_to_move;
1101 request = name_to_labels (cname);
1102 name_copy = vec_dup (request);
1104 qp_offset = vec_len (request);
1106 /* Add space for the query header */
1107 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
1109 qp = (dns_query_t *) (request + qp_offset);
1111 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
1112 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1113 clib_memcpy (qp, name_copy, vec_len (name_copy));
1114 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
1115 vec_free (name_copy);
1117 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1118 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1120 /* Punch in space for the dns_header_t */
1121 vec_insert (request, sizeof (dns_header_t), 0);
1123 h = (dns_header_t *) request;
1125 /* Transaction ID = pool index */
1126 h->id = clib_host_to_net_u16 (next_ep - dm->entries);
1128 /* Ask for a recursive lookup */
1129 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
1130 h->qdcount = clib_host_to_net_u16 (2);
1134 next_ep->dns_request = request;
1135 next_ep->retry_timer = now + 2.0;
1136 next_ep->retry_count = 0;
1139 * Enable this to watch recursive resolution happen...
1140 * fformat (stdout, "%U", format_dns_reply, request, 2);
1143 vec_add1 (dm->unresolved_entries, next_ep - dm->entries);
1144 vnet_send_dns_request (dm, next_ep);
1149 vnet_dns_response_to_reply (u8 * response,
1150 vl_api_dns_resolve_name_reply_t * rmp,
1158 u8 *curpos, *pos, *pos2;
1164 h = (dns_header_t *) response;
1165 flags = clib_net_to_host_u16 (h->flags);
1166 rcode = flags & DNS_RCODE_MASK;
1168 /* See if the response is OK, etc. */
1172 case DNS_RCODE_NO_ERROR:
1175 case DNS_RCODE_NAME_ERROR:
1176 case DNS_RCODE_FORMAT_ERROR:
1177 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1179 case DNS_RCODE_SERVER_FAILURE:
1180 case DNS_RCODE_NOT_IMPLEMENTED:
1181 case DNS_RCODE_REFUSED:
1182 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1185 /* No answers? Loser... */
1186 if (clib_net_to_host_u16 (h->anscount) < 1)
1187 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1189 curpos = (u8 *) (h + 1);
1191 /* Skip the name we asked about */
1194 /* Should never happen, but stil... */
1195 if ((len & 0xC0) == 0xC0)
1199 /* skip the name / label-set */
1208 limit = clib_net_to_host_u16 (h->qdcount);
1209 qp = (dns_query_t *) curpos;
1214 limit = clib_net_to_host_u16 (h->anscount);
1216 for (i = 0; i < limit; i++)
1218 pos = pos2 = curpos;
1221 /* Expect pointer chases in the answer section... */
1222 if ((pos2[0] & 0xC0) == 0xC0)
1225 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1234 if ((pos2[0] & 0xc0) == 0xc0)
1237 * If we've already done one pointer chase,
1238 * do not move the pos pointer.
1240 if (pointer_chase == 0)
1242 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1250 if (pointer_chase == 0)
1253 rr = (dns_rr_t *) pos;
1255 switch (clib_net_to_host_u16 (rr->type))
1258 /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1259 memcpy (rmp->ip4_address, rr->rdata, sizeof (ip4_address_t));
1261 ttl = clib_net_to_host_u32 (rr->ttl);
1262 if (min_ttlp && *min_ttlp > ttl)
1266 /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1267 memcpy (rmp->ip6_address, rr->rdata, sizeof (ip6_address_t));
1268 ttl = clib_net_to_host_u32 (rr->ttl);
1269 if (min_ttlp && *min_ttlp > ttl)
1277 /* Might as well stop ASAP */
1278 if (rmp->ip4_set && rmp->ip6_set)
1280 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1284 if ((rmp->ip4_set + rmp->ip6_set) == 0)
1285 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1290 vnet_dns_response_to_name (u8 * response,
1291 vl_api_dns_resolve_ip_reply_t * rmp,
1299 u8 *curpos, *pos, *pos2;
1304 u8 *junk __attribute__ ((unused));
1308 h = (dns_header_t *) response;
1309 flags = clib_net_to_host_u16 (h->flags);
1310 rcode = flags & DNS_RCODE_MASK;
1312 /* See if the response is OK, etc. */
1316 case DNS_RCODE_NO_ERROR:
1319 case DNS_RCODE_NAME_ERROR:
1320 case DNS_RCODE_FORMAT_ERROR:
1321 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1323 case DNS_RCODE_SERVER_FAILURE:
1324 case DNS_RCODE_NOT_IMPLEMENTED:
1325 case DNS_RCODE_REFUSED:
1326 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1329 /* No answers? Loser... */
1330 if (clib_net_to_host_u16 (h->anscount) < 1)
1331 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1333 curpos = (u8 *) (h + 1);
1335 /* Skip the name we asked about */
1338 /* Should never happen, but stil... */
1339 if ((len & 0xC0) == 0xC0)
1343 /* skip the name / label-set */
1352 limit = clib_net_to_host_u16 (h->qdcount);
1353 qp = (dns_query_t *) curpos;
1358 limit = clib_net_to_host_u16 (h->anscount);
1360 for (i = 0; i < limit; i++)
1362 pos = pos2 = curpos;
1365 /* Expect pointer chases in the answer section... */
1366 if ((pos2[0] & 0xC0) == 0xC0)
1369 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1378 if ((pos2[0] & 0xc0) == 0xc0)
1381 * If we've already done one pointer chase,
1382 * do not move the pos pointer.
1384 if (pointer_chase == 0)
1386 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1394 if (pointer_chase == 0)
1397 rr = (dns_rr_t *) pos;
1399 switch (clib_net_to_host_u16 (rr->type))
1402 name = vnet_dns_labels_to_name (rr->rdata, response, &junk);
1403 memcpy (rmp->name, name, vec_len (name));
1404 ttl = clib_net_to_host_u32 (rr->ttl);
1407 rmp->name[vec_len (name)] = 0;
1413 /* Might as well stop ASAP */
1416 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1421 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1426 vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1428 dns_main_t *dm = &dns_main;
1429 vl_api_dns_resolve_name_reply_t *rmp;
1430 dns_cache_entry_t *ep;
1431 dns_pending_request_t _t0, *t0 = &_t0;
1434 /* Sanitize the name slightly */
1435 mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1437 t0->request_type = DNS_API_PENDING_NAME_TO_IP;
1438 t0->client_index = mp->client_index;
1439 t0->client_context = mp->context;
1441 rv = vnet_dns_resolve_name (dm, mp->name, t0, &ep);
1443 /* Error, e.g. not enabled? Tell the user */
1446 REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1450 /* Resolution pending? Don't reply... */
1455 REPLY_MACRO2(VL_API_DNS_RESOLVE_NAME_REPLY,
1457 rv = vnet_dns_response_to_reply (ep->dns_response, rmp, 0 /* ttl-ptr */);
1458 rmp->retval = clib_host_to_net_u32 (rv);
1463 * dns_resolve_name leaves the cache locked when it returns
1464 * a cached result, so unlock it here.
1466 dns_cache_unlock (dm);
1470 vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
1472 dns_main_t *dm = &dns_main;
1473 vl_api_dns_resolve_ip_reply_t *rmp;
1474 dns_cache_entry_t *ep;
1477 u8 *lookup_name = 0;
1479 dns_pending_request_t _t0, *t0 = &_t0;
1483 for (i = 15; i >= 0; i--)
1485 digit = mp->address[i];
1486 nybble = (digit & 0x0F);
1488 vec_add1 (lookup_name, (nybble - 10) + 'a');
1490 vec_add1 (lookup_name, nybble + '0');
1491 vec_add1 (lookup_name, '.');
1492 nybble = (digit & 0xF0) >> 4;
1494 vec_add1 (lookup_name, (nybble - 10) + 'a');
1496 vec_add1 (lookup_name, nybble + '0');
1497 vec_add1 (lookup_name, '.');
1499 len = vec_len (lookup_name);
1500 vec_validate (lookup_name, len + 8);
1501 memcpy (lookup_name + len, "ip6.arpa", 8);
1505 for (i = 3; i >= 0; i--)
1507 digit = mp->address[i];
1508 lookup_name = format (lookup_name, "%d.", digit);
1510 lookup_name = format (lookup_name, "in-addr.arpa");
1513 vec_add1 (lookup_name, 0);
1515 t0->request_type = DNS_API_PENDING_IP_TO_NAME;
1516 t0->client_index = mp->client_index;
1517 t0->client_context = mp->context;
1519 rv = vnet_dns_resolve_name (dm, lookup_name, t0, &ep);
1521 vec_free (lookup_name);
1523 /* Error, e.g. not enabled? Tell the user */
1526 REPLY_MACRO (VL_API_DNS_RESOLVE_IP_REPLY);
1530 /* Resolution pending? Don't reply... */
1535 REPLY_MACRO2(VL_API_DNS_RESOLVE_IP_REPLY,
1537 rv = vnet_dns_response_to_name (ep->dns_response, rmp, 0 /* ttl-ptr */);
1538 rmp->retval = clib_host_to_net_u32 (rv);
1543 * vnet_dns_resolve_name leaves the cache locked when it returns
1544 * a cached result, so unlock it here.
1546 dns_cache_unlock (dm);
1549 #define vl_msg_name_crc_list
1550 #include <vpp/api/vpe_all_api_h.h>
1551 #undef vl_msg_name_crc_list
1554 setup_message_id_table (api_main_t * am)
1556 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1557 foreach_vl_msg_name_crc_dns;
1561 #define foreach_dns_api_msg \
1562 _(DNS_ENABLE_DISABLE, dns_enable_disable) \
1563 _(DNS_NAME_SERVER_ADD_DEL, dns_name_server_add_del) \
1564 _(DNS_RESOLVE_NAME, dns_resolve_name) \
1565 _(DNS_RESOLVE_IP, dns_resolve_ip)
1567 static clib_error_t *
1568 dns_api_hookup (vlib_main_t * vm)
1571 vl_msg_api_set_handlers(VL_API_##N, #n, \
1572 vl_api_##n##_t_handler, \
1574 vl_api_##n##_t_endian, \
1575 vl_api_##n##_t_print, \
1576 sizeof(vl_api_##n##_t), 1);
1577 foreach_dns_api_msg;
1580 setup_message_id_table (&api_main);
1584 VLIB_API_INIT_FUNCTION (dns_api_hookup);
1587 static clib_error_t *
1588 dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1590 dns_main_t *dm = &dns_main;
1592 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1594 if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1596 else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1599 return clib_error_return (0, "unknown input `%U'",
1600 format_unformat_error, input);
1605 VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1607 static clib_error_t *
1608 dns_init (vlib_main_t * vm)
1610 dns_main_t *dm = &dns_main;
1613 dm->vnet_main = vnet_get_main ();
1614 dm->name_cache_size = 65535;
1615 dm->max_ttl_in_seconds = 86400;
1616 dm->random_seed = 0xDEADDABE;
1621 VLIB_INIT_FUNCTION (dns_init);
1624 unformat_dns_reply (unformat_input_t * input, va_list * args)
1626 u8 **result = va_arg (*args, u8 **);
1627 u8 **namep = va_arg (*args, u8 **);
1641 if (unformat (input, "%v", &name))
1644 if (unformat (input, "%U", unformat_ip4_address, &a4))
1647 if (unformat (input, "%U", unformat_ip6_address, &a6))
1651 if (unformat (input, "%U", unformat_ip6_address, &a6))
1654 if (unformat (input, "%U", unformat_ip4_address, &a6))
1658 /* Must have a name */
1662 /* Must have at least one address */
1663 if (!(a4_set + a6_set))
1666 /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1667 ce = name_to_labels (name);
1668 qp_offset = vec_len (ce);
1670 /* Add space for the query header */
1671 vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1672 qp = (dns_query_t *) (ce + qp_offset);
1674 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1675 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1677 /* Punch in space for the dns_header_t */
1678 vec_insert (ce, sizeof (dns_header_t), 0);
1680 h = (dns_header_t *) ce;
1682 /* Fake Transaction ID */
1685 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1686 h->qdcount = clib_host_to_net_u16 (1);
1687 h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1691 /* Now append one or two A/AAAA RR's... */
1694 /* Pointer to the name (DGMS) */
1695 vec_add1 (ce, 0xC0);
1696 vec_add1 (ce, 0x0C);
1697 vec_add2 (ce, rru8, sizeof (*rr) + 4);
1699 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1700 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1701 rr->ttl = clib_host_to_net_u32 (86400);
1702 rr->rdlength = clib_host_to_net_u16 (4);
1703 memcpy (rr->rdata, &a4, sizeof (a4));
1707 /* Pointer to the name (DGMS) */
1708 vec_add1 (ce, 0xC0);
1709 vec_add1 (ce, 0x0C);
1710 vec_add2 (ce, rru8, sizeof (*rr) + 16);
1712 rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1713 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1714 rr->ttl = clib_host_to_net_u32 (86400);
1715 rr->rdlength = clib_host_to_net_u16 (16);
1716 memcpy (rr->rdata, &a6, sizeof (a6));
1728 format_dns_query (u8 * s, va_list * args)
1730 u8 **curpos = va_arg (*args, u8 **);
1731 int verbose = va_arg (*args, int);
1736 s = format (s, " Name: ");
1738 /* Unwind execrated counted-label sheit */
1744 for (i = 0; i < len; i++)
1745 vec_add1 (s, *pos++);
1757 qp = (dns_query_t *) pos;
1760 switch (clib_net_to_host_u16 (qp->type))
1763 s = format (s, "type A\n");
1766 s = format (s, "type AAAA\n");
1769 s = format (s, "type ALL\n");
1773 s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1778 pos += sizeof (*qp);
1785 * format dns reply data
1786 * verbose > 1, dump everything
1787 * verbose == 1, dump all A and AAAA records
1788 * verbose == 0, dump one A record, and one AAAA record
1792 format_dns_reply_data (u8 * s, va_list * args)
1794 u8 *reply = va_arg (*args, u8 *);
1795 u8 **curpos = va_arg (*args, u8 **);
1796 int verbose = va_arg (*args, int);
1797 int *print_ip4 = va_arg (*args, int *);
1798 int *print_ip6 = va_arg (*args, int *);
1803 int pointer_chase = 0;
1805 u16 rrtype_host_byte_order;
1807 pos = pos2 = *curpos;
1810 s = format (s, " ");
1812 /* chase pointer? almost always yes here... */
1813 if ((pos2[0] & 0xc0) == 0xc0)
1816 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1824 for (i = 0; i < len; i++)
1827 vec_add1 (s, *pos2);
1830 if ((pos2[0] & 0xc0) == 0xc0)
1833 * If we've already done one pointer chase,
1834 * do not move the pos pointer.
1836 if (pointer_chase == 0)
1838 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1856 if (pointer_chase == 0)
1859 rr = (dns_rr_t *) pos;
1860 rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
1862 switch (rrtype_host_byte_order)
1867 s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1868 format_ip4_address, rr->rdata);
1873 s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1874 clib_net_to_host_u32 (rr->ttl));
1879 pos += sizeof (*rr) + 4;
1885 s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1886 format_ip6_address, rr->rdata);
1891 s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1892 clib_net_to_host_u32 (rr->ttl));
1896 pos += sizeof (*rr) + 16;
1902 s = format (s, "TEXT: ");
1903 for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1904 vec_add1 (s, rr->rdata[i]);
1907 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1910 case DNS_TYPE_HINFO:
1912 /* Two counted strings. DGMS */
1918 s = format (s, "HINFO: ");
1921 for (i = 0; i < *len; i++)
1922 vec_add1 (s, *curpos++);
1926 for (i = 0; i < *len; i++)
1927 vec_add1 (s, *curpos++);
1932 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1935 case DNS_TYPE_NAMESERVER:
1938 s = format (s, "Nameserver: ");
1941 /* chase pointer? */
1942 if ((pos2[0] & 0xc0) == 0xc0)
1945 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1952 for (i = 0; i < len; i++)
1953 vec_add1 (s, *pos2++);
1955 /* chase pointer, typically to offset 12... */
1956 if (pos2[0] == 0xC0)
1957 pos2 = reply + pos2[1];
1966 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1969 case DNS_TYPE_MAIL_EXCHANGE:
1972 tp = (u16 *) rr->rdata;
1974 s = format (s, "Mail Exchange: Preference %d ", (u32)
1975 clib_net_to_host_u16 (*tp));
1977 pos2 = rr->rdata + 2;
1979 /* chase pointer? */
1980 if (pos2[0] == 0xc0)
1981 pos2 = reply + pos2[1];
1987 for (i = 0; i < len; i++)
1988 vec_add1 (s, *pos2++);
1991 if (pos2[0] == 0xC0)
1992 pos2 = reply + pos2[1];
2002 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2006 case DNS_TYPE_CNAME:
2009 tp = (u16 *) rr->rdata;
2011 if (rrtype_host_byte_order == DNS_TYPE_CNAME)
2012 s = format (s, "CNAME: ");
2014 s = format (s, "PTR: ");
2018 /* chase pointer? */
2019 if (pos2[0] == 0xc0)
2020 pos2 = reply + pos2[1];
2026 for (i = 0; i < len; i++)
2027 vec_add1 (s, *pos2++);
2030 if (pos2[0] == 0xC0)
2031 pos2 = reply + pos2[1];
2040 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2045 s = format (s, "type %d: len %d\n",
2046 (int) clib_net_to_host_u16 (rr->type),
2047 sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
2048 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2058 format_dns_reply (u8 * s, va_list * args)
2060 u8 *reply_as_u8 = va_arg (*args, u8 *);
2061 int verbose = va_arg (*args, int);
2069 h = (dns_header_t *) reply_as_u8;
2070 id = clib_net_to_host_u16 (h->id);
2071 flags = clib_net_to_host_u16 (h->flags);
2075 s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
2077 s = format (s, " %s %s %s %s\n",
2078 (flags & DNS_RA) ? "recur" : "no-recur",
2079 (flags & DNS_RD) ? "recur-des" : "no-recur-des",
2080 (flags & DNS_TC) ? "trunc" : "no-trunc",
2081 (flags & DNS_AA) ? "auth" : "non-auth");
2082 s = format (s, " %d queries, %d answers, %d name-servers,"
2084 clib_net_to_host_u16 (h->qdcount),
2085 clib_net_to_host_u16 (h->anscount),
2086 clib_net_to_host_u16 (h->nscount),
2087 clib_net_to_host_u16 (h->arcount));
2090 curpos = (u8 *) (h + 1);
2095 s = format (s, " Queries:\n");
2096 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
2098 /* The query is variable-length, so curpos is a value-result parm */
2099 s = format (s, "%U", format_dns_query, &curpos, verbose);
2105 s = format (s, " Replies:\n");
2107 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
2109 /* curpos is a value-result parm */
2110 s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
2111 verbose, &print_ip4, &print_ip6);
2118 format_dns_cache (u8 * s, va_list * args)
2120 dns_main_t *dm = va_arg (*args, dns_main_t *);
2121 f64 now = va_arg (*args, f64);
2122 int verbose = va_arg (*args, int);
2123 u8 *name = va_arg (*args, u8 *);
2124 dns_cache_entry_t *ep;
2128 if (dm->is_enabled == 0)
2130 s = format (s, "The DNS cache is disabled...");
2134 if (pool_elts (dm->entries) == 0)
2136 s = format (s, "The DNS cache is empty...");
2140 dns_cache_lock (dm);
2144 p = hash_get_mem (dm->cache_entry_by_name, name);
2147 s = format (s, "%s is not in the cache...", name);
2148 dns_cache_unlock (dm);
2152 ep = pool_elt_at_index (dm->entries, p[0]);
2153 /* Magic to spit out a C-initializer to research hemorrhoids... */
2157 s = format (s, "static u8 dns_reply_data_initializer[] =\n");
2158 s = format (s, "{\n");
2160 for (i = 0; i < vec_len (ep->dns_response); i++)
2167 s = format (s, "0x%02x, ", ep->dns_response[i]);
2169 s = format (s, "};\n");
2173 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2175 ASSERT (ep->dns_response);
2176 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2181 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2182 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2184 s = format (s, "%s%s -> %U", ss, ep->name,
2185 format_dns_reply, ep->dns_response, verbose);
2186 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2188 f64 time_left = ep->expiration_time - now;
2189 if (time_left > 0.0)
2190 s = format (s, " TTL left %.1f", time_left);
2192 s = format (s, " EXPIRED");
2197 ASSERT (ep->dns_request);
2198 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2207 pool_foreach (ep, dm->entries,
2209 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2211 ASSERT (ep->dns_response);
2212 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2217 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2218 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2220 s = format (s, "%s%s -> %U", ss, ep->name,
2224 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2226 f64 time_left = ep->expiration_time - now;
2227 if (time_left > 0.0)
2228 s = format (s, " TTL left %.1f", time_left);
2230 s = format (s, " EXPIRED");
2233 s = format (s, " %d client notifications pending\n",
2234 vec_len(ep->pending_requests));
2239 ASSERT (ep->dns_request);
2240 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2247 dns_cache_unlock (dm);
2252 static clib_error_t *
2253 show_dns_cache_command_fn (vlib_main_t * vm,
2254 unformat_input_t * input, vlib_cli_command_t * cmd)
2256 dns_main_t *dm = &dns_main;
2259 f64 now = vlib_time_now (vm);
2261 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2263 if (unformat (input, "verbose %d", &verbose))
2265 else if (unformat (input, "verbose"))
2267 else if (unformat (input, "name %s", &name))
2270 return clib_error_return (0, "unknown input `%U'",
2271 format_unformat_error, input);
2274 vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
2280 VLIB_CLI_COMMAND (show_dns_cache_command) =
2282 .path = "show dns cache",
2283 .short_help = "show dns cache [verbose [nn]]",
2284 .function = show_dns_cache_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);
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;
2765 ASSERT (ep && ep->dns_response);
2767 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2769 /* Quick and dirty way to dig up the A-record address. $$ FIXME */
2770 clib_memset (rnr, 0, sizeof (*rnr));
2771 if (vnet_dns_response_to_reply (ep->dns_response, rnr, &ttl))
2773 /* clib_warning ("response_to_reply failed..."); */
2776 if (rnr->ip4_set == 0)
2778 /* clib_warning ("No A-record..."); */
2782 else if (pr->request_type == DNS_PEER_PENDING_IP_TO_NAME)
2784 clib_memset (rir, 0, sizeof (*rir));
2785 if (vnet_dns_response_to_name (ep->dns_response, rir, &ttl))
2787 /* clib_warning ("response_to_name failed..."); */
2793 clib_warning ("Unknown request type %d", pr->request_type);
2797 /* Initialize a buffer */
2800 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2802 b0 = vlib_get_buffer (vm, bi);
2805 if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
2806 vlib_buffer_free_one (vm, b0->next_buffer);
2809 * Reset the buffer. We recycle the DNS request packet in the cache
2810 * hit case, and reply immediately from the request node.
2812 * In the resolution-required / deferred case, resetting a freshly-allocated
2813 * buffer won't hurt. We hope.
2815 b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
2816 | VLIB_BUFFER_TOTAL_LENGTH_VALID);
2817 b0->current_data = 0;
2818 b0->current_length = 0;
2819 b0->total_length_not_including_first_buffer = 0;
2820 vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; /* "local0" */
2821 vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
2823 /* Find a FIB path to the peer we're trying to answer */
2824 clib_memcpy (&prefix.fp_addr.ip4, pr->dst_address, sizeof (ip4_address_t));
2825 prefix.fp_proto = FIB_PROTOCOL_IP4;
2828 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
2829 if (fib_index == (u32) ~ 0)
2831 clib_warning ("no fib table");
2835 fei = fib_table_lookup (fib_index, &prefix);
2837 /* Couldn't find route to destination. Bail out. */
2838 if (fei == FIB_NODE_INDEX_INVALID)
2840 clib_warning ("no route to DNS server");
2844 sw_if_index = fib_entry_get_resolving_interface (fei);
2846 if (sw_if_index == ~0)
2849 ("route to %U exists, fei %d, get_resolving_interface returned"
2850 " ~0", fei, format_ip4_address, &prefix.fp_addr);
2855 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnumbered */,
2857 src_address = ip_interface_address_get_address (lm4, ia);
2858 goto found_src_address;
2862 clib_warning ("FIB BUG");
2867 ip = vlib_buffer_get_current (b0);
2868 udp = (udp_header_t *) (ip + 1);
2869 dns_response = (u8 *) (udp + 1);
2870 clib_memset (ip, 0, sizeof (*ip) + sizeof (*udp));
2873 * Start with the variadic portion of the exercise.
2874 * Turn the name into a set of DNS "labels". Max length
2875 * per label is 63, enforce that.
2877 reply = name_to_labels (pr->name);
2878 vec_free (pr->name);
2880 qp_offset = vec_len (reply);
2882 /* Add space for the query header */
2883 vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
2885 qp = (dns_query_t *) (reply + qp_offset);
2887 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2888 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
2890 qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2892 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
2894 /* Punch in space for the dns_header_t */
2895 vec_insert (reply, sizeof (dns_header_t), 0);
2897 dh = (dns_header_t *) reply;
2899 /* Transaction ID = pool index */
2902 /* Announce that we did a recursive lookup */
2903 tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
2905 tmp |= DNS_RCODE_NAME_ERROR;
2906 dh->flags = clib_host_to_net_u16 (tmp);
2907 dh->qdcount = clib_host_to_net_u16 (1);
2908 dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
2912 /* If the name resolution worked, cough up an appropriate RR */
2915 /* Add the answer. First, a name pointer (0xC00C) */
2916 vec_add1 (reply, 0xC0);
2917 vec_add1 (reply, 0x0C);
2919 /* Now, add single A-rec RR */
2920 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2922 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
2923 rr = (dns_rr_t *) rrptr;
2925 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
2926 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2927 rr->ttl = clib_host_to_net_u32 (ttl);
2928 rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
2929 clib_memcpy (rr->rdata, rnr->ip4_address, sizeof (ip4_address_t));
2933 /* Or a single PTR RR */
2934 u8 *vecname = format (0, "%s", rir->name);
2935 u8 *label_vec = name_to_labels (vecname);
2938 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
2939 rr = (dns_rr_t *) rrptr;
2940 rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2941 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2942 rr->ttl = clib_host_to_net_u32 (ttl);
2943 rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
2944 clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
2945 vec_free (label_vec);
2948 clib_memcpy (dns_response, reply, vec_len (reply));
2950 /* Set the packet length */
2951 b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
2954 ip->ip_version_and_header_length = 0x45;
2955 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
2957 ip->protocol = IP_PROTOCOL_UDP;
2958 ip->src_address.as_u32 = src_address->as_u32;
2959 clib_memcpy (ip->dst_address.as_u8, pr->dst_address,
2960 sizeof (ip4_address_t));
2961 ip->checksum = ip4_header_checksum (ip);
2964 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
2965 udp->dst_port = pr->dst_port;
2966 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
2971 /* Ship it to ip4_lookup */
2972 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
2973 to_next = vlib_frame_vector_args (f);
2976 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
2980 * fd.io coding-style-patch-verification: ON
2983 * eval: (c-set-style "gnu")