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... */
826 p = hash_get_mem (dm->cache_entry_by_name, name);
829 ep = pool_elt_at_index (dm->entries, p[0]);
830 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
832 /* Has the entry expired? */
833 if (((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0)
834 && (now > ep->expiration_time))
837 u32 *indices_to_delete = 0;
840 * Take out the rest of the resolution chain
841 * This isn't optimal, but it won't happen very often.
845 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME))
847 vec_add1 (indices_to_delete, ep - dm->entries);
849 p = hash_get_mem (dm->cache_entry_by_name, ep->cname);
852 ep = pool_elt_at_index (dm->entries, p[0]);
856 vec_add1 (indices_to_delete, ep - dm->entries);
860 for (i = 0; i < vec_len (indices_to_delete); i++)
862 /* Reenable to watch re-resolutions */
865 ep = pool_elt_at_index (dm->entries,
866 indices_to_delete[i]);
867 clib_warning ("Re-resolve %s", ep->name);
870 vnet_dns_delete_entry_by_index_nolock
871 (dm, indices_to_delete[i]);
873 vec_free (indices_to_delete);
874 /* Yes, kill it... */
878 if (ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
884 /* Note: caller must drop the lock! */
891 * Resolution pending. Add request to the pending vector
892 * by copying the template request
894 vec_add2 (ep->pending_requests, pr, 1);
895 memcpy (pr, t, sizeof (*pr));
896 dns_cache_unlock (dm);
902 if (pool_elts (dm->entries) == dm->name_cache_size)
904 /* Will only fail if the cache is totally filled w/ static entries... */
905 rv = delete_random_entry (dm);
908 dns_cache_unlock (dm);
913 /* add new hash table entry */
914 pool_get (dm->entries, ep);
915 clib_memset (ep, 0, sizeof (*ep));
917 ep->name = format (0, "%s%c", name, 0);
918 _vec_len (ep->name) = vec_len (ep->name) - 1;
920 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
922 vec_add1 (dm->unresolved_entries, ep - dm->entries);
923 vec_add2 (ep->pending_requests, pr, 1);
925 pr->request_type = t->request_type;
927 /* Remember details so we can reply later... */
928 if (t->request_type == DNS_API_PENDING_NAME_TO_IP ||
929 t->request_type == DNS_API_PENDING_IP_TO_NAME)
931 pr->client_index = t->client_index;
932 pr->client_context = t->client_context;
936 pr->client_index = ~0;
937 pr->is_ip6 = t->is_ip6;
938 pr->dst_port = t->dst_port;
945 clib_memcpy (pr->dst_address, t->dst_address, count);
948 vnet_send_dns_request (dm, ep);
949 dns_cache_unlock (dm);
953 #define foreach_notification_to_move \
957 * Handle cname indirection. JFC. Called with the cache locked.
958 * returns 0 if the reply is not a CNAME.
962 vnet_dns_cname_indirection_nolock (dns_main_t * dm, u32 ep_index, u8 * reply)
977 dns_cache_entry_t *ep, *next_ep;
980 h = (dns_header_t *) reply;
981 flags = clib_net_to_host_u16 (h->flags);
982 rcode = flags & DNS_RCODE_MASK;
984 /* See if the response is OK */
987 case DNS_RCODE_NO_ERROR:
990 case DNS_RCODE_NAME_ERROR:
991 case DNS_RCODE_FORMAT_ERROR:
992 case DNS_RCODE_SERVER_FAILURE:
993 case DNS_RCODE_NOT_IMPLEMENTED:
994 case DNS_RCODE_REFUSED:
998 curpos = (u8 *) (h + 1);
1002 /* Skip the questions */
1003 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
1010 pos += sizeof (dns_query_t);
1013 /* expect a pointer chase here for a CNAME record */
1014 if ((pos2[0] & 0xC0) == 0xC0)
1019 /* Walk the answer(s) to see what to do next */
1020 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
1022 rr = (dns_rr_t *) pos;
1023 switch (clib_net_to_host_u16 (rr->type))
1025 /* Real address record? Done.. */
1030 * Maybe chase a CNAME pointer?
1031 * It's not unheard-of for name-servers to return
1032 * both CNAME and A/AAAA records...
1034 case DNS_TYPE_CNAME:
1038 /* Some other junk, e.g. a nameserver... */
1042 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1044 if ((pos2[0] & 0xc0) == 0xc0)
1048 /* Neither a CNAME nor a real address. Try another server */
1051 flags &= ~DNS_RCODE_MASK;
1052 flags |= DNS_RCODE_NAME_ERROR;
1053 h->flags = clib_host_to_net_u16 (flags);
1057 /* This is a CNAME record, chase the name chain. */
1060 /* The last request is no longer pending.. */
1061 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
1062 if (ep_index == dm->unresolved_entries[i])
1064 vec_delete (dm->unresolved_entries, 1, i);
1065 goto found_last_request;
1067 clib_warning ("pool elt %d supposedly pending, but not found...", ep_index);
1072 now = vlib_time_now (dm->vlib_main);
1073 cname = vnet_dns_labels_to_name (rr->rdata, reply, &pos2);
1074 /* Save the cname */
1075 vec_add1 (cname, 0);
1076 _vec_len (cname) -= 1;
1077 ep = pool_elt_at_index (dm->entries, ep_index);
1079 ep->flags |= (DNS_CACHE_ENTRY_FLAG_CNAME | DNS_CACHE_ENTRY_FLAG_VALID);
1080 /* Save the response */
1081 if (ep->dns_response)
1082 vec_free (ep->dns_response);
1083 ep->dns_response = reply;
1084 /* Set up expiration time */
1085 ep->expiration_time = now + clib_net_to_host_u32 (rr->ttl);
1087 pool_get (dm->entries, next_ep);
1089 /* Need to recompute ep post pool-get */
1090 ep = pool_elt_at_index (dm->entries, ep_index);
1092 clib_memset (next_ep, 0, sizeof (*next_ep));
1093 next_ep->name = vec_dup (cname);
1094 vec_add1 (next_ep->name, 0);
1095 _vec_len (next_ep->name) -= 1;
1097 hash_set_mem (dm->cache_entry_by_name, next_ep->name,
1098 next_ep - dm->entries);
1100 /* Use the same server */
1101 next_ep->server_rotor = ep->server_rotor;
1102 next_ep->server_af = ep->server_af;
1104 /* Move notification data to the next name in the chain */
1105 #define _(a) next_ep->a = ep->a; ep->a = 0;
1106 foreach_notification_to_move;
1109 request = name_to_labels (cname);
1110 name_copy = vec_dup (request);
1112 qp_offset = vec_len (request);
1114 /* Add space for the query header */
1115 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
1117 qp = (dns_query_t *) (request + qp_offset);
1119 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
1120 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1121 clib_memcpy (qp, name_copy, vec_len (name_copy));
1122 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
1123 vec_free (name_copy);
1125 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1126 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1128 /* Punch in space for the dns_header_t */
1129 vec_insert (request, sizeof (dns_header_t), 0);
1131 h = (dns_header_t *) request;
1133 /* Transaction ID = pool index */
1134 h->id = clib_host_to_net_u16 (next_ep - dm->entries);
1136 /* Ask for a recursive lookup */
1137 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
1138 h->qdcount = clib_host_to_net_u16 (2);
1142 next_ep->dns_request = request;
1143 next_ep->retry_timer = now + 2.0;
1144 next_ep->retry_count = 0;
1147 * Enable this to watch recursive resolution happen...
1148 * fformat (stdout, "%U", format_dns_reply, request, 2);
1151 vec_add1 (dm->unresolved_entries, next_ep - dm->entries);
1152 vnet_send_dns_request (dm, next_ep);
1157 vnet_dns_response_to_reply (u8 * response,
1158 vl_api_dns_resolve_name_reply_t * rmp,
1166 u8 *curpos, *pos, *pos2;
1172 h = (dns_header_t *) response;
1173 flags = clib_net_to_host_u16 (h->flags);
1174 rcode = flags & DNS_RCODE_MASK;
1176 /* See if the response is OK, etc. */
1180 case DNS_RCODE_NO_ERROR:
1183 case DNS_RCODE_NAME_ERROR:
1184 case DNS_RCODE_FORMAT_ERROR:
1185 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1187 case DNS_RCODE_SERVER_FAILURE:
1188 case DNS_RCODE_NOT_IMPLEMENTED:
1189 case DNS_RCODE_REFUSED:
1190 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1193 /* No answers? Loser... */
1194 if (clib_net_to_host_u16 (h->anscount) < 1)
1195 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1197 curpos = (u8 *) (h + 1);
1199 /* Skip the name we asked about */
1202 /* Should never happen, but stil... */
1203 if ((len & 0xC0) == 0xC0)
1207 /* skip the name / label-set */
1216 limit = clib_net_to_host_u16 (h->qdcount);
1217 qp = (dns_query_t *) curpos;
1222 limit = clib_net_to_host_u16 (h->anscount);
1224 for (i = 0; i < limit; i++)
1226 pos = pos2 = curpos;
1229 /* Expect pointer chases in the answer section... */
1230 if ((pos2[0] & 0xC0) == 0xC0)
1233 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1242 if ((pos2[0] & 0xc0) == 0xc0)
1245 * If we've already done one pointer chase,
1246 * do not move the pos pointer.
1248 if (pointer_chase == 0)
1250 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1258 if (pointer_chase == 0)
1261 rr = (dns_rr_t *) pos;
1263 switch (clib_net_to_host_u16 (rr->type))
1266 /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1267 memcpy (rmp->ip4_address, rr->rdata, sizeof (ip4_address_t));
1269 ttl = clib_net_to_host_u32 (rr->ttl);
1270 if (min_ttlp && *min_ttlp > ttl)
1274 /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1275 memcpy (rmp->ip6_address, rr->rdata, sizeof (ip6_address_t));
1276 ttl = clib_net_to_host_u32 (rr->ttl);
1277 if (min_ttlp && *min_ttlp > ttl)
1285 /* Might as well stop ASAP */
1286 if (rmp->ip4_set && rmp->ip6_set)
1288 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1292 if ((rmp->ip4_set + rmp->ip6_set) == 0)
1293 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1298 vnet_dns_response_to_name (u8 * response,
1299 vl_api_dns_resolve_ip_reply_t * rmp,
1307 u8 *curpos, *pos, *pos2;
1312 u8 *junk __attribute__ ((unused));
1316 h = (dns_header_t *) response;
1317 flags = clib_net_to_host_u16 (h->flags);
1318 rcode = flags & DNS_RCODE_MASK;
1320 /* See if the response is OK, etc. */
1324 case DNS_RCODE_NO_ERROR:
1327 case DNS_RCODE_NAME_ERROR:
1328 case DNS_RCODE_FORMAT_ERROR:
1329 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1331 case DNS_RCODE_SERVER_FAILURE:
1332 case DNS_RCODE_NOT_IMPLEMENTED:
1333 case DNS_RCODE_REFUSED:
1334 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1337 /* No answers? Loser... */
1338 if (clib_net_to_host_u16 (h->anscount) < 1)
1339 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1341 curpos = (u8 *) (h + 1);
1343 /* Skip the name we asked about */
1346 /* Should never happen, but stil... */
1347 if ((len & 0xC0) == 0xC0)
1351 /* skip the name / label-set */
1360 limit = clib_net_to_host_u16 (h->qdcount);
1361 qp = (dns_query_t *) curpos;
1366 limit = clib_net_to_host_u16 (h->anscount);
1368 for (i = 0; i < limit; i++)
1370 pos = pos2 = curpos;
1373 /* Expect pointer chases in the answer section... */
1374 if ((pos2[0] & 0xC0) == 0xC0)
1377 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1386 if ((pos2[0] & 0xc0) == 0xc0)
1389 * If we've already done one pointer chase,
1390 * do not move the pos pointer.
1392 if (pointer_chase == 0)
1394 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1402 if (pointer_chase == 0)
1405 rr = (dns_rr_t *) pos;
1407 switch (clib_net_to_host_u16 (rr->type))
1410 name = vnet_dns_labels_to_name (rr->rdata, response, &junk);
1411 memcpy (rmp->name, name, vec_len (name));
1412 ttl = clib_net_to_host_u32 (rr->ttl);
1415 rmp->name[vec_len (name)] = 0;
1421 /* Might as well stop ASAP */
1424 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1429 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1434 vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1436 dns_main_t *dm = &dns_main;
1437 vl_api_dns_resolve_name_reply_t *rmp;
1438 dns_cache_entry_t *ep;
1439 dns_pending_request_t _t0, *t0 = &_t0;
1442 /* Sanitize the name slightly */
1443 mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1445 t0->request_type = DNS_API_PENDING_NAME_TO_IP;
1446 t0->client_index = mp->client_index;
1447 t0->client_context = mp->context;
1449 rv = vnet_dns_resolve_name (dm, mp->name, t0, &ep);
1451 /* Error, e.g. not enabled? Tell the user */
1454 REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1458 /* Resolution pending? Don't reply... */
1463 REPLY_MACRO2(VL_API_DNS_RESOLVE_NAME_REPLY,
1465 rv = vnet_dns_response_to_reply (ep->dns_response, rmp, 0 /* ttl-ptr */);
1466 rmp->retval = clib_host_to_net_u32 (rv);
1471 * dns_resolve_name leaves the cache locked when it returns
1472 * a cached result, so unlock it here.
1474 dns_cache_unlock (dm);
1478 vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
1480 dns_main_t *dm = &dns_main;
1481 vl_api_dns_resolve_ip_reply_t *rmp;
1482 dns_cache_entry_t *ep;
1485 u8 *lookup_name = 0;
1487 dns_pending_request_t _t0, *t0 = &_t0;
1491 for (i = 15; i >= 0; i--)
1493 digit = mp->address[i];
1494 nybble = (digit & 0x0F);
1496 vec_add1 (lookup_name, (nybble - 10) + 'a');
1498 vec_add1 (lookup_name, nybble + '0');
1499 vec_add1 (lookup_name, '.');
1500 nybble = (digit & 0xF0) >> 4;
1502 vec_add1 (lookup_name, (nybble - 10) + 'a');
1504 vec_add1 (lookup_name, nybble + '0');
1505 vec_add1 (lookup_name, '.');
1507 len = vec_len (lookup_name);
1508 vec_validate (lookup_name, len + 8);
1509 memcpy (lookup_name + len, "ip6.arpa", 8);
1513 for (i = 3; i >= 0; i--)
1515 digit = mp->address[i];
1516 lookup_name = format (lookup_name, "%d.", digit);
1518 lookup_name = format (lookup_name, "in-addr.arpa");
1521 vec_add1 (lookup_name, 0);
1523 t0->request_type = DNS_API_PENDING_IP_TO_NAME;
1524 t0->client_index = mp->client_index;
1525 t0->client_context = mp->context;
1527 rv = vnet_dns_resolve_name (dm, lookup_name, t0, &ep);
1529 vec_free (lookup_name);
1531 /* Error, e.g. not enabled? Tell the user */
1534 REPLY_MACRO (VL_API_DNS_RESOLVE_IP_REPLY);
1538 /* Resolution pending? Don't reply... */
1543 REPLY_MACRO2(VL_API_DNS_RESOLVE_IP_REPLY,
1545 rv = vnet_dns_response_to_name (ep->dns_response, rmp, 0 /* ttl-ptr */);
1546 rmp->retval = clib_host_to_net_u32 (rv);
1551 * vnet_dns_resolve_name leaves the cache locked when it returns
1552 * a cached result, so unlock it here.
1554 dns_cache_unlock (dm);
1557 #define vl_msg_name_crc_list
1558 #include <vpp/api/vpe_all_api_h.h>
1559 #undef vl_msg_name_crc_list
1562 setup_message_id_table (api_main_t * am)
1564 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1565 foreach_vl_msg_name_crc_dns;
1569 #define foreach_dns_api_msg \
1570 _(DNS_ENABLE_DISABLE, dns_enable_disable) \
1571 _(DNS_NAME_SERVER_ADD_DEL, dns_name_server_add_del) \
1572 _(DNS_RESOLVE_NAME, dns_resolve_name) \
1573 _(DNS_RESOLVE_IP, dns_resolve_ip)
1575 static clib_error_t *
1576 dns_api_hookup (vlib_main_t * vm)
1579 vl_msg_api_set_handlers(VL_API_##N, #n, \
1580 vl_api_##n##_t_handler, \
1582 vl_api_##n##_t_endian, \
1583 vl_api_##n##_t_print, \
1584 sizeof(vl_api_##n##_t), 1);
1585 foreach_dns_api_msg;
1588 setup_message_id_table (&api_main);
1592 VLIB_API_INIT_FUNCTION (dns_api_hookup);
1595 static clib_error_t *
1596 dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1598 dns_main_t *dm = &dns_main;
1600 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1602 if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1604 else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1607 return clib_error_return (0, "unknown input `%U'",
1608 format_unformat_error, input);
1613 VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1615 static clib_error_t *
1616 dns_init (vlib_main_t * vm)
1618 dns_main_t *dm = &dns_main;
1621 dm->vnet_main = vnet_get_main ();
1622 dm->name_cache_size = 65535;
1623 dm->max_ttl_in_seconds = 86400;
1624 dm->random_seed = 0xDEADDABE;
1629 VLIB_INIT_FUNCTION (dns_init);
1632 unformat_dns_reply (unformat_input_t * input, va_list * args)
1634 u8 **result = va_arg (*args, u8 **);
1635 u8 **namep = va_arg (*args, u8 **);
1649 if (unformat (input, "%v", &name))
1652 if (unformat (input, "%U", unformat_ip4_address, &a4))
1655 if (unformat (input, "%U", unformat_ip6_address, &a6))
1659 if (unformat (input, "%U", unformat_ip6_address, &a6))
1662 if (unformat (input, "%U", unformat_ip4_address, &a6))
1666 /* Must have a name */
1670 /* Must have at least one address */
1671 if (!(a4_set + a6_set))
1674 /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1675 ce = name_to_labels (name);
1676 qp_offset = vec_len (ce);
1678 /* Add space for the query header */
1679 vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1680 qp = (dns_query_t *) (ce + qp_offset);
1682 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1683 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1685 /* Punch in space for the dns_header_t */
1686 vec_insert (ce, sizeof (dns_header_t), 0);
1688 h = (dns_header_t *) ce;
1690 /* Fake Transaction ID */
1693 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1694 h->qdcount = clib_host_to_net_u16 (1);
1695 h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1699 /* Now append one or two A/AAAA RR's... */
1702 /* Pointer to the name (DGMS) */
1703 vec_add1 (ce, 0xC0);
1704 vec_add1 (ce, 0x0C);
1705 vec_add2 (ce, rru8, sizeof (*rr) + 4);
1707 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1708 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1709 rr->ttl = clib_host_to_net_u32 (86400);
1710 rr->rdlength = clib_host_to_net_u16 (4);
1711 memcpy (rr->rdata, &a4, sizeof (a4));
1715 /* Pointer to the name (DGMS) */
1716 vec_add1 (ce, 0xC0);
1717 vec_add1 (ce, 0x0C);
1718 vec_add2 (ce, rru8, sizeof (*rr) + 16);
1720 rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1721 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1722 rr->ttl = clib_host_to_net_u32 (86400);
1723 rr->rdlength = clib_host_to_net_u16 (16);
1724 memcpy (rr->rdata, &a6, sizeof (a6));
1736 format_dns_query (u8 * s, va_list * args)
1738 u8 **curpos = va_arg (*args, u8 **);
1739 int verbose = va_arg (*args, int);
1744 s = format (s, " Name: ");
1746 /* Unwind execrated counted-label sheit */
1752 for (i = 0; i < len; i++)
1753 vec_add1 (s, *pos++);
1765 qp = (dns_query_t *) pos;
1768 switch (clib_net_to_host_u16 (qp->type))
1771 s = format (s, "type A\n");
1774 s = format (s, "type AAAA\n");
1777 s = format (s, "type ALL\n");
1781 s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1786 pos += sizeof (*qp);
1793 * format dns reply data
1794 * verbose > 1, dump everything
1795 * verbose == 1, dump all A and AAAA records
1796 * verbose == 0, dump one A record, and one AAAA record
1800 format_dns_reply_data (u8 * s, va_list * args)
1802 u8 *reply = va_arg (*args, u8 *);
1803 u8 **curpos = va_arg (*args, u8 **);
1804 int verbose = va_arg (*args, int);
1805 int *print_ip4 = va_arg (*args, int *);
1806 int *print_ip6 = va_arg (*args, int *);
1811 int pointer_chase = 0;
1813 u16 rrtype_host_byte_order;
1815 pos = pos2 = *curpos;
1818 s = format (s, " ");
1820 /* chase pointer? almost always yes here... */
1821 if ((pos2[0] & 0xc0) == 0xc0)
1824 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1832 for (i = 0; i < len; i++)
1835 vec_add1 (s, *pos2);
1838 if ((pos2[0] & 0xc0) == 0xc0)
1841 * If we've already done one pointer chase,
1842 * do not move the pos pointer.
1844 if (pointer_chase == 0)
1846 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1864 if (pointer_chase == 0)
1867 rr = (dns_rr_t *) pos;
1868 rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
1870 switch (rrtype_host_byte_order)
1875 s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1876 format_ip4_address, rr->rdata);
1881 s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1882 clib_net_to_host_u32 (rr->ttl));
1887 pos += sizeof (*rr) + 4;
1893 s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1894 format_ip6_address, rr->rdata);
1899 s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1900 clib_net_to_host_u32 (rr->ttl));
1904 pos += sizeof (*rr) + 16;
1910 s = format (s, "TEXT: ");
1911 for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1912 vec_add1 (s, rr->rdata[i]);
1915 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1918 case DNS_TYPE_HINFO:
1920 /* Two counted strings. DGMS */
1926 s = format (s, "HINFO: ");
1929 for (i = 0; i < *len; i++)
1930 vec_add1 (s, *curpos++);
1934 for (i = 0; i < *len; i++)
1935 vec_add1 (s, *curpos++);
1940 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1943 case DNS_TYPE_NAMESERVER:
1946 s = format (s, "Nameserver: ");
1949 /* chase pointer? */
1950 if ((pos2[0] & 0xc0) == 0xc0)
1953 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1960 for (i = 0; i < len; i++)
1961 vec_add1 (s, *pos2++);
1963 /* chase pointer, typically to offset 12... */
1964 if (pos2[0] == 0xC0)
1965 pos2 = reply + pos2[1];
1974 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1977 case DNS_TYPE_MAIL_EXCHANGE:
1980 tp = (u16 *) rr->rdata;
1982 s = format (s, "Mail Exchange: Preference %d ", (u32)
1983 clib_net_to_host_u16 (*tp));
1985 pos2 = rr->rdata + 2;
1987 /* chase pointer? */
1988 if (pos2[0] == 0xc0)
1989 pos2 = reply + pos2[1];
1995 for (i = 0; i < len; i++)
1996 vec_add1 (s, *pos2++);
1999 if (pos2[0] == 0xC0)
2000 pos2 = reply + pos2[1];
2010 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2014 case DNS_TYPE_CNAME:
2017 tp = (u16 *) rr->rdata;
2019 if (rrtype_host_byte_order == DNS_TYPE_CNAME)
2020 s = format (s, "CNAME: ");
2022 s = format (s, "PTR: ");
2026 /* chase pointer? */
2027 if (pos2[0] == 0xc0)
2028 pos2 = reply + pos2[1];
2034 for (i = 0; i < len; i++)
2035 vec_add1 (s, *pos2++);
2038 if (pos2[0] == 0xC0)
2039 pos2 = reply + pos2[1];
2048 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2053 s = format (s, "type %d: len %d\n",
2054 (int) clib_net_to_host_u16 (rr->type),
2055 sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
2056 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2066 format_dns_reply (u8 * s, va_list * args)
2068 u8 *reply_as_u8 = va_arg (*args, u8 *);
2069 int verbose = va_arg (*args, int);
2077 h = (dns_header_t *) reply_as_u8;
2078 id = clib_net_to_host_u16 (h->id);
2079 flags = clib_net_to_host_u16 (h->flags);
2083 s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
2085 s = format (s, " %s %s %s %s\n",
2086 (flags & DNS_RA) ? "recur" : "no-recur",
2087 (flags & DNS_RD) ? "recur-des" : "no-recur-des",
2088 (flags & DNS_TC) ? "trunc" : "no-trunc",
2089 (flags & DNS_AA) ? "auth" : "non-auth");
2090 s = format (s, " %d queries, %d answers, %d name-servers,"
2092 clib_net_to_host_u16 (h->qdcount),
2093 clib_net_to_host_u16 (h->anscount),
2094 clib_net_to_host_u16 (h->nscount),
2095 clib_net_to_host_u16 (h->arcount));
2098 curpos = (u8 *) (h + 1);
2103 s = format (s, " Queries:\n");
2104 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
2106 /* The query is variable-length, so curpos is a value-result parm */
2107 s = format (s, "%U", format_dns_query, &curpos, verbose);
2113 s = format (s, " Replies:\n");
2115 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
2117 /* curpos is a value-result parm */
2118 s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
2119 verbose, &print_ip4, &print_ip6);
2126 format_dns_cache (u8 * s, va_list * args)
2128 dns_main_t *dm = va_arg (*args, dns_main_t *);
2129 f64 now = va_arg (*args, f64);
2130 int verbose = va_arg (*args, int);
2131 u8 *name = va_arg (*args, u8 *);
2132 dns_cache_entry_t *ep;
2136 if (dm->is_enabled == 0)
2138 s = format (s, "The DNS cache is disabled...");
2142 if (pool_elts (dm->entries) == 0)
2144 s = format (s, "The DNS cache is empty...");
2148 dns_cache_lock (dm);
2152 p = hash_get_mem (dm->cache_entry_by_name, name);
2155 s = format (s, "%s is not in the cache...", name);
2156 dns_cache_unlock (dm);
2160 ep = pool_elt_at_index (dm->entries, p[0]);
2161 /* Magic to spit out a C-initializer to research hemorrhoids... */
2165 s = format (s, "static u8 dns_reply_data_initializer[] =\n");
2166 s = format (s, "{\n");
2168 for (i = 0; i < vec_len (ep->dns_response); i++)
2175 s = format (s, "0x%02x, ", ep->dns_response[i]);
2177 s = format (s, "};\n");
2181 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2183 ASSERT (ep->dns_response);
2184 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2189 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2190 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2192 s = format (s, "%s%s -> %U", ss, ep->name,
2193 format_dns_reply, ep->dns_response, verbose);
2194 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2196 f64 time_left = ep->expiration_time - now;
2197 if (time_left > 0.0)
2198 s = format (s, " TTL left %.1f", time_left);
2200 s = format (s, " EXPIRED");
2205 ASSERT (ep->dns_request);
2206 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2214 s = format (s, "DNS cache contains %d entries\n", pool_elts (dm->entries));
2219 pool_foreach (ep, dm->entries,
2221 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2223 ASSERT (ep->dns_response);
2224 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2229 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2230 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2232 s = format (s, "%s%s -> %U", ss, ep->name,
2236 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2238 f64 time_left = ep->expiration_time - now;
2239 if (time_left > 0.0)
2240 s = format (s, " TTL left %.1f", time_left);
2242 s = format (s, " EXPIRED");
2245 s = format (s, " %d client notifications pending\n",
2246 vec_len(ep->pending_requests));
2251 ASSERT (ep->dns_request);
2252 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2260 dns_cache_unlock (dm);
2265 static clib_error_t *
2266 show_dns_cache_command_fn (vlib_main_t * vm,
2267 unformat_input_t * input, vlib_cli_command_t * cmd)
2269 dns_main_t *dm = &dns_main;
2272 f64 now = vlib_time_now (vm);
2274 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2276 if (unformat (input, "verbose %d", &verbose))
2278 else if (unformat (input, "verbose"))
2280 else if (unformat (input, "name %s", &name))
2283 return clib_error_return (0, "unknown input `%U'",
2284 format_unformat_error, input);
2287 vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
2293 VLIB_CLI_COMMAND (show_dns_cache_command) =
2295 .path = "show dns cache",
2296 .short_help = "show dns cache [verbose [nn]]",
2297 .function = show_dns_cache_command_fn,
2301 static clib_error_t *
2302 dns_cache_add_del_command_fn (vlib_main_t * vm,
2303 unformat_input_t * input,
2304 vlib_cli_command_t * cmd)
2306 dns_main_t *dm = &dns_main;
2312 clib_error_t *error;
2314 if (unformat (input, "add"))
2316 if (unformat (input, "del"))
2318 if (unformat (input, "clear"))
2321 if (is_add == -1 && is_clear == -1)
2322 return clib_error_return (0, "add / del / clear required...");
2326 rv = dns_cache_clear (dm);
2332 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2333 error = clib_error_return (0, "Name resolution not enabled");
2338 /* Delete (by name)? */
2341 if (unformat (input, "%v", &name))
2343 rv = dns_delete_by_name (dm, name);
2346 case VNET_API_ERROR_NO_SUCH_ENTRY:
2347 error = clib_error_return (0, "%v not in the cache...", name);
2351 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2352 error = clib_error_return (0, "Name resolution not enabled");
2361 error = clib_error_return (0, "dns_delete_by_name returned %d",
2367 return clib_error_return (0, "unknown input `%U'",
2368 format_unformat_error, input);
2371 /* Note: dns_add_static_entry consumes the name vector if OK... */
2372 if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2374 rv = dns_add_static_entry (dm, name, dns_reply_data);
2377 case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2379 vec_free (dns_reply_data);
2380 return clib_error_return (0, "%v already in the cache...", name);
2385 return clib_error_return (0, "dns_add_static_entry returned %d",
2394 VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2396 .path = "dns cache",
2397 .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2398 .function = dns_cache_add_del_command_fn,
2402 #define DNS_FORMAT_TEST 1
2404 #if DNS_FORMAT_TEST > 0
2407 static u8 dns_reply_data_initializer[] =
2408 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2409 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2411 0x0, 0xff, /* type ALL */
2412 0x0, 0x1, /* class IN */
2413 0xc0, 0xc, /* pointer to yahoo.com name */
2414 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2415 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2416 0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2417 0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2418 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2419 0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2420 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2421 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2422 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2423 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2424 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2425 0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2426 0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2428 0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2429 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2430 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2431 0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2432 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2434 0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2435 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2436 0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2437 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2439 0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2440 0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2442 0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2444 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2446 0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2448 0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2449 0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2450 0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2454 /* www.cisco.com, has no addresses in reply */
2455 static u8 dns_reply_data_initializer[] = {
2456 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2457 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2458 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2460 0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2461 0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2462 0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2463 0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2464 0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2467 /* bind8 (linux widget, w/ nasty double pointer chasees */
2468 static u8 dns_reply_data_initializer[] = {
2470 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08,
2472 0x00, 0x06, 0x00, 0x06, 0x0a, 0x6f, 0x72, 0x69,
2474 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77, 0x77, 0x05,
2476 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f,
2478 0x6d, 0x00, 0x00, 0xff, 0x00, 0x01, 0x0a, 0x6f,
2480 0x72, 0x69, 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77,
2482 0x77, 0x05, 0x43, 0x49, 0x53, 0x43, 0x4f, 0xc0,
2485 0x1d, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2488 0x9a, 0x00, 0x18, 0x15, 0x72, 0x63, 0x64,
2489 0x6e, 0x39, 0x2d, 0x31, 0x34, 0x70, 0x2d, 0x64, 0x63,
2490 0x7a, 0x30, 0x35, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31,
2491 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00, 0x01, 0x00,
2492 0x00, 0x05, 0x9a, 0x00, 0x1a, 0x17, 0x61, 0x6c, 0x6c,
2493 0x6e, 0x30, 0x31, 0x2d, 0x61, 0x67, 0x30, 0x39, 0x2d,
2494 0x64, 0x63, 0x7a, 0x30, 0x33, 0x6e, 0x2d, 0x67, 0x73,
2495 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00,
2496 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x10, 0x0d, 0x72,
2497 0x74, 0x70, 0x35, 0x2d, 0x64, 0x6d, 0x7a, 0x2d, 0x67,
2498 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2499 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x18, 0x15,
2500 0x6d, 0x74, 0x76, 0x35, 0x2d, 0x61, 0x70, 0x31, 0x30,
2501 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x36, 0x6e, 0x2d, 0x67,
2502 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2503 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x1b, 0x18,
2504 0x73, 0x6e, 0x67, 0x64, 0x63, 0x30, 0x31, 0x2d, 0x61,
2505 0x62, 0x30, 0x37, 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x31,
2506 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0,
2507 0x26, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a,
2508 0x00, 0x1a, 0x17, 0x61, 0x65, 0x72, 0x30, 0x31, 0x2d,
2509 0x72, 0x34, 0x63, 0x32, 0x35, 0x2d, 0x64, 0x63, 0x7a,
2510 0x30, 0x31, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0,
2511 0x17, 0xc0, 0x26, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2512 0x00, 0x81, 0x00, 0x04, 0x48, 0xa3, 0x04, 0xa1, 0xc0,
2513 0x26, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82,
2514 0x00, 0x10, 0x20, 0x01, 0x04, 0x20, 0x12, 0x01, 0x00,
2515 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
2516 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2517 0x9a, 0x00, 0x02, 0xc0, 0xf4, 0xc0, 0x0c, 0x00, 0x02,
2518 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0,
2519 0xcd, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00,
2520 0x05, 0x9a, 0x00, 0x02, 0xc0, 0x8d, 0xc0, 0x0c, 0x00,
2521 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02,
2522 0xc0, 0x43, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00,
2523 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0, 0xa9, 0xc0, 0x0c,
2524 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00,
2525 0x02, 0xc0, 0x67, 0xc0, 0x8d, 0x00, 0x01, 0x00, 0x01,
2526 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0x40, 0x66, 0xf6,
2527 0x05, 0xc0, 0xa9, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2528 0x07, 0x08, 0x00, 0x04, 0xad, 0x24, 0xe0, 0x64, 0xc0,
2529 0x43, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08,
2530 0x00, 0x04, 0x48, 0xa3, 0x04, 0x1c, 0xc0, 0xf4, 0x00,
2531 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04,
2532 0xad, 0x26, 0xd4, 0x6c, 0xc0, 0x67, 0x00, 0x01, 0x00,
2533 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x25,
2534 0x90, 0x64, 0xc0, 0xcd, 0x00, 0x01, 0x00, 0x01, 0x00,
2535 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x27, 0x70, 0x44,
2539 static u8 dns_reply_data_initializer[] =
2540 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
2541 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
2542 0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
2543 0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
2545 0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
2546 0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
2547 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
2548 0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
2549 0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
2550 0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
2551 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
2552 0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
2553 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
2554 0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
2555 0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
2556 0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
2557 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
2558 0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
2559 0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
2560 0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
2561 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2562 0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
2563 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
2564 0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
2565 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
2566 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
2567 0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
2569 0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2573 /* www.weatherlink.com */
2574 static u8 dns_reply_data_initializer[] = {
2575 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2576 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x0b,
2577 0x77, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x6c, 0x69,
2578 0x6e, 0x6b, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0xff,
2579 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00,
2580 0x00, 0x0c, 0x9e, 0x00, 0x1f, 0x0e, 0x64, 0x33, 0x6b,
2581 0x72, 0x30, 0x67, 0x75, 0x62, 0x61, 0x31, 0x64, 0x76,
2582 0x77, 0x66, 0x0a, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x66,
2583 0x72, 0x6f, 0x6e, 0x74, 0x03, 0x6e, 0x65, 0x74, 0x00,
2588 static clib_error_t *
2589 test_dns_fmt_command_fn (vlib_main_t * vm,
2590 unformat_input_t * input, vlib_cli_command_t * cmd)
2592 u8 *dns_reply_data = 0;
2595 vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2597 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2599 if (unformat (input, "verbose %d", &verbose))
2601 else if (unformat (input, "verbose"))
2604 return clib_error_return (0, "unknown input `%U'",
2605 format_unformat_error, input);
2608 vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2610 memcpy (dns_reply_data, dns_reply_data_initializer,
2611 ARRAY_LEN (dns_reply_data_initializer));
2613 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2615 clib_memset (rmp, 0, sizeof (*rmp));
2617 rv = vnet_dns_response_to_reply (dns_reply_data, rmp, 0 /* ttl-ptr */ );
2621 case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2622 vlib_cli_output (vm, "no addresses found...");
2626 vlib_cli_output (vm, "response to reply returned %d", rv);
2631 vlib_cli_output (vm, "ip4 address: %U", format_ip4_address,
2632 (ip4_address_t *) rmp->ip4_address);
2634 vlib_cli_output (vm, "ip6 address: %U", format_ip6_address,
2635 (ip6_address_t *) rmp->ip6_address);
2639 vec_free (dns_reply_data);
2646 VLIB_CLI_COMMAND (test_dns_fmt_command) =
2648 .path = "test dns format",
2649 .short_help = "test dns format",
2650 .function = test_dns_fmt_command_fn,
2654 static clib_error_t *
2655 test_dns_unfmt_command_fn (vlib_main_t * vm,
2656 unformat_input_t * input, vlib_cli_command_t * cmd)
2658 u8 *dns_reply_data = 0;
2662 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2664 if (unformat (input, "verbose %d", &verbose))
2666 else if (unformat (input, "verbose"))
2668 else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2671 return clib_error_return (0, "unknown input `%U'",
2672 format_unformat_error, input);
2676 return clib_error_return (0, "dns data not set...");
2678 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2680 vec_free (dns_reply_data);
2686 VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2688 .path = "test dns unformat",
2689 .short_help = "test dns unformat <name> [ip4][ip6]",
2690 .function = test_dns_unfmt_command_fn,
2694 static clib_error_t *
2695 test_dns_expire_command_fn (vlib_main_t * vm,
2696 unformat_input_t * input,
2697 vlib_cli_command_t * cmd)
2699 dns_main_t *dm = &dns_main;
2703 dns_cache_entry_t *ep;
2705 if (unformat (input, "%v", &name))
2708 _vec_len (name) -= 1;
2711 return clib_error_return (0, "no name provided");
2713 dns_cache_lock (dm);
2715 p = hash_get_mem (dm->cache_entry_by_name, name);
2718 dns_cache_unlock (dm);
2719 e = clib_error_return (0, "%s is not in the cache...", name);
2724 ep = pool_elt_at_index (dm->entries, p[0]);
2726 ep->expiration_time = 0;
2732 VLIB_CLI_COMMAND (test_dns_expire_command) =
2734 .path = "test dns expire",
2735 .short_help = "test dns expire <name>",
2736 .function = test_dns_expire_command_fn,
2742 vnet_send_dns6_reply (dns_main_t * dm, dns_pending_request_t * pr,
2743 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2745 clib_warning ("Unimplemented...");
2750 vnet_send_dns4_reply (dns_main_t * dm, dns_pending_request_t * pr,
2751 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2753 vlib_main_t *vm = dm->vlib_main;
2755 fib_prefix_t prefix;
2756 fib_node_index_t fei;
2757 u32 sw_if_index, fib_index;
2758 ip4_main_t *im4 = &ip4_main;
2759 ip_lookup_main_t *lm4 = &im4->lookup_main;
2760 ip_interface_address_t *ia = 0;
2761 ip4_address_t *src_address;
2769 vl_api_dns_resolve_name_reply_t _rnr, *rnr = &_rnr;
2770 vl_api_dns_resolve_ip_reply_t _rir, *rir = &_rir;
2777 int is_recycle = (b0 != 0);
2779 ASSERT (ep && ep->dns_response);
2781 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2783 /* Quick and dirty way to dig up the A-record address. $$ FIXME */
2784 clib_memset (rnr, 0, sizeof (*rnr));
2785 if (vnet_dns_response_to_reply (ep->dns_response, rnr, &ttl))
2787 /* clib_warning ("response_to_reply failed..."); */
2790 if (rnr->ip4_set == 0)
2792 /* clib_warning ("No A-record..."); */
2796 else if (pr->request_type == DNS_PEER_PENDING_IP_TO_NAME)
2798 clib_memset (rir, 0, sizeof (*rir));
2799 if (vnet_dns_response_to_name (ep->dns_response, rir, &ttl))
2801 /* clib_warning ("response_to_name failed..."); */
2807 clib_warning ("Unknown request type %d", pr->request_type);
2811 /* Initialize a buffer */
2814 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2816 b0 = vlib_get_buffer (vm, bi);
2820 /* Use the buffer we were handed. Reinitialize it... */
2821 vlib_buffer_t bt = { };
2822 /* push/pop the reference count */
2823 u8 save_ref_count = b0->ref_count;
2824 vlib_buffer_copy_template (b0, &bt);
2825 b0->ref_count = save_ref_count;
2826 bi = vlib_get_buffer_index (vm, b0);
2829 if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
2830 vlib_buffer_free_one (vm, b0->next_buffer);
2833 * Reset the buffer. We recycle the DNS request packet in the cache
2834 * hit case, and reply immediately from the request node.
2836 * In the resolution-required / deferred case, resetting a freshly-allocated
2837 * buffer won't hurt. We hope.
2839 b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
2840 | VLIB_BUFFER_TOTAL_LENGTH_VALID);
2841 vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; /* "local0" */
2842 vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
2844 /* Find a FIB path to the peer we're trying to answer */
2845 clib_memcpy (&prefix.fp_addr.ip4, pr->dst_address, sizeof (ip4_address_t));
2846 prefix.fp_proto = FIB_PROTOCOL_IP4;
2849 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
2850 if (fib_index == (u32) ~ 0)
2852 clib_warning ("no fib table");
2856 fei = fib_table_lookup (fib_index, &prefix);
2858 /* Couldn't find route to destination. Bail out. */
2859 if (fei == FIB_NODE_INDEX_INVALID)
2861 clib_warning ("no route to DNS server");
2865 sw_if_index = fib_entry_get_resolving_interface (fei);
2867 if (sw_if_index == ~0)
2870 ("route to %U exists, fei %d, get_resolving_interface returned"
2871 " ~0", fei, format_ip4_address, &prefix.fp_addr);
2876 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnumbered */,
2878 src_address = ip_interface_address_get_address (lm4, ia);
2879 goto found_src_address;
2883 clib_warning ("FIB BUG");
2888 ip = vlib_buffer_get_current (b0);
2889 udp = (udp_header_t *) (ip + 1);
2890 dns_response = (u8 *) (udp + 1);
2891 clib_memset (ip, 0, sizeof (*ip) + sizeof (*udp));
2894 * Start with the variadic portion of the exercise.
2895 * Turn the name into a set of DNS "labels". Max length
2896 * per label is 63, enforce that.
2898 reply = name_to_labels (pr->name);
2899 vec_free (pr->name);
2901 qp_offset = vec_len (reply);
2903 /* Add space for the query header */
2904 vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
2906 qp = (dns_query_t *) (reply + qp_offset);
2908 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2909 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
2911 qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2913 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
2915 /* Punch in space for the dns_header_t */
2916 vec_insert (reply, sizeof (dns_header_t), 0);
2918 dh = (dns_header_t *) reply;
2920 /* Transaction ID = pool index */
2923 /* Announce that we did a recursive lookup */
2924 tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
2926 tmp |= DNS_RCODE_NAME_ERROR;
2927 dh->flags = clib_host_to_net_u16 (tmp);
2928 dh->qdcount = clib_host_to_net_u16 (1);
2929 dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
2933 /* If the name resolution worked, cough up an appropriate RR */
2936 /* Add the answer. First, a name pointer (0xC00C) */
2937 vec_add1 (reply, 0xC0);
2938 vec_add1 (reply, 0x0C);
2940 /* Now, add single A-rec RR */
2941 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2943 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
2944 rr = (dns_rr_t *) rrptr;
2946 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
2947 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2948 rr->ttl = clib_host_to_net_u32 (ttl);
2949 rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
2950 clib_memcpy (rr->rdata, rnr->ip4_address, sizeof (ip4_address_t));
2954 /* Or a single PTR RR */
2955 u8 *vecname = format (0, "%s", rir->name);
2956 u8 *label_vec = name_to_labels (vecname);
2959 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
2960 rr = (dns_rr_t *) rrptr;
2961 rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2962 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2963 rr->ttl = clib_host_to_net_u32 (ttl);
2964 rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
2965 clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
2966 vec_free (label_vec);
2969 clib_memcpy (dns_response, reply, vec_len (reply));
2971 /* Set the packet length */
2972 b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
2975 ip->ip_version_and_header_length = 0x45;
2976 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
2978 ip->protocol = IP_PROTOCOL_UDP;
2979 ip->src_address.as_u32 = src_address->as_u32;
2980 clib_memcpy (ip->dst_address.as_u8, pr->dst_address,
2981 sizeof (ip4_address_t));
2982 ip->checksum = ip4_header_checksum (ip);
2985 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
2986 udp->dst_port = pr->dst_port;
2987 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
2993 * Ship pkts made out of whole cloth to ip4_lookup
2994 * Caller will ship recycled dns reply packets to ip4_lookup
2996 if (is_recycle == 0)
2998 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
2999 to_next = vlib_frame_vector_args (f);
3002 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
3007 * fd.io coding-style-patch-verification: ON
3010 * eval: (c-set-style "gnu")