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 clib_spinlock_init (&dm->cache_lock);
108 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
115 dns_cache_clear (dm);
121 static void vl_api_dns_enable_disable_t_handler
122 (vl_api_dns_enable_disable_t * mp)
124 vl_api_dns_enable_disable_reply_t *rmp;
125 dns_main_t *dm = &dns_main;
128 rv = dns_enable_disable (dm, mp->enable);
130 REPLY_MACRO (VL_API_DNS_ENABLE_DISABLE_REPLY);
134 dns6_name_server_add_del (dns_main_t * dm,
135 u8 * server_address_as_u8, int is_add)
142 /* Already there? done... */
143 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
145 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
146 sizeof (ip6_address_t)))
150 vec_add2 (dm->ip6_name_servers, ap, 1);
151 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
155 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
157 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
158 sizeof (ip6_address_t)))
160 vec_delete (dm->ip6_name_servers, 1, i);
164 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
170 dns4_name_server_add_del (dns_main_t * dm,
171 u8 * server_address_as_u8, int is_add)
178 /* Already there? done... */
179 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
181 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
182 sizeof (ip4_address_t)))
186 vec_add2 (dm->ip4_name_servers, ap, 1);
187 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
191 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
193 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
194 sizeof (ip4_address_t)))
196 vec_delete (dm->ip4_name_servers, 1, i);
200 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
205 static void vl_api_dns_name_server_add_del_t_handler
206 (vl_api_dns_name_server_add_del_t * mp)
208 dns_main_t *dm = &dns_main;
209 vl_api_dns_name_server_add_del_reply_t *rmp;
213 rv = dns6_name_server_add_del (dm, mp->server_address, mp->is_add);
215 rv = dns4_name_server_add_del (dm, mp->server_address, mp->is_add);
217 REPLY_MACRO (VL_API_DNS_NAME_SERVER_ADD_DEL_REPLY);
221 vnet_dns_send_dns4_request (dns_main_t * dm,
222 dns_cache_entry_t * ep, ip4_address_t * server)
224 vlib_main_t *vm = dm->vlib_main;
225 f64 now = vlib_time_now (vm);
230 fib_node_index_t fei;
231 u32 sw_if_index, fib_index;
233 ip4_main_t *im4 = &ip4_main;
234 ip_lookup_main_t *lm4 = &im4->lookup_main;
235 ip_interface_address_t *ia = 0;
236 ip4_address_t *src_address;
241 ASSERT (ep->dns_request);
243 /* Find a FIB path to the server */
244 clib_memcpy (&prefix.fp_addr.ip4, server, sizeof (*server));
245 prefix.fp_proto = FIB_PROTOCOL_IP4;
248 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
249 if (fib_index == (u32) ~ 0)
252 clib_warning ("no fib table");
256 fei = fib_table_lookup (fib_index, &prefix);
258 /* Couldn't find route to destination. Bail out. */
259 if (fei == FIB_NODE_INDEX_INVALID)
262 clib_warning ("no route to DNS server");
266 sw_if_index = fib_entry_get_resolving_interface (fei);
268 if (sw_if_index == ~0)
272 ("route to %U exists, fei %d, get_resolving_interface returned"
273 " ~0", format_ip4_address, &prefix.fp_addr, fei);
278 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnumbered */,
280 src_address = ip_interface_address_get_address (lm4, ia);
281 goto found_src_address;
285 clib_warning ("FIB BUG");
290 /* Go get a buffer */
291 if (vlib_buffer_alloc (dm->vlib_main, &bi, 1) != 1)
294 b = vlib_get_buffer (vm, bi);
295 b->current_length = sizeof (ip4_header_t) + sizeof (udp_header_t) +
296 vec_len (ep->dns_request);
297 b->total_length_not_including_first_buffer = 0;
299 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
300 vnet_buffer (b)->sw_if_index[VLIB_RX] = 0; /* "local0" */
301 vnet_buffer (b)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
303 ip = vlib_buffer_get_current (b);
304 clib_memset (ip, 0, sizeof (*ip));
305 udp = (udp_header_t *) (ip + 1);
306 clib_memset (udp, 0, sizeof (*udp));
308 dns_request = (u8 *) (udp + 1);
311 ip->ip_version_and_header_length = 0x45;
312 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b));
314 ip->protocol = IP_PROTOCOL_UDP;
315 ip->src_address.as_u32 = src_address->as_u32;
316 ip->dst_address.as_u32 = server->as_u32;
317 ip->checksum = ip4_header_checksum (ip);
320 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
321 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
322 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
323 vec_len (ep->dns_request));
326 /* The actual DNS request */
327 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
329 /* Ship it to ip4_lookup */
330 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
331 to_next = vlib_frame_vector_args (f);
334 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
336 ep->retry_timer = now + 2.0;
340 vnet_dns_send_dns6_request (dns_main_t * dm,
341 dns_cache_entry_t * ep, ip6_address_t * server)
343 vlib_main_t *vm = dm->vlib_main;
344 f64 now = vlib_time_now (vm);
349 fib_node_index_t fei;
350 u32 sw_if_index, fib_index;
352 ip6_main_t *im6 = &ip6_main;
353 ip_lookup_main_t *lm6 = &im6->lookup_main;
354 ip_interface_address_t *ia = 0;
355 ip6_address_t *src_address;
359 int junk __attribute__ ((unused));
361 ASSERT (ep->dns_request);
363 /* Find a FIB path to the server */
364 clib_memcpy (&prefix.fp_addr, server, sizeof (*server));
365 prefix.fp_proto = FIB_PROTOCOL_IP6;
368 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
369 if (fib_index == (u32) ~ 0)
372 clib_warning ("no fib table");
376 fei = fib_table_lookup (fib_index, &prefix);
378 /* Couldn't find route to destination. Bail out. */
379 if (fei == FIB_NODE_INDEX_INVALID)
381 clib_warning ("no route to DNS server");
384 sw_if_index = fib_entry_get_resolving_interface (fei);
387 foreach_ip_interface_address(lm6, ia, sw_if_index, 1 /* honor unnumbered */,
389 src_address = ip_interface_address_get_address (lm6, ia);
390 goto found_src_address;
394 clib_warning ("FIB BUG");
399 /* Go get a buffer */
400 if (vlib_buffer_alloc (dm->vlib_main, &bi, 1) != 1)
403 b = vlib_get_buffer (vm, bi);
404 b->current_length = sizeof (ip6_header_t) + sizeof (udp_header_t) +
405 vec_len (ep->dns_request);
406 b->total_length_not_including_first_buffer = 0;
408 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
410 ip = vlib_buffer_get_current (b);
411 clib_memset (ip, 0, sizeof (*ip));
412 udp = (udp_header_t *) (ip + 1);
413 clib_memset (udp, 0, sizeof (*udp));
415 dns_request = (u8 *) (udp + 1);
418 ip->ip_version_traffic_class_and_flow_label =
419 clib_host_to_net_u32 (0x6 << 28);
422 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b)
423 - sizeof (ip6_header_t));
425 ip->protocol = IP_PROTOCOL_UDP;
426 clib_memcpy (&ip->src_address, src_address, sizeof (ip6_address_t));
427 clib_memcpy (&ip->dst_address, server, sizeof (ip6_address_t));
430 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
431 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
432 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
433 vec_len (ep->dns_request));
435 udp->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ip, &junk);
437 /* The actual DNS request */
438 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
440 /* Ship it to ip6_lookup */
441 f = vlib_get_frame_to_node (vm, ip6_lookup_node.index);
442 to_next = vlib_frame_vector_args (f);
446 ep->retry_timer = now + 2.0;
450 * Translate "foo.com" into "0x3 f o o 0x3 c o m 0x0"
451 * A historical / hysterical micro-TLV scheme. DGMS.
454 name_to_labels (u8 * name)
457 int last_label_index;
462 /* punch in space for the first length */
463 vec_insert (rv, 1, 0);
464 last_label_index = 0;
467 while (i < vec_len (rv))
471 rv[last_label_index] = (i - last_label_index) - 1;
472 if ((i - last_label_index) > 63)
473 clib_warning ("stupid name, label length %d",
474 i - last_label_index);
475 last_label_index = i;
480 /* Set the last real label length */
481 rv[last_label_index] = (i - last_label_index) - 1;
484 * Add a [sic] NULL root label. Otherwise, the name parser can't figure out
492 * arc-function for the above.
493 * Translate "0x3 f o o 0x3 c o m 0x0" into "foo.com"
494 * Produces a non-NULL-terminated u8 *vector. %v format is your friend.
497 vnet_dns_labels_to_name (u8 * label, u8 * full_text, u8 ** parse_from_here)
504 *parse_from_here = 0;
506 /* chase initial pointer? */
507 if ((label[0] & 0xC0) == 0xC0)
509 *parse_from_here = label + 2;
510 offset = ((label[0] & 0x3f) << 8) + label[1];
511 label = full_text + offset;
518 for (i = 0; i < len; i++)
519 vec_add1 (reply, *label++);
522 if ((label[0] & 0xC0) == 0xC0)
524 *parse_from_here = label + 2;
525 offset = ((label[0] & 0x3f) << 8) + label[1];
526 label = full_text + offset;
531 vec_add1 (reply, '.');
533 if (*parse_from_here == 0)
534 *parse_from_here = label;
539 vnet_send_dns_request (dns_main_t * dm, dns_cache_entry_t * ep)
544 u8 *request, *name_copy;
547 /* This can easily happen if sitting in GDB, etc. */
548 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID || ep->server_fails > 1)
551 /* Construct the dns request, if we haven't been here already */
552 if (vec_len (ep->dns_request) == 0)
555 * Start with the variadic portion of the exercise.
556 * Turn the name into a set of DNS "labels". Max length
557 * per label is 63, enforce that.
559 request = name_to_labels (ep->name);
560 name_copy = vec_dup (request);
561 qp_offset = vec_len (request);
564 * At least when testing against "known good" DNS servers:
565 * it turns out that sending 2x requests - one for an A-record
566 * and another for a AAAA-record - seems to work better than
567 * sending a DNS_TYPE_ALL request.
570 /* Add space for the query header */
571 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
573 qp = (dns_query_t *) (request + qp_offset);
575 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
576 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
578 clib_memcpy (qp, name_copy, vec_len (name_copy));
579 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
580 vec_free (name_copy);
582 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
583 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
585 /* Punch in space for the dns_header_t */
586 vec_insert (request, sizeof (dns_header_t), 0);
588 h = (dns_header_t *) request;
590 /* Transaction ID = pool index */
591 h->id = clib_host_to_net_u16 (ep - dm->entries);
593 /* Ask for a recursive lookup */
594 tmp = DNS_RD | DNS_OPCODE_QUERY;
595 h->flags = clib_host_to_net_u16 (tmp);
596 h->qdcount = clib_host_to_net_u16 (2);
600 ep->dns_request = request;
603 /* Work out which server / address family we're going to use */
605 /* Retry using current server */
606 if (ep->retry_count++ < DNS_RETRIES_PER_SERVER)
608 if (ep->server_af == 1 /* ip6 */ )
610 if (vec_len (dm->ip6_name_servers))
612 vnet_dns_send_dns6_request
613 (dm, ep, dm->ip6_name_servers + ep->server_rotor);
619 if (vec_len (dm->ip4_name_servers))
621 vnet_dns_send_dns4_request
622 (dm, ep, dm->ip4_name_servers + ep->server_rotor);
626 else /* switch to a new server */
630 if (ep->server_af == 1 /* ip6 */ )
632 if (ep->server_rotor >= vec_len (dm->ip6_name_servers))
634 ep->server_rotor = 0;
635 ep->server_af = vec_len (dm->ip4_name_servers) > 0 ? 0 : 1;
640 if (ep->server_rotor >= vec_len (dm->ip4_name_servers))
642 ep->server_rotor = 0;
643 ep->server_af = vec_len (dm->ip6_name_servers) > 0 ? 1 : 0;
648 if (ep->server_af == 1 /* ip6 */ )
649 vnet_dns_send_dns6_request
650 (dm, ep, dm->ip6_name_servers + ep->server_rotor);
652 vnet_dns_send_dns4_request
653 (dm, ep, dm->ip4_name_servers + ep->server_rotor);
657 vlib_process_signal_event_mt (dm->vlib_main,
658 dm->resolver_process_node_index,
659 DNS_RESOLVER_EVENT_PENDING, 0);
663 vnet_dns_delete_entry_by_index_nolock (dns_main_t * dm, u32 index)
665 dns_cache_entry_t *ep;
668 if (dm->is_enabled == 0)
669 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
671 if (pool_is_free_index (dm->entries, index))
672 return VNET_API_ERROR_NO_SUCH_ENTRY;
674 ep = pool_elt_at_index (dm->entries, index);
675 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_VALID))
677 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
678 if (index == dm->unresolved_entries[i])
680 vec_delete (dm->unresolved_entries, 1, i);
683 clib_warning ("pool elt %d supposedly pending, but not found...",
688 hash_unset_mem (dm->cache_entry_by_name, ep->name);
690 vec_free (ep->pending_requests);
691 pool_put (dm->entries, ep);
697 dns_delete_by_name (dns_main_t * dm, u8 * name)
702 if (dm->is_enabled == 0)
703 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
706 p = hash_get_mem (dm->cache_entry_by_name, name);
709 dns_cache_unlock (dm);
710 return VNET_API_ERROR_NO_SUCH_ENTRY;
712 rv = vnet_dns_delete_entry_by_index_nolock (dm, p[0]);
714 dns_cache_unlock (dm);
720 delete_random_entry (dns_main_t * dm)
723 u32 victim_index, start_index, i;
725 dns_cache_entry_t *ep;
727 if (dm->is_enabled == 0)
728 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
731 * Silence spurious coverity warning. We know pool_elts >> 0, or
732 * we wouldn't be here...
735 if (pool_elts (dm->entries) == 0)
736 return VNET_API_ERROR_UNSPECIFIED;
740 limit = pool_elts (dm->entries);
741 start_index = random_u32 (&dm->random_seed) % limit;
743 for (i = 0; i < limit; i++)
745 victim_index = (start_index + i) % limit;
747 if (!pool_is_free_index (dm->entries, victim_index))
749 ep = pool_elt_at_index (dm->entries, victim_index);
750 /* Delete only valid, non-static entries */
751 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
752 && ((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0))
754 rv = vnet_dns_delete_entry_by_index_nolock (dm, victim_index);
755 dns_cache_unlock (dm);
760 dns_cache_unlock (dm);
762 clib_warning ("Couldn't find an entry to delete?");
763 return VNET_API_ERROR_UNSPECIFIED;
767 dns_add_static_entry (dns_main_t * dm, u8 * name, u8 * dns_reply_data)
769 dns_cache_entry_t *ep;
773 if (dm->is_enabled == 0)
774 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
777 p = hash_get_mem (dm->cache_entry_by_name, name);
780 dns_cache_unlock (dm);
781 return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
784 if (pool_elts (dm->entries) == dm->name_cache_size)
786 /* Will only fail if the cache is totally filled w/ static entries... */
787 rv = delete_random_entry (dm);
790 dns_cache_unlock (dm);
795 pool_get (dm->entries, ep);
796 clib_memset (ep, 0, sizeof (*ep));
798 /* Note: consumes the name vector */
800 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
801 ep->flags = DNS_CACHE_ENTRY_FLAG_VALID | DNS_CACHE_ENTRY_FLAG_STATIC;
802 ep->dns_response = dns_reply_data;
804 dns_cache_unlock (dm);
809 vnet_dns_resolve_name (dns_main_t * dm, u8 * name, dns_pending_request_t * t,
810 dns_cache_entry_t ** retp)
812 dns_cache_entry_t *ep;
816 dns_pending_request_t *pr;
819 now = vlib_time_now (dm->vlib_main);
821 /* In case we can't actually answer the question right now... */
824 /* binary API caller might forget to set the name. Guess how we know. */
826 return VNET_API_ERROR_INVALID_VALUE;
830 p = hash_get_mem (dm->cache_entry_by_name, name);
833 ep = pool_elt_at_index (dm->entries, p[0]);
834 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
836 /* Has the entry expired? */
837 if (((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0)
838 && (now > ep->expiration_time))
841 u32 *indices_to_delete = 0;
844 * Take out the rest of the resolution chain
845 * This isn't optimal, but it won't happen very often.
849 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME))
851 vec_add1 (indices_to_delete, ep - dm->entries);
853 p = hash_get_mem (dm->cache_entry_by_name, ep->cname);
856 ep = pool_elt_at_index (dm->entries, p[0]);
860 vec_add1 (indices_to_delete, ep - dm->entries);
864 for (i = 0; i < vec_len (indices_to_delete); i++)
866 /* Reenable to watch re-resolutions */
869 ep = pool_elt_at_index (dm->entries,
870 indices_to_delete[i]);
871 clib_warning ("Re-resolve %s", ep->name);
874 vnet_dns_delete_entry_by_index_nolock
875 (dm, indices_to_delete[i]);
877 vec_free (indices_to_delete);
878 /* Yes, kill it... */
882 if (ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
888 /* Note: caller must drop the lock! */
895 * Resolution pending. Add request to the pending vector
896 * by copying the template request
898 vec_add2 (ep->pending_requests, pr, 1);
899 memcpy (pr, t, sizeof (*pr));
900 dns_cache_unlock (dm);
906 if (pool_elts (dm->entries) == dm->name_cache_size)
908 /* Will only fail if the cache is totally filled w/ static entries... */
909 rv = delete_random_entry (dm);
912 dns_cache_unlock (dm);
917 /* add new hash table entry */
918 pool_get (dm->entries, ep);
919 clib_memset (ep, 0, sizeof (*ep));
921 ep->name = format (0, "%s%c", name, 0);
922 _vec_len (ep->name) = vec_len (ep->name) - 1;
924 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
926 vec_add1 (dm->unresolved_entries, ep - dm->entries);
927 vec_add2 (ep->pending_requests, pr, 1);
929 pr->request_type = t->request_type;
931 /* Remember details so we can reply later... */
932 if (t->request_type == DNS_API_PENDING_NAME_TO_IP ||
933 t->request_type == DNS_API_PENDING_IP_TO_NAME)
935 pr->client_index = t->client_index;
936 pr->client_context = t->client_context;
940 pr->client_index = ~0;
941 pr->is_ip6 = t->is_ip6;
942 pr->dst_port = t->dst_port;
949 clib_memcpy (pr->dst_address, t->dst_address, count);
952 vnet_send_dns_request (dm, ep);
953 dns_cache_unlock (dm);
957 #define foreach_notification_to_move \
961 * Handle cname indirection. JFC. Called with the cache locked.
962 * returns 0 if the reply is not a CNAME.
966 vnet_dns_cname_indirection_nolock (dns_main_t * dm, u32 ep_index, u8 * reply)
981 dns_cache_entry_t *ep, *next_ep;
984 h = (dns_header_t *) reply;
985 flags = clib_net_to_host_u16 (h->flags);
986 rcode = flags & DNS_RCODE_MASK;
988 /* See if the response is OK */
991 case DNS_RCODE_NO_ERROR:
994 case DNS_RCODE_NAME_ERROR:
995 case DNS_RCODE_FORMAT_ERROR:
996 case DNS_RCODE_SERVER_FAILURE:
997 case DNS_RCODE_NOT_IMPLEMENTED:
998 case DNS_RCODE_REFUSED:
1002 curpos = (u8 *) (h + 1);
1006 /* Skip the questions */
1007 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
1014 pos += sizeof (dns_query_t);
1017 /* expect a pointer chase here for a CNAME record */
1018 if ((pos2[0] & 0xC0) == 0xC0)
1023 /* Walk the answer(s) to see what to do next */
1024 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
1026 rr = (dns_rr_t *) pos;
1027 switch (clib_net_to_host_u16 (rr->type))
1029 /* Real address record? Done.. */
1034 * Maybe chase a CNAME pointer?
1035 * It's not unheard-of for name-servers to return
1036 * both CNAME and A/AAAA records...
1038 case DNS_TYPE_CNAME:
1042 /* Some other junk, e.g. a nameserver... */
1046 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1048 if ((pos2[0] & 0xc0) == 0xc0)
1052 /* Neither a CNAME nor a real address. Try another server */
1055 flags &= ~DNS_RCODE_MASK;
1056 flags |= DNS_RCODE_NAME_ERROR;
1057 h->flags = clib_host_to_net_u16 (flags);
1061 /* This is a CNAME record, chase the name chain. */
1064 /* The last request is no longer pending.. */
1065 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
1066 if (ep_index == dm->unresolved_entries[i])
1068 vec_delete (dm->unresolved_entries, 1, i);
1069 goto found_last_request;
1071 clib_warning ("pool elt %d supposedly pending, but not found...", ep_index);
1076 now = vlib_time_now (dm->vlib_main);
1077 cname = vnet_dns_labels_to_name (rr->rdata, reply, &pos2);
1078 /* Save the cname */
1079 vec_add1 (cname, 0);
1080 _vec_len (cname) -= 1;
1081 ep = pool_elt_at_index (dm->entries, ep_index);
1083 ep->flags |= (DNS_CACHE_ENTRY_FLAG_CNAME | DNS_CACHE_ENTRY_FLAG_VALID);
1084 /* Save the response */
1085 if (ep->dns_response)
1086 vec_free (ep->dns_response);
1087 ep->dns_response = reply;
1088 /* Set up expiration time */
1089 ep->expiration_time = now + clib_net_to_host_u32 (rr->ttl);
1091 pool_get (dm->entries, next_ep);
1093 /* Need to recompute ep post pool-get */
1094 ep = pool_elt_at_index (dm->entries, ep_index);
1096 clib_memset (next_ep, 0, sizeof (*next_ep));
1097 next_ep->name = vec_dup (cname);
1098 vec_add1 (next_ep->name, 0);
1099 _vec_len (next_ep->name) -= 1;
1101 hash_set_mem (dm->cache_entry_by_name, next_ep->name,
1102 next_ep - dm->entries);
1104 /* Use the same server */
1105 next_ep->server_rotor = ep->server_rotor;
1106 next_ep->server_af = ep->server_af;
1108 /* Move notification data to the next name in the chain */
1109 #define _(a) next_ep->a = ep->a; ep->a = 0;
1110 foreach_notification_to_move;
1113 request = name_to_labels (cname);
1114 name_copy = vec_dup (request);
1116 qp_offset = vec_len (request);
1118 /* Add space for the query header */
1119 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
1121 qp = (dns_query_t *) (request + qp_offset);
1123 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
1124 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1125 clib_memcpy (qp, name_copy, vec_len (name_copy));
1126 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
1127 vec_free (name_copy);
1129 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1130 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1132 /* Punch in space for the dns_header_t */
1133 vec_insert (request, sizeof (dns_header_t), 0);
1135 h = (dns_header_t *) request;
1137 /* Transaction ID = pool index */
1138 h->id = clib_host_to_net_u16 (next_ep - dm->entries);
1140 /* Ask for a recursive lookup */
1141 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
1142 h->qdcount = clib_host_to_net_u16 (2);
1146 next_ep->dns_request = request;
1147 next_ep->retry_timer = now + 2.0;
1148 next_ep->retry_count = 0;
1151 * Enable this to watch recursive resolution happen...
1152 * fformat (stdout, "%U", format_dns_reply, request, 2);
1155 vec_add1 (dm->unresolved_entries, next_ep - dm->entries);
1156 vnet_send_dns_request (dm, next_ep);
1161 vnet_dns_response_to_reply (u8 * response,
1162 vl_api_dns_resolve_name_reply_t * rmp,
1170 u8 *curpos, *pos, *pos2;
1176 h = (dns_header_t *) response;
1177 flags = clib_net_to_host_u16 (h->flags);
1178 rcode = flags & DNS_RCODE_MASK;
1180 /* See if the response is OK, etc. */
1184 case DNS_RCODE_NO_ERROR:
1187 case DNS_RCODE_NAME_ERROR:
1188 case DNS_RCODE_FORMAT_ERROR:
1189 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1191 case DNS_RCODE_SERVER_FAILURE:
1192 case DNS_RCODE_NOT_IMPLEMENTED:
1193 case DNS_RCODE_REFUSED:
1194 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1197 /* No answers? Loser... */
1198 if (clib_net_to_host_u16 (h->anscount) < 1)
1199 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1201 curpos = (u8 *) (h + 1);
1203 /* Skip the name we asked about */
1206 /* Should never happen, but stil... */
1207 if ((len & 0xC0) == 0xC0)
1211 /* skip the name / label-set */
1220 limit = clib_net_to_host_u16 (h->qdcount);
1221 qp = (dns_query_t *) curpos;
1226 limit = clib_net_to_host_u16 (h->anscount);
1228 for (i = 0; i < limit; i++)
1230 pos = pos2 = curpos;
1233 /* Expect pointer chases in the answer section... */
1234 if ((pos2[0] & 0xC0) == 0xC0)
1237 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1246 if ((pos2[0] & 0xc0) == 0xc0)
1249 * If we've already done one pointer chase,
1250 * do not move the pos pointer.
1252 if (pointer_chase == 0)
1254 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1262 if (pointer_chase == 0)
1265 rr = (dns_rr_t *) pos;
1267 switch (clib_net_to_host_u16 (rr->type))
1270 /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1271 memcpy (rmp->ip4_address, rr->rdata, sizeof (ip4_address_t));
1273 ttl = clib_net_to_host_u32 (rr->ttl);
1274 if (min_ttlp && *min_ttlp > ttl)
1278 /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1279 memcpy (rmp->ip6_address, rr->rdata, sizeof (ip6_address_t));
1280 ttl = clib_net_to_host_u32 (rr->ttl);
1281 if (min_ttlp && *min_ttlp > ttl)
1289 /* Might as well stop ASAP */
1290 if (rmp->ip4_set && rmp->ip6_set)
1292 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1296 if ((rmp->ip4_set + rmp->ip6_set) == 0)
1297 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1302 vnet_dns_response_to_name (u8 * response,
1303 vl_api_dns_resolve_ip_reply_t * rmp,
1311 u8 *curpos, *pos, *pos2;
1316 u8 *junk __attribute__ ((unused));
1320 h = (dns_header_t *) response;
1321 flags = clib_net_to_host_u16 (h->flags);
1322 rcode = flags & DNS_RCODE_MASK;
1324 /* See if the response is OK, etc. */
1328 case DNS_RCODE_NO_ERROR:
1331 case DNS_RCODE_NAME_ERROR:
1332 case DNS_RCODE_FORMAT_ERROR:
1333 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1335 case DNS_RCODE_SERVER_FAILURE:
1336 case DNS_RCODE_NOT_IMPLEMENTED:
1337 case DNS_RCODE_REFUSED:
1338 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1341 /* No answers? Loser... */
1342 if (clib_net_to_host_u16 (h->anscount) < 1)
1343 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1345 curpos = (u8 *) (h + 1);
1347 /* Skip the name we asked about */
1350 /* Should never happen, but stil... */
1351 if ((len & 0xC0) == 0xC0)
1355 /* skip the name / label-set */
1364 limit = clib_net_to_host_u16 (h->qdcount);
1365 qp = (dns_query_t *) curpos;
1370 limit = clib_net_to_host_u16 (h->anscount);
1372 for (i = 0; i < limit; i++)
1374 pos = pos2 = curpos;
1377 /* Expect pointer chases in the answer section... */
1378 if ((pos2[0] & 0xC0) == 0xC0)
1381 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1390 if ((pos2[0] & 0xc0) == 0xc0)
1393 * If we've already done one pointer chase,
1394 * do not move the pos pointer.
1396 if (pointer_chase == 0)
1398 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1406 if (pointer_chase == 0)
1409 rr = (dns_rr_t *) pos;
1411 switch (clib_net_to_host_u16 (rr->type))
1414 name = vnet_dns_labels_to_name (rr->rdata, response, &junk);
1415 memcpy (rmp->name, name, vec_len (name));
1416 ttl = clib_net_to_host_u32 (rr->ttl);
1419 rmp->name[vec_len (name)] = 0;
1425 /* Might as well stop ASAP */
1428 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1433 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1438 vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1440 dns_main_t *dm = &dns_main;
1441 vl_api_dns_resolve_name_reply_t *rmp;
1442 dns_cache_entry_t *ep;
1443 dns_pending_request_t _t0, *t0 = &_t0;
1446 /* Sanitize the name slightly */
1447 mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1449 t0->request_type = DNS_API_PENDING_NAME_TO_IP;
1450 t0->client_index = mp->client_index;
1451 t0->client_context = mp->context;
1453 rv = vnet_dns_resolve_name (dm, mp->name, t0, &ep);
1455 /* Error, e.g. not enabled? Tell the user */
1458 REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1462 /* Resolution pending? Don't reply... */
1467 REPLY_MACRO2(VL_API_DNS_RESOLVE_NAME_REPLY,
1469 rv = vnet_dns_response_to_reply (ep->dns_response, rmp, 0 /* ttl-ptr */);
1470 rmp->retval = clib_host_to_net_u32 (rv);
1475 * dns_resolve_name leaves the cache locked when it returns
1476 * a cached result, so unlock it here.
1478 dns_cache_unlock (dm);
1482 vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
1484 dns_main_t *dm = &dns_main;
1485 vl_api_dns_resolve_ip_reply_t *rmp;
1486 dns_cache_entry_t *ep;
1489 u8 *lookup_name = 0;
1491 dns_pending_request_t _t0, *t0 = &_t0;
1495 for (i = 15; i >= 0; i--)
1497 digit = mp->address[i];
1498 nybble = (digit & 0x0F);
1500 vec_add1 (lookup_name, (nybble - 10) + 'a');
1502 vec_add1 (lookup_name, nybble + '0');
1503 vec_add1 (lookup_name, '.');
1504 nybble = (digit & 0xF0) >> 4;
1506 vec_add1 (lookup_name, (nybble - 10) + 'a');
1508 vec_add1 (lookup_name, nybble + '0');
1509 vec_add1 (lookup_name, '.');
1511 len = vec_len (lookup_name);
1512 vec_validate (lookup_name, len + 8);
1513 memcpy (lookup_name + len, "ip6.arpa", 8);
1517 for (i = 3; i >= 0; i--)
1519 digit = mp->address[i];
1520 lookup_name = format (lookup_name, "%d.", digit);
1522 lookup_name = format (lookup_name, "in-addr.arpa");
1525 vec_add1 (lookup_name, 0);
1527 t0->request_type = DNS_API_PENDING_IP_TO_NAME;
1528 t0->client_index = mp->client_index;
1529 t0->client_context = mp->context;
1531 rv = vnet_dns_resolve_name (dm, lookup_name, t0, &ep);
1533 vec_free (lookup_name);
1535 /* Error, e.g. not enabled? Tell the user */
1538 REPLY_MACRO (VL_API_DNS_RESOLVE_IP_REPLY);
1542 /* Resolution pending? Don't reply... */
1547 REPLY_MACRO2(VL_API_DNS_RESOLVE_IP_REPLY,
1549 rv = vnet_dns_response_to_name (ep->dns_response, rmp, 0 /* ttl-ptr */);
1550 rmp->retval = clib_host_to_net_u32 (rv);
1555 * vnet_dns_resolve_name leaves the cache locked when it returns
1556 * a cached result, so unlock it here.
1558 dns_cache_unlock (dm);
1561 #define vl_msg_name_crc_list
1562 #include <vpp/api/vpe_all_api_h.h>
1563 #undef vl_msg_name_crc_list
1566 setup_message_id_table (api_main_t * am)
1568 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1569 foreach_vl_msg_name_crc_dns;
1573 #define foreach_dns_api_msg \
1574 _(DNS_ENABLE_DISABLE, dns_enable_disable) \
1575 _(DNS_NAME_SERVER_ADD_DEL, dns_name_server_add_del) \
1576 _(DNS_RESOLVE_NAME, dns_resolve_name) \
1577 _(DNS_RESOLVE_IP, dns_resolve_ip)
1579 static clib_error_t *
1580 dns_api_hookup (vlib_main_t * vm)
1583 vl_msg_api_set_handlers(VL_API_##N, #n, \
1584 vl_api_##n##_t_handler, \
1586 vl_api_##n##_t_endian, \
1587 vl_api_##n##_t_print, \
1588 sizeof(vl_api_##n##_t), 1);
1589 foreach_dns_api_msg;
1592 setup_message_id_table (&api_main);
1596 VLIB_API_INIT_FUNCTION (dns_api_hookup);
1599 static clib_error_t *
1600 dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1602 dns_main_t *dm = &dns_main;
1604 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1606 if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1608 else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1611 return clib_error_return (0, "unknown input `%U'",
1612 format_unformat_error, input);
1617 VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1619 static clib_error_t *
1620 dns_init (vlib_main_t * vm)
1622 dns_main_t *dm = &dns_main;
1625 dm->vnet_main = vnet_get_main ();
1626 dm->name_cache_size = 65535;
1627 dm->max_ttl_in_seconds = 86400;
1628 dm->random_seed = 0xDEADDABE;
1633 VLIB_INIT_FUNCTION (dns_init);
1636 unformat_dns_reply (unformat_input_t * input, va_list * args)
1638 u8 **result = va_arg (*args, u8 **);
1639 u8 **namep = va_arg (*args, u8 **);
1653 if (unformat (input, "%v", &name))
1656 if (unformat (input, "%U", unformat_ip4_address, &a4))
1659 if (unformat (input, "%U", unformat_ip6_address, &a6))
1663 if (unformat (input, "%U", unformat_ip6_address, &a6))
1666 if (unformat (input, "%U", unformat_ip4_address, &a6))
1670 /* Must have a name */
1674 /* Must have at least one address */
1675 if (!(a4_set + a6_set))
1678 /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1679 ce = name_to_labels (name);
1680 qp_offset = vec_len (ce);
1682 /* Add space for the query header */
1683 vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1684 qp = (dns_query_t *) (ce + qp_offset);
1686 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1687 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1689 /* Punch in space for the dns_header_t */
1690 vec_insert (ce, sizeof (dns_header_t), 0);
1692 h = (dns_header_t *) ce;
1694 /* Fake Transaction ID */
1697 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1698 h->qdcount = clib_host_to_net_u16 (1);
1699 h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1703 /* Now append one or two A/AAAA RR's... */
1706 /* Pointer to the name (DGMS) */
1707 vec_add1 (ce, 0xC0);
1708 vec_add1 (ce, 0x0C);
1709 vec_add2 (ce, rru8, sizeof (*rr) + 4);
1711 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1712 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1713 rr->ttl = clib_host_to_net_u32 (86400);
1714 rr->rdlength = clib_host_to_net_u16 (4);
1715 memcpy (rr->rdata, &a4, sizeof (a4));
1719 /* Pointer to the name (DGMS) */
1720 vec_add1 (ce, 0xC0);
1721 vec_add1 (ce, 0x0C);
1722 vec_add2 (ce, rru8, sizeof (*rr) + 16);
1724 rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1725 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1726 rr->ttl = clib_host_to_net_u32 (86400);
1727 rr->rdlength = clib_host_to_net_u16 (16);
1728 memcpy (rr->rdata, &a6, sizeof (a6));
1740 format_dns_query (u8 * s, va_list * args)
1742 u8 **curpos = va_arg (*args, u8 **);
1743 int verbose = va_arg (*args, int);
1748 s = format (s, " Name: ");
1750 /* Unwind execrated counted-label sheit */
1756 for (i = 0; i < len; i++)
1757 vec_add1 (s, *pos++);
1769 qp = (dns_query_t *) pos;
1772 switch (clib_net_to_host_u16 (qp->type))
1775 s = format (s, "type A\n");
1778 s = format (s, "type AAAA\n");
1781 s = format (s, "type ALL\n");
1785 s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1790 pos += sizeof (*qp);
1797 * format dns reply data
1798 * verbose > 1, dump everything
1799 * verbose == 1, dump all A and AAAA records
1800 * verbose == 0, dump one A record, and one AAAA record
1804 format_dns_reply_data (u8 * s, va_list * args)
1806 u8 *reply = va_arg (*args, u8 *);
1807 u8 **curpos = va_arg (*args, u8 **);
1808 int verbose = va_arg (*args, int);
1809 int *print_ip4 = va_arg (*args, int *);
1810 int *print_ip6 = va_arg (*args, int *);
1815 int pointer_chase = 0;
1817 u16 rrtype_host_byte_order;
1819 pos = pos2 = *curpos;
1822 s = format (s, " ");
1824 /* chase pointer? almost always yes here... */
1825 if ((pos2[0] & 0xc0) == 0xc0)
1828 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1836 for (i = 0; i < len; i++)
1839 vec_add1 (s, *pos2);
1842 if ((pos2[0] & 0xc0) == 0xc0)
1845 * If we've already done one pointer chase,
1846 * do not move the pos pointer.
1848 if (pointer_chase == 0)
1850 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1868 if (pointer_chase == 0)
1871 rr = (dns_rr_t *) pos;
1872 rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
1874 switch (rrtype_host_byte_order)
1879 s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1880 format_ip4_address, rr->rdata);
1885 s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1886 clib_net_to_host_u32 (rr->ttl));
1891 pos += sizeof (*rr) + 4;
1897 s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1898 format_ip6_address, rr->rdata);
1903 s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1904 clib_net_to_host_u32 (rr->ttl));
1908 pos += sizeof (*rr) + 16;
1914 s = format (s, "TEXT: ");
1915 for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1916 vec_add1 (s, rr->rdata[i]);
1919 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1922 case DNS_TYPE_HINFO:
1924 /* Two counted strings. DGMS */
1930 s = format (s, "HINFO: ");
1933 for (i = 0; i < *len; i++)
1934 vec_add1 (s, *curpos++);
1938 for (i = 0; i < *len; i++)
1939 vec_add1 (s, *curpos++);
1944 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1947 case DNS_TYPE_NAMESERVER:
1950 s = format (s, "Nameserver: ");
1953 /* chase pointer? */
1954 if ((pos2[0] & 0xc0) == 0xc0)
1957 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1964 for (i = 0; i < len; i++)
1965 vec_add1 (s, *pos2++);
1967 /* chase pointer, typically to offset 12... */
1968 if (pos2[0] == 0xC0)
1969 pos2 = reply + pos2[1];
1978 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1981 case DNS_TYPE_MAIL_EXCHANGE:
1984 tp = (u16 *) rr->rdata;
1986 s = format (s, "Mail Exchange: Preference %d ", (u32)
1987 clib_net_to_host_u16 (*tp));
1989 pos2 = rr->rdata + 2;
1991 /* chase pointer? */
1992 if (pos2[0] == 0xc0)
1993 pos2 = reply + pos2[1];
1999 for (i = 0; i < len; i++)
2000 vec_add1 (s, *pos2++);
2003 if (pos2[0] == 0xC0)
2004 pos2 = reply + pos2[1];
2014 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2018 case DNS_TYPE_CNAME:
2021 tp = (u16 *) rr->rdata;
2023 if (rrtype_host_byte_order == DNS_TYPE_CNAME)
2024 s = format (s, "CNAME: ");
2026 s = format (s, "PTR: ");
2030 /* chase pointer? */
2031 if (pos2[0] == 0xc0)
2032 pos2 = reply + pos2[1];
2038 for (i = 0; i < len; i++)
2039 vec_add1 (s, *pos2++);
2042 if (pos2[0] == 0xC0)
2043 pos2 = reply + pos2[1];
2052 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2057 s = format (s, "type %d: len %d\n",
2058 (int) clib_net_to_host_u16 (rr->type),
2059 sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
2060 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2070 format_dns_reply (u8 * s, va_list * args)
2072 u8 *reply_as_u8 = va_arg (*args, u8 *);
2073 int verbose = va_arg (*args, int);
2081 h = (dns_header_t *) reply_as_u8;
2082 id = clib_net_to_host_u16 (h->id);
2083 flags = clib_net_to_host_u16 (h->flags);
2087 s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
2089 s = format (s, " %s %s %s %s\n",
2090 (flags & DNS_RA) ? "recur" : "no-recur",
2091 (flags & DNS_RD) ? "recur-des" : "no-recur-des",
2092 (flags & DNS_TC) ? "trunc" : "no-trunc",
2093 (flags & DNS_AA) ? "auth" : "non-auth");
2094 s = format (s, " %d queries, %d answers, %d name-servers,"
2096 clib_net_to_host_u16 (h->qdcount),
2097 clib_net_to_host_u16 (h->anscount),
2098 clib_net_to_host_u16 (h->nscount),
2099 clib_net_to_host_u16 (h->arcount));
2102 curpos = (u8 *) (h + 1);
2107 s = format (s, " Queries:\n");
2108 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
2110 /* The query is variable-length, so curpos is a value-result parm */
2111 s = format (s, "%U", format_dns_query, &curpos, verbose);
2117 s = format (s, " Replies:\n");
2119 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
2121 /* curpos is a value-result parm */
2122 s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
2123 verbose, &print_ip4, &print_ip6);
2130 format_dns_cache (u8 * s, va_list * args)
2132 dns_main_t *dm = va_arg (*args, dns_main_t *);
2133 f64 now = va_arg (*args, f64);
2134 int verbose = va_arg (*args, int);
2135 u8 *name = va_arg (*args, u8 *);
2136 dns_cache_entry_t *ep;
2140 if (dm->is_enabled == 0)
2142 s = format (s, "The DNS cache is disabled...");
2146 if (pool_elts (dm->entries) == 0)
2148 s = format (s, "The DNS cache is empty...");
2152 dns_cache_lock (dm);
2156 p = hash_get_mem (dm->cache_entry_by_name, name);
2159 s = format (s, "%s is not in the cache...", name);
2160 dns_cache_unlock (dm);
2164 ep = pool_elt_at_index (dm->entries, p[0]);
2165 /* Magic to spit out a C-initializer to research hemorrhoids... */
2169 s = format (s, "static u8 dns_reply_data_initializer[] =\n");
2170 s = format (s, "{\n");
2172 for (i = 0; i < vec_len (ep->dns_response); i++)
2179 s = format (s, "0x%02x, ", ep->dns_response[i]);
2181 s = format (s, "};\n");
2185 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2187 ASSERT (ep->dns_response);
2188 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2193 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2194 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2196 s = format (s, "%s%s -> %U", ss, ep->name,
2197 format_dns_reply, ep->dns_response, verbose);
2198 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2200 f64 time_left = ep->expiration_time - now;
2201 if (time_left > 0.0)
2202 s = format (s, " TTL left %.1f", time_left);
2204 s = format (s, " EXPIRED");
2209 ASSERT (ep->dns_request);
2210 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2218 s = format (s, "DNS cache contains %d entries\n", pool_elts (dm->entries));
2223 pool_foreach (ep, dm->entries,
2225 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2227 ASSERT (ep->dns_response);
2228 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2233 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2234 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2236 s = format (s, "%s%s -> %U", ss, ep->name,
2240 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2242 f64 time_left = ep->expiration_time - now;
2243 if (time_left > 0.0)
2244 s = format (s, " TTL left %.1f", time_left);
2246 s = format (s, " EXPIRED");
2249 s = format (s, " %d client notifications pending\n",
2250 vec_len(ep->pending_requests));
2255 ASSERT (ep->dns_request);
2256 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2264 dns_cache_unlock (dm);
2269 static clib_error_t *
2270 show_dns_cache_command_fn (vlib_main_t * vm,
2271 unformat_input_t * input, vlib_cli_command_t * cmd)
2273 dns_main_t *dm = &dns_main;
2276 f64 now = vlib_time_now (vm);
2278 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2280 if (unformat (input, "verbose %d", &verbose))
2282 else if (unformat (input, "verbose"))
2284 else if (unformat (input, "name %s", &name))
2287 return clib_error_return (0, "unknown input `%U'",
2288 format_unformat_error, input);
2291 vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
2297 VLIB_CLI_COMMAND (show_dns_cache_command) =
2299 .path = "show dns cache",
2300 .short_help = "show dns cache [verbose [nn]]",
2301 .function = show_dns_cache_command_fn,
2305 static clib_error_t *
2306 dns_cache_add_del_command_fn (vlib_main_t * vm,
2307 unformat_input_t * input,
2308 vlib_cli_command_t * cmd)
2310 dns_main_t *dm = &dns_main;
2316 clib_error_t *error;
2318 if (unformat (input, "add"))
2320 if (unformat (input, "del"))
2322 if (unformat (input, "clear"))
2325 if (is_add == -1 && is_clear == -1)
2326 return clib_error_return (0, "add / del / clear required...");
2330 rv = dns_cache_clear (dm);
2336 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2337 error = clib_error_return (0, "Name resolution not enabled");
2342 /* Delete (by name)? */
2345 if (unformat (input, "%v", &name))
2347 rv = dns_delete_by_name (dm, name);
2350 case VNET_API_ERROR_NO_SUCH_ENTRY:
2351 error = clib_error_return (0, "%v not in the cache...", name);
2355 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2356 error = clib_error_return (0, "Name resolution not enabled");
2365 error = clib_error_return (0, "dns_delete_by_name returned %d",
2371 return clib_error_return (0, "unknown input `%U'",
2372 format_unformat_error, input);
2375 /* Note: dns_add_static_entry consumes the name vector if OK... */
2376 if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2378 rv = dns_add_static_entry (dm, name, dns_reply_data);
2381 case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2383 vec_free (dns_reply_data);
2384 return clib_error_return (0, "%v already in the cache...", name);
2389 return clib_error_return (0, "dns_add_static_entry returned %d",
2398 VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2400 .path = "dns cache",
2401 .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2402 .function = dns_cache_add_del_command_fn,
2406 #define DNS_FORMAT_TEST 1
2408 #if DNS_FORMAT_TEST > 0
2411 static u8 dns_reply_data_initializer[] =
2412 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2413 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2415 0x0, 0xff, /* type ALL */
2416 0x0, 0x1, /* class IN */
2417 0xc0, 0xc, /* pointer to yahoo.com name */
2418 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2419 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2420 0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2421 0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2422 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2423 0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2424 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2425 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2426 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2427 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2428 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2429 0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2430 0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2432 0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2433 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2434 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2435 0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2436 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2438 0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2439 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2440 0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2441 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2443 0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2444 0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2446 0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2448 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2450 0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2452 0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2453 0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2454 0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2458 /* www.cisco.com, has no addresses in reply */
2459 static u8 dns_reply_data_initializer[] = {
2460 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2461 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2462 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2464 0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2465 0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2466 0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2467 0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2468 0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2471 /* bind8 (linux widget, w/ nasty double pointer chasees */
2472 static u8 dns_reply_data_initializer[] = {
2474 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08,
2476 0x00, 0x06, 0x00, 0x06, 0x0a, 0x6f, 0x72, 0x69,
2478 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77, 0x77, 0x05,
2480 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f,
2482 0x6d, 0x00, 0x00, 0xff, 0x00, 0x01, 0x0a, 0x6f,
2484 0x72, 0x69, 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77,
2486 0x77, 0x05, 0x43, 0x49, 0x53, 0x43, 0x4f, 0xc0,
2489 0x1d, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2492 0x9a, 0x00, 0x18, 0x15, 0x72, 0x63, 0x64,
2493 0x6e, 0x39, 0x2d, 0x31, 0x34, 0x70, 0x2d, 0x64, 0x63,
2494 0x7a, 0x30, 0x35, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31,
2495 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00, 0x01, 0x00,
2496 0x00, 0x05, 0x9a, 0x00, 0x1a, 0x17, 0x61, 0x6c, 0x6c,
2497 0x6e, 0x30, 0x31, 0x2d, 0x61, 0x67, 0x30, 0x39, 0x2d,
2498 0x64, 0x63, 0x7a, 0x30, 0x33, 0x6e, 0x2d, 0x67, 0x73,
2499 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00,
2500 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x10, 0x0d, 0x72,
2501 0x74, 0x70, 0x35, 0x2d, 0x64, 0x6d, 0x7a, 0x2d, 0x67,
2502 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2503 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x18, 0x15,
2504 0x6d, 0x74, 0x76, 0x35, 0x2d, 0x61, 0x70, 0x31, 0x30,
2505 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x36, 0x6e, 0x2d, 0x67,
2506 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2507 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x1b, 0x18,
2508 0x73, 0x6e, 0x67, 0x64, 0x63, 0x30, 0x31, 0x2d, 0x61,
2509 0x62, 0x30, 0x37, 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x31,
2510 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0,
2511 0x26, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a,
2512 0x00, 0x1a, 0x17, 0x61, 0x65, 0x72, 0x30, 0x31, 0x2d,
2513 0x72, 0x34, 0x63, 0x32, 0x35, 0x2d, 0x64, 0x63, 0x7a,
2514 0x30, 0x31, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0,
2515 0x17, 0xc0, 0x26, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2516 0x00, 0x81, 0x00, 0x04, 0x48, 0xa3, 0x04, 0xa1, 0xc0,
2517 0x26, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82,
2518 0x00, 0x10, 0x20, 0x01, 0x04, 0x20, 0x12, 0x01, 0x00,
2519 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
2520 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2521 0x9a, 0x00, 0x02, 0xc0, 0xf4, 0xc0, 0x0c, 0x00, 0x02,
2522 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0,
2523 0xcd, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00,
2524 0x05, 0x9a, 0x00, 0x02, 0xc0, 0x8d, 0xc0, 0x0c, 0x00,
2525 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02,
2526 0xc0, 0x43, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00,
2527 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0, 0xa9, 0xc0, 0x0c,
2528 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00,
2529 0x02, 0xc0, 0x67, 0xc0, 0x8d, 0x00, 0x01, 0x00, 0x01,
2530 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0x40, 0x66, 0xf6,
2531 0x05, 0xc0, 0xa9, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2532 0x07, 0x08, 0x00, 0x04, 0xad, 0x24, 0xe0, 0x64, 0xc0,
2533 0x43, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08,
2534 0x00, 0x04, 0x48, 0xa3, 0x04, 0x1c, 0xc0, 0xf4, 0x00,
2535 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04,
2536 0xad, 0x26, 0xd4, 0x6c, 0xc0, 0x67, 0x00, 0x01, 0x00,
2537 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x25,
2538 0x90, 0x64, 0xc0, 0xcd, 0x00, 0x01, 0x00, 0x01, 0x00,
2539 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x27, 0x70, 0x44,
2543 static u8 dns_reply_data_initializer[] =
2544 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
2545 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
2546 0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
2547 0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
2549 0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
2550 0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
2551 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
2552 0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
2553 0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
2554 0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
2555 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
2556 0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
2557 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
2558 0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
2559 0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
2560 0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
2561 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
2562 0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
2563 0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
2564 0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
2565 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2566 0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
2567 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
2568 0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
2569 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
2570 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
2571 0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
2573 0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2577 /* www.weatherlink.com */
2578 static u8 dns_reply_data_initializer[] = {
2579 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2580 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x0b,
2581 0x77, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x6c, 0x69,
2582 0x6e, 0x6b, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0xff,
2583 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00,
2584 0x00, 0x0c, 0x9e, 0x00, 0x1f, 0x0e, 0x64, 0x33, 0x6b,
2585 0x72, 0x30, 0x67, 0x75, 0x62, 0x61, 0x31, 0x64, 0x76,
2586 0x77, 0x66, 0x0a, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x66,
2587 0x72, 0x6f, 0x6e, 0x74, 0x03, 0x6e, 0x65, 0x74, 0x00,
2592 static clib_error_t *
2593 test_dns_fmt_command_fn (vlib_main_t * vm,
2594 unformat_input_t * input, vlib_cli_command_t * cmd)
2596 u8 *dns_reply_data = 0;
2599 vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2601 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2603 if (unformat (input, "verbose %d", &verbose))
2605 else if (unformat (input, "verbose"))
2608 return clib_error_return (0, "unknown input `%U'",
2609 format_unformat_error, input);
2612 vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2614 memcpy (dns_reply_data, dns_reply_data_initializer,
2615 ARRAY_LEN (dns_reply_data_initializer));
2617 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2619 clib_memset (rmp, 0, sizeof (*rmp));
2621 rv = vnet_dns_response_to_reply (dns_reply_data, rmp, 0 /* ttl-ptr */ );
2625 case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2626 vlib_cli_output (vm, "no addresses found...");
2630 vlib_cli_output (vm, "response to reply returned %d", rv);
2635 vlib_cli_output (vm, "ip4 address: %U", format_ip4_address,
2636 (ip4_address_t *) rmp->ip4_address);
2638 vlib_cli_output (vm, "ip6 address: %U", format_ip6_address,
2639 (ip6_address_t *) rmp->ip6_address);
2643 vec_free (dns_reply_data);
2650 VLIB_CLI_COMMAND (test_dns_fmt_command) =
2652 .path = "test dns format",
2653 .short_help = "test dns format",
2654 .function = test_dns_fmt_command_fn,
2658 static clib_error_t *
2659 test_dns_unfmt_command_fn (vlib_main_t * vm,
2660 unformat_input_t * input, vlib_cli_command_t * cmd)
2662 u8 *dns_reply_data = 0;
2666 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2668 if (unformat (input, "verbose %d", &verbose))
2670 else if (unformat (input, "verbose"))
2672 else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2675 return clib_error_return (0, "unknown input `%U'",
2676 format_unformat_error, input);
2680 return clib_error_return (0, "dns data not set...");
2682 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2684 vec_free (dns_reply_data);
2690 VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2692 .path = "test dns unformat",
2693 .short_help = "test dns unformat <name> [ip4][ip6]",
2694 .function = test_dns_unfmt_command_fn,
2698 static clib_error_t *
2699 test_dns_expire_command_fn (vlib_main_t * vm,
2700 unformat_input_t * input,
2701 vlib_cli_command_t * cmd)
2703 dns_main_t *dm = &dns_main;
2707 dns_cache_entry_t *ep;
2709 if (unformat (input, "%v", &name))
2712 _vec_len (name) -= 1;
2715 return clib_error_return (0, "no name provided");
2717 dns_cache_lock (dm);
2719 p = hash_get_mem (dm->cache_entry_by_name, name);
2722 dns_cache_unlock (dm);
2723 e = clib_error_return (0, "%s is not in the cache...", name);
2728 ep = pool_elt_at_index (dm->entries, p[0]);
2730 ep->expiration_time = 0;
2736 VLIB_CLI_COMMAND (test_dns_expire_command) =
2738 .path = "test dns expire",
2739 .short_help = "test dns expire <name>",
2740 .function = test_dns_expire_command_fn,
2746 vnet_send_dns6_reply (dns_main_t * dm, dns_pending_request_t * pr,
2747 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2749 clib_warning ("Unimplemented...");
2754 vnet_send_dns4_reply (dns_main_t * dm, dns_pending_request_t * pr,
2755 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2757 vlib_main_t *vm = dm->vlib_main;
2759 fib_prefix_t prefix;
2760 fib_node_index_t fei;
2761 u32 sw_if_index, fib_index;
2762 ip4_main_t *im4 = &ip4_main;
2763 ip_lookup_main_t *lm4 = &im4->lookup_main;
2764 ip_interface_address_t *ia = 0;
2765 ip4_address_t *src_address;
2773 vl_api_dns_resolve_name_reply_t _rnr, *rnr = &_rnr;
2774 vl_api_dns_resolve_ip_reply_t _rir, *rir = &_rir;
2781 int is_recycle = (b0 != 0);
2783 ASSERT (ep && ep->dns_response);
2785 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2787 /* Quick and dirty way to dig up the A-record address. $$ FIXME */
2788 clib_memset (rnr, 0, sizeof (*rnr));
2789 if (vnet_dns_response_to_reply (ep->dns_response, rnr, &ttl))
2791 /* clib_warning ("response_to_reply failed..."); */
2794 if (rnr->ip4_set == 0)
2796 /* clib_warning ("No A-record..."); */
2800 else if (pr->request_type == DNS_PEER_PENDING_IP_TO_NAME)
2802 clib_memset (rir, 0, sizeof (*rir));
2803 if (vnet_dns_response_to_name (ep->dns_response, rir, &ttl))
2805 /* clib_warning ("response_to_name failed..."); */
2811 clib_warning ("Unknown request type %d", pr->request_type);
2815 /* Initialize a buffer */
2818 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2820 b0 = vlib_get_buffer (vm, bi);
2824 /* Use the buffer we were handed. Reinitialize it... */
2825 vlib_buffer_t bt = { };
2826 /* push/pop the reference count */
2827 u8 save_ref_count = b0->ref_count;
2828 vlib_buffer_copy_template (b0, &bt);
2829 b0->ref_count = save_ref_count;
2830 bi = vlib_get_buffer_index (vm, b0);
2833 if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
2834 vlib_buffer_free_one (vm, b0->next_buffer);
2837 * Reset the buffer. We recycle the DNS request packet in the cache
2838 * hit case, and reply immediately from the request node.
2840 * In the resolution-required / deferred case, resetting a freshly-allocated
2841 * buffer won't hurt. We hope.
2843 b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
2844 | VLIB_BUFFER_TOTAL_LENGTH_VALID);
2845 vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; /* "local0" */
2846 vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
2848 /* Find a FIB path to the peer we're trying to answer */
2849 clib_memcpy (&prefix.fp_addr.ip4, pr->dst_address, sizeof (ip4_address_t));
2850 prefix.fp_proto = FIB_PROTOCOL_IP4;
2853 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
2854 if (fib_index == (u32) ~ 0)
2856 clib_warning ("no fib table");
2860 fei = fib_table_lookup (fib_index, &prefix);
2862 /* Couldn't find route to destination. Bail out. */
2863 if (fei == FIB_NODE_INDEX_INVALID)
2865 clib_warning ("no route to DNS server");
2869 sw_if_index = fib_entry_get_resolving_interface (fei);
2871 if (sw_if_index == ~0)
2874 ("route to %U exists, fei %d, get_resolving_interface returned"
2875 " ~0", fei, format_ip4_address, &prefix.fp_addr);
2880 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnumbered */,
2882 src_address = ip_interface_address_get_address (lm4, ia);
2883 goto found_src_address;
2887 clib_warning ("FIB BUG");
2892 ip = vlib_buffer_get_current (b0);
2893 udp = (udp_header_t *) (ip + 1);
2894 dns_response = (u8 *) (udp + 1);
2895 clib_memset (ip, 0, sizeof (*ip) + sizeof (*udp));
2898 * Start with the variadic portion of the exercise.
2899 * Turn the name into a set of DNS "labels". Max length
2900 * per label is 63, enforce that.
2902 reply = name_to_labels (pr->name);
2903 vec_free (pr->name);
2905 qp_offset = vec_len (reply);
2907 /* Add space for the query header */
2908 vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
2910 qp = (dns_query_t *) (reply + qp_offset);
2912 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2913 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
2915 qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2917 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
2919 /* Punch in space for the dns_header_t */
2920 vec_insert (reply, sizeof (dns_header_t), 0);
2922 dh = (dns_header_t *) reply;
2924 /* Transaction ID = pool index */
2927 /* Announce that we did a recursive lookup */
2928 tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
2930 tmp |= DNS_RCODE_NAME_ERROR;
2931 dh->flags = clib_host_to_net_u16 (tmp);
2932 dh->qdcount = clib_host_to_net_u16 (1);
2933 dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
2937 /* If the name resolution worked, cough up an appropriate RR */
2940 /* Add the answer. First, a name pointer (0xC00C) */
2941 vec_add1 (reply, 0xC0);
2942 vec_add1 (reply, 0x0C);
2944 /* Now, add single A-rec RR */
2945 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2947 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
2948 rr = (dns_rr_t *) rrptr;
2950 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
2951 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2952 rr->ttl = clib_host_to_net_u32 (ttl);
2953 rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
2954 clib_memcpy (rr->rdata, rnr->ip4_address, sizeof (ip4_address_t));
2958 /* Or a single PTR RR */
2959 u8 *vecname = format (0, "%s", rir->name);
2960 u8 *label_vec = name_to_labels (vecname);
2963 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
2964 rr = (dns_rr_t *) rrptr;
2965 rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2966 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2967 rr->ttl = clib_host_to_net_u32 (ttl);
2968 rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
2969 clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
2970 vec_free (label_vec);
2973 clib_memcpy (dns_response, reply, vec_len (reply));
2975 /* Set the packet length */
2976 b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
2979 ip->ip_version_and_header_length = 0x45;
2980 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
2982 ip->protocol = IP_PROTOCOL_UDP;
2983 ip->src_address.as_u32 = src_address->as_u32;
2984 clib_memcpy (ip->dst_address.as_u8, pr->dst_address,
2985 sizeof (ip4_address_t));
2986 ip->checksum = ip4_header_checksum (ip);
2989 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
2990 udp->dst_port = pr->dst_port;
2991 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
2997 * Ship pkts made out of whole cloth to ip4_lookup
2998 * Caller will ship recycled dns reply packets to ip4_lookup
3000 if (is_recycle == 0)
3002 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
3003 to_next = vlib_frame_vector_args (f);
3006 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
3011 * fd.io coding-style-patch-verification: ON
3014 * eval: (c-set-style "gnu")