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 /* Construct the dns request, if we haven't been here already */
527 if (vec_len (ep->dns_request) == 0)
530 * Start with the variadic portion of the exercise.
531 * Turn the name into a set of DNS "labels". Max length
532 * per label is 63, enforce that.
534 request = name_to_labels (ep->name);
535 qp_offset = vec_len (request);
537 /* Add space for the query header */
538 vec_validate (request, qp_offset + sizeof (dns_query_t) - 1);
540 qp = (dns_query_t *) (request + qp_offset);
542 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
543 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
545 /* Punch in space for the dns_header_t */
546 vec_insert (request, sizeof (dns_header_t), 0);
548 h = (dns_header_t *) request;
550 /* Transaction ID = pool index */
551 h->id = clib_host_to_net_u16 (ep - dm->entries);
553 /* Ask for a recursive lookup */
554 tmp = DNS_RD | DNS_OPCODE_QUERY;
555 h->flags = clib_host_to_net_u16 (tmp);
556 h->qdcount = clib_host_to_net_u16 (1);
560 ep->dns_request = request;
563 /* Work out which server / address family we're going to use */
565 /* Retry using current server */
566 if (ep->retry_count++ < DNS_RETRIES_PER_SERVER)
568 if (ep->server_af == 1 /* ip6 */ )
570 if (vec_len (dm->ip6_name_servers))
572 send_dns6_request (dm, ep,
573 dm->ip6_name_servers + ep->server_rotor);
579 if (vec_len (dm->ip4_name_servers))
581 send_dns4_request (dm, ep, dm->ip4_name_servers + ep->server_rotor);
585 else /* switch to a new server */
589 if (ep->server_af == 1 /* ip6 */ )
591 if (ep->server_rotor >= vec_len (dm->ip6_name_servers))
593 ep->server_rotor = 0;
594 ep->server_af = vec_len (dm->ip4_name_servers) > 0 ? 0 : 1;
599 if (ep->server_rotor >= vec_len (dm->ip4_name_servers))
601 ep->server_rotor = 0;
602 ep->server_af = vec_len (dm->ip6_name_servers) > 0 ? 1 : 0;
607 if (ep->server_af == 1 /* ip6 */ )
608 send_dns6_request (dm, ep, dm->ip6_name_servers + ep->server_rotor);
610 send_dns4_request (dm, ep, dm->ip4_name_servers + ep->server_rotor);
614 vlib_process_signal_event_mt (dm->vlib_main, dns_resolver_node.index,
615 DNS_RESOLVER_EVENT_PENDING, 0);
619 vnet_dns_delete_entry_by_index_nolock (dns_main_t * dm, u32 index)
621 dns_cache_entry_t *ep;
624 if (dm->is_enabled == 0)
625 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
627 if (pool_is_free_index (dm->entries, index))
628 return VNET_API_ERROR_NO_SUCH_ENTRY;
630 ep = pool_elt_at_index (dm->entries, index);
632 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_VALID))
634 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
635 if (index == dm->unresolved_entries[i])
637 vec_delete (dm->unresolved_entries, 1, i);
640 clib_warning ("pool elt %d supposedly pending, but not found...",
645 hash_unset_mem (dm->cache_entry_by_name, ep->name);
647 vec_free (ep->api_clients_to_notify);
648 vec_free (ep->api_client_contexts);
649 vec_free (ep->ip4_peers_to_notify);
650 vec_free (ep->ip6_peers_to_notify);
651 pool_put (dm->entries, ep);
657 dns_delete_by_name (dns_main_t * dm, u8 * name)
662 if (dm->is_enabled == 0)
663 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
666 p = hash_get_mem (dm->cache_entry_by_name, name);
669 dns_cache_unlock (dm);
670 return VNET_API_ERROR_NO_SUCH_ENTRY;
672 rv = vnet_dns_delete_entry_by_index_nolock (dm, p[0]);
674 dns_cache_unlock (dm);
680 delete_random_entry (dns_main_t * dm)
683 u32 victim_index, start_index, i;
685 dns_cache_entry_t *ep;
687 if (dm->is_enabled == 0)
688 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
691 limit = pool_elts (dm->entries);
692 start_index = random_u32 (&dm->random_seed) % limit;
694 for (i = 0; i < limit; i++)
696 victim_index = (start_index + i) % limit;
698 if (!pool_is_free_index (dm->entries, victim_index))
700 ep = pool_elt_at_index (dm->entries, victim_index);
701 /* Delete only valid, non-static entries */
702 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
703 && ((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0))
705 rv = vnet_dns_delete_entry_by_index_nolock (dm, victim_index);
706 dns_cache_unlock (dm);
711 dns_cache_unlock (dm);
713 clib_warning ("Couldn't find an entry to delete?");
714 return VNET_API_ERROR_UNSPECIFIED;
718 dns_add_static_entry (dns_main_t * dm, u8 * name, u8 * dns_reply_data)
720 dns_cache_entry_t *ep;
724 if (dm->is_enabled == 0)
725 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
728 p = hash_get_mem (dm->cache_entry_by_name, name);
731 dns_cache_unlock (dm);
732 return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
735 if (pool_elts (dm->entries) == dm->name_cache_size)
737 /* Will only fail if the cache is totally filled w/ static entries... */
738 rv = delete_random_entry (dm);
741 dns_cache_unlock (dm);
746 pool_get (dm->entries, ep);
747 memset (ep, 0, sizeof (*ep));
749 /* Note: consumes the name vector */
751 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
752 ep->flags = DNS_CACHE_ENTRY_FLAG_VALID | DNS_CACHE_ENTRY_FLAG_STATIC;
753 ep->dns_response = dns_reply_data;
755 dns_cache_unlock (dm);
760 dns_resolve_name (dns_main_t * dm,
761 u8 * name, u32 client_index, u32 client_context,
762 dns_cache_entry_t ** retp)
764 dns_cache_entry_t *ep;
769 now = vlib_time_now (dm->vlib_main);
771 /* In case we can't actually answer the question right now... */
775 p = hash_get_mem (dm->cache_entry_by_name, name);
778 ep = pool_elt_at_index (dm->entries, p[0]);
779 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
781 /* Has the entry expired? */
782 if (((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0)
783 && (now > ep->expiration_time))
785 clib_warning ("Re-resolve %s", name);
786 /* Yes, kill it... */
787 vnet_dns_delete_entry_by_index_nolock (dm, p[0]);
791 /* Note: caller must drop the lock! */
797 if (pool_elts (dm->entries) == dm->name_cache_size)
799 /* Will only fail if the cache is totally filled w/ static entries... */
800 rv = delete_random_entry (dm);
803 dns_cache_unlock (dm);
809 /* add new hash table entry */
810 pool_get (dm->entries, ep);
811 memset (ep, 0, sizeof (*ep));
813 ep->name = format (0, "%s%c", name, 0);
814 _vec_len (ep->name) = vec_len (ep->name) - 1;
816 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
818 vec_add1 (dm->unresolved_entries, ep - dm->entries);
819 vec_add1 (ep->api_clients_to_notify, client_index);
820 vec_add1 (ep->api_client_contexts, client_context);
821 vnet_send_dns_request (dm, ep);
822 dns_cache_unlock (dm);
828 * Handle cname indirection. JFC. Called with the cache locked.
829 * returns 0 if the reply is not a CNAME.
833 vnet_dns_cname_indirection_nolock (dns_main_t * dm, dns_cache_entry_t * ep,
848 h = (dns_header_t *) reply;
849 flags = clib_net_to_host_u16 (h->flags);
850 rcode = flags & DNS_RCODE_MASK;
852 /* See if the response is OK */
855 case DNS_RCODE_NO_ERROR:
858 case DNS_RCODE_NAME_ERROR:
859 case DNS_RCODE_FORMAT_ERROR:
860 case DNS_RCODE_SERVER_FAILURE:
861 case DNS_RCODE_NOT_IMPLEMENTED:
862 case DNS_RCODE_REFUSED:
866 curpos = (u8 *) (h + 1);
870 /* Skip the questions */
871 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
878 qp = (dns_query_t *) pos;
882 /* expect a pointer chase here for a CNAME record */
883 if ((pos2[0] & 0xC0) == 0xC0)
888 rr = (dns_rr_t *) pos;
890 /* This is a real record, not a CNAME record */
891 if (clib_net_to_host_u16 (rr->type) != DNS_TYPE_CNAME)
894 /* Crap. Chase the CNAME name chain. */
896 cname = labels_to_name (rr->rdata, reply, &pos2);
897 request = name_to_labels (cname);
900 qp_offset = vec_len (request);
902 /* Add space for the query header */
903 vec_validate (request, qp_offset + sizeof (dns_query_t) - 1);
905 qp = (dns_query_t *) (request + qp_offset);
907 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
908 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
910 /* Punch in space for the dns_header_t */
911 vec_insert (request, sizeof (dns_header_t), 0);
913 h = (dns_header_t *) request;
915 /* Transaction ID = pool index */
916 h->id = clib_host_to_net_u16 (ep - dm->entries);
918 /* Ask for a recursive lookup */
919 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
920 h->qdcount = clib_host_to_net_u16 (1);
924 vec_free (ep->dns_request);
925 ep->dns_request = request;
926 ep->retry_timer = vlib_time_now (dm->vlib_main) + 2.0;
930 * Enable this to watch recursive resolution happen...
931 * fformat (stdout, "%U", format_dns_reply, request, 2);
934 if (ep->server_af == 1 /* ip6 */ )
935 send_dns6_request (dm, ep, dm->ip6_name_servers + ep->server_rotor);
937 send_dns4_request (dm, ep, dm->ip4_name_servers + ep->server_rotor);
944 vnet_dns_response_to_reply (u8 * response,
945 vl_api_dns_resolve_name_reply_t * rmp,
958 h = (dns_header_t *) response;
959 flags = clib_net_to_host_u16 (h->flags);
960 rcode = flags & DNS_RCODE_MASK;
962 /* See if the response is OK, etc. */
966 case DNS_RCODE_NO_ERROR:
969 case DNS_RCODE_NAME_ERROR:
970 case DNS_RCODE_FORMAT_ERROR:
971 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
973 case DNS_RCODE_SERVER_FAILURE:
974 case DNS_RCODE_NOT_IMPLEMENTED:
975 case DNS_RCODE_REFUSED:
976 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
979 /* No answers? Loser... */
980 if (clib_net_to_host_u16 (h->anscount) < 1)
981 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
983 curpos = (u8 *) (h + 1);
985 /* Skip the name we asked about */
988 /* Should never happen, but stil... */
989 if ((len & 0xC0) == 0xC0)
993 /* skip the name / label-set */
1002 limit = clib_net_to_host_u16 (h->qdcount);
1003 qp = (dns_query_t *) curpos;
1008 limit = clib_net_to_host_u16 (h->anscount);
1010 for (i = 0; i < limit; i++)
1014 /* Expect pointer chases in the answer section... */
1015 if ((pos[0] & 0xC0) == 0xC0)
1022 if ((pos[0] & 0xC0) == 0xC0)
1033 rr = (dns_rr_t *) curpos;
1035 switch (clib_net_to_host_u16 (rr->type))
1038 /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1039 memcpy (rmp->ip4_address, rr->rdata, sizeof (ip4_address_t));
1041 ttl = clib_net_to_host_u32 (rr->ttl);
1042 if (min_ttlp && *min_ttlp > ttl)
1046 /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1047 memcpy (rmp->ip6_address, rr->rdata, sizeof (ip6_address_t));
1048 ttl = clib_net_to_host_u32 (rr->ttl);
1049 if (min_ttlp && *min_ttlp > ttl)
1056 /* Might as well stop ASAP */
1057 if (rmp->ip4_set && rmp->ip6_set)
1059 curpos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1062 if ((rmp->ip4_set + rmp->ip6_set) == 0)
1063 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1068 vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1070 dns_main_t *dm = &dns_main;
1071 vl_api_dns_resolve_name_reply_t *rmp;
1072 dns_cache_entry_t *ep;
1075 /* Sanitize the name slightly */
1076 mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1078 rv = dns_resolve_name (dm, mp->name, mp->client_index, mp->context, &ep);
1080 /* Error, e.g. not enabled? Tell the user */
1083 REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1087 /* Resolution pending? Don't reply... */
1092 REPLY_MACRO2(VL_API_DNS_RESOLVE_NAME_REPLY,
1094 rv = vnet_dns_response_to_reply (ep->dns_response, rmp, 0 /* ttl-ptr */);
1095 rmp->retval = clib_host_to_net_u32 (rv);
1100 * dns_resolve_name leaves the cache locked when it returns
1101 * a cached result, so unlock it here.
1103 dns_cache_unlock (dm);
1106 #define vl_msg_name_crc_list
1107 #include <vpp/api/vpe_all_api_h.h>
1108 #undef vl_msg_name_crc_list
1111 setup_message_id_table (api_main_t * am)
1113 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1114 foreach_vl_msg_name_crc_dns;
1118 #define foreach_dns_api_msg \
1119 _(DNS_ENABLE_DISABLE, dns_enable_disable) \
1120 _(DNS_NAME_SERVER_ADD_DEL, dns_name_server_add_del) \
1121 _(DNS_RESOLVE_NAME, dns_resolve_name)
1123 static clib_error_t *
1124 dns_api_hookup (vlib_main_t * vm)
1127 vl_msg_api_set_handlers(VL_API_##N, #n, \
1128 vl_api_##n##_t_handler, \
1130 vl_api_##n##_t_endian, \
1131 vl_api_##n##_t_print, \
1132 sizeof(vl_api_##n##_t), 1);
1133 foreach_dns_api_msg;
1136 setup_message_id_table (&api_main);
1140 VLIB_API_INIT_FUNCTION (dns_api_hookup);
1143 static clib_error_t *
1144 dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1146 dns_main_t *dm = &dns_main;
1148 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1150 if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1152 else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1155 return clib_error_return (0, "unknown input `%U'",
1156 format_unformat_error, input);
1161 VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1163 static clib_error_t *
1164 dns_init (vlib_main_t * vm)
1166 dns_main_t *dm = &dns_main;
1169 dm->vnet_main = vnet_get_main ();
1170 dm->name_cache_size = 65535;
1171 dm->max_ttl_in_seconds = 86400;
1172 dm->random_seed = 0xDEADDABE;
1174 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply, dns46_reply_node.index,
1177 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply6, dns46_reply_node.index,
1181 udp_register_dst_port (vm, UDP_DST_PORT_dns, dns4_request_node.index,
1183 udp_register_dst_port (vm, UDP_DST_PORT_dns6, dns6_request_node.index,
1190 VLIB_INIT_FUNCTION (dns_init);
1193 unformat_dns_reply (unformat_input_t * input, va_list * args)
1195 u8 **result = va_arg (*args, u8 **);
1196 u8 **namep = va_arg (*args, u8 **);
1210 if (unformat (input, "%v", &name))
1213 if (unformat (input, "%U", unformat_ip4_address, &a4))
1216 if (unformat (input, "%U", unformat_ip6_address, &a6))
1220 if (unformat (input, "%U", unformat_ip6_address, &a6))
1223 if (unformat (input, "%U", unformat_ip4_address, &a6))
1227 /* Must have a name */
1231 /* Must have at least one address */
1232 if (!(a4_set + a6_set))
1235 /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1236 ce = name_to_labels (name);
1237 qp_offset = vec_len (ce);
1239 /* Add space for the query header */
1240 vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1241 qp = (dns_query_t *) (ce + qp_offset);
1243 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1244 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1246 /* Punch in space for the dns_header_t */
1247 vec_insert (ce, sizeof (dns_header_t), 0);
1249 h = (dns_header_t *) ce;
1251 /* Fake Transaction ID */
1254 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1255 h->qdcount = clib_host_to_net_u16 (1);
1256 h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1260 /* Now append one or two A/AAAA RR's... */
1263 /* Pointer to the name (DGMS) */
1264 vec_add1 (ce, 0xC0);
1265 vec_add1 (ce, 0x0C);
1266 vec_add2 (ce, rru8, sizeof (*rr) + 4);
1268 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1269 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1270 rr->ttl = clib_host_to_net_u32 (86400);
1271 rr->rdlength = clib_host_to_net_u16 (4);
1272 memcpy (rr->rdata, &a4, sizeof (a4));
1276 /* Pointer to the name (DGMS) */
1277 vec_add1 (ce, 0xC0);
1278 vec_add1 (ce, 0x0C);
1279 vec_add2 (ce, rru8, sizeof (*rr) + 16);
1281 rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1282 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1283 rr->ttl = clib_host_to_net_u32 (86400);
1284 rr->rdlength = clib_host_to_net_u16 (16);
1285 memcpy (rr->rdata, &a6, sizeof (a6));
1297 format_dns_query (u8 * s, va_list * args)
1299 u8 **curpos = va_arg (*args, u8 **);
1300 int verbose = va_arg (*args, int);
1305 s = format (s, " Name: ");
1307 /* Unwind execrated counted-label sheit */
1313 for (i = 0; i < len; i++)
1314 vec_add1 (s, *pos++);
1326 qp = (dns_query_t *) pos;
1329 switch (clib_net_to_host_u16 (qp->type))
1332 s = format (s, "type A\n");
1335 s = format (s, "type AAAA\n");
1338 s = format (s, "type ALL\n");
1342 s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1347 pos += sizeof (*qp);
1354 * format dns reply data
1355 * verbose > 1, dump everything
1356 * verbose == 1, dump all A and AAAA records
1357 * verbose == 0, dump one A record, and one AAAA record
1361 format_dns_reply_data (u8 * s, va_list * args)
1363 u8 *reply = va_arg (*args, u8 *);
1364 u8 **curpos = va_arg (*args, u8 **);
1365 int verbose = va_arg (*args, int);
1366 int *print_ip4 = va_arg (*args, int *);
1367 int *print_ip6 = va_arg (*args, int *);
1372 int initial_pointer_chase = 0;
1375 pos = pos2 = *curpos;
1378 s = format (s, " ");
1380 /* chase pointer? almost always yes here... */
1381 if (pos2[0] == 0xc0)
1383 pos2 = reply + pos2[1];
1385 initial_pointer_chase = 1;
1392 for (i = 0; i < len; i++)
1395 vec_add1 (s, *pos2);
1411 if (initial_pointer_chase == 0)
1414 rr = (dns_rr_t *) pos;
1416 switch (clib_net_to_host_u16 (rr->type))
1421 s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1422 format_ip4_address, rr->rdata);
1427 s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1428 clib_net_to_host_u32 (rr->ttl));
1433 pos += sizeof (*rr) + 4;
1439 s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1440 format_ip6_address, rr->rdata);
1445 s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1446 clib_net_to_host_u32 (rr->ttl));
1450 pos += sizeof (*rr) + 16;
1456 s = format (s, "TEXT: ");
1457 for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1458 vec_add1 (s, rr->rdata[i]);
1461 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1464 case DNS_TYPE_NAMESERVER:
1467 s = format (s, "Nameserver: ");
1470 /* chase pointer? */
1471 if (pos2[0] == 0xc0)
1472 pos2 = reply + pos2[1];
1478 for (i = 0; i < len; i++)
1479 vec_add1 (s, *pos2++);
1481 /* chase pointer, typically to offset 12... */
1482 if (pos2[0] == 0xC0)
1483 pos2 = reply + pos2[1];
1492 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1495 case DNS_TYPE_MAIL_EXCHANGE:
1498 tp = (u16 *) rr->rdata;
1500 s = format (s, "Mail Exchange: Preference %d ", (u32)
1501 clib_net_to_host_u16 (*tp));
1503 pos2 = rr->rdata + 2;
1505 /* chase pointer? */
1506 if (pos2[0] == 0xc0)
1507 pos2 = reply + pos2[1];
1513 for (i = 0; i < len; i++)
1514 vec_add1 (s, *pos2++);
1517 if (pos2[0] == 0xC0)
1518 pos2 = reply + pos2[1];
1528 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1531 case DNS_TYPE_CNAME:
1534 tp = (u16 *) rr->rdata;
1536 s = format (s, "CNAME: ");
1540 /* chase pointer? */
1541 if (pos2[0] == 0xc0)
1542 pos2 = reply + pos2[1];
1548 for (i = 0; i < len; i++)
1549 vec_add1 (s, *pos2++);
1552 if (pos2[0] == 0xC0)
1553 pos2 = reply + pos2[1];
1562 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1567 s = format (s, "type %d: len %d\n",
1568 (int) clib_net_to_host_u16 (rr->type),
1569 sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
1570 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1580 format_dns_reply (u8 * s, va_list * args)
1582 u8 *reply_as_u8 = va_arg (*args, u8 *);
1583 int verbose = va_arg (*args, int);
1591 h = (dns_header_t *) reply_as_u8;
1592 id = clib_net_to_host_u16 (h->id);
1593 flags = clib_net_to_host_u16 (h->flags);
1597 s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
1599 s = format (s, " %s %s %s %s\n",
1600 (flags & DNS_RA) ? "recur" : "no-recur",
1601 (flags & DNS_RD) ? "recur-des" : "no-recur-des",
1602 (flags & DNS_TC) ? "trunc" : "no-trunc",
1603 (flags & DNS_AA) ? "auth" : "non-auth");
1604 s = format (s, " %d queries, %d answers, %d name-servers,"
1606 clib_net_to_host_u16 (h->qdcount),
1607 clib_net_to_host_u16 (h->anscount),
1608 clib_net_to_host_u16 (h->nscount),
1609 clib_net_to_host_u16 (h->arcount));
1612 curpos = (u8 *) (h + 1);
1617 s = format (s, " Queries:\n");
1618 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
1620 /* The query is variable-length, so curpos is a value-result parm */
1621 s = format (s, "%U", format_dns_query, &curpos, verbose);
1627 s = format (s, " Replies:\n");
1629 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
1631 /* curpos is a value-result parm */
1632 s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
1633 verbose, &print_ip4, &print_ip6);
1640 format_dns_cache (u8 * s, va_list * args)
1642 dns_main_t *dm = va_arg (*args, dns_main_t *);
1643 f64 now = va_arg (*args, f64);
1644 int verbose = va_arg (*args, int);
1645 u8 *name = va_arg (*args, u8 *);
1646 dns_cache_entry_t *ep;
1650 if (dm->is_enabled == 0)
1652 s = format (s, "The DNS cache is disabled...");
1656 if (pool_elts (dm->entries) == 0)
1658 s = format (s, "The DNS cache is empty...");
1662 dns_cache_lock (dm);
1666 p = hash_get_mem (dm->cache_entry_by_name, name);
1669 s = format (s, "%s is not in the cache...", name);
1670 dns_cache_unlock (dm);
1674 ep = pool_elt_at_index (dm->entries, p[0]);
1675 /* Magic to spit out a C-initializer to research hemorrhoids... */
1679 s = format (s, "static u8 dns_reply_data_initializer[] =\n");
1680 s = format (s, "{\n");
1682 for (i = 0; i < vec_len (ep->dns_response); i++)
1689 s = format (s, "0x%02x, ", ep->dns_response[i]);
1691 s = format (s, "};\n");
1695 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
1697 ASSERT (ep->dns_response);
1698 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
1703 s = format (s, "%s%s -> %U", ss, ep->name,
1704 format_dns_reply, ep->dns_response, verbose);
1705 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
1707 f64 time_left = ep->expiration_time - now;
1708 if (time_left > 0.0)
1709 s = format (s, " TTL left %.1f", time_left);
1711 s = format (s, " EXPIRED");
1716 ASSERT (ep->dns_request);
1717 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
1726 pool_foreach (ep, dm->entries,
1728 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
1730 ASSERT (ep->dns_response);
1731 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
1736 s = format (s, "%s%s -> %U", ss, ep->name,
1740 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
1742 f64 time_left = ep->expiration_time - now;
1743 if (time_left > 0.0)
1744 s = format (s, " TTL left %.1f", time_left);
1746 s = format (s, " EXPIRED");
1751 ASSERT (ep->dns_request);
1752 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
1759 dns_cache_unlock (dm);
1764 static clib_error_t *
1765 show_dns_cache_command_fn (vlib_main_t * vm,
1766 unformat_input_t * input, vlib_cli_command_t * cmd)
1768 dns_main_t *dm = &dns_main;
1771 f64 now = vlib_time_now (vm);
1773 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1775 if (unformat (input, "verbose %d", &verbose))
1777 else if (unformat (input, "verbose"))
1779 else if (unformat (input, "name %s", &name))
1782 return clib_error_return (0, "unknown input `%U'",
1783 format_unformat_error, input);
1786 vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
1792 VLIB_CLI_COMMAND (show_dns_cache_command) =
1794 .path = "show dns cache",
1795 .short_help = "show dns cache [verbose [nn]]",
1796 .function = show_dns_cache_command_fn,
1800 static clib_error_t *
1801 dns_cache_add_del_command_fn (vlib_main_t * vm,
1802 unformat_input_t * input,
1803 vlib_cli_command_t * cmd)
1805 dns_main_t *dm = &dns_main;
1811 clib_error_t *error;
1813 if (unformat (input, "add"))
1815 if (unformat (input, "del"))
1817 if (unformat (input, "clear"))
1820 if (is_add == -1 && is_clear == -1)
1821 return clib_error_return (0, "add / del / clear required...");
1825 rv = dns_cache_clear (dm);
1831 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
1832 error = clib_error_return (0, "Name resolution not enabled");
1837 /* Delete (by name)? */
1840 if (unformat (input, "%v", &name))
1842 rv = dns_delete_by_name (dm, name);
1845 case VNET_API_ERROR_NO_SUCH_ENTRY:
1846 error = clib_error_return (0, "%v not in the cache...", name);
1850 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
1851 error = clib_error_return (0, "Name resolution not enabled");
1860 error = clib_error_return (0, "dns_delete_by_name returned %d",
1866 return clib_error_return (0, "unknown input `%U'",
1867 format_unformat_error, input);
1870 /* Note: dns_add_static_entry consumes the name vector if OK... */
1871 if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
1873 rv = dns_add_static_entry (dm, name, dns_reply_data);
1876 case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
1878 vec_free (dns_reply_data);
1879 return clib_error_return (0, "%v already in the cache...", name);
1884 return clib_error_return (0, "dns_add_static_entry returned %d",
1893 VLIB_CLI_COMMAND (dns_cache_add_del_command) =
1895 .path = "dns cache",
1896 .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
1897 .function = dns_cache_add_del_command_fn,
1901 #define DNS_FORMAT_TEST 1
1903 #if DNS_FORMAT_TEST > 0
1906 static u8 dns_reply_data_initializer[] =
1907 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
1908 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
1910 0x0, 0xff, /* type ALL */
1911 0x0, 0x1, /* class IN */
1912 0xc0, 0xc, /* pointer to yahoo.com name */
1913 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
1914 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
1915 0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
1916 0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
1917 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
1918 0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
1919 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
1920 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
1921 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
1922 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
1923 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
1924 0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
1925 0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
1927 0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
1928 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
1929 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
1930 0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
1931 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
1933 0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
1934 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
1935 0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
1936 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
1938 0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
1939 0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
1941 0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
1943 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
1945 0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
1947 0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
1948 0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
1949 0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
1953 /* www.cisco.com, has no addresses in reply */
1954 static u8 dns_reply_data_initializer[] = {
1955 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
1956 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
1957 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
1959 0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
1960 0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
1961 0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
1962 0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
1963 0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
1967 static u8 dns_reply_data_initializer[] =
1968 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
1969 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
1970 0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
1971 0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
1973 0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
1974 0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
1975 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
1976 0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
1977 0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
1978 0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
1979 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
1980 0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
1981 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
1982 0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
1983 0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
1984 0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
1985 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
1986 0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
1987 0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
1988 0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
1989 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
1990 0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
1991 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
1992 0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
1993 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
1994 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
1995 0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
1997 0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2001 static clib_error_t *
2002 test_dns_fmt_command_fn (vlib_main_t * vm,
2003 unformat_input_t * input, vlib_cli_command_t * cmd)
2005 u8 *dns_reply_data = 0;
2008 vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2010 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2012 if (unformat (input, "verbose %d", &verbose))
2014 else if (unformat (input, "verbose"))
2017 return clib_error_return (0, "unknown input `%U'",
2018 format_unformat_error, input);
2021 vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2023 memcpy (dns_reply_data, dns_reply_data_initializer,
2024 ARRAY_LEN (dns_reply_data_initializer));
2026 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2028 memset (rmp, 0, sizeof (*rmp));
2030 rv = vnet_dns_response_to_reply (dns_reply_data, rmp, 0 /* ttl-ptr */ );
2034 case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2035 vlib_cli_output (vm, "no addresses found...");
2039 vlib_cli_output (vm, "response to reply returned %d", rv);
2044 vlib_cli_output (vm, "ip4 address: %U", format_ip4_address,
2045 (ip4_address_t *) rmp->ip4_address);
2047 vlib_cli_output (vm, "ip6 address: %U", format_ip6_address,
2048 (ip6_address_t *) rmp->ip6_address);
2052 vec_free (dns_reply_data);
2059 VLIB_CLI_COMMAND (test_dns_fmt_command) =
2061 .path = "test dns format",
2062 .short_help = "test dns format",
2063 .function = test_dns_fmt_command_fn,
2067 static clib_error_t *
2068 test_dns_unfmt_command_fn (vlib_main_t * vm,
2069 unformat_input_t * input, vlib_cli_command_t * cmd)
2071 u8 *dns_reply_data = 0;
2075 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2077 if (unformat (input, "verbose %d", &verbose))
2079 else if (unformat (input, "verbose"))
2081 else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2084 return clib_error_return (0, "unknown input `%U'",
2085 format_unformat_error, input);
2089 return clib_error_return (0, "dns data not set...");
2091 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2093 vec_free (dns_reply_data);
2099 VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2101 .path = "test dns unformat",
2102 .short_help = "test dns unformat <name> [ip4][ip6]",
2103 .function = test_dns_unfmt_command_fn,
2109 * fd.io coding-style-patch-verification: ON
2112 * eval: (c-set-style "gnu")