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_api_requests);
59 vec_free (ep->ip4_peers_to_notify);
60 vec_free (ep->ip6_peers_to_notify);
64 pool_free (dm->entries);
65 hash_free (dm->cache_entry_by_name);
66 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
67 vec_free (dm->unresolved_entries);
68 dns_cache_unlock (dm);
73 dns_enable_disable (dns_main_t * dm, int is_enable)
75 vlib_thread_main_t *tm = &vlib_thread_main;
76 u32 n_vlib_mains = tm->n_vlib_mains;
80 if (vec_len (dm->ip4_name_servers) == 0
81 && (vec_len (dm->ip6_name_servers) == 0))
82 return VNET_API_ERROR_NO_NAME_SERVERS;
84 if (dm->cache_entry_by_name == 0)
87 dm->cache_lock = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
88 CLIB_CACHE_LINE_BYTES);
90 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
103 static void vl_api_dns_enable_disable_t_handler
104 (vl_api_dns_enable_disable_t * mp)
106 vl_api_dns_enable_disable_reply_t *rmp;
107 dns_main_t *dm = &dns_main;
110 rv = dns_enable_disable (dm, mp->enable);
112 REPLY_MACRO (VL_API_DNS_ENABLE_DISABLE_REPLY);
116 dns6_name_server_add_del (dns_main_t * dm,
117 u8 * server_address_as_u8, int is_add)
124 /* Already there? done... */
125 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
127 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
128 sizeof (ip6_address_t)))
132 vec_add2 (dm->ip6_name_servers, ap, 1);
133 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
137 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
139 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
140 sizeof (ip6_address_t)))
142 vec_delete (dm->ip6_name_servers, 1, i);
146 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
152 dns4_name_server_add_del (dns_main_t * dm,
153 u8 * server_address_as_u8, int is_add)
160 /* Already there? done... */
161 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
163 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
164 sizeof (ip4_address_t)))
168 vec_add2 (dm->ip4_name_servers, ap, 1);
169 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
173 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
175 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
176 sizeof (ip4_address_t)))
178 vec_delete (dm->ip4_name_servers, 1, i);
182 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
187 static void vl_api_dns_name_server_add_del_t_handler
188 (vl_api_dns_name_server_add_del_t * mp)
190 dns_main_t *dm = &dns_main;
191 vl_api_dns_name_server_add_del_reply_t *rmp;
195 rv = dns6_name_server_add_del (dm, mp->server_address, mp->is_add);
197 rv = dns4_name_server_add_del (dm, mp->server_address, mp->is_add);
199 REPLY_MACRO (VL_API_DNS_NAME_SERVER_ADD_DEL_REPLY);
203 send_dns4_request (dns_main_t * dm,
204 dns_cache_entry_t * ep, ip4_address_t * server)
206 vlib_main_t *vm = dm->vlib_main;
207 f64 now = vlib_time_now (vm);
212 fib_node_index_t fei;
213 u32 sw_if_index, fib_index;
215 ip4_main_t *im4 = &ip4_main;
216 ip_lookup_main_t *lm4 = &im4->lookup_main;
217 ip_interface_address_t *ia = 0;
218 ip4_address_t *src_address;
223 ASSERT (ep->dns_request);
225 /* Find a FIB path to the server */
226 clib_memcpy (&prefix.fp_addr.ip4, server, sizeof (*server));
227 prefix.fp_proto = FIB_PROTOCOL_IP4;
230 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
231 if (fib_index == (u32) ~ 0)
233 clib_warning ("no fib table");
237 fei = fib_table_lookup (fib_index, &prefix);
239 /* Couldn't find route to destination. Bail out. */
240 if (fei == FIB_NODE_INDEX_INVALID)
242 clib_warning ("no route to DNS server");
246 sw_if_index = fib_entry_get_resolving_interface (fei);
248 if (sw_if_index == ~0)
251 ("route to %U exists, fei %d, get_resolving_interface returned"
252 " ~0", fei, format_ip4_address, &prefix.fp_addr);
257 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnummbered */,
259 src_address = ip_interface_address_get_address (lm4, ia);
260 goto found_src_address;
264 clib_warning ("FIB BUG");
269 /* Go get a buffer */
270 if (vlib_buffer_alloc (dm->vlib_main, &bi, 1) != 1)
273 b = vlib_get_buffer (vm, bi);
274 b->current_length = sizeof (ip4_header_t) + sizeof (udp_header_t) +
275 vec_len (ep->dns_request);
276 b->total_length_not_including_first_buffer = 0;
278 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
279 vnet_buffer (b)->sw_if_index[VLIB_RX] = 0; /* "local0" */
280 vnet_buffer (b)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
282 ip = vlib_buffer_get_current (b);
283 memset (ip, 0, sizeof (*ip));
284 udp = (udp_header_t *) (ip + 1);
285 memset (udp, 0, sizeof (*udp));
287 dns_request = (u8 *) (udp + 1);
290 ip->ip_version_and_header_length = 0x45;
291 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b));
293 ip->protocol = IP_PROTOCOL_UDP;
294 ip->src_address.as_u32 = src_address->as_u32;
295 ip->dst_address.as_u32 = server->as_u32;
296 ip->checksum = ip4_header_checksum (ip);
299 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
300 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
301 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
302 vec_len (ep->dns_request));
305 /* The actual DNS request */
306 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
308 /* Ship it to ip4_lookup */
309 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
310 to_next = vlib_frame_vector_args (f);
313 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
315 ep->retry_timer = now + 2.0;
319 send_dns6_request (dns_main_t * dm,
320 dns_cache_entry_t * ep, ip6_address_t * server)
322 vlib_main_t *vm = dm->vlib_main;
323 f64 now = vlib_time_now (vm);
328 fib_node_index_t fei;
329 u32 sw_if_index, fib_index;
331 ip6_main_t *im6 = &ip6_main;
332 ip_lookup_main_t *lm6 = &im6->lookup_main;
333 ip_interface_address_t *ia = 0;
334 ip6_address_t *src_address;
338 int junk __attribute__ ((unused));
340 ASSERT (ep->dns_request);
342 /* Find a FIB path to the server */
343 clib_memcpy (&prefix.fp_addr, server, sizeof (*server));
344 prefix.fp_proto = FIB_PROTOCOL_IP6;
347 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
348 if (fib_index == (u32) ~ 0)
350 clib_warning ("no fib table");
354 fei = fib_table_lookup (fib_index, &prefix);
356 /* Couldn't find route to destination. Bail out. */
357 if (fei == FIB_NODE_INDEX_INVALID)
359 clib_warning ("no route to DNS server");
362 sw_if_index = fib_entry_get_resolving_interface (fei);
365 foreach_ip_interface_address(lm6, ia, sw_if_index, 1 /* honor unnummbered */,
367 src_address = ip_interface_address_get_address (lm6, ia);
368 goto found_src_address;
372 clib_warning ("FIB BUG");
377 /* Go get a buffer */
378 if (vlib_buffer_alloc (dm->vlib_main, &bi, 1) != 1)
381 b = vlib_get_buffer (vm, bi);
382 b->current_length = sizeof (ip6_header_t) + sizeof (udp_header_t) +
383 vec_len (ep->dns_request);
384 b->total_length_not_including_first_buffer = 0;
386 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
388 ip = vlib_buffer_get_current (b);
389 memset (ip, 0, sizeof (*ip));
390 udp = (udp_header_t *) (ip + 1);
391 memset (udp, 0, sizeof (*udp));
393 dns_request = (u8 *) (udp + 1);
396 ip->ip_version_traffic_class_and_flow_label =
397 clib_host_to_net_u32 (0x6 << 28);
400 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b)
401 - sizeof (ip6_header_t));
403 ip->protocol = IP_PROTOCOL_UDP;
404 clib_memcpy (&ip->src_address, src_address, sizeof (ip6_address_t));
405 clib_memcpy (&ip->dst_address, server, sizeof (ip6_address_t));
408 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
409 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
410 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
411 vec_len (ep->dns_request));
413 udp->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ip, &junk);
415 /* The actual DNS request */
416 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
418 /* Ship it to ip6_lookup */
419 f = vlib_get_frame_to_node (vm, ip6_lookup_node.index);
420 to_next = vlib_frame_vector_args (f);
424 ep->retry_timer = now + 2.0;
428 * Translate "foo.com" into "0x3 f o o 0x3 c o m 0x0"
429 * A historical / hysterical micro-TLV scheme. DGMS.
432 name_to_labels (u8 * name)
435 int last_label_index;
440 /* punch in space for the first length */
441 vec_insert (rv, 1, 0);
442 last_label_index = 0;
445 while (i < vec_len (rv))
449 rv[last_label_index] = (i - last_label_index) - 1;
450 if ((i - last_label_index) > 63)
451 clib_warning ("stupid name, label length %d",
452 i - last_label_index);
453 last_label_index = i;
458 /* Set the last real label length */
459 rv[last_label_index] = (i - last_label_index) - 1;
462 * Add a [sic] NULL root label. Otherwise, the name parser can't figure out
470 * arc-function for the above.
471 * Translate "0x3 f o o 0x3 c o m 0x0" into "foo.com"
472 * Produces a non-NULL-terminated u8 *vector. %v format is your friend.
475 labels_to_name (u8 * label, u8 * full_text, u8 ** parse_from_here)
482 *parse_from_here = 0;
484 /* chase initial pointer? */
485 if ((label[0] & 0xC0) == 0xC0)
487 *parse_from_here = label + 2;
488 offset = ((label[0] & 0x3f) << 8) + label[1];
489 label = full_text + offset;
496 for (i = 0; i < len; i++)
497 vec_add1 (reply, *label++);
500 if ((label[0] & 0xC0) == 0xC0)
502 *parse_from_here = label + 2;
503 offset = ((label[0] & 0x3f) << 8) + label[1];
504 label = full_text + offset;
509 vec_add1 (reply, '.');
511 if (*parse_from_here == 0)
512 *parse_from_here = label;
517 vnet_send_dns_request (dns_main_t * dm, dns_cache_entry_t * ep)
525 /* This can easily happen if sitting in GDB, etc. */
526 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
529 /* Construct the dns request, if we haven't been here already */
530 if (vec_len (ep->dns_request) == 0)
533 * Start with the variadic portion of the exercise.
534 * Turn the name into a set of DNS "labels". Max length
535 * per label is 63, enforce that.
537 request = name_to_labels (ep->name);
538 qp_offset = vec_len (request);
540 /* Add space for the query header */
541 vec_validate (request, qp_offset + sizeof (dns_query_t) - 1);
543 qp = (dns_query_t *) (request + qp_offset);
545 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
546 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
548 /* Punch in space for the dns_header_t */
549 vec_insert (request, sizeof (dns_header_t), 0);
551 h = (dns_header_t *) request;
553 /* Transaction ID = pool index */
554 h->id = clib_host_to_net_u16 (ep - dm->entries);
556 /* Ask for a recursive lookup */
557 tmp = DNS_RD | DNS_OPCODE_QUERY;
558 h->flags = clib_host_to_net_u16 (tmp);
559 h->qdcount = clib_host_to_net_u16 (1);
563 ep->dns_request = request;
566 /* Work out which server / address family we're going to use */
568 /* Retry using current server */
569 if (ep->retry_count++ < DNS_RETRIES_PER_SERVER)
571 if (ep->server_af == 1 /* ip6 */ )
573 if (vec_len (dm->ip6_name_servers))
575 send_dns6_request (dm, ep,
576 dm->ip6_name_servers + ep->server_rotor);
582 if (vec_len (dm->ip4_name_servers))
584 send_dns4_request (dm, ep, dm->ip4_name_servers + ep->server_rotor);
588 else /* switch to a new server */
592 if (ep->server_af == 1 /* ip6 */ )
594 if (ep->server_rotor >= vec_len (dm->ip6_name_servers))
596 ep->server_rotor = 0;
597 ep->server_af = vec_len (dm->ip4_name_servers) > 0 ? 0 : 1;
602 if (ep->server_rotor >= vec_len (dm->ip4_name_servers))
604 ep->server_rotor = 0;
605 ep->server_af = vec_len (dm->ip6_name_servers) > 0 ? 1 : 0;
610 if (ep->server_af == 1 /* ip6 */ )
611 send_dns6_request (dm, ep, dm->ip6_name_servers + ep->server_rotor);
613 send_dns4_request (dm, ep, dm->ip4_name_servers + ep->server_rotor);
617 vlib_process_signal_event_mt (dm->vlib_main, dns_resolver_node.index,
618 DNS_RESOLVER_EVENT_PENDING, 0);
622 vnet_dns_delete_entry_by_index_nolock (dns_main_t * dm, u32 index)
624 dns_cache_entry_t *ep;
627 if (dm->is_enabled == 0)
628 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
630 if (pool_is_free_index (dm->entries, index))
631 return VNET_API_ERROR_NO_SUCH_ENTRY;
633 ep = pool_elt_at_index (dm->entries, index);
634 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_VALID))
636 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
637 if (index == dm->unresolved_entries[i])
639 vec_delete (dm->unresolved_entries, 1, i);
642 clib_warning ("pool elt %d supposedly pending, but not found...",
647 hash_unset_mem (dm->cache_entry_by_name, ep->name);
649 vec_free (ep->pending_api_requests);
650 vec_free (ep->ip4_peers_to_notify);
651 vec_free (ep->ip6_peers_to_notify);
652 pool_put (dm->entries, ep);
658 dns_delete_by_name (dns_main_t * dm, u8 * name)
663 if (dm->is_enabled == 0)
664 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
667 p = hash_get_mem (dm->cache_entry_by_name, name);
670 dns_cache_unlock (dm);
671 return VNET_API_ERROR_NO_SUCH_ENTRY;
673 rv = vnet_dns_delete_entry_by_index_nolock (dm, p[0]);
675 dns_cache_unlock (dm);
681 delete_random_entry (dns_main_t * dm)
684 u32 victim_index, start_index, i;
686 dns_cache_entry_t *ep;
688 if (dm->is_enabled == 0)
689 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
692 * Silence spurious coverity warning. We know pool_elts >> 0, or
693 * we wouldn't be here...
696 if (pool_elts (dm->entries) == 0)
697 return VNET_API_ERROR_UNSPECIFIED;
701 limit = pool_elts (dm->entries);
702 start_index = random_u32 (&dm->random_seed) % limit;
704 for (i = 0; i < limit; i++)
706 victim_index = (start_index + i) % limit;
708 if (!pool_is_free_index (dm->entries, victim_index))
710 ep = pool_elt_at_index (dm->entries, victim_index);
711 /* Delete only valid, non-static entries */
712 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
713 && ((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0))
715 rv = vnet_dns_delete_entry_by_index_nolock (dm, victim_index);
716 dns_cache_unlock (dm);
721 dns_cache_unlock (dm);
723 clib_warning ("Couldn't find an entry to delete?");
724 return VNET_API_ERROR_UNSPECIFIED;
728 dns_add_static_entry (dns_main_t * dm, u8 * name, u8 * dns_reply_data)
730 dns_cache_entry_t *ep;
734 if (dm->is_enabled == 0)
735 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
738 p = hash_get_mem (dm->cache_entry_by_name, name);
741 dns_cache_unlock (dm);
742 return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
745 if (pool_elts (dm->entries) == dm->name_cache_size)
747 /* Will only fail if the cache is totally filled w/ static entries... */
748 rv = delete_random_entry (dm);
751 dns_cache_unlock (dm);
756 pool_get (dm->entries, ep);
757 memset (ep, 0, sizeof (*ep));
759 /* Note: consumes the name vector */
761 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
762 ep->flags = DNS_CACHE_ENTRY_FLAG_VALID | DNS_CACHE_ENTRY_FLAG_STATIC;
763 ep->dns_response = dns_reply_data;
765 dns_cache_unlock (dm);
770 dns_resolve_name (dns_main_t * dm,
771 u8 * name, u32 client_index, u32 client_context,
772 u32 request_type, dns_cache_entry_t ** retp)
774 dns_cache_entry_t *ep;
778 pending_api_request_t *pr;
780 now = vlib_time_now (dm->vlib_main);
782 /* In case we can't actually answer the question right now... */
787 p = hash_get_mem (dm->cache_entry_by_name, name);
790 ep = pool_elt_at_index (dm->entries, p[0]);
791 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
793 /* Has the entry expired? */
794 if (((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0)
795 && (now > ep->expiration_time))
798 u32 *indices_to_delete = 0;
801 * Take out the rest of the resolution chain
802 * This isn't optimal, but it won't happen very often.
806 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME))
808 vec_add1 (indices_to_delete, ep - dm->entries);
810 p = hash_get_mem (dm->cache_entry_by_name, ep->cname);
813 ep = pool_elt_at_index (dm->entries, p[0]);
817 vec_add1 (indices_to_delete, ep - dm->entries);
821 for (i = 0; i < vec_len (indices_to_delete); i++)
823 /* Reenable to watch re-resolutions */
826 ep = pool_elt_at_index (dm->entries,
827 indices_to_delete[i]);
828 clib_warning ("Re-resolve %s", ep->name);
831 vnet_dns_delete_entry_by_index_nolock
832 (dm, indices_to_delete[i]);
834 vec_free (indices_to_delete);
835 /* Yes, kill it... */
839 if (ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
845 /* Note: caller must drop the lock! */
852 * Resolution pending. Add request to the pending vector
854 vec_add2 (ep->pending_api_requests, pr, 1);
855 pr->request_type = request_type;
856 pr->client_index = client_index;
857 pr->client_context = client_context;
858 dns_cache_unlock (dm);
864 if (pool_elts (dm->entries) == dm->name_cache_size)
866 /* Will only fail if the cache is totally filled w/ static entries... */
867 rv = delete_random_entry (dm);
870 dns_cache_unlock (dm);
875 /* add new hash table entry */
876 pool_get (dm->entries, ep);
877 memset (ep, 0, sizeof (*ep));
879 ep->name = format (0, "%s%c", name, 0);
880 _vec_len (ep->name) = vec_len (ep->name) - 1;
882 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
884 vec_add1 (dm->unresolved_entries, ep - dm->entries);
885 vec_add2 (ep->pending_api_requests, pr, 1);
886 pr->request_type = request_type;
887 pr->client_index = client_index;
888 pr->client_context = client_context;
889 vnet_send_dns_request (dm, ep);
890 dns_cache_unlock (dm);
894 #define foreach_notification_to_move \
895 _(pending_api_requests) \
896 _(ip4_peers_to_notify) \
897 _(ip6_peers_to_notify)
900 * Handle cname indirection. JFC. Called with the cache locked.
901 * returns 0 if the reply is not a CNAME.
905 vnet_dns_cname_indirection_nolock (dns_main_t * dm, u32 ep_index, u8 * reply)
918 dns_cache_entry_t *ep, *next_ep;
921 h = (dns_header_t *) reply;
922 flags = clib_net_to_host_u16 (h->flags);
923 rcode = flags & DNS_RCODE_MASK;
925 /* See if the response is OK */
928 case DNS_RCODE_NO_ERROR:
931 case DNS_RCODE_NAME_ERROR:
932 case DNS_RCODE_FORMAT_ERROR:
933 case DNS_RCODE_SERVER_FAILURE:
934 case DNS_RCODE_NOT_IMPLEMENTED:
935 case DNS_RCODE_REFUSED:
939 curpos = (u8 *) (h + 1);
943 /* Skip the questions */
944 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
951 pos += sizeof (dns_query_t);
954 /* expect a pointer chase here for a CNAME record */
955 if ((pos2[0] & 0xC0) == 0xC0)
960 rr = (dns_rr_t *) pos;
962 /* This is a real record, not a CNAME record */
963 if (clib_net_to_host_u16 (rr->type) != DNS_TYPE_CNAME)
966 /* This is a CNAME record, chase the name chain. */
968 /* The last request is no longer pending.. */
969 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
970 if (ep_index == dm->unresolved_entries[i])
972 vec_delete (dm->unresolved_entries, 1, i);
973 goto found_last_request;
975 clib_warning ("pool elt %d supposedly pending, but not found...", ep_index);
979 now = vlib_time_now (dm->vlib_main);
980 cname = labels_to_name (rr->rdata, reply, &pos2);
983 _vec_len (cname) -= 1;
984 ep = pool_elt_at_index (dm->entries, ep_index);
986 ep->flags |= (DNS_CACHE_ENTRY_FLAG_CNAME | DNS_CACHE_ENTRY_FLAG_VALID);
987 /* Save the response */
988 ep->dns_response = reply;
989 /* Set up expiration time */
990 ep->expiration_time = now + clib_net_to_host_u32 (rr->ttl);
992 pool_get (dm->entries, next_ep);
994 /* Need to recompute ep post pool-get */
995 ep = pool_elt_at_index (dm->entries, ep_index);
997 memset (next_ep, 0, sizeof (*next_ep));
998 next_ep->name = vec_dup (cname);
999 vec_add1 (next_ep->name, 0);
1000 _vec_len (next_ep->name) -= 1;
1002 hash_set_mem (dm->cache_entry_by_name, next_ep->name,
1003 next_ep - dm->entries);
1005 /* Use the same server */
1006 next_ep->server_rotor = ep->server_rotor;
1007 next_ep->server_af = ep->server_af;
1009 /* Move notification data to the next name in the chain */
1010 #define _(a) next_ep->a = ep->a; ep->a = 0;
1011 foreach_notification_to_move;
1014 request = name_to_labels (cname);
1016 qp_offset = vec_len (request);
1018 /* Add space for the query header */
1019 vec_validate (request, qp_offset + sizeof (dns_query_t) - 1);
1021 qp = (dns_query_t *) (request + qp_offset);
1023 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1024 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1026 /* Punch in space for the dns_header_t */
1027 vec_insert (request, sizeof (dns_header_t), 0);
1029 h = (dns_header_t *) request;
1031 /* Transaction ID = pool index */
1032 h->id = clib_host_to_net_u16 (next_ep - dm->entries);
1034 /* Ask for a recursive lookup */
1035 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
1036 h->qdcount = clib_host_to_net_u16 (1);
1040 next_ep->dns_request = request;
1041 next_ep->retry_timer = now + 2.0;
1042 next_ep->retry_count = 0;
1045 * Enable this to watch recursive resolution happen...
1046 * fformat (stdout, "%U", format_dns_reply, request, 2);
1049 vec_add1 (dm->unresolved_entries, next_ep - dm->entries);
1050 vnet_send_dns_request (dm, next_ep);
1055 vnet_dns_response_to_reply (u8 * response,
1056 vl_api_dns_resolve_name_reply_t * rmp,
1069 h = (dns_header_t *) response;
1070 flags = clib_net_to_host_u16 (h->flags);
1071 rcode = flags & DNS_RCODE_MASK;
1073 /* See if the response is OK, etc. */
1077 case DNS_RCODE_NO_ERROR:
1080 case DNS_RCODE_NAME_ERROR:
1081 case DNS_RCODE_FORMAT_ERROR:
1082 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1084 case DNS_RCODE_SERVER_FAILURE:
1085 case DNS_RCODE_NOT_IMPLEMENTED:
1086 case DNS_RCODE_REFUSED:
1087 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1090 /* No answers? Loser... */
1091 if (clib_net_to_host_u16 (h->anscount) < 1)
1092 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1094 curpos = (u8 *) (h + 1);
1096 /* Skip the name we asked about */
1099 /* Should never happen, but stil... */
1100 if ((len & 0xC0) == 0xC0)
1104 /* skip the name / label-set */
1113 limit = clib_net_to_host_u16 (h->qdcount);
1114 qp = (dns_query_t *) curpos;
1119 limit = clib_net_to_host_u16 (h->anscount);
1121 for (i = 0; i < limit; i++)
1125 /* Expect pointer chases in the answer section... */
1126 if ((pos[0] & 0xC0) == 0xC0)
1133 if ((pos[0] & 0xC0) == 0xC0)
1145 rr = (dns_rr_t *) curpos;
1147 switch (clib_net_to_host_u16 (rr->type))
1150 /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1151 memcpy (rmp->ip4_address, rr->rdata, sizeof (ip4_address_t));
1153 ttl = clib_net_to_host_u32 (rr->ttl);
1154 if (min_ttlp && *min_ttlp > ttl)
1158 /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1159 memcpy (rmp->ip6_address, rr->rdata, sizeof (ip6_address_t));
1160 ttl = clib_net_to_host_u32 (rr->ttl);
1161 if (min_ttlp && *min_ttlp > ttl)
1168 /* Might as well stop ASAP */
1169 if (rmp->ip4_set && rmp->ip6_set)
1171 curpos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1174 if ((rmp->ip4_set + rmp->ip6_set) == 0)
1175 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1180 vnet_dns_response_to_name (u8 * response,
1181 vl_api_dns_resolve_ip_reply_t * rmp,
1194 u8 *junk __attribute__ ((unused));
1197 h = (dns_header_t *) response;
1198 flags = clib_net_to_host_u16 (h->flags);
1199 rcode = flags & DNS_RCODE_MASK;
1201 /* See if the response is OK, etc. */
1205 case DNS_RCODE_NO_ERROR:
1208 case DNS_RCODE_NAME_ERROR:
1209 case DNS_RCODE_FORMAT_ERROR:
1210 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1212 case DNS_RCODE_SERVER_FAILURE:
1213 case DNS_RCODE_NOT_IMPLEMENTED:
1214 case DNS_RCODE_REFUSED:
1215 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1218 /* No answers? Loser... */
1219 if (clib_net_to_host_u16 (h->anscount) < 1)
1220 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1222 curpos = (u8 *) (h + 1);
1224 /* Skip the name we asked about */
1227 /* Should never happen, but stil... */
1228 if ((len & 0xC0) == 0xC0)
1232 /* skip the name / label-set */
1241 limit = clib_net_to_host_u16 (h->qdcount);
1242 qp = (dns_query_t *) curpos;
1247 limit = clib_net_to_host_u16 (h->anscount);
1249 for (i = 0; i < limit; i++)
1253 /* Expect pointer chases in the answer section... */
1254 if ((pos[0] & 0xC0) == 0xC0)
1261 if ((pos[0] & 0xC0) == 0xC0)
1273 rr = (dns_rr_t *) curpos;
1275 switch (clib_net_to_host_u16 (rr->type))
1278 name = labels_to_name (rr->rdata, response, &junk);
1279 memcpy (rmp->name, name, vec_len (name));
1280 ttl = clib_net_to_host_u32 (rr->ttl);
1283 rmp->name[vec_len (name)] = 0;
1289 /* Might as well stop ASAP */
1292 curpos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1296 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1301 vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1303 dns_main_t *dm = &dns_main;
1304 vl_api_dns_resolve_name_reply_t *rmp;
1305 dns_cache_entry_t *ep;
1308 /* Sanitize the name slightly */
1309 mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1311 rv = dns_resolve_name (dm, mp->name, mp->client_index, mp->context,
1312 DNS_API_PENDING_NAME_TO_IP, &ep);
1314 /* Error, e.g. not enabled? Tell the user */
1317 REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1321 /* Resolution pending? Don't reply... */
1326 REPLY_MACRO2(VL_API_DNS_RESOLVE_NAME_REPLY,
1328 rv = vnet_dns_response_to_reply (ep->dns_response, rmp, 0 /* ttl-ptr */);
1329 rmp->retval = clib_host_to_net_u32 (rv);
1334 * dns_resolve_name leaves the cache locked when it returns
1335 * a cached result, so unlock it here.
1337 dns_cache_unlock (dm);
1341 vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
1343 dns_main_t *dm = &dns_main;
1344 vl_api_dns_resolve_ip_reply_t *rmp;
1345 dns_cache_entry_t *ep;
1348 u8 *lookup_name = 0;
1353 for (i = 15; i >= 0; i--)
1355 digit = mp->address[i];
1356 nybble = (digit & 0x0F);
1358 vec_add1 (lookup_name, (nybble - 10) + 'a');
1360 vec_add1 (lookup_name, nybble + '0');
1361 vec_add1 (lookup_name, '.');
1362 nybble = (digit & 0xF0) >> 4;
1364 vec_add1 (lookup_name, (nybble - 10) + 'a');
1366 vec_add1 (lookup_name, nybble + '0');
1367 vec_add1 (lookup_name, '.');
1369 len = vec_len (lookup_name);
1370 vec_validate (lookup_name, len + 8);
1371 memcpy (lookup_name + len, "ip6.arpa", 8);
1375 for (i = 3; i >= 0; i--)
1377 digit = mp->address[i];
1378 lookup_name = format (lookup_name, "%d.", digit);
1380 lookup_name = format (lookup_name, "in-addr.arpa");
1383 vec_add1 (lookup_name, 0);
1385 rv = dns_resolve_name (dm, lookup_name, mp->client_index, mp->context,
1386 DNS_API_PENDING_IP_TO_NAME, &ep);
1388 vec_free (lookup_name);
1390 /* Error, e.g. not enabled? Tell the user */
1393 REPLY_MACRO (VL_API_DNS_RESOLVE_IP_REPLY);
1397 /* Resolution pending? Don't reply... */
1402 REPLY_MACRO2(VL_API_DNS_RESOLVE_IP_REPLY,
1404 rv = vnet_dns_response_to_name (ep->dns_response, rmp, 0 /* ttl-ptr */);
1405 rmp->retval = clib_host_to_net_u32 (rv);
1410 * dns_resolve_name leaves the cache locked when it returns
1411 * a cached result, so unlock it here.
1413 dns_cache_unlock (dm);
1416 #define vl_msg_name_crc_list
1417 #include <vpp/api/vpe_all_api_h.h>
1418 #undef vl_msg_name_crc_list
1421 setup_message_id_table (api_main_t * am)
1423 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1424 foreach_vl_msg_name_crc_dns;
1428 #define foreach_dns_api_msg \
1429 _(DNS_ENABLE_DISABLE, dns_enable_disable) \
1430 _(DNS_NAME_SERVER_ADD_DEL, dns_name_server_add_del) \
1431 _(DNS_RESOLVE_NAME, dns_resolve_name) \
1432 _(DNS_RESOLVE_IP, dns_resolve_ip)
1434 static clib_error_t *
1435 dns_api_hookup (vlib_main_t * vm)
1438 vl_msg_api_set_handlers(VL_API_##N, #n, \
1439 vl_api_##n##_t_handler, \
1441 vl_api_##n##_t_endian, \
1442 vl_api_##n##_t_print, \
1443 sizeof(vl_api_##n##_t), 1);
1444 foreach_dns_api_msg;
1447 setup_message_id_table (&api_main);
1451 VLIB_API_INIT_FUNCTION (dns_api_hookup);
1454 static clib_error_t *
1455 dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1457 dns_main_t *dm = &dns_main;
1459 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1461 if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1463 else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1466 return clib_error_return (0, "unknown input `%U'",
1467 format_unformat_error, input);
1472 VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1474 static clib_error_t *
1475 dns_init (vlib_main_t * vm)
1477 dns_main_t *dm = &dns_main;
1480 dm->vnet_main = vnet_get_main ();
1481 dm->name_cache_size = 65535;
1482 dm->max_ttl_in_seconds = 86400;
1483 dm->random_seed = 0xDEADDABE;
1485 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply, dns46_reply_node.index,
1488 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply6, dns46_reply_node.index,
1492 udp_register_dst_port (vm, UDP_DST_PORT_dns, dns4_request_node.index,
1494 udp_register_dst_port (vm, UDP_DST_PORT_dns6, dns6_request_node.index,
1501 VLIB_INIT_FUNCTION (dns_init);
1504 unformat_dns_reply (unformat_input_t * input, va_list * args)
1506 u8 **result = va_arg (*args, u8 **);
1507 u8 **namep = va_arg (*args, u8 **);
1521 if (unformat (input, "%v", &name))
1524 if (unformat (input, "%U", unformat_ip4_address, &a4))
1527 if (unformat (input, "%U", unformat_ip6_address, &a6))
1531 if (unformat (input, "%U", unformat_ip6_address, &a6))
1534 if (unformat (input, "%U", unformat_ip4_address, &a6))
1538 /* Must have a name */
1542 /* Must have at least one address */
1543 if (!(a4_set + a6_set))
1546 /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1547 ce = name_to_labels (name);
1548 qp_offset = vec_len (ce);
1550 /* Add space for the query header */
1551 vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1552 qp = (dns_query_t *) (ce + qp_offset);
1554 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1555 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1557 /* Punch in space for the dns_header_t */
1558 vec_insert (ce, sizeof (dns_header_t), 0);
1560 h = (dns_header_t *) ce;
1562 /* Fake Transaction ID */
1565 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1566 h->qdcount = clib_host_to_net_u16 (1);
1567 h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1571 /* Now append one or two A/AAAA RR's... */
1574 /* Pointer to the name (DGMS) */
1575 vec_add1 (ce, 0xC0);
1576 vec_add1 (ce, 0x0C);
1577 vec_add2 (ce, rru8, sizeof (*rr) + 4);
1579 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1580 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1581 rr->ttl = clib_host_to_net_u32 (86400);
1582 rr->rdlength = clib_host_to_net_u16 (4);
1583 memcpy (rr->rdata, &a4, sizeof (a4));
1587 /* Pointer to the name (DGMS) */
1588 vec_add1 (ce, 0xC0);
1589 vec_add1 (ce, 0x0C);
1590 vec_add2 (ce, rru8, sizeof (*rr) + 16);
1592 rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1593 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1594 rr->ttl = clib_host_to_net_u32 (86400);
1595 rr->rdlength = clib_host_to_net_u16 (16);
1596 memcpy (rr->rdata, &a6, sizeof (a6));
1608 format_dns_query (u8 * s, va_list * args)
1610 u8 **curpos = va_arg (*args, u8 **);
1611 int verbose = va_arg (*args, int);
1616 s = format (s, " Name: ");
1618 /* Unwind execrated counted-label sheit */
1624 for (i = 0; i < len; i++)
1625 vec_add1 (s, *pos++);
1637 qp = (dns_query_t *) pos;
1640 switch (clib_net_to_host_u16 (qp->type))
1643 s = format (s, "type A\n");
1646 s = format (s, "type AAAA\n");
1649 s = format (s, "type ALL\n");
1653 s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1658 pos += sizeof (*qp);
1665 * format dns reply data
1666 * verbose > 1, dump everything
1667 * verbose == 1, dump all A and AAAA records
1668 * verbose == 0, dump one A record, and one AAAA record
1672 format_dns_reply_data (u8 * s, va_list * args)
1674 u8 *reply = va_arg (*args, u8 *);
1675 u8 **curpos = va_arg (*args, u8 **);
1676 int verbose = va_arg (*args, int);
1677 int *print_ip4 = va_arg (*args, int *);
1678 int *print_ip6 = va_arg (*args, int *);
1683 int initial_pointer_chase = 0;
1685 u16 rrtype_host_byte_order;
1687 pos = pos2 = *curpos;
1690 s = format (s, " ");
1692 /* chase pointer? almost always yes here... */
1693 if (pos2[0] == 0xc0)
1695 pos2 = reply + pos2[1];
1697 initial_pointer_chase = 1;
1704 for (i = 0; i < len; i++)
1707 vec_add1 (s, *pos2);
1723 if (initial_pointer_chase == 0)
1726 rr = (dns_rr_t *) pos;
1727 rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
1729 switch (rrtype_host_byte_order)
1734 s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1735 format_ip4_address, rr->rdata);
1740 s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1741 clib_net_to_host_u32 (rr->ttl));
1746 pos += sizeof (*rr) + 4;
1752 s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1753 format_ip6_address, rr->rdata);
1758 s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1759 clib_net_to_host_u32 (rr->ttl));
1763 pos += sizeof (*rr) + 16;
1769 s = format (s, "TEXT: ");
1770 for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1771 vec_add1 (s, rr->rdata[i]);
1774 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1777 case DNS_TYPE_HINFO:
1779 /* Two counted strings. DGMS */
1785 s = format (s, "HINFO: ");
1788 for (i = 0; i < *len; i++)
1789 vec_add1 (s, *curpos++);
1793 for (i = 0; i < *len; i++)
1794 vec_add1 (s, *curpos++);
1799 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1802 case DNS_TYPE_NAMESERVER:
1805 s = format (s, "Nameserver: ");
1808 /* chase pointer? */
1809 if (pos2[0] == 0xc0)
1810 pos2 = reply + pos2[1];
1816 for (i = 0; i < len; i++)
1817 vec_add1 (s, *pos2++);
1819 /* chase pointer, typically to offset 12... */
1820 if (pos2[0] == 0xC0)
1821 pos2 = reply + pos2[1];
1830 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1833 case DNS_TYPE_MAIL_EXCHANGE:
1836 tp = (u16 *) rr->rdata;
1838 s = format (s, "Mail Exchange: Preference %d ", (u32)
1839 clib_net_to_host_u16 (*tp));
1841 pos2 = rr->rdata + 2;
1843 /* chase pointer? */
1844 if (pos2[0] == 0xc0)
1845 pos2 = reply + pos2[1];
1851 for (i = 0; i < len; i++)
1852 vec_add1 (s, *pos2++);
1855 if (pos2[0] == 0xC0)
1856 pos2 = reply + pos2[1];
1866 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1870 case DNS_TYPE_CNAME:
1873 tp = (u16 *) rr->rdata;
1875 if (rrtype_host_byte_order == DNS_TYPE_CNAME)
1876 s = format (s, "CNAME: ");
1878 s = format (s, "PTR: ");
1882 /* chase pointer? */
1883 if (pos2[0] == 0xc0)
1884 pos2 = reply + pos2[1];
1890 for (i = 0; i < len; i++)
1891 vec_add1 (s, *pos2++);
1894 if (pos2[0] == 0xC0)
1895 pos2 = reply + pos2[1];
1904 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1909 s = format (s, "type %d: len %d\n",
1910 (int) clib_net_to_host_u16 (rr->type),
1911 sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
1912 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1922 format_dns_reply (u8 * s, va_list * args)
1924 u8 *reply_as_u8 = va_arg (*args, u8 *);
1925 int verbose = va_arg (*args, int);
1933 h = (dns_header_t *) reply_as_u8;
1934 id = clib_net_to_host_u16 (h->id);
1935 flags = clib_net_to_host_u16 (h->flags);
1939 s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
1941 s = format (s, " %s %s %s %s\n",
1942 (flags & DNS_RA) ? "recur" : "no-recur",
1943 (flags & DNS_RD) ? "recur-des" : "no-recur-des",
1944 (flags & DNS_TC) ? "trunc" : "no-trunc",
1945 (flags & DNS_AA) ? "auth" : "non-auth");
1946 s = format (s, " %d queries, %d answers, %d name-servers,"
1948 clib_net_to_host_u16 (h->qdcount),
1949 clib_net_to_host_u16 (h->anscount),
1950 clib_net_to_host_u16 (h->nscount),
1951 clib_net_to_host_u16 (h->arcount));
1954 curpos = (u8 *) (h + 1);
1959 s = format (s, " Queries:\n");
1960 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
1962 /* The query is variable-length, so curpos is a value-result parm */
1963 s = format (s, "%U", format_dns_query, &curpos, verbose);
1969 s = format (s, " Replies:\n");
1971 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
1973 /* curpos is a value-result parm */
1974 s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
1975 verbose, &print_ip4, &print_ip6);
1982 format_dns_cache (u8 * s, va_list * args)
1984 dns_main_t *dm = va_arg (*args, dns_main_t *);
1985 f64 now = va_arg (*args, f64);
1986 int verbose = va_arg (*args, int);
1987 u8 *name = va_arg (*args, u8 *);
1988 dns_cache_entry_t *ep;
1992 if (dm->is_enabled == 0)
1994 s = format (s, "The DNS cache is disabled...");
1998 if (pool_elts (dm->entries) == 0)
2000 s = format (s, "The DNS cache is empty...");
2004 dns_cache_lock (dm);
2008 p = hash_get_mem (dm->cache_entry_by_name, name);
2011 s = format (s, "%s is not in the cache...", name);
2012 dns_cache_unlock (dm);
2016 ep = pool_elt_at_index (dm->entries, p[0]);
2017 /* Magic to spit out a C-initializer to research hemorrhoids... */
2021 s = format (s, "static u8 dns_reply_data_initializer[] =\n");
2022 s = format (s, "{\n");
2024 for (i = 0; i < vec_len (ep->dns_response); i++)
2031 s = format (s, "0x%02x, ", ep->dns_response[i]);
2033 s = format (s, "};\n");
2037 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2039 ASSERT (ep->dns_response);
2040 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2045 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2046 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2048 s = format (s, "%s%s -> %U", ss, ep->name,
2049 format_dns_reply, ep->dns_response, verbose);
2050 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2052 f64 time_left = ep->expiration_time - now;
2053 if (time_left > 0.0)
2054 s = format (s, " TTL left %.1f", time_left);
2056 s = format (s, " EXPIRED");
2061 ASSERT (ep->dns_request);
2062 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2071 pool_foreach (ep, dm->entries,
2073 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2075 ASSERT (ep->dns_response);
2076 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2081 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2082 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2084 s = format (s, "%s%s -> %U", ss, ep->name,
2088 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2090 f64 time_left = ep->expiration_time - now;
2091 if (time_left > 0.0)
2092 s = format (s, " TTL left %.1f", time_left);
2094 s = format (s, " EXPIRED");
2097 s = format (s, " %d client notifications pending\n",
2098 vec_len(ep->pending_api_requests));
2103 ASSERT (ep->dns_request);
2104 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2111 dns_cache_unlock (dm);
2116 static clib_error_t *
2117 show_dns_cache_command_fn (vlib_main_t * vm,
2118 unformat_input_t * input, vlib_cli_command_t * cmd)
2120 dns_main_t *dm = &dns_main;
2123 f64 now = vlib_time_now (vm);
2125 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2127 if (unformat (input, "verbose %d", &verbose))
2129 else if (unformat (input, "verbose"))
2131 else if (unformat (input, "name %s", &name))
2134 return clib_error_return (0, "unknown input `%U'",
2135 format_unformat_error, input);
2138 vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
2144 VLIB_CLI_COMMAND (show_dns_cache_command) =
2146 .path = "show dns cache",
2147 .short_help = "show dns cache [verbose [nn]]",
2148 .function = show_dns_cache_command_fn,
2152 static clib_error_t *
2153 dns_cache_add_del_command_fn (vlib_main_t * vm,
2154 unformat_input_t * input,
2155 vlib_cli_command_t * cmd)
2157 dns_main_t *dm = &dns_main;
2163 clib_error_t *error;
2165 if (unformat (input, "add"))
2167 if (unformat (input, "del"))
2169 if (unformat (input, "clear"))
2172 if (is_add == -1 && is_clear == -1)
2173 return clib_error_return (0, "add / del / clear required...");
2177 rv = dns_cache_clear (dm);
2183 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2184 error = clib_error_return (0, "Name resolution not enabled");
2189 /* Delete (by name)? */
2192 if (unformat (input, "%v", &name))
2194 rv = dns_delete_by_name (dm, name);
2197 case VNET_API_ERROR_NO_SUCH_ENTRY:
2198 error = clib_error_return (0, "%v not in the cache...", name);
2202 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2203 error = clib_error_return (0, "Name resolution not enabled");
2212 error = clib_error_return (0, "dns_delete_by_name returned %d",
2218 return clib_error_return (0, "unknown input `%U'",
2219 format_unformat_error, input);
2222 /* Note: dns_add_static_entry consumes the name vector if OK... */
2223 if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2225 rv = dns_add_static_entry (dm, name, dns_reply_data);
2228 case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2230 vec_free (dns_reply_data);
2231 return clib_error_return (0, "%v already in the cache...", name);
2236 return clib_error_return (0, "dns_add_static_entry returned %d",
2245 VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2247 .path = "dns cache",
2248 .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2249 .function = dns_cache_add_del_command_fn,
2253 #define DNS_FORMAT_TEST 1
2255 #if DNS_FORMAT_TEST > 0
2258 static u8 dns_reply_data_initializer[] =
2259 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2260 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2262 0x0, 0xff, /* type ALL */
2263 0x0, 0x1, /* class IN */
2264 0xc0, 0xc, /* pointer to yahoo.com name */
2265 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2266 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2267 0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2268 0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2269 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2270 0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2271 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2272 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2273 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2274 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2275 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2276 0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2277 0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2279 0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2280 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2281 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2282 0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2283 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2285 0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2286 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2287 0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2288 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2290 0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2291 0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2293 0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2295 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2297 0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2299 0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2300 0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2301 0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2305 /* www.cisco.com, has no addresses in reply */
2306 static u8 dns_reply_data_initializer[] = {
2307 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2308 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2309 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2311 0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2312 0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2313 0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2314 0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2315 0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2319 static u8 dns_reply_data_initializer[] =
2320 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
2321 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
2322 0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
2323 0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
2325 0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
2326 0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
2327 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
2328 0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
2329 0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
2330 0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
2331 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
2332 0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
2333 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
2334 0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
2335 0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
2336 0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
2337 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
2338 0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
2339 0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
2340 0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
2341 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2342 0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
2343 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
2344 0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
2345 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
2346 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
2347 0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
2349 0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2353 static clib_error_t *
2354 test_dns_fmt_command_fn (vlib_main_t * vm,
2355 unformat_input_t * input, vlib_cli_command_t * cmd)
2357 u8 *dns_reply_data = 0;
2360 vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2362 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2364 if (unformat (input, "verbose %d", &verbose))
2366 else if (unformat (input, "verbose"))
2369 return clib_error_return (0, "unknown input `%U'",
2370 format_unformat_error, input);
2373 vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2375 memcpy (dns_reply_data, dns_reply_data_initializer,
2376 ARRAY_LEN (dns_reply_data_initializer));
2378 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2380 memset (rmp, 0, sizeof (*rmp));
2382 rv = vnet_dns_response_to_reply (dns_reply_data, rmp, 0 /* ttl-ptr */ );
2386 case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2387 vlib_cli_output (vm, "no addresses found...");
2391 vlib_cli_output (vm, "response to reply returned %d", rv);
2396 vlib_cli_output (vm, "ip4 address: %U", format_ip4_address,
2397 (ip4_address_t *) rmp->ip4_address);
2399 vlib_cli_output (vm, "ip6 address: %U", format_ip6_address,
2400 (ip6_address_t *) rmp->ip6_address);
2404 vec_free (dns_reply_data);
2411 VLIB_CLI_COMMAND (test_dns_fmt_command) =
2413 .path = "test dns format",
2414 .short_help = "test dns format",
2415 .function = test_dns_fmt_command_fn,
2419 static clib_error_t *
2420 test_dns_unfmt_command_fn (vlib_main_t * vm,
2421 unformat_input_t * input, vlib_cli_command_t * cmd)
2423 u8 *dns_reply_data = 0;
2427 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2429 if (unformat (input, "verbose %d", &verbose))
2431 else if (unformat (input, "verbose"))
2433 else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2436 return clib_error_return (0, "unknown input `%U'",
2437 format_unformat_error, input);
2441 return clib_error_return (0, "dns data not set...");
2443 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2445 vec_free (dns_reply_data);
2451 VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2453 .path = "test dns unformat",
2454 .short_help = "test dns unformat <name> [ip4][ip6]",
2455 .function = test_dns_unfmt_command_fn,
2459 static clib_error_t *
2460 test_dns_expire_command_fn (vlib_main_t * vm,
2461 unformat_input_t * input,
2462 vlib_cli_command_t * cmd)
2464 dns_main_t *dm = &dns_main;
2468 dns_cache_entry_t *ep;
2470 if (unformat (input, "%v", &name))
2473 _vec_len (name) -= 1;
2476 dns_cache_lock (dm);
2478 p = hash_get_mem (dm->cache_entry_by_name, name);
2481 dns_cache_unlock (dm);
2482 e = clib_error_return (0, "%s is not in the cache...", name);
2487 ep = pool_elt_at_index (dm->entries, p[0]);
2489 ep->expiration_time = 0;
2495 VLIB_CLI_COMMAND (test_dns_expire_command) =
2497 .path = "test dns expire",
2498 .short_help = "test dns expire <name>",
2499 .function = test_dns_expire_command_fn,
2505 * fd.io coding-style-patch-verification: ON
2508 * eval: (c-set-style "gnu")