2 * Copyright (c) 2017 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 #include <vnet/vnet.h>
17 #include <vnet/udp/udp_local.h>
18 #include <vnet/plugin/plugin.h>
20 #include <vnet/ip/ip_sas.h>
21 #include <vlibapi/api.h>
22 #include <vlibmemory/api.h>
23 #include <vpp/app/version.h>
26 /* define message IDs */
27 #include <dns/dns.api_enum.h>
28 #include <dns/dns.api_types.h>
30 #define REPLY_MSG_ID_BASE dm->msg_id_base
31 #include <vlibapi/api_helper_macros.h>
33 /* Macro to finish up custom dump fns */
34 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
37 vl_print (handle, (char *)s); \
44 dns_cache_clear (dns_main_t * dm)
46 dns_cache_entry_t *ep;
48 if (dm->is_enabled == 0)
49 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
51 dns_cache_lock (dm, 1);
54 pool_foreach (ep, dm->entries)
57 vec_free (ep->pending_requests);
61 pool_free (dm->entries);
62 hash_free (dm->cache_entry_by_name);
63 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
64 vec_free (dm->unresolved_entries);
65 dns_cache_unlock (dm);
70 dns_enable_disable (vlib_main_t * vm, dns_main_t * dm, int is_enable)
72 vlib_thread_main_t *tm = &vlib_thread_main;
73 u32 n_vlib_mains = tm->n_vlib_mains;
75 /* Create the resolver process if not done already */
76 vnet_dns_create_resolver_process (vm, dm);
80 if (vec_len (dm->ip4_name_servers) == 0
81 && (vec_len (dm->ip6_name_servers) == 0))
82 return VNET_API_ERROR_NO_NAME_SERVERS;
84 if (dm->udp_ports_registered == 0)
86 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply,
87 dns46_reply_node.index, 1 /* is_ip4 */ );
89 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply6,
90 dns46_reply_node.index, 0 /* is_ip4 */ );
92 udp_register_dst_port (vm, UDP_DST_PORT_dns,
93 dns4_request_node.index, 1 /* is_ip4 */ );
95 udp_register_dst_port (vm, UDP_DST_PORT_dns6,
96 dns6_request_node.index, 0 /* is_ip4 */ );
98 dm->udp_ports_registered = 1;
101 if (dm->cache_entry_by_name == 0)
103 if (n_vlib_mains > 1)
104 clib_spinlock_init (&dm->cache_lock);
106 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
113 dns_cache_clear (dm);
119 static void vl_api_dns_enable_disable_t_handler
120 (vl_api_dns_enable_disable_t * mp)
122 vl_api_dns_enable_disable_reply_t *rmp;
123 vlib_main_t *vm = vlib_get_main ();
124 dns_main_t *dm = &dns_main;
127 rv = dns_enable_disable (vm, dm, mp->enable);
129 REPLY_MACRO (VL_API_DNS_ENABLE_DISABLE_REPLY);
133 dns6_name_server_add_del (dns_main_t * dm,
134 u8 * server_address_as_u8, int is_add)
141 /* Already there? done... */
142 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
144 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
145 sizeof (ip6_address_t)))
149 vec_add2 (dm->ip6_name_servers, ap, 1);
150 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
154 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
156 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
157 sizeof (ip6_address_t)))
159 vec_delete (dm->ip6_name_servers, 1, i);
163 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
169 dns4_name_server_add_del (dns_main_t * dm,
170 u8 * server_address_as_u8, int is_add)
177 /* Already there? done... */
178 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
180 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
181 sizeof (ip4_address_t)))
185 vec_add2 (dm->ip4_name_servers, ap, 1);
186 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
190 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
192 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
193 sizeof (ip4_address_t)))
195 vec_delete (dm->ip4_name_servers, 1, i);
199 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
204 static void vl_api_dns_name_server_add_del_t_handler
205 (vl_api_dns_name_server_add_del_t * mp)
207 dns_main_t *dm = &dns_main;
208 vl_api_dns_name_server_add_del_reply_t *rmp;
212 rv = dns6_name_server_add_del (dm, mp->server_address, mp->is_add);
214 rv = dns4_name_server_add_del (dm, mp->server_address, mp->is_add);
216 REPLY_MACRO (VL_API_DNS_NAME_SERVER_ADD_DEL_REPLY);
220 vnet_dns_send_dns4_request (vlib_main_t * vm, dns_main_t * dm,
221 dns_cache_entry_t * ep, ip4_address_t * server)
223 f64 now = vlib_time_now (vm);
228 ip4_address_t src_address;
233 ASSERT (ep->dns_request);
235 if (!ip4_sas (0 /* default VRF for now */, ~0, server, &src_address))
238 /* Go get a buffer */
239 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
242 b = vlib_get_buffer (vm, bi);
243 b->current_length = sizeof (ip4_header_t) + sizeof (udp_header_t) +
244 vec_len (ep->dns_request);
245 b->total_length_not_including_first_buffer = 0;
247 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
248 vnet_buffer (b)->sw_if_index[VLIB_RX] = 0; /* "local0" */
249 vnet_buffer (b)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
251 ip = vlib_buffer_get_current (b);
252 clib_memset (ip, 0, sizeof (*ip));
253 udp = (udp_header_t *) (ip + 1);
254 clib_memset (udp, 0, sizeof (*udp));
256 dns_request = (u8 *) (udp + 1);
259 ip->ip_version_and_header_length = 0x45;
260 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b));
262 ip->protocol = IP_PROTOCOL_UDP;
263 ip->src_address.as_u32 = src_address.as_u32;
264 ip->dst_address.as_u32 = server->as_u32;
265 ip->checksum = ip4_header_checksum (ip);
268 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
269 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
270 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
271 vec_len (ep->dns_request));
274 /* The actual DNS request */
275 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
277 /* Ship it to ip4_lookup */
278 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
279 to_next = vlib_frame_vector_args (f);
282 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
284 ep->retry_timer = now + 2.0;
288 vnet_dns_send_dns6_request (vlib_main_t * vm, dns_main_t * dm,
289 dns_cache_entry_t * ep, ip6_address_t * server)
291 f64 now = vlib_time_now (vm);
296 ip6_address_t src_address;
300 int junk __attribute__ ((unused));
302 ASSERT (ep->dns_request);
304 if (!ip6_sas (0 /* default VRF for now */, ~0, server, &src_address))
307 /* Go get a buffer */
308 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
311 b = vlib_get_buffer (vm, bi);
312 b->current_length = sizeof (ip6_header_t) + sizeof (udp_header_t) +
313 vec_len (ep->dns_request);
314 b->total_length_not_including_first_buffer = 0;
316 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
318 ip = vlib_buffer_get_current (b);
319 clib_memset (ip, 0, sizeof (*ip));
320 udp = (udp_header_t *) (ip + 1);
321 clib_memset (udp, 0, sizeof (*udp));
323 dns_request = (u8 *) (udp + 1);
326 ip->ip_version_traffic_class_and_flow_label =
327 clib_host_to_net_u32 (0x6 << 28);
330 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b)
331 - sizeof (ip6_header_t));
333 ip->protocol = IP_PROTOCOL_UDP;
334 ip6_address_copy (&ip->src_address, &src_address);
335 clib_memcpy (&ip->dst_address, server, sizeof (ip6_address_t));
338 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
339 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
340 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
341 vec_len (ep->dns_request));
343 udp->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ip, &junk);
345 /* The actual DNS request */
346 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
348 /* Ship it to ip6_lookup */
349 f = vlib_get_frame_to_node (vm, ip6_lookup_node.index);
350 to_next = vlib_frame_vector_args (f);
354 ep->retry_timer = now + 2.0;
358 * Translate "foo.com" into "0x3 f o o 0x3 c o m 0x0"
359 * A historical / hysterical micro-TLV scheme. DGMS.
362 name_to_labels (u8 * name)
365 int last_label_index;
370 /* punch in space for the first length */
371 vec_insert (rv, 1, 0);
372 last_label_index = 0;
375 while (i < vec_len (rv))
379 rv[last_label_index] = (i - last_label_index) - 1;
380 if ((i - last_label_index) > 63)
381 clib_warning ("stupid name, label length %d",
382 i - last_label_index);
383 last_label_index = i;
388 /* Set the last real label length */
389 rv[last_label_index] = (i - last_label_index) - 1;
392 * Add a [sic] NULL root label. Otherwise, the name parser can't figure out
400 * arc-function for the above.
401 * Translate "0x3 f o o 0x3 c o m 0x0" into "foo.com"
402 * Produces a non-NULL-terminated u8 *vector. %v format is your friend.
405 vnet_dns_labels_to_name (u8 * label, u8 * full_text, u8 ** parse_from_here)
412 *parse_from_here = 0;
414 /* chase initial pointer? */
415 if ((label[0] & 0xC0) == 0xC0)
417 *parse_from_here = label + 2;
418 offset = ((label[0] & 0x3f) << 8) + label[1];
419 label = full_text + offset;
426 for (i = 0; i < len; i++)
427 vec_add1 (reply, *label++);
430 if ((label[0] & 0xC0) == 0xC0)
432 *parse_from_here = label + 2;
433 offset = ((label[0] & 0x3f) << 8) + label[1];
434 label = full_text + offset;
439 vec_add1 (reply, '.');
441 if (*parse_from_here == 0)
442 *parse_from_here = label;
447 vnet_send_dns_request (vlib_main_t * vm, dns_main_t * dm,
448 dns_cache_entry_t * ep)
453 u8 *request, *name_copy;
456 /* This can easily happen if sitting in GDB, etc. */
457 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID || ep->server_fails > 1)
460 /* Construct the dns request, if we haven't been here already */
461 if (vec_len (ep->dns_request) == 0)
464 * Start with the variadic portion of the exercise.
465 * Turn the name into a set of DNS "labels". Max length
466 * per label is 63, enforce that.
468 request = name_to_labels (ep->name);
469 name_copy = vec_dup (request);
470 qp_offset = vec_len (request);
473 * At least when testing against "known good" DNS servers:
474 * it turns out that sending 2x requests - one for an A-record
475 * and another for a AAAA-record - seems to work better than
476 * sending a DNS_TYPE_ALL request.
479 /* Add space for the query header */
480 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
482 qp = (dns_query_t *) (request + qp_offset);
484 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
485 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
487 clib_memcpy (qp, name_copy, vec_len (name_copy));
488 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
489 vec_free (name_copy);
491 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
492 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
494 /* Punch in space for the dns_header_t */
495 vec_insert (request, sizeof (dns_header_t), 0);
497 h = (dns_header_t *) request;
499 /* Transaction ID = pool index */
500 h->id = clib_host_to_net_u16 (ep - dm->entries);
502 /* Ask for a recursive lookup */
503 tmp = DNS_RD | DNS_OPCODE_QUERY;
504 h->flags = clib_host_to_net_u16 (tmp);
505 h->qdcount = clib_host_to_net_u16 (2);
509 ep->dns_request = request;
512 /* Work out which server / address family we're going to use */
514 /* Retry using current server */
515 if (ep->retry_count++ < DNS_RETRIES_PER_SERVER)
517 if (ep->server_af == 1 /* ip6 */ )
519 if (vec_len (dm->ip6_name_servers))
521 vnet_dns_send_dns6_request
522 (vm, dm, ep, dm->ip6_name_servers + ep->server_rotor);
528 if (vec_len (dm->ip4_name_servers))
530 vnet_dns_send_dns4_request
531 (vm, dm, ep, dm->ip4_name_servers + ep->server_rotor);
535 else /* switch to a new server */
539 if (ep->server_af == 1 /* ip6 */ )
541 if (ep->server_rotor >= vec_len (dm->ip6_name_servers))
543 ep->server_rotor = 0;
544 ep->server_af = vec_len (dm->ip4_name_servers) > 0 ? 0 : 1;
549 if (ep->server_rotor >= vec_len (dm->ip4_name_servers))
551 ep->server_rotor = 0;
552 ep->server_af = vec_len (dm->ip6_name_servers) > 0 ? 1 : 0;
557 if (ep->server_af == 1 /* ip6 */ )
558 vnet_dns_send_dns6_request
559 (vm, dm, ep, dm->ip6_name_servers + ep->server_rotor);
561 vnet_dns_send_dns4_request
562 (vm, dm, ep, dm->ip4_name_servers + ep->server_rotor);
566 vlib_process_signal_event_mt (vm,
567 dm->resolver_process_node_index,
568 DNS_RESOLVER_EVENT_PENDING, 0);
572 vnet_dns_delete_entry_by_index_nolock (dns_main_t * dm, u32 index)
574 dns_cache_entry_t *ep;
577 if (dm->is_enabled == 0)
578 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
580 if (pool_is_free_index (dm->entries, index))
581 return VNET_API_ERROR_NO_SUCH_ENTRY;
583 ep = pool_elt_at_index (dm->entries, index);
584 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_VALID))
586 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
587 if (index == dm->unresolved_entries[i])
589 vec_delete (dm->unresolved_entries, 1, i);
592 clib_warning ("pool elt %d supposedly pending, but not found...",
597 hash_unset_mem (dm->cache_entry_by_name, ep->name);
599 vec_free (ep->pending_requests);
600 pool_put (dm->entries, ep);
606 dns_delete_by_name (dns_main_t * dm, u8 * name)
611 if (dm->is_enabled == 0)
612 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
614 dns_cache_lock (dm, 2);
615 p = hash_get_mem (dm->cache_entry_by_name, name);
618 dns_cache_unlock (dm);
619 return VNET_API_ERROR_NO_SUCH_ENTRY;
621 rv = vnet_dns_delete_entry_by_index_nolock (dm, p[0]);
623 dns_cache_unlock (dm);
629 delete_random_entry (dns_main_t * dm)
632 u32 victim_index, start_index, i;
634 dns_cache_entry_t *ep;
636 if (dm->is_enabled == 0)
637 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
640 * Silence spurious coverity warning. We know pool_elts >> 0, or
641 * we wouldn't be here...
644 if (pool_elts (dm->entries) == 0)
645 return VNET_API_ERROR_UNSPECIFIED;
648 dns_cache_lock (dm, 3);
649 limit = pool_elts (dm->entries);
650 start_index = random_u32 (&dm->random_seed) % limit;
652 for (i = 0; i < limit; i++)
654 victim_index = (start_index + i) % limit;
656 if (!pool_is_free_index (dm->entries, victim_index))
658 ep = pool_elt_at_index (dm->entries, victim_index);
659 /* Delete only valid, non-static entries */
660 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
661 && ((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0))
663 rv = vnet_dns_delete_entry_by_index_nolock (dm, victim_index);
664 dns_cache_unlock (dm);
669 dns_cache_unlock (dm);
671 clib_warning ("Couldn't find an entry to delete?");
672 return VNET_API_ERROR_UNSPECIFIED;
676 dns_add_static_entry (dns_main_t * dm, u8 * name, u8 * dns_reply_data)
678 dns_cache_entry_t *ep;
682 if (dm->is_enabled == 0)
683 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
685 dns_cache_lock (dm, 4);
686 p = hash_get_mem (dm->cache_entry_by_name, name);
689 dns_cache_unlock (dm);
690 return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
693 if (pool_elts (dm->entries) == dm->name_cache_size)
695 /* Will only fail if the cache is totally filled w/ static entries... */
696 rv = delete_random_entry (dm);
699 dns_cache_unlock (dm);
704 pool_get (dm->entries, ep);
705 clib_memset (ep, 0, sizeof (*ep));
707 /* Note: consumes the name vector */
709 /* make sure it NULL-terminated as hash_set_mem will use strlen() */
710 vec_terminate_c_string (ep->name);
711 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
712 ep->flags = DNS_CACHE_ENTRY_FLAG_VALID | DNS_CACHE_ENTRY_FLAG_STATIC;
713 ep->dns_response = dns_reply_data;
715 dns_cache_unlock (dm);
720 vnet_dns_resolve_name (vlib_main_t * vm, dns_main_t * dm, u8 * name,
721 dns_pending_request_t * t, dns_cache_entry_t ** retp)
723 dns_cache_entry_t *ep;
727 dns_pending_request_t *pr;
730 now = vlib_time_now (vm);
732 /* In case we can't actually answer the question right now... */
735 /* binary API caller might forget to set the name. Guess how we know. */
737 return VNET_API_ERROR_INVALID_VALUE;
739 dns_cache_lock (dm, 5);
741 p = hash_get_mem (dm->cache_entry_by_name, name);
744 ep = pool_elt_at_index (dm->entries, p[0]);
745 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
747 /* Has the entry expired? */
748 if (((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0)
749 && (now > ep->expiration_time))
752 u32 *indices_to_delete = 0;
755 * Take out the rest of the resolution chain
756 * This isn't optimal, but it won't happen very often.
760 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME))
762 vec_add1 (indices_to_delete, ep - dm->entries);
764 p = hash_get_mem (dm->cache_entry_by_name, ep->cname);
767 ep = pool_elt_at_index (dm->entries, p[0]);
771 vec_add1 (indices_to_delete, ep - dm->entries);
775 for (i = 0; i < vec_len (indices_to_delete); i++)
777 /* Reenable to watch re-resolutions */
780 ep = pool_elt_at_index (dm->entries,
781 indices_to_delete[i]);
782 clib_warning ("Re-resolve %s", ep->name);
785 vnet_dns_delete_entry_by_index_nolock
786 (dm, indices_to_delete[i]);
788 vec_free (indices_to_delete);
789 /* Yes, kill it... */
793 if (ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
799 dns_cache_unlock (dm);
805 * Resolution pending. Add request to the pending vector
806 * by copying the template request
808 vec_add2 (ep->pending_requests, pr, 1);
809 memcpy (pr, t, sizeof (*pr));
810 dns_cache_unlock (dm);
816 if (pool_elts (dm->entries) == dm->name_cache_size)
818 /* Will only fail if the cache is totally filled w/ static entries... */
819 rv = delete_random_entry (dm);
822 dns_cache_unlock (dm);
827 /* add new hash table entry */
828 pool_get (dm->entries, ep);
829 clib_memset (ep, 0, sizeof (*ep));
831 ep->name = format (0, "%s%c", name, 0);
832 _vec_len (ep->name) = vec_len (ep->name) - 1;
834 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
836 vec_add1 (dm->unresolved_entries, ep - dm->entries);
837 vec_add2 (ep->pending_requests, pr, 1);
839 pr->request_type = t->request_type;
841 /* Remember details so we can reply later... */
842 if (t->request_type == DNS_API_PENDING_NAME_TO_IP ||
843 t->request_type == DNS_API_PENDING_IP_TO_NAME)
845 pr->client_index = t->client_index;
846 pr->client_context = t->client_context;
850 pr->client_index = ~0;
851 pr->is_ip6 = t->is_ip6;
852 pr->dst_port = t->dst_port;
859 clib_memcpy (pr->dst_address, t->dst_address, count);
862 vnet_send_dns_request (vm, dm, ep);
863 dns_cache_unlock (dm);
867 #define foreach_notification_to_move \
871 * Handle cname indirection. JFC. Called with the cache locked.
872 * returns 0 if the reply is not a CNAME.
876 vnet_dns_cname_indirection_nolock (vlib_main_t * vm, dns_main_t * dm,
877 u32 ep_index, u8 * reply)
892 dns_cache_entry_t *ep, *next_ep;
895 h = (dns_header_t *) reply;
896 flags = clib_net_to_host_u16 (h->flags);
897 rcode = flags & DNS_RCODE_MASK;
899 /* See if the response is OK */
902 case DNS_RCODE_NO_ERROR:
905 case DNS_RCODE_NAME_ERROR:
906 case DNS_RCODE_FORMAT_ERROR:
907 case DNS_RCODE_SERVER_FAILURE:
908 case DNS_RCODE_NOT_IMPLEMENTED:
909 case DNS_RCODE_REFUSED:
913 curpos = (u8 *) (h + 1);
917 /* Skip the questions */
918 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
925 pos += sizeof (dns_query_t);
928 /* expect a pointer chase here for a CNAME record */
929 if ((pos2[0] & 0xC0) == 0xC0)
934 /* Walk the answer(s) to see what to do next */
935 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
937 rr = (dns_rr_t *) pos;
938 switch (clib_net_to_host_u16 (rr->type))
940 /* Real address record? Done.. */
945 * Maybe chase a CNAME pointer?
946 * It's not unheard-of for name-servers to return
947 * both CNAME and A/AAAA records...
953 /* Some other junk, e.g. a nameserver... */
957 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
959 if ((pos2[0] & 0xc0) == 0xc0)
963 /* Neither a CNAME nor a real address. Try another server */
966 flags &= ~DNS_RCODE_MASK;
967 flags |= DNS_RCODE_NAME_ERROR;
968 h->flags = clib_host_to_net_u16 (flags);
972 /* This is a CNAME record, chase the name chain. */
975 /* The last request is no longer pending.. */
976 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
977 if (ep_index == dm->unresolved_entries[i])
979 vec_delete (dm->unresolved_entries, 1, i);
980 goto found_last_request;
982 clib_warning ("pool elt %d supposedly pending, but not found...", ep_index);
987 now = vlib_time_now (vm);
988 cname = vnet_dns_labels_to_name (rr->rdata, reply, &pos2);
991 _vec_len (cname) -= 1;
992 ep = pool_elt_at_index (dm->entries, ep_index);
994 ep->flags |= (DNS_CACHE_ENTRY_FLAG_CNAME | DNS_CACHE_ENTRY_FLAG_VALID);
995 /* Save the response */
996 if (ep->dns_response)
997 vec_free (ep->dns_response);
998 ep->dns_response = reply;
999 /* Set up expiration time */
1000 ep->expiration_time = now + clib_net_to_host_u32 (rr->ttl);
1002 pool_get (dm->entries, next_ep);
1004 /* Need to recompute ep post pool-get */
1005 ep = pool_elt_at_index (dm->entries, ep_index);
1007 clib_memset (next_ep, 0, sizeof (*next_ep));
1008 next_ep->name = vec_dup (cname);
1009 vec_add1 (next_ep->name, 0);
1010 _vec_len (next_ep->name) -= 1;
1012 hash_set_mem (dm->cache_entry_by_name, next_ep->name,
1013 next_ep - dm->entries);
1015 /* Use the same server */
1016 next_ep->server_rotor = ep->server_rotor;
1017 next_ep->server_af = ep->server_af;
1019 /* Move notification data to the next name in the chain */
1020 #define _(a) next_ep->a = ep->a; ep->a = 0;
1021 foreach_notification_to_move;
1024 request = name_to_labels (cname);
1025 name_copy = vec_dup (request);
1027 qp_offset = vec_len (request);
1029 /* Add space for the query header */
1030 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
1032 qp = (dns_query_t *) (request + qp_offset);
1034 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
1035 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1036 clib_memcpy (qp, name_copy, vec_len (name_copy));
1037 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
1038 vec_free (name_copy);
1040 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1041 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1043 /* Punch in space for the dns_header_t */
1044 vec_insert (request, sizeof (dns_header_t), 0);
1046 h = (dns_header_t *) request;
1048 /* Transaction ID = pool index */
1049 h->id = clib_host_to_net_u16 (next_ep - dm->entries);
1051 /* Ask for a recursive lookup */
1052 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
1053 h->qdcount = clib_host_to_net_u16 (2);
1057 next_ep->dns_request = request;
1058 next_ep->retry_timer = now + 2.0;
1059 next_ep->retry_count = 0;
1062 * Enable this to watch recursive resolution happen...
1063 * fformat (stdout, "%U", format_dns_reply, request, 2);
1066 vec_add1 (dm->unresolved_entries, next_ep - dm->entries);
1067 vnet_send_dns_request (vm, dm, next_ep);
1072 vnet_dns_response_to_reply (u8 *response, dns_resolve_name_t *rn,
1080 u8 *curpos, *pos, *pos2;
1084 int pointer_chase, addr_set = 0;
1086 h = (dns_header_t *) response;
1087 flags = clib_net_to_host_u16 (h->flags);
1088 rcode = flags & DNS_RCODE_MASK;
1090 /* See if the response is OK, etc. */
1094 case DNS_RCODE_NO_ERROR:
1097 case DNS_RCODE_NAME_ERROR:
1098 case DNS_RCODE_FORMAT_ERROR:
1099 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1101 case DNS_RCODE_SERVER_FAILURE:
1102 case DNS_RCODE_NOT_IMPLEMENTED:
1103 case DNS_RCODE_REFUSED:
1104 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1107 /* No answers? Loser... */
1108 if (clib_net_to_host_u16 (h->anscount) < 1)
1109 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1111 curpos = (u8 *) (h + 1);
1113 /* Skip the name we asked about */
1116 /* Should never happen, but stil... */
1117 if ((len & 0xC0) == 0xC0)
1121 /* skip the name / label-set */
1130 limit = clib_net_to_host_u16 (h->qdcount);
1131 qp = (dns_query_t *) curpos;
1136 limit = clib_net_to_host_u16 (h->anscount);
1138 for (i = 0; i < limit; i++)
1140 pos = pos2 = curpos;
1143 /* Expect pointer chases in the answer section... */
1144 if ((pos2[0] & 0xC0) == 0xC0)
1147 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1156 if ((pos2[0] & 0xc0) == 0xc0)
1159 * If we've already done one pointer chase,
1160 * do not move the pos pointer.
1162 if (pointer_chase == 0)
1164 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1172 if (pointer_chase == 0)
1175 rr = (dns_rr_t *) pos;
1177 switch (clib_net_to_host_u16 (rr->type))
1180 /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1181 ip_address_set (&rn->address, rr->rdata, AF_IP4);
1182 ttl = clib_net_to_host_u32 (rr->ttl);
1184 if (min_ttlp && *min_ttlp > ttl)
1188 /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1189 ip_address_set (&rn->address, rr->rdata, AF_IP6);
1190 ttl = clib_net_to_host_u32 (rr->ttl);
1191 if (min_ttlp && *min_ttlp > ttl)
1199 /* Might as well stop ASAP */
1202 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1207 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1212 vnet_dns_response_to_name (u8 * response,
1213 vl_api_dns_resolve_ip_reply_t * rmp,
1221 u8 *curpos, *pos, *pos2;
1226 u8 *junk __attribute__ ((unused));
1230 h = (dns_header_t *) response;
1231 flags = clib_net_to_host_u16 (h->flags);
1232 rcode = flags & DNS_RCODE_MASK;
1234 /* See if the response is OK, etc. */
1238 case DNS_RCODE_NO_ERROR:
1241 case DNS_RCODE_NAME_ERROR:
1242 case DNS_RCODE_FORMAT_ERROR:
1243 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1245 case DNS_RCODE_SERVER_FAILURE:
1246 case DNS_RCODE_NOT_IMPLEMENTED:
1247 case DNS_RCODE_REFUSED:
1248 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1251 /* No answers? Loser... */
1252 if (clib_net_to_host_u16 (h->anscount) < 1)
1253 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1255 curpos = (u8 *) (h + 1);
1257 /* Skip the name we asked about */
1260 /* Should never happen, but stil... */
1261 if ((len & 0xC0) == 0xC0)
1265 /* skip the name / label-set */
1274 limit = clib_net_to_host_u16 (h->qdcount);
1275 qp = (dns_query_t *) curpos;
1280 limit = clib_net_to_host_u16 (h->anscount);
1282 for (i = 0; i < limit; i++)
1284 pos = pos2 = curpos;
1287 /* Expect pointer chases in the answer section... */
1288 if ((pos2[0] & 0xC0) == 0xC0)
1291 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1300 if ((pos2[0] & 0xc0) == 0xc0)
1303 * If we've already done one pointer chase,
1304 * do not move the pos pointer.
1306 if (pointer_chase == 0)
1308 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1316 if (pointer_chase == 0)
1319 rr = (dns_rr_t *) pos;
1321 switch (clib_net_to_host_u16 (rr->type))
1324 name = vnet_dns_labels_to_name (rr->rdata, response, &junk);
1325 memcpy (rmp->name, name, vec_len (name));
1326 ttl = clib_net_to_host_u32 (rr->ttl);
1329 rmp->name[vec_len (name)] = 0;
1335 /* Might as well stop ASAP */
1338 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1343 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1348 dns_resolve_name (u8 *name, dns_cache_entry_t **ep, dns_pending_request_t *t0,
1349 dns_resolve_name_t *rn)
1351 dns_main_t *dm = &dns_main;
1352 vlib_main_t *vm = vlib_get_main ();
1354 int rv = vnet_dns_resolve_name (vm, dm, name, t0, ep);
1356 /* Error, e.g. not enabled? Tell the user */
1360 /* Resolution pending? Don't reply... */
1364 return vnet_dns_response_to_reply (ep[0]->dns_response, rn, 0 /* ttl-ptr */);
1368 vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1370 dns_main_t *dm = &dns_main;
1371 vl_api_dns_resolve_name_reply_t *rmp;
1372 dns_cache_entry_t *ep = 0;
1373 dns_pending_request_t _t0, *t0 = &_t0;
1375 dns_resolve_name_t rn;
1377 /* Sanitize the name slightly */
1378 mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1380 t0->request_type = DNS_API_PENDING_NAME_TO_IP;
1381 t0->client_index = mp->client_index;
1382 t0->client_context = mp->context;
1384 rv = dns_resolve_name (mp->name, &ep, t0, &rn);
1386 /* Error, e.g. not enabled? Tell the user */
1389 REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1393 /* Resolution pending? Don't reply... */
1398 REPLY_MACRO2 (VL_API_DNS_RESOLVE_NAME_REPLY, ({
1399 ip_address_copy_addr (rmp->ip4_address, &rn.address);
1400 if (ip_addr_version (&rn.address) == AF_IP4)
1409 vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
1411 vlib_main_t *vm = vlib_get_main ();
1412 dns_main_t *dm = &dns_main;
1413 vl_api_dns_resolve_ip_reply_t *rmp;
1414 dns_cache_entry_t *ep;
1417 u8 *lookup_name = 0;
1419 dns_pending_request_t _t0, *t0 = &_t0;
1423 for (i = 15; i >= 0; i--)
1425 digit = mp->address[i];
1426 nybble = (digit & 0x0F);
1428 vec_add1 (lookup_name, (nybble - 10) + 'a');
1430 vec_add1 (lookup_name, nybble + '0');
1431 vec_add1 (lookup_name, '.');
1432 nybble = (digit & 0xF0) >> 4;
1434 vec_add1 (lookup_name, (nybble - 10) + 'a');
1436 vec_add1 (lookup_name, nybble + '0');
1437 vec_add1 (lookup_name, '.');
1439 len = vec_len (lookup_name);
1440 vec_validate (lookup_name, len + 8);
1441 memcpy (lookup_name + len, "ip6.arpa", 8);
1445 for (i = 3; i >= 0; i--)
1447 digit = mp->address[i];
1448 lookup_name = format (lookup_name, "%d.", digit);
1450 lookup_name = format (lookup_name, "in-addr.arpa");
1453 vec_add1 (lookup_name, 0);
1455 t0->request_type = DNS_API_PENDING_IP_TO_NAME;
1456 t0->client_index = mp->client_index;
1457 t0->client_context = mp->context;
1459 rv = vnet_dns_resolve_name (vm, dm, lookup_name, t0, &ep);
1461 vec_free (lookup_name);
1463 /* Error, e.g. not enabled? Tell the user */
1466 REPLY_MACRO (VL_API_DNS_RESOLVE_IP_REPLY);
1470 /* Resolution pending? Don't reply... */
1475 REPLY_MACRO2(VL_API_DNS_RESOLVE_IP_REPLY,
1477 rv = vnet_dns_response_to_name (ep->dns_response, rmp, 0 /* ttl-ptr */);
1478 rmp->retval = clib_host_to_net_u32 (rv);
1483 static clib_error_t *
1484 dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1486 dns_main_t *dm = &dns_main;
1488 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1490 if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1492 else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1495 return clib_error_return (0, "unknown input `%U'",
1496 format_unformat_error, input);
1501 VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1504 unformat_dns_reply (unformat_input_t * input, va_list * args)
1506 u8 **result = va_arg (*args, u8 **);
1507 u8 **namep = va_arg (*args, u8 **);
1521 if (unformat (input, "%v", &name))
1524 if (unformat (input, "%U", unformat_ip4_address, &a4))
1527 if (unformat (input, "%U", unformat_ip6_address, &a6))
1531 if (unformat (input, "%U", unformat_ip6_address, &a6))
1534 if (unformat (input, "%U", unformat_ip4_address, &a6))
1538 /* Must have a name */
1542 /* Must have at least one address */
1543 if (!(a4_set + a6_set))
1546 /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1547 ce = name_to_labels (name);
1548 qp_offset = vec_len (ce);
1550 /* Add space for the query header */
1551 vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1552 qp = (dns_query_t *) (ce + qp_offset);
1554 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1555 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1557 /* Punch in space for the dns_header_t */
1558 vec_insert (ce, sizeof (dns_header_t), 0);
1560 h = (dns_header_t *) ce;
1562 /* Fake Transaction ID */
1565 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1566 h->qdcount = clib_host_to_net_u16 (1);
1567 h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1571 /* Now append one or two A/AAAA RR's... */
1574 /* Pointer to the name (DGMS) */
1575 vec_add1 (ce, 0xC0);
1576 vec_add1 (ce, 0x0C);
1577 vec_add2 (ce, rru8, sizeof (*rr) + 4);
1579 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1580 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1581 rr->ttl = clib_host_to_net_u32 (86400);
1582 rr->rdlength = clib_host_to_net_u16 (4);
1583 memcpy (rr->rdata, &a4, sizeof (a4));
1587 /* Pointer to the name (DGMS) */
1588 vec_add1 (ce, 0xC0);
1589 vec_add1 (ce, 0x0C);
1590 vec_add2 (ce, rru8, sizeof (*rr) + 16);
1592 rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1593 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1594 rr->ttl = clib_host_to_net_u32 (86400);
1595 rr->rdlength = clib_host_to_net_u16 (16);
1596 memcpy (rr->rdata, &a6, sizeof (a6));
1608 format_dns_query (u8 * s, va_list * args)
1610 u8 **curpos = va_arg (*args, u8 **);
1611 int verbose = va_arg (*args, int);
1616 s = format (s, " Name: ");
1618 /* Unwind execrated counted-label sheit */
1624 for (i = 0; i < len; i++)
1625 vec_add1 (s, *pos++);
1637 qp = (dns_query_t *) pos;
1640 switch (clib_net_to_host_u16 (qp->type))
1643 s = format (s, "type A\n");
1646 s = format (s, "type AAAA\n");
1649 s = format (s, "type ALL\n");
1653 s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1658 pos += sizeof (*qp);
1665 * format dns reply data
1666 * verbose > 1, dump everything
1667 * verbose == 1, dump all A and AAAA records
1668 * verbose == 0, dump one A record, and one AAAA record
1672 format_dns_reply_data (u8 * s, va_list * args)
1674 u8 *reply = va_arg (*args, u8 *);
1675 u8 **curpos = va_arg (*args, u8 **);
1676 int verbose = va_arg (*args, int);
1677 int *print_ip4 = va_arg (*args, int *);
1678 int *print_ip6 = va_arg (*args, int *);
1683 int pointer_chase = 0;
1685 u16 rrtype_host_byte_order;
1687 pos = pos2 = *curpos;
1690 s = format (s, " ");
1692 /* chase pointer? almost always yes here... */
1693 if ((pos2[0] & 0xc0) == 0xc0)
1696 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1704 for (i = 0; i < len; i++)
1707 vec_add1 (s, *pos2);
1710 if ((pos2[0] & 0xc0) == 0xc0)
1713 * If we've already done one pointer chase,
1714 * do not move the pos pointer.
1716 if (pointer_chase == 0)
1718 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1736 if (pointer_chase == 0)
1739 rr = (dns_rr_t *) pos;
1740 rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
1742 switch (rrtype_host_byte_order)
1747 s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1748 format_ip4_address, rr->rdata);
1753 s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1754 clib_net_to_host_u32 (rr->ttl));
1759 pos += sizeof (*rr) + 4;
1765 s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1766 format_ip6_address, rr->rdata);
1771 s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1772 clib_net_to_host_u32 (rr->ttl));
1776 pos += sizeof (*rr) + 16;
1782 s = format (s, "TEXT: ");
1783 for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1784 vec_add1 (s, rr->rdata[i]);
1787 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1790 case DNS_TYPE_HINFO:
1792 /* Two counted strings. DGMS */
1798 s = format (s, "HINFO: ");
1801 for (i = 0; i < *len; i++)
1802 vec_add1 (s, *curpos++);
1806 for (i = 0; i < *len; i++)
1807 vec_add1 (s, *curpos++);
1812 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1815 case DNS_TYPE_NAMESERVER:
1818 s = format (s, "Nameserver: ");
1821 /* chase pointer? */
1822 if ((pos2[0] & 0xc0) == 0xc0)
1825 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1832 for (i = 0; i < len; i++)
1833 vec_add1 (s, *pos2++);
1835 /* chase pointer, typically to offset 12... */
1836 if (pos2[0] == 0xC0)
1837 pos2 = reply + pos2[1];
1846 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1849 case DNS_TYPE_MAIL_EXCHANGE:
1852 tp = (u16 *) rr->rdata;
1854 s = format (s, "Mail Exchange: Preference %d ", (u32)
1855 clib_net_to_host_u16 (*tp));
1857 pos2 = rr->rdata + 2;
1859 /* chase pointer? */
1860 if (pos2[0] == 0xc0)
1861 pos2 = reply + pos2[1];
1867 for (i = 0; i < len; i++)
1868 vec_add1 (s, *pos2++);
1871 if (pos2[0] == 0xC0)
1872 pos2 = reply + pos2[1];
1882 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1886 case DNS_TYPE_CNAME:
1889 tp = (u16 *) rr->rdata;
1891 if (rrtype_host_byte_order == DNS_TYPE_CNAME)
1892 s = format (s, "CNAME: ");
1894 s = format (s, "PTR: ");
1898 /* chase pointer? */
1899 if (pos2[0] == 0xc0)
1900 pos2 = reply + pos2[1];
1906 for (i = 0; i < len; i++)
1907 vec_add1 (s, *pos2++);
1910 if (pos2[0] == 0xC0)
1911 pos2 = reply + pos2[1];
1920 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1925 s = format (s, "type %d: len %d\n",
1926 (int) clib_net_to_host_u16 (rr->type),
1927 sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
1928 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1938 format_dns_reply (u8 * s, va_list * args)
1940 u8 *reply_as_u8 = va_arg (*args, u8 *);
1941 int verbose = va_arg (*args, int);
1949 h = (dns_header_t *) reply_as_u8;
1950 id = clib_net_to_host_u16 (h->id);
1951 flags = clib_net_to_host_u16 (h->flags);
1955 s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
1957 s = format (s, " %s %s %s %s\n",
1958 (flags & DNS_RA) ? "recur" : "no-recur",
1959 (flags & DNS_RD) ? "recur-des" : "no-recur-des",
1960 (flags & DNS_TC) ? "trunc" : "no-trunc",
1961 (flags & DNS_AA) ? "auth" : "non-auth");
1962 s = format (s, " %d queries, %d answers, %d name-servers,"
1964 clib_net_to_host_u16 (h->qdcount),
1965 clib_net_to_host_u16 (h->anscount),
1966 clib_net_to_host_u16 (h->nscount),
1967 clib_net_to_host_u16 (h->arcount));
1970 curpos = (u8 *) (h + 1);
1975 s = format (s, " Queries:\n");
1976 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
1978 /* The query is variable-length, so curpos is a value-result parm */
1979 s = format (s, "%U", format_dns_query, &curpos, verbose);
1985 s = format (s, " Replies:\n");
1987 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
1989 /* curpos is a value-result parm */
1990 s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
1991 verbose, &print_ip4, &print_ip6);
1998 format_dns_cache (u8 * s, va_list * args)
2000 dns_main_t *dm = va_arg (*args, dns_main_t *);
2001 f64 now = va_arg (*args, f64);
2002 int verbose = va_arg (*args, int);
2003 u8 *name = va_arg (*args, u8 *);
2004 dns_cache_entry_t *ep;
2008 if (dm->is_enabled == 0)
2010 s = format (s, "The DNS cache is disabled...");
2014 if (pool_elts (dm->entries) == 0)
2016 s = format (s, "The DNS cache is empty...");
2020 dns_cache_lock (dm, 6);
2024 p = hash_get_mem (dm->cache_entry_by_name, name);
2027 s = format (s, "%s is not in the cache...", name);
2028 dns_cache_unlock (dm);
2032 ep = pool_elt_at_index (dm->entries, p[0]);
2033 /* Magic to spit out a C-initializer to research hemorrhoids... */
2037 s = format (s, "static u8 dns_reply_data_initializer[] =\n");
2038 s = format (s, "{\n");
2040 for (i = 0; i < vec_len (ep->dns_response); i++)
2047 s = format (s, "0x%02x, ", ep->dns_response[i]);
2049 s = format (s, "};\n");
2053 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2055 ASSERT (ep->dns_response);
2056 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2061 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2062 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2064 s = format (s, "%s%s -> %U", ss, ep->name,
2065 format_dns_reply, ep->dns_response, verbose);
2066 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2068 f64 time_left = ep->expiration_time - now;
2069 if (time_left > 0.0)
2070 s = format (s, " TTL left %.1f", time_left);
2072 s = format (s, " EXPIRED");
2077 ASSERT (ep->dns_request);
2078 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2086 s = format (s, "DNS cache contains %d entries\n", pool_elts (dm->entries));
2091 pool_foreach (ep, dm->entries)
2093 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2095 ASSERT (ep->dns_response);
2096 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2101 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2102 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2104 s = format (s, "%s%s -> %U", ss, ep->name,
2108 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2110 f64 time_left = ep->expiration_time - now;
2111 if (time_left > 0.0)
2112 s = format (s, " TTL left %.1f", time_left);
2114 s = format (s, " EXPIRED");
2117 s = format (s, " %d client notifications pending\n",
2118 vec_len(ep->pending_requests));
2123 ASSERT (ep->dns_request);
2124 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2132 dns_cache_unlock (dm);
2137 static clib_error_t *
2138 show_dns_cache_command_fn (vlib_main_t * vm,
2139 unformat_input_t * input, vlib_cli_command_t * cmd)
2141 dns_main_t *dm = &dns_main;
2144 f64 now = vlib_time_now (vm);
2146 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2148 if (unformat (input, "verbose %d", &verbose))
2150 else if (unformat (input, "verbose"))
2152 else if (unformat (input, "name %s", &name))
2155 return clib_error_return (0, "unknown input `%U'",
2156 format_unformat_error, input);
2159 vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
2165 VLIB_CLI_COMMAND (show_dns_cache_command) =
2167 .path = "show dns cache",
2168 .short_help = "show dns cache [verbose [nn]]",
2169 .function = show_dns_cache_command_fn,
2173 static clib_error_t *
2174 show_dns_servers_command_fn (vlib_main_t * vm,
2175 unformat_input_t * input,
2176 vlib_cli_command_t * cmd)
2178 dns_main_t *dm = &dns_main;
2181 if ((vec_len (dm->ip4_name_servers) + vec_len (dm->ip6_name_servers)) == 0)
2182 return clib_error_return (0, "No name servers configured...");
2184 if (vec_len (dm->ip4_name_servers))
2186 vlib_cli_output (vm, "ip4 name servers:");
2187 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
2188 vlib_cli_output (vm, "%U", format_ip4_address,
2189 dm->ip4_name_servers + i);
2191 if (vec_len (dm->ip6_name_servers))
2193 vlib_cli_output (vm, "ip6 name servers:");
2194 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
2195 vlib_cli_output (vm, "%U", format_ip6_address,
2196 dm->ip4_name_servers + i);
2202 VLIB_CLI_COMMAND (show_dns_server_command) =
2204 .path = "show dns servers",
2205 .short_help = "show dns servers",
2206 .function = show_dns_servers_command_fn,
2211 static clib_error_t *
2212 dns_cache_add_del_command_fn (vlib_main_t * vm,
2213 unformat_input_t * input,
2214 vlib_cli_command_t * cmd)
2216 dns_main_t *dm = &dns_main;
2222 clib_error_t *error;
2224 if (unformat (input, "add"))
2226 if (unformat (input, "del"))
2228 if (unformat (input, "clear"))
2231 if (is_add == -1 && is_clear == -1)
2232 return clib_error_return (0, "add / del / clear required...");
2236 rv = dns_cache_clear (dm);
2242 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2243 error = clib_error_return (0, "Name resolution not enabled");
2248 /* Delete (by name)? */
2251 if (unformat (input, "%v", &name))
2253 rv = dns_delete_by_name (dm, name);
2256 case VNET_API_ERROR_NO_SUCH_ENTRY:
2257 error = clib_error_return (0, "%v not in the cache...", name);
2261 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2262 error = clib_error_return (0, "Name resolution not enabled");
2271 error = clib_error_return (0, "dns_delete_by_name returned %d",
2277 return clib_error_return (0, "unknown input `%U'",
2278 format_unformat_error, input);
2281 /* Note: dns_add_static_entry consumes the name vector if OK... */
2282 if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2284 rv = dns_add_static_entry (dm, name, dns_reply_data);
2287 case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2289 vec_free (dns_reply_data);
2290 return clib_error_return (0, "%v already in the cache...", name);
2295 return clib_error_return (0, "dns_add_static_entry returned %d",
2304 VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2306 .path = "dns cache",
2307 .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2308 .function = dns_cache_add_del_command_fn,
2312 #define DNS_FORMAT_TEST 1
2314 #if DNS_FORMAT_TEST > 0
2317 static u8 dns_reply_data_initializer[] =
2318 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2319 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2321 0x0, 0xff, /* type ALL */
2322 0x0, 0x1, /* class IN */
2323 0xc0, 0xc, /* pointer to yahoo.com name */
2324 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2325 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2326 0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2327 0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2328 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2329 0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2330 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2331 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2332 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2333 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2334 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2335 0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2336 0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2338 0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2339 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2340 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2341 0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2342 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2344 0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2345 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2346 0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2347 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2349 0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2350 0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2352 0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2354 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2356 0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2358 0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2359 0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2360 0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2364 /* www.cisco.com, has no addresses in reply */
2365 static u8 dns_reply_data_initializer[] = {
2366 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2367 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2368 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2370 0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2371 0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2372 0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2373 0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2374 0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2377 /* bind8 (linux widget, w/ nasty double pointer chasees */
2378 static u8 dns_reply_data_initializer[] = {
2380 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08,
2382 0x00, 0x06, 0x00, 0x06, 0x0a, 0x6f, 0x72, 0x69,
2384 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77, 0x77, 0x05,
2386 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f,
2388 0x6d, 0x00, 0x00, 0xff, 0x00, 0x01, 0x0a, 0x6f,
2390 0x72, 0x69, 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77,
2392 0x77, 0x05, 0x43, 0x49, 0x53, 0x43, 0x4f, 0xc0,
2395 0x1d, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2398 0x9a, 0x00, 0x18, 0x15, 0x72, 0x63, 0x64,
2399 0x6e, 0x39, 0x2d, 0x31, 0x34, 0x70, 0x2d, 0x64, 0x63,
2400 0x7a, 0x30, 0x35, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31,
2401 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00, 0x01, 0x00,
2402 0x00, 0x05, 0x9a, 0x00, 0x1a, 0x17, 0x61, 0x6c, 0x6c,
2403 0x6e, 0x30, 0x31, 0x2d, 0x61, 0x67, 0x30, 0x39, 0x2d,
2404 0x64, 0x63, 0x7a, 0x30, 0x33, 0x6e, 0x2d, 0x67, 0x73,
2405 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00,
2406 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x10, 0x0d, 0x72,
2407 0x74, 0x70, 0x35, 0x2d, 0x64, 0x6d, 0x7a, 0x2d, 0x67,
2408 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2409 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x18, 0x15,
2410 0x6d, 0x74, 0x76, 0x35, 0x2d, 0x61, 0x70, 0x31, 0x30,
2411 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x36, 0x6e, 0x2d, 0x67,
2412 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2413 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x1b, 0x18,
2414 0x73, 0x6e, 0x67, 0x64, 0x63, 0x30, 0x31, 0x2d, 0x61,
2415 0x62, 0x30, 0x37, 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x31,
2416 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0,
2417 0x26, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a,
2418 0x00, 0x1a, 0x17, 0x61, 0x65, 0x72, 0x30, 0x31, 0x2d,
2419 0x72, 0x34, 0x63, 0x32, 0x35, 0x2d, 0x64, 0x63, 0x7a,
2420 0x30, 0x31, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0,
2421 0x17, 0xc0, 0x26, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2422 0x00, 0x81, 0x00, 0x04, 0x48, 0xa3, 0x04, 0xa1, 0xc0,
2423 0x26, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82,
2424 0x00, 0x10, 0x20, 0x01, 0x04, 0x20, 0x12, 0x01, 0x00,
2425 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
2426 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2427 0x9a, 0x00, 0x02, 0xc0, 0xf4, 0xc0, 0x0c, 0x00, 0x02,
2428 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0,
2429 0xcd, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00,
2430 0x05, 0x9a, 0x00, 0x02, 0xc0, 0x8d, 0xc0, 0x0c, 0x00,
2431 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02,
2432 0xc0, 0x43, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00,
2433 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0, 0xa9, 0xc0, 0x0c,
2434 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00,
2435 0x02, 0xc0, 0x67, 0xc0, 0x8d, 0x00, 0x01, 0x00, 0x01,
2436 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0x40, 0x66, 0xf6,
2437 0x05, 0xc0, 0xa9, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2438 0x07, 0x08, 0x00, 0x04, 0xad, 0x24, 0xe0, 0x64, 0xc0,
2439 0x43, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08,
2440 0x00, 0x04, 0x48, 0xa3, 0x04, 0x1c, 0xc0, 0xf4, 0x00,
2441 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04,
2442 0xad, 0x26, 0xd4, 0x6c, 0xc0, 0x67, 0x00, 0x01, 0x00,
2443 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x25,
2444 0x90, 0x64, 0xc0, 0xcd, 0x00, 0x01, 0x00, 0x01, 0x00,
2445 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x27, 0x70, 0x44,
2449 static u8 dns_reply_data_initializer[] =
2450 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
2451 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
2452 0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
2453 0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
2455 0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
2456 0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
2457 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
2458 0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
2459 0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
2460 0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
2461 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
2462 0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
2463 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
2464 0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
2465 0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
2466 0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
2467 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
2468 0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
2469 0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
2470 0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
2471 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2472 0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
2473 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
2474 0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
2475 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
2476 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
2477 0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
2479 0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2483 /* www.weatherlink.com */
2484 static u8 dns_reply_data_initializer[] = {
2485 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2486 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x0b,
2487 0x77, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x6c, 0x69,
2488 0x6e, 0x6b, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0xff,
2489 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00,
2490 0x00, 0x0c, 0x9e, 0x00, 0x1f, 0x0e, 0x64, 0x33, 0x6b,
2491 0x72, 0x30, 0x67, 0x75, 0x62, 0x61, 0x31, 0x64, 0x76,
2492 0x77, 0x66, 0x0a, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x66,
2493 0x72, 0x6f, 0x6e, 0x74, 0x03, 0x6e, 0x65, 0x74, 0x00,
2498 static clib_error_t *
2499 test_dns_fmt_command_fn (vlib_main_t * vm,
2500 unformat_input_t * input, vlib_cli_command_t * cmd)
2502 dns_resolve_name_t _rn, *rn = &_rn;
2503 u8 *dns_reply_data = 0;
2506 vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2508 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2510 if (unformat (input, "verbose %d", &verbose))
2512 else if (unformat (input, "verbose"))
2515 return clib_error_return (0, "unknown input `%U'",
2516 format_unformat_error, input);
2519 vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2521 memcpy (dns_reply_data, dns_reply_data_initializer,
2522 ARRAY_LEN (dns_reply_data_initializer));
2524 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2526 clib_memset (rmp, 0, sizeof (*rmp));
2528 rv = vnet_dns_response_to_reply (dns_reply_data, rn, 0 /* ttl-ptr */);
2532 case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2533 vlib_cli_output (vm, "no addresses found...");
2537 vlib_cli_output (vm, "response to reply returned %d", rv);
2541 vlib_cli_output (vm, "ip address: %U", format_ip_address, &rn->address);
2545 vec_free (dns_reply_data);
2552 VLIB_CLI_COMMAND (test_dns_fmt_command) =
2554 .path = "test dns format",
2555 .short_help = "test dns format",
2556 .function = test_dns_fmt_command_fn,
2560 static clib_error_t *
2561 test_dns_unfmt_command_fn (vlib_main_t * vm,
2562 unformat_input_t * input, vlib_cli_command_t * cmd)
2564 u8 *dns_reply_data = 0;
2568 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2570 if (unformat (input, "verbose %d", &verbose))
2572 else if (unformat (input, "verbose"))
2574 else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2577 return clib_error_return (0, "unknown input `%U'",
2578 format_unformat_error, input);
2582 return clib_error_return (0, "dns data not set...");
2584 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2586 vec_free (dns_reply_data);
2592 VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2594 .path = "test dns unformat",
2595 .short_help = "test dns unformat <name> [ip4][ip6]",
2596 .function = test_dns_unfmt_command_fn,
2600 static clib_error_t *
2601 test_dns_expire_command_fn (vlib_main_t * vm,
2602 unformat_input_t * input,
2603 vlib_cli_command_t * cmd)
2605 dns_main_t *dm = &dns_main;
2609 dns_cache_entry_t *ep;
2611 if (unformat (input, "%v", &name))
2614 _vec_len (name) -= 1;
2617 return clib_error_return (0, "no name provided");
2619 dns_cache_lock (dm, 7);
2621 p = hash_get_mem (dm->cache_entry_by_name, name);
2624 dns_cache_unlock (dm);
2625 e = clib_error_return (0, "%s is not in the cache...", name);
2630 ep = pool_elt_at_index (dm->entries, p[0]);
2632 ep->expiration_time = 0;
2638 VLIB_CLI_COMMAND (test_dns_expire_command) =
2640 .path = "test dns expire",
2641 .short_help = "test dns expire <name>",
2642 .function = test_dns_expire_command_fn,
2648 vnet_send_dns6_reply (vlib_main_t * vm, dns_main_t * dm,
2649 dns_pending_request_t * pr, dns_cache_entry_t * ep,
2652 clib_warning ("Unimplemented...");
2657 vnet_send_dns4_reply (vlib_main_t * vm, dns_main_t * dm,
2658 dns_pending_request_t * pr, dns_cache_entry_t * ep,
2662 ip4_address_t src_address;
2670 /* vl_api_dns_resolve_name_reply_t _rnr, *rnr = &_rnr; */
2671 dns_resolve_name_t _rn, *rn = &_rn;
2672 vl_api_dns_resolve_ip_reply_t _rir, *rir = &_rir;
2679 int is_recycle = (b0 != 0);
2681 ASSERT (ep && ep->dns_response);
2683 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2685 /* Quick and dirty way to dig up the A-record address. $$ FIXME */
2686 clib_memset (rn, 0, sizeof (*rn));
2687 if (vnet_dns_response_to_reply (ep->dns_response, rn, &ttl))
2689 /* clib_warning ("response_to_reply failed..."); */
2692 else if (ip_addr_version (&rn->address) != AF_IP4)
2694 /* clib_warning ("No A-record..."); */
2698 else if (pr->request_type == DNS_PEER_PENDING_IP_TO_NAME)
2700 clib_memset (rir, 0, sizeof (*rir));
2701 if (vnet_dns_response_to_name (ep->dns_response, rir, &ttl))
2703 /* clib_warning ("response_to_name failed..."); */
2709 clib_warning ("Unknown request type %d", pr->request_type);
2713 /* Initialize a buffer */
2716 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2718 b0 = vlib_get_buffer (vm, bi);
2722 /* Use the buffer we were handed. Reinitialize it... */
2723 vlib_buffer_t bt = { };
2724 /* push/pop the reference count */
2725 u8 save_ref_count = b0->ref_count;
2726 vlib_buffer_copy_template (b0, &bt);
2727 b0->ref_count = save_ref_count;
2728 bi = vlib_get_buffer_index (vm, b0);
2731 if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
2732 vlib_buffer_free_one (vm, b0->next_buffer);
2735 * Reset the buffer. We recycle the DNS request packet in the cache
2736 * hit case, and reply immediately from the request node.
2738 * In the resolution-required / deferred case, resetting a freshly-allocated
2739 * buffer won't hurt. We hope.
2741 b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
2742 | VLIB_BUFFER_TOTAL_LENGTH_VALID);
2743 vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; /* "local0" */
2744 vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
2746 if (!ip4_sas (0 /* default VRF for now */, ~0,
2747 (const ip4_address_t *) &pr->dst_address, &src_address))
2750 ip = vlib_buffer_get_current (b0);
2751 udp = (udp_header_t *) (ip + 1);
2752 dns_response = (u8 *) (udp + 1);
2753 clib_memset (ip, 0, sizeof (*ip) + sizeof (*udp));
2756 * Start with the variadic portion of the exercise.
2757 * Turn the name into a set of DNS "labels". Max length
2758 * per label is 63, enforce that.
2760 reply = name_to_labels (pr->name);
2761 vec_free (pr->name);
2763 qp_offset = vec_len (reply);
2765 /* Add space for the query header */
2766 vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
2768 qp = (dns_query_t *) (reply + qp_offset);
2770 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2771 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
2773 qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2775 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
2777 /* Punch in space for the dns_header_t */
2778 vec_insert (reply, sizeof (dns_header_t), 0);
2780 dh = (dns_header_t *) reply;
2782 /* Transaction ID = pool index */
2785 /* Announce that we did a recursive lookup */
2786 tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
2788 tmp |= DNS_RCODE_NAME_ERROR;
2789 dh->flags = clib_host_to_net_u16 (tmp);
2790 dh->qdcount = clib_host_to_net_u16 (1);
2791 dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
2795 /* If the name resolution worked, cough up an appropriate RR */
2798 /* Add the answer. First, a name pointer (0xC00C) */
2799 vec_add1 (reply, 0xC0);
2800 vec_add1 (reply, 0x0C);
2802 /* Now, add single A-rec RR */
2803 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2805 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
2806 rr = (dns_rr_t *) rrptr;
2808 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
2809 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2810 rr->ttl = clib_host_to_net_u32 (ttl);
2811 rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
2812 ip_address_copy_addr (rr->rdata, &rn->address);
2816 /* Or a single PTR RR */
2817 u8 *vecname = format (0, "%s", rir->name);
2818 u8 *label_vec = name_to_labels (vecname);
2821 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
2822 rr = (dns_rr_t *) rrptr;
2823 rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2824 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2825 rr->ttl = clib_host_to_net_u32 (ttl);
2826 rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
2827 clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
2828 vec_free (label_vec);
2831 clib_memcpy (dns_response, reply, vec_len (reply));
2833 /* Set the packet length */
2834 b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
2837 ip->ip_version_and_header_length = 0x45;
2838 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
2840 ip->protocol = IP_PROTOCOL_UDP;
2841 ip->src_address.as_u32 = src_address.as_u32;
2842 clib_memcpy (ip->dst_address.as_u8, pr->dst_address,
2843 sizeof (ip4_address_t));
2844 ip->checksum = ip4_header_checksum (ip);
2847 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
2848 udp->dst_port = pr->dst_port;
2849 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
2855 * Ship pkts made out of whole cloth to ip4_lookup
2856 * Caller will ship recycled dns reply packets to ip4_lookup
2858 if (is_recycle == 0)
2860 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
2861 to_next = vlib_frame_vector_args (f);
2864 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
2868 #include <dns/dns.api.c>
2869 static clib_error_t *
2870 dns_init (vlib_main_t * vm)
2872 dns_main_t *dm = &dns_main;
2874 dm->vnet_main = vnet_get_main ();
2875 dm->name_cache_size = 1000;
2876 dm->max_ttl_in_seconds = 86400;
2877 dm->random_seed = 0xDEADDABE;
2878 dm->api_main = vlibapi_get_main ();
2880 /* Ask for a correctly-sized block of API message decode slots */
2881 dm->msg_id_base = setup_message_id_table ();
2887 VLIB_INIT_FUNCTION (dns_init) = {
2888 .init_order = VLIB_INITS ("flow_classify_init", "dns_init"),
2891 VLIB_PLUGIN_REGISTER () =
2893 .version = VPP_BUILD_VER,
2894 .description = "Simple DNS name resolver",
2900 * fd.io coding-style-patch-verification: ON
2903 * eval: (c-set-style "gnu")