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>
35 vlib_cli_output (handle, (char *) s); \
41 /* the cache hashtable expects a NULL-terminated C-string but everywhere else
42 * expects a non-NULL terminated vector... The pattern of adding \0 but hiding
43 * it away drives AddressSanitizer crazy, this helper tries to bring some of
46 static_always_inline void
47 dns_terminate_c_string (u8 **v)
51 clib_mem_unpoison (vec_end (*v), 1);
55 dns_cache_clear (dns_main_t * dm)
57 dns_cache_entry_t *ep;
59 if (dm->is_enabled == 0)
60 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
62 dns_cache_lock (dm, 1);
64 pool_foreach (ep, dm->entries)
67 vec_free (ep->pending_requests);
70 pool_free (dm->entries);
71 hash_free (dm->cache_entry_by_name);
72 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
73 vec_free (dm->unresolved_entries);
74 dns_cache_unlock (dm);
79 dns_enable_disable (vlib_main_t * vm, dns_main_t * dm, int is_enable)
81 vlib_thread_main_t *tm = &vlib_thread_main;
82 u32 n_vlib_mains = tm->n_vlib_mains;
84 /* Create the resolver process if not done already */
85 vnet_dns_create_resolver_process (vm, dm);
89 if (vec_len (dm->ip4_name_servers) == 0
90 && (vec_len (dm->ip6_name_servers) == 0))
91 return VNET_API_ERROR_NO_NAME_SERVERS;
93 if (dm->udp_ports_registered == 0)
95 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply,
96 dns46_reply_node.index, 1 /* is_ip4 */ );
98 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply6,
99 dns46_reply_node.index, 0 /* is_ip4 */ );
101 udp_register_dst_port (vm, UDP_DST_PORT_dns,
102 dns4_request_node.index, 1 /* is_ip4 */ );
104 udp_register_dst_port (vm, UDP_DST_PORT_dns6,
105 dns6_request_node.index, 0 /* is_ip4 */ );
107 dm->udp_ports_registered = 1;
110 if (dm->cache_entry_by_name == 0)
112 if (n_vlib_mains > 1)
113 clib_spinlock_init (&dm->cache_lock);
115 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
122 dns_cache_clear (dm);
128 static void vl_api_dns_enable_disable_t_handler
129 (vl_api_dns_enable_disable_t * mp)
131 vl_api_dns_enable_disable_reply_t *rmp;
132 vlib_main_t *vm = vlib_get_main ();
133 dns_main_t *dm = &dns_main;
136 rv = dns_enable_disable (vm, dm, mp->enable);
138 REPLY_MACRO (VL_API_DNS_ENABLE_DISABLE_REPLY);
142 dns6_name_server_add_del (dns_main_t * dm,
143 u8 * server_address_as_u8, int is_add)
150 /* Already there? done... */
151 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
153 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
154 sizeof (ip6_address_t)))
158 vec_add2 (dm->ip6_name_servers, ap, 1);
159 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
163 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
165 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
166 sizeof (ip6_address_t)))
168 vec_delete (dm->ip6_name_servers, 1, i);
172 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
178 dns4_name_server_add_del (dns_main_t * dm,
179 u8 * server_address_as_u8, int is_add)
186 /* Already there? done... */
187 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
189 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
190 sizeof (ip4_address_t)))
194 vec_add2 (dm->ip4_name_servers, ap, 1);
195 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
199 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
201 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
202 sizeof (ip4_address_t)))
204 vec_delete (dm->ip4_name_servers, 1, i);
208 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
213 static void vl_api_dns_name_server_add_del_t_handler
214 (vl_api_dns_name_server_add_del_t * mp)
216 dns_main_t *dm = &dns_main;
217 vl_api_dns_name_server_add_del_reply_t *rmp;
221 rv = dns6_name_server_add_del (dm, mp->server_address, mp->is_add);
223 rv = dns4_name_server_add_del (dm, mp->server_address, mp->is_add);
225 REPLY_MACRO (VL_API_DNS_NAME_SERVER_ADD_DEL_REPLY);
229 vnet_dns_send_dns4_request (vlib_main_t * vm, dns_main_t * dm,
230 dns_cache_entry_t * ep, ip4_address_t * server)
232 f64 now = vlib_time_now (vm);
237 ip4_address_t src_address;
242 ASSERT (ep->dns_request);
244 if (!ip4_sas (0 /* default VRF for now */, ~0, server, &src_address))
247 /* Go get a buffer */
248 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
251 b = vlib_get_buffer (vm, bi);
252 b->current_length = sizeof (ip4_header_t) + sizeof (udp_header_t) +
253 vec_len (ep->dns_request);
254 b->total_length_not_including_first_buffer = 0;
256 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
257 vnet_buffer (b)->sw_if_index[VLIB_RX] = 0; /* "local0" */
258 vnet_buffer (b)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
260 ip = vlib_buffer_get_current (b);
261 clib_memset (ip, 0, sizeof (*ip));
262 udp = (udp_header_t *) (ip + 1);
263 clib_memset (udp, 0, sizeof (*udp));
265 dns_request = (u8 *) (udp + 1);
268 ip->ip_version_and_header_length = 0x45;
269 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b));
271 ip->protocol = IP_PROTOCOL_UDP;
272 ip->src_address.as_u32 = src_address.as_u32;
273 ip->dst_address.as_u32 = server->as_u32;
274 ip->checksum = ip4_header_checksum (ip);
277 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
278 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
279 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
280 vec_len (ep->dns_request));
283 /* The actual DNS request */
284 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
286 /* Ship it to ip4_lookup */
287 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
288 to_next = vlib_frame_vector_args (f);
291 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
293 ep->retry_timer = now + 2.0;
297 vnet_dns_send_dns6_request (vlib_main_t * vm, dns_main_t * dm,
298 dns_cache_entry_t * ep, ip6_address_t * server)
300 f64 now = vlib_time_now (vm);
305 ip6_address_t src_address;
309 int junk __attribute__ ((unused));
311 ASSERT (ep->dns_request);
313 if (!ip6_sas (0 /* default VRF for now */, ~0, server, &src_address))
316 /* Go get a buffer */
317 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
320 b = vlib_get_buffer (vm, bi);
321 b->current_length = sizeof (ip6_header_t) + sizeof (udp_header_t) +
322 vec_len (ep->dns_request);
323 b->total_length_not_including_first_buffer = 0;
325 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
327 ip = vlib_buffer_get_current (b);
328 clib_memset (ip, 0, sizeof (*ip));
329 udp = (udp_header_t *) (ip + 1);
330 clib_memset (udp, 0, sizeof (*udp));
332 dns_request = (u8 *) (udp + 1);
335 ip->ip_version_traffic_class_and_flow_label =
336 clib_host_to_net_u32 (0x6 << 28);
339 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b)
340 - sizeof (ip6_header_t));
342 ip->protocol = IP_PROTOCOL_UDP;
343 ip6_address_copy (&ip->src_address, &src_address);
344 clib_memcpy (&ip->dst_address, server, sizeof (ip6_address_t));
347 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
348 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
349 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
350 vec_len (ep->dns_request));
352 udp->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ip, &junk);
354 /* The actual DNS request */
355 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
357 /* Ship it to ip6_lookup */
358 f = vlib_get_frame_to_node (vm, ip6_lookup_node.index);
359 to_next = vlib_frame_vector_args (f);
363 ep->retry_timer = now + 2.0;
367 * Translate "foo.com" into "0x3 f o o 0x3 c o m 0x0"
368 * A historical / hysterical micro-TLV scheme. DGMS.
371 name_to_labels (u8 * name)
374 int last_label_index;
379 /* punch in space for the first length */
380 vec_insert (rv, 1, 0);
381 last_label_index = 0;
384 while (i < vec_len (rv))
388 rv[last_label_index] = (i - last_label_index) - 1;
389 if ((i - last_label_index) > 63)
390 clib_warning ("stupid name, label length %d",
391 i - last_label_index);
392 last_label_index = i;
397 /* Set the last real label length */
398 rv[last_label_index] = (i - last_label_index) - 1;
401 * Add a [sic] NULL root label. Otherwise, the name parser can't figure out
409 * arc-function for the above.
410 * Translate "0x3 f o o 0x3 c o m 0x0" into "foo.com"
411 * Produces a non-NULL-terminated u8 *vector. %v format is your friend.
414 vnet_dns_labels_to_name (u8 * label, u8 * full_text, u8 ** parse_from_here)
421 *parse_from_here = 0;
423 /* chase initial pointer? */
424 if ((label[0] & 0xC0) == 0xC0)
426 *parse_from_here = label + 2;
427 offset = ((label[0] & 0x3f) << 8) + label[1];
428 label = full_text + offset;
435 for (i = 0; i < len; i++)
436 vec_add1 (reply, *label++);
439 if ((label[0] & 0xC0) == 0xC0)
441 *parse_from_here = label + 2;
442 offset = ((label[0] & 0x3f) << 8) + label[1];
443 label = full_text + offset;
448 vec_add1 (reply, '.');
450 if (*parse_from_here == 0)
451 *parse_from_here = label;
456 vnet_send_dns_request (vlib_main_t * vm, dns_main_t * dm,
457 dns_cache_entry_t * ep)
462 u8 *request, *name_copy;
465 /* This can easily happen if sitting in GDB, etc. */
466 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID || ep->server_fails > 1)
469 /* Construct the dns request, if we haven't been here already */
470 if (vec_len (ep->dns_request) == 0)
473 * Start with the variadic portion of the exercise.
474 * Turn the name into a set of DNS "labels". Max length
475 * per label is 63, enforce that.
477 request = name_to_labels (ep->name);
478 name_copy = vec_dup (request);
479 qp_offset = vec_len (request);
482 * At least when testing against "known good" DNS servers:
483 * it turns out that sending 2x requests - one for an A-record
484 * and another for a AAAA-record - seems to work better than
485 * sending a DNS_TYPE_ALL request.
488 /* Add space for the query header */
489 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
491 qp = (dns_query_t *) (request + qp_offset);
493 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
494 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
496 clib_memcpy (qp, name_copy, vec_len (name_copy));
497 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
498 vec_free (name_copy);
500 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
501 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
503 /* Punch in space for the dns_header_t */
504 vec_insert (request, sizeof (dns_header_t), 0);
506 h = (dns_header_t *) request;
508 /* Transaction ID = pool index */
509 h->id = clib_host_to_net_u16 (ep - dm->entries);
511 /* Ask for a recursive lookup */
512 tmp = DNS_RD | DNS_OPCODE_QUERY;
513 h->flags = clib_host_to_net_u16 (tmp);
514 h->qdcount = clib_host_to_net_u16 (2);
518 ep->dns_request = request;
521 /* Work out which server / address family we're going to use */
523 /* Retry using current server */
524 if (ep->retry_count++ < DNS_RETRIES_PER_SERVER)
526 if (ep->server_af == 1 /* ip6 */ )
528 if (vec_len (dm->ip6_name_servers))
530 vnet_dns_send_dns6_request
531 (vm, dm, ep, dm->ip6_name_servers + ep->server_rotor);
537 if (vec_len (dm->ip4_name_servers))
539 vnet_dns_send_dns4_request
540 (vm, dm, ep, dm->ip4_name_servers + ep->server_rotor);
544 else /* switch to a new server */
548 if (ep->server_af == 1 /* ip6 */ )
550 if (ep->server_rotor >= vec_len (dm->ip6_name_servers))
552 ep->server_rotor = 0;
553 ep->server_af = vec_len (dm->ip4_name_servers) > 0 ? 0 : 1;
558 if (ep->server_rotor >= vec_len (dm->ip4_name_servers))
560 ep->server_rotor = 0;
561 ep->server_af = vec_len (dm->ip6_name_servers) > 0 ? 1 : 0;
566 if (ep->server_af == 1 /* ip6 */ )
567 vnet_dns_send_dns6_request
568 (vm, dm, ep, dm->ip6_name_servers + ep->server_rotor);
570 vnet_dns_send_dns4_request
571 (vm, dm, ep, dm->ip4_name_servers + ep->server_rotor);
575 vlib_process_signal_event_mt (vm,
576 dm->resolver_process_node_index,
577 DNS_RESOLVER_EVENT_PENDING, 0);
581 vnet_dns_delete_entry_by_index_nolock (dns_main_t * dm, u32 index)
583 dns_cache_entry_t *ep;
586 if (dm->is_enabled == 0)
587 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
589 if (pool_is_free_index (dm->entries, index))
590 return VNET_API_ERROR_NO_SUCH_ENTRY;
592 ep = pool_elt_at_index (dm->entries, index);
593 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_VALID))
595 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
596 if (index == dm->unresolved_entries[i])
598 vec_delete (dm->unresolved_entries, 1, i);
601 clib_warning ("pool elt %d supposedly pending, but not found...",
606 hash_unset_mem (dm->cache_entry_by_name, ep->name);
608 vec_free (ep->pending_requests);
609 pool_put (dm->entries, ep);
615 dns_delete_by_name (dns_main_t * dm, u8 * name)
620 if (dm->is_enabled == 0)
621 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
623 dns_cache_lock (dm, 2);
624 p = hash_get_mem (dm->cache_entry_by_name, name);
627 dns_cache_unlock (dm);
628 return VNET_API_ERROR_NO_SUCH_ENTRY;
630 rv = vnet_dns_delete_entry_by_index_nolock (dm, p[0]);
632 dns_cache_unlock (dm);
638 delete_random_entry (dns_main_t * dm)
641 u32 victim_index, start_index, i;
643 dns_cache_entry_t *ep;
645 if (dm->is_enabled == 0)
646 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
649 * Silence spurious coverity warning. We know pool_elts >> 0, or
650 * we wouldn't be here...
653 if (pool_elts (dm->entries) == 0)
654 return VNET_API_ERROR_UNSPECIFIED;
657 dns_cache_lock (dm, 3);
658 limit = pool_elts (dm->entries);
659 start_index = random_u32 (&dm->random_seed) % limit;
661 for (i = 0; i < limit; i++)
663 victim_index = (start_index + i) % limit;
665 if (!pool_is_free_index (dm->entries, victim_index))
667 ep = pool_elt_at_index (dm->entries, victim_index);
668 /* Delete only valid, non-static entries */
669 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
670 && ((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0))
672 rv = vnet_dns_delete_entry_by_index_nolock (dm, victim_index);
673 dns_cache_unlock (dm);
678 dns_cache_unlock (dm);
680 clib_warning ("Couldn't find an entry to delete?");
681 return VNET_API_ERROR_UNSPECIFIED;
685 dns_add_static_entry (dns_main_t * dm, u8 * name, u8 * dns_reply_data)
687 dns_cache_entry_t *ep;
691 if (dm->is_enabled == 0)
692 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
694 dns_cache_lock (dm, 4);
695 p = hash_get_mem (dm->cache_entry_by_name, name);
698 dns_cache_unlock (dm);
699 return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
702 if (pool_elts (dm->entries) == dm->name_cache_size)
704 /* Will only fail if the cache is totally filled w/ static entries... */
705 rv = delete_random_entry (dm);
708 dns_cache_unlock (dm);
713 pool_get (dm->entries, ep);
714 clib_memset (ep, 0, sizeof (*ep));
716 /* Note: consumes the name vector */
718 /* make sure it NULL-terminated as hash_set_mem will use strlen() */
719 vec_terminate_c_string (ep->name);
720 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
721 ep->flags = DNS_CACHE_ENTRY_FLAG_VALID | DNS_CACHE_ENTRY_FLAG_STATIC;
722 ep->dns_response = dns_reply_data;
724 dns_cache_unlock (dm);
729 vnet_dns_resolve_name (vlib_main_t * vm, dns_main_t * dm, u8 * name,
730 dns_pending_request_t * t, dns_cache_entry_t ** retp)
732 dns_cache_entry_t *ep;
736 dns_pending_request_t *pr;
739 now = vlib_time_now (vm);
741 /* In case we can't actually answer the question right now... */
744 /* binary API caller might forget to set the name. Guess how we know. */
746 return VNET_API_ERROR_INVALID_VALUE;
748 dns_cache_lock (dm, 5);
750 p = hash_get_mem (dm->cache_entry_by_name, name);
753 ep = pool_elt_at_index (dm->entries, p[0]);
754 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
756 /* Has the entry expired? */
757 if (((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0)
758 && (now > ep->expiration_time))
761 u32 *indices_to_delete = 0;
764 * Take out the rest of the resolution chain
765 * This isn't optimal, but it won't happen very often.
769 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME))
771 vec_add1 (indices_to_delete, ep - dm->entries);
773 p = hash_get_mem (dm->cache_entry_by_name, ep->cname);
776 ep = pool_elt_at_index (dm->entries, p[0]);
780 vec_add1 (indices_to_delete, ep - dm->entries);
784 for (i = 0; i < vec_len (indices_to_delete); i++)
786 /* Reenable to watch re-resolutions */
789 ep = pool_elt_at_index (dm->entries,
790 indices_to_delete[i]);
791 clib_warning ("Re-resolve %s", ep->name);
794 vnet_dns_delete_entry_by_index_nolock
795 (dm, indices_to_delete[i]);
797 vec_free (indices_to_delete);
798 /* Yes, kill it... */
802 if (ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
808 dns_cache_unlock (dm);
814 * Resolution pending. Add request to the pending vector
815 * by copying the template request
817 vec_add2 (ep->pending_requests, pr, 1);
818 memcpy (pr, t, sizeof (*pr));
819 dns_cache_unlock (dm);
825 if (pool_elts (dm->entries) == dm->name_cache_size)
827 /* Will only fail if the cache is totally filled w/ static entries... */
828 rv = delete_random_entry (dm);
831 dns_cache_unlock (dm);
836 /* add new hash table entry */
837 pool_get (dm->entries, ep);
838 clib_memset (ep, 0, sizeof (*ep));
840 ep->name = format (0, "%s", name);
841 dns_terminate_c_string (&ep->name);
843 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
845 vec_add1 (dm->unresolved_entries, ep - dm->entries);
846 vec_add2 (ep->pending_requests, pr, 1);
848 pr->request_type = t->request_type;
850 /* Remember details so we can reply later... */
851 if (t->request_type == DNS_API_PENDING_NAME_TO_IP ||
852 t->request_type == DNS_API_PENDING_IP_TO_NAME)
854 pr->client_index = t->client_index;
855 pr->client_context = t->client_context;
859 pr->client_index = ~0;
860 pr->is_ip6 = t->is_ip6;
861 pr->dst_port = t->dst_port;
868 clib_memcpy (pr->dst_address, t->dst_address, count);
871 vnet_send_dns_request (vm, dm, ep);
872 dns_cache_unlock (dm);
876 #define foreach_notification_to_move \
880 * Handle cname indirection. JFC. Called with the cache locked.
881 * returns 0 if the reply is not a CNAME.
885 vnet_dns_cname_indirection_nolock (vlib_main_t * vm, dns_main_t * dm,
886 u32 ep_index, u8 * reply)
901 dns_cache_entry_t *ep, *next_ep;
904 h = (dns_header_t *) reply;
905 flags = clib_net_to_host_u16 (h->flags);
906 rcode = flags & DNS_RCODE_MASK;
908 /* See if the response is OK */
911 case DNS_RCODE_NO_ERROR:
914 case DNS_RCODE_NAME_ERROR:
915 case DNS_RCODE_FORMAT_ERROR:
916 case DNS_RCODE_SERVER_FAILURE:
917 case DNS_RCODE_NOT_IMPLEMENTED:
918 case DNS_RCODE_REFUSED:
922 curpos = (u8 *) (h + 1);
926 /* Skip the questions */
927 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
934 pos += sizeof (dns_query_t);
937 /* expect a pointer chase here for a CNAME record */
938 if ((pos2[0] & 0xC0) == 0xC0)
943 /* Walk the answer(s) to see what to do next */
944 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
946 rr = (dns_rr_t *) pos;
947 switch (clib_net_to_host_u16 (rr->type))
949 /* Real address record? Done.. */
954 * Maybe chase a CNAME pointer?
955 * It's not unheard-of for name-servers to return
956 * both CNAME and A/AAAA records...
962 /* Some other junk, e.g. a nameserver... */
966 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
968 if ((pos2[0] & 0xc0) == 0xc0)
972 /* Neither a CNAME nor a real address. Try another server */
975 flags &= ~DNS_RCODE_MASK;
976 flags |= DNS_RCODE_NAME_ERROR;
977 h->flags = clib_host_to_net_u16 (flags);
981 /* This is a CNAME record, chase the name chain. */
984 /* The last request is no longer pending.. */
985 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
986 if (ep_index == dm->unresolved_entries[i])
988 vec_delete (dm->unresolved_entries, 1, i);
989 goto found_last_request;
991 clib_warning ("pool elt %d supposedly pending, but not found...", ep_index);
996 now = vlib_time_now (vm);
997 cname = vnet_dns_labels_to_name (rr->rdata, reply, &pos2);
999 dns_terminate_c_string (&cname);
1000 ep = pool_elt_at_index (dm->entries, ep_index);
1002 ep->flags |= (DNS_CACHE_ENTRY_FLAG_CNAME | DNS_CACHE_ENTRY_FLAG_VALID);
1003 /* Save the response */
1004 if (ep->dns_response)
1005 vec_free (ep->dns_response);
1006 ep->dns_response = reply;
1007 /* Set up expiration time */
1008 ep->expiration_time = now + clib_net_to_host_u32 (rr->ttl);
1010 pool_get (dm->entries, next_ep);
1012 /* Need to recompute ep post pool-get */
1013 ep = pool_elt_at_index (dm->entries, ep_index);
1015 clib_memset (next_ep, 0, sizeof (*next_ep));
1016 next_ep->name = vec_dup (cname);
1017 dns_terminate_c_string (&next_ep->name);
1019 hash_set_mem (dm->cache_entry_by_name, next_ep->name,
1020 next_ep - dm->entries);
1022 /* Use the same server */
1023 next_ep->server_rotor = ep->server_rotor;
1024 next_ep->server_af = ep->server_af;
1026 /* Move notification data to the next name in the chain */
1027 #define _(a) next_ep->a = ep->a; ep->a = 0;
1028 foreach_notification_to_move;
1031 request = name_to_labels (cname);
1032 name_copy = vec_dup (request);
1034 qp_offset = vec_len (request);
1036 /* Add space for the query header */
1037 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
1039 qp = (dns_query_t *) (request + qp_offset);
1041 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
1042 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1043 clib_memcpy (qp, name_copy, vec_len (name_copy));
1044 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
1045 vec_free (name_copy);
1047 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1048 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1050 /* Punch in space for the dns_header_t */
1051 vec_insert (request, sizeof (dns_header_t), 0);
1053 h = (dns_header_t *) request;
1055 /* Transaction ID = pool index */
1056 h->id = clib_host_to_net_u16 (next_ep - dm->entries);
1058 /* Ask for a recursive lookup */
1059 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
1060 h->qdcount = clib_host_to_net_u16 (2);
1064 next_ep->dns_request = request;
1065 next_ep->retry_timer = now + 2.0;
1066 next_ep->retry_count = 0;
1069 * Enable this to watch recursive resolution happen...
1070 * fformat (stdout, "%U", format_dns_reply, request, 2);
1073 vec_add1 (dm->unresolved_entries, next_ep - dm->entries);
1074 vnet_send_dns_request (vm, dm, next_ep);
1079 vnet_dns_response_to_reply (u8 *response, dns_resolve_name_t *rn,
1087 u8 *curpos, *pos, *pos2;
1091 int pointer_chase, addr_set = 0;
1093 h = (dns_header_t *) response;
1094 flags = clib_net_to_host_u16 (h->flags);
1095 rcode = flags & DNS_RCODE_MASK;
1097 /* See if the response is OK, etc. */
1101 case DNS_RCODE_NO_ERROR:
1104 case DNS_RCODE_NAME_ERROR:
1105 case DNS_RCODE_FORMAT_ERROR:
1106 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1108 case DNS_RCODE_SERVER_FAILURE:
1109 case DNS_RCODE_NOT_IMPLEMENTED:
1110 case DNS_RCODE_REFUSED:
1111 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1114 /* No answers? Loser... */
1115 if (clib_net_to_host_u16 (h->anscount) < 1)
1116 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1118 curpos = (u8 *) (h + 1);
1120 /* Skip the name we asked about */
1123 /* Should never happen, but stil... */
1124 if ((len & 0xC0) == 0xC0)
1128 /* skip the name / label-set */
1137 limit = clib_net_to_host_u16 (h->qdcount);
1138 qp = (dns_query_t *) curpos;
1143 limit = clib_net_to_host_u16 (h->anscount);
1145 for (i = 0; i < limit; i++)
1147 pos = pos2 = curpos;
1150 /* Expect pointer chases in the answer section... */
1151 if ((pos2[0] & 0xC0) == 0xC0)
1154 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1163 if ((pos2[0] & 0xc0) == 0xc0)
1166 * If we've already done one pointer chase,
1167 * do not move the pos pointer.
1169 if (pointer_chase == 0)
1171 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1179 if (pointer_chase == 0)
1182 rr = (dns_rr_t *) pos;
1184 switch (clib_net_to_host_u16 (rr->type))
1187 /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1188 ip_address_set (&rn->address, rr->rdata, AF_IP4);
1189 ttl = clib_net_to_host_u32 (rr->ttl);
1191 if (min_ttlp && *min_ttlp > ttl)
1195 /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1196 ip_address_set (&rn->address, rr->rdata, AF_IP6);
1197 ttl = clib_net_to_host_u32 (rr->ttl);
1198 if (min_ttlp && *min_ttlp > ttl)
1206 /* Might as well stop ASAP */
1209 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1214 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1219 vnet_dns_response_to_name (u8 * response,
1220 vl_api_dns_resolve_ip_reply_t * rmp,
1228 u8 *curpos, *pos, *pos2;
1233 u8 *junk __attribute__ ((unused));
1237 h = (dns_header_t *) response;
1238 flags = clib_net_to_host_u16 (h->flags);
1239 rcode = flags & DNS_RCODE_MASK;
1241 /* See if the response is OK, etc. */
1245 case DNS_RCODE_NO_ERROR:
1248 case DNS_RCODE_NAME_ERROR:
1249 case DNS_RCODE_FORMAT_ERROR:
1250 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1252 case DNS_RCODE_SERVER_FAILURE:
1253 case DNS_RCODE_NOT_IMPLEMENTED:
1254 case DNS_RCODE_REFUSED:
1255 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1258 /* No answers? Loser... */
1259 if (clib_net_to_host_u16 (h->anscount) < 1)
1260 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1262 curpos = (u8 *) (h + 1);
1264 /* Skip the name we asked about */
1267 /* Should never happen, but stil... */
1268 if ((len & 0xC0) == 0xC0)
1272 /* skip the name / label-set */
1281 limit = clib_net_to_host_u16 (h->qdcount);
1282 qp = (dns_query_t *) curpos;
1287 limit = clib_net_to_host_u16 (h->anscount);
1289 for (i = 0; i < limit; i++)
1291 pos = pos2 = curpos;
1294 /* Expect pointer chases in the answer section... */
1295 if ((pos2[0] & 0xC0) == 0xC0)
1298 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1307 if ((pos2[0] & 0xc0) == 0xc0)
1310 * If we've already done one pointer chase,
1311 * do not move the pos pointer.
1313 if (pointer_chase == 0)
1315 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1323 if (pointer_chase == 0)
1326 rr = (dns_rr_t *) pos;
1328 switch (clib_net_to_host_u16 (rr->type))
1331 name = vnet_dns_labels_to_name (rr->rdata, response, &junk);
1332 memcpy (rmp->name, name, vec_len (name));
1333 ttl = clib_net_to_host_u32 (rr->ttl);
1336 rmp->name[vec_len (name)] = 0;
1342 /* Might as well stop ASAP */
1345 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1350 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1355 dns_resolve_name (u8 *name, dns_cache_entry_t **ep, dns_pending_request_t *t0,
1356 dns_resolve_name_t *rn)
1358 dns_main_t *dm = &dns_main;
1359 vlib_main_t *vm = vlib_get_main ();
1361 int rv = vnet_dns_resolve_name (vm, dm, name, t0, ep);
1363 /* Error, e.g. not enabled? Tell the user */
1367 /* Resolution pending? Don't reply... */
1371 return vnet_dns_response_to_reply (ep[0]->dns_response, rn, 0 /* ttl-ptr */);
1375 vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1377 dns_main_t *dm = &dns_main;
1378 vl_api_dns_resolve_name_reply_t *rmp;
1379 dns_cache_entry_t *ep = 0;
1380 dns_pending_request_t _t0 = { 0 }, *t0 = &_t0;
1382 dns_resolve_name_t rn;
1384 /* Sanitize the name slightly */
1385 mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1387 t0->request_type = DNS_API_PENDING_NAME_TO_IP;
1388 t0->client_index = mp->client_index;
1389 t0->client_context = mp->context;
1391 rv = dns_resolve_name (mp->name, &ep, t0, &rn);
1393 /* Error, e.g. not enabled? Tell the user */
1396 REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1400 /* Resolution pending? Don't reply... */
1404 REPLY_MACRO2 (VL_API_DNS_RESOLVE_NAME_REPLY, ({
1405 ip_address_copy_addr (rmp->ip4_address, &rn.address);
1406 if (ip_addr_version (&rn.address) == AF_IP4)
1414 vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
1416 vlib_main_t *vm = vlib_get_main ();
1417 dns_main_t *dm = &dns_main;
1418 vl_api_dns_resolve_ip_reply_t *rmp;
1419 dns_cache_entry_t *ep;
1422 u8 *lookup_name = 0;
1424 dns_pending_request_t _t0 = { 0 }, *t0 = &_t0;
1428 for (i = 15; i >= 0; i--)
1430 digit = mp->address[i];
1431 nybble = (digit & 0x0F);
1433 vec_add1 (lookup_name, (nybble - 10) + 'a');
1435 vec_add1 (lookup_name, nybble + '0');
1436 vec_add1 (lookup_name, '.');
1437 nybble = (digit & 0xF0) >> 4;
1439 vec_add1 (lookup_name, (nybble - 10) + 'a');
1441 vec_add1 (lookup_name, nybble + '0');
1442 vec_add1 (lookup_name, '.');
1444 len = vec_len (lookup_name);
1445 vec_validate (lookup_name, len + 8);
1446 memcpy (lookup_name + len, "ip6.arpa", 8);
1450 for (i = 3; i >= 0; i--)
1452 digit = mp->address[i];
1453 lookup_name = format (lookup_name, "%d.", digit);
1455 lookup_name = format (lookup_name, "in-addr.arpa");
1458 vec_add1 (lookup_name, 0);
1460 t0->request_type = DNS_API_PENDING_IP_TO_NAME;
1461 t0->client_index = mp->client_index;
1462 t0->client_context = mp->context;
1464 rv = vnet_dns_resolve_name (vm, dm, lookup_name, t0, &ep);
1466 vec_free (lookup_name);
1468 /* Error, e.g. not enabled? Tell the user */
1471 REPLY_MACRO (VL_API_DNS_RESOLVE_IP_REPLY);
1475 /* Resolution pending? Don't reply... */
1479 REPLY_MACRO2(VL_API_DNS_RESOLVE_IP_REPLY,
1481 rv = vnet_dns_response_to_name (ep->dns_response, rmp, 0 /* ttl-ptr */);
1482 rmp->retval = clib_host_to_net_u32 (rv);
1486 static clib_error_t *
1487 dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1489 dns_main_t *dm = &dns_main;
1491 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1493 if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1495 else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1498 return clib_error_return (0, "unknown input `%U'",
1499 format_unformat_error, input);
1504 VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1507 unformat_dns_reply (unformat_input_t * input, va_list * args)
1509 u8 **result = va_arg (*args, u8 **);
1510 u8 **namep = va_arg (*args, u8 **);
1524 if (unformat (input, "%v", &name))
1527 if (unformat (input, "%U", unformat_ip4_address, &a4))
1530 if (unformat (input, "%U", unformat_ip6_address, &a6))
1534 if (unformat (input, "%U", unformat_ip6_address, &a6))
1537 if (unformat (input, "%U", unformat_ip4_address, &a6))
1541 /* Must have a name */
1545 /* Must have at least one address */
1546 if (!(a4_set + a6_set))
1549 /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1550 ce = name_to_labels (name);
1551 qp_offset = vec_len (ce);
1553 /* Add space for the query header */
1554 vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1555 qp = (dns_query_t *) (ce + qp_offset);
1557 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1558 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1560 /* Punch in space for the dns_header_t */
1561 vec_insert (ce, sizeof (dns_header_t), 0);
1563 h = (dns_header_t *) ce;
1565 /* Fake Transaction ID */
1568 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1569 h->qdcount = clib_host_to_net_u16 (1);
1570 h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1574 /* Now append one or two A/AAAA RR's... */
1577 /* Pointer to the name (DGMS) */
1578 vec_add1 (ce, 0xC0);
1579 vec_add1 (ce, 0x0C);
1580 vec_add2 (ce, rru8, sizeof (*rr) + 4);
1582 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1583 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1584 rr->ttl = clib_host_to_net_u32 (86400);
1585 rr->rdlength = clib_host_to_net_u16 (4);
1586 memcpy (rr->rdata, &a4, sizeof (a4));
1590 /* Pointer to the name (DGMS) */
1591 vec_add1 (ce, 0xC0);
1592 vec_add1 (ce, 0x0C);
1593 vec_add2 (ce, rru8, sizeof (*rr) + 16);
1595 rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1596 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1597 rr->ttl = clib_host_to_net_u32 (86400);
1598 rr->rdlength = clib_host_to_net_u16 (16);
1599 memcpy (rr->rdata, &a6, sizeof (a6));
1611 format_dns_query (u8 * s, va_list * args)
1613 u8 **curpos = va_arg (*args, u8 **);
1614 int verbose = va_arg (*args, int);
1619 s = format (s, " Name: ");
1621 /* Unwind execrated counted-label sheit */
1627 for (i = 0; i < len; i++)
1628 vec_add1 (s, *pos++);
1640 qp = (dns_query_t *) pos;
1643 switch (clib_net_to_host_u16 (qp->type))
1646 s = format (s, "type A\n");
1649 s = format (s, "type AAAA\n");
1652 s = format (s, "type ALL\n");
1656 s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1661 pos += sizeof (*qp);
1668 * format dns reply data
1669 * verbose > 1, dump everything
1670 * verbose == 1, dump all A and AAAA records
1671 * verbose == 0, dump one A record, and one AAAA record
1675 format_dns_reply_data (u8 * s, va_list * args)
1677 u8 *reply = va_arg (*args, u8 *);
1678 u8 **curpos = va_arg (*args, u8 **);
1679 int verbose = va_arg (*args, int);
1680 int *print_ip4 = va_arg (*args, int *);
1681 int *print_ip6 = va_arg (*args, int *);
1686 int pointer_chase = 0;
1688 u16 rrtype_host_byte_order;
1690 pos = pos2 = *curpos;
1693 s = format (s, " ");
1695 /* chase pointer? almost always yes here... */
1696 if ((pos2[0] & 0xc0) == 0xc0)
1699 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1707 for (i = 0; i < len; i++)
1710 vec_add1 (s, *pos2);
1713 if ((pos2[0] & 0xc0) == 0xc0)
1716 * If we've already done one pointer chase,
1717 * do not move the pos pointer.
1719 if (pointer_chase == 0)
1721 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1739 if (pointer_chase == 0)
1742 rr = (dns_rr_t *) pos;
1743 rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
1745 switch (rrtype_host_byte_order)
1750 s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1751 format_ip4_address, rr->rdata);
1756 s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1757 clib_net_to_host_u32 (rr->ttl));
1762 pos += sizeof (*rr) + 4;
1768 s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1769 format_ip6_address, rr->rdata);
1774 s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1775 clib_net_to_host_u32 (rr->ttl));
1779 pos += sizeof (*rr) + 16;
1785 s = format (s, "TEXT: ");
1786 for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1787 vec_add1 (s, rr->rdata[i]);
1790 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1793 case DNS_TYPE_HINFO:
1795 /* Two counted strings. DGMS */
1801 s = format (s, "HINFO: ");
1804 for (i = 0; i < *len; i++)
1805 vec_add1 (s, *curpos++);
1809 for (i = 0; i < *len; i++)
1810 vec_add1 (s, *curpos++);
1815 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1818 case DNS_TYPE_NAMESERVER:
1821 s = format (s, "Nameserver: ");
1824 /* chase pointer? */
1825 if ((pos2[0] & 0xc0) == 0xc0)
1828 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1835 for (i = 0; i < len; i++)
1836 vec_add1 (s, *pos2++);
1838 /* chase pointer, typically to offset 12... */
1839 if (pos2[0] == 0xC0)
1840 pos2 = reply + pos2[1];
1849 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1852 case DNS_TYPE_MAIL_EXCHANGE:
1855 tp = (u16 *) rr->rdata;
1857 s = format (s, "Mail Exchange: Preference %d ", (u32)
1858 clib_net_to_host_u16 (*tp));
1860 pos2 = rr->rdata + 2;
1862 /* chase pointer? */
1863 if (pos2[0] == 0xc0)
1864 pos2 = reply + pos2[1];
1870 for (i = 0; i < len; i++)
1871 vec_add1 (s, *pos2++);
1874 if (pos2[0] == 0xC0)
1875 pos2 = reply + pos2[1];
1885 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1889 case DNS_TYPE_CNAME:
1892 tp = (u16 *) rr->rdata;
1894 if (rrtype_host_byte_order == DNS_TYPE_CNAME)
1895 s = format (s, "CNAME: ");
1897 s = format (s, "PTR: ");
1901 /* chase pointer? */
1902 if (pos2[0] == 0xc0)
1903 pos2 = reply + pos2[1];
1909 for (i = 0; i < len; i++)
1910 vec_add1 (s, *pos2++);
1913 if (pos2[0] == 0xC0)
1914 pos2 = reply + pos2[1];
1923 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1928 s = format (s, "type %d: len %d\n",
1929 (int) clib_net_to_host_u16 (rr->type),
1930 sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
1931 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1941 format_dns_reply (u8 * s, va_list * args)
1943 u8 *reply_as_u8 = va_arg (*args, u8 *);
1944 int verbose = va_arg (*args, int);
1952 h = (dns_header_t *) reply_as_u8;
1953 id = clib_net_to_host_u16 (h->id);
1954 flags = clib_net_to_host_u16 (h->flags);
1958 s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
1960 s = format (s, " %s %s %s %s\n",
1961 (flags & DNS_RA) ? "recur" : "no-recur",
1962 (flags & DNS_RD) ? "recur-des" : "no-recur-des",
1963 (flags & DNS_TC) ? "trunc" : "no-trunc",
1964 (flags & DNS_AA) ? "auth" : "non-auth");
1965 s = format (s, " %d queries, %d answers, %d name-servers,"
1967 clib_net_to_host_u16 (h->qdcount),
1968 clib_net_to_host_u16 (h->anscount),
1969 clib_net_to_host_u16 (h->nscount),
1970 clib_net_to_host_u16 (h->arcount));
1973 curpos = (u8 *) (h + 1);
1978 s = format (s, " Queries:\n");
1979 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
1981 /* The query is variable-length, so curpos is a value-result parm */
1982 s = format (s, "%U", format_dns_query, &curpos, verbose);
1988 s = format (s, " Replies:\n");
1990 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
1992 /* curpos is a value-result parm */
1993 s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
1994 verbose, &print_ip4, &print_ip6);
2001 format_dns_cache (u8 * s, va_list * args)
2003 dns_main_t *dm = va_arg (*args, dns_main_t *);
2004 f64 now = va_arg (*args, f64);
2005 int verbose = va_arg (*args, int);
2006 u8 *name = va_arg (*args, u8 *);
2007 dns_cache_entry_t *ep;
2011 if (dm->is_enabled == 0)
2013 s = format (s, "The DNS cache is disabled...");
2017 if (pool_elts (dm->entries) == 0)
2019 s = format (s, "The DNS cache is empty...");
2023 dns_cache_lock (dm, 6);
2027 p = hash_get_mem (dm->cache_entry_by_name, name);
2030 s = format (s, "%s is not in the cache...", name);
2031 dns_cache_unlock (dm);
2035 ep = pool_elt_at_index (dm->entries, p[0]);
2036 /* Magic to spit out a C-initializer to research hemorrhoids... */
2040 s = format (s, "static u8 dns_reply_data_initializer[] =\n");
2041 s = format (s, "{\n");
2043 for (i = 0; i < vec_len (ep->dns_response); i++)
2050 s = format (s, "0x%02x, ", ep->dns_response[i]);
2052 s = format (s, "};\n");
2056 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2058 ASSERT (ep->dns_response);
2059 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2064 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2065 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2067 s = format (s, "%s%s -> %U", ss, ep->name,
2068 format_dns_reply, ep->dns_response, verbose);
2069 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2071 f64 time_left = ep->expiration_time - now;
2072 if (time_left > 0.0)
2073 s = format (s, " TTL left %.1f", time_left);
2075 s = format (s, " EXPIRED");
2080 ASSERT (ep->dns_request);
2081 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2089 s = format (s, "DNS cache contains %d entries\n", pool_elts (dm->entries));
2093 pool_foreach (ep, dm->entries)
2095 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2097 ASSERT (ep->dns_response);
2098 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2103 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2104 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2106 s = format (s, "%s%s -> %U", ss, ep->name,
2110 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2112 f64 time_left = ep->expiration_time - now;
2113 if (time_left > 0.0)
2114 s = format (s, " TTL left %.1f", time_left);
2116 s = format (s, " EXPIRED");
2119 s = format (s, " %d client notifications pending\n",
2120 vec_len(ep->pending_requests));
2125 ASSERT (ep->dns_request);
2126 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2133 dns_cache_unlock (dm);
2138 static clib_error_t *
2139 show_dns_cache_command_fn (vlib_main_t * vm,
2140 unformat_input_t * input, vlib_cli_command_t * cmd)
2142 dns_main_t *dm = &dns_main;
2145 f64 now = vlib_time_now (vm);
2147 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2149 if (unformat (input, "verbose %d", &verbose))
2151 else if (unformat (input, "verbose"))
2153 else if (unformat (input, "name %s", &name))
2156 return clib_error_return (0, "unknown input `%U'",
2157 format_unformat_error, input);
2160 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,
2172 static clib_error_t *
2173 show_dns_servers_command_fn (vlib_main_t * vm,
2174 unformat_input_t * input,
2175 vlib_cli_command_t * cmd)
2177 dns_main_t *dm = &dns_main;
2180 if ((vec_len (dm->ip4_name_servers) + vec_len (dm->ip6_name_servers)) == 0)
2181 return clib_error_return (0, "No name servers configured...");
2183 if (vec_len (dm->ip4_name_servers))
2185 vlib_cli_output (vm, "ip4 name servers:");
2186 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
2187 vlib_cli_output (vm, "%U", format_ip4_address,
2188 dm->ip4_name_servers + i);
2190 if (vec_len (dm->ip6_name_servers))
2192 vlib_cli_output (vm, "ip6 name servers:");
2193 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
2194 vlib_cli_output (vm, "%U", format_ip6_address,
2195 dm->ip4_name_servers + i);
2200 VLIB_CLI_COMMAND (show_dns_server_command) =
2202 .path = "show dns servers",
2203 .short_help = "show dns servers",
2204 .function = show_dns_servers_command_fn,
2208 static clib_error_t *
2209 dns_cache_add_del_command_fn (vlib_main_t * vm,
2210 unformat_input_t * input,
2211 vlib_cli_command_t * cmd)
2213 dns_main_t *dm = &dns_main;
2219 clib_error_t *error;
2221 if (unformat (input, "add"))
2223 if (unformat (input, "del"))
2225 if (unformat (input, "clear"))
2228 if (is_add == -1 && is_clear == -1)
2229 return clib_error_return (0, "add / del / clear required...");
2233 rv = dns_cache_clear (dm);
2239 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2240 error = clib_error_return (0, "Name resolution not enabled");
2245 /* Delete (by name)? */
2248 if (unformat (input, "%v", &name))
2250 rv = dns_delete_by_name (dm, name);
2253 case VNET_API_ERROR_NO_SUCH_ENTRY:
2254 error = clib_error_return (0, "%v not in the cache...", name);
2258 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2259 error = clib_error_return (0, "Name resolution not enabled");
2268 error = clib_error_return (0, "dns_delete_by_name returned %d",
2274 return clib_error_return (0, "unknown input `%U'",
2275 format_unformat_error, input);
2278 /* Note: dns_add_static_entry consumes the name vector if OK... */
2279 if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2281 rv = dns_add_static_entry (dm, name, dns_reply_data);
2284 case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2286 vec_free (dns_reply_data);
2287 return clib_error_return (0, "%v already in the cache...", name);
2292 return clib_error_return (0, "dns_add_static_entry returned %d",
2300 VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2302 .path = "dns cache",
2303 .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2304 .function = dns_cache_add_del_command_fn,
2307 #define DNS_FORMAT_TEST 1
2309 #if DNS_FORMAT_TEST > 0
2312 static u8 dns_reply_data_initializer[] =
2313 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2314 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2316 0x0, 0xff, /* type ALL */
2317 0x0, 0x1, /* class IN */
2318 0xc0, 0xc, /* pointer to yahoo.com name */
2319 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2320 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2321 0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2322 0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2323 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2324 0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2325 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2326 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2327 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2328 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2329 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2330 0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2331 0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2333 0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2334 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2335 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2336 0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2337 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2339 0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2340 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2341 0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2342 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2344 0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2345 0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2347 0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2349 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2351 0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2353 0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2354 0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2355 0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2359 /* www.cisco.com, has no addresses in reply */
2360 static u8 dns_reply_data_initializer[] = {
2361 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2362 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2363 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2365 0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2366 0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2367 0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2368 0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2369 0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2372 /* bind8 (linux widget, w/ nasty double pointer chasees */
2373 static u8 dns_reply_data_initializer[] = {
2375 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08,
2377 0x00, 0x06, 0x00, 0x06, 0x0a, 0x6f, 0x72, 0x69,
2379 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77, 0x77, 0x05,
2381 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f,
2383 0x6d, 0x00, 0x00, 0xff, 0x00, 0x01, 0x0a, 0x6f,
2385 0x72, 0x69, 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77,
2387 0x77, 0x05, 0x43, 0x49, 0x53, 0x43, 0x4f, 0xc0,
2390 0x1d, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2393 0x9a, 0x00, 0x18, 0x15, 0x72, 0x63, 0x64,
2394 0x6e, 0x39, 0x2d, 0x31, 0x34, 0x70, 0x2d, 0x64, 0x63,
2395 0x7a, 0x30, 0x35, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31,
2396 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00, 0x01, 0x00,
2397 0x00, 0x05, 0x9a, 0x00, 0x1a, 0x17, 0x61, 0x6c, 0x6c,
2398 0x6e, 0x30, 0x31, 0x2d, 0x61, 0x67, 0x30, 0x39, 0x2d,
2399 0x64, 0x63, 0x7a, 0x30, 0x33, 0x6e, 0x2d, 0x67, 0x73,
2400 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00,
2401 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x10, 0x0d, 0x72,
2402 0x74, 0x70, 0x35, 0x2d, 0x64, 0x6d, 0x7a, 0x2d, 0x67,
2403 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2404 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x18, 0x15,
2405 0x6d, 0x74, 0x76, 0x35, 0x2d, 0x61, 0x70, 0x31, 0x30,
2406 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x36, 0x6e, 0x2d, 0x67,
2407 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2408 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x1b, 0x18,
2409 0x73, 0x6e, 0x67, 0x64, 0x63, 0x30, 0x31, 0x2d, 0x61,
2410 0x62, 0x30, 0x37, 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x31,
2411 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0,
2412 0x26, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a,
2413 0x00, 0x1a, 0x17, 0x61, 0x65, 0x72, 0x30, 0x31, 0x2d,
2414 0x72, 0x34, 0x63, 0x32, 0x35, 0x2d, 0x64, 0x63, 0x7a,
2415 0x30, 0x31, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0,
2416 0x17, 0xc0, 0x26, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2417 0x00, 0x81, 0x00, 0x04, 0x48, 0xa3, 0x04, 0xa1, 0xc0,
2418 0x26, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82,
2419 0x00, 0x10, 0x20, 0x01, 0x04, 0x20, 0x12, 0x01, 0x00,
2420 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
2421 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2422 0x9a, 0x00, 0x02, 0xc0, 0xf4, 0xc0, 0x0c, 0x00, 0x02,
2423 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0,
2424 0xcd, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00,
2425 0x05, 0x9a, 0x00, 0x02, 0xc0, 0x8d, 0xc0, 0x0c, 0x00,
2426 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02,
2427 0xc0, 0x43, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00,
2428 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0, 0xa9, 0xc0, 0x0c,
2429 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00,
2430 0x02, 0xc0, 0x67, 0xc0, 0x8d, 0x00, 0x01, 0x00, 0x01,
2431 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0x40, 0x66, 0xf6,
2432 0x05, 0xc0, 0xa9, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2433 0x07, 0x08, 0x00, 0x04, 0xad, 0x24, 0xe0, 0x64, 0xc0,
2434 0x43, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08,
2435 0x00, 0x04, 0x48, 0xa3, 0x04, 0x1c, 0xc0, 0xf4, 0x00,
2436 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04,
2437 0xad, 0x26, 0xd4, 0x6c, 0xc0, 0x67, 0x00, 0x01, 0x00,
2438 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x25,
2439 0x90, 0x64, 0xc0, 0xcd, 0x00, 0x01, 0x00, 0x01, 0x00,
2440 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x27, 0x70, 0x44,
2444 static u8 dns_reply_data_initializer[] =
2445 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
2446 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
2447 0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
2448 0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
2450 0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
2451 0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
2452 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
2453 0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
2454 0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
2455 0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
2456 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
2457 0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
2458 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
2459 0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
2460 0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
2461 0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
2462 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
2463 0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
2464 0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
2465 0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
2466 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2467 0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
2468 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
2469 0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
2470 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
2471 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
2472 0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
2474 0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2478 /* www.weatherlink.com */
2479 static u8 dns_reply_data_initializer[] = {
2480 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2481 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x0b,
2482 0x77, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x6c, 0x69,
2483 0x6e, 0x6b, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0xff,
2484 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00,
2485 0x00, 0x0c, 0x9e, 0x00, 0x1f, 0x0e, 0x64, 0x33, 0x6b,
2486 0x72, 0x30, 0x67, 0x75, 0x62, 0x61, 0x31, 0x64, 0x76,
2487 0x77, 0x66, 0x0a, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x66,
2488 0x72, 0x6f, 0x6e, 0x74, 0x03, 0x6e, 0x65, 0x74, 0x00,
2493 static clib_error_t *
2494 test_dns_fmt_command_fn (vlib_main_t * vm,
2495 unformat_input_t * input, vlib_cli_command_t * cmd)
2497 dns_resolve_name_t _rn, *rn = &_rn;
2498 u8 *dns_reply_data = 0;
2501 vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2503 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2505 if (unformat (input, "verbose %d", &verbose))
2507 else if (unformat (input, "verbose"))
2510 return clib_error_return (0, "unknown input `%U'",
2511 format_unformat_error, input);
2514 vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2516 memcpy (dns_reply_data, dns_reply_data_initializer,
2517 ARRAY_LEN (dns_reply_data_initializer));
2519 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2521 clib_memset (rmp, 0, sizeof (*rmp));
2523 rv = vnet_dns_response_to_reply (dns_reply_data, rn, 0 /* ttl-ptr */);
2527 case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2528 vlib_cli_output (vm, "no addresses found...");
2532 vlib_cli_output (vm, "response to reply returned %d", rv);
2536 vlib_cli_output (vm, "ip address: %U", format_ip_address, &rn->address);
2540 vec_free (dns_reply_data);
2546 VLIB_CLI_COMMAND (test_dns_fmt_command) =
2548 .path = "test dns format",
2549 .short_help = "test dns format",
2550 .function = test_dns_fmt_command_fn,
2553 static clib_error_t *
2554 test_dns_unfmt_command_fn (vlib_main_t * vm,
2555 unformat_input_t * input, vlib_cli_command_t * cmd)
2557 u8 *dns_reply_data = 0;
2561 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2563 if (unformat (input, "verbose %d", &verbose))
2565 else if (unformat (input, "verbose"))
2567 else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2570 return clib_error_return (0, "unknown input `%U'",
2571 format_unformat_error, input);
2575 return clib_error_return (0, "dns data not set...");
2577 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2579 vec_free (dns_reply_data);
2584 VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2586 .path = "test dns unformat",
2587 .short_help = "test dns unformat <name> [ip4][ip6]",
2588 .function = test_dns_unfmt_command_fn,
2591 static clib_error_t *
2592 test_dns_expire_command_fn (vlib_main_t * vm,
2593 unformat_input_t * input,
2594 vlib_cli_command_t * cmd)
2596 dns_main_t *dm = &dns_main;
2600 dns_cache_entry_t *ep;
2602 if (unformat (input, "%v", &name))
2603 dns_terminate_c_string (&name);
2605 return clib_error_return (0, "no name provided");
2607 dns_cache_lock (dm, 7);
2609 p = hash_get_mem (dm->cache_entry_by_name, name);
2612 dns_cache_unlock (dm);
2613 e = clib_error_return (0, "%s is not in the cache...", name);
2618 ep = pool_elt_at_index (dm->entries, p[0]);
2620 ep->expiration_time = 0;
2625 VLIB_CLI_COMMAND (test_dns_expire_command) =
2627 .path = "test dns expire",
2628 .short_help = "test dns expire <name>",
2629 .function = test_dns_expire_command_fn,
2634 vnet_send_dns6_reply (vlib_main_t * vm, dns_main_t * dm,
2635 dns_pending_request_t * pr, dns_cache_entry_t * ep,
2638 clib_warning ("Unimplemented...");
2643 vnet_send_dns4_reply (vlib_main_t * vm, dns_main_t * dm,
2644 dns_pending_request_t * pr, dns_cache_entry_t * ep,
2648 ip4_address_t src_address;
2656 /* vl_api_dns_resolve_name_reply_t _rnr, *rnr = &_rnr; */
2657 dns_resolve_name_t _rn, *rn = &_rn;
2658 vl_api_dns_resolve_ip_reply_t _rir, *rir = &_rir;
2665 int is_recycle = (b0 != 0);
2667 ASSERT (ep && ep->dns_response);
2669 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2671 /* Quick and dirty way to dig up the A-record address. $$ FIXME */
2672 clib_memset (rn, 0, sizeof (*rn));
2673 if (vnet_dns_response_to_reply (ep->dns_response, rn, &ttl))
2675 /* clib_warning ("response_to_reply failed..."); */
2678 else if (ip_addr_version (&rn->address) != AF_IP4)
2680 /* clib_warning ("No A-record..."); */
2684 else if (pr->request_type == DNS_PEER_PENDING_IP_TO_NAME)
2686 clib_memset (rir, 0, sizeof (*rir));
2687 if (vnet_dns_response_to_name (ep->dns_response, rir, &ttl))
2689 /* clib_warning ("response_to_name failed..."); */
2695 clib_warning ("Unknown request type %d", pr->request_type);
2699 /* Initialize a buffer */
2702 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2704 b0 = vlib_get_buffer (vm, bi);
2708 /* Use the buffer we were handed. Reinitialize it... */
2709 vlib_buffer_t bt = { };
2710 /* push/pop the reference count */
2711 u8 save_ref_count = b0->ref_count;
2712 vlib_buffer_copy_template (b0, &bt);
2713 b0->ref_count = save_ref_count;
2714 bi = vlib_get_buffer_index (vm, b0);
2717 if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
2718 vlib_buffer_free_one (vm, b0->next_buffer);
2721 * Reset the buffer. We recycle the DNS request packet in the cache
2722 * hit case, and reply immediately from the request node.
2724 * In the resolution-required / deferred case, resetting a freshly-allocated
2725 * buffer won't hurt. We hope.
2727 b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
2728 | VLIB_BUFFER_TOTAL_LENGTH_VALID);
2729 vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; /* "local0" */
2730 vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
2732 if (!ip4_sas (0 /* default VRF for now */, ~0,
2733 (const ip4_address_t *) &pr->dst_address, &src_address))
2736 ip = vlib_buffer_get_current (b0);
2737 udp = (udp_header_t *) (ip + 1);
2738 dns_response = (u8 *) (udp + 1);
2739 clib_memset (ip, 0, sizeof (*ip) + sizeof (*udp));
2742 * Start with the variadic portion of the exercise.
2743 * Turn the name into a set of DNS "labels". Max length
2744 * per label is 63, enforce that.
2746 reply = name_to_labels (pr->name);
2747 vec_free (pr->name);
2749 qp_offset = vec_len (reply);
2751 /* Add space for the query header */
2752 vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
2754 qp = (dns_query_t *) (reply + qp_offset);
2756 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2757 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
2759 qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2761 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
2763 /* Punch in space for the dns_header_t */
2764 vec_insert (reply, sizeof (dns_header_t), 0);
2766 dh = (dns_header_t *) reply;
2768 /* Transaction ID = pool index */
2771 /* Announce that we did a recursive lookup */
2772 tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
2774 tmp |= DNS_RCODE_NAME_ERROR;
2775 dh->flags = clib_host_to_net_u16 (tmp);
2776 dh->qdcount = clib_host_to_net_u16 (1);
2777 dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
2781 /* If the name resolution worked, cough up an appropriate RR */
2784 /* Add the answer. First, a name pointer (0xC00C) */
2785 vec_add1 (reply, 0xC0);
2786 vec_add1 (reply, 0x0C);
2788 /* Now, add single A-rec RR */
2789 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2791 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
2792 rr = (dns_rr_t *) rrptr;
2794 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
2795 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2796 rr->ttl = clib_host_to_net_u32 (ttl);
2797 rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
2798 ip_address_copy_addr (rr->rdata, &rn->address);
2802 /* Or a single PTR RR */
2803 u8 *vecname = format (0, "%s", rir->name);
2804 u8 *label_vec = name_to_labels (vecname);
2807 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
2808 rr = (dns_rr_t *) rrptr;
2809 rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2810 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2811 rr->ttl = clib_host_to_net_u32 (ttl);
2812 rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
2813 clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
2814 vec_free (label_vec);
2817 clib_memcpy (dns_response, reply, vec_len (reply));
2819 /* Set the packet length */
2820 b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
2823 ip->ip_version_and_header_length = 0x45;
2824 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
2826 ip->protocol = IP_PROTOCOL_UDP;
2827 ip->src_address.as_u32 = src_address.as_u32;
2828 clib_memcpy (ip->dst_address.as_u8, pr->dst_address,
2829 sizeof (ip4_address_t));
2830 ip->checksum = ip4_header_checksum (ip);
2833 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
2834 udp->dst_port = pr->dst_port;
2835 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
2841 * Ship pkts made out of whole cloth to ip4_lookup
2842 * Caller will ship recycled dns reply packets to ip4_lookup
2844 if (is_recycle == 0)
2846 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
2847 to_next = vlib_frame_vector_args (f);
2850 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
2854 #include <dns/dns.api.c>
2855 static clib_error_t *
2856 dns_init (vlib_main_t * vm)
2858 dns_main_t *dm = &dns_main;
2860 dm->vnet_main = vnet_get_main ();
2861 dm->name_cache_size = 1000;
2862 dm->max_ttl_in_seconds = 86400;
2863 dm->random_seed = 0xDEADDABE;
2864 dm->api_main = vlibapi_get_main ();
2866 /* Ask for a correctly-sized block of API message decode slots */
2867 dm->msg_id_base = setup_message_id_table ();
2872 VLIB_INIT_FUNCTION (dns_init) = {
2873 .init_order = VLIB_INITS ("flow_classify_init", "dns_init"),
2876 VLIB_PLUGIN_REGISTER () =
2878 .version = VPP_BUILD_VER,
2879 .description = "Simple DNS name resolver",
2884 * fd.io coding-style-patch-verification: ON
2887 * eval: (c-set-style "gnu")