2 * Copyright (c) 2017 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 #include <vnet/dns/dns.h>
18 #include <vnet/vnet.h>
19 #include <vnet/fib/fib.h>
20 #include <vlibmemory/api.h>
22 #include <vnet/udp/udp.h>
24 #include <vnet/vnet_msg_enum.h>
26 #define vl_typedefs /* define message structures */
27 #include <vnet/vnet_all_api_h.h>
30 #define vl_endianfun /* define message structures */
31 #include <vnet/vnet_all_api_h.h>
34 /* instantiate all the print functions we know about */
35 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
37 #include <vnet/vnet_all_api_h.h>
40 #include <vlibapi/api_helper_macros.h>
45 dns_cache_clear (dns_main_t * dm)
47 dns_cache_entry_t *ep;
49 if (dm->is_enabled == 0)
50 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
55 pool_foreach (ep, dm->entries,
58 vec_free (ep->pending_requests);
62 pool_free (dm->entries);
63 hash_free (dm->cache_entry_by_name);
64 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
65 vec_free (dm->unresolved_entries);
66 dns_cache_unlock (dm);
71 dns_enable_disable (dns_main_t * dm, int is_enable)
73 vlib_thread_main_t *tm = &vlib_thread_main;
74 u32 n_vlib_mains = tm->n_vlib_mains;
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->cache_entry_by_name == 0)
85 dm->cache_lock = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
86 CLIB_CACHE_LINE_BYTES);
88 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
101 static void vl_api_dns_enable_disable_t_handler
102 (vl_api_dns_enable_disable_t * mp)
104 vl_api_dns_enable_disable_reply_t *rmp;
105 dns_main_t *dm = &dns_main;
108 rv = dns_enable_disable (dm, mp->enable);
110 REPLY_MACRO (VL_API_DNS_ENABLE_DISABLE_REPLY);
114 dns6_name_server_add_del (dns_main_t * dm,
115 u8 * server_address_as_u8, int is_add)
122 /* Already there? done... */
123 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
125 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
126 sizeof (ip6_address_t)))
130 vec_add2 (dm->ip6_name_servers, ap, 1);
131 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
135 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
137 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
138 sizeof (ip6_address_t)))
140 vec_delete (dm->ip6_name_servers, 1, i);
144 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
150 dns4_name_server_add_del (dns_main_t * dm,
151 u8 * server_address_as_u8, int is_add)
158 /* Already there? done... */
159 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
161 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
162 sizeof (ip4_address_t)))
166 vec_add2 (dm->ip4_name_servers, ap, 1);
167 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
171 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
173 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
174 sizeof (ip4_address_t)))
176 vec_delete (dm->ip4_name_servers, 1, i);
180 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
185 static void vl_api_dns_name_server_add_del_t_handler
186 (vl_api_dns_name_server_add_del_t * mp)
188 dns_main_t *dm = &dns_main;
189 vl_api_dns_name_server_add_del_reply_t *rmp;
193 rv = dns6_name_server_add_del (dm, mp->server_address, mp->is_add);
195 rv = dns4_name_server_add_del (dm, mp->server_address, mp->is_add);
197 REPLY_MACRO (VL_API_DNS_NAME_SERVER_ADD_DEL_REPLY);
201 send_dns4_request (dns_main_t * dm,
202 dns_cache_entry_t * ep, ip4_address_t * server)
204 vlib_main_t *vm = dm->vlib_main;
205 f64 now = vlib_time_now (vm);
210 fib_node_index_t fei;
211 u32 sw_if_index, fib_index;
213 ip4_main_t *im4 = &ip4_main;
214 ip_lookup_main_t *lm4 = &im4->lookup_main;
215 ip_interface_address_t *ia = 0;
216 ip4_address_t *src_address;
221 ASSERT (ep->dns_request);
223 /* Find a FIB path to the server */
224 clib_memcpy (&prefix.fp_addr.ip4, server, sizeof (*server));
225 prefix.fp_proto = FIB_PROTOCOL_IP4;
228 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
229 if (fib_index == (u32) ~ 0)
231 clib_warning ("no fib table");
235 fei = fib_table_lookup (fib_index, &prefix);
237 /* Couldn't find route to destination. Bail out. */
238 if (fei == FIB_NODE_INDEX_INVALID)
240 clib_warning ("no route to DNS server");
244 sw_if_index = fib_entry_get_resolving_interface (fei);
246 if (sw_if_index == ~0)
249 ("route to %U exists, fei %d, get_resolving_interface returned"
250 " ~0", fei, format_ip4_address, &prefix.fp_addr);
255 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnummbered */,
257 src_address = ip_interface_address_get_address (lm4, ia);
258 goto found_src_address;
262 clib_warning ("FIB BUG");
267 /* Go get a buffer */
268 if (vlib_buffer_alloc (dm->vlib_main, &bi, 1) != 1)
271 b = vlib_get_buffer (vm, bi);
272 b->current_length = sizeof (ip4_header_t) + sizeof (udp_header_t) +
273 vec_len (ep->dns_request);
274 b->total_length_not_including_first_buffer = 0;
276 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
277 vnet_buffer (b)->sw_if_index[VLIB_RX] = 0; /* "local0" */
278 vnet_buffer (b)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
280 ip = vlib_buffer_get_current (b);
281 memset (ip, 0, sizeof (*ip));
282 udp = (udp_header_t *) (ip + 1);
283 memset (udp, 0, sizeof (*udp));
285 dns_request = (u8 *) (udp + 1);
288 ip->ip_version_and_header_length = 0x45;
289 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b));
291 ip->protocol = IP_PROTOCOL_UDP;
292 ip->src_address.as_u32 = src_address->as_u32;
293 ip->dst_address.as_u32 = server->as_u32;
294 ip->checksum = ip4_header_checksum (ip);
297 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
298 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
299 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
300 vec_len (ep->dns_request));
303 /* The actual DNS request */
304 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
306 /* Ship it to ip4_lookup */
307 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
308 to_next = vlib_frame_vector_args (f);
311 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
313 ep->retry_timer = now + 2.0;
317 send_dns6_request (dns_main_t * dm,
318 dns_cache_entry_t * ep, ip6_address_t * server)
320 vlib_main_t *vm = dm->vlib_main;
321 f64 now = vlib_time_now (vm);
326 fib_node_index_t fei;
327 u32 sw_if_index, fib_index;
329 ip6_main_t *im6 = &ip6_main;
330 ip_lookup_main_t *lm6 = &im6->lookup_main;
331 ip_interface_address_t *ia = 0;
332 ip6_address_t *src_address;
336 int junk __attribute__ ((unused));
338 ASSERT (ep->dns_request);
340 /* Find a FIB path to the server */
341 clib_memcpy (&prefix.fp_addr, server, sizeof (*server));
342 prefix.fp_proto = FIB_PROTOCOL_IP6;
345 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
346 if (fib_index == (u32) ~ 0)
348 clib_warning ("no fib table");
352 fei = fib_table_lookup (fib_index, &prefix);
354 /* Couldn't find route to destination. Bail out. */
355 if (fei == FIB_NODE_INDEX_INVALID)
357 clib_warning ("no route to DNS server");
360 sw_if_index = fib_entry_get_resolving_interface (fei);
363 foreach_ip_interface_address(lm6, ia, sw_if_index, 1 /* honor unnummbered */,
365 src_address = ip_interface_address_get_address (lm6, ia);
366 goto found_src_address;
370 clib_warning ("FIB BUG");
375 /* Go get a buffer */
376 if (vlib_buffer_alloc (dm->vlib_main, &bi, 1) != 1)
379 b = vlib_get_buffer (vm, bi);
380 b->current_length = sizeof (ip6_header_t) + sizeof (udp_header_t) +
381 vec_len (ep->dns_request);
382 b->total_length_not_including_first_buffer = 0;
384 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
386 ip = vlib_buffer_get_current (b);
387 memset (ip, 0, sizeof (*ip));
388 udp = (udp_header_t *) (ip + 1);
389 memset (udp, 0, sizeof (*udp));
391 dns_request = (u8 *) (udp + 1);
394 ip->ip_version_traffic_class_and_flow_label =
395 clib_host_to_net_u32 (0x6 << 28);
398 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b)
399 - sizeof (ip6_header_t));
401 ip->protocol = IP_PROTOCOL_UDP;
402 clib_memcpy (&ip->src_address, src_address, sizeof (ip6_address_t));
403 clib_memcpy (&ip->dst_address, server, sizeof (ip6_address_t));
406 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
407 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
408 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
409 vec_len (ep->dns_request));
411 udp->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ip, &junk);
413 /* The actual DNS request */
414 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
416 /* Ship it to ip6_lookup */
417 f = vlib_get_frame_to_node (vm, ip6_lookup_node.index);
418 to_next = vlib_frame_vector_args (f);
422 ep->retry_timer = now + 2.0;
426 * Translate "foo.com" into "0x3 f o o 0x3 c o m 0x0"
427 * A historical / hysterical micro-TLV scheme. DGMS.
430 name_to_labels (u8 * name)
433 int last_label_index;
438 /* punch in space for the first length */
439 vec_insert (rv, 1, 0);
440 last_label_index = 0;
443 while (i < vec_len (rv))
447 rv[last_label_index] = (i - last_label_index) - 1;
448 if ((i - last_label_index) > 63)
449 clib_warning ("stupid name, label length %d",
450 i - last_label_index);
451 last_label_index = i;
456 /* Set the last real label length */
457 rv[last_label_index] = (i - last_label_index) - 1;
460 * Add a [sic] NULL root label. Otherwise, the name parser can't figure out
468 * arc-function for the above.
469 * Translate "0x3 f o o 0x3 c o m 0x0" into "foo.com"
470 * Produces a non-NULL-terminated u8 *vector. %v format is your friend.
473 vnet_dns_labels_to_name (u8 * label, u8 * full_text, u8 ** parse_from_here)
480 *parse_from_here = 0;
482 /* chase initial pointer? */
483 if ((label[0] & 0xC0) == 0xC0)
485 *parse_from_here = label + 2;
486 offset = ((label[0] & 0x3f) << 8) + label[1];
487 label = full_text + offset;
494 for (i = 0; i < len; i++)
495 vec_add1 (reply, *label++);
498 if ((label[0] & 0xC0) == 0xC0)
500 *parse_from_here = label + 2;
501 offset = ((label[0] & 0x3f) << 8) + label[1];
502 label = full_text + offset;
507 vec_add1 (reply, '.');
509 if (*parse_from_here == 0)
510 *parse_from_here = label;
515 vnet_send_dns_request (dns_main_t * dm, dns_cache_entry_t * ep)
523 /* This can easily happen if sitting in GDB, etc. */
524 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
527 /* Construct the dns request, if we haven't been here already */
528 if (vec_len (ep->dns_request) == 0)
531 * Start with the variadic portion of the exercise.
532 * Turn the name into a set of DNS "labels". Max length
533 * per label is 63, enforce that.
535 request = name_to_labels (ep->name);
536 qp_offset = vec_len (request);
538 /* Add space for the query header */
539 vec_validate (request, qp_offset + sizeof (dns_query_t) - 1);
541 qp = (dns_query_t *) (request + qp_offset);
543 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
544 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
546 /* Punch in space for the dns_header_t */
547 vec_insert (request, sizeof (dns_header_t), 0);
549 h = (dns_header_t *) request;
551 /* Transaction ID = pool index */
552 h->id = clib_host_to_net_u16 (ep - dm->entries);
554 /* Ask for a recursive lookup */
555 tmp = DNS_RD | DNS_OPCODE_QUERY;
556 h->flags = clib_host_to_net_u16 (tmp);
557 h->qdcount = clib_host_to_net_u16 (1);
561 ep->dns_request = request;
564 /* Work out which server / address family we're going to use */
566 /* Retry using current server */
567 if (ep->retry_count++ < DNS_RETRIES_PER_SERVER)
569 if (ep->server_af == 1 /* ip6 */ )
571 if (vec_len (dm->ip6_name_servers))
573 send_dns6_request (dm, ep,
574 dm->ip6_name_servers + ep->server_rotor);
580 if (vec_len (dm->ip4_name_servers))
582 send_dns4_request (dm, ep, dm->ip4_name_servers + ep->server_rotor);
586 else /* switch to a new server */
590 if (ep->server_af == 1 /* ip6 */ )
592 if (ep->server_rotor >= vec_len (dm->ip6_name_servers))
594 ep->server_rotor = 0;
595 ep->server_af = vec_len (dm->ip4_name_servers) > 0 ? 0 : 1;
600 if (ep->server_rotor >= vec_len (dm->ip4_name_servers))
602 ep->server_rotor = 0;
603 ep->server_af = vec_len (dm->ip6_name_servers) > 0 ? 1 : 0;
608 if (ep->server_af == 1 /* ip6 */ )
609 send_dns6_request (dm, ep, dm->ip6_name_servers + ep->server_rotor);
611 send_dns4_request (dm, ep, dm->ip4_name_servers + ep->server_rotor);
615 vlib_process_signal_event_mt (dm->vlib_main, dns_resolver_node.index,
616 DNS_RESOLVER_EVENT_PENDING, 0);
620 vnet_dns_delete_entry_by_index_nolock (dns_main_t * dm, u32 index)
622 dns_cache_entry_t *ep;
625 if (dm->is_enabled == 0)
626 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
628 if (pool_is_free_index (dm->entries, index))
629 return VNET_API_ERROR_NO_SUCH_ENTRY;
631 ep = pool_elt_at_index (dm->entries, index);
632 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_VALID))
634 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
635 if (index == dm->unresolved_entries[i])
637 vec_delete (dm->unresolved_entries, 1, i);
640 clib_warning ("pool elt %d supposedly pending, but not found...",
645 hash_unset_mem (dm->cache_entry_by_name, ep->name);
647 vec_free (ep->pending_requests);
648 pool_put (dm->entries, ep);
654 dns_delete_by_name (dns_main_t * dm, u8 * name)
659 if (dm->is_enabled == 0)
660 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
663 p = hash_get_mem (dm->cache_entry_by_name, name);
666 dns_cache_unlock (dm);
667 return VNET_API_ERROR_NO_SUCH_ENTRY;
669 rv = vnet_dns_delete_entry_by_index_nolock (dm, p[0]);
671 dns_cache_unlock (dm);
677 delete_random_entry (dns_main_t * dm)
680 u32 victim_index, start_index, i;
682 dns_cache_entry_t *ep;
684 if (dm->is_enabled == 0)
685 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
688 * Silence spurious coverity warning. We know pool_elts >> 0, or
689 * we wouldn't be here...
692 if (pool_elts (dm->entries) == 0)
693 return VNET_API_ERROR_UNSPECIFIED;
697 limit = pool_elts (dm->entries);
698 start_index = random_u32 (&dm->random_seed) % limit;
700 for (i = 0; i < limit; i++)
702 victim_index = (start_index + i) % limit;
704 if (!pool_is_free_index (dm->entries, victim_index))
706 ep = pool_elt_at_index (dm->entries, victim_index);
707 /* Delete only valid, non-static entries */
708 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
709 && ((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0))
711 rv = vnet_dns_delete_entry_by_index_nolock (dm, victim_index);
712 dns_cache_unlock (dm);
717 dns_cache_unlock (dm);
719 clib_warning ("Couldn't find an entry to delete?");
720 return VNET_API_ERROR_UNSPECIFIED;
724 dns_add_static_entry (dns_main_t * dm, u8 * name, u8 * dns_reply_data)
726 dns_cache_entry_t *ep;
730 if (dm->is_enabled == 0)
731 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
734 p = hash_get_mem (dm->cache_entry_by_name, name);
737 dns_cache_unlock (dm);
738 return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
741 if (pool_elts (dm->entries) == dm->name_cache_size)
743 /* Will only fail if the cache is totally filled w/ static entries... */
744 rv = delete_random_entry (dm);
747 dns_cache_unlock (dm);
752 pool_get (dm->entries, ep);
753 memset (ep, 0, sizeof (*ep));
755 /* Note: consumes the name vector */
757 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
758 ep->flags = DNS_CACHE_ENTRY_FLAG_VALID | DNS_CACHE_ENTRY_FLAG_STATIC;
759 ep->dns_response = dns_reply_data;
761 dns_cache_unlock (dm);
766 vnet_dns_resolve_name (dns_main_t * dm, u8 * name, dns_pending_request_t * t,
767 dns_cache_entry_t ** retp)
769 dns_cache_entry_t *ep;
773 dns_pending_request_t *pr;
776 now = vlib_time_now (dm->vlib_main);
778 /* In case we can't actually answer the question right now... */
783 p = hash_get_mem (dm->cache_entry_by_name, name);
786 ep = pool_elt_at_index (dm->entries, p[0]);
787 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
789 /* Has the entry expired? */
790 if (((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0)
791 && (now > ep->expiration_time))
794 u32 *indices_to_delete = 0;
797 * Take out the rest of the resolution chain
798 * This isn't optimal, but it won't happen very often.
802 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME))
804 vec_add1 (indices_to_delete, ep - dm->entries);
806 p = hash_get_mem (dm->cache_entry_by_name, ep->cname);
809 ep = pool_elt_at_index (dm->entries, p[0]);
813 vec_add1 (indices_to_delete, ep - dm->entries);
817 for (i = 0; i < vec_len (indices_to_delete); i++)
819 /* Reenable to watch re-resolutions */
822 ep = pool_elt_at_index (dm->entries,
823 indices_to_delete[i]);
824 clib_warning ("Re-resolve %s", ep->name);
827 vnet_dns_delete_entry_by_index_nolock
828 (dm, indices_to_delete[i]);
830 vec_free (indices_to_delete);
831 /* Yes, kill it... */
835 if (ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
841 /* Note: caller must drop the lock! */
848 * Resolution pending. Add request to the pending vector
849 * by copying the template request
851 vec_add2 (ep->pending_requests, pr, 1);
852 memcpy (pr, t, sizeof (*pr));
853 dns_cache_unlock (dm);
859 if (pool_elts (dm->entries) == dm->name_cache_size)
861 /* Will only fail if the cache is totally filled w/ static entries... */
862 rv = delete_random_entry (dm);
865 dns_cache_unlock (dm);
870 /* add new hash table entry */
871 pool_get (dm->entries, ep);
872 memset (ep, 0, sizeof (*ep));
874 ep->name = format (0, "%s%c", name, 0);
875 _vec_len (ep->name) = vec_len (ep->name) - 1;
877 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
879 vec_add1 (dm->unresolved_entries, ep - dm->entries);
880 vec_add2 (ep->pending_requests, pr, 1);
882 pr->request_type = t->request_type;
884 /* Remember details so we can reply later... */
885 if (t->request_type == DNS_API_PENDING_NAME_TO_IP ||
886 t->request_type == DNS_API_PENDING_IP_TO_NAME)
888 pr->client_index = t->client_index;
889 pr->client_context = t->client_context;
893 pr->client_index = ~0;
894 pr->is_ip6 = t->is_ip6;
895 pr->dst_port = t->dst_port;
902 clib_memcpy (pr->dst_address, t->dst_address, count);
905 vnet_send_dns_request (dm, ep);
906 dns_cache_unlock (dm);
910 #define foreach_notification_to_move \
914 * Handle cname indirection. JFC. Called with the cache locked.
915 * returns 0 if the reply is not a CNAME.
919 vnet_dns_cname_indirection_nolock (dns_main_t * dm, u32 ep_index, u8 * reply)
932 dns_cache_entry_t *ep, *next_ep;
935 h = (dns_header_t *) reply;
936 flags = clib_net_to_host_u16 (h->flags);
937 rcode = flags & DNS_RCODE_MASK;
939 /* See if the response is OK */
942 case DNS_RCODE_NO_ERROR:
945 case DNS_RCODE_NAME_ERROR:
946 case DNS_RCODE_FORMAT_ERROR:
947 case DNS_RCODE_SERVER_FAILURE:
948 case DNS_RCODE_NOT_IMPLEMENTED:
949 case DNS_RCODE_REFUSED:
953 curpos = (u8 *) (h + 1);
957 /* Skip the questions */
958 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
965 pos += sizeof (dns_query_t);
968 /* expect a pointer chase here for a CNAME record */
969 if ((pos2[0] & 0xC0) == 0xC0)
974 rr = (dns_rr_t *) pos;
976 /* This is a real record, not a CNAME record */
977 if (clib_net_to_host_u16 (rr->type) != DNS_TYPE_CNAME)
980 /* This is a CNAME record, chase the name chain. */
982 /* The last request is no longer pending.. */
983 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
984 if (ep_index == dm->unresolved_entries[i])
986 vec_delete (dm->unresolved_entries, 1, i);
987 goto found_last_request;
989 clib_warning ("pool elt %d supposedly pending, but not found...", ep_index);
993 now = vlib_time_now (dm->vlib_main);
994 cname = vnet_dns_labels_to_name (rr->rdata, reply, &pos2);
997 _vec_len (cname) -= 1;
998 ep = pool_elt_at_index (dm->entries, ep_index);
1000 ep->flags |= (DNS_CACHE_ENTRY_FLAG_CNAME | DNS_CACHE_ENTRY_FLAG_VALID);
1001 /* Save the response */
1002 ep->dns_response = reply;
1003 /* Set up expiration time */
1004 ep->expiration_time = now + clib_net_to_host_u32 (rr->ttl);
1006 pool_get (dm->entries, next_ep);
1008 /* Need to recompute ep post pool-get */
1009 ep = pool_elt_at_index (dm->entries, ep_index);
1011 memset (next_ep, 0, sizeof (*next_ep));
1012 next_ep->name = vec_dup (cname);
1013 vec_add1 (next_ep->name, 0);
1014 _vec_len (next_ep->name) -= 1;
1016 hash_set_mem (dm->cache_entry_by_name, next_ep->name,
1017 next_ep - dm->entries);
1019 /* Use the same server */
1020 next_ep->server_rotor = ep->server_rotor;
1021 next_ep->server_af = ep->server_af;
1023 /* Move notification data to the next name in the chain */
1024 #define _(a) next_ep->a = ep->a; ep->a = 0;
1025 foreach_notification_to_move;
1028 request = name_to_labels (cname);
1030 qp_offset = vec_len (request);
1032 /* Add space for the query header */
1033 vec_validate (request, qp_offset + sizeof (dns_query_t) - 1);
1035 qp = (dns_query_t *) (request + qp_offset);
1037 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1038 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1040 /* Punch in space for the dns_header_t */
1041 vec_insert (request, sizeof (dns_header_t), 0);
1043 h = (dns_header_t *) request;
1045 /* Transaction ID = pool index */
1046 h->id = clib_host_to_net_u16 (next_ep - dm->entries);
1048 /* Ask for a recursive lookup */
1049 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
1050 h->qdcount = clib_host_to_net_u16 (1);
1054 next_ep->dns_request = request;
1055 next_ep->retry_timer = now + 2.0;
1056 next_ep->retry_count = 0;
1059 * Enable this to watch recursive resolution happen...
1060 * fformat (stdout, "%U", format_dns_reply, request, 2);
1063 vec_add1 (dm->unresolved_entries, next_ep - dm->entries);
1064 vnet_send_dns_request (dm, next_ep);
1069 vnet_dns_response_to_reply (u8 * response,
1070 vl_api_dns_resolve_name_reply_t * rmp,
1078 u8 *curpos, *pos, *pos2;
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 memcpy (rmp->ip4_address, rr->rdata, sizeof (ip4_address_t));
1181 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 memcpy (rmp->ip6_address, rr->rdata, sizeof (ip6_address_t));
1188 ttl = clib_net_to_host_u32 (rr->ttl);
1189 if (min_ttlp && *min_ttlp > ttl)
1197 /* Might as well stop ASAP */
1198 if (rmp->ip4_set && rmp->ip6_set)
1200 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1204 if ((rmp->ip4_set + rmp->ip6_set) == 0)
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 vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1348 dns_main_t *dm = &dns_main;
1349 vl_api_dns_resolve_name_reply_t *rmp;
1350 dns_cache_entry_t *ep;
1351 dns_pending_request_t _t0, *t0 = &_t0;
1354 /* Sanitize the name slightly */
1355 mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1357 t0->request_type = DNS_API_PENDING_NAME_TO_IP;
1358 t0->client_index = mp->client_index;
1359 t0->client_context = mp->context;
1361 rv = vnet_dns_resolve_name (dm, mp->name, t0, &ep);
1363 /* Error, e.g. not enabled? Tell the user */
1366 REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1370 /* Resolution pending? Don't reply... */
1375 REPLY_MACRO2(VL_API_DNS_RESOLVE_NAME_REPLY,
1377 rv = vnet_dns_response_to_reply (ep->dns_response, rmp, 0 /* ttl-ptr */);
1378 rmp->retval = clib_host_to_net_u32 (rv);
1383 * dns_resolve_name leaves the cache locked when it returns
1384 * a cached result, so unlock it here.
1386 dns_cache_unlock (dm);
1390 vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
1392 dns_main_t *dm = &dns_main;
1393 vl_api_dns_resolve_ip_reply_t *rmp;
1394 dns_cache_entry_t *ep;
1397 u8 *lookup_name = 0;
1399 dns_pending_request_t _t0, *t0 = &_t0;
1403 for (i = 15; i >= 0; i--)
1405 digit = mp->address[i];
1406 nybble = (digit & 0x0F);
1408 vec_add1 (lookup_name, (nybble - 10) + 'a');
1410 vec_add1 (lookup_name, nybble + '0');
1411 vec_add1 (lookup_name, '.');
1412 nybble = (digit & 0xF0) >> 4;
1414 vec_add1 (lookup_name, (nybble - 10) + 'a');
1416 vec_add1 (lookup_name, nybble + '0');
1417 vec_add1 (lookup_name, '.');
1419 len = vec_len (lookup_name);
1420 vec_validate (lookup_name, len + 8);
1421 memcpy (lookup_name + len, "ip6.arpa", 8);
1425 for (i = 3; i >= 0; i--)
1427 digit = mp->address[i];
1428 lookup_name = format (lookup_name, "%d.", digit);
1430 lookup_name = format (lookup_name, "in-addr.arpa");
1433 vec_add1 (lookup_name, 0);
1435 t0->request_type = DNS_API_PENDING_IP_TO_NAME;
1436 t0->client_index = mp->client_index;
1437 t0->client_context = mp->context;
1439 rv = vnet_dns_resolve_name (dm, lookup_name, t0, &ep);
1441 vec_free (lookup_name);
1443 /* Error, e.g. not enabled? Tell the user */
1446 REPLY_MACRO (VL_API_DNS_RESOLVE_IP_REPLY);
1450 /* Resolution pending? Don't reply... */
1455 REPLY_MACRO2(VL_API_DNS_RESOLVE_IP_REPLY,
1457 rv = vnet_dns_response_to_name (ep->dns_response, rmp, 0 /* ttl-ptr */);
1458 rmp->retval = clib_host_to_net_u32 (rv);
1463 * vnet_dns_resolve_name leaves the cache locked when it returns
1464 * a cached result, so unlock it here.
1466 dns_cache_unlock (dm);
1469 #define vl_msg_name_crc_list
1470 #include <vpp/api/vpe_all_api_h.h>
1471 #undef vl_msg_name_crc_list
1474 setup_message_id_table (api_main_t * am)
1476 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1477 foreach_vl_msg_name_crc_dns;
1481 #define foreach_dns_api_msg \
1482 _(DNS_ENABLE_DISABLE, dns_enable_disable) \
1483 _(DNS_NAME_SERVER_ADD_DEL, dns_name_server_add_del) \
1484 _(DNS_RESOLVE_NAME, dns_resolve_name) \
1485 _(DNS_RESOLVE_IP, dns_resolve_ip)
1487 static clib_error_t *
1488 dns_api_hookup (vlib_main_t * vm)
1491 vl_msg_api_set_handlers(VL_API_##N, #n, \
1492 vl_api_##n##_t_handler, \
1494 vl_api_##n##_t_endian, \
1495 vl_api_##n##_t_print, \
1496 sizeof(vl_api_##n##_t), 1);
1497 foreach_dns_api_msg;
1500 setup_message_id_table (&api_main);
1504 VLIB_API_INIT_FUNCTION (dns_api_hookup);
1507 static clib_error_t *
1508 dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1510 dns_main_t *dm = &dns_main;
1512 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1514 if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1516 else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1519 return clib_error_return (0, "unknown input `%U'",
1520 format_unformat_error, input);
1525 VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1527 static clib_error_t *
1528 dns_init (vlib_main_t * vm)
1530 dns_main_t *dm = &dns_main;
1533 dm->vnet_main = vnet_get_main ();
1534 dm->name_cache_size = 65535;
1535 dm->max_ttl_in_seconds = 86400;
1536 dm->random_seed = 0xDEADDABE;
1538 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply, dns46_reply_node.index,
1541 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply6, dns46_reply_node.index,
1544 udp_register_dst_port (vm, UDP_DST_PORT_dns, dns4_request_node.index,
1547 udp_register_dst_port (vm, UDP_DST_PORT_dns6, dns6_request_node.index,
1552 VLIB_INIT_FUNCTION (dns_init);
1555 unformat_dns_reply (unformat_input_t * input, va_list * args)
1557 u8 **result = va_arg (*args, u8 **);
1558 u8 **namep = va_arg (*args, u8 **);
1572 if (unformat (input, "%v", &name))
1575 if (unformat (input, "%U", unformat_ip4_address, &a4))
1578 if (unformat (input, "%U", unformat_ip6_address, &a6))
1582 if (unformat (input, "%U", unformat_ip6_address, &a6))
1585 if (unformat (input, "%U", unformat_ip4_address, &a6))
1589 /* Must have a name */
1593 /* Must have at least one address */
1594 if (!(a4_set + a6_set))
1597 /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1598 ce = name_to_labels (name);
1599 qp_offset = vec_len (ce);
1601 /* Add space for the query header */
1602 vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1603 qp = (dns_query_t *) (ce + qp_offset);
1605 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1606 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1608 /* Punch in space for the dns_header_t */
1609 vec_insert (ce, sizeof (dns_header_t), 0);
1611 h = (dns_header_t *) ce;
1613 /* Fake Transaction ID */
1616 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1617 h->qdcount = clib_host_to_net_u16 (1);
1618 h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1622 /* Now append one or two A/AAAA RR's... */
1625 /* Pointer to the name (DGMS) */
1626 vec_add1 (ce, 0xC0);
1627 vec_add1 (ce, 0x0C);
1628 vec_add2 (ce, rru8, sizeof (*rr) + 4);
1630 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1631 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1632 rr->ttl = clib_host_to_net_u32 (86400);
1633 rr->rdlength = clib_host_to_net_u16 (4);
1634 memcpy (rr->rdata, &a4, sizeof (a4));
1638 /* Pointer to the name (DGMS) */
1639 vec_add1 (ce, 0xC0);
1640 vec_add1 (ce, 0x0C);
1641 vec_add2 (ce, rru8, sizeof (*rr) + 16);
1643 rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1644 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1645 rr->ttl = clib_host_to_net_u32 (86400);
1646 rr->rdlength = clib_host_to_net_u16 (16);
1647 memcpy (rr->rdata, &a6, sizeof (a6));
1659 format_dns_query (u8 * s, va_list * args)
1661 u8 **curpos = va_arg (*args, u8 **);
1662 int verbose = va_arg (*args, int);
1667 s = format (s, " Name: ");
1669 /* Unwind execrated counted-label sheit */
1675 for (i = 0; i < len; i++)
1676 vec_add1 (s, *pos++);
1688 qp = (dns_query_t *) pos;
1691 switch (clib_net_to_host_u16 (qp->type))
1694 s = format (s, "type A\n");
1697 s = format (s, "type AAAA\n");
1700 s = format (s, "type ALL\n");
1704 s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1709 pos += sizeof (*qp);
1716 * format dns reply data
1717 * verbose > 1, dump everything
1718 * verbose == 1, dump all A and AAAA records
1719 * verbose == 0, dump one A record, and one AAAA record
1723 format_dns_reply_data (u8 * s, va_list * args)
1725 u8 *reply = va_arg (*args, u8 *);
1726 u8 **curpos = va_arg (*args, u8 **);
1727 int verbose = va_arg (*args, int);
1728 int *print_ip4 = va_arg (*args, int *);
1729 int *print_ip6 = va_arg (*args, int *);
1734 int pointer_chase = 0;
1736 u16 rrtype_host_byte_order;
1738 pos = pos2 = *curpos;
1741 s = format (s, " ");
1743 /* chase pointer? almost always yes here... */
1744 if ((pos2[0] & 0xc0) == 0xc0)
1747 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1755 for (i = 0; i < len; i++)
1758 vec_add1 (s, *pos2);
1761 if ((pos2[0] & 0xc0) == 0xc0)
1764 * If we've already done one pointer chase,
1765 * do not move the pos pointer.
1767 if (pointer_chase == 0)
1769 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1787 if (pointer_chase == 0)
1790 rr = (dns_rr_t *) pos;
1791 rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
1793 switch (rrtype_host_byte_order)
1798 s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1799 format_ip4_address, rr->rdata);
1804 s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1805 clib_net_to_host_u32 (rr->ttl));
1810 pos += sizeof (*rr) + 4;
1816 s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1817 format_ip6_address, rr->rdata);
1822 s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1823 clib_net_to_host_u32 (rr->ttl));
1827 pos += sizeof (*rr) + 16;
1833 s = format (s, "TEXT: ");
1834 for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1835 vec_add1 (s, rr->rdata[i]);
1838 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1841 case DNS_TYPE_HINFO:
1843 /* Two counted strings. DGMS */
1849 s = format (s, "HINFO: ");
1852 for (i = 0; i < *len; i++)
1853 vec_add1 (s, *curpos++);
1857 for (i = 0; i < *len; i++)
1858 vec_add1 (s, *curpos++);
1863 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1866 case DNS_TYPE_NAMESERVER:
1869 s = format (s, "Nameserver: ");
1872 /* chase pointer? */
1873 if ((pos2[0] & 0xc0) == 0xc0)
1876 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1883 for (i = 0; i < len; i++)
1884 vec_add1 (s, *pos2++);
1886 /* chase pointer, typically to offset 12... */
1887 if (pos2[0] == 0xC0)
1888 pos2 = reply + pos2[1];
1897 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1900 case DNS_TYPE_MAIL_EXCHANGE:
1903 tp = (u16 *) rr->rdata;
1905 s = format (s, "Mail Exchange: Preference %d ", (u32)
1906 clib_net_to_host_u16 (*tp));
1908 pos2 = rr->rdata + 2;
1910 /* chase pointer? */
1911 if (pos2[0] == 0xc0)
1912 pos2 = reply + pos2[1];
1918 for (i = 0; i < len; i++)
1919 vec_add1 (s, *pos2++);
1922 if (pos2[0] == 0xC0)
1923 pos2 = reply + pos2[1];
1933 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1937 case DNS_TYPE_CNAME:
1940 tp = (u16 *) rr->rdata;
1942 if (rrtype_host_byte_order == DNS_TYPE_CNAME)
1943 s = format (s, "CNAME: ");
1945 s = format (s, "PTR: ");
1949 /* chase pointer? */
1950 if (pos2[0] == 0xc0)
1951 pos2 = reply + pos2[1];
1957 for (i = 0; i < len; i++)
1958 vec_add1 (s, *pos2++);
1961 if (pos2[0] == 0xC0)
1962 pos2 = reply + pos2[1];
1971 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1976 s = format (s, "type %d: len %d\n",
1977 (int) clib_net_to_host_u16 (rr->type),
1978 sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
1979 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1989 format_dns_reply (u8 * s, va_list * args)
1991 u8 *reply_as_u8 = va_arg (*args, u8 *);
1992 int verbose = va_arg (*args, int);
2000 h = (dns_header_t *) reply_as_u8;
2001 id = clib_net_to_host_u16 (h->id);
2002 flags = clib_net_to_host_u16 (h->flags);
2006 s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
2008 s = format (s, " %s %s %s %s\n",
2009 (flags & DNS_RA) ? "recur" : "no-recur",
2010 (flags & DNS_RD) ? "recur-des" : "no-recur-des",
2011 (flags & DNS_TC) ? "trunc" : "no-trunc",
2012 (flags & DNS_AA) ? "auth" : "non-auth");
2013 s = format (s, " %d queries, %d answers, %d name-servers,"
2015 clib_net_to_host_u16 (h->qdcount),
2016 clib_net_to_host_u16 (h->anscount),
2017 clib_net_to_host_u16 (h->nscount),
2018 clib_net_to_host_u16 (h->arcount));
2021 curpos = (u8 *) (h + 1);
2026 s = format (s, " Queries:\n");
2027 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
2029 /* The query is variable-length, so curpos is a value-result parm */
2030 s = format (s, "%U", format_dns_query, &curpos, verbose);
2036 s = format (s, " Replies:\n");
2038 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
2040 /* curpos is a value-result parm */
2041 s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
2042 verbose, &print_ip4, &print_ip6);
2049 format_dns_cache (u8 * s, va_list * args)
2051 dns_main_t *dm = va_arg (*args, dns_main_t *);
2052 f64 now = va_arg (*args, f64);
2053 int verbose = va_arg (*args, int);
2054 u8 *name = va_arg (*args, u8 *);
2055 dns_cache_entry_t *ep;
2059 if (dm->is_enabled == 0)
2061 s = format (s, "The DNS cache is disabled...");
2065 if (pool_elts (dm->entries) == 0)
2067 s = format (s, "The DNS cache is empty...");
2071 dns_cache_lock (dm);
2075 p = hash_get_mem (dm->cache_entry_by_name, name);
2078 s = format (s, "%s is not in the cache...", name);
2079 dns_cache_unlock (dm);
2083 ep = pool_elt_at_index (dm->entries, p[0]);
2084 /* Magic to spit out a C-initializer to research hemorrhoids... */
2088 s = format (s, "static u8 dns_reply_data_initializer[] =\n");
2089 s = format (s, "{\n");
2091 for (i = 0; i < vec_len (ep->dns_response); i++)
2098 s = format (s, "0x%02x, ", ep->dns_response[i]);
2100 s = format (s, "};\n");
2104 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2106 ASSERT (ep->dns_response);
2107 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2112 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2113 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2115 s = format (s, "%s%s -> %U", ss, ep->name,
2116 format_dns_reply, ep->dns_response, verbose);
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");
2128 ASSERT (ep->dns_request);
2129 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2138 pool_foreach (ep, dm->entries,
2140 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2142 ASSERT (ep->dns_response);
2143 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2148 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2149 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2151 s = format (s, "%s%s -> %U", ss, ep->name,
2155 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2157 f64 time_left = ep->expiration_time - now;
2158 if (time_left > 0.0)
2159 s = format (s, " TTL left %.1f", time_left);
2161 s = format (s, " EXPIRED");
2164 s = format (s, " %d client notifications pending\n",
2165 vec_len(ep->pending_requests));
2170 ASSERT (ep->dns_request);
2171 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2178 dns_cache_unlock (dm);
2183 static clib_error_t *
2184 show_dns_cache_command_fn (vlib_main_t * vm,
2185 unformat_input_t * input, vlib_cli_command_t * cmd)
2187 dns_main_t *dm = &dns_main;
2190 f64 now = vlib_time_now (vm);
2192 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2194 if (unformat (input, "verbose %d", &verbose))
2196 else if (unformat (input, "verbose"))
2198 else if (unformat (input, "name %s", &name))
2201 return clib_error_return (0, "unknown input `%U'",
2202 format_unformat_error, input);
2205 vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
2211 VLIB_CLI_COMMAND (show_dns_cache_command) =
2213 .path = "show dns cache",
2214 .short_help = "show dns cache [verbose [nn]]",
2215 .function = show_dns_cache_command_fn,
2219 static clib_error_t *
2220 dns_cache_add_del_command_fn (vlib_main_t * vm,
2221 unformat_input_t * input,
2222 vlib_cli_command_t * cmd)
2224 dns_main_t *dm = &dns_main;
2230 clib_error_t *error;
2232 if (unformat (input, "add"))
2234 if (unformat (input, "del"))
2236 if (unformat (input, "clear"))
2239 if (is_add == -1 && is_clear == -1)
2240 return clib_error_return (0, "add / del / clear required...");
2244 rv = dns_cache_clear (dm);
2250 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2251 error = clib_error_return (0, "Name resolution not enabled");
2256 /* Delete (by name)? */
2259 if (unformat (input, "%v", &name))
2261 rv = dns_delete_by_name (dm, name);
2264 case VNET_API_ERROR_NO_SUCH_ENTRY:
2265 error = clib_error_return (0, "%v not in the cache...", name);
2269 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2270 error = clib_error_return (0, "Name resolution not enabled");
2279 error = clib_error_return (0, "dns_delete_by_name returned %d",
2285 return clib_error_return (0, "unknown input `%U'",
2286 format_unformat_error, input);
2289 /* Note: dns_add_static_entry consumes the name vector if OK... */
2290 if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2292 rv = dns_add_static_entry (dm, name, dns_reply_data);
2295 case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2297 vec_free (dns_reply_data);
2298 return clib_error_return (0, "%v already in the cache...", name);
2303 return clib_error_return (0, "dns_add_static_entry returned %d",
2312 VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2314 .path = "dns cache",
2315 .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2316 .function = dns_cache_add_del_command_fn,
2320 #define DNS_FORMAT_TEST 0
2322 #if DNS_FORMAT_TEST > 0
2325 static u8 dns_reply_data_initializer[] =
2326 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2327 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2329 0x0, 0xff, /* type ALL */
2330 0x0, 0x1, /* class IN */
2331 0xc0, 0xc, /* pointer to yahoo.com name */
2332 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2333 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2334 0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2335 0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2336 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2337 0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2338 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2339 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2340 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2341 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2342 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2343 0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2344 0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2346 0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2347 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2348 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2349 0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2350 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2352 0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2353 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2354 0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2355 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2357 0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2358 0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2360 0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2362 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2364 0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2366 0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2367 0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2368 0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2372 /* www.cisco.com, has no addresses in reply */
2373 static u8 dns_reply_data_initializer[] = {
2374 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2375 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2376 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2378 0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2379 0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2380 0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2381 0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2382 0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2385 /* bind8 (linux widget, w/ nasty double pointer chasees */
2386 static u8 dns_reply_data_initializer[] = {
2388 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08,
2390 0x00, 0x06, 0x00, 0x06, 0x0a, 0x6f, 0x72, 0x69,
2392 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77, 0x77, 0x05,
2394 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f,
2396 0x6d, 0x00, 0x00, 0xff, 0x00, 0x01, 0x0a, 0x6f,
2398 0x72, 0x69, 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77,
2400 0x77, 0x05, 0x43, 0x49, 0x53, 0x43, 0x4f, 0xc0,
2403 0x1d, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2406 0x9a, 0x00, 0x18, 0x15, 0x72, 0x63, 0x64,
2407 0x6e, 0x39, 0x2d, 0x31, 0x34, 0x70, 0x2d, 0x64, 0x63,
2408 0x7a, 0x30, 0x35, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31,
2409 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00, 0x01, 0x00,
2410 0x00, 0x05, 0x9a, 0x00, 0x1a, 0x17, 0x61, 0x6c, 0x6c,
2411 0x6e, 0x30, 0x31, 0x2d, 0x61, 0x67, 0x30, 0x39, 0x2d,
2412 0x64, 0x63, 0x7a, 0x30, 0x33, 0x6e, 0x2d, 0x67, 0x73,
2413 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00,
2414 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x10, 0x0d, 0x72,
2415 0x74, 0x70, 0x35, 0x2d, 0x64, 0x6d, 0x7a, 0x2d, 0x67,
2416 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2417 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x18, 0x15,
2418 0x6d, 0x74, 0x76, 0x35, 0x2d, 0x61, 0x70, 0x31, 0x30,
2419 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x36, 0x6e, 0x2d, 0x67,
2420 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2421 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x1b, 0x18,
2422 0x73, 0x6e, 0x67, 0x64, 0x63, 0x30, 0x31, 0x2d, 0x61,
2423 0x62, 0x30, 0x37, 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x31,
2424 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0,
2425 0x26, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a,
2426 0x00, 0x1a, 0x17, 0x61, 0x65, 0x72, 0x30, 0x31, 0x2d,
2427 0x72, 0x34, 0x63, 0x32, 0x35, 0x2d, 0x64, 0x63, 0x7a,
2428 0x30, 0x31, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0,
2429 0x17, 0xc0, 0x26, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2430 0x00, 0x81, 0x00, 0x04, 0x48, 0xa3, 0x04, 0xa1, 0xc0,
2431 0x26, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82,
2432 0x00, 0x10, 0x20, 0x01, 0x04, 0x20, 0x12, 0x01, 0x00,
2433 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
2434 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2435 0x9a, 0x00, 0x02, 0xc0, 0xf4, 0xc0, 0x0c, 0x00, 0x02,
2436 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0,
2437 0xcd, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00,
2438 0x05, 0x9a, 0x00, 0x02, 0xc0, 0x8d, 0xc0, 0x0c, 0x00,
2439 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02,
2440 0xc0, 0x43, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00,
2441 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0, 0xa9, 0xc0, 0x0c,
2442 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00,
2443 0x02, 0xc0, 0x67, 0xc0, 0x8d, 0x00, 0x01, 0x00, 0x01,
2444 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0x40, 0x66, 0xf6,
2445 0x05, 0xc0, 0xa9, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2446 0x07, 0x08, 0x00, 0x04, 0xad, 0x24, 0xe0, 0x64, 0xc0,
2447 0x43, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08,
2448 0x00, 0x04, 0x48, 0xa3, 0x04, 0x1c, 0xc0, 0xf4, 0x00,
2449 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04,
2450 0xad, 0x26, 0xd4, 0x6c, 0xc0, 0x67, 0x00, 0x01, 0x00,
2451 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x25,
2452 0x90, 0x64, 0xc0, 0xcd, 0x00, 0x01, 0x00, 0x01, 0x00,
2453 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 static clib_error_t *
2493 test_dns_fmt_command_fn (vlib_main_t * vm,
2494 unformat_input_t * input, vlib_cli_command_t * cmd)
2496 u8 *dns_reply_data = 0;
2499 vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2501 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2503 if (unformat (input, "verbose %d", &verbose))
2505 else if (unformat (input, "verbose"))
2508 return clib_error_return (0, "unknown input `%U'",
2509 format_unformat_error, input);
2512 vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2514 memcpy (dns_reply_data, dns_reply_data_initializer,
2515 ARRAY_LEN (dns_reply_data_initializer));
2517 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2519 memset (rmp, 0, sizeof (*rmp));
2521 rv = vnet_dns_response_to_reply (dns_reply_data, rmp, 0 /* ttl-ptr */ );
2525 case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2526 vlib_cli_output (vm, "no addresses found...");
2530 vlib_cli_output (vm, "response to reply returned %d", rv);
2535 vlib_cli_output (vm, "ip4 address: %U", format_ip4_address,
2536 (ip4_address_t *) rmp->ip4_address);
2538 vlib_cli_output (vm, "ip6 address: %U", format_ip6_address,
2539 (ip6_address_t *) rmp->ip6_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_len (name) -= 1;
2615 dns_cache_lock (dm);
2617 p = hash_get_mem (dm->cache_entry_by_name, name);
2620 dns_cache_unlock (dm);
2621 e = clib_error_return (0, "%s is not in the cache...", name);
2626 ep = pool_elt_at_index (dm->entries, p[0]);
2628 ep->expiration_time = 0;
2634 VLIB_CLI_COMMAND (test_dns_expire_command) =
2636 .path = "test dns expire",
2637 .short_help = "test dns expire <name>",
2638 .function = test_dns_expire_command_fn,
2644 vnet_send_dns6_reply (dns_main_t * dm, dns_pending_request_t * pr,
2645 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2647 clib_warning ("Unimplemented...");
2652 vnet_send_dns4_reply (dns_main_t * dm, dns_pending_request_t * pr,
2653 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2655 vlib_main_t *vm = dm->vlib_main;
2657 fib_prefix_t prefix;
2658 fib_node_index_t fei;
2659 u32 sw_if_index, fib_index;
2660 ip4_main_t *im4 = &ip4_main;
2661 ip_lookup_main_t *lm4 = &im4->lookup_main;
2662 ip_interface_address_t *ia = 0;
2663 ip4_address_t *src_address;
2671 vl_api_dns_resolve_name_reply_t _rnr, *rnr = &_rnr;
2672 vl_api_dns_resolve_ip_reply_t _rir, *rir = &_rir;
2680 ASSERT (ep && ep->dns_response);
2682 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2684 /* Quick and dirty way to dig up the A-record address. $$ FIXME */
2685 memset (rnr, 0, sizeof (*rnr));
2686 if (vnet_dns_response_to_reply (ep->dns_response, rnr, &ttl))
2688 /* clib_warning ("response_to_reply failed..."); */
2691 if (rnr->ip4_set == 0)
2693 /* clib_warning ("No A-record..."); */
2697 else if (pr->request_type == DNS_PEER_PENDING_IP_TO_NAME)
2699 memset (rir, 0, sizeof (*rir));
2700 if (vnet_dns_response_to_name (ep->dns_response, rir, &ttl))
2702 /* clib_warning ("response_to_name failed..."); */
2708 clib_warning ("Unknown request type %d", pr->request_type);
2712 /* Initialize a buffer */
2715 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2717 b0 = vlib_get_buffer (vm, bi);
2720 if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
2721 vlib_buffer_free_one (vm, b0->next_buffer);
2724 * Reset the buffer. We recycle the DNS request packet in the cache
2725 * hit case, and reply immediately from the request node.
2727 * In the resolution-required / deferred case, resetting a freshly-allocated
2728 * buffer won't hurt. We hope.
2730 b0->flags &= VLIB_BUFFER_FREE_LIST_INDEX_MASK;
2731 b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
2732 | VLIB_BUFFER_TOTAL_LENGTH_VALID);
2733 b0->current_data = 0;
2734 b0->current_length = 0;
2735 b0->total_length_not_including_first_buffer = 0;
2736 vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; /* "local0" */
2737 vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
2739 /* Find a FIB path to the peer we're trying to answer */
2740 clib_memcpy (&prefix.fp_addr.ip4, pr->dst_address, sizeof (ip4_address_t));
2741 prefix.fp_proto = FIB_PROTOCOL_IP4;
2744 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
2745 if (fib_index == (u32) ~ 0)
2747 clib_warning ("no fib table");
2751 fei = fib_table_lookup (fib_index, &prefix);
2753 /* Couldn't find route to destination. Bail out. */
2754 if (fei == FIB_NODE_INDEX_INVALID)
2756 clib_warning ("no route to DNS server");
2760 sw_if_index = fib_entry_get_resolving_interface (fei);
2762 if (sw_if_index == ~0)
2765 ("route to %U exists, fei %d, get_resolving_interface returned"
2766 " ~0", fei, format_ip4_address, &prefix.fp_addr);
2771 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnummbered */,
2773 src_address = ip_interface_address_get_address (lm4, ia);
2774 goto found_src_address;
2778 clib_warning ("FIB BUG");
2783 ip = vlib_buffer_get_current (b0);
2784 udp = (udp_header_t *) (ip + 1);
2785 dns_response = (u8 *) (udp + 1);
2786 memset (ip, 0, sizeof (*ip) + sizeof (*udp));
2789 * Start with the variadic portion of the exercise.
2790 * Turn the name into a set of DNS "labels". Max length
2791 * per label is 63, enforce that.
2793 reply = name_to_labels (pr->name);
2794 vec_free (pr->name);
2796 qp_offset = vec_len (reply);
2798 /* Add space for the query header */
2799 vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
2801 qp = (dns_query_t *) (reply + qp_offset);
2803 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2804 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
2806 qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2808 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
2810 /* Punch in space for the dns_header_t */
2811 vec_insert (reply, sizeof (dns_header_t), 0);
2813 dh = (dns_header_t *) reply;
2815 /* Transaction ID = pool index */
2818 /* Announce that we did a recursive lookup */
2819 tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
2821 tmp |= DNS_RCODE_NAME_ERROR;
2822 dh->flags = clib_host_to_net_u16 (tmp);
2823 dh->qdcount = clib_host_to_net_u16 (1);
2824 dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
2828 /* If the name resolution worked, cough up an appropriate RR */
2831 /* Add the answer. First, a name pointer (0xC00C) */
2832 vec_add1 (reply, 0xC0);
2833 vec_add1 (reply, 0x0C);
2835 /* Now, add single A-rec RR */
2836 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2838 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
2839 rr = (dns_rr_t *) rrptr;
2841 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
2842 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2843 rr->ttl = clib_host_to_net_u32 (ttl);
2844 rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
2845 clib_memcpy (rr->rdata, rnr->ip4_address, sizeof (ip4_address_t));
2849 /* Or a single PTR RR */
2850 u8 *vecname = format (0, "%s", rir->name);
2851 u8 *label_vec = name_to_labels (vecname);
2854 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
2855 rr = (dns_rr_t *) rrptr;
2856 rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2857 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2858 rr->ttl = clib_host_to_net_u32 (ttl);
2859 rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
2860 clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
2861 vec_free (label_vec);
2864 clib_memcpy (dns_response, reply, vec_len (reply));
2866 /* Set the packet length */
2867 b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
2870 ip->ip_version_and_header_length = 0x45;
2871 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
2873 ip->protocol = IP_PROTOCOL_UDP;
2874 ip->src_address.as_u32 = src_address->as_u32;
2875 clib_memcpy (ip->dst_address.as_u8, pr->dst_address,
2876 sizeof (ip4_address_t));
2877 ip->checksum = ip4_header_checksum (ip);
2880 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
2881 udp->dst_port = pr->dst_port;
2882 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
2887 /* Ship it to ip4_lookup */
2888 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
2889 to_next = vlib_frame_vector_args (f);
2892 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
2896 * fd.io coding-style-patch-verification: ON
2899 * eval: (c-set-style "gnu")