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->api_clients_to_notify);
59 vec_free (ep->api_client_contexts);
60 vec_free (ep->ip4_peers_to_notify);
61 vec_free (ep->ip6_peers_to_notify);
65 pool_free (dm->entries);
66 hash_free (dm->cache_entry_by_name);
67 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
68 vec_free (dm->unresolved_entries);
69 dns_cache_unlock (dm);
74 dns_enable_disable (dns_main_t * dm, int is_enable)
76 vlib_thread_main_t *tm = &vlib_thread_main;
77 u32 n_vlib_mains = tm->n_vlib_mains;
81 if (vec_len (dm->ip4_name_servers) == 0
82 && (vec_len (dm->ip6_name_servers) == 0))
83 return VNET_API_ERROR_NO_NAME_SERVERS;
85 if (dm->cache_entry_by_name == 0)
88 dm->cache_lock = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
89 CLIB_CACHE_LINE_BYTES);
91 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
104 static void vl_api_dns_enable_disable_t_handler
105 (vl_api_dns_enable_disable_t * mp)
107 vl_api_dns_enable_disable_reply_t *rmp;
108 dns_main_t *dm = &dns_main;
111 rv = dns_enable_disable (dm, mp->enable);
113 REPLY_MACRO (VL_API_DNS_ENABLE_DISABLE_REPLY);
117 dns6_name_server_add_del (dns_main_t * dm,
118 u8 * server_address_as_u8, int is_add)
125 /* Already there? done... */
126 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
128 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
129 sizeof (ip6_address_t)))
133 vec_add2 (dm->ip6_name_servers, ap, 1);
134 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
138 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
140 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
141 sizeof (ip6_address_t)))
143 vec_delete (dm->ip6_name_servers, 1, i);
147 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
153 dns4_name_server_add_del (dns_main_t * dm,
154 u8 * server_address_as_u8, int is_add)
161 /* Already there? done... */
162 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
164 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
165 sizeof (ip4_address_t)))
169 vec_add2 (dm->ip4_name_servers, ap, 1);
170 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
174 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
176 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
177 sizeof (ip4_address_t)))
179 vec_delete (dm->ip4_name_servers, 1, i);
183 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
188 static void vl_api_dns_name_server_add_del_t_handler
189 (vl_api_dns_name_server_add_del_t * mp)
191 dns_main_t *dm = &dns_main;
192 vl_api_dns_name_server_add_del_reply_t *rmp;
196 rv = dns6_name_server_add_del (dm, mp->server_address, mp->is_add);
198 rv = dns4_name_server_add_del (dm, mp->server_address, mp->is_add);
200 REPLY_MACRO (VL_API_DNS_NAME_SERVER_ADD_DEL_REPLY);
204 send_dns4_request (dns_main_t * dm,
205 dns_cache_entry_t * ep, ip4_address_t * server)
207 vlib_main_t *vm = dm->vlib_main;
208 f64 now = vlib_time_now (vm);
213 fib_node_index_t fei;
214 u32 sw_if_index, fib_index;
216 ip4_main_t *im4 = &ip4_main;
217 ip_lookup_main_t *lm4 = &im4->lookup_main;
218 ip_interface_address_t *ia = 0;
219 ip4_address_t *src_address;
224 ASSERT (ep->dns_request);
226 /* Find a FIB path to the server */
227 clib_memcpy (&prefix.fp_addr.ip4, server, sizeof (*server));
228 prefix.fp_proto = FIB_PROTOCOL_IP4;
231 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
232 if (fib_index == (u32) ~ 0)
234 clib_warning ("no fib table");
238 fei = fib_table_lookup (fib_index, &prefix);
240 /* Couldn't find route to destination. Bail out. */
241 if (fei == FIB_NODE_INDEX_INVALID)
243 clib_warning ("no route to DNS server");
247 sw_if_index = fib_entry_get_resolving_interface (fei);
249 if (sw_if_index == ~0)
252 ("route to %U exists, fei %d, get_resolving_interface returned"
253 " ~0", fei, format_ip4_address, &prefix.fp_addr);
258 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnummbered */,
260 src_address = ip_interface_address_get_address (lm4, ia);
261 goto found_src_address;
265 clib_warning ("FIB BUG");
270 /* Go get a buffer */
271 if (vlib_buffer_alloc (dm->vlib_main, &bi, 1) != 1)
274 b = vlib_get_buffer (vm, bi);
275 b->current_length = sizeof (ip4_header_t) + sizeof (udp_header_t) +
276 vec_len (ep->dns_request);
277 b->total_length_not_including_first_buffer = 0;
279 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
280 vnet_buffer (b)->sw_if_index[VLIB_RX] = 0; /* "local0" */
281 vnet_buffer (b)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
283 ip = vlib_buffer_get_current (b);
284 memset (ip, 0, sizeof (*ip));
285 udp = (udp_header_t *) (ip + 1);
286 memset (udp, 0, sizeof (*udp));
288 dns_request = (u8 *) (udp + 1);
291 ip->ip_version_and_header_length = 0x45;
292 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b));
294 ip->protocol = IP_PROTOCOL_UDP;
295 ip->src_address.as_u32 = src_address->as_u32;
296 ip->dst_address.as_u32 = server->as_u32;
297 ip->checksum = ip4_header_checksum (ip);
300 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
301 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
302 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
303 vec_len (ep->dns_request));
306 /* The actual DNS request */
307 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
309 /* Ship it to ip4_lookup */
310 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
311 to_next = vlib_frame_vector_args (f);
314 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
316 ep->retry_timer = now + 2.0;
320 send_dns6_request (dns_main_t * dm,
321 dns_cache_entry_t * ep, ip6_address_t * server)
323 vlib_main_t *vm = dm->vlib_main;
324 f64 now = vlib_time_now (vm);
329 fib_node_index_t fei;
330 u32 sw_if_index, fib_index;
332 ip6_main_t *im6 = &ip6_main;
333 ip_lookup_main_t *lm6 = &im6->lookup_main;
334 ip_interface_address_t *ia = 0;
335 ip6_address_t *src_address;
339 int junk __attribute__ ((unused));
341 ASSERT (ep->dns_request);
343 /* Find a FIB path to the server */
344 clib_memcpy (&prefix.fp_addr, server, sizeof (*server));
345 prefix.fp_proto = FIB_PROTOCOL_IP6;
348 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
349 if (fib_index == (u32) ~ 0)
351 clib_warning ("no fib table");
355 fei = fib_table_lookup (fib_index, &prefix);
357 /* Couldn't find route to destination. Bail out. */
358 if (fei == FIB_NODE_INDEX_INVALID)
360 clib_warning ("no route to DNS server");
363 sw_if_index = fib_entry_get_resolving_interface (fei);
366 foreach_ip_interface_address(lm6, ia, sw_if_index, 1 /* honor unnummbered */,
368 src_address = ip_interface_address_get_address (lm6, ia);
369 goto found_src_address;
373 clib_warning ("FIB BUG");
378 /* Go get a buffer */
379 if (vlib_buffer_alloc (dm->vlib_main, &bi, 1) != 1)
382 b = vlib_get_buffer (vm, bi);
383 b->current_length = sizeof (ip6_header_t) + sizeof (udp_header_t) +
384 vec_len (ep->dns_request);
385 b->total_length_not_including_first_buffer = 0;
387 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
389 ip = vlib_buffer_get_current (b);
390 memset (ip, 0, sizeof (*ip));
391 udp = (udp_header_t *) (ip + 1);
392 memset (udp, 0, sizeof (*udp));
394 dns_request = (u8 *) (udp + 1);
397 ip->ip_version_traffic_class_and_flow_label =
398 clib_host_to_net_u32 (0x6 << 28);
401 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b)
402 - sizeof (ip6_header_t));
404 ip->protocol = IP_PROTOCOL_UDP;
405 clib_memcpy (&ip->src_address, src_address, sizeof (ip6_address_t));
406 clib_memcpy (&ip->dst_address, server, sizeof (ip6_address_t));
409 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
410 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
411 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
412 vec_len (ep->dns_request));
414 udp->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ip, &junk);
416 /* The actual DNS request */
417 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
419 /* Ship it to ip6_lookup */
420 f = vlib_get_frame_to_node (vm, ip6_lookup_node.index);
421 to_next = vlib_frame_vector_args (f);
425 ep->retry_timer = now + 2.0;
429 * Translate "foo.com" into "0x3 f o o 0x3 c o m 0x0"
430 * A historical / hysterical micro-TLV scheme. DGMS.
433 name_to_labels (u8 * name)
436 int last_label_index;
441 /* punch in space for the first length */
442 vec_insert (rv, 1, 0);
443 last_label_index = 0;
446 while (i < vec_len (rv))
450 rv[last_label_index] = (i - last_label_index) - 1;
451 if ((i - last_label_index) > 63)
452 clib_warning ("stupid name, label length %d",
453 i - last_label_index);
454 last_label_index = i;
459 /* Set the last real label length */
460 rv[last_label_index] = (i - last_label_index) - 1;
463 * Add a [sic] NULL root label. Otherwise, the name parser can't figure out
471 * arc-function for the above.
472 * Translate "0x3 f o o 0x3 c o m 0x0" into "foo.com"
473 * Produces a non-NULL-terminated u8 *vector. %v format is your friend.
476 labels_to_name (u8 * label, u8 * full_text, u8 ** parse_from_here)
483 *parse_from_here = 0;
485 /* chase initial pointer? */
486 if ((label[0] & 0xC0) == 0xC0)
488 *parse_from_here = label + 2;
489 offset = ((label[0] & 0x3f) << 8) + label[1];
490 label = full_text + offset;
497 for (i = 0; i < len; i++)
498 vec_add1 (reply, *label++);
501 if ((label[0] & 0xC0) == 0xC0)
503 *parse_from_here = label + 2;
504 offset = ((label[0] & 0x3f) << 8) + label[1];
505 label = full_text + offset;
510 vec_add1 (reply, '.');
512 if (*parse_from_here == 0)
513 *parse_from_here = label;
518 vnet_send_dns_request (dns_main_t * dm, dns_cache_entry_t * ep)
526 /* This can easily happen if sitting in GDB, etc. */
527 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
530 /* Construct the dns request, if we haven't been here already */
531 if (vec_len (ep->dns_request) == 0)
534 * Start with the variadic portion of the exercise.
535 * Turn the name into a set of DNS "labels". Max length
536 * per label is 63, enforce that.
538 request = name_to_labels (ep->name);
539 qp_offset = vec_len (request);
541 /* Add space for the query header */
542 vec_validate (request, qp_offset + sizeof (dns_query_t) - 1);
544 qp = (dns_query_t *) (request + qp_offset);
546 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
547 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
549 /* Punch in space for the dns_header_t */
550 vec_insert (request, sizeof (dns_header_t), 0);
552 h = (dns_header_t *) request;
554 /* Transaction ID = pool index */
555 h->id = clib_host_to_net_u16 (ep - dm->entries);
557 /* Ask for a recursive lookup */
558 tmp = DNS_RD | DNS_OPCODE_QUERY;
559 h->flags = clib_host_to_net_u16 (tmp);
560 h->qdcount = clib_host_to_net_u16 (1);
564 ep->dns_request = request;
567 /* Work out which server / address family we're going to use */
569 /* Retry using current server */
570 if (ep->retry_count++ < DNS_RETRIES_PER_SERVER)
572 if (ep->server_af == 1 /* ip6 */ )
574 if (vec_len (dm->ip6_name_servers))
576 send_dns6_request (dm, ep,
577 dm->ip6_name_servers + ep->server_rotor);
583 if (vec_len (dm->ip4_name_servers))
585 send_dns4_request (dm, ep, dm->ip4_name_servers + ep->server_rotor);
589 else /* switch to a new server */
593 if (ep->server_af == 1 /* ip6 */ )
595 if (ep->server_rotor >= vec_len (dm->ip6_name_servers))
597 ep->server_rotor = 0;
598 ep->server_af = vec_len (dm->ip4_name_servers) > 0 ? 0 : 1;
603 if (ep->server_rotor >= vec_len (dm->ip4_name_servers))
605 ep->server_rotor = 0;
606 ep->server_af = vec_len (dm->ip6_name_servers) > 0 ? 1 : 0;
611 if (ep->server_af == 1 /* ip6 */ )
612 send_dns6_request (dm, ep, dm->ip6_name_servers + ep->server_rotor);
614 send_dns4_request (dm, ep, dm->ip4_name_servers + ep->server_rotor);
618 vlib_process_signal_event_mt (dm->vlib_main, dns_resolver_node.index,
619 DNS_RESOLVER_EVENT_PENDING, 0);
623 vnet_dns_delete_entry_by_index_nolock (dns_main_t * dm, u32 index)
625 dns_cache_entry_t *ep;
628 if (dm->is_enabled == 0)
629 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
631 if (pool_is_free_index (dm->entries, index))
632 return VNET_API_ERROR_NO_SUCH_ENTRY;
634 ep = pool_elt_at_index (dm->entries, index);
635 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_VALID))
637 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
638 if (index == dm->unresolved_entries[i])
640 vec_delete (dm->unresolved_entries, 1, i);
643 clib_warning ("pool elt %d supposedly pending, but not found...",
648 hash_unset_mem (dm->cache_entry_by_name, ep->name);
650 vec_free (ep->api_clients_to_notify);
651 vec_free (ep->api_client_contexts);
652 vec_free (ep->ip4_peers_to_notify);
653 vec_free (ep->ip6_peers_to_notify);
654 pool_put (dm->entries, ep);
660 dns_delete_by_name (dns_main_t * dm, u8 * name)
665 if (dm->is_enabled == 0)
666 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
669 p = hash_get_mem (dm->cache_entry_by_name, name);
672 dns_cache_unlock (dm);
673 return VNET_API_ERROR_NO_SUCH_ENTRY;
675 rv = vnet_dns_delete_entry_by_index_nolock (dm, p[0]);
677 dns_cache_unlock (dm);
683 delete_random_entry (dns_main_t * dm)
686 u32 victim_index, start_index, i;
688 dns_cache_entry_t *ep;
690 if (dm->is_enabled == 0)
691 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
694 * Silence spurious coverity warning. We know pool_elts >> 0, or
695 * we wouldn't be here...
698 if (pool_elts (dm->entries) == 0)
699 return VNET_API_ERROR_UNSPECIFIED;
703 limit = pool_elts (dm->entries);
704 start_index = random_u32 (&dm->random_seed) % limit;
706 for (i = 0; i < limit; i++)
708 victim_index = (start_index + i) % limit;
710 if (!pool_is_free_index (dm->entries, victim_index))
712 ep = pool_elt_at_index (dm->entries, victim_index);
713 /* Delete only valid, non-static entries */
714 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
715 && ((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0))
717 rv = vnet_dns_delete_entry_by_index_nolock (dm, victim_index);
718 dns_cache_unlock (dm);
723 dns_cache_unlock (dm);
725 clib_warning ("Couldn't find an entry to delete?");
726 return VNET_API_ERROR_UNSPECIFIED;
730 dns_add_static_entry (dns_main_t * dm, u8 * name, u8 * dns_reply_data)
732 dns_cache_entry_t *ep;
736 if (dm->is_enabled == 0)
737 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
740 p = hash_get_mem (dm->cache_entry_by_name, name);
743 dns_cache_unlock (dm);
744 return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
747 if (pool_elts (dm->entries) == dm->name_cache_size)
749 /* Will only fail if the cache is totally filled w/ static entries... */
750 rv = delete_random_entry (dm);
753 dns_cache_unlock (dm);
758 pool_get (dm->entries, ep);
759 memset (ep, 0, sizeof (*ep));
761 /* Note: consumes the name vector */
763 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
764 ep->flags = DNS_CACHE_ENTRY_FLAG_VALID | DNS_CACHE_ENTRY_FLAG_STATIC;
765 ep->dns_response = dns_reply_data;
767 dns_cache_unlock (dm);
772 dns_resolve_name (dns_main_t * dm,
773 u8 * name, u32 client_index, u32 client_context,
774 dns_cache_entry_t ** retp)
776 dns_cache_entry_t *ep;
781 now = vlib_time_now (dm->vlib_main);
783 /* In case we can't actually answer the question right now... */
788 p = hash_get_mem (dm->cache_entry_by_name, name);
791 ep = pool_elt_at_index (dm->entries, p[0]);
792 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
794 /* Has the entry expired? */
795 if (((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0)
796 && (now > ep->expiration_time))
799 u32 *indices_to_delete = 0;
802 * Take out the rest of the resolution chain
803 * This isn't optimal, but it won't happen very often.
807 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME))
809 vec_add1 (indices_to_delete, ep - dm->entries);
811 p = hash_get_mem (dm->cache_entry_by_name, ep->cname);
814 ep = pool_elt_at_index (dm->entries, p[0]);
818 vec_add1 (indices_to_delete, ep - dm->entries);
822 for (i = 0; i < vec_len (indices_to_delete); i++)
824 /* Reenable to watch re-resolutions */
827 ep = pool_elt_at_index (dm->entries,
828 indices_to_delete[i]);
829 clib_warning ("Re-resolve %s", ep->name);
832 vnet_dns_delete_entry_by_index_nolock
833 (dm, indices_to_delete[i]);
835 vec_free (indices_to_delete);
836 /* Yes, kill it... */
840 if (ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
846 /* Note: caller must drop the lock! */
853 * Resolution pending. Add request to the pending vector(s) */
854 vec_add1 (ep->api_clients_to_notify, client_index);
855 vec_add1 (ep->api_client_contexts, client_context);
856 dns_cache_unlock (dm);
862 if (pool_elts (dm->entries) == dm->name_cache_size)
864 /* Will only fail if the cache is totally filled w/ static entries... */
865 rv = delete_random_entry (dm);
868 dns_cache_unlock (dm);
873 /* add new hash table entry */
874 pool_get (dm->entries, ep);
875 memset (ep, 0, sizeof (*ep));
877 ep->name = format (0, "%s%c", name, 0);
878 _vec_len (ep->name) = vec_len (ep->name) - 1;
880 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
882 vec_add1 (dm->unresolved_entries, ep - dm->entries);
883 vec_add1 (ep->api_clients_to_notify, client_index);
884 vec_add1 (ep->api_client_contexts, client_context);
885 vnet_send_dns_request (dm, ep);
886 dns_cache_unlock (dm);
890 #define foreach_notification_to_move \
891 _(api_clients_to_notify) \
892 _(api_client_contexts) \
893 _(ip4_peers_to_notify) \
894 _(ip6_peers_to_notify)
897 * Handle cname indirection. JFC. Called with the cache locked.
898 * returns 0 if the reply is not a CNAME.
902 vnet_dns_cname_indirection_nolock (dns_main_t * dm, u32 ep_index, u8 * reply)
915 dns_cache_entry_t *ep, *next_ep;
918 h = (dns_header_t *) reply;
919 flags = clib_net_to_host_u16 (h->flags);
920 rcode = flags & DNS_RCODE_MASK;
922 /* See if the response is OK */
925 case DNS_RCODE_NO_ERROR:
928 case DNS_RCODE_NAME_ERROR:
929 case DNS_RCODE_FORMAT_ERROR:
930 case DNS_RCODE_SERVER_FAILURE:
931 case DNS_RCODE_NOT_IMPLEMENTED:
932 case DNS_RCODE_REFUSED:
936 curpos = (u8 *) (h + 1);
940 /* Skip the questions */
941 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
948 pos += sizeof (dns_query_t);
951 /* expect a pointer chase here for a CNAME record */
952 if ((pos2[0] & 0xC0) == 0xC0)
957 rr = (dns_rr_t *) pos;
959 /* This is a real record, not a CNAME record */
960 if (clib_net_to_host_u16 (rr->type) != DNS_TYPE_CNAME)
963 /* This is a CNAME record, chase the name chain. */
965 /* The last request is no longer pending.. */
966 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
967 if (ep_index == dm->unresolved_entries[i])
969 vec_delete (dm->unresolved_entries, 1, i);
970 goto found_last_request;
972 clib_warning ("pool elt %d supposedly pending, but not found...", ep_index);
976 now = vlib_time_now (dm->vlib_main);
977 cname = labels_to_name (rr->rdata, reply, &pos2);
980 _vec_len (cname) -= 1;
981 ep = pool_elt_at_index (dm->entries, ep_index);
983 ep->flags |= (DNS_CACHE_ENTRY_FLAG_CNAME | DNS_CACHE_ENTRY_FLAG_VALID);
984 /* Save the response */
985 ep->dns_response = reply;
986 /* Set up expiration time */
987 ep->expiration_time = now + clib_net_to_host_u32 (rr->ttl);
989 pool_get (dm->entries, next_ep);
991 /* Need to recompute ep post pool-get */
992 ep = pool_elt_at_index (dm->entries, ep_index);
994 memset (next_ep, 0, sizeof (*next_ep));
995 next_ep->name = vec_dup (cname);
996 vec_add1 (next_ep->name, 0);
997 _vec_len (next_ep->name) -= 1;
999 hash_set_mem (dm->cache_entry_by_name, next_ep->name,
1000 next_ep - dm->entries);
1002 /* Use the same server */
1003 next_ep->server_rotor = ep->server_rotor;
1004 next_ep->server_af = ep->server_af;
1006 /* Move notification data to the next name in the chain */
1007 #define _(a) next_ep->a = ep->a; ep->a = 0;
1008 foreach_notification_to_move;
1011 request = name_to_labels (cname);
1013 qp_offset = vec_len (request);
1015 /* Add space for the query header */
1016 vec_validate (request, qp_offset + sizeof (dns_query_t) - 1);
1018 qp = (dns_query_t *) (request + qp_offset);
1020 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1021 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1023 /* Punch in space for the dns_header_t */
1024 vec_insert (request, sizeof (dns_header_t), 0);
1026 h = (dns_header_t *) request;
1028 /* Transaction ID = pool index */
1029 h->id = clib_host_to_net_u16 (next_ep - dm->entries);
1031 /* Ask for a recursive lookup */
1032 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
1033 h->qdcount = clib_host_to_net_u16 (1);
1037 next_ep->dns_request = request;
1038 next_ep->retry_timer = now + 2.0;
1039 next_ep->retry_count = 0;
1042 * Enable this to watch recursive resolution happen...
1043 * fformat (stdout, "%U", format_dns_reply, request, 2);
1046 vec_add1 (dm->unresolved_entries, next_ep - dm->entries);
1047 vnet_send_dns_request (dm, next_ep);
1052 vnet_dns_response_to_reply (u8 * response,
1053 vl_api_dns_resolve_name_reply_t * rmp,
1066 h = (dns_header_t *) response;
1067 flags = clib_net_to_host_u16 (h->flags);
1068 rcode = flags & DNS_RCODE_MASK;
1070 /* See if the response is OK, etc. */
1074 case DNS_RCODE_NO_ERROR:
1077 case DNS_RCODE_NAME_ERROR:
1078 case DNS_RCODE_FORMAT_ERROR:
1079 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1081 case DNS_RCODE_SERVER_FAILURE:
1082 case DNS_RCODE_NOT_IMPLEMENTED:
1083 case DNS_RCODE_REFUSED:
1084 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1087 /* No answers? Loser... */
1088 if (clib_net_to_host_u16 (h->anscount) < 1)
1089 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1091 curpos = (u8 *) (h + 1);
1093 /* Skip the name we asked about */
1096 /* Should never happen, but stil... */
1097 if ((len & 0xC0) == 0xC0)
1101 /* skip the name / label-set */
1110 limit = clib_net_to_host_u16 (h->qdcount);
1111 qp = (dns_query_t *) curpos;
1116 limit = clib_net_to_host_u16 (h->anscount);
1118 for (i = 0; i < limit; i++)
1122 /* Expect pointer chases in the answer section... */
1123 if ((pos[0] & 0xC0) == 0xC0)
1130 if ((pos[0] & 0xC0) == 0xC0)
1142 rr = (dns_rr_t *) curpos;
1144 switch (clib_net_to_host_u16 (rr->type))
1147 /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1148 memcpy (rmp->ip4_address, rr->rdata, sizeof (ip4_address_t));
1150 ttl = clib_net_to_host_u32 (rr->ttl);
1151 if (min_ttlp && *min_ttlp > ttl)
1155 /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1156 memcpy (rmp->ip6_address, rr->rdata, sizeof (ip6_address_t));
1157 ttl = clib_net_to_host_u32 (rr->ttl);
1158 if (min_ttlp && *min_ttlp > ttl)
1165 /* Might as well stop ASAP */
1166 if (rmp->ip4_set && rmp->ip6_set)
1168 curpos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1171 if ((rmp->ip4_set + rmp->ip6_set) == 0)
1172 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1177 vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1179 dns_main_t *dm = &dns_main;
1180 vl_api_dns_resolve_name_reply_t *rmp;
1181 dns_cache_entry_t *ep;
1184 /* Sanitize the name slightly */
1185 mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1187 rv = dns_resolve_name (dm, mp->name, mp->client_index, mp->context, &ep);
1189 /* Error, e.g. not enabled? Tell the user */
1192 REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1196 /* Resolution pending? Don't reply... */
1201 REPLY_MACRO2(VL_API_DNS_RESOLVE_NAME_REPLY,
1203 rv = vnet_dns_response_to_reply (ep->dns_response, rmp, 0 /* ttl-ptr */);
1204 rmp->retval = clib_host_to_net_u32 (rv);
1209 * dns_resolve_name leaves the cache locked when it returns
1210 * a cached result, so unlock it here.
1212 dns_cache_unlock (dm);
1215 #define vl_msg_name_crc_list
1216 #include <vpp/api/vpe_all_api_h.h>
1217 #undef vl_msg_name_crc_list
1220 setup_message_id_table (api_main_t * am)
1222 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1223 foreach_vl_msg_name_crc_dns;
1227 #define foreach_dns_api_msg \
1228 _(DNS_ENABLE_DISABLE, dns_enable_disable) \
1229 _(DNS_NAME_SERVER_ADD_DEL, dns_name_server_add_del) \
1230 _(DNS_RESOLVE_NAME, dns_resolve_name)
1232 static clib_error_t *
1233 dns_api_hookup (vlib_main_t * vm)
1236 vl_msg_api_set_handlers(VL_API_##N, #n, \
1237 vl_api_##n##_t_handler, \
1239 vl_api_##n##_t_endian, \
1240 vl_api_##n##_t_print, \
1241 sizeof(vl_api_##n##_t), 1);
1242 foreach_dns_api_msg;
1245 setup_message_id_table (&api_main);
1249 VLIB_API_INIT_FUNCTION (dns_api_hookup);
1252 static clib_error_t *
1253 dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1255 dns_main_t *dm = &dns_main;
1257 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1259 if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1261 else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1264 return clib_error_return (0, "unknown input `%U'",
1265 format_unformat_error, input);
1270 VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1272 static clib_error_t *
1273 dns_init (vlib_main_t * vm)
1275 dns_main_t *dm = &dns_main;
1278 dm->vnet_main = vnet_get_main ();
1279 dm->name_cache_size = 65535;
1280 dm->max_ttl_in_seconds = 86400;
1281 dm->random_seed = 0xDEADDABE;
1283 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply, dns46_reply_node.index,
1286 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply6, dns46_reply_node.index,
1290 udp_register_dst_port (vm, UDP_DST_PORT_dns, dns4_request_node.index,
1292 udp_register_dst_port (vm, UDP_DST_PORT_dns6, dns6_request_node.index,
1299 VLIB_INIT_FUNCTION (dns_init);
1302 unformat_dns_reply (unformat_input_t * input, va_list * args)
1304 u8 **result = va_arg (*args, u8 **);
1305 u8 **namep = va_arg (*args, u8 **);
1319 if (unformat (input, "%v", &name))
1322 if (unformat (input, "%U", unformat_ip4_address, &a4))
1325 if (unformat (input, "%U", unformat_ip6_address, &a6))
1329 if (unformat (input, "%U", unformat_ip6_address, &a6))
1332 if (unformat (input, "%U", unformat_ip4_address, &a6))
1336 /* Must have a name */
1340 /* Must have at least one address */
1341 if (!(a4_set + a6_set))
1344 /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1345 ce = name_to_labels (name);
1346 qp_offset = vec_len (ce);
1348 /* Add space for the query header */
1349 vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1350 qp = (dns_query_t *) (ce + qp_offset);
1352 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1353 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1355 /* Punch in space for the dns_header_t */
1356 vec_insert (ce, sizeof (dns_header_t), 0);
1358 h = (dns_header_t *) ce;
1360 /* Fake Transaction ID */
1363 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1364 h->qdcount = clib_host_to_net_u16 (1);
1365 h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1369 /* Now append one or two A/AAAA RR's... */
1372 /* Pointer to the name (DGMS) */
1373 vec_add1 (ce, 0xC0);
1374 vec_add1 (ce, 0x0C);
1375 vec_add2 (ce, rru8, sizeof (*rr) + 4);
1377 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1378 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1379 rr->ttl = clib_host_to_net_u32 (86400);
1380 rr->rdlength = clib_host_to_net_u16 (4);
1381 memcpy (rr->rdata, &a4, sizeof (a4));
1385 /* Pointer to the name (DGMS) */
1386 vec_add1 (ce, 0xC0);
1387 vec_add1 (ce, 0x0C);
1388 vec_add2 (ce, rru8, sizeof (*rr) + 16);
1390 rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1391 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1392 rr->ttl = clib_host_to_net_u32 (86400);
1393 rr->rdlength = clib_host_to_net_u16 (16);
1394 memcpy (rr->rdata, &a6, sizeof (a6));
1406 format_dns_query (u8 * s, va_list * args)
1408 u8 **curpos = va_arg (*args, u8 **);
1409 int verbose = va_arg (*args, int);
1414 s = format (s, " Name: ");
1416 /* Unwind execrated counted-label sheit */
1422 for (i = 0; i < len; i++)
1423 vec_add1 (s, *pos++);
1435 qp = (dns_query_t *) pos;
1438 switch (clib_net_to_host_u16 (qp->type))
1441 s = format (s, "type A\n");
1444 s = format (s, "type AAAA\n");
1447 s = format (s, "type ALL\n");
1451 s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1456 pos += sizeof (*qp);
1463 * format dns reply data
1464 * verbose > 1, dump everything
1465 * verbose == 1, dump all A and AAAA records
1466 * verbose == 0, dump one A record, and one AAAA record
1470 format_dns_reply_data (u8 * s, va_list * args)
1472 u8 *reply = va_arg (*args, u8 *);
1473 u8 **curpos = va_arg (*args, u8 **);
1474 int verbose = va_arg (*args, int);
1475 int *print_ip4 = va_arg (*args, int *);
1476 int *print_ip6 = va_arg (*args, int *);
1481 int initial_pointer_chase = 0;
1484 pos = pos2 = *curpos;
1487 s = format (s, " ");
1489 /* chase pointer? almost always yes here... */
1490 if (pos2[0] == 0xc0)
1492 pos2 = reply + pos2[1];
1494 initial_pointer_chase = 1;
1501 for (i = 0; i < len; i++)
1504 vec_add1 (s, *pos2);
1520 if (initial_pointer_chase == 0)
1523 rr = (dns_rr_t *) pos;
1525 switch (clib_net_to_host_u16 (rr->type))
1530 s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1531 format_ip4_address, rr->rdata);
1536 s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1537 clib_net_to_host_u32 (rr->ttl));
1542 pos += sizeof (*rr) + 4;
1548 s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1549 format_ip6_address, rr->rdata);
1554 s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1555 clib_net_to_host_u32 (rr->ttl));
1559 pos += sizeof (*rr) + 16;
1565 s = format (s, "TEXT: ");
1566 for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1567 vec_add1 (s, rr->rdata[i]);
1570 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1573 case DNS_TYPE_HINFO:
1575 /* Two counted strings. DGMS */
1581 s = format (s, "HINFO: ");
1584 for (i = 0; i < *len; i++)
1585 vec_add1 (s, *curpos++);
1589 for (i = 0; i < *len; i++)
1590 vec_add1 (s, *curpos++);
1595 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1598 case DNS_TYPE_NAMESERVER:
1601 s = format (s, "Nameserver: ");
1604 /* chase pointer? */
1605 if (pos2[0] == 0xc0)
1606 pos2 = reply + pos2[1];
1612 for (i = 0; i < len; i++)
1613 vec_add1 (s, *pos2++);
1615 /* chase pointer, typically to offset 12... */
1616 if (pos2[0] == 0xC0)
1617 pos2 = reply + pos2[1];
1626 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1629 case DNS_TYPE_MAIL_EXCHANGE:
1632 tp = (u16 *) rr->rdata;
1634 s = format (s, "Mail Exchange: Preference %d ", (u32)
1635 clib_net_to_host_u16 (*tp));
1637 pos2 = rr->rdata + 2;
1639 /* chase pointer? */
1640 if (pos2[0] == 0xc0)
1641 pos2 = reply + pos2[1];
1647 for (i = 0; i < len; i++)
1648 vec_add1 (s, *pos2++);
1651 if (pos2[0] == 0xC0)
1652 pos2 = reply + pos2[1];
1662 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1665 case DNS_TYPE_CNAME:
1668 tp = (u16 *) rr->rdata;
1670 s = format (s, "CNAME: ");
1674 /* chase pointer? */
1675 if (pos2[0] == 0xc0)
1676 pos2 = reply + pos2[1];
1682 for (i = 0; i < len; i++)
1683 vec_add1 (s, *pos2++);
1686 if (pos2[0] == 0xC0)
1687 pos2 = reply + pos2[1];
1696 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1701 s = format (s, "type %d: len %d\n",
1702 (int) clib_net_to_host_u16 (rr->type),
1703 sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
1704 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1714 format_dns_reply (u8 * s, va_list * args)
1716 u8 *reply_as_u8 = va_arg (*args, u8 *);
1717 int verbose = va_arg (*args, int);
1725 h = (dns_header_t *) reply_as_u8;
1726 id = clib_net_to_host_u16 (h->id);
1727 flags = clib_net_to_host_u16 (h->flags);
1731 s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
1733 s = format (s, " %s %s %s %s\n",
1734 (flags & DNS_RA) ? "recur" : "no-recur",
1735 (flags & DNS_RD) ? "recur-des" : "no-recur-des",
1736 (flags & DNS_TC) ? "trunc" : "no-trunc",
1737 (flags & DNS_AA) ? "auth" : "non-auth");
1738 s = format (s, " %d queries, %d answers, %d name-servers,"
1740 clib_net_to_host_u16 (h->qdcount),
1741 clib_net_to_host_u16 (h->anscount),
1742 clib_net_to_host_u16 (h->nscount),
1743 clib_net_to_host_u16 (h->arcount));
1746 curpos = (u8 *) (h + 1);
1751 s = format (s, " Queries:\n");
1752 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
1754 /* The query is variable-length, so curpos is a value-result parm */
1755 s = format (s, "%U", format_dns_query, &curpos, verbose);
1761 s = format (s, " Replies:\n");
1763 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
1765 /* curpos is a value-result parm */
1766 s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
1767 verbose, &print_ip4, &print_ip6);
1774 format_dns_cache (u8 * s, va_list * args)
1776 dns_main_t *dm = va_arg (*args, dns_main_t *);
1777 f64 now = va_arg (*args, f64);
1778 int verbose = va_arg (*args, int);
1779 u8 *name = va_arg (*args, u8 *);
1780 dns_cache_entry_t *ep;
1784 if (dm->is_enabled == 0)
1786 s = format (s, "The DNS cache is disabled...");
1790 if (pool_elts (dm->entries) == 0)
1792 s = format (s, "The DNS cache is empty...");
1796 dns_cache_lock (dm);
1800 p = hash_get_mem (dm->cache_entry_by_name, name);
1803 s = format (s, "%s is not in the cache...", name);
1804 dns_cache_unlock (dm);
1808 ep = pool_elt_at_index (dm->entries, p[0]);
1809 /* Magic to spit out a C-initializer to research hemorrhoids... */
1813 s = format (s, "static u8 dns_reply_data_initializer[] =\n");
1814 s = format (s, "{\n");
1816 for (i = 0; i < vec_len (ep->dns_response); i++)
1823 s = format (s, "0x%02x, ", ep->dns_response[i]);
1825 s = format (s, "};\n");
1829 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
1831 ASSERT (ep->dns_response);
1832 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
1837 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
1838 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
1840 s = format (s, "%s%s -> %U", ss, ep->name,
1841 format_dns_reply, ep->dns_response, verbose);
1842 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
1844 f64 time_left = ep->expiration_time - now;
1845 if (time_left > 0.0)
1846 s = format (s, " TTL left %.1f", time_left);
1848 s = format (s, " EXPIRED");
1853 ASSERT (ep->dns_request);
1854 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
1863 pool_foreach (ep, dm->entries,
1865 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
1867 ASSERT (ep->dns_response);
1868 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
1873 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
1874 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
1876 s = format (s, "%s%s -> %U", ss, ep->name,
1880 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
1882 f64 time_left = ep->expiration_time - now;
1883 if (time_left > 0.0)
1884 s = format (s, " TTL left %.1f", time_left);
1886 s = format (s, " EXPIRED");
1889 s = format (s, " %d client notifications pending\n",
1890 vec_len(ep->api_clients_to_notify));
1895 ASSERT (ep->dns_request);
1896 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
1903 dns_cache_unlock (dm);
1908 static clib_error_t *
1909 show_dns_cache_command_fn (vlib_main_t * vm,
1910 unformat_input_t * input, vlib_cli_command_t * cmd)
1912 dns_main_t *dm = &dns_main;
1915 f64 now = vlib_time_now (vm);
1917 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1919 if (unformat (input, "verbose %d", &verbose))
1921 else if (unformat (input, "verbose"))
1923 else if (unformat (input, "name %s", &name))
1926 return clib_error_return (0, "unknown input `%U'",
1927 format_unformat_error, input);
1930 vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
1936 VLIB_CLI_COMMAND (show_dns_cache_command) =
1938 .path = "show dns cache",
1939 .short_help = "show dns cache [verbose [nn]]",
1940 .function = show_dns_cache_command_fn,
1944 static clib_error_t *
1945 dns_cache_add_del_command_fn (vlib_main_t * vm,
1946 unformat_input_t * input,
1947 vlib_cli_command_t * cmd)
1949 dns_main_t *dm = &dns_main;
1955 clib_error_t *error;
1957 if (unformat (input, "add"))
1959 if (unformat (input, "del"))
1961 if (unformat (input, "clear"))
1964 if (is_add == -1 && is_clear == -1)
1965 return clib_error_return (0, "add / del / clear required...");
1969 rv = dns_cache_clear (dm);
1975 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
1976 error = clib_error_return (0, "Name resolution not enabled");
1981 /* Delete (by name)? */
1984 if (unformat (input, "%v", &name))
1986 rv = dns_delete_by_name (dm, name);
1989 case VNET_API_ERROR_NO_SUCH_ENTRY:
1990 error = clib_error_return (0, "%v not in the cache...", name);
1994 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
1995 error = clib_error_return (0, "Name resolution not enabled");
2004 error = clib_error_return (0, "dns_delete_by_name returned %d",
2010 return clib_error_return (0, "unknown input `%U'",
2011 format_unformat_error, input);
2014 /* Note: dns_add_static_entry consumes the name vector if OK... */
2015 if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2017 rv = dns_add_static_entry (dm, name, dns_reply_data);
2020 case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2022 vec_free (dns_reply_data);
2023 return clib_error_return (0, "%v already in the cache...", name);
2028 return clib_error_return (0, "dns_add_static_entry returned %d",
2037 VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2039 .path = "dns cache",
2040 .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2041 .function = dns_cache_add_del_command_fn,
2045 #define DNS_FORMAT_TEST 1
2047 #if DNS_FORMAT_TEST > 0
2050 static u8 dns_reply_data_initializer[] =
2051 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2052 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2054 0x0, 0xff, /* type ALL */
2055 0x0, 0x1, /* class IN */
2056 0xc0, 0xc, /* pointer to yahoo.com name */
2057 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2058 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2059 0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2060 0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2061 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2062 0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2063 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2064 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2065 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2066 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2067 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2068 0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2069 0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2071 0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2072 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2073 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2074 0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2075 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2077 0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2078 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2079 0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2080 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2082 0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2083 0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2085 0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2087 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2089 0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2091 0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2092 0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2093 0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2097 /* www.cisco.com, has no addresses in reply */
2098 static u8 dns_reply_data_initializer[] = {
2099 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2100 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2101 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2103 0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2104 0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2105 0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2106 0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2107 0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2111 static u8 dns_reply_data_initializer[] =
2112 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
2113 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
2114 0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
2115 0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
2117 0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
2118 0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
2119 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
2120 0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
2121 0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
2122 0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
2123 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
2124 0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
2125 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
2126 0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
2127 0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
2128 0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
2129 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
2130 0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
2131 0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
2132 0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
2133 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2134 0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
2135 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
2136 0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
2137 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
2138 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
2139 0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
2141 0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2145 static clib_error_t *
2146 test_dns_fmt_command_fn (vlib_main_t * vm,
2147 unformat_input_t * input, vlib_cli_command_t * cmd)
2149 u8 *dns_reply_data = 0;
2152 vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2154 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2156 if (unformat (input, "verbose %d", &verbose))
2158 else if (unformat (input, "verbose"))
2161 return clib_error_return (0, "unknown input `%U'",
2162 format_unformat_error, input);
2165 vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2167 memcpy (dns_reply_data, dns_reply_data_initializer,
2168 ARRAY_LEN (dns_reply_data_initializer));
2170 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2172 memset (rmp, 0, sizeof (*rmp));
2174 rv = vnet_dns_response_to_reply (dns_reply_data, rmp, 0 /* ttl-ptr */ );
2178 case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2179 vlib_cli_output (vm, "no addresses found...");
2183 vlib_cli_output (vm, "response to reply returned %d", rv);
2188 vlib_cli_output (vm, "ip4 address: %U", format_ip4_address,
2189 (ip4_address_t *) rmp->ip4_address);
2191 vlib_cli_output (vm, "ip6 address: %U", format_ip6_address,
2192 (ip6_address_t *) rmp->ip6_address);
2196 vec_free (dns_reply_data);
2203 VLIB_CLI_COMMAND (test_dns_fmt_command) =
2205 .path = "test dns format",
2206 .short_help = "test dns format",
2207 .function = test_dns_fmt_command_fn,
2211 static clib_error_t *
2212 test_dns_unfmt_command_fn (vlib_main_t * vm,
2213 unformat_input_t * input, vlib_cli_command_t * cmd)
2215 u8 *dns_reply_data = 0;
2219 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2221 if (unformat (input, "verbose %d", &verbose))
2223 else if (unformat (input, "verbose"))
2225 else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2228 return clib_error_return (0, "unknown input `%U'",
2229 format_unformat_error, input);
2233 return clib_error_return (0, "dns data not set...");
2235 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2237 vec_free (dns_reply_data);
2243 VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2245 .path = "test dns unformat",
2246 .short_help = "test dns unformat <name> [ip4][ip6]",
2247 .function = test_dns_unfmt_command_fn,
2251 static clib_error_t *
2252 test_dns_expire_command_fn (vlib_main_t * vm,
2253 unformat_input_t * input,
2254 vlib_cli_command_t * cmd)
2256 dns_main_t *dm = &dns_main;
2260 dns_cache_entry_t *ep;
2262 if (unformat (input, "%v", &name))
2265 _vec_len (name) -= 1;
2268 dns_cache_lock (dm);
2270 p = hash_get_mem (dm->cache_entry_by_name, name);
2273 dns_cache_unlock (dm);
2274 e = clib_error_return (0, "%s is not in the cache...", name);
2279 ep = pool_elt_at_index (dm->entries, p[0]);
2281 ep->expiration_time = 0;
2287 VLIB_CLI_COMMAND (test_dns_expire_command) =
2289 .path = "test dns expire",
2290 .short_help = "test dns expire <name>",
2291 .function = test_dns_expire_command_fn,
2297 * fd.io coding-style-patch-verification: ON
2300 * eval: (c-set-style "gnu")