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);
65 pool_foreach (ep, dm->entries)
68 vec_free (ep->pending_requests);
72 pool_free (dm->entries);
73 hash_free (dm->cache_entry_by_name);
74 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
75 vec_free (dm->unresolved_entries);
76 dns_cache_unlock (dm);
81 dns_enable_disable (vlib_main_t * vm, dns_main_t * dm, int is_enable)
83 vlib_thread_main_t *tm = &vlib_thread_main;
84 u32 n_vlib_mains = tm->n_vlib_mains;
86 /* Create the resolver process if not done already */
87 vnet_dns_create_resolver_process (vm, dm);
91 if (vec_len (dm->ip4_name_servers) == 0
92 && (vec_len (dm->ip6_name_servers) == 0))
93 return VNET_API_ERROR_NO_NAME_SERVERS;
95 if (dm->udp_ports_registered == 0)
97 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply,
98 dns46_reply_node.index, 1 /* is_ip4 */ );
100 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply6,
101 dns46_reply_node.index, 0 /* is_ip4 */ );
103 udp_register_dst_port (vm, UDP_DST_PORT_dns,
104 dns4_request_node.index, 1 /* is_ip4 */ );
106 udp_register_dst_port (vm, UDP_DST_PORT_dns6,
107 dns6_request_node.index, 0 /* is_ip4 */ );
109 dm->udp_ports_registered = 1;
112 if (dm->cache_entry_by_name == 0)
114 if (n_vlib_mains > 1)
115 clib_spinlock_init (&dm->cache_lock);
117 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
124 dns_cache_clear (dm);
130 static void vl_api_dns_enable_disable_t_handler
131 (vl_api_dns_enable_disable_t * mp)
133 vl_api_dns_enable_disable_reply_t *rmp;
134 vlib_main_t *vm = vlib_get_main ();
135 dns_main_t *dm = &dns_main;
138 rv = dns_enable_disable (vm, dm, mp->enable);
140 REPLY_MACRO (VL_API_DNS_ENABLE_DISABLE_REPLY);
144 dns6_name_server_add_del (dns_main_t * dm,
145 u8 * server_address_as_u8, int is_add)
152 /* Already there? done... */
153 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
155 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
156 sizeof (ip6_address_t)))
160 vec_add2 (dm->ip6_name_servers, ap, 1);
161 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
165 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
167 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
168 sizeof (ip6_address_t)))
170 vec_delete (dm->ip6_name_servers, 1, i);
174 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
180 dns4_name_server_add_del (dns_main_t * dm,
181 u8 * server_address_as_u8, int is_add)
188 /* Already there? done... */
189 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
191 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
192 sizeof (ip4_address_t)))
196 vec_add2 (dm->ip4_name_servers, ap, 1);
197 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
201 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
203 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
204 sizeof (ip4_address_t)))
206 vec_delete (dm->ip4_name_servers, 1, i);
210 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
215 static void vl_api_dns_name_server_add_del_t_handler
216 (vl_api_dns_name_server_add_del_t * mp)
218 dns_main_t *dm = &dns_main;
219 vl_api_dns_name_server_add_del_reply_t *rmp;
223 rv = dns6_name_server_add_del (dm, mp->server_address, mp->is_add);
225 rv = dns4_name_server_add_del (dm, mp->server_address, mp->is_add);
227 REPLY_MACRO (VL_API_DNS_NAME_SERVER_ADD_DEL_REPLY);
231 vnet_dns_send_dns4_request (vlib_main_t * vm, dns_main_t * dm,
232 dns_cache_entry_t * ep, ip4_address_t * server)
234 f64 now = vlib_time_now (vm);
239 ip4_address_t src_address;
244 ASSERT (ep->dns_request);
246 if (!ip4_sas (0 /* default VRF for now */, ~0, server, &src_address))
249 /* Go get a buffer */
250 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
253 b = vlib_get_buffer (vm, bi);
254 b->current_length = sizeof (ip4_header_t) + sizeof (udp_header_t) +
255 vec_len (ep->dns_request);
256 b->total_length_not_including_first_buffer = 0;
258 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
259 vnet_buffer (b)->sw_if_index[VLIB_RX] = 0; /* "local0" */
260 vnet_buffer (b)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
262 ip = vlib_buffer_get_current (b);
263 clib_memset (ip, 0, sizeof (*ip));
264 udp = (udp_header_t *) (ip + 1);
265 clib_memset (udp, 0, sizeof (*udp));
267 dns_request = (u8 *) (udp + 1);
270 ip->ip_version_and_header_length = 0x45;
271 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b));
273 ip->protocol = IP_PROTOCOL_UDP;
274 ip->src_address.as_u32 = src_address.as_u32;
275 ip->dst_address.as_u32 = server->as_u32;
276 ip->checksum = ip4_header_checksum (ip);
279 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
280 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
281 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
282 vec_len (ep->dns_request));
285 /* The actual DNS request */
286 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
288 /* Ship it to ip4_lookup */
289 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
290 to_next = vlib_frame_vector_args (f);
293 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
295 ep->retry_timer = now + 2.0;
299 vnet_dns_send_dns6_request (vlib_main_t * vm, dns_main_t * dm,
300 dns_cache_entry_t * ep, ip6_address_t * server)
302 f64 now = vlib_time_now (vm);
307 ip6_address_t src_address;
311 int junk __attribute__ ((unused));
313 ASSERT (ep->dns_request);
315 if (!ip6_sas (0 /* default VRF for now */, ~0, server, &src_address))
318 /* Go get a buffer */
319 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
322 b = vlib_get_buffer (vm, bi);
323 b->current_length = sizeof (ip6_header_t) + sizeof (udp_header_t) +
324 vec_len (ep->dns_request);
325 b->total_length_not_including_first_buffer = 0;
327 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
329 ip = vlib_buffer_get_current (b);
330 clib_memset (ip, 0, sizeof (*ip));
331 udp = (udp_header_t *) (ip + 1);
332 clib_memset (udp, 0, sizeof (*udp));
334 dns_request = (u8 *) (udp + 1);
337 ip->ip_version_traffic_class_and_flow_label =
338 clib_host_to_net_u32 (0x6 << 28);
341 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b)
342 - sizeof (ip6_header_t));
344 ip->protocol = IP_PROTOCOL_UDP;
345 ip6_address_copy (&ip->src_address, &src_address);
346 clib_memcpy (&ip->dst_address, server, sizeof (ip6_address_t));
349 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
350 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
351 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
352 vec_len (ep->dns_request));
354 udp->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ip, &junk);
356 /* The actual DNS request */
357 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
359 /* Ship it to ip6_lookup */
360 f = vlib_get_frame_to_node (vm, ip6_lookup_node.index);
361 to_next = vlib_frame_vector_args (f);
365 ep->retry_timer = now + 2.0;
369 * Translate "foo.com" into "0x3 f o o 0x3 c o m 0x0"
370 * A historical / hysterical micro-TLV scheme. DGMS.
373 name_to_labels (u8 * name)
376 int last_label_index;
381 /* punch in space for the first length */
382 vec_insert (rv, 1, 0);
383 last_label_index = 0;
386 while (i < vec_len (rv))
390 rv[last_label_index] = (i - last_label_index) - 1;
391 if ((i - last_label_index) > 63)
392 clib_warning ("stupid name, label length %d",
393 i - last_label_index);
394 last_label_index = i;
399 /* Set the last real label length */
400 rv[last_label_index] = (i - last_label_index) - 1;
403 * Add a [sic] NULL root label. Otherwise, the name parser can't figure out
411 * arc-function for the above.
412 * Translate "0x3 f o o 0x3 c o m 0x0" into "foo.com"
413 * Produces a non-NULL-terminated u8 *vector. %v format is your friend.
416 vnet_dns_labels_to_name (u8 * label, u8 * full_text, u8 ** parse_from_here)
423 *parse_from_here = 0;
425 /* chase initial pointer? */
426 if ((label[0] & 0xC0) == 0xC0)
428 *parse_from_here = label + 2;
429 offset = ((label[0] & 0x3f) << 8) + label[1];
430 label = full_text + offset;
437 for (i = 0; i < len; i++)
438 vec_add1 (reply, *label++);
441 if ((label[0] & 0xC0) == 0xC0)
443 *parse_from_here = label + 2;
444 offset = ((label[0] & 0x3f) << 8) + label[1];
445 label = full_text + offset;
450 vec_add1 (reply, '.');
452 if (*parse_from_here == 0)
453 *parse_from_here = label;
458 vnet_send_dns_request (vlib_main_t * vm, dns_main_t * dm,
459 dns_cache_entry_t * ep)
464 u8 *request, *name_copy;
467 /* This can easily happen if sitting in GDB, etc. */
468 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID || ep->server_fails > 1)
471 /* Construct the dns request, if we haven't been here already */
472 if (vec_len (ep->dns_request) == 0)
475 * Start with the variadic portion of the exercise.
476 * Turn the name into a set of DNS "labels". Max length
477 * per label is 63, enforce that.
479 request = name_to_labels (ep->name);
480 name_copy = vec_dup (request);
481 qp_offset = vec_len (request);
484 * At least when testing against "known good" DNS servers:
485 * it turns out that sending 2x requests - one for an A-record
486 * and another for a AAAA-record - seems to work better than
487 * sending a DNS_TYPE_ALL request.
490 /* Add space for the query header */
491 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
493 qp = (dns_query_t *) (request + qp_offset);
495 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
496 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
498 clib_memcpy (qp, name_copy, vec_len (name_copy));
499 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
500 vec_free (name_copy);
502 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
503 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
505 /* Punch in space for the dns_header_t */
506 vec_insert (request, sizeof (dns_header_t), 0);
508 h = (dns_header_t *) request;
510 /* Transaction ID = pool index */
511 h->id = clib_host_to_net_u16 (ep - dm->entries);
513 /* Ask for a recursive lookup */
514 tmp = DNS_RD | DNS_OPCODE_QUERY;
515 h->flags = clib_host_to_net_u16 (tmp);
516 h->qdcount = clib_host_to_net_u16 (2);
520 ep->dns_request = request;
523 /* Work out which server / address family we're going to use */
525 /* Retry using current server */
526 if (ep->retry_count++ < DNS_RETRIES_PER_SERVER)
528 if (ep->server_af == 1 /* ip6 */ )
530 if (vec_len (dm->ip6_name_servers))
532 vnet_dns_send_dns6_request
533 (vm, dm, ep, dm->ip6_name_servers + ep->server_rotor);
539 if (vec_len (dm->ip4_name_servers))
541 vnet_dns_send_dns4_request
542 (vm, dm, ep, dm->ip4_name_servers + ep->server_rotor);
546 else /* switch to a new server */
550 if (ep->server_af == 1 /* ip6 */ )
552 if (ep->server_rotor >= vec_len (dm->ip6_name_servers))
554 ep->server_rotor = 0;
555 ep->server_af = vec_len (dm->ip4_name_servers) > 0 ? 0 : 1;
560 if (ep->server_rotor >= vec_len (dm->ip4_name_servers))
562 ep->server_rotor = 0;
563 ep->server_af = vec_len (dm->ip6_name_servers) > 0 ? 1 : 0;
568 if (ep->server_af == 1 /* ip6 */ )
569 vnet_dns_send_dns6_request
570 (vm, dm, ep, dm->ip6_name_servers + ep->server_rotor);
572 vnet_dns_send_dns4_request
573 (vm, dm, ep, dm->ip4_name_servers + ep->server_rotor);
577 vlib_process_signal_event_mt (vm,
578 dm->resolver_process_node_index,
579 DNS_RESOLVER_EVENT_PENDING, 0);
583 vnet_dns_delete_entry_by_index_nolock (dns_main_t * dm, u32 index)
585 dns_cache_entry_t *ep;
588 if (dm->is_enabled == 0)
589 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
591 if (pool_is_free_index (dm->entries, index))
592 return VNET_API_ERROR_NO_SUCH_ENTRY;
594 ep = pool_elt_at_index (dm->entries, index);
595 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_VALID))
597 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
598 if (index == dm->unresolved_entries[i])
600 vec_delete (dm->unresolved_entries, 1, i);
603 clib_warning ("pool elt %d supposedly pending, but not found...",
608 hash_unset_mem (dm->cache_entry_by_name, ep->name);
610 vec_free (ep->pending_requests);
611 pool_put (dm->entries, ep);
617 dns_delete_by_name (dns_main_t * dm, u8 * name)
622 if (dm->is_enabled == 0)
623 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
625 dns_cache_lock (dm, 2);
626 p = hash_get_mem (dm->cache_entry_by_name, name);
629 dns_cache_unlock (dm);
630 return VNET_API_ERROR_NO_SUCH_ENTRY;
632 rv = vnet_dns_delete_entry_by_index_nolock (dm, p[0]);
634 dns_cache_unlock (dm);
640 delete_random_entry (dns_main_t * dm)
643 u32 victim_index, start_index, i;
645 dns_cache_entry_t *ep;
647 if (dm->is_enabled == 0)
648 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
651 * Silence spurious coverity warning. We know pool_elts >> 0, or
652 * we wouldn't be here...
655 if (pool_elts (dm->entries) == 0)
656 return VNET_API_ERROR_UNSPECIFIED;
659 dns_cache_lock (dm, 3);
660 limit = pool_elts (dm->entries);
661 start_index = random_u32 (&dm->random_seed) % limit;
663 for (i = 0; i < limit; i++)
665 victim_index = (start_index + i) % limit;
667 if (!pool_is_free_index (dm->entries, victim_index))
669 ep = pool_elt_at_index (dm->entries, victim_index);
670 /* Delete only valid, non-static entries */
671 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
672 && ((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0))
674 rv = vnet_dns_delete_entry_by_index_nolock (dm, victim_index);
675 dns_cache_unlock (dm);
680 dns_cache_unlock (dm);
682 clib_warning ("Couldn't find an entry to delete?");
683 return VNET_API_ERROR_UNSPECIFIED;
687 dns_add_static_entry (dns_main_t * dm, u8 * name, u8 * dns_reply_data)
689 dns_cache_entry_t *ep;
693 if (dm->is_enabled == 0)
694 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
696 dns_cache_lock (dm, 4);
697 p = hash_get_mem (dm->cache_entry_by_name, name);
700 dns_cache_unlock (dm);
701 return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
704 if (pool_elts (dm->entries) == dm->name_cache_size)
706 /* Will only fail if the cache is totally filled w/ static entries... */
707 rv = delete_random_entry (dm);
710 dns_cache_unlock (dm);
715 pool_get (dm->entries, ep);
716 clib_memset (ep, 0, sizeof (*ep));
718 /* Note: consumes the name vector */
720 /* make sure it NULL-terminated as hash_set_mem will use strlen() */
721 vec_terminate_c_string (ep->name);
722 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
723 ep->flags = DNS_CACHE_ENTRY_FLAG_VALID | DNS_CACHE_ENTRY_FLAG_STATIC;
724 ep->dns_response = dns_reply_data;
726 dns_cache_unlock (dm);
731 vnet_dns_resolve_name (vlib_main_t * vm, dns_main_t * dm, u8 * name,
732 dns_pending_request_t * t, dns_cache_entry_t ** retp)
734 dns_cache_entry_t *ep;
738 dns_pending_request_t *pr;
741 now = vlib_time_now (vm);
743 /* In case we can't actually answer the question right now... */
746 /* binary API caller might forget to set the name. Guess how we know. */
748 return VNET_API_ERROR_INVALID_VALUE;
750 dns_cache_lock (dm, 5);
752 p = hash_get_mem (dm->cache_entry_by_name, name);
755 ep = pool_elt_at_index (dm->entries, p[0]);
756 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
758 /* Has the entry expired? */
759 if (((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0)
760 && (now > ep->expiration_time))
763 u32 *indices_to_delete = 0;
766 * Take out the rest of the resolution chain
767 * This isn't optimal, but it won't happen very often.
771 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME))
773 vec_add1 (indices_to_delete, ep - dm->entries);
775 p = hash_get_mem (dm->cache_entry_by_name, ep->cname);
778 ep = pool_elt_at_index (dm->entries, p[0]);
782 vec_add1 (indices_to_delete, ep - dm->entries);
786 for (i = 0; i < vec_len (indices_to_delete); i++)
788 /* Reenable to watch re-resolutions */
791 ep = pool_elt_at_index (dm->entries,
792 indices_to_delete[i]);
793 clib_warning ("Re-resolve %s", ep->name);
796 vnet_dns_delete_entry_by_index_nolock
797 (dm, indices_to_delete[i]);
799 vec_free (indices_to_delete);
800 /* Yes, kill it... */
804 if (ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
810 dns_cache_unlock (dm);
816 * Resolution pending. Add request to the pending vector
817 * by copying the template request
819 vec_add2 (ep->pending_requests, pr, 1);
820 memcpy (pr, t, sizeof (*pr));
821 dns_cache_unlock (dm);
827 if (pool_elts (dm->entries) == dm->name_cache_size)
829 /* Will only fail if the cache is totally filled w/ static entries... */
830 rv = delete_random_entry (dm);
833 dns_cache_unlock (dm);
838 /* add new hash table entry */
839 pool_get (dm->entries, ep);
840 clib_memset (ep, 0, sizeof (*ep));
842 ep->name = format (0, "%s", name);
843 dns_terminate_c_string (&ep->name);
845 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
847 vec_add1 (dm->unresolved_entries, ep - dm->entries);
848 vec_add2 (ep->pending_requests, pr, 1);
850 pr->request_type = t->request_type;
852 /* Remember details so we can reply later... */
853 if (t->request_type == DNS_API_PENDING_NAME_TO_IP ||
854 t->request_type == DNS_API_PENDING_IP_TO_NAME)
856 pr->client_index = t->client_index;
857 pr->client_context = t->client_context;
861 pr->client_index = ~0;
862 pr->is_ip6 = t->is_ip6;
863 pr->dst_port = t->dst_port;
870 clib_memcpy (pr->dst_address, t->dst_address, count);
873 vnet_send_dns_request (vm, dm, ep);
874 dns_cache_unlock (dm);
878 #define foreach_notification_to_move \
882 * Handle cname indirection. JFC. Called with the cache locked.
883 * returns 0 if the reply is not a CNAME.
887 vnet_dns_cname_indirection_nolock (vlib_main_t * vm, dns_main_t * dm,
888 u32 ep_index, u8 * reply)
903 dns_cache_entry_t *ep, *next_ep;
906 h = (dns_header_t *) reply;
907 flags = clib_net_to_host_u16 (h->flags);
908 rcode = flags & DNS_RCODE_MASK;
910 /* See if the response is OK */
913 case DNS_RCODE_NO_ERROR:
916 case DNS_RCODE_NAME_ERROR:
917 case DNS_RCODE_FORMAT_ERROR:
918 case DNS_RCODE_SERVER_FAILURE:
919 case DNS_RCODE_NOT_IMPLEMENTED:
920 case DNS_RCODE_REFUSED:
924 curpos = (u8 *) (h + 1);
928 /* Skip the questions */
929 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
936 pos += sizeof (dns_query_t);
939 /* expect a pointer chase here for a CNAME record */
940 if ((pos2[0] & 0xC0) == 0xC0)
945 /* Walk the answer(s) to see what to do next */
946 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
948 rr = (dns_rr_t *) pos;
949 switch (clib_net_to_host_u16 (rr->type))
951 /* Real address record? Done.. */
956 * Maybe chase a CNAME pointer?
957 * It's not unheard-of for name-servers to return
958 * both CNAME and A/AAAA records...
964 /* Some other junk, e.g. a nameserver... */
968 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
970 if ((pos2[0] & 0xc0) == 0xc0)
974 /* Neither a CNAME nor a real address. Try another server */
977 flags &= ~DNS_RCODE_MASK;
978 flags |= DNS_RCODE_NAME_ERROR;
979 h->flags = clib_host_to_net_u16 (flags);
983 /* This is a CNAME record, chase the name chain. */
986 /* The last request is no longer pending.. */
987 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
988 if (ep_index == dm->unresolved_entries[i])
990 vec_delete (dm->unresolved_entries, 1, i);
991 goto found_last_request;
993 clib_warning ("pool elt %d supposedly pending, but not found...", ep_index);
998 now = vlib_time_now (vm);
999 cname = vnet_dns_labels_to_name (rr->rdata, reply, &pos2);
1000 /* Save the cname */
1001 dns_terminate_c_string (&cname);
1002 ep = pool_elt_at_index (dm->entries, ep_index);
1004 ep->flags |= (DNS_CACHE_ENTRY_FLAG_CNAME | DNS_CACHE_ENTRY_FLAG_VALID);
1005 /* Save the response */
1006 if (ep->dns_response)
1007 vec_free (ep->dns_response);
1008 ep->dns_response = reply;
1009 /* Set up expiration time */
1010 ep->expiration_time = now + clib_net_to_host_u32 (rr->ttl);
1012 pool_get (dm->entries, next_ep);
1014 /* Need to recompute ep post pool-get */
1015 ep = pool_elt_at_index (dm->entries, ep_index);
1017 clib_memset (next_ep, 0, sizeof (*next_ep));
1018 next_ep->name = vec_dup (cname);
1019 dns_terminate_c_string (&next_ep->name);
1021 hash_set_mem (dm->cache_entry_by_name, next_ep->name,
1022 next_ep - dm->entries);
1024 /* Use the same server */
1025 next_ep->server_rotor = ep->server_rotor;
1026 next_ep->server_af = ep->server_af;
1028 /* Move notification data to the next name in the chain */
1029 #define _(a) next_ep->a = ep->a; ep->a = 0;
1030 foreach_notification_to_move;
1033 request = name_to_labels (cname);
1034 name_copy = vec_dup (request);
1036 qp_offset = vec_len (request);
1038 /* Add space for the query header */
1039 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
1041 qp = (dns_query_t *) (request + qp_offset);
1043 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
1044 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1045 clib_memcpy (qp, name_copy, vec_len (name_copy));
1046 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
1047 vec_free (name_copy);
1049 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1050 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1052 /* Punch in space for the dns_header_t */
1053 vec_insert (request, sizeof (dns_header_t), 0);
1055 h = (dns_header_t *) request;
1057 /* Transaction ID = pool index */
1058 h->id = clib_host_to_net_u16 (next_ep - dm->entries);
1060 /* Ask for a recursive lookup */
1061 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
1062 h->qdcount = clib_host_to_net_u16 (2);
1066 next_ep->dns_request = request;
1067 next_ep->retry_timer = now + 2.0;
1068 next_ep->retry_count = 0;
1071 * Enable this to watch recursive resolution happen...
1072 * fformat (stdout, "%U", format_dns_reply, request, 2);
1075 vec_add1 (dm->unresolved_entries, next_ep - dm->entries);
1076 vnet_send_dns_request (vm, dm, next_ep);
1081 vnet_dns_response_to_reply (u8 *response, dns_resolve_name_t *rn,
1089 u8 *curpos, *pos, *pos2;
1093 int pointer_chase, addr_set = 0;
1095 h = (dns_header_t *) response;
1096 flags = clib_net_to_host_u16 (h->flags);
1097 rcode = flags & DNS_RCODE_MASK;
1099 /* See if the response is OK, etc. */
1103 case DNS_RCODE_NO_ERROR:
1106 case DNS_RCODE_NAME_ERROR:
1107 case DNS_RCODE_FORMAT_ERROR:
1108 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1110 case DNS_RCODE_SERVER_FAILURE:
1111 case DNS_RCODE_NOT_IMPLEMENTED:
1112 case DNS_RCODE_REFUSED:
1113 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1116 /* No answers? Loser... */
1117 if (clib_net_to_host_u16 (h->anscount) < 1)
1118 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1120 curpos = (u8 *) (h + 1);
1122 /* Skip the name we asked about */
1125 /* Should never happen, but stil... */
1126 if ((len & 0xC0) == 0xC0)
1130 /* skip the name / label-set */
1139 limit = clib_net_to_host_u16 (h->qdcount);
1140 qp = (dns_query_t *) curpos;
1145 limit = clib_net_to_host_u16 (h->anscount);
1147 for (i = 0; i < limit; i++)
1149 pos = pos2 = curpos;
1152 /* Expect pointer chases in the answer section... */
1153 if ((pos2[0] & 0xC0) == 0xC0)
1156 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1165 if ((pos2[0] & 0xc0) == 0xc0)
1168 * If we've already done one pointer chase,
1169 * do not move the pos pointer.
1171 if (pointer_chase == 0)
1173 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1181 if (pointer_chase == 0)
1184 rr = (dns_rr_t *) pos;
1186 switch (clib_net_to_host_u16 (rr->type))
1189 /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1190 ip_address_set (&rn->address, rr->rdata, AF_IP4);
1191 ttl = clib_net_to_host_u32 (rr->ttl);
1193 if (min_ttlp && *min_ttlp > ttl)
1197 /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1198 ip_address_set (&rn->address, rr->rdata, AF_IP6);
1199 ttl = clib_net_to_host_u32 (rr->ttl);
1200 if (min_ttlp && *min_ttlp > ttl)
1208 /* Might as well stop ASAP */
1211 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1216 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1221 vnet_dns_response_to_name (u8 * response,
1222 vl_api_dns_resolve_ip_reply_t * rmp,
1230 u8 *curpos, *pos, *pos2;
1235 u8 *junk __attribute__ ((unused));
1239 h = (dns_header_t *) response;
1240 flags = clib_net_to_host_u16 (h->flags);
1241 rcode = flags & DNS_RCODE_MASK;
1243 /* See if the response is OK, etc. */
1247 case DNS_RCODE_NO_ERROR:
1250 case DNS_RCODE_NAME_ERROR:
1251 case DNS_RCODE_FORMAT_ERROR:
1252 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1254 case DNS_RCODE_SERVER_FAILURE:
1255 case DNS_RCODE_NOT_IMPLEMENTED:
1256 case DNS_RCODE_REFUSED:
1257 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1260 /* No answers? Loser... */
1261 if (clib_net_to_host_u16 (h->anscount) < 1)
1262 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1264 curpos = (u8 *) (h + 1);
1266 /* Skip the name we asked about */
1269 /* Should never happen, but stil... */
1270 if ((len & 0xC0) == 0xC0)
1274 /* skip the name / label-set */
1283 limit = clib_net_to_host_u16 (h->qdcount);
1284 qp = (dns_query_t *) curpos;
1289 limit = clib_net_to_host_u16 (h->anscount);
1291 for (i = 0; i < limit; i++)
1293 pos = pos2 = curpos;
1296 /* Expect pointer chases in the answer section... */
1297 if ((pos2[0] & 0xC0) == 0xC0)
1300 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1309 if ((pos2[0] & 0xc0) == 0xc0)
1312 * If we've already done one pointer chase,
1313 * do not move the pos pointer.
1315 if (pointer_chase == 0)
1317 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1325 if (pointer_chase == 0)
1328 rr = (dns_rr_t *) pos;
1330 switch (clib_net_to_host_u16 (rr->type))
1333 name = vnet_dns_labels_to_name (rr->rdata, response, &junk);
1334 memcpy (rmp->name, name, vec_len (name));
1335 ttl = clib_net_to_host_u32 (rr->ttl);
1338 rmp->name[vec_len (name)] = 0;
1344 /* Might as well stop ASAP */
1347 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1352 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1357 dns_resolve_name (u8 *name, dns_cache_entry_t **ep, dns_pending_request_t *t0,
1358 dns_resolve_name_t *rn)
1360 dns_main_t *dm = &dns_main;
1361 vlib_main_t *vm = vlib_get_main ();
1363 int rv = vnet_dns_resolve_name (vm, dm, name, t0, ep);
1365 /* Error, e.g. not enabled? Tell the user */
1369 /* Resolution pending? Don't reply... */
1373 return vnet_dns_response_to_reply (ep[0]->dns_response, rn, 0 /* ttl-ptr */);
1377 vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1379 dns_main_t *dm = &dns_main;
1380 vl_api_dns_resolve_name_reply_t *rmp;
1381 dns_cache_entry_t *ep = 0;
1382 dns_pending_request_t _t0 = { 0 }, *t0 = &_t0;
1384 dns_resolve_name_t rn;
1386 /* Sanitize the name slightly */
1387 mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1389 t0->request_type = DNS_API_PENDING_NAME_TO_IP;
1390 t0->client_index = mp->client_index;
1391 t0->client_context = mp->context;
1393 rv = dns_resolve_name (mp->name, &ep, t0, &rn);
1395 /* Error, e.g. not enabled? Tell the user */
1398 REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1402 /* Resolution pending? Don't reply... */
1407 REPLY_MACRO2 (VL_API_DNS_RESOLVE_NAME_REPLY, ({
1408 ip_address_copy_addr (rmp->ip4_address, &rn.address);
1409 if (ip_addr_version (&rn.address) == AF_IP4)
1418 vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
1420 vlib_main_t *vm = vlib_get_main ();
1421 dns_main_t *dm = &dns_main;
1422 vl_api_dns_resolve_ip_reply_t *rmp;
1423 dns_cache_entry_t *ep;
1426 u8 *lookup_name = 0;
1428 dns_pending_request_t _t0 = { 0 }, *t0 = &_t0;
1432 for (i = 15; i >= 0; i--)
1434 digit = mp->address[i];
1435 nybble = (digit & 0x0F);
1437 vec_add1 (lookup_name, (nybble - 10) + 'a');
1439 vec_add1 (lookup_name, nybble + '0');
1440 vec_add1 (lookup_name, '.');
1441 nybble = (digit & 0xF0) >> 4;
1443 vec_add1 (lookup_name, (nybble - 10) + 'a');
1445 vec_add1 (lookup_name, nybble + '0');
1446 vec_add1 (lookup_name, '.');
1448 len = vec_len (lookup_name);
1449 vec_validate (lookup_name, len + 8);
1450 memcpy (lookup_name + len, "ip6.arpa", 8);
1454 for (i = 3; i >= 0; i--)
1456 digit = mp->address[i];
1457 lookup_name = format (lookup_name, "%d.", digit);
1459 lookup_name = format (lookup_name, "in-addr.arpa");
1462 vec_add1 (lookup_name, 0);
1464 t0->request_type = DNS_API_PENDING_IP_TO_NAME;
1465 t0->client_index = mp->client_index;
1466 t0->client_context = mp->context;
1468 rv = vnet_dns_resolve_name (vm, dm, lookup_name, t0, &ep);
1470 vec_free (lookup_name);
1472 /* Error, e.g. not enabled? Tell the user */
1475 REPLY_MACRO (VL_API_DNS_RESOLVE_IP_REPLY);
1479 /* Resolution pending? Don't reply... */
1484 REPLY_MACRO2(VL_API_DNS_RESOLVE_IP_REPLY,
1486 rv = vnet_dns_response_to_name (ep->dns_response, rmp, 0 /* ttl-ptr */);
1487 rmp->retval = clib_host_to_net_u32 (rv);
1492 static clib_error_t *
1493 dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1495 dns_main_t *dm = &dns_main;
1497 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1499 if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1501 else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1504 return clib_error_return (0, "unknown input `%U'",
1505 format_unformat_error, input);
1510 VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1513 unformat_dns_reply (unformat_input_t * input, va_list * args)
1515 u8 **result = va_arg (*args, u8 **);
1516 u8 **namep = va_arg (*args, u8 **);
1530 if (unformat (input, "%v", &name))
1533 if (unformat (input, "%U", unformat_ip4_address, &a4))
1536 if (unformat (input, "%U", unformat_ip6_address, &a6))
1540 if (unformat (input, "%U", unformat_ip6_address, &a6))
1543 if (unformat (input, "%U", unformat_ip4_address, &a6))
1547 /* Must have a name */
1551 /* Must have at least one address */
1552 if (!(a4_set + a6_set))
1555 /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1556 ce = name_to_labels (name);
1557 qp_offset = vec_len (ce);
1559 /* Add space for the query header */
1560 vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1561 qp = (dns_query_t *) (ce + qp_offset);
1563 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1564 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1566 /* Punch in space for the dns_header_t */
1567 vec_insert (ce, sizeof (dns_header_t), 0);
1569 h = (dns_header_t *) ce;
1571 /* Fake Transaction ID */
1574 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1575 h->qdcount = clib_host_to_net_u16 (1);
1576 h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1580 /* Now append one or two A/AAAA RR's... */
1583 /* Pointer to the name (DGMS) */
1584 vec_add1 (ce, 0xC0);
1585 vec_add1 (ce, 0x0C);
1586 vec_add2 (ce, rru8, sizeof (*rr) + 4);
1588 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1589 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1590 rr->ttl = clib_host_to_net_u32 (86400);
1591 rr->rdlength = clib_host_to_net_u16 (4);
1592 memcpy (rr->rdata, &a4, sizeof (a4));
1596 /* Pointer to the name (DGMS) */
1597 vec_add1 (ce, 0xC0);
1598 vec_add1 (ce, 0x0C);
1599 vec_add2 (ce, rru8, sizeof (*rr) + 16);
1601 rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1602 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1603 rr->ttl = clib_host_to_net_u32 (86400);
1604 rr->rdlength = clib_host_to_net_u16 (16);
1605 memcpy (rr->rdata, &a6, sizeof (a6));
1617 format_dns_query (u8 * s, va_list * args)
1619 u8 **curpos = va_arg (*args, u8 **);
1620 int verbose = va_arg (*args, int);
1625 s = format (s, " Name: ");
1627 /* Unwind execrated counted-label sheit */
1633 for (i = 0; i < len; i++)
1634 vec_add1 (s, *pos++);
1646 qp = (dns_query_t *) pos;
1649 switch (clib_net_to_host_u16 (qp->type))
1652 s = format (s, "type A\n");
1655 s = format (s, "type AAAA\n");
1658 s = format (s, "type ALL\n");
1662 s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1667 pos += sizeof (*qp);
1674 * format dns reply data
1675 * verbose > 1, dump everything
1676 * verbose == 1, dump all A and AAAA records
1677 * verbose == 0, dump one A record, and one AAAA record
1681 format_dns_reply_data (u8 * s, va_list * args)
1683 u8 *reply = va_arg (*args, u8 *);
1684 u8 **curpos = va_arg (*args, u8 **);
1685 int verbose = va_arg (*args, int);
1686 int *print_ip4 = va_arg (*args, int *);
1687 int *print_ip6 = va_arg (*args, int *);
1692 int pointer_chase = 0;
1694 u16 rrtype_host_byte_order;
1696 pos = pos2 = *curpos;
1699 s = format (s, " ");
1701 /* chase pointer? almost always yes here... */
1702 if ((pos2[0] & 0xc0) == 0xc0)
1705 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1713 for (i = 0; i < len; i++)
1716 vec_add1 (s, *pos2);
1719 if ((pos2[0] & 0xc0) == 0xc0)
1722 * If we've already done one pointer chase,
1723 * do not move the pos pointer.
1725 if (pointer_chase == 0)
1727 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1745 if (pointer_chase == 0)
1748 rr = (dns_rr_t *) pos;
1749 rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
1751 switch (rrtype_host_byte_order)
1756 s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1757 format_ip4_address, rr->rdata);
1762 s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1763 clib_net_to_host_u32 (rr->ttl));
1768 pos += sizeof (*rr) + 4;
1774 s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1775 format_ip6_address, rr->rdata);
1780 s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1781 clib_net_to_host_u32 (rr->ttl));
1785 pos += sizeof (*rr) + 16;
1791 s = format (s, "TEXT: ");
1792 for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1793 vec_add1 (s, rr->rdata[i]);
1796 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1799 case DNS_TYPE_HINFO:
1801 /* Two counted strings. DGMS */
1807 s = format (s, "HINFO: ");
1810 for (i = 0; i < *len; i++)
1811 vec_add1 (s, *curpos++);
1815 for (i = 0; i < *len; i++)
1816 vec_add1 (s, *curpos++);
1821 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1824 case DNS_TYPE_NAMESERVER:
1827 s = format (s, "Nameserver: ");
1830 /* chase pointer? */
1831 if ((pos2[0] & 0xc0) == 0xc0)
1834 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1841 for (i = 0; i < len; i++)
1842 vec_add1 (s, *pos2++);
1844 /* chase pointer, typically to offset 12... */
1845 if (pos2[0] == 0xC0)
1846 pos2 = reply + pos2[1];
1855 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1858 case DNS_TYPE_MAIL_EXCHANGE:
1861 tp = (u16 *) rr->rdata;
1863 s = format (s, "Mail Exchange: Preference %d ", (u32)
1864 clib_net_to_host_u16 (*tp));
1866 pos2 = rr->rdata + 2;
1868 /* chase pointer? */
1869 if (pos2[0] == 0xc0)
1870 pos2 = reply + pos2[1];
1876 for (i = 0; i < len; i++)
1877 vec_add1 (s, *pos2++);
1880 if (pos2[0] == 0xC0)
1881 pos2 = reply + pos2[1];
1891 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1895 case DNS_TYPE_CNAME:
1898 tp = (u16 *) rr->rdata;
1900 if (rrtype_host_byte_order == DNS_TYPE_CNAME)
1901 s = format (s, "CNAME: ");
1903 s = format (s, "PTR: ");
1907 /* chase pointer? */
1908 if (pos2[0] == 0xc0)
1909 pos2 = reply + pos2[1];
1915 for (i = 0; i < len; i++)
1916 vec_add1 (s, *pos2++);
1919 if (pos2[0] == 0xC0)
1920 pos2 = reply + pos2[1];
1929 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1934 s = format (s, "type %d: len %d\n",
1935 (int) clib_net_to_host_u16 (rr->type),
1936 sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
1937 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1947 format_dns_reply (u8 * s, va_list * args)
1949 u8 *reply_as_u8 = va_arg (*args, u8 *);
1950 int verbose = va_arg (*args, int);
1958 h = (dns_header_t *) reply_as_u8;
1959 id = clib_net_to_host_u16 (h->id);
1960 flags = clib_net_to_host_u16 (h->flags);
1964 s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
1966 s = format (s, " %s %s %s %s\n",
1967 (flags & DNS_RA) ? "recur" : "no-recur",
1968 (flags & DNS_RD) ? "recur-des" : "no-recur-des",
1969 (flags & DNS_TC) ? "trunc" : "no-trunc",
1970 (flags & DNS_AA) ? "auth" : "non-auth");
1971 s = format (s, " %d queries, %d answers, %d name-servers,"
1973 clib_net_to_host_u16 (h->qdcount),
1974 clib_net_to_host_u16 (h->anscount),
1975 clib_net_to_host_u16 (h->nscount),
1976 clib_net_to_host_u16 (h->arcount));
1979 curpos = (u8 *) (h + 1);
1984 s = format (s, " Queries:\n");
1985 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
1987 /* The query is variable-length, so curpos is a value-result parm */
1988 s = format (s, "%U", format_dns_query, &curpos, verbose);
1994 s = format (s, " Replies:\n");
1996 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
1998 /* curpos is a value-result parm */
1999 s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
2000 verbose, &print_ip4, &print_ip6);
2007 format_dns_cache (u8 * s, va_list * args)
2009 dns_main_t *dm = va_arg (*args, dns_main_t *);
2010 f64 now = va_arg (*args, f64);
2011 int verbose = va_arg (*args, int);
2012 u8 *name = va_arg (*args, u8 *);
2013 dns_cache_entry_t *ep;
2017 if (dm->is_enabled == 0)
2019 s = format (s, "The DNS cache is disabled...");
2023 if (pool_elts (dm->entries) == 0)
2025 s = format (s, "The DNS cache is empty...");
2029 dns_cache_lock (dm, 6);
2033 p = hash_get_mem (dm->cache_entry_by_name, name);
2036 s = format (s, "%s is not in the cache...", name);
2037 dns_cache_unlock (dm);
2041 ep = pool_elt_at_index (dm->entries, p[0]);
2042 /* Magic to spit out a C-initializer to research hemorrhoids... */
2046 s = format (s, "static u8 dns_reply_data_initializer[] =\n");
2047 s = format (s, "{\n");
2049 for (i = 0; i < vec_len (ep->dns_response); i++)
2056 s = format (s, "0x%02x, ", ep->dns_response[i]);
2058 s = format (s, "};\n");
2062 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2064 ASSERT (ep->dns_response);
2065 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2070 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2071 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2073 s = format (s, "%s%s -> %U", ss, ep->name,
2074 format_dns_reply, ep->dns_response, verbose);
2075 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2077 f64 time_left = ep->expiration_time - now;
2078 if (time_left > 0.0)
2079 s = format (s, " TTL left %.1f", time_left);
2081 s = format (s, " EXPIRED");
2086 ASSERT (ep->dns_request);
2087 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2095 s = format (s, "DNS cache contains %d entries\n", pool_elts (dm->entries));
2100 pool_foreach (ep, dm->entries)
2102 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2104 ASSERT (ep->dns_response);
2105 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2110 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2111 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2113 s = format (s, "%s%s -> %U", ss, ep->name,
2117 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2119 f64 time_left = ep->expiration_time - now;
2120 if (time_left > 0.0)
2121 s = format (s, " TTL left %.1f", time_left);
2123 s = format (s, " EXPIRED");
2126 s = format (s, " %d client notifications pending\n",
2127 vec_len(ep->pending_requests));
2132 ASSERT (ep->dns_request);
2133 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2141 dns_cache_unlock (dm);
2146 static clib_error_t *
2147 show_dns_cache_command_fn (vlib_main_t * vm,
2148 unformat_input_t * input, vlib_cli_command_t * cmd)
2150 dns_main_t *dm = &dns_main;
2153 f64 now = vlib_time_now (vm);
2155 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2157 if (unformat (input, "verbose %d", &verbose))
2159 else if (unformat (input, "verbose"))
2161 else if (unformat (input, "name %s", &name))
2164 return clib_error_return (0, "unknown input `%U'",
2165 format_unformat_error, input);
2168 vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
2174 VLIB_CLI_COMMAND (show_dns_cache_command) =
2176 .path = "show dns cache",
2177 .short_help = "show dns cache [verbose [nn]]",
2178 .function = show_dns_cache_command_fn,
2182 static clib_error_t *
2183 show_dns_servers_command_fn (vlib_main_t * vm,
2184 unformat_input_t * input,
2185 vlib_cli_command_t * cmd)
2187 dns_main_t *dm = &dns_main;
2190 if ((vec_len (dm->ip4_name_servers) + vec_len (dm->ip6_name_servers)) == 0)
2191 return clib_error_return (0, "No name servers configured...");
2193 if (vec_len (dm->ip4_name_servers))
2195 vlib_cli_output (vm, "ip4 name servers:");
2196 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
2197 vlib_cli_output (vm, "%U", format_ip4_address,
2198 dm->ip4_name_servers + i);
2200 if (vec_len (dm->ip6_name_servers))
2202 vlib_cli_output (vm, "ip6 name servers:");
2203 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
2204 vlib_cli_output (vm, "%U", format_ip6_address,
2205 dm->ip4_name_servers + i);
2211 VLIB_CLI_COMMAND (show_dns_server_command) =
2213 .path = "show dns servers",
2214 .short_help = "show dns servers",
2215 .function = show_dns_servers_command_fn,
2220 static clib_error_t *
2221 dns_cache_add_del_command_fn (vlib_main_t * vm,
2222 unformat_input_t * input,
2223 vlib_cli_command_t * cmd)
2225 dns_main_t *dm = &dns_main;
2231 clib_error_t *error;
2233 if (unformat (input, "add"))
2235 if (unformat (input, "del"))
2237 if (unformat (input, "clear"))
2240 if (is_add == -1 && is_clear == -1)
2241 return clib_error_return (0, "add / del / clear required...");
2245 rv = dns_cache_clear (dm);
2251 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2252 error = clib_error_return (0, "Name resolution not enabled");
2257 /* Delete (by name)? */
2260 if (unformat (input, "%v", &name))
2262 rv = dns_delete_by_name (dm, name);
2265 case VNET_API_ERROR_NO_SUCH_ENTRY:
2266 error = clib_error_return (0, "%v not in the cache...", name);
2270 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2271 error = clib_error_return (0, "Name resolution not enabled");
2280 error = clib_error_return (0, "dns_delete_by_name returned %d",
2286 return clib_error_return (0, "unknown input `%U'",
2287 format_unformat_error, input);
2290 /* Note: dns_add_static_entry consumes the name vector if OK... */
2291 if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2293 rv = dns_add_static_entry (dm, name, dns_reply_data);
2296 case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2298 vec_free (dns_reply_data);
2299 return clib_error_return (0, "%v already in the cache...", name);
2304 return clib_error_return (0, "dns_add_static_entry returned %d",
2313 VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2315 .path = "dns cache",
2316 .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2317 .function = dns_cache_add_del_command_fn,
2321 #define DNS_FORMAT_TEST 1
2323 #if DNS_FORMAT_TEST > 0
2326 static u8 dns_reply_data_initializer[] =
2327 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2328 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2330 0x0, 0xff, /* type ALL */
2331 0x0, 0x1, /* class IN */
2332 0xc0, 0xc, /* pointer to yahoo.com name */
2333 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2334 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2335 0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2336 0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2337 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2338 0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2339 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2340 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2341 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2342 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2343 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2344 0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2345 0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2347 0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2348 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2349 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2350 0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2351 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2353 0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2354 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2355 0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2356 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2358 0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2359 0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2361 0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2363 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2365 0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2367 0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2368 0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2369 0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2373 /* www.cisco.com, has no addresses in reply */
2374 static u8 dns_reply_data_initializer[] = {
2375 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2376 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2377 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2379 0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2380 0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2381 0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2382 0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2383 0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2386 /* bind8 (linux widget, w/ nasty double pointer chasees */
2387 static u8 dns_reply_data_initializer[] = {
2389 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08,
2391 0x00, 0x06, 0x00, 0x06, 0x0a, 0x6f, 0x72, 0x69,
2393 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77, 0x77, 0x05,
2395 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f,
2397 0x6d, 0x00, 0x00, 0xff, 0x00, 0x01, 0x0a, 0x6f,
2399 0x72, 0x69, 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77,
2401 0x77, 0x05, 0x43, 0x49, 0x53, 0x43, 0x4f, 0xc0,
2404 0x1d, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2407 0x9a, 0x00, 0x18, 0x15, 0x72, 0x63, 0x64,
2408 0x6e, 0x39, 0x2d, 0x31, 0x34, 0x70, 0x2d, 0x64, 0x63,
2409 0x7a, 0x30, 0x35, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31,
2410 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00, 0x01, 0x00,
2411 0x00, 0x05, 0x9a, 0x00, 0x1a, 0x17, 0x61, 0x6c, 0x6c,
2412 0x6e, 0x30, 0x31, 0x2d, 0x61, 0x67, 0x30, 0x39, 0x2d,
2413 0x64, 0x63, 0x7a, 0x30, 0x33, 0x6e, 0x2d, 0x67, 0x73,
2414 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00,
2415 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x10, 0x0d, 0x72,
2416 0x74, 0x70, 0x35, 0x2d, 0x64, 0x6d, 0x7a, 0x2d, 0x67,
2417 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2418 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x18, 0x15,
2419 0x6d, 0x74, 0x76, 0x35, 0x2d, 0x61, 0x70, 0x31, 0x30,
2420 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x36, 0x6e, 0x2d, 0x67,
2421 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2422 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x1b, 0x18,
2423 0x73, 0x6e, 0x67, 0x64, 0x63, 0x30, 0x31, 0x2d, 0x61,
2424 0x62, 0x30, 0x37, 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x31,
2425 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0,
2426 0x26, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a,
2427 0x00, 0x1a, 0x17, 0x61, 0x65, 0x72, 0x30, 0x31, 0x2d,
2428 0x72, 0x34, 0x63, 0x32, 0x35, 0x2d, 0x64, 0x63, 0x7a,
2429 0x30, 0x31, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0,
2430 0x17, 0xc0, 0x26, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2431 0x00, 0x81, 0x00, 0x04, 0x48, 0xa3, 0x04, 0xa1, 0xc0,
2432 0x26, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82,
2433 0x00, 0x10, 0x20, 0x01, 0x04, 0x20, 0x12, 0x01, 0x00,
2434 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
2435 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2436 0x9a, 0x00, 0x02, 0xc0, 0xf4, 0xc0, 0x0c, 0x00, 0x02,
2437 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0,
2438 0xcd, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00,
2439 0x05, 0x9a, 0x00, 0x02, 0xc0, 0x8d, 0xc0, 0x0c, 0x00,
2440 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02,
2441 0xc0, 0x43, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00,
2442 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0, 0xa9, 0xc0, 0x0c,
2443 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00,
2444 0x02, 0xc0, 0x67, 0xc0, 0x8d, 0x00, 0x01, 0x00, 0x01,
2445 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0x40, 0x66, 0xf6,
2446 0x05, 0xc0, 0xa9, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2447 0x07, 0x08, 0x00, 0x04, 0xad, 0x24, 0xe0, 0x64, 0xc0,
2448 0x43, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08,
2449 0x00, 0x04, 0x48, 0xa3, 0x04, 0x1c, 0xc0, 0xf4, 0x00,
2450 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04,
2451 0xad, 0x26, 0xd4, 0x6c, 0xc0, 0x67, 0x00, 0x01, 0x00,
2452 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x25,
2453 0x90, 0x64, 0xc0, 0xcd, 0x00, 0x01, 0x00, 0x01, 0x00,
2454 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x27, 0x70, 0x44,
2458 static u8 dns_reply_data_initializer[] =
2459 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
2460 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
2461 0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
2462 0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
2464 0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
2465 0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
2466 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
2467 0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
2468 0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
2469 0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
2470 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
2471 0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
2472 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
2473 0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
2474 0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
2475 0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
2476 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
2477 0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
2478 0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
2479 0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
2480 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2481 0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
2482 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
2483 0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
2484 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
2485 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
2486 0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
2488 0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2492 /* www.weatherlink.com */
2493 static u8 dns_reply_data_initializer[] = {
2494 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2495 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x0b,
2496 0x77, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x6c, 0x69,
2497 0x6e, 0x6b, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0xff,
2498 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00,
2499 0x00, 0x0c, 0x9e, 0x00, 0x1f, 0x0e, 0x64, 0x33, 0x6b,
2500 0x72, 0x30, 0x67, 0x75, 0x62, 0x61, 0x31, 0x64, 0x76,
2501 0x77, 0x66, 0x0a, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x66,
2502 0x72, 0x6f, 0x6e, 0x74, 0x03, 0x6e, 0x65, 0x74, 0x00,
2507 static clib_error_t *
2508 test_dns_fmt_command_fn (vlib_main_t * vm,
2509 unformat_input_t * input, vlib_cli_command_t * cmd)
2511 dns_resolve_name_t _rn, *rn = &_rn;
2512 u8 *dns_reply_data = 0;
2515 vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2517 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2519 if (unformat (input, "verbose %d", &verbose))
2521 else if (unformat (input, "verbose"))
2524 return clib_error_return (0, "unknown input `%U'",
2525 format_unformat_error, input);
2528 vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2530 memcpy (dns_reply_data, dns_reply_data_initializer,
2531 ARRAY_LEN (dns_reply_data_initializer));
2533 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2535 clib_memset (rmp, 0, sizeof (*rmp));
2537 rv = vnet_dns_response_to_reply (dns_reply_data, rn, 0 /* ttl-ptr */);
2541 case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2542 vlib_cli_output (vm, "no addresses found...");
2546 vlib_cli_output (vm, "response to reply returned %d", rv);
2550 vlib_cli_output (vm, "ip address: %U", format_ip_address, &rn->address);
2554 vec_free (dns_reply_data);
2561 VLIB_CLI_COMMAND (test_dns_fmt_command) =
2563 .path = "test dns format",
2564 .short_help = "test dns format",
2565 .function = test_dns_fmt_command_fn,
2569 static clib_error_t *
2570 test_dns_unfmt_command_fn (vlib_main_t * vm,
2571 unformat_input_t * input, vlib_cli_command_t * cmd)
2573 u8 *dns_reply_data = 0;
2577 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2579 if (unformat (input, "verbose %d", &verbose))
2581 else if (unformat (input, "verbose"))
2583 else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2586 return clib_error_return (0, "unknown input `%U'",
2587 format_unformat_error, input);
2591 return clib_error_return (0, "dns data not set...");
2593 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2595 vec_free (dns_reply_data);
2601 VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2603 .path = "test dns unformat",
2604 .short_help = "test dns unformat <name> [ip4][ip6]",
2605 .function = test_dns_unfmt_command_fn,
2609 static clib_error_t *
2610 test_dns_expire_command_fn (vlib_main_t * vm,
2611 unformat_input_t * input,
2612 vlib_cli_command_t * cmd)
2614 dns_main_t *dm = &dns_main;
2618 dns_cache_entry_t *ep;
2620 if (unformat (input, "%v", &name))
2621 dns_terminate_c_string (&name);
2623 return clib_error_return (0, "no name provided");
2625 dns_cache_lock (dm, 7);
2627 p = hash_get_mem (dm->cache_entry_by_name, name);
2630 dns_cache_unlock (dm);
2631 e = clib_error_return (0, "%s is not in the cache...", name);
2636 ep = pool_elt_at_index (dm->entries, p[0]);
2638 ep->expiration_time = 0;
2644 VLIB_CLI_COMMAND (test_dns_expire_command) =
2646 .path = "test dns expire",
2647 .short_help = "test dns expire <name>",
2648 .function = test_dns_expire_command_fn,
2654 vnet_send_dns6_reply (vlib_main_t * vm, dns_main_t * dm,
2655 dns_pending_request_t * pr, dns_cache_entry_t * ep,
2658 clib_warning ("Unimplemented...");
2663 vnet_send_dns4_reply (vlib_main_t * vm, dns_main_t * dm,
2664 dns_pending_request_t * pr, dns_cache_entry_t * ep,
2668 ip4_address_t src_address;
2676 /* vl_api_dns_resolve_name_reply_t _rnr, *rnr = &_rnr; */
2677 dns_resolve_name_t _rn, *rn = &_rn;
2678 vl_api_dns_resolve_ip_reply_t _rir, *rir = &_rir;
2685 int is_recycle = (b0 != 0);
2687 ASSERT (ep && ep->dns_response);
2689 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2691 /* Quick and dirty way to dig up the A-record address. $$ FIXME */
2692 clib_memset (rn, 0, sizeof (*rn));
2693 if (vnet_dns_response_to_reply (ep->dns_response, rn, &ttl))
2695 /* clib_warning ("response_to_reply failed..."); */
2698 else if (ip_addr_version (&rn->address) != AF_IP4)
2700 /* clib_warning ("No A-record..."); */
2704 else if (pr->request_type == DNS_PEER_PENDING_IP_TO_NAME)
2706 clib_memset (rir, 0, sizeof (*rir));
2707 if (vnet_dns_response_to_name (ep->dns_response, rir, &ttl))
2709 /* clib_warning ("response_to_name failed..."); */
2715 clib_warning ("Unknown request type %d", pr->request_type);
2719 /* Initialize a buffer */
2722 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2724 b0 = vlib_get_buffer (vm, bi);
2728 /* Use the buffer we were handed. Reinitialize it... */
2729 vlib_buffer_t bt = { };
2730 /* push/pop the reference count */
2731 u8 save_ref_count = b0->ref_count;
2732 vlib_buffer_copy_template (b0, &bt);
2733 b0->ref_count = save_ref_count;
2734 bi = vlib_get_buffer_index (vm, b0);
2737 if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
2738 vlib_buffer_free_one (vm, b0->next_buffer);
2741 * Reset the buffer. We recycle the DNS request packet in the cache
2742 * hit case, and reply immediately from the request node.
2744 * In the resolution-required / deferred case, resetting a freshly-allocated
2745 * buffer won't hurt. We hope.
2747 b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
2748 | VLIB_BUFFER_TOTAL_LENGTH_VALID);
2749 vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; /* "local0" */
2750 vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
2752 if (!ip4_sas (0 /* default VRF for now */, ~0,
2753 (const ip4_address_t *) &pr->dst_address, &src_address))
2756 ip = vlib_buffer_get_current (b0);
2757 udp = (udp_header_t *) (ip + 1);
2758 dns_response = (u8 *) (udp + 1);
2759 clib_memset (ip, 0, sizeof (*ip) + sizeof (*udp));
2762 * Start with the variadic portion of the exercise.
2763 * Turn the name into a set of DNS "labels". Max length
2764 * per label is 63, enforce that.
2766 reply = name_to_labels (pr->name);
2767 vec_free (pr->name);
2769 qp_offset = vec_len (reply);
2771 /* Add space for the query header */
2772 vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
2774 qp = (dns_query_t *) (reply + qp_offset);
2776 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2777 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
2779 qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2781 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
2783 /* Punch in space for the dns_header_t */
2784 vec_insert (reply, sizeof (dns_header_t), 0);
2786 dh = (dns_header_t *) reply;
2788 /* Transaction ID = pool index */
2791 /* Announce that we did a recursive lookup */
2792 tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
2794 tmp |= DNS_RCODE_NAME_ERROR;
2795 dh->flags = clib_host_to_net_u16 (tmp);
2796 dh->qdcount = clib_host_to_net_u16 (1);
2797 dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
2801 /* If the name resolution worked, cough up an appropriate RR */
2804 /* Add the answer. First, a name pointer (0xC00C) */
2805 vec_add1 (reply, 0xC0);
2806 vec_add1 (reply, 0x0C);
2808 /* Now, add single A-rec RR */
2809 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2811 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
2812 rr = (dns_rr_t *) rrptr;
2814 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
2815 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2816 rr->ttl = clib_host_to_net_u32 (ttl);
2817 rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
2818 ip_address_copy_addr (rr->rdata, &rn->address);
2822 /* Or a single PTR RR */
2823 u8 *vecname = format (0, "%s", rir->name);
2824 u8 *label_vec = name_to_labels (vecname);
2827 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
2828 rr = (dns_rr_t *) rrptr;
2829 rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2830 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2831 rr->ttl = clib_host_to_net_u32 (ttl);
2832 rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
2833 clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
2834 vec_free (label_vec);
2837 clib_memcpy (dns_response, reply, vec_len (reply));
2839 /* Set the packet length */
2840 b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
2843 ip->ip_version_and_header_length = 0x45;
2844 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
2846 ip->protocol = IP_PROTOCOL_UDP;
2847 ip->src_address.as_u32 = src_address.as_u32;
2848 clib_memcpy (ip->dst_address.as_u8, pr->dst_address,
2849 sizeof (ip4_address_t));
2850 ip->checksum = ip4_header_checksum (ip);
2853 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
2854 udp->dst_port = pr->dst_port;
2855 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
2861 * Ship pkts made out of whole cloth to ip4_lookup
2862 * Caller will ship recycled dns reply packets to ip4_lookup
2864 if (is_recycle == 0)
2866 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
2867 to_next = vlib_frame_vector_args (f);
2870 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
2874 #include <dns/dns.api.c>
2875 static clib_error_t *
2876 dns_init (vlib_main_t * vm)
2878 dns_main_t *dm = &dns_main;
2880 dm->vnet_main = vnet_get_main ();
2881 dm->name_cache_size = 1000;
2882 dm->max_ttl_in_seconds = 86400;
2883 dm->random_seed = 0xDEADDABE;
2884 dm->api_main = vlibapi_get_main ();
2886 /* Ask for a correctly-sized block of API message decode slots */
2887 dm->msg_id_base = setup_message_id_table ();
2893 VLIB_INIT_FUNCTION (dns_init) = {
2894 .init_order = VLIB_INITS ("flow_classify_init", "dns_init"),
2897 VLIB_PLUGIN_REGISTER () =
2899 .version = VPP_BUILD_VER,
2900 .description = "Simple DNS name resolver",
2906 * fd.io coding-style-patch-verification: ON
2909 * eval: (c-set-style "gnu")