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 limit = pool_elts (dm->entries);
695 start_index = random_u32 (&dm->random_seed) % limit;
697 for (i = 0; i < limit; i++)
699 victim_index = (start_index + i) % limit;
701 if (!pool_is_free_index (dm->entries, victim_index))
703 ep = pool_elt_at_index (dm->entries, victim_index);
704 /* Delete only valid, non-static entries */
705 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
706 && ((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0))
708 rv = vnet_dns_delete_entry_by_index_nolock (dm, victim_index);
709 dns_cache_unlock (dm);
714 dns_cache_unlock (dm);
716 clib_warning ("Couldn't find an entry to delete?");
717 return VNET_API_ERROR_UNSPECIFIED;
721 dns_add_static_entry (dns_main_t * dm, u8 * name, u8 * dns_reply_data)
723 dns_cache_entry_t *ep;
727 if (dm->is_enabled == 0)
728 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
731 p = hash_get_mem (dm->cache_entry_by_name, name);
734 dns_cache_unlock (dm);
735 return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
738 if (pool_elts (dm->entries) == dm->name_cache_size)
740 /* Will only fail if the cache is totally filled w/ static entries... */
741 rv = delete_random_entry (dm);
744 dns_cache_unlock (dm);
749 pool_get (dm->entries, ep);
750 memset (ep, 0, sizeof (*ep));
752 /* Note: consumes the name vector */
754 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
755 ep->flags = DNS_CACHE_ENTRY_FLAG_VALID | DNS_CACHE_ENTRY_FLAG_STATIC;
756 ep->dns_response = dns_reply_data;
758 dns_cache_unlock (dm);
763 dns_resolve_name (dns_main_t * dm,
764 u8 * name, u32 client_index, u32 client_context,
765 dns_cache_entry_t ** retp)
767 dns_cache_entry_t *ep;
772 now = vlib_time_now (dm->vlib_main);
774 /* In case we can't actually answer the question right now... */
779 p = hash_get_mem (dm->cache_entry_by_name, name);
782 ep = pool_elt_at_index (dm->entries, p[0]);
783 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
785 /* Has the entry expired? */
786 if (((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0)
787 && (now > ep->expiration_time))
790 u32 *indices_to_delete = 0;
793 * Take out the rest of the resolution chain
794 * This isn't optimal, but it won't happen very often.
798 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME))
800 vec_add1 (indices_to_delete, ep - dm->entries);
802 p = hash_get_mem (dm->cache_entry_by_name, ep->cname);
805 ep = pool_elt_at_index (dm->entries, p[0]);
809 vec_add1 (indices_to_delete, ep - dm->entries);
813 for (i = 0; i < vec_len (indices_to_delete); i++)
815 /* Reenable to watch re-resolutions */
818 ep = pool_elt_at_index (dm->entries,
819 indices_to_delete[i]);
820 clib_warning ("Re-resolve %s", ep->name);
823 vnet_dns_delete_entry_by_index_nolock
824 (dm, indices_to_delete[i]);
826 vec_free (indices_to_delete);
827 /* Yes, kill it... */
831 if (ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
837 /* Note: caller must drop the lock! */
844 * Resolution pending. Add request to the pending vector(s) */
845 vec_add1 (ep->api_clients_to_notify, client_index);
846 vec_add1 (ep->api_client_contexts, client_context);
847 dns_cache_unlock (dm);
853 if (pool_elts (dm->entries) == dm->name_cache_size)
855 /* Will only fail if the cache is totally filled w/ static entries... */
856 rv = delete_random_entry (dm);
859 dns_cache_unlock (dm);
864 /* add new hash table entry */
865 pool_get (dm->entries, ep);
866 memset (ep, 0, sizeof (*ep));
868 ep->name = format (0, "%s%c", name, 0);
869 _vec_len (ep->name) = vec_len (ep->name) - 1;
871 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
873 vec_add1 (dm->unresolved_entries, ep - dm->entries);
874 vec_add1 (ep->api_clients_to_notify, client_index);
875 vec_add1 (ep->api_client_contexts, client_context);
876 vnet_send_dns_request (dm, ep);
877 dns_cache_unlock (dm);
881 #define foreach_notification_to_move \
882 _(api_clients_to_notify) \
883 _(api_client_contexts) \
884 _(ip4_peers_to_notify) \
885 _(ip6_peers_to_notify)
888 * Handle cname indirection. JFC. Called with the cache locked.
889 * returns 0 if the reply is not a CNAME.
893 vnet_dns_cname_indirection_nolock (dns_main_t * dm, u32 ep_index, u8 * reply)
906 dns_cache_entry_t *ep, *next_ep;
909 h = (dns_header_t *) reply;
910 flags = clib_net_to_host_u16 (h->flags);
911 rcode = flags & DNS_RCODE_MASK;
913 /* See if the response is OK */
916 case DNS_RCODE_NO_ERROR:
919 case DNS_RCODE_NAME_ERROR:
920 case DNS_RCODE_FORMAT_ERROR:
921 case DNS_RCODE_SERVER_FAILURE:
922 case DNS_RCODE_NOT_IMPLEMENTED:
923 case DNS_RCODE_REFUSED:
927 curpos = (u8 *) (h + 1);
931 /* Skip the questions */
932 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
939 qp = (dns_query_t *) pos;
943 /* expect a pointer chase here for a CNAME record */
944 if ((pos2[0] & 0xC0) == 0xC0)
949 rr = (dns_rr_t *) pos;
951 /* This is a real record, not a CNAME record */
952 if (clib_net_to_host_u16 (rr->type) != DNS_TYPE_CNAME)
955 /* This is a CNAME record, chase the name chain. */
957 /* The last request is no longer pending.. */
958 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
959 if (ep_index == dm->unresolved_entries[i])
961 vec_delete (dm->unresolved_entries, 1, i);
962 goto found_last_request;
964 clib_warning ("pool elt %d supposedly pending, but not found...", ep_index);
968 now = vlib_time_now (dm->vlib_main);
969 cname = labels_to_name (rr->rdata, reply, &pos2);
972 _vec_len (cname) -= 1;
973 ep = pool_elt_at_index (dm->entries, ep_index);
975 ep->flags |= (DNS_CACHE_ENTRY_FLAG_CNAME | DNS_CACHE_ENTRY_FLAG_VALID);
976 /* Save the response */
977 ep->dns_response = reply;
978 /* Set up expiration time */
979 ep->expiration_time = now + clib_net_to_host_u32 (rr->ttl);
981 pool_get (dm->entries, next_ep);
983 /* Need to recompute ep post pool-get */
984 ep = pool_elt_at_index (dm->entries, ep_index);
986 memset (next_ep, 0, sizeof (*next_ep));
987 next_ep->name = vec_dup (cname);
988 vec_add1 (next_ep->name, 0);
989 _vec_len (next_ep->name) -= 1;
991 hash_set_mem (dm->cache_entry_by_name, next_ep->name,
992 next_ep - dm->entries);
994 /* Use the same server */
995 next_ep->server_rotor = ep->server_rotor;
996 next_ep->server_af = ep->server_af;
998 /* Move notification data to the next name in the chain */
999 #define _(a) next_ep->a = ep->a; ep->a = 0;
1000 foreach_notification_to_move;
1003 request = name_to_labels (cname);
1005 qp_offset = vec_len (request);
1007 /* Add space for the query header */
1008 vec_validate (request, qp_offset + sizeof (dns_query_t) - 1);
1010 qp = (dns_query_t *) (request + qp_offset);
1012 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1013 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1015 /* Punch in space for the dns_header_t */
1016 vec_insert (request, sizeof (dns_header_t), 0);
1018 h = (dns_header_t *) request;
1020 /* Transaction ID = pool index */
1021 h->id = clib_host_to_net_u16 (next_ep - dm->entries);
1023 /* Ask for a recursive lookup */
1024 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
1025 h->qdcount = clib_host_to_net_u16 (1);
1029 next_ep->dns_request = request;
1030 next_ep->retry_timer = now + 2.0;
1031 next_ep->retry_count = 0;
1034 * Enable this to watch recursive resolution happen...
1035 * fformat (stdout, "%U", format_dns_reply, request, 2);
1038 vec_add1 (dm->unresolved_entries, next_ep - dm->entries);
1039 vnet_send_dns_request (dm, next_ep);
1044 vnet_dns_response_to_reply (u8 * response,
1045 vl_api_dns_resolve_name_reply_t * rmp,
1058 h = (dns_header_t *) response;
1059 flags = clib_net_to_host_u16 (h->flags);
1060 rcode = flags & DNS_RCODE_MASK;
1062 /* See if the response is OK, etc. */
1066 case DNS_RCODE_NO_ERROR:
1069 case DNS_RCODE_NAME_ERROR:
1070 case DNS_RCODE_FORMAT_ERROR:
1071 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1073 case DNS_RCODE_SERVER_FAILURE:
1074 case DNS_RCODE_NOT_IMPLEMENTED:
1075 case DNS_RCODE_REFUSED:
1076 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1079 /* No answers? Loser... */
1080 if (clib_net_to_host_u16 (h->anscount) < 1)
1081 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1083 curpos = (u8 *) (h + 1);
1085 /* Skip the name we asked about */
1088 /* Should never happen, but stil... */
1089 if ((len & 0xC0) == 0xC0)
1093 /* skip the name / label-set */
1102 limit = clib_net_to_host_u16 (h->qdcount);
1103 qp = (dns_query_t *) curpos;
1108 limit = clib_net_to_host_u16 (h->anscount);
1110 for (i = 0; i < limit; i++)
1114 /* Expect pointer chases in the answer section... */
1115 if ((pos[0] & 0xC0) == 0xC0)
1122 if ((pos[0] & 0xC0) == 0xC0)
1133 rr = (dns_rr_t *) curpos;
1135 switch (clib_net_to_host_u16 (rr->type))
1138 /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1139 memcpy (rmp->ip4_address, rr->rdata, sizeof (ip4_address_t));
1141 ttl = clib_net_to_host_u32 (rr->ttl);
1142 if (min_ttlp && *min_ttlp > ttl)
1146 /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1147 memcpy (rmp->ip6_address, rr->rdata, sizeof (ip6_address_t));
1148 ttl = clib_net_to_host_u32 (rr->ttl);
1149 if (min_ttlp && *min_ttlp > ttl)
1156 /* Might as well stop ASAP */
1157 if (rmp->ip4_set && rmp->ip6_set)
1159 curpos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1162 if ((rmp->ip4_set + rmp->ip6_set) == 0)
1163 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1168 vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1170 dns_main_t *dm = &dns_main;
1171 vl_api_dns_resolve_name_reply_t *rmp;
1172 dns_cache_entry_t *ep;
1175 /* Sanitize the name slightly */
1176 mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1178 rv = dns_resolve_name (dm, mp->name, mp->client_index, mp->context, &ep);
1180 /* Error, e.g. not enabled? Tell the user */
1183 REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1187 /* Resolution pending? Don't reply... */
1192 REPLY_MACRO2(VL_API_DNS_RESOLVE_NAME_REPLY,
1194 rv = vnet_dns_response_to_reply (ep->dns_response, rmp, 0 /* ttl-ptr */);
1195 rmp->retval = clib_host_to_net_u32 (rv);
1200 * dns_resolve_name leaves the cache locked when it returns
1201 * a cached result, so unlock it here.
1203 dns_cache_unlock (dm);
1206 #define vl_msg_name_crc_list
1207 #include <vpp/api/vpe_all_api_h.h>
1208 #undef vl_msg_name_crc_list
1211 setup_message_id_table (api_main_t * am)
1213 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1214 foreach_vl_msg_name_crc_dns;
1218 #define foreach_dns_api_msg \
1219 _(DNS_ENABLE_DISABLE, dns_enable_disable) \
1220 _(DNS_NAME_SERVER_ADD_DEL, dns_name_server_add_del) \
1221 _(DNS_RESOLVE_NAME, dns_resolve_name)
1223 static clib_error_t *
1224 dns_api_hookup (vlib_main_t * vm)
1227 vl_msg_api_set_handlers(VL_API_##N, #n, \
1228 vl_api_##n##_t_handler, \
1230 vl_api_##n##_t_endian, \
1231 vl_api_##n##_t_print, \
1232 sizeof(vl_api_##n##_t), 1);
1233 foreach_dns_api_msg;
1236 setup_message_id_table (&api_main);
1240 VLIB_API_INIT_FUNCTION (dns_api_hookup);
1243 static clib_error_t *
1244 dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1246 dns_main_t *dm = &dns_main;
1248 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1250 if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1252 else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1255 return clib_error_return (0, "unknown input `%U'",
1256 format_unformat_error, input);
1261 VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1263 static clib_error_t *
1264 dns_init (vlib_main_t * vm)
1266 dns_main_t *dm = &dns_main;
1269 dm->vnet_main = vnet_get_main ();
1270 dm->name_cache_size = 65535;
1271 dm->max_ttl_in_seconds = 86400;
1272 dm->random_seed = 0xDEADDABE;
1274 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply, dns46_reply_node.index,
1277 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply6, dns46_reply_node.index,
1281 udp_register_dst_port (vm, UDP_DST_PORT_dns, dns4_request_node.index,
1283 udp_register_dst_port (vm, UDP_DST_PORT_dns6, dns6_request_node.index,
1290 VLIB_INIT_FUNCTION (dns_init);
1293 unformat_dns_reply (unformat_input_t * input, va_list * args)
1295 u8 **result = va_arg (*args, u8 **);
1296 u8 **namep = va_arg (*args, u8 **);
1310 if (unformat (input, "%v", &name))
1313 if (unformat (input, "%U", unformat_ip4_address, &a4))
1316 if (unformat (input, "%U", unformat_ip6_address, &a6))
1320 if (unformat (input, "%U", unformat_ip6_address, &a6))
1323 if (unformat (input, "%U", unformat_ip4_address, &a6))
1327 /* Must have a name */
1331 /* Must have at least one address */
1332 if (!(a4_set + a6_set))
1335 /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1336 ce = name_to_labels (name);
1337 qp_offset = vec_len (ce);
1339 /* Add space for the query header */
1340 vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1341 qp = (dns_query_t *) (ce + qp_offset);
1343 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1344 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1346 /* Punch in space for the dns_header_t */
1347 vec_insert (ce, sizeof (dns_header_t), 0);
1349 h = (dns_header_t *) ce;
1351 /* Fake Transaction ID */
1354 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1355 h->qdcount = clib_host_to_net_u16 (1);
1356 h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1360 /* Now append one or two A/AAAA RR's... */
1363 /* Pointer to the name (DGMS) */
1364 vec_add1 (ce, 0xC0);
1365 vec_add1 (ce, 0x0C);
1366 vec_add2 (ce, rru8, sizeof (*rr) + 4);
1368 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1369 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1370 rr->ttl = clib_host_to_net_u32 (86400);
1371 rr->rdlength = clib_host_to_net_u16 (4);
1372 memcpy (rr->rdata, &a4, sizeof (a4));
1376 /* Pointer to the name (DGMS) */
1377 vec_add1 (ce, 0xC0);
1378 vec_add1 (ce, 0x0C);
1379 vec_add2 (ce, rru8, sizeof (*rr) + 16);
1381 rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1382 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1383 rr->ttl = clib_host_to_net_u32 (86400);
1384 rr->rdlength = clib_host_to_net_u16 (16);
1385 memcpy (rr->rdata, &a6, sizeof (a6));
1397 format_dns_query (u8 * s, va_list * args)
1399 u8 **curpos = va_arg (*args, u8 **);
1400 int verbose = va_arg (*args, int);
1405 s = format (s, " Name: ");
1407 /* Unwind execrated counted-label sheit */
1413 for (i = 0; i < len; i++)
1414 vec_add1 (s, *pos++);
1426 qp = (dns_query_t *) pos;
1429 switch (clib_net_to_host_u16 (qp->type))
1432 s = format (s, "type A\n");
1435 s = format (s, "type AAAA\n");
1438 s = format (s, "type ALL\n");
1442 s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1447 pos += sizeof (*qp);
1454 * format dns reply data
1455 * verbose > 1, dump everything
1456 * verbose == 1, dump all A and AAAA records
1457 * verbose == 0, dump one A record, and one AAAA record
1461 format_dns_reply_data (u8 * s, va_list * args)
1463 u8 *reply = va_arg (*args, u8 *);
1464 u8 **curpos = va_arg (*args, u8 **);
1465 int verbose = va_arg (*args, int);
1466 int *print_ip4 = va_arg (*args, int *);
1467 int *print_ip6 = va_arg (*args, int *);
1472 int initial_pointer_chase = 0;
1475 pos = pos2 = *curpos;
1478 s = format (s, " ");
1480 /* chase pointer? almost always yes here... */
1481 if (pos2[0] == 0xc0)
1483 pos2 = reply + pos2[1];
1485 initial_pointer_chase = 1;
1492 for (i = 0; i < len; i++)
1495 vec_add1 (s, *pos2);
1511 if (initial_pointer_chase == 0)
1514 rr = (dns_rr_t *) pos;
1516 switch (clib_net_to_host_u16 (rr->type))
1521 s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1522 format_ip4_address, rr->rdata);
1527 s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1528 clib_net_to_host_u32 (rr->ttl));
1533 pos += sizeof (*rr) + 4;
1539 s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1540 format_ip6_address, rr->rdata);
1545 s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1546 clib_net_to_host_u32 (rr->ttl));
1550 pos += sizeof (*rr) + 16;
1556 s = format (s, "TEXT: ");
1557 for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1558 vec_add1 (s, rr->rdata[i]);
1561 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1564 case DNS_TYPE_HINFO:
1566 /* Two counted strings. DGMS */
1572 s = format (s, "HINFO: ");
1575 for (i = 0; i < *len; i++)
1576 vec_add1 (s, *curpos++);
1580 for (i = 0; i < *len; i++)
1581 vec_add1 (s, *curpos++);
1586 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1589 case DNS_TYPE_NAMESERVER:
1592 s = format (s, "Nameserver: ");
1595 /* chase pointer? */
1596 if (pos2[0] == 0xc0)
1597 pos2 = reply + pos2[1];
1603 for (i = 0; i < len; i++)
1604 vec_add1 (s, *pos2++);
1606 /* chase pointer, typically to offset 12... */
1607 if (pos2[0] == 0xC0)
1608 pos2 = reply + pos2[1];
1617 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1620 case DNS_TYPE_MAIL_EXCHANGE:
1623 tp = (u16 *) rr->rdata;
1625 s = format (s, "Mail Exchange: Preference %d ", (u32)
1626 clib_net_to_host_u16 (*tp));
1628 pos2 = rr->rdata + 2;
1630 /* chase pointer? */
1631 if (pos2[0] == 0xc0)
1632 pos2 = reply + pos2[1];
1638 for (i = 0; i < len; i++)
1639 vec_add1 (s, *pos2++);
1642 if (pos2[0] == 0xC0)
1643 pos2 = reply + pos2[1];
1653 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1656 case DNS_TYPE_CNAME:
1659 tp = (u16 *) rr->rdata;
1661 s = format (s, "CNAME: ");
1665 /* chase pointer? */
1666 if (pos2[0] == 0xc0)
1667 pos2 = reply + pos2[1];
1673 for (i = 0; i < len; i++)
1674 vec_add1 (s, *pos2++);
1677 if (pos2[0] == 0xC0)
1678 pos2 = reply + pos2[1];
1687 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1692 s = format (s, "type %d: len %d\n",
1693 (int) clib_net_to_host_u16 (rr->type),
1694 sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
1695 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1705 format_dns_reply (u8 * s, va_list * args)
1707 u8 *reply_as_u8 = va_arg (*args, u8 *);
1708 int verbose = va_arg (*args, int);
1716 h = (dns_header_t *) reply_as_u8;
1717 id = clib_net_to_host_u16 (h->id);
1718 flags = clib_net_to_host_u16 (h->flags);
1722 s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
1724 s = format (s, " %s %s %s %s\n",
1725 (flags & DNS_RA) ? "recur" : "no-recur",
1726 (flags & DNS_RD) ? "recur-des" : "no-recur-des",
1727 (flags & DNS_TC) ? "trunc" : "no-trunc",
1728 (flags & DNS_AA) ? "auth" : "non-auth");
1729 s = format (s, " %d queries, %d answers, %d name-servers,"
1731 clib_net_to_host_u16 (h->qdcount),
1732 clib_net_to_host_u16 (h->anscount),
1733 clib_net_to_host_u16 (h->nscount),
1734 clib_net_to_host_u16 (h->arcount));
1737 curpos = (u8 *) (h + 1);
1742 s = format (s, " Queries:\n");
1743 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
1745 /* The query is variable-length, so curpos is a value-result parm */
1746 s = format (s, "%U", format_dns_query, &curpos, verbose);
1752 s = format (s, " Replies:\n");
1754 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
1756 /* curpos is a value-result parm */
1757 s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
1758 verbose, &print_ip4, &print_ip6);
1765 format_dns_cache (u8 * s, va_list * args)
1767 dns_main_t *dm = va_arg (*args, dns_main_t *);
1768 f64 now = va_arg (*args, f64);
1769 int verbose = va_arg (*args, int);
1770 u8 *name = va_arg (*args, u8 *);
1771 dns_cache_entry_t *ep;
1775 if (dm->is_enabled == 0)
1777 s = format (s, "The DNS cache is disabled...");
1781 if (pool_elts (dm->entries) == 0)
1783 s = format (s, "The DNS cache is empty...");
1787 dns_cache_lock (dm);
1791 p = hash_get_mem (dm->cache_entry_by_name, name);
1794 s = format (s, "%s is not in the cache...", name);
1795 dns_cache_unlock (dm);
1799 ep = pool_elt_at_index (dm->entries, p[0]);
1800 /* Magic to spit out a C-initializer to research hemorrhoids... */
1804 s = format (s, "static u8 dns_reply_data_initializer[] =\n");
1805 s = format (s, "{\n");
1807 for (i = 0; i < vec_len (ep->dns_response); i++)
1814 s = format (s, "0x%02x, ", ep->dns_response[i]);
1816 s = format (s, "};\n");
1820 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
1822 ASSERT (ep->dns_response);
1823 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
1828 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
1829 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
1831 s = format (s, "%s%s -> %U", ss, ep->name,
1832 format_dns_reply, ep->dns_response, verbose);
1833 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
1835 f64 time_left = ep->expiration_time - now;
1836 if (time_left > 0.0)
1837 s = format (s, " TTL left %.1f", time_left);
1839 s = format (s, " EXPIRED");
1844 ASSERT (ep->dns_request);
1845 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
1854 pool_foreach (ep, dm->entries,
1856 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
1858 ASSERT (ep->dns_response);
1859 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
1864 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
1865 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
1867 s = format (s, "%s%s -> %U", ss, ep->name,
1871 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
1873 f64 time_left = ep->expiration_time - now;
1874 if (time_left > 0.0)
1875 s = format (s, " TTL left %.1f", time_left);
1877 s = format (s, " EXPIRED");
1880 s = format (s, " %d client notifications pending\n",
1881 vec_len(ep->api_clients_to_notify));
1886 ASSERT (ep->dns_request);
1887 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
1894 dns_cache_unlock (dm);
1899 static clib_error_t *
1900 show_dns_cache_command_fn (vlib_main_t * vm,
1901 unformat_input_t * input, vlib_cli_command_t * cmd)
1903 dns_main_t *dm = &dns_main;
1906 f64 now = vlib_time_now (vm);
1908 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1910 if (unformat (input, "verbose %d", &verbose))
1912 else if (unformat (input, "verbose"))
1914 else if (unformat (input, "name %s", &name))
1917 return clib_error_return (0, "unknown input `%U'",
1918 format_unformat_error, input);
1921 vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
1927 VLIB_CLI_COMMAND (show_dns_cache_command) =
1929 .path = "show dns cache",
1930 .short_help = "show dns cache [verbose [nn]]",
1931 .function = show_dns_cache_command_fn,
1935 static clib_error_t *
1936 dns_cache_add_del_command_fn (vlib_main_t * vm,
1937 unformat_input_t * input,
1938 vlib_cli_command_t * cmd)
1940 dns_main_t *dm = &dns_main;
1946 clib_error_t *error;
1948 if (unformat (input, "add"))
1950 if (unformat (input, "del"))
1952 if (unformat (input, "clear"))
1955 if (is_add == -1 && is_clear == -1)
1956 return clib_error_return (0, "add / del / clear required...");
1960 rv = dns_cache_clear (dm);
1966 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
1967 error = clib_error_return (0, "Name resolution not enabled");
1972 /* Delete (by name)? */
1975 if (unformat (input, "%v", &name))
1977 rv = dns_delete_by_name (dm, name);
1980 case VNET_API_ERROR_NO_SUCH_ENTRY:
1981 error = clib_error_return (0, "%v not in the cache...", name);
1985 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
1986 error = clib_error_return (0, "Name resolution not enabled");
1995 error = clib_error_return (0, "dns_delete_by_name returned %d",
2001 return clib_error_return (0, "unknown input `%U'",
2002 format_unformat_error, input);
2005 /* Note: dns_add_static_entry consumes the name vector if OK... */
2006 if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2008 rv = dns_add_static_entry (dm, name, dns_reply_data);
2011 case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2013 vec_free (dns_reply_data);
2014 return clib_error_return (0, "%v already in the cache...", name);
2019 return clib_error_return (0, "dns_add_static_entry returned %d",
2028 VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2030 .path = "dns cache",
2031 .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2032 .function = dns_cache_add_del_command_fn,
2036 #define DNS_FORMAT_TEST 1
2038 #if DNS_FORMAT_TEST > 0
2041 static u8 dns_reply_data_initializer[] =
2042 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2043 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2045 0x0, 0xff, /* type ALL */
2046 0x0, 0x1, /* class IN */
2047 0xc0, 0xc, /* pointer to yahoo.com name */
2048 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2049 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2050 0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2051 0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2052 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2053 0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2054 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2055 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2056 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2057 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2058 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2059 0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2060 0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2062 0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2063 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2064 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2065 0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2066 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2068 0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2069 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2070 0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2071 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2073 0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2074 0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2076 0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2078 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2080 0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2082 0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2083 0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2084 0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2088 /* www.cisco.com, has no addresses in reply */
2089 static u8 dns_reply_data_initializer[] = {
2090 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2091 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2092 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2094 0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2095 0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2096 0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2097 0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2098 0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2102 static u8 dns_reply_data_initializer[] =
2103 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
2104 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
2105 0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
2106 0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
2108 0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
2109 0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
2110 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
2111 0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
2112 0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
2113 0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
2114 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
2115 0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
2116 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
2117 0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
2118 0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
2119 0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
2120 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
2121 0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
2122 0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
2123 0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
2124 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2125 0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
2126 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
2127 0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
2128 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
2129 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
2130 0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
2132 0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2136 static clib_error_t *
2137 test_dns_fmt_command_fn (vlib_main_t * vm,
2138 unformat_input_t * input, vlib_cli_command_t * cmd)
2140 u8 *dns_reply_data = 0;
2143 vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2145 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2147 if (unformat (input, "verbose %d", &verbose))
2149 else if (unformat (input, "verbose"))
2152 return clib_error_return (0, "unknown input `%U'",
2153 format_unformat_error, input);
2156 vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2158 memcpy (dns_reply_data, dns_reply_data_initializer,
2159 ARRAY_LEN (dns_reply_data_initializer));
2161 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2163 memset (rmp, 0, sizeof (*rmp));
2165 rv = vnet_dns_response_to_reply (dns_reply_data, rmp, 0 /* ttl-ptr */ );
2169 case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2170 vlib_cli_output (vm, "no addresses found...");
2174 vlib_cli_output (vm, "response to reply returned %d", rv);
2179 vlib_cli_output (vm, "ip4 address: %U", format_ip4_address,
2180 (ip4_address_t *) rmp->ip4_address);
2182 vlib_cli_output (vm, "ip6 address: %U", format_ip6_address,
2183 (ip6_address_t *) rmp->ip6_address);
2187 vec_free (dns_reply_data);
2194 VLIB_CLI_COMMAND (test_dns_fmt_command) =
2196 .path = "test dns format",
2197 .short_help = "test dns format",
2198 .function = test_dns_fmt_command_fn,
2202 static clib_error_t *
2203 test_dns_unfmt_command_fn (vlib_main_t * vm,
2204 unformat_input_t * input, vlib_cli_command_t * cmd)
2206 u8 *dns_reply_data = 0;
2210 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2212 if (unformat (input, "verbose %d", &verbose))
2214 else if (unformat (input, "verbose"))
2216 else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2219 return clib_error_return (0, "unknown input `%U'",
2220 format_unformat_error, input);
2224 return clib_error_return (0, "dns data not set...");
2226 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2228 vec_free (dns_reply_data);
2234 VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2236 .path = "test dns unformat",
2237 .short_help = "test dns unformat <name> [ip4][ip6]",
2238 .function = test_dns_unfmt_command_fn,
2242 static clib_error_t *
2243 test_dns_expire_command_fn (vlib_main_t * vm,
2244 unformat_input_t * input,
2245 vlib_cli_command_t * cmd)
2247 dns_main_t *dm = &dns_main;
2251 dns_cache_entry_t *ep;
2253 if (unformat (input, "%v", &name))
2256 _vec_len (name) -= 1;
2259 dns_cache_lock (dm);
2261 p = hash_get_mem (dm->cache_entry_by_name, name);
2264 dns_cache_unlock (dm);
2265 e = clib_error_return (0, "%s is not in the cache...", name);
2270 ep = pool_elt_at_index (dm->entries, p[0]);
2272 ep->expiration_time = 0;
2278 VLIB_CLI_COMMAND (test_dns_expire_command) =
2280 .path = "test dns expire",
2281 .short_help = "test dns expire <name>",
2282 .function = test_dns_expire_command_fn,
2288 * fd.io coding-style-patch-verification: ON
2291 * eval: (c-set-style "gnu")