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); \
42 dns_cache_clear (dns_main_t * dm)
44 dns_cache_entry_t *ep;
46 if (dm->is_enabled == 0)
47 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
49 dns_cache_lock (dm, 1);
52 pool_foreach (ep, dm->entries)
55 vec_free (ep->pending_requests);
59 pool_free (dm->entries);
60 hash_free (dm->cache_entry_by_name);
61 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
62 vec_free (dm->unresolved_entries);
63 dns_cache_unlock (dm);
68 dns_enable_disable (vlib_main_t * vm, dns_main_t * dm, int is_enable)
70 vlib_thread_main_t *tm = &vlib_thread_main;
71 u32 n_vlib_mains = tm->n_vlib_mains;
73 /* Create the resolver process if not done already */
74 vnet_dns_create_resolver_process (vm, dm);
78 if (vec_len (dm->ip4_name_servers) == 0
79 && (vec_len (dm->ip6_name_servers) == 0))
80 return VNET_API_ERROR_NO_NAME_SERVERS;
82 if (dm->udp_ports_registered == 0)
84 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply,
85 dns46_reply_node.index, 1 /* is_ip4 */ );
87 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply6,
88 dns46_reply_node.index, 0 /* is_ip4 */ );
90 udp_register_dst_port (vm, UDP_DST_PORT_dns,
91 dns4_request_node.index, 1 /* is_ip4 */ );
93 udp_register_dst_port (vm, UDP_DST_PORT_dns6,
94 dns6_request_node.index, 0 /* is_ip4 */ );
96 dm->udp_ports_registered = 1;
99 if (dm->cache_entry_by_name == 0)
101 if (n_vlib_mains > 1)
102 clib_spinlock_init (&dm->cache_lock);
104 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
111 dns_cache_clear (dm);
117 static void vl_api_dns_enable_disable_t_handler
118 (vl_api_dns_enable_disable_t * mp)
120 vl_api_dns_enable_disable_reply_t *rmp;
121 vlib_main_t *vm = vlib_get_main ();
122 dns_main_t *dm = &dns_main;
125 rv = dns_enable_disable (vm, dm, mp->enable);
127 REPLY_MACRO (VL_API_DNS_ENABLE_DISABLE_REPLY);
131 dns6_name_server_add_del (dns_main_t * dm,
132 u8 * server_address_as_u8, int is_add)
139 /* Already there? done... */
140 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
142 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
143 sizeof (ip6_address_t)))
147 vec_add2 (dm->ip6_name_servers, ap, 1);
148 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
152 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
154 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
155 sizeof (ip6_address_t)))
157 vec_delete (dm->ip6_name_servers, 1, i);
161 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
167 dns4_name_server_add_del (dns_main_t * dm,
168 u8 * server_address_as_u8, int is_add)
175 /* Already there? done... */
176 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
178 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
179 sizeof (ip4_address_t)))
183 vec_add2 (dm->ip4_name_servers, ap, 1);
184 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
188 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
190 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
191 sizeof (ip4_address_t)))
193 vec_delete (dm->ip4_name_servers, 1, i);
197 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
202 static void vl_api_dns_name_server_add_del_t_handler
203 (vl_api_dns_name_server_add_del_t * mp)
205 dns_main_t *dm = &dns_main;
206 vl_api_dns_name_server_add_del_reply_t *rmp;
210 rv = dns6_name_server_add_del (dm, mp->server_address, mp->is_add);
212 rv = dns4_name_server_add_del (dm, mp->server_address, mp->is_add);
214 REPLY_MACRO (VL_API_DNS_NAME_SERVER_ADD_DEL_REPLY);
218 vnet_dns_send_dns4_request (vlib_main_t * vm, dns_main_t * dm,
219 dns_cache_entry_t * ep, ip4_address_t * server)
221 f64 now = vlib_time_now (vm);
226 ip4_address_t src_address;
231 ASSERT (ep->dns_request);
233 if (!ip4_sas (0 /* default VRF for now */, ~0, server, &src_address))
236 /* Go get a buffer */
237 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
240 b = vlib_get_buffer (vm, bi);
241 b->current_length = sizeof (ip4_header_t) + sizeof (udp_header_t) +
242 vec_len (ep->dns_request);
243 b->total_length_not_including_first_buffer = 0;
245 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
246 vnet_buffer (b)->sw_if_index[VLIB_RX] = 0; /* "local0" */
247 vnet_buffer (b)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
249 ip = vlib_buffer_get_current (b);
250 clib_memset (ip, 0, sizeof (*ip));
251 udp = (udp_header_t *) (ip + 1);
252 clib_memset (udp, 0, sizeof (*udp));
254 dns_request = (u8 *) (udp + 1);
257 ip->ip_version_and_header_length = 0x45;
258 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b));
260 ip->protocol = IP_PROTOCOL_UDP;
261 ip->src_address.as_u32 = src_address.as_u32;
262 ip->dst_address.as_u32 = server->as_u32;
263 ip->checksum = ip4_header_checksum (ip);
266 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
267 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
268 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
269 vec_len (ep->dns_request));
272 /* The actual DNS request */
273 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
275 /* Ship it to ip4_lookup */
276 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
277 to_next = vlib_frame_vector_args (f);
280 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
282 ep->retry_timer = now + 2.0;
286 vnet_dns_send_dns6_request (vlib_main_t * vm, dns_main_t * dm,
287 dns_cache_entry_t * ep, ip6_address_t * server)
289 f64 now = vlib_time_now (vm);
294 ip6_address_t src_address;
298 int junk __attribute__ ((unused));
300 ASSERT (ep->dns_request);
302 if (!ip6_sas (0 /* default VRF for now */, ~0, server, &src_address))
305 /* Go get a buffer */
306 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
309 b = vlib_get_buffer (vm, bi);
310 b->current_length = sizeof (ip6_header_t) + sizeof (udp_header_t) +
311 vec_len (ep->dns_request);
312 b->total_length_not_including_first_buffer = 0;
314 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
316 ip = vlib_buffer_get_current (b);
317 clib_memset (ip, 0, sizeof (*ip));
318 udp = (udp_header_t *) (ip + 1);
319 clib_memset (udp, 0, sizeof (*udp));
321 dns_request = (u8 *) (udp + 1);
324 ip->ip_version_traffic_class_and_flow_label =
325 clib_host_to_net_u32 (0x6 << 28);
328 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b)
329 - sizeof (ip6_header_t));
331 ip->protocol = IP_PROTOCOL_UDP;
332 ip6_address_copy (&ip->src_address, &src_address);
333 clib_memcpy (&ip->dst_address, server, sizeof (ip6_address_t));
336 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
337 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
338 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
339 vec_len (ep->dns_request));
341 udp->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ip, &junk);
343 /* The actual DNS request */
344 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
346 /* Ship it to ip6_lookup */
347 f = vlib_get_frame_to_node (vm, ip6_lookup_node.index);
348 to_next = vlib_frame_vector_args (f);
352 ep->retry_timer = now + 2.0;
356 * Translate "foo.com" into "0x3 f o o 0x3 c o m 0x0"
357 * A historical / hysterical micro-TLV scheme. DGMS.
360 name_to_labels (u8 * name)
363 int last_label_index;
368 /* punch in space for the first length */
369 vec_insert (rv, 1, 0);
370 last_label_index = 0;
373 while (i < vec_len (rv))
377 rv[last_label_index] = (i - last_label_index) - 1;
378 if ((i - last_label_index) > 63)
379 clib_warning ("stupid name, label length %d",
380 i - last_label_index);
381 last_label_index = i;
386 /* Set the last real label length */
387 rv[last_label_index] = (i - last_label_index) - 1;
390 * Add a [sic] NULL root label. Otherwise, the name parser can't figure out
398 * arc-function for the above.
399 * Translate "0x3 f o o 0x3 c o m 0x0" into "foo.com"
400 * Produces a non-NULL-terminated u8 *vector. %v format is your friend.
403 vnet_dns_labels_to_name (u8 * label, u8 * full_text, u8 ** parse_from_here)
410 *parse_from_here = 0;
412 /* chase initial pointer? */
413 if ((label[0] & 0xC0) == 0xC0)
415 *parse_from_here = label + 2;
416 offset = ((label[0] & 0x3f) << 8) + label[1];
417 label = full_text + offset;
424 for (i = 0; i < len; i++)
425 vec_add1 (reply, *label++);
428 if ((label[0] & 0xC0) == 0xC0)
430 *parse_from_here = label + 2;
431 offset = ((label[0] & 0x3f) << 8) + label[1];
432 label = full_text + offset;
437 vec_add1 (reply, '.');
439 if (*parse_from_here == 0)
440 *parse_from_here = label;
445 vnet_send_dns_request (vlib_main_t * vm, dns_main_t * dm,
446 dns_cache_entry_t * ep)
451 u8 *request, *name_copy;
454 /* This can easily happen if sitting in GDB, etc. */
455 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID || ep->server_fails > 1)
458 /* Construct the dns request, if we haven't been here already */
459 if (vec_len (ep->dns_request) == 0)
462 * Start with the variadic portion of the exercise.
463 * Turn the name into a set of DNS "labels". Max length
464 * per label is 63, enforce that.
466 request = name_to_labels (ep->name);
467 name_copy = vec_dup (request);
468 qp_offset = vec_len (request);
471 * At least when testing against "known good" DNS servers:
472 * it turns out that sending 2x requests - one for an A-record
473 * and another for a AAAA-record - seems to work better than
474 * sending a DNS_TYPE_ALL request.
477 /* Add space for the query header */
478 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
480 qp = (dns_query_t *) (request + qp_offset);
482 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
483 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
485 clib_memcpy (qp, name_copy, vec_len (name_copy));
486 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
487 vec_free (name_copy);
489 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
490 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
492 /* Punch in space for the dns_header_t */
493 vec_insert (request, sizeof (dns_header_t), 0);
495 h = (dns_header_t *) request;
497 /* Transaction ID = pool index */
498 h->id = clib_host_to_net_u16 (ep - dm->entries);
500 /* Ask for a recursive lookup */
501 tmp = DNS_RD | DNS_OPCODE_QUERY;
502 h->flags = clib_host_to_net_u16 (tmp);
503 h->qdcount = clib_host_to_net_u16 (2);
507 ep->dns_request = request;
510 /* Work out which server / address family we're going to use */
512 /* Retry using current server */
513 if (ep->retry_count++ < DNS_RETRIES_PER_SERVER)
515 if (ep->server_af == 1 /* ip6 */ )
517 if (vec_len (dm->ip6_name_servers))
519 vnet_dns_send_dns6_request
520 (vm, dm, ep, dm->ip6_name_servers + ep->server_rotor);
526 if (vec_len (dm->ip4_name_servers))
528 vnet_dns_send_dns4_request
529 (vm, dm, ep, dm->ip4_name_servers + ep->server_rotor);
533 else /* switch to a new server */
537 if (ep->server_af == 1 /* ip6 */ )
539 if (ep->server_rotor >= vec_len (dm->ip6_name_servers))
541 ep->server_rotor = 0;
542 ep->server_af = vec_len (dm->ip4_name_servers) > 0 ? 0 : 1;
547 if (ep->server_rotor >= vec_len (dm->ip4_name_servers))
549 ep->server_rotor = 0;
550 ep->server_af = vec_len (dm->ip6_name_servers) > 0 ? 1 : 0;
555 if (ep->server_af == 1 /* ip6 */ )
556 vnet_dns_send_dns6_request
557 (vm, dm, ep, dm->ip6_name_servers + ep->server_rotor);
559 vnet_dns_send_dns4_request
560 (vm, dm, ep, dm->ip4_name_servers + ep->server_rotor);
564 vlib_process_signal_event_mt (vm,
565 dm->resolver_process_node_index,
566 DNS_RESOLVER_EVENT_PENDING, 0);
570 vnet_dns_delete_entry_by_index_nolock (dns_main_t * dm, u32 index)
572 dns_cache_entry_t *ep;
575 if (dm->is_enabled == 0)
576 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
578 if (pool_is_free_index (dm->entries, index))
579 return VNET_API_ERROR_NO_SUCH_ENTRY;
581 ep = pool_elt_at_index (dm->entries, index);
582 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_VALID))
584 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
585 if (index == dm->unresolved_entries[i])
587 vec_delete (dm->unresolved_entries, 1, i);
590 clib_warning ("pool elt %d supposedly pending, but not found...",
595 hash_unset_mem (dm->cache_entry_by_name, ep->name);
597 vec_free (ep->pending_requests);
598 pool_put (dm->entries, ep);
604 dns_delete_by_name (dns_main_t * dm, u8 * name)
609 if (dm->is_enabled == 0)
610 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
612 dns_cache_lock (dm, 2);
613 p = hash_get_mem (dm->cache_entry_by_name, name);
616 dns_cache_unlock (dm);
617 return VNET_API_ERROR_NO_SUCH_ENTRY;
619 rv = vnet_dns_delete_entry_by_index_nolock (dm, p[0]);
621 dns_cache_unlock (dm);
627 delete_random_entry (dns_main_t * dm)
630 u32 victim_index, start_index, i;
632 dns_cache_entry_t *ep;
634 if (dm->is_enabled == 0)
635 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
638 * Silence spurious coverity warning. We know pool_elts >> 0, or
639 * we wouldn't be here...
642 if (pool_elts (dm->entries) == 0)
643 return VNET_API_ERROR_UNSPECIFIED;
646 dns_cache_lock (dm, 3);
647 limit = pool_elts (dm->entries);
648 start_index = random_u32 (&dm->random_seed) % limit;
650 for (i = 0; i < limit; i++)
652 victim_index = (start_index + i) % limit;
654 if (!pool_is_free_index (dm->entries, victim_index))
656 ep = pool_elt_at_index (dm->entries, victim_index);
657 /* Delete only valid, non-static entries */
658 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
659 && ((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0))
661 rv = vnet_dns_delete_entry_by_index_nolock (dm, victim_index);
662 dns_cache_unlock (dm);
667 dns_cache_unlock (dm);
669 clib_warning ("Couldn't find an entry to delete?");
670 return VNET_API_ERROR_UNSPECIFIED;
674 dns_add_static_entry (dns_main_t * dm, u8 * name, u8 * dns_reply_data)
676 dns_cache_entry_t *ep;
680 if (dm->is_enabled == 0)
681 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
683 dns_cache_lock (dm, 4);
684 p = hash_get_mem (dm->cache_entry_by_name, name);
687 dns_cache_unlock (dm);
688 return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
691 if (pool_elts (dm->entries) == dm->name_cache_size)
693 /* Will only fail if the cache is totally filled w/ static entries... */
694 rv = delete_random_entry (dm);
697 dns_cache_unlock (dm);
702 pool_get (dm->entries, ep);
703 clib_memset (ep, 0, sizeof (*ep));
705 /* Note: consumes the name vector */
707 /* make sure it NULL-terminated as hash_set_mem will use strlen() */
708 vec_terminate_c_string (ep->name);
709 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
710 ep->flags = DNS_CACHE_ENTRY_FLAG_VALID | DNS_CACHE_ENTRY_FLAG_STATIC;
711 ep->dns_response = dns_reply_data;
713 dns_cache_unlock (dm);
718 vnet_dns_resolve_name (vlib_main_t * vm, dns_main_t * dm, u8 * name,
719 dns_pending_request_t * t, dns_cache_entry_t ** retp)
721 dns_cache_entry_t *ep;
725 dns_pending_request_t *pr;
728 now = vlib_time_now (vm);
730 /* In case we can't actually answer the question right now... */
733 /* binary API caller might forget to set the name. Guess how we know. */
735 return VNET_API_ERROR_INVALID_VALUE;
737 dns_cache_lock (dm, 5);
739 p = hash_get_mem (dm->cache_entry_by_name, name);
742 ep = pool_elt_at_index (dm->entries, p[0]);
743 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
745 /* Has the entry expired? */
746 if (((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0)
747 && (now > ep->expiration_time))
750 u32 *indices_to_delete = 0;
753 * Take out the rest of the resolution chain
754 * This isn't optimal, but it won't happen very often.
758 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME))
760 vec_add1 (indices_to_delete, ep - dm->entries);
762 p = hash_get_mem (dm->cache_entry_by_name, ep->cname);
765 ep = pool_elt_at_index (dm->entries, p[0]);
769 vec_add1 (indices_to_delete, ep - dm->entries);
773 for (i = 0; i < vec_len (indices_to_delete); i++)
775 /* Reenable to watch re-resolutions */
778 ep = pool_elt_at_index (dm->entries,
779 indices_to_delete[i]);
780 clib_warning ("Re-resolve %s", ep->name);
783 vnet_dns_delete_entry_by_index_nolock
784 (dm, indices_to_delete[i]);
786 vec_free (indices_to_delete);
787 /* Yes, kill it... */
791 if (ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
797 dns_cache_unlock (dm);
803 * Resolution pending. Add request to the pending vector
804 * by copying the template request
806 vec_add2 (ep->pending_requests, pr, 1);
807 memcpy (pr, t, sizeof (*pr));
808 dns_cache_unlock (dm);
814 if (pool_elts (dm->entries) == dm->name_cache_size)
816 /* Will only fail if the cache is totally filled w/ static entries... */
817 rv = delete_random_entry (dm);
820 dns_cache_unlock (dm);
825 /* add new hash table entry */
826 pool_get (dm->entries, ep);
827 clib_memset (ep, 0, sizeof (*ep));
829 ep->name = format (0, "%s%c", name, 0);
830 vec_set_len (ep->name, vec_len (ep->name) - 1);
832 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
834 vec_add1 (dm->unresolved_entries, ep - dm->entries);
835 vec_add2 (ep->pending_requests, pr, 1);
837 pr->request_type = t->request_type;
839 /* Remember details so we can reply later... */
840 if (t->request_type == DNS_API_PENDING_NAME_TO_IP ||
841 t->request_type == DNS_API_PENDING_IP_TO_NAME)
843 pr->client_index = t->client_index;
844 pr->client_context = t->client_context;
848 pr->client_index = ~0;
849 pr->is_ip6 = t->is_ip6;
850 pr->dst_port = t->dst_port;
857 clib_memcpy (pr->dst_address, t->dst_address, count);
860 vnet_send_dns_request (vm, dm, ep);
861 dns_cache_unlock (dm);
865 #define foreach_notification_to_move \
869 * Handle cname indirection. JFC. Called with the cache locked.
870 * returns 0 if the reply is not a CNAME.
874 vnet_dns_cname_indirection_nolock (vlib_main_t * vm, dns_main_t * dm,
875 u32 ep_index, u8 * reply)
890 dns_cache_entry_t *ep, *next_ep;
893 h = (dns_header_t *) reply;
894 flags = clib_net_to_host_u16 (h->flags);
895 rcode = flags & DNS_RCODE_MASK;
897 /* See if the response is OK */
900 case DNS_RCODE_NO_ERROR:
903 case DNS_RCODE_NAME_ERROR:
904 case DNS_RCODE_FORMAT_ERROR:
905 case DNS_RCODE_SERVER_FAILURE:
906 case DNS_RCODE_NOT_IMPLEMENTED:
907 case DNS_RCODE_REFUSED:
911 curpos = (u8 *) (h + 1);
915 /* Skip the questions */
916 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
923 pos += sizeof (dns_query_t);
926 /* expect a pointer chase here for a CNAME record */
927 if ((pos2[0] & 0xC0) == 0xC0)
932 /* Walk the answer(s) to see what to do next */
933 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
935 rr = (dns_rr_t *) pos;
936 switch (clib_net_to_host_u16 (rr->type))
938 /* Real address record? Done.. */
943 * Maybe chase a CNAME pointer?
944 * It's not unheard-of for name-servers to return
945 * both CNAME and A/AAAA records...
951 /* Some other junk, e.g. a nameserver... */
955 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
957 if ((pos2[0] & 0xc0) == 0xc0)
961 /* Neither a CNAME nor a real address. Try another server */
964 flags &= ~DNS_RCODE_MASK;
965 flags |= DNS_RCODE_NAME_ERROR;
966 h->flags = clib_host_to_net_u16 (flags);
970 /* This is a CNAME record, chase the name chain. */
973 /* The last request is no longer pending.. */
974 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
975 if (ep_index == dm->unresolved_entries[i])
977 vec_delete (dm->unresolved_entries, 1, i);
978 goto found_last_request;
980 clib_warning ("pool elt %d supposedly pending, but not found...", ep_index);
985 now = vlib_time_now (vm);
986 cname = vnet_dns_labels_to_name (rr->rdata, reply, &pos2);
989 vec_dec_len (cname, 1);
990 ep = pool_elt_at_index (dm->entries, ep_index);
992 ep->flags |= (DNS_CACHE_ENTRY_FLAG_CNAME | DNS_CACHE_ENTRY_FLAG_VALID);
993 /* Save the response */
994 if (ep->dns_response)
995 vec_free (ep->dns_response);
996 ep->dns_response = reply;
997 /* Set up expiration time */
998 ep->expiration_time = now + clib_net_to_host_u32 (rr->ttl);
1000 pool_get (dm->entries, next_ep);
1002 /* Need to recompute ep post pool-get */
1003 ep = pool_elt_at_index (dm->entries, ep_index);
1005 clib_memset (next_ep, 0, sizeof (*next_ep));
1006 next_ep->name = vec_dup (cname);
1007 vec_add1 (next_ep->name, 0);
1008 vec_dec_len (next_ep->name, 1);
1010 hash_set_mem (dm->cache_entry_by_name, next_ep->name,
1011 next_ep - dm->entries);
1013 /* Use the same server */
1014 next_ep->server_rotor = ep->server_rotor;
1015 next_ep->server_af = ep->server_af;
1017 /* Move notification data to the next name in the chain */
1018 #define _(a) next_ep->a = ep->a; ep->a = 0;
1019 foreach_notification_to_move;
1022 request = name_to_labels (cname);
1023 name_copy = vec_dup (request);
1025 qp_offset = vec_len (request);
1027 /* Add space for the query header */
1028 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
1030 qp = (dns_query_t *) (request + qp_offset);
1032 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
1033 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1034 clib_memcpy (qp, name_copy, vec_len (name_copy));
1035 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
1036 vec_free (name_copy);
1038 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1039 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1041 /* Punch in space for the dns_header_t */
1042 vec_insert (request, sizeof (dns_header_t), 0);
1044 h = (dns_header_t *) request;
1046 /* Transaction ID = pool index */
1047 h->id = clib_host_to_net_u16 (next_ep - dm->entries);
1049 /* Ask for a recursive lookup */
1050 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
1051 h->qdcount = clib_host_to_net_u16 (2);
1055 next_ep->dns_request = request;
1056 next_ep->retry_timer = now + 2.0;
1057 next_ep->retry_count = 0;
1060 * Enable this to watch recursive resolution happen...
1061 * fformat (stdout, "%U", format_dns_reply, request, 2);
1064 vec_add1 (dm->unresolved_entries, next_ep - dm->entries);
1065 vnet_send_dns_request (vm, dm, next_ep);
1070 vnet_dns_response_to_reply (u8 *response, dns_resolve_name_t *rn,
1078 u8 *curpos, *pos, *pos2;
1082 int pointer_chase, addr_set = 0;
1084 h = (dns_header_t *) response;
1085 flags = clib_net_to_host_u16 (h->flags);
1086 rcode = flags & DNS_RCODE_MASK;
1088 /* See if the response is OK, etc. */
1092 case DNS_RCODE_NO_ERROR:
1095 case DNS_RCODE_NAME_ERROR:
1096 case DNS_RCODE_FORMAT_ERROR:
1097 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1099 case DNS_RCODE_SERVER_FAILURE:
1100 case DNS_RCODE_NOT_IMPLEMENTED:
1101 case DNS_RCODE_REFUSED:
1102 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1105 /* No answers? Loser... */
1106 if (clib_net_to_host_u16 (h->anscount) < 1)
1107 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1109 curpos = (u8 *) (h + 1);
1111 /* Skip the name we asked about */
1114 /* Should never happen, but stil... */
1115 if ((len & 0xC0) == 0xC0)
1119 /* skip the name / label-set */
1128 limit = clib_net_to_host_u16 (h->qdcount);
1129 qp = (dns_query_t *) curpos;
1134 limit = clib_net_to_host_u16 (h->anscount);
1136 for (i = 0; i < limit; i++)
1138 pos = pos2 = curpos;
1141 /* Expect pointer chases in the answer section... */
1142 if ((pos2[0] & 0xC0) == 0xC0)
1145 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1154 if ((pos2[0] & 0xc0) == 0xc0)
1157 * If we've already done one pointer chase,
1158 * do not move the pos pointer.
1160 if (pointer_chase == 0)
1162 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1170 if (pointer_chase == 0)
1173 rr = (dns_rr_t *) pos;
1175 switch (clib_net_to_host_u16 (rr->type))
1178 /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1179 ip_address_set (&rn->address, rr->rdata, AF_IP4);
1180 ttl = clib_net_to_host_u32 (rr->ttl);
1182 if (min_ttlp && *min_ttlp > ttl)
1186 /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1187 ip_address_set (&rn->address, rr->rdata, AF_IP6);
1188 ttl = clib_net_to_host_u32 (rr->ttl);
1189 if (min_ttlp && *min_ttlp > ttl)
1197 /* Might as well stop ASAP */
1200 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1205 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1210 vnet_dns_response_to_name (u8 * response,
1211 vl_api_dns_resolve_ip_reply_t * rmp,
1219 u8 *curpos, *pos, *pos2;
1224 u8 *junk __attribute__ ((unused));
1228 h = (dns_header_t *) response;
1229 flags = clib_net_to_host_u16 (h->flags);
1230 rcode = flags & DNS_RCODE_MASK;
1232 /* See if the response is OK, etc. */
1236 case DNS_RCODE_NO_ERROR:
1239 case DNS_RCODE_NAME_ERROR:
1240 case DNS_RCODE_FORMAT_ERROR:
1241 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1243 case DNS_RCODE_SERVER_FAILURE:
1244 case DNS_RCODE_NOT_IMPLEMENTED:
1245 case DNS_RCODE_REFUSED:
1246 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1249 /* No answers? Loser... */
1250 if (clib_net_to_host_u16 (h->anscount) < 1)
1251 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1253 curpos = (u8 *) (h + 1);
1255 /* Skip the name we asked about */
1258 /* Should never happen, but stil... */
1259 if ((len & 0xC0) == 0xC0)
1263 /* skip the name / label-set */
1272 limit = clib_net_to_host_u16 (h->qdcount);
1273 qp = (dns_query_t *) curpos;
1278 limit = clib_net_to_host_u16 (h->anscount);
1280 for (i = 0; i < limit; i++)
1282 pos = pos2 = curpos;
1285 /* Expect pointer chases in the answer section... */
1286 if ((pos2[0] & 0xC0) == 0xC0)
1289 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1298 if ((pos2[0] & 0xc0) == 0xc0)
1301 * If we've already done one pointer chase,
1302 * do not move the pos pointer.
1304 if (pointer_chase == 0)
1306 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1314 if (pointer_chase == 0)
1317 rr = (dns_rr_t *) pos;
1319 switch (clib_net_to_host_u16 (rr->type))
1322 name = vnet_dns_labels_to_name (rr->rdata, response, &junk);
1323 memcpy (rmp->name, name, vec_len (name));
1324 ttl = clib_net_to_host_u32 (rr->ttl);
1327 rmp->name[vec_len (name)] = 0;
1333 /* Might as well stop ASAP */
1336 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1341 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1346 dns_resolve_name (u8 *name, dns_cache_entry_t **ep, dns_pending_request_t *t0,
1347 dns_resolve_name_t *rn)
1349 dns_main_t *dm = &dns_main;
1350 vlib_main_t *vm = vlib_get_main ();
1352 int rv = vnet_dns_resolve_name (vm, dm, name, t0, ep);
1354 /* Error, e.g. not enabled? Tell the user */
1358 /* Resolution pending? Don't reply... */
1362 return vnet_dns_response_to_reply (ep[0]->dns_response, rn, 0 /* ttl-ptr */);
1366 vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1368 dns_main_t *dm = &dns_main;
1369 vl_api_dns_resolve_name_reply_t *rmp;
1370 dns_cache_entry_t *ep = 0;
1371 dns_pending_request_t _t0 = { 0 }, *t0 = &_t0;
1373 dns_resolve_name_t rn;
1375 /* Sanitize the name slightly */
1376 mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1378 t0->request_type = DNS_API_PENDING_NAME_TO_IP;
1379 t0->client_index = mp->client_index;
1380 t0->client_context = mp->context;
1382 rv = dns_resolve_name (mp->name, &ep, t0, &rn);
1384 /* Error, e.g. not enabled? Tell the user */
1387 REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1391 /* Resolution pending? Don't reply... */
1396 REPLY_MACRO2 (VL_API_DNS_RESOLVE_NAME_REPLY, ({
1397 ip_address_copy_addr (rmp->ip4_address, &rn.address);
1398 if (ip_addr_version (&rn.address) == AF_IP4)
1407 vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
1409 vlib_main_t *vm = vlib_get_main ();
1410 dns_main_t *dm = &dns_main;
1411 vl_api_dns_resolve_ip_reply_t *rmp;
1412 dns_cache_entry_t *ep;
1415 u8 *lookup_name = 0;
1417 dns_pending_request_t _t0 = { 0 }, *t0 = &_t0;
1421 for (i = 15; i >= 0; i--)
1423 digit = mp->address[i];
1424 nybble = (digit & 0x0F);
1426 vec_add1 (lookup_name, (nybble - 10) + 'a');
1428 vec_add1 (lookup_name, nybble + '0');
1429 vec_add1 (lookup_name, '.');
1430 nybble = (digit & 0xF0) >> 4;
1432 vec_add1 (lookup_name, (nybble - 10) + 'a');
1434 vec_add1 (lookup_name, nybble + '0');
1435 vec_add1 (lookup_name, '.');
1437 len = vec_len (lookup_name);
1438 vec_validate (lookup_name, len + 8);
1439 memcpy (lookup_name + len, "ip6.arpa", 8);
1443 for (i = 3; i >= 0; i--)
1445 digit = mp->address[i];
1446 lookup_name = format (lookup_name, "%d.", digit);
1448 lookup_name = format (lookup_name, "in-addr.arpa");
1451 vec_add1 (lookup_name, 0);
1453 t0->request_type = DNS_API_PENDING_IP_TO_NAME;
1454 t0->client_index = mp->client_index;
1455 t0->client_context = mp->context;
1457 rv = vnet_dns_resolve_name (vm, dm, lookup_name, t0, &ep);
1459 vec_free (lookup_name);
1461 /* Error, e.g. not enabled? Tell the user */
1464 REPLY_MACRO (VL_API_DNS_RESOLVE_IP_REPLY);
1468 /* Resolution pending? Don't reply... */
1473 REPLY_MACRO2(VL_API_DNS_RESOLVE_IP_REPLY,
1475 rv = vnet_dns_response_to_name (ep->dns_response, rmp, 0 /* ttl-ptr */);
1476 rmp->retval = clib_host_to_net_u32 (rv);
1481 static clib_error_t *
1482 dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1484 dns_main_t *dm = &dns_main;
1486 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1488 if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1490 else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1493 return clib_error_return (0, "unknown input `%U'",
1494 format_unformat_error, input);
1499 VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1502 unformat_dns_reply (unformat_input_t * input, va_list * args)
1504 u8 **result = va_arg (*args, u8 **);
1505 u8 **namep = va_arg (*args, u8 **);
1519 if (unformat (input, "%v", &name))
1522 if (unformat (input, "%U", unformat_ip4_address, &a4))
1525 if (unformat (input, "%U", unformat_ip6_address, &a6))
1529 if (unformat (input, "%U", unformat_ip6_address, &a6))
1532 if (unformat (input, "%U", unformat_ip4_address, &a6))
1536 /* Must have a name */
1540 /* Must have at least one address */
1541 if (!(a4_set + a6_set))
1544 /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1545 ce = name_to_labels (name);
1546 qp_offset = vec_len (ce);
1548 /* Add space for the query header */
1549 vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1550 qp = (dns_query_t *) (ce + qp_offset);
1552 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1553 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1555 /* Punch in space for the dns_header_t */
1556 vec_insert (ce, sizeof (dns_header_t), 0);
1558 h = (dns_header_t *) ce;
1560 /* Fake Transaction ID */
1563 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1564 h->qdcount = clib_host_to_net_u16 (1);
1565 h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1569 /* Now append one or two A/AAAA RR's... */
1572 /* Pointer to the name (DGMS) */
1573 vec_add1 (ce, 0xC0);
1574 vec_add1 (ce, 0x0C);
1575 vec_add2 (ce, rru8, sizeof (*rr) + 4);
1577 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1578 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1579 rr->ttl = clib_host_to_net_u32 (86400);
1580 rr->rdlength = clib_host_to_net_u16 (4);
1581 memcpy (rr->rdata, &a4, sizeof (a4));
1585 /* Pointer to the name (DGMS) */
1586 vec_add1 (ce, 0xC0);
1587 vec_add1 (ce, 0x0C);
1588 vec_add2 (ce, rru8, sizeof (*rr) + 16);
1590 rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1591 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1592 rr->ttl = clib_host_to_net_u32 (86400);
1593 rr->rdlength = clib_host_to_net_u16 (16);
1594 memcpy (rr->rdata, &a6, sizeof (a6));
1606 format_dns_query (u8 * s, va_list * args)
1608 u8 **curpos = va_arg (*args, u8 **);
1609 int verbose = va_arg (*args, int);
1614 s = format (s, " Name: ");
1616 /* Unwind execrated counted-label sheit */
1622 for (i = 0; i < len; i++)
1623 vec_add1 (s, *pos++);
1635 qp = (dns_query_t *) pos;
1638 switch (clib_net_to_host_u16 (qp->type))
1641 s = format (s, "type A\n");
1644 s = format (s, "type AAAA\n");
1647 s = format (s, "type ALL\n");
1651 s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1656 pos += sizeof (*qp);
1663 * format dns reply data
1664 * verbose > 1, dump everything
1665 * verbose == 1, dump all A and AAAA records
1666 * verbose == 0, dump one A record, and one AAAA record
1670 format_dns_reply_data (u8 * s, va_list * args)
1672 u8 *reply = va_arg (*args, u8 *);
1673 u8 **curpos = va_arg (*args, u8 **);
1674 int verbose = va_arg (*args, int);
1675 int *print_ip4 = va_arg (*args, int *);
1676 int *print_ip6 = va_arg (*args, int *);
1681 int pointer_chase = 0;
1683 u16 rrtype_host_byte_order;
1685 pos = pos2 = *curpos;
1688 s = format (s, " ");
1690 /* chase pointer? almost always yes here... */
1691 if ((pos2[0] & 0xc0) == 0xc0)
1694 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1702 for (i = 0; i < len; i++)
1705 vec_add1 (s, *pos2);
1708 if ((pos2[0] & 0xc0) == 0xc0)
1711 * If we've already done one pointer chase,
1712 * do not move the pos pointer.
1714 if (pointer_chase == 0)
1716 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1734 if (pointer_chase == 0)
1737 rr = (dns_rr_t *) pos;
1738 rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
1740 switch (rrtype_host_byte_order)
1745 s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1746 format_ip4_address, rr->rdata);
1751 s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1752 clib_net_to_host_u32 (rr->ttl));
1757 pos += sizeof (*rr) + 4;
1763 s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1764 format_ip6_address, rr->rdata);
1769 s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1770 clib_net_to_host_u32 (rr->ttl));
1774 pos += sizeof (*rr) + 16;
1780 s = format (s, "TEXT: ");
1781 for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1782 vec_add1 (s, rr->rdata[i]);
1785 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1788 case DNS_TYPE_HINFO:
1790 /* Two counted strings. DGMS */
1796 s = format (s, "HINFO: ");
1799 for (i = 0; i < *len; i++)
1800 vec_add1 (s, *curpos++);
1804 for (i = 0; i < *len; i++)
1805 vec_add1 (s, *curpos++);
1810 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1813 case DNS_TYPE_NAMESERVER:
1816 s = format (s, "Nameserver: ");
1819 /* chase pointer? */
1820 if ((pos2[0] & 0xc0) == 0xc0)
1823 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1830 for (i = 0; i < len; i++)
1831 vec_add1 (s, *pos2++);
1833 /* chase pointer, typically to offset 12... */
1834 if (pos2[0] == 0xC0)
1835 pos2 = reply + pos2[1];
1844 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1847 case DNS_TYPE_MAIL_EXCHANGE:
1850 tp = (u16 *) rr->rdata;
1852 s = format (s, "Mail Exchange: Preference %d ", (u32)
1853 clib_net_to_host_u16 (*tp));
1855 pos2 = rr->rdata + 2;
1857 /* chase pointer? */
1858 if (pos2[0] == 0xc0)
1859 pos2 = reply + pos2[1];
1865 for (i = 0; i < len; i++)
1866 vec_add1 (s, *pos2++);
1869 if (pos2[0] == 0xC0)
1870 pos2 = reply + pos2[1];
1880 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1884 case DNS_TYPE_CNAME:
1887 tp = (u16 *) rr->rdata;
1889 if (rrtype_host_byte_order == DNS_TYPE_CNAME)
1890 s = format (s, "CNAME: ");
1892 s = format (s, "PTR: ");
1896 /* chase pointer? */
1897 if (pos2[0] == 0xc0)
1898 pos2 = reply + pos2[1];
1904 for (i = 0; i < len; i++)
1905 vec_add1 (s, *pos2++);
1908 if (pos2[0] == 0xC0)
1909 pos2 = reply + pos2[1];
1918 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1923 s = format (s, "type %d: len %d\n",
1924 (int) clib_net_to_host_u16 (rr->type),
1925 sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
1926 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1936 format_dns_reply (u8 * s, va_list * args)
1938 u8 *reply_as_u8 = va_arg (*args, u8 *);
1939 int verbose = va_arg (*args, int);
1947 h = (dns_header_t *) reply_as_u8;
1948 id = clib_net_to_host_u16 (h->id);
1949 flags = clib_net_to_host_u16 (h->flags);
1953 s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
1955 s = format (s, " %s %s %s %s\n",
1956 (flags & DNS_RA) ? "recur" : "no-recur",
1957 (flags & DNS_RD) ? "recur-des" : "no-recur-des",
1958 (flags & DNS_TC) ? "trunc" : "no-trunc",
1959 (flags & DNS_AA) ? "auth" : "non-auth");
1960 s = format (s, " %d queries, %d answers, %d name-servers,"
1962 clib_net_to_host_u16 (h->qdcount),
1963 clib_net_to_host_u16 (h->anscount),
1964 clib_net_to_host_u16 (h->nscount),
1965 clib_net_to_host_u16 (h->arcount));
1968 curpos = (u8 *) (h + 1);
1973 s = format (s, " Queries:\n");
1974 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
1976 /* The query is variable-length, so curpos is a value-result parm */
1977 s = format (s, "%U", format_dns_query, &curpos, verbose);
1983 s = format (s, " Replies:\n");
1985 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
1987 /* curpos is a value-result parm */
1988 s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
1989 verbose, &print_ip4, &print_ip6);
1996 format_dns_cache (u8 * s, va_list * args)
1998 dns_main_t *dm = va_arg (*args, dns_main_t *);
1999 f64 now = va_arg (*args, f64);
2000 int verbose = va_arg (*args, int);
2001 u8 *name = va_arg (*args, u8 *);
2002 dns_cache_entry_t *ep;
2006 if (dm->is_enabled == 0)
2008 s = format (s, "The DNS cache is disabled...");
2012 if (pool_elts (dm->entries) == 0)
2014 s = format (s, "The DNS cache is empty...");
2018 dns_cache_lock (dm, 6);
2022 p = hash_get_mem (dm->cache_entry_by_name, name);
2025 s = format (s, "%s is not in the cache...", name);
2026 dns_cache_unlock (dm);
2030 ep = pool_elt_at_index (dm->entries, p[0]);
2031 /* Magic to spit out a C-initializer to research hemorrhoids... */
2035 s = format (s, "static u8 dns_reply_data_initializer[] =\n");
2036 s = format (s, "{\n");
2038 for (i = 0; i < vec_len (ep->dns_response); i++)
2045 s = format (s, "0x%02x, ", ep->dns_response[i]);
2047 s = format (s, "};\n");
2051 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2053 ASSERT (ep->dns_response);
2054 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2059 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2060 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2062 s = format (s, "%s%s -> %U", ss, ep->name,
2063 format_dns_reply, ep->dns_response, verbose);
2064 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2066 f64 time_left = ep->expiration_time - now;
2067 if (time_left > 0.0)
2068 s = format (s, " TTL left %.1f", time_left);
2070 s = format (s, " EXPIRED");
2075 ASSERT (ep->dns_request);
2076 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2084 s = format (s, "DNS cache contains %d entries\n", pool_elts (dm->entries));
2089 pool_foreach (ep, dm->entries)
2091 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2093 ASSERT (ep->dns_response);
2094 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2099 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2100 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2102 s = format (s, "%s%s -> %U", ss, ep->name,
2106 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2108 f64 time_left = ep->expiration_time - now;
2109 if (time_left > 0.0)
2110 s = format (s, " TTL left %.1f", time_left);
2112 s = format (s, " EXPIRED");
2115 s = format (s, " %d client notifications pending\n",
2116 vec_len(ep->pending_requests));
2121 ASSERT (ep->dns_request);
2122 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2130 dns_cache_unlock (dm);
2135 static clib_error_t *
2136 show_dns_cache_command_fn (vlib_main_t * vm,
2137 unformat_input_t * input, vlib_cli_command_t * cmd)
2139 dns_main_t *dm = &dns_main;
2142 f64 now = vlib_time_now (vm);
2144 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2146 if (unformat (input, "verbose %d", &verbose))
2148 else if (unformat (input, "verbose"))
2150 else if (unformat (input, "name %s", &name))
2153 return clib_error_return (0, "unknown input `%U'",
2154 format_unformat_error, input);
2157 vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
2163 VLIB_CLI_COMMAND (show_dns_cache_command) =
2165 .path = "show dns cache",
2166 .short_help = "show dns cache [verbose [nn]]",
2167 .function = show_dns_cache_command_fn,
2171 static clib_error_t *
2172 show_dns_servers_command_fn (vlib_main_t * vm,
2173 unformat_input_t * input,
2174 vlib_cli_command_t * cmd)
2176 dns_main_t *dm = &dns_main;
2179 if ((vec_len (dm->ip4_name_servers) + vec_len (dm->ip6_name_servers)) == 0)
2180 return clib_error_return (0, "No name servers configured...");
2182 if (vec_len (dm->ip4_name_servers))
2184 vlib_cli_output (vm, "ip4 name servers:");
2185 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
2186 vlib_cli_output (vm, "%U", format_ip4_address,
2187 dm->ip4_name_servers + i);
2189 if (vec_len (dm->ip6_name_servers))
2191 vlib_cli_output (vm, "ip6 name servers:");
2192 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
2193 vlib_cli_output (vm, "%U", format_ip6_address,
2194 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,
2209 static clib_error_t *
2210 dns_cache_add_del_command_fn (vlib_main_t * vm,
2211 unformat_input_t * input,
2212 vlib_cli_command_t * cmd)
2214 dns_main_t *dm = &dns_main;
2220 clib_error_t *error;
2222 if (unformat (input, "add"))
2224 if (unformat (input, "del"))
2226 if (unformat (input, "clear"))
2229 if (is_add == -1 && is_clear == -1)
2230 return clib_error_return (0, "add / del / clear required...");
2234 rv = dns_cache_clear (dm);
2240 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2241 error = clib_error_return (0, "Name resolution not enabled");
2246 /* Delete (by name)? */
2249 if (unformat (input, "%v", &name))
2251 rv = dns_delete_by_name (dm, name);
2254 case VNET_API_ERROR_NO_SUCH_ENTRY:
2255 error = clib_error_return (0, "%v not in the cache...", name);
2259 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2260 error = clib_error_return (0, "Name resolution not enabled");
2269 error = clib_error_return (0, "dns_delete_by_name returned %d",
2275 return clib_error_return (0, "unknown input `%U'",
2276 format_unformat_error, input);
2279 /* Note: dns_add_static_entry consumes the name vector if OK... */
2280 if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2282 rv = dns_add_static_entry (dm, name, dns_reply_data);
2285 case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2287 vec_free (dns_reply_data);
2288 return clib_error_return (0, "%v already in the cache...", name);
2293 return clib_error_return (0, "dns_add_static_entry returned %d",
2302 VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2304 .path = "dns cache",
2305 .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2306 .function = dns_cache_add_del_command_fn,
2310 #define DNS_FORMAT_TEST 1
2312 #if DNS_FORMAT_TEST > 0
2315 static u8 dns_reply_data_initializer[] =
2316 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2317 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2319 0x0, 0xff, /* type ALL */
2320 0x0, 0x1, /* class IN */
2321 0xc0, 0xc, /* pointer to yahoo.com name */
2322 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2323 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2324 0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2325 0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2326 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2327 0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2328 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2329 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2330 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2331 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2332 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2333 0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2334 0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2336 0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2337 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2338 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2339 0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2340 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2342 0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2343 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2344 0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2345 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2347 0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2348 0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2350 0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2352 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2354 0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2356 0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2357 0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2358 0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2362 /* www.cisco.com, has no addresses in reply */
2363 static u8 dns_reply_data_initializer[] = {
2364 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2365 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2366 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2368 0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2369 0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2370 0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2371 0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2372 0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2375 /* bind8 (linux widget, w/ nasty double pointer chasees */
2376 static u8 dns_reply_data_initializer[] = {
2378 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08,
2380 0x00, 0x06, 0x00, 0x06, 0x0a, 0x6f, 0x72, 0x69,
2382 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77, 0x77, 0x05,
2384 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f,
2386 0x6d, 0x00, 0x00, 0xff, 0x00, 0x01, 0x0a, 0x6f,
2388 0x72, 0x69, 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77,
2390 0x77, 0x05, 0x43, 0x49, 0x53, 0x43, 0x4f, 0xc0,
2393 0x1d, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2396 0x9a, 0x00, 0x18, 0x15, 0x72, 0x63, 0x64,
2397 0x6e, 0x39, 0x2d, 0x31, 0x34, 0x70, 0x2d, 0x64, 0x63,
2398 0x7a, 0x30, 0x35, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31,
2399 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00, 0x01, 0x00,
2400 0x00, 0x05, 0x9a, 0x00, 0x1a, 0x17, 0x61, 0x6c, 0x6c,
2401 0x6e, 0x30, 0x31, 0x2d, 0x61, 0x67, 0x30, 0x39, 0x2d,
2402 0x64, 0x63, 0x7a, 0x30, 0x33, 0x6e, 0x2d, 0x67, 0x73,
2403 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00,
2404 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x10, 0x0d, 0x72,
2405 0x74, 0x70, 0x35, 0x2d, 0x64, 0x6d, 0x7a, 0x2d, 0x67,
2406 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2407 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x18, 0x15,
2408 0x6d, 0x74, 0x76, 0x35, 0x2d, 0x61, 0x70, 0x31, 0x30,
2409 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x36, 0x6e, 0x2d, 0x67,
2410 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2411 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x1b, 0x18,
2412 0x73, 0x6e, 0x67, 0x64, 0x63, 0x30, 0x31, 0x2d, 0x61,
2413 0x62, 0x30, 0x37, 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x31,
2414 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0,
2415 0x26, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a,
2416 0x00, 0x1a, 0x17, 0x61, 0x65, 0x72, 0x30, 0x31, 0x2d,
2417 0x72, 0x34, 0x63, 0x32, 0x35, 0x2d, 0x64, 0x63, 0x7a,
2418 0x30, 0x31, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0,
2419 0x17, 0xc0, 0x26, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2420 0x00, 0x81, 0x00, 0x04, 0x48, 0xa3, 0x04, 0xa1, 0xc0,
2421 0x26, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82,
2422 0x00, 0x10, 0x20, 0x01, 0x04, 0x20, 0x12, 0x01, 0x00,
2423 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
2424 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2425 0x9a, 0x00, 0x02, 0xc0, 0xf4, 0xc0, 0x0c, 0x00, 0x02,
2426 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0,
2427 0xcd, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00,
2428 0x05, 0x9a, 0x00, 0x02, 0xc0, 0x8d, 0xc0, 0x0c, 0x00,
2429 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02,
2430 0xc0, 0x43, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00,
2431 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0, 0xa9, 0xc0, 0x0c,
2432 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00,
2433 0x02, 0xc0, 0x67, 0xc0, 0x8d, 0x00, 0x01, 0x00, 0x01,
2434 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0x40, 0x66, 0xf6,
2435 0x05, 0xc0, 0xa9, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2436 0x07, 0x08, 0x00, 0x04, 0xad, 0x24, 0xe0, 0x64, 0xc0,
2437 0x43, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08,
2438 0x00, 0x04, 0x48, 0xa3, 0x04, 0x1c, 0xc0, 0xf4, 0x00,
2439 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04,
2440 0xad, 0x26, 0xd4, 0x6c, 0xc0, 0x67, 0x00, 0x01, 0x00,
2441 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x25,
2442 0x90, 0x64, 0xc0, 0xcd, 0x00, 0x01, 0x00, 0x01, 0x00,
2443 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x27, 0x70, 0x44,
2447 static u8 dns_reply_data_initializer[] =
2448 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
2449 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
2450 0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
2451 0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
2453 0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
2454 0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
2455 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
2456 0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
2457 0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
2458 0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
2459 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
2460 0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
2461 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
2462 0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
2463 0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
2464 0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
2465 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
2466 0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
2467 0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
2468 0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
2469 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2470 0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
2471 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
2472 0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
2473 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
2474 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
2475 0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
2477 0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2481 /* www.weatherlink.com */
2482 static u8 dns_reply_data_initializer[] = {
2483 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2484 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x0b,
2485 0x77, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x6c, 0x69,
2486 0x6e, 0x6b, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0xff,
2487 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00,
2488 0x00, 0x0c, 0x9e, 0x00, 0x1f, 0x0e, 0x64, 0x33, 0x6b,
2489 0x72, 0x30, 0x67, 0x75, 0x62, 0x61, 0x31, 0x64, 0x76,
2490 0x77, 0x66, 0x0a, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x66,
2491 0x72, 0x6f, 0x6e, 0x74, 0x03, 0x6e, 0x65, 0x74, 0x00,
2496 static clib_error_t *
2497 test_dns_fmt_command_fn (vlib_main_t * vm,
2498 unformat_input_t * input, vlib_cli_command_t * cmd)
2500 dns_resolve_name_t _rn, *rn = &_rn;
2501 u8 *dns_reply_data = 0;
2504 vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2506 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2508 if (unformat (input, "verbose %d", &verbose))
2510 else if (unformat (input, "verbose"))
2513 return clib_error_return (0, "unknown input `%U'",
2514 format_unformat_error, input);
2517 vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2519 memcpy (dns_reply_data, dns_reply_data_initializer,
2520 ARRAY_LEN (dns_reply_data_initializer));
2522 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2524 clib_memset (rmp, 0, sizeof (*rmp));
2526 rv = vnet_dns_response_to_reply (dns_reply_data, rn, 0 /* ttl-ptr */);
2530 case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2531 vlib_cli_output (vm, "no addresses found...");
2535 vlib_cli_output (vm, "response to reply returned %d", rv);
2539 vlib_cli_output (vm, "ip address: %U", format_ip_address, &rn->address);
2543 vec_free (dns_reply_data);
2550 VLIB_CLI_COMMAND (test_dns_fmt_command) =
2552 .path = "test dns format",
2553 .short_help = "test dns format",
2554 .function = test_dns_fmt_command_fn,
2558 static clib_error_t *
2559 test_dns_unfmt_command_fn (vlib_main_t * vm,
2560 unformat_input_t * input, vlib_cli_command_t * cmd)
2562 u8 *dns_reply_data = 0;
2566 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2568 if (unformat (input, "verbose %d", &verbose))
2570 else if (unformat (input, "verbose"))
2572 else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2575 return clib_error_return (0, "unknown input `%U'",
2576 format_unformat_error, input);
2580 return clib_error_return (0, "dns data not set...");
2582 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2584 vec_free (dns_reply_data);
2590 VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2592 .path = "test dns unformat",
2593 .short_help = "test dns unformat <name> [ip4][ip6]",
2594 .function = test_dns_unfmt_command_fn,
2598 static clib_error_t *
2599 test_dns_expire_command_fn (vlib_main_t * vm,
2600 unformat_input_t * input,
2601 vlib_cli_command_t * cmd)
2603 dns_main_t *dm = &dns_main;
2607 dns_cache_entry_t *ep;
2609 if (unformat (input, "%v", &name))
2612 vec_dec_len (name, 1);
2615 return clib_error_return (0, "no name provided");
2617 dns_cache_lock (dm, 7);
2619 p = hash_get_mem (dm->cache_entry_by_name, name);
2622 dns_cache_unlock (dm);
2623 e = clib_error_return (0, "%s is not in the cache...", name);
2628 ep = pool_elt_at_index (dm->entries, p[0]);
2630 ep->expiration_time = 0;
2636 VLIB_CLI_COMMAND (test_dns_expire_command) =
2638 .path = "test dns expire",
2639 .short_help = "test dns expire <name>",
2640 .function = test_dns_expire_command_fn,
2646 vnet_send_dns6_reply (vlib_main_t * vm, dns_main_t * dm,
2647 dns_pending_request_t * pr, dns_cache_entry_t * ep,
2650 clib_warning ("Unimplemented...");
2655 vnet_send_dns4_reply (vlib_main_t * vm, dns_main_t * dm,
2656 dns_pending_request_t * pr, dns_cache_entry_t * ep,
2660 ip4_address_t src_address;
2668 /* vl_api_dns_resolve_name_reply_t _rnr, *rnr = &_rnr; */
2669 dns_resolve_name_t _rn, *rn = &_rn;
2670 vl_api_dns_resolve_ip_reply_t _rir, *rir = &_rir;
2677 int is_recycle = (b0 != 0);
2679 ASSERT (ep && ep->dns_response);
2681 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2683 /* Quick and dirty way to dig up the A-record address. $$ FIXME */
2684 clib_memset (rn, 0, sizeof (*rn));
2685 if (vnet_dns_response_to_reply (ep->dns_response, rn, &ttl))
2687 /* clib_warning ("response_to_reply failed..."); */
2690 else if (ip_addr_version (&rn->address) != AF_IP4)
2692 /* clib_warning ("No A-record..."); */
2696 else if (pr->request_type == DNS_PEER_PENDING_IP_TO_NAME)
2698 clib_memset (rir, 0, sizeof (*rir));
2699 if (vnet_dns_response_to_name (ep->dns_response, rir, &ttl))
2701 /* clib_warning ("response_to_name failed..."); */
2707 clib_warning ("Unknown request type %d", pr->request_type);
2711 /* Initialize a buffer */
2714 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2716 b0 = vlib_get_buffer (vm, bi);
2720 /* Use the buffer we were handed. Reinitialize it... */
2721 vlib_buffer_t bt = { };
2722 /* push/pop the reference count */
2723 u8 save_ref_count = b0->ref_count;
2724 vlib_buffer_copy_template (b0, &bt);
2725 b0->ref_count = save_ref_count;
2726 bi = vlib_get_buffer_index (vm, b0);
2729 if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
2730 vlib_buffer_free_one (vm, b0->next_buffer);
2733 * Reset the buffer. We recycle the DNS request packet in the cache
2734 * hit case, and reply immediately from the request node.
2736 * In the resolution-required / deferred case, resetting a freshly-allocated
2737 * buffer won't hurt. We hope.
2739 b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
2740 | VLIB_BUFFER_TOTAL_LENGTH_VALID);
2741 vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; /* "local0" */
2742 vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
2744 if (!ip4_sas (0 /* default VRF for now */, ~0,
2745 (const ip4_address_t *) &pr->dst_address, &src_address))
2748 ip = vlib_buffer_get_current (b0);
2749 udp = (udp_header_t *) (ip + 1);
2750 dns_response = (u8 *) (udp + 1);
2751 clib_memset (ip, 0, sizeof (*ip) + sizeof (*udp));
2754 * Start with the variadic portion of the exercise.
2755 * Turn the name into a set of DNS "labels". Max length
2756 * per label is 63, enforce that.
2758 reply = name_to_labels (pr->name);
2759 vec_free (pr->name);
2761 qp_offset = vec_len (reply);
2763 /* Add space for the query header */
2764 vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
2766 qp = (dns_query_t *) (reply + qp_offset);
2768 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2769 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
2771 qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2773 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
2775 /* Punch in space for the dns_header_t */
2776 vec_insert (reply, sizeof (dns_header_t), 0);
2778 dh = (dns_header_t *) reply;
2780 /* Transaction ID = pool index */
2783 /* Announce that we did a recursive lookup */
2784 tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
2786 tmp |= DNS_RCODE_NAME_ERROR;
2787 dh->flags = clib_host_to_net_u16 (tmp);
2788 dh->qdcount = clib_host_to_net_u16 (1);
2789 dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
2793 /* If the name resolution worked, cough up an appropriate RR */
2796 /* Add the answer. First, a name pointer (0xC00C) */
2797 vec_add1 (reply, 0xC0);
2798 vec_add1 (reply, 0x0C);
2800 /* Now, add single A-rec RR */
2801 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2803 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
2804 rr = (dns_rr_t *) rrptr;
2806 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
2807 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2808 rr->ttl = clib_host_to_net_u32 (ttl);
2809 rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
2810 ip_address_copy_addr (rr->rdata, &rn->address);
2814 /* Or a single PTR RR */
2815 u8 *vecname = format (0, "%s", rir->name);
2816 u8 *label_vec = name_to_labels (vecname);
2819 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
2820 rr = (dns_rr_t *) rrptr;
2821 rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2822 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2823 rr->ttl = clib_host_to_net_u32 (ttl);
2824 rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
2825 clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
2826 vec_free (label_vec);
2829 clib_memcpy (dns_response, reply, vec_len (reply));
2831 /* Set the packet length */
2832 b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
2835 ip->ip_version_and_header_length = 0x45;
2836 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
2838 ip->protocol = IP_PROTOCOL_UDP;
2839 ip->src_address.as_u32 = src_address.as_u32;
2840 clib_memcpy (ip->dst_address.as_u8, pr->dst_address,
2841 sizeof (ip4_address_t));
2842 ip->checksum = ip4_header_checksum (ip);
2845 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
2846 udp->dst_port = pr->dst_port;
2847 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
2853 * Ship pkts made out of whole cloth to ip4_lookup
2854 * Caller will ship recycled dns reply packets to ip4_lookup
2856 if (is_recycle == 0)
2858 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
2859 to_next = vlib_frame_vector_args (f);
2862 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
2866 #include <dns/dns.api.c>
2867 static clib_error_t *
2868 dns_init (vlib_main_t * vm)
2870 dns_main_t *dm = &dns_main;
2872 dm->vnet_main = vnet_get_main ();
2873 dm->name_cache_size = 1000;
2874 dm->max_ttl_in_seconds = 86400;
2875 dm->random_seed = 0xDEADDABE;
2876 dm->api_main = vlibapi_get_main ();
2878 /* Ask for a correctly-sized block of API message decode slots */
2879 dm->msg_id_base = setup_message_id_table ();
2885 VLIB_INIT_FUNCTION (dns_init) = {
2886 .init_order = VLIB_INITS ("flow_classify_init", "dns_init"),
2889 VLIB_PLUGIN_REGISTER () =
2891 .version = VPP_BUILD_VER,
2892 .description = "Simple DNS name resolver",
2898 * fd.io coding-style-patch-verification: ON
2901 * eval: (c-set-style "gnu")