2 * Copyright (c) 2017 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 #include <vnet/dns/dns.h>
18 #include <vnet/vnet.h>
19 #include <vnet/fib/fib.h>
20 #include <vlibmemory/api.h>
22 #include <vnet/udp/udp.h>
24 #include <vnet/vnet_msg_enum.h>
26 #define vl_typedefs /* define message structures */
27 #include <vnet/vnet_all_api_h.h>
30 #define vl_endianfun /* define message structures */
31 #include <vnet/vnet_all_api_h.h>
34 /* instantiate all the print functions we know about */
35 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
37 #include <vnet/vnet_all_api_h.h>
40 #include <vlibapi/api_helper_macros.h>
45 dns_cache_clear (dns_main_t * dm)
47 dns_cache_entry_t *ep;
49 if (dm->is_enabled == 0)
50 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
55 pool_foreach (ep, dm->entries,
58 vec_free (ep->pending_requests);
62 pool_free (dm->entries);
63 hash_free (dm->cache_entry_by_name);
64 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
65 vec_free (dm->unresolved_entries);
66 dns_cache_unlock (dm);
71 dns_enable_disable (dns_main_t * dm, int is_enable)
73 vlib_thread_main_t *tm = &vlib_thread_main;
74 u32 n_vlib_mains = tm->n_vlib_mains;
78 if (vec_len (dm->ip4_name_servers) == 0
79 && (vec_len (dm->ip6_name_servers) == 0))
80 return VNET_API_ERROR_NO_NAME_SERVERS;
82 if (dm->cache_entry_by_name == 0)
85 dm->cache_lock = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
86 CLIB_CACHE_LINE_BYTES);
88 dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
101 static void vl_api_dns_enable_disable_t_handler
102 (vl_api_dns_enable_disable_t * mp)
104 vl_api_dns_enable_disable_reply_t *rmp;
105 dns_main_t *dm = &dns_main;
108 rv = dns_enable_disable (dm, mp->enable);
110 REPLY_MACRO (VL_API_DNS_ENABLE_DISABLE_REPLY);
114 dns6_name_server_add_del (dns_main_t * dm,
115 u8 * server_address_as_u8, int is_add)
122 /* Already there? done... */
123 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
125 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
126 sizeof (ip6_address_t)))
130 vec_add2 (dm->ip6_name_servers, ap, 1);
131 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
135 for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
137 if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
138 sizeof (ip6_address_t)))
140 vec_delete (dm->ip6_name_servers, 1, i);
144 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
150 dns4_name_server_add_del (dns_main_t * dm,
151 u8 * server_address_as_u8, int is_add)
158 /* Already there? done... */
159 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
161 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
162 sizeof (ip4_address_t)))
166 vec_add2 (dm->ip4_name_servers, ap, 1);
167 clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
171 for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
173 if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
174 sizeof (ip4_address_t)))
176 vec_delete (dm->ip4_name_servers, 1, i);
180 return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
185 static void vl_api_dns_name_server_add_del_t_handler
186 (vl_api_dns_name_server_add_del_t * mp)
188 dns_main_t *dm = &dns_main;
189 vl_api_dns_name_server_add_del_reply_t *rmp;
193 rv = dns6_name_server_add_del (dm, mp->server_address, mp->is_add);
195 rv = dns4_name_server_add_del (dm, mp->server_address, mp->is_add);
197 REPLY_MACRO (VL_API_DNS_NAME_SERVER_ADD_DEL_REPLY);
201 vnet_dns_send_dns4_request (dns_main_t * dm,
202 dns_cache_entry_t * ep, ip4_address_t * server)
204 vlib_main_t *vm = dm->vlib_main;
205 f64 now = vlib_time_now (vm);
210 fib_node_index_t fei;
211 u32 sw_if_index, fib_index;
213 ip4_main_t *im4 = &ip4_main;
214 ip_lookup_main_t *lm4 = &im4->lookup_main;
215 ip_interface_address_t *ia = 0;
216 ip4_address_t *src_address;
221 ASSERT (ep->dns_request);
223 /* Find a FIB path to the server */
224 clib_memcpy (&prefix.fp_addr.ip4, server, sizeof (*server));
225 prefix.fp_proto = FIB_PROTOCOL_IP4;
228 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
229 if (fib_index == (u32) ~ 0)
231 clib_warning ("no fib table");
235 fei = fib_table_lookup (fib_index, &prefix);
237 /* Couldn't find route to destination. Bail out. */
238 if (fei == FIB_NODE_INDEX_INVALID)
240 clib_warning ("no route to DNS server");
244 sw_if_index = fib_entry_get_resolving_interface (fei);
246 if (sw_if_index == ~0)
249 ("route to %U exists, fei %d, get_resolving_interface returned"
250 " ~0", format_ip4_address, &prefix.fp_addr, fei);
255 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnummbered */,
257 src_address = ip_interface_address_get_address (lm4, ia);
258 goto found_src_address;
262 clib_warning ("FIB BUG");
267 /* Go get a buffer */
268 if (vlib_buffer_alloc (dm->vlib_main, &bi, 1) != 1)
271 b = vlib_get_buffer (vm, bi);
272 b->current_length = sizeof (ip4_header_t) + sizeof (udp_header_t) +
273 vec_len (ep->dns_request);
274 b->total_length_not_including_first_buffer = 0;
276 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
277 vnet_buffer (b)->sw_if_index[VLIB_RX] = 0; /* "local0" */
278 vnet_buffer (b)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
280 ip = vlib_buffer_get_current (b);
281 memset (ip, 0, sizeof (*ip));
282 udp = (udp_header_t *) (ip + 1);
283 memset (udp, 0, sizeof (*udp));
285 dns_request = (u8 *) (udp + 1);
288 ip->ip_version_and_header_length = 0x45;
289 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b));
291 ip->protocol = IP_PROTOCOL_UDP;
292 ip->src_address.as_u32 = src_address->as_u32;
293 ip->dst_address.as_u32 = server->as_u32;
294 ip->checksum = ip4_header_checksum (ip);
297 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
298 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
299 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
300 vec_len (ep->dns_request));
303 /* The actual DNS request */
304 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
306 /* Ship it to ip4_lookup */
307 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
308 to_next = vlib_frame_vector_args (f);
311 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
313 ep->retry_timer = now + 2.0;
317 vnet_dns_send_dns6_request (dns_main_t * dm,
318 dns_cache_entry_t * ep, ip6_address_t * server)
320 vlib_main_t *vm = dm->vlib_main;
321 f64 now = vlib_time_now (vm);
326 fib_node_index_t fei;
327 u32 sw_if_index, fib_index;
329 ip6_main_t *im6 = &ip6_main;
330 ip_lookup_main_t *lm6 = &im6->lookup_main;
331 ip_interface_address_t *ia = 0;
332 ip6_address_t *src_address;
336 int junk __attribute__ ((unused));
338 ASSERT (ep->dns_request);
340 /* Find a FIB path to the server */
341 clib_memcpy (&prefix.fp_addr, server, sizeof (*server));
342 prefix.fp_proto = FIB_PROTOCOL_IP6;
345 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
346 if (fib_index == (u32) ~ 0)
348 clib_warning ("no fib table");
352 fei = fib_table_lookup (fib_index, &prefix);
354 /* Couldn't find route to destination. Bail out. */
355 if (fei == FIB_NODE_INDEX_INVALID)
357 clib_warning ("no route to DNS server");
360 sw_if_index = fib_entry_get_resolving_interface (fei);
363 foreach_ip_interface_address(lm6, ia, sw_if_index, 1 /* honor unnummbered */,
365 src_address = ip_interface_address_get_address (lm6, ia);
366 goto found_src_address;
370 clib_warning ("FIB BUG");
375 /* Go get a buffer */
376 if (vlib_buffer_alloc (dm->vlib_main, &bi, 1) != 1)
379 b = vlib_get_buffer (vm, bi);
380 b->current_length = sizeof (ip6_header_t) + sizeof (udp_header_t) +
381 vec_len (ep->dns_request);
382 b->total_length_not_including_first_buffer = 0;
384 VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
386 ip = vlib_buffer_get_current (b);
387 memset (ip, 0, sizeof (*ip));
388 udp = (udp_header_t *) (ip + 1);
389 memset (udp, 0, sizeof (*udp));
391 dns_request = (u8 *) (udp + 1);
394 ip->ip_version_traffic_class_and_flow_label =
395 clib_host_to_net_u32 (0x6 << 28);
398 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b)
399 - sizeof (ip6_header_t));
401 ip->protocol = IP_PROTOCOL_UDP;
402 clib_memcpy (&ip->src_address, src_address, sizeof (ip6_address_t));
403 clib_memcpy (&ip->dst_address, server, sizeof (ip6_address_t));
406 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
407 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
408 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
409 vec_len (ep->dns_request));
411 udp->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ip, &junk);
413 /* The actual DNS request */
414 clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
416 /* Ship it to ip6_lookup */
417 f = vlib_get_frame_to_node (vm, ip6_lookup_node.index);
418 to_next = vlib_frame_vector_args (f);
422 ep->retry_timer = now + 2.0;
426 * Translate "foo.com" into "0x3 f o o 0x3 c o m 0x0"
427 * A historical / hysterical micro-TLV scheme. DGMS.
430 name_to_labels (u8 * name)
433 int last_label_index;
438 /* punch in space for the first length */
439 vec_insert (rv, 1, 0);
440 last_label_index = 0;
443 while (i < vec_len (rv))
447 rv[last_label_index] = (i - last_label_index) - 1;
448 if ((i - last_label_index) > 63)
449 clib_warning ("stupid name, label length %d",
450 i - last_label_index);
451 last_label_index = i;
456 /* Set the last real label length */
457 rv[last_label_index] = (i - last_label_index) - 1;
460 * Add a [sic] NULL root label. Otherwise, the name parser can't figure out
468 * arc-function for the above.
469 * Translate "0x3 f o o 0x3 c o m 0x0" into "foo.com"
470 * Produces a non-NULL-terminated u8 *vector. %v format is your friend.
473 vnet_dns_labels_to_name (u8 * label, u8 * full_text, u8 ** parse_from_here)
480 *parse_from_here = 0;
482 /* chase initial pointer? */
483 if ((label[0] & 0xC0) == 0xC0)
485 *parse_from_here = label + 2;
486 offset = ((label[0] & 0x3f) << 8) + label[1];
487 label = full_text + offset;
494 for (i = 0; i < len; i++)
495 vec_add1 (reply, *label++);
498 if ((label[0] & 0xC0) == 0xC0)
500 *parse_from_here = label + 2;
501 offset = ((label[0] & 0x3f) << 8) + label[1];
502 label = full_text + offset;
507 vec_add1 (reply, '.');
509 if (*parse_from_here == 0)
510 *parse_from_here = label;
515 vnet_send_dns_request (dns_main_t * dm, dns_cache_entry_t * ep)
520 u8 *request, *name_copy;
523 /* This can easily happen if sitting in GDB, etc. */
524 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID || ep->server_fails > 1)
527 /* Construct the dns request, if we haven't been here already */
528 if (vec_len (ep->dns_request) == 0)
531 * Start with the variadic portion of the exercise.
532 * Turn the name into a set of DNS "labels". Max length
533 * per label is 63, enforce that.
535 request = name_to_labels (ep->name);
536 name_copy = vec_dup (request);
537 qp_offset = vec_len (request);
540 * At least when testing against "known good" DNS servers:
541 * it turns out that sending 2x requests - one for an A-record
542 * and another for a AAAA-record - seems to work better than
543 * sending a DNS_TYPE_ALL request.
546 /* Add space for the query header */
547 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
549 qp = (dns_query_t *) (request + qp_offset);
551 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
552 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
554 clib_memcpy (qp, name_copy, vec_len (name_copy));
555 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
556 vec_free (name_copy);
558 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
559 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
561 /* Punch in space for the dns_header_t */
562 vec_insert (request, sizeof (dns_header_t), 0);
564 h = (dns_header_t *) request;
566 /* Transaction ID = pool index */
567 h->id = clib_host_to_net_u16 (ep - dm->entries);
569 /* Ask for a recursive lookup */
570 tmp = DNS_RD | DNS_OPCODE_QUERY;
571 h->flags = clib_host_to_net_u16 (tmp);
572 h->qdcount = clib_host_to_net_u16 (2);
576 ep->dns_request = request;
579 /* Work out which server / address family we're going to use */
581 /* Retry using current server */
582 if (ep->retry_count++ < DNS_RETRIES_PER_SERVER)
584 if (ep->server_af == 1 /* ip6 */ )
586 if (vec_len (dm->ip6_name_servers))
588 vnet_dns_send_dns6_request
589 (dm, ep, dm->ip6_name_servers + ep->server_rotor);
595 if (vec_len (dm->ip4_name_servers))
597 vnet_dns_send_dns4_request
598 (dm, ep, dm->ip4_name_servers + ep->server_rotor);
602 else /* switch to a new server */
606 if (ep->server_af == 1 /* ip6 */ )
608 if (ep->server_rotor >= vec_len (dm->ip6_name_servers))
610 ep->server_rotor = 0;
611 ep->server_af = vec_len (dm->ip4_name_servers) > 0 ? 0 : 1;
616 if (ep->server_rotor >= vec_len (dm->ip4_name_servers))
618 ep->server_rotor = 0;
619 ep->server_af = vec_len (dm->ip6_name_servers) > 0 ? 1 : 0;
624 if (ep->server_af == 1 /* ip6 */ )
625 vnet_dns_send_dns6_request
626 (dm, ep, dm->ip6_name_servers + ep->server_rotor);
628 vnet_dns_send_dns4_request
629 (dm, ep, dm->ip4_name_servers + ep->server_rotor);
633 vlib_process_signal_event_mt (dm->vlib_main, dns_resolver_node.index,
634 DNS_RESOLVER_EVENT_PENDING, 0);
638 vnet_dns_delete_entry_by_index_nolock (dns_main_t * dm, u32 index)
640 dns_cache_entry_t *ep;
643 if (dm->is_enabled == 0)
644 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
646 if (pool_is_free_index (dm->entries, index))
647 return VNET_API_ERROR_NO_SUCH_ENTRY;
649 ep = pool_elt_at_index (dm->entries, index);
650 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_VALID))
652 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
653 if (index == dm->unresolved_entries[i])
655 vec_delete (dm->unresolved_entries, 1, i);
658 clib_warning ("pool elt %d supposedly pending, but not found...",
663 hash_unset_mem (dm->cache_entry_by_name, ep->name);
665 vec_free (ep->pending_requests);
666 pool_put (dm->entries, ep);
672 dns_delete_by_name (dns_main_t * dm, u8 * name)
677 if (dm->is_enabled == 0)
678 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
681 p = hash_get_mem (dm->cache_entry_by_name, name);
684 dns_cache_unlock (dm);
685 return VNET_API_ERROR_NO_SUCH_ENTRY;
687 rv = vnet_dns_delete_entry_by_index_nolock (dm, p[0]);
689 dns_cache_unlock (dm);
695 delete_random_entry (dns_main_t * dm)
698 u32 victim_index, start_index, i;
700 dns_cache_entry_t *ep;
702 if (dm->is_enabled == 0)
703 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
706 * Silence spurious coverity warning. We know pool_elts >> 0, or
707 * we wouldn't be here...
710 if (pool_elts (dm->entries) == 0)
711 return VNET_API_ERROR_UNSPECIFIED;
715 limit = pool_elts (dm->entries);
716 start_index = random_u32 (&dm->random_seed) % limit;
718 for (i = 0; i < limit; i++)
720 victim_index = (start_index + i) % limit;
722 if (!pool_is_free_index (dm->entries, victim_index))
724 ep = pool_elt_at_index (dm->entries, victim_index);
725 /* Delete only valid, non-static entries */
726 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
727 && ((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0))
729 rv = vnet_dns_delete_entry_by_index_nolock (dm, victim_index);
730 dns_cache_unlock (dm);
735 dns_cache_unlock (dm);
737 clib_warning ("Couldn't find an entry to delete?");
738 return VNET_API_ERROR_UNSPECIFIED;
742 dns_add_static_entry (dns_main_t * dm, u8 * name, u8 * dns_reply_data)
744 dns_cache_entry_t *ep;
748 if (dm->is_enabled == 0)
749 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
752 p = hash_get_mem (dm->cache_entry_by_name, name);
755 dns_cache_unlock (dm);
756 return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
759 if (pool_elts (dm->entries) == dm->name_cache_size)
761 /* Will only fail if the cache is totally filled w/ static entries... */
762 rv = delete_random_entry (dm);
765 dns_cache_unlock (dm);
770 pool_get (dm->entries, ep);
771 memset (ep, 0, sizeof (*ep));
773 /* Note: consumes the name vector */
775 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
776 ep->flags = DNS_CACHE_ENTRY_FLAG_VALID | DNS_CACHE_ENTRY_FLAG_STATIC;
777 ep->dns_response = dns_reply_data;
779 dns_cache_unlock (dm);
784 vnet_dns_resolve_name (dns_main_t * dm, u8 * name, dns_pending_request_t * t,
785 dns_cache_entry_t ** retp)
787 dns_cache_entry_t *ep;
791 dns_pending_request_t *pr;
794 now = vlib_time_now (dm->vlib_main);
796 /* In case we can't actually answer the question right now... */
801 p = hash_get_mem (dm->cache_entry_by_name, name);
804 ep = pool_elt_at_index (dm->entries, p[0]);
805 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
807 /* Has the entry expired? */
808 if (((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0)
809 && (now > ep->expiration_time))
812 u32 *indices_to_delete = 0;
815 * Take out the rest of the resolution chain
816 * This isn't optimal, but it won't happen very often.
820 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME))
822 vec_add1 (indices_to_delete, ep - dm->entries);
824 p = hash_get_mem (dm->cache_entry_by_name, ep->cname);
827 ep = pool_elt_at_index (dm->entries, p[0]);
831 vec_add1 (indices_to_delete, ep - dm->entries);
835 for (i = 0; i < vec_len (indices_to_delete); i++)
837 /* Reenable to watch re-resolutions */
840 ep = pool_elt_at_index (dm->entries,
841 indices_to_delete[i]);
842 clib_warning ("Re-resolve %s", ep->name);
845 vnet_dns_delete_entry_by_index_nolock
846 (dm, indices_to_delete[i]);
848 vec_free (indices_to_delete);
849 /* Yes, kill it... */
853 if (ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
859 /* Note: caller must drop the lock! */
866 * Resolution pending. Add request to the pending vector
867 * by copying the template request
869 vec_add2 (ep->pending_requests, pr, 1);
870 memcpy (pr, t, sizeof (*pr));
871 dns_cache_unlock (dm);
877 if (pool_elts (dm->entries) == dm->name_cache_size)
879 /* Will only fail if the cache is totally filled w/ static entries... */
880 rv = delete_random_entry (dm);
883 dns_cache_unlock (dm);
888 /* add new hash table entry */
889 pool_get (dm->entries, ep);
890 memset (ep, 0, sizeof (*ep));
892 ep->name = format (0, "%s%c", name, 0);
893 _vec_len (ep->name) = vec_len (ep->name) - 1;
895 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
897 vec_add1 (dm->unresolved_entries, ep - dm->entries);
898 vec_add2 (ep->pending_requests, pr, 1);
900 pr->request_type = t->request_type;
902 /* Remember details so we can reply later... */
903 if (t->request_type == DNS_API_PENDING_NAME_TO_IP ||
904 t->request_type == DNS_API_PENDING_IP_TO_NAME)
906 pr->client_index = t->client_index;
907 pr->client_context = t->client_context;
911 pr->client_index = ~0;
912 pr->is_ip6 = t->is_ip6;
913 pr->dst_port = t->dst_port;
920 clib_memcpy (pr->dst_address, t->dst_address, count);
923 vnet_send_dns_request (dm, ep);
924 dns_cache_unlock (dm);
928 #define foreach_notification_to_move \
932 * Handle cname indirection. JFC. Called with the cache locked.
933 * returns 0 if the reply is not a CNAME.
937 vnet_dns_cname_indirection_nolock (dns_main_t * dm, u32 ep_index, u8 * reply)
952 dns_cache_entry_t *ep, *next_ep;
955 h = (dns_header_t *) reply;
956 flags = clib_net_to_host_u16 (h->flags);
957 rcode = flags & DNS_RCODE_MASK;
959 /* See if the response is OK */
962 case DNS_RCODE_NO_ERROR:
965 case DNS_RCODE_NAME_ERROR:
966 case DNS_RCODE_FORMAT_ERROR:
967 case DNS_RCODE_SERVER_FAILURE:
968 case DNS_RCODE_NOT_IMPLEMENTED:
969 case DNS_RCODE_REFUSED:
973 curpos = (u8 *) (h + 1);
977 /* Skip the questions */
978 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
985 pos += sizeof (dns_query_t);
988 /* expect a pointer chase here for a CNAME record */
989 if ((pos2[0] & 0xC0) == 0xC0)
994 /* Walk the answer(s) to see what to do next */
995 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
997 rr = (dns_rr_t *) pos;
998 switch (clib_net_to_host_u16 (rr->type))
1000 /* Real address record? Done.. */
1005 * Maybe chase a CNAME pointer?
1006 * It's not unheard-of for name-servers to return
1007 * both CNAME and A/AAAA records...
1009 case DNS_TYPE_CNAME:
1013 /* Some other junk, e.g. a nameserver... */
1017 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1019 if ((pos2[0] & 0xc0) == 0xc0)
1023 /* Neither a CNAME nor a real address. Try another server */
1026 flags &= ~DNS_RCODE_MASK;
1027 flags |= DNS_RCODE_NAME_ERROR;
1028 h->flags = clib_host_to_net_u16 (flags);
1032 /* This is a CNAME record, chase the name chain. */
1035 /* The last request is no longer pending.. */
1036 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
1037 if (ep_index == dm->unresolved_entries[i])
1039 vec_delete (dm->unresolved_entries, 1, i);
1040 goto found_last_request;
1042 clib_warning ("pool elt %d supposedly pending, but not found...", ep_index);
1046 now = vlib_time_now (dm->vlib_main);
1047 cname = vnet_dns_labels_to_name (rr->rdata, reply, &pos2);
1048 /* Save the cname */
1049 vec_add1 (cname, 0);
1050 _vec_len (cname) -= 1;
1051 ep = pool_elt_at_index (dm->entries, ep_index);
1053 ep->flags |= (DNS_CACHE_ENTRY_FLAG_CNAME | DNS_CACHE_ENTRY_FLAG_VALID);
1054 /* Save the response */
1055 if (ep->dns_response)
1056 vec_free (ep->dns_response);
1057 ep->dns_response = reply;
1058 /* Set up expiration time */
1059 ep->expiration_time = now + clib_net_to_host_u32 (rr->ttl);
1061 pool_get (dm->entries, next_ep);
1063 /* Need to recompute ep post pool-get */
1064 ep = pool_elt_at_index (dm->entries, ep_index);
1066 memset (next_ep, 0, sizeof (*next_ep));
1067 next_ep->name = vec_dup (cname);
1068 vec_add1 (next_ep->name, 0);
1069 _vec_len (next_ep->name) -= 1;
1071 hash_set_mem (dm->cache_entry_by_name, next_ep->name,
1072 next_ep - dm->entries);
1074 /* Use the same server */
1075 next_ep->server_rotor = ep->server_rotor;
1076 next_ep->server_af = ep->server_af;
1078 /* Move notification data to the next name in the chain */
1079 #define _(a) next_ep->a = ep->a; ep->a = 0;
1080 foreach_notification_to_move;
1083 request = name_to_labels (cname);
1084 name_copy = vec_dup (request);
1086 qp_offset = vec_len (request);
1088 /* Add space for the query header */
1089 vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
1091 qp = (dns_query_t *) (request + qp_offset);
1093 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
1094 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1095 clib_memcpy (qp, name_copy, vec_len (name_copy));
1096 qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
1097 vec_free (name_copy);
1099 qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1100 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1102 /* Punch in space for the dns_header_t */
1103 vec_insert (request, sizeof (dns_header_t), 0);
1105 h = (dns_header_t *) request;
1107 /* Transaction ID = pool index */
1108 h->id = clib_host_to_net_u16 (next_ep - dm->entries);
1110 /* Ask for a recursive lookup */
1111 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
1112 h->qdcount = clib_host_to_net_u16 (2);
1116 next_ep->dns_request = request;
1117 next_ep->retry_timer = now + 2.0;
1118 next_ep->retry_count = 0;
1121 * Enable this to watch recursive resolution happen...
1122 * fformat (stdout, "%U", format_dns_reply, request, 2);
1125 vec_add1 (dm->unresolved_entries, next_ep - dm->entries);
1126 vnet_send_dns_request (dm, next_ep);
1131 vnet_dns_response_to_reply (u8 * response,
1132 vl_api_dns_resolve_name_reply_t * rmp,
1140 u8 *curpos, *pos, *pos2;
1146 h = (dns_header_t *) response;
1147 flags = clib_net_to_host_u16 (h->flags);
1148 rcode = flags & DNS_RCODE_MASK;
1150 /* See if the response is OK, etc. */
1154 case DNS_RCODE_NO_ERROR:
1157 case DNS_RCODE_NAME_ERROR:
1158 case DNS_RCODE_FORMAT_ERROR:
1159 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1161 case DNS_RCODE_SERVER_FAILURE:
1162 case DNS_RCODE_NOT_IMPLEMENTED:
1163 case DNS_RCODE_REFUSED:
1164 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1167 /* No answers? Loser... */
1168 if (clib_net_to_host_u16 (h->anscount) < 1)
1169 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1171 curpos = (u8 *) (h + 1);
1173 /* Skip the name we asked about */
1176 /* Should never happen, but stil... */
1177 if ((len & 0xC0) == 0xC0)
1181 /* skip the name / label-set */
1190 limit = clib_net_to_host_u16 (h->qdcount);
1191 qp = (dns_query_t *) curpos;
1196 limit = clib_net_to_host_u16 (h->anscount);
1198 for (i = 0; i < limit; i++)
1200 pos = pos2 = curpos;
1203 /* Expect pointer chases in the answer section... */
1204 if ((pos2[0] & 0xC0) == 0xC0)
1207 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1216 if ((pos2[0] & 0xc0) == 0xc0)
1219 * If we've already done one pointer chase,
1220 * do not move the pos pointer.
1222 if (pointer_chase == 0)
1224 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1232 if (pointer_chase == 0)
1235 rr = (dns_rr_t *) pos;
1237 switch (clib_net_to_host_u16 (rr->type))
1240 /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1241 memcpy (rmp->ip4_address, rr->rdata, sizeof (ip4_address_t));
1243 ttl = clib_net_to_host_u32 (rr->ttl);
1244 if (min_ttlp && *min_ttlp > ttl)
1248 /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1249 memcpy (rmp->ip6_address, rr->rdata, sizeof (ip6_address_t));
1250 ttl = clib_net_to_host_u32 (rr->ttl);
1251 if (min_ttlp && *min_ttlp > ttl)
1259 /* Might as well stop ASAP */
1260 if (rmp->ip4_set && rmp->ip6_set)
1262 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1266 if ((rmp->ip4_set + rmp->ip6_set) == 0)
1267 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1272 vnet_dns_response_to_name (u8 * response,
1273 vl_api_dns_resolve_ip_reply_t * rmp,
1281 u8 *curpos, *pos, *pos2;
1286 u8 *junk __attribute__ ((unused));
1290 h = (dns_header_t *) response;
1291 flags = clib_net_to_host_u16 (h->flags);
1292 rcode = flags & DNS_RCODE_MASK;
1294 /* See if the response is OK, etc. */
1298 case DNS_RCODE_NO_ERROR:
1301 case DNS_RCODE_NAME_ERROR:
1302 case DNS_RCODE_FORMAT_ERROR:
1303 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1305 case DNS_RCODE_SERVER_FAILURE:
1306 case DNS_RCODE_NOT_IMPLEMENTED:
1307 case DNS_RCODE_REFUSED:
1308 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1311 /* No answers? Loser... */
1312 if (clib_net_to_host_u16 (h->anscount) < 1)
1313 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1315 curpos = (u8 *) (h + 1);
1317 /* Skip the name we asked about */
1320 /* Should never happen, but stil... */
1321 if ((len & 0xC0) == 0xC0)
1325 /* skip the name / label-set */
1334 limit = clib_net_to_host_u16 (h->qdcount);
1335 qp = (dns_query_t *) curpos;
1340 limit = clib_net_to_host_u16 (h->anscount);
1342 for (i = 0; i < limit; i++)
1344 pos = pos2 = curpos;
1347 /* Expect pointer chases in the answer section... */
1348 if ((pos2[0] & 0xC0) == 0xC0)
1351 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1360 if ((pos2[0] & 0xc0) == 0xc0)
1363 * If we've already done one pointer chase,
1364 * do not move the pos pointer.
1366 if (pointer_chase == 0)
1368 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1376 if (pointer_chase == 0)
1379 rr = (dns_rr_t *) pos;
1381 switch (clib_net_to_host_u16 (rr->type))
1384 name = vnet_dns_labels_to_name (rr->rdata, response, &junk);
1385 memcpy (rmp->name, name, vec_len (name));
1386 ttl = clib_net_to_host_u32 (rr->ttl);
1389 rmp->name[vec_len (name)] = 0;
1395 /* Might as well stop ASAP */
1398 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1403 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1408 vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1410 dns_main_t *dm = &dns_main;
1411 vl_api_dns_resolve_name_reply_t *rmp;
1412 dns_cache_entry_t *ep;
1413 dns_pending_request_t _t0, *t0 = &_t0;
1416 /* Sanitize the name slightly */
1417 mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1419 t0->request_type = DNS_API_PENDING_NAME_TO_IP;
1420 t0->client_index = mp->client_index;
1421 t0->client_context = mp->context;
1423 rv = vnet_dns_resolve_name (dm, mp->name, t0, &ep);
1425 /* Error, e.g. not enabled? Tell the user */
1428 REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1432 /* Resolution pending? Don't reply... */
1437 REPLY_MACRO2(VL_API_DNS_RESOLVE_NAME_REPLY,
1439 rv = vnet_dns_response_to_reply (ep->dns_response, rmp, 0 /* ttl-ptr */);
1440 rmp->retval = clib_host_to_net_u32 (rv);
1445 * dns_resolve_name leaves the cache locked when it returns
1446 * a cached result, so unlock it here.
1448 dns_cache_unlock (dm);
1452 vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
1454 dns_main_t *dm = &dns_main;
1455 vl_api_dns_resolve_ip_reply_t *rmp;
1456 dns_cache_entry_t *ep;
1459 u8 *lookup_name = 0;
1461 dns_pending_request_t _t0, *t0 = &_t0;
1465 for (i = 15; i >= 0; i--)
1467 digit = mp->address[i];
1468 nybble = (digit & 0x0F);
1470 vec_add1 (lookup_name, (nybble - 10) + 'a');
1472 vec_add1 (lookup_name, nybble + '0');
1473 vec_add1 (lookup_name, '.');
1474 nybble = (digit & 0xF0) >> 4;
1476 vec_add1 (lookup_name, (nybble - 10) + 'a');
1478 vec_add1 (lookup_name, nybble + '0');
1479 vec_add1 (lookup_name, '.');
1481 len = vec_len (lookup_name);
1482 vec_validate (lookup_name, len + 8);
1483 memcpy (lookup_name + len, "ip6.arpa", 8);
1487 for (i = 3; i >= 0; i--)
1489 digit = mp->address[i];
1490 lookup_name = format (lookup_name, "%d.", digit);
1492 lookup_name = format (lookup_name, "in-addr.arpa");
1495 vec_add1 (lookup_name, 0);
1497 t0->request_type = DNS_API_PENDING_IP_TO_NAME;
1498 t0->client_index = mp->client_index;
1499 t0->client_context = mp->context;
1501 rv = vnet_dns_resolve_name (dm, lookup_name, t0, &ep);
1503 vec_free (lookup_name);
1505 /* Error, e.g. not enabled? Tell the user */
1508 REPLY_MACRO (VL_API_DNS_RESOLVE_IP_REPLY);
1512 /* Resolution pending? Don't reply... */
1517 REPLY_MACRO2(VL_API_DNS_RESOLVE_IP_REPLY,
1519 rv = vnet_dns_response_to_name (ep->dns_response, rmp, 0 /* ttl-ptr */);
1520 rmp->retval = clib_host_to_net_u32 (rv);
1525 * vnet_dns_resolve_name leaves the cache locked when it returns
1526 * a cached result, so unlock it here.
1528 dns_cache_unlock (dm);
1531 #define vl_msg_name_crc_list
1532 #include <vpp/api/vpe_all_api_h.h>
1533 #undef vl_msg_name_crc_list
1536 setup_message_id_table (api_main_t * am)
1538 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1539 foreach_vl_msg_name_crc_dns;
1543 #define foreach_dns_api_msg \
1544 _(DNS_ENABLE_DISABLE, dns_enable_disable) \
1545 _(DNS_NAME_SERVER_ADD_DEL, dns_name_server_add_del) \
1546 _(DNS_RESOLVE_NAME, dns_resolve_name) \
1547 _(DNS_RESOLVE_IP, dns_resolve_ip)
1549 static clib_error_t *
1550 dns_api_hookup (vlib_main_t * vm)
1553 vl_msg_api_set_handlers(VL_API_##N, #n, \
1554 vl_api_##n##_t_handler, \
1556 vl_api_##n##_t_endian, \
1557 vl_api_##n##_t_print, \
1558 sizeof(vl_api_##n##_t), 1);
1559 foreach_dns_api_msg;
1562 setup_message_id_table (&api_main);
1566 VLIB_API_INIT_FUNCTION (dns_api_hookup);
1569 static clib_error_t *
1570 dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1572 dns_main_t *dm = &dns_main;
1574 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1576 if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1578 else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1581 return clib_error_return (0, "unknown input `%U'",
1582 format_unformat_error, input);
1587 VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1589 static clib_error_t *
1590 dns_init (vlib_main_t * vm)
1592 dns_main_t *dm = &dns_main;
1595 dm->vnet_main = vnet_get_main ();
1596 dm->name_cache_size = 65535;
1597 dm->max_ttl_in_seconds = 86400;
1598 dm->random_seed = 0xDEADDABE;
1600 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply, dns46_reply_node.index,
1603 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply6, dns46_reply_node.index,
1606 udp_register_dst_port (vm, UDP_DST_PORT_dns, dns4_request_node.index,
1609 udp_register_dst_port (vm, UDP_DST_PORT_dns6, dns6_request_node.index,
1614 VLIB_INIT_FUNCTION (dns_init);
1617 unformat_dns_reply (unformat_input_t * input, va_list * args)
1619 u8 **result = va_arg (*args, u8 **);
1620 u8 **namep = va_arg (*args, u8 **);
1634 if (unformat (input, "%v", &name))
1637 if (unformat (input, "%U", unformat_ip4_address, &a4))
1640 if (unformat (input, "%U", unformat_ip6_address, &a6))
1644 if (unformat (input, "%U", unformat_ip6_address, &a6))
1647 if (unformat (input, "%U", unformat_ip4_address, &a6))
1651 /* Must have a name */
1655 /* Must have at least one address */
1656 if (!(a4_set + a6_set))
1659 /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1660 ce = name_to_labels (name);
1661 qp_offset = vec_len (ce);
1663 /* Add space for the query header */
1664 vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1665 qp = (dns_query_t *) (ce + qp_offset);
1667 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1668 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1670 /* Punch in space for the dns_header_t */
1671 vec_insert (ce, sizeof (dns_header_t), 0);
1673 h = (dns_header_t *) ce;
1675 /* Fake Transaction ID */
1678 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1679 h->qdcount = clib_host_to_net_u16 (1);
1680 h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1684 /* Now append one or two A/AAAA RR's... */
1687 /* Pointer to the name (DGMS) */
1688 vec_add1 (ce, 0xC0);
1689 vec_add1 (ce, 0x0C);
1690 vec_add2 (ce, rru8, sizeof (*rr) + 4);
1692 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1693 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1694 rr->ttl = clib_host_to_net_u32 (86400);
1695 rr->rdlength = clib_host_to_net_u16 (4);
1696 memcpy (rr->rdata, &a4, sizeof (a4));
1700 /* Pointer to the name (DGMS) */
1701 vec_add1 (ce, 0xC0);
1702 vec_add1 (ce, 0x0C);
1703 vec_add2 (ce, rru8, sizeof (*rr) + 16);
1705 rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1706 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1707 rr->ttl = clib_host_to_net_u32 (86400);
1708 rr->rdlength = clib_host_to_net_u16 (16);
1709 memcpy (rr->rdata, &a6, sizeof (a6));
1721 format_dns_query (u8 * s, va_list * args)
1723 u8 **curpos = va_arg (*args, u8 **);
1724 int verbose = va_arg (*args, int);
1729 s = format (s, " Name: ");
1731 /* Unwind execrated counted-label sheit */
1737 for (i = 0; i < len; i++)
1738 vec_add1 (s, *pos++);
1750 qp = (dns_query_t *) pos;
1753 switch (clib_net_to_host_u16 (qp->type))
1756 s = format (s, "type A\n");
1759 s = format (s, "type AAAA\n");
1762 s = format (s, "type ALL\n");
1766 s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1771 pos += sizeof (*qp);
1778 * format dns reply data
1779 * verbose > 1, dump everything
1780 * verbose == 1, dump all A and AAAA records
1781 * verbose == 0, dump one A record, and one AAAA record
1785 format_dns_reply_data (u8 * s, va_list * args)
1787 u8 *reply = va_arg (*args, u8 *);
1788 u8 **curpos = va_arg (*args, u8 **);
1789 int verbose = va_arg (*args, int);
1790 int *print_ip4 = va_arg (*args, int *);
1791 int *print_ip6 = va_arg (*args, int *);
1796 int pointer_chase = 0;
1798 u16 rrtype_host_byte_order;
1800 pos = pos2 = *curpos;
1803 s = format (s, " ");
1805 /* chase pointer? almost always yes here... */
1806 if ((pos2[0] & 0xc0) == 0xc0)
1809 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1817 for (i = 0; i < len; i++)
1820 vec_add1 (s, *pos2);
1823 if ((pos2[0] & 0xc0) == 0xc0)
1826 * If we've already done one pointer chase,
1827 * do not move the pos pointer.
1829 if (pointer_chase == 0)
1831 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1849 if (pointer_chase == 0)
1852 rr = (dns_rr_t *) pos;
1853 rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
1855 switch (rrtype_host_byte_order)
1860 s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1861 format_ip4_address, rr->rdata);
1866 s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1867 clib_net_to_host_u32 (rr->ttl));
1872 pos += sizeof (*rr) + 4;
1878 s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1879 format_ip6_address, rr->rdata);
1884 s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1885 clib_net_to_host_u32 (rr->ttl));
1889 pos += sizeof (*rr) + 16;
1895 s = format (s, "TEXT: ");
1896 for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1897 vec_add1 (s, rr->rdata[i]);
1900 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1903 case DNS_TYPE_HINFO:
1905 /* Two counted strings. DGMS */
1911 s = format (s, "HINFO: ");
1914 for (i = 0; i < *len; i++)
1915 vec_add1 (s, *curpos++);
1919 for (i = 0; i < *len; i++)
1920 vec_add1 (s, *curpos++);
1925 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1928 case DNS_TYPE_NAMESERVER:
1931 s = format (s, "Nameserver: ");
1934 /* chase pointer? */
1935 if ((pos2[0] & 0xc0) == 0xc0)
1938 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1945 for (i = 0; i < len; i++)
1946 vec_add1 (s, *pos2++);
1948 /* chase pointer, typically to offset 12... */
1949 if (pos2[0] == 0xC0)
1950 pos2 = reply + pos2[1];
1959 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1962 case DNS_TYPE_MAIL_EXCHANGE:
1965 tp = (u16 *) rr->rdata;
1967 s = format (s, "Mail Exchange: Preference %d ", (u32)
1968 clib_net_to_host_u16 (*tp));
1970 pos2 = rr->rdata + 2;
1972 /* chase pointer? */
1973 if (pos2[0] == 0xc0)
1974 pos2 = reply + pos2[1];
1980 for (i = 0; i < len; i++)
1981 vec_add1 (s, *pos2++);
1984 if (pos2[0] == 0xC0)
1985 pos2 = reply + pos2[1];
1995 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1999 case DNS_TYPE_CNAME:
2002 tp = (u16 *) rr->rdata;
2004 if (rrtype_host_byte_order == DNS_TYPE_CNAME)
2005 s = format (s, "CNAME: ");
2007 s = format (s, "PTR: ");
2011 /* chase pointer? */
2012 if (pos2[0] == 0xc0)
2013 pos2 = reply + pos2[1];
2019 for (i = 0; i < len; i++)
2020 vec_add1 (s, *pos2++);
2023 if (pos2[0] == 0xC0)
2024 pos2 = reply + pos2[1];
2033 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2038 s = format (s, "type %d: len %d\n",
2039 (int) clib_net_to_host_u16 (rr->type),
2040 sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
2041 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2051 format_dns_reply (u8 * s, va_list * args)
2053 u8 *reply_as_u8 = va_arg (*args, u8 *);
2054 int verbose = va_arg (*args, int);
2062 h = (dns_header_t *) reply_as_u8;
2063 id = clib_net_to_host_u16 (h->id);
2064 flags = clib_net_to_host_u16 (h->flags);
2068 s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
2070 s = format (s, " %s %s %s %s\n",
2071 (flags & DNS_RA) ? "recur" : "no-recur",
2072 (flags & DNS_RD) ? "recur-des" : "no-recur-des",
2073 (flags & DNS_TC) ? "trunc" : "no-trunc",
2074 (flags & DNS_AA) ? "auth" : "non-auth");
2075 s = format (s, " %d queries, %d answers, %d name-servers,"
2077 clib_net_to_host_u16 (h->qdcount),
2078 clib_net_to_host_u16 (h->anscount),
2079 clib_net_to_host_u16 (h->nscount),
2080 clib_net_to_host_u16 (h->arcount));
2083 curpos = (u8 *) (h + 1);
2088 s = format (s, " Queries:\n");
2089 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
2091 /* The query is variable-length, so curpos is a value-result parm */
2092 s = format (s, "%U", format_dns_query, &curpos, verbose);
2098 s = format (s, " Replies:\n");
2100 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
2102 /* curpos is a value-result parm */
2103 s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
2104 verbose, &print_ip4, &print_ip6);
2111 format_dns_cache (u8 * s, va_list * args)
2113 dns_main_t *dm = va_arg (*args, dns_main_t *);
2114 f64 now = va_arg (*args, f64);
2115 int verbose = va_arg (*args, int);
2116 u8 *name = va_arg (*args, u8 *);
2117 dns_cache_entry_t *ep;
2121 if (dm->is_enabled == 0)
2123 s = format (s, "The DNS cache is disabled...");
2127 if (pool_elts (dm->entries) == 0)
2129 s = format (s, "The DNS cache is empty...");
2133 dns_cache_lock (dm);
2137 p = hash_get_mem (dm->cache_entry_by_name, name);
2140 s = format (s, "%s is not in the cache...", name);
2141 dns_cache_unlock (dm);
2145 ep = pool_elt_at_index (dm->entries, p[0]);
2146 /* Magic to spit out a C-initializer to research hemorrhoids... */
2150 s = format (s, "static u8 dns_reply_data_initializer[] =\n");
2151 s = format (s, "{\n");
2153 for (i = 0; i < vec_len (ep->dns_response); i++)
2160 s = format (s, "0x%02x, ", ep->dns_response[i]);
2162 s = format (s, "};\n");
2166 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2168 ASSERT (ep->dns_response);
2169 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2174 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2175 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2177 s = format (s, "%s%s -> %U", ss, ep->name,
2178 format_dns_reply, ep->dns_response, verbose);
2179 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2181 f64 time_left = ep->expiration_time - now;
2182 if (time_left > 0.0)
2183 s = format (s, " TTL left %.1f", time_left);
2185 s = format (s, " EXPIRED");
2190 ASSERT (ep->dns_request);
2191 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2200 pool_foreach (ep, dm->entries,
2202 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2204 ASSERT (ep->dns_response);
2205 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2210 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2211 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2213 s = format (s, "%s%s -> %U", ss, ep->name,
2217 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2219 f64 time_left = ep->expiration_time - now;
2220 if (time_left > 0.0)
2221 s = format (s, " TTL left %.1f", time_left);
2223 s = format (s, " EXPIRED");
2226 s = format (s, " %d client notifications pending\n",
2227 vec_len(ep->pending_requests));
2232 ASSERT (ep->dns_request);
2233 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2240 dns_cache_unlock (dm);
2245 static clib_error_t *
2246 show_dns_cache_command_fn (vlib_main_t * vm,
2247 unformat_input_t * input, vlib_cli_command_t * cmd)
2249 dns_main_t *dm = &dns_main;
2252 f64 now = vlib_time_now (vm);
2254 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2256 if (unformat (input, "verbose %d", &verbose))
2258 else if (unformat (input, "verbose"))
2260 else if (unformat (input, "name %s", &name))
2263 return clib_error_return (0, "unknown input `%U'",
2264 format_unformat_error, input);
2267 vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
2273 VLIB_CLI_COMMAND (show_dns_cache_command) =
2275 .path = "show dns cache",
2276 .short_help = "show dns cache [verbose [nn]]",
2277 .function = show_dns_cache_command_fn,
2281 static clib_error_t *
2282 dns_cache_add_del_command_fn (vlib_main_t * vm,
2283 unformat_input_t * input,
2284 vlib_cli_command_t * cmd)
2286 dns_main_t *dm = &dns_main;
2292 clib_error_t *error;
2294 if (unformat (input, "add"))
2296 if (unformat (input, "del"))
2298 if (unformat (input, "clear"))
2301 if (is_add == -1 && is_clear == -1)
2302 return clib_error_return (0, "add / del / clear required...");
2306 rv = dns_cache_clear (dm);
2312 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2313 error = clib_error_return (0, "Name resolution not enabled");
2318 /* Delete (by name)? */
2321 if (unformat (input, "%v", &name))
2323 rv = dns_delete_by_name (dm, name);
2326 case VNET_API_ERROR_NO_SUCH_ENTRY:
2327 error = clib_error_return (0, "%v not in the cache...", name);
2331 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2332 error = clib_error_return (0, "Name resolution not enabled");
2341 error = clib_error_return (0, "dns_delete_by_name returned %d",
2347 return clib_error_return (0, "unknown input `%U'",
2348 format_unformat_error, input);
2351 /* Note: dns_add_static_entry consumes the name vector if OK... */
2352 if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2354 rv = dns_add_static_entry (dm, name, dns_reply_data);
2357 case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2359 vec_free (dns_reply_data);
2360 return clib_error_return (0, "%v already in the cache...", name);
2365 return clib_error_return (0, "dns_add_static_entry returned %d",
2374 VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2376 .path = "dns cache",
2377 .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2378 .function = dns_cache_add_del_command_fn,
2382 #define DNS_FORMAT_TEST 1
2384 #if DNS_FORMAT_TEST > 0
2387 static u8 dns_reply_data_initializer[] =
2388 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2389 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2391 0x0, 0xff, /* type ALL */
2392 0x0, 0x1, /* class IN */
2393 0xc0, 0xc, /* pointer to yahoo.com name */
2394 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2395 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2396 0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2397 0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2398 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2399 0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2400 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2401 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2402 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2403 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2404 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2405 0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2406 0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2408 0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2409 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2410 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2411 0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2412 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2414 0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2415 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2416 0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2417 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2419 0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2420 0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2422 0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2424 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2426 0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2428 0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2429 0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2430 0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2434 /* www.cisco.com, has no addresses in reply */
2435 static u8 dns_reply_data_initializer[] = {
2436 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2437 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2438 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2440 0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2441 0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2442 0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2443 0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2444 0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2447 /* bind8 (linux widget, w/ nasty double pointer chasees */
2448 static u8 dns_reply_data_initializer[] = {
2450 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08,
2452 0x00, 0x06, 0x00, 0x06, 0x0a, 0x6f, 0x72, 0x69,
2454 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77, 0x77, 0x05,
2456 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f,
2458 0x6d, 0x00, 0x00, 0xff, 0x00, 0x01, 0x0a, 0x6f,
2460 0x72, 0x69, 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77,
2462 0x77, 0x05, 0x43, 0x49, 0x53, 0x43, 0x4f, 0xc0,
2465 0x1d, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2468 0x9a, 0x00, 0x18, 0x15, 0x72, 0x63, 0x64,
2469 0x6e, 0x39, 0x2d, 0x31, 0x34, 0x70, 0x2d, 0x64, 0x63,
2470 0x7a, 0x30, 0x35, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31,
2471 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00, 0x01, 0x00,
2472 0x00, 0x05, 0x9a, 0x00, 0x1a, 0x17, 0x61, 0x6c, 0x6c,
2473 0x6e, 0x30, 0x31, 0x2d, 0x61, 0x67, 0x30, 0x39, 0x2d,
2474 0x64, 0x63, 0x7a, 0x30, 0x33, 0x6e, 0x2d, 0x67, 0x73,
2475 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00,
2476 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x10, 0x0d, 0x72,
2477 0x74, 0x70, 0x35, 0x2d, 0x64, 0x6d, 0x7a, 0x2d, 0x67,
2478 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2479 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x18, 0x15,
2480 0x6d, 0x74, 0x76, 0x35, 0x2d, 0x61, 0x70, 0x31, 0x30,
2481 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x36, 0x6e, 0x2d, 0x67,
2482 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2483 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x1b, 0x18,
2484 0x73, 0x6e, 0x67, 0x64, 0x63, 0x30, 0x31, 0x2d, 0x61,
2485 0x62, 0x30, 0x37, 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x31,
2486 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0,
2487 0x26, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a,
2488 0x00, 0x1a, 0x17, 0x61, 0x65, 0x72, 0x30, 0x31, 0x2d,
2489 0x72, 0x34, 0x63, 0x32, 0x35, 0x2d, 0x64, 0x63, 0x7a,
2490 0x30, 0x31, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0,
2491 0x17, 0xc0, 0x26, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2492 0x00, 0x81, 0x00, 0x04, 0x48, 0xa3, 0x04, 0xa1, 0xc0,
2493 0x26, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82,
2494 0x00, 0x10, 0x20, 0x01, 0x04, 0x20, 0x12, 0x01, 0x00,
2495 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
2496 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2497 0x9a, 0x00, 0x02, 0xc0, 0xf4, 0xc0, 0x0c, 0x00, 0x02,
2498 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0,
2499 0xcd, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00,
2500 0x05, 0x9a, 0x00, 0x02, 0xc0, 0x8d, 0xc0, 0x0c, 0x00,
2501 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02,
2502 0xc0, 0x43, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00,
2503 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0, 0xa9, 0xc0, 0x0c,
2504 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00,
2505 0x02, 0xc0, 0x67, 0xc0, 0x8d, 0x00, 0x01, 0x00, 0x01,
2506 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0x40, 0x66, 0xf6,
2507 0x05, 0xc0, 0xa9, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2508 0x07, 0x08, 0x00, 0x04, 0xad, 0x24, 0xe0, 0x64, 0xc0,
2509 0x43, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08,
2510 0x00, 0x04, 0x48, 0xa3, 0x04, 0x1c, 0xc0, 0xf4, 0x00,
2511 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04,
2512 0xad, 0x26, 0xd4, 0x6c, 0xc0, 0x67, 0x00, 0x01, 0x00,
2513 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x25,
2514 0x90, 0x64, 0xc0, 0xcd, 0x00, 0x01, 0x00, 0x01, 0x00,
2515 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x27, 0x70, 0x44,
2519 static u8 dns_reply_data_initializer[] =
2520 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
2521 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
2522 0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
2523 0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
2525 0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
2526 0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
2527 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
2528 0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
2529 0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
2530 0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
2531 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
2532 0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
2533 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
2534 0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
2535 0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
2536 0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
2537 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
2538 0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
2539 0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
2540 0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
2541 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2542 0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
2543 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
2544 0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
2545 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
2546 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
2547 0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
2549 0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2553 /* www.weatherlink.com */
2554 static u8 dns_reply_data_initializer[] = {
2555 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2556 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x0b,
2557 0x77, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x6c, 0x69,
2558 0x6e, 0x6b, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0xff,
2559 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00,
2560 0x00, 0x0c, 0x9e, 0x00, 0x1f, 0x0e, 0x64, 0x33, 0x6b,
2561 0x72, 0x30, 0x67, 0x75, 0x62, 0x61, 0x31, 0x64, 0x76,
2562 0x77, 0x66, 0x0a, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x66,
2563 0x72, 0x6f, 0x6e, 0x74, 0x03, 0x6e, 0x65, 0x74, 0x00,
2568 static clib_error_t *
2569 test_dns_fmt_command_fn (vlib_main_t * vm,
2570 unformat_input_t * input, vlib_cli_command_t * cmd)
2572 u8 *dns_reply_data = 0;
2575 vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2577 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2579 if (unformat (input, "verbose %d", &verbose))
2581 else if (unformat (input, "verbose"))
2584 return clib_error_return (0, "unknown input `%U'",
2585 format_unformat_error, input);
2588 vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2590 memcpy (dns_reply_data, dns_reply_data_initializer,
2591 ARRAY_LEN (dns_reply_data_initializer));
2593 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2595 memset (rmp, 0, sizeof (*rmp));
2597 rv = vnet_dns_response_to_reply (dns_reply_data, rmp, 0 /* ttl-ptr */ );
2601 case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2602 vlib_cli_output (vm, "no addresses found...");
2606 vlib_cli_output (vm, "response to reply returned %d", rv);
2611 vlib_cli_output (vm, "ip4 address: %U", format_ip4_address,
2612 (ip4_address_t *) rmp->ip4_address);
2614 vlib_cli_output (vm, "ip6 address: %U", format_ip6_address,
2615 (ip6_address_t *) rmp->ip6_address);
2619 vec_free (dns_reply_data);
2626 VLIB_CLI_COMMAND (test_dns_fmt_command) =
2628 .path = "test dns format",
2629 .short_help = "test dns format",
2630 .function = test_dns_fmt_command_fn,
2634 static clib_error_t *
2635 test_dns_unfmt_command_fn (vlib_main_t * vm,
2636 unformat_input_t * input, vlib_cli_command_t * cmd)
2638 u8 *dns_reply_data = 0;
2642 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2644 if (unformat (input, "verbose %d", &verbose))
2646 else if (unformat (input, "verbose"))
2648 else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2651 return clib_error_return (0, "unknown input `%U'",
2652 format_unformat_error, input);
2656 return clib_error_return (0, "dns data not set...");
2658 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2660 vec_free (dns_reply_data);
2666 VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2668 .path = "test dns unformat",
2669 .short_help = "test dns unformat <name> [ip4][ip6]",
2670 .function = test_dns_unfmt_command_fn,
2674 static clib_error_t *
2675 test_dns_expire_command_fn (vlib_main_t * vm,
2676 unformat_input_t * input,
2677 vlib_cli_command_t * cmd)
2679 dns_main_t *dm = &dns_main;
2683 dns_cache_entry_t *ep;
2685 if (unformat (input, "%v", &name))
2688 _vec_len (name) -= 1;
2691 dns_cache_lock (dm);
2693 p = hash_get_mem (dm->cache_entry_by_name, name);
2696 dns_cache_unlock (dm);
2697 e = clib_error_return (0, "%s is not in the cache...", name);
2702 ep = pool_elt_at_index (dm->entries, p[0]);
2704 ep->expiration_time = 0;
2710 VLIB_CLI_COMMAND (test_dns_expire_command) =
2712 .path = "test dns expire",
2713 .short_help = "test dns expire <name>",
2714 .function = test_dns_expire_command_fn,
2720 vnet_send_dns6_reply (dns_main_t * dm, dns_pending_request_t * pr,
2721 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2723 clib_warning ("Unimplemented...");
2728 vnet_send_dns4_reply (dns_main_t * dm, dns_pending_request_t * pr,
2729 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2731 vlib_main_t *vm = dm->vlib_main;
2733 fib_prefix_t prefix;
2734 fib_node_index_t fei;
2735 u32 sw_if_index, fib_index;
2736 ip4_main_t *im4 = &ip4_main;
2737 ip_lookup_main_t *lm4 = &im4->lookup_main;
2738 ip_interface_address_t *ia = 0;
2739 ip4_address_t *src_address;
2747 vl_api_dns_resolve_name_reply_t _rnr, *rnr = &_rnr;
2748 vl_api_dns_resolve_ip_reply_t _rir, *rir = &_rir;
2756 ASSERT (ep && ep->dns_response);
2758 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2760 /* Quick and dirty way to dig up the A-record address. $$ FIXME */
2761 memset (rnr, 0, sizeof (*rnr));
2762 if (vnet_dns_response_to_reply (ep->dns_response, rnr, &ttl))
2764 /* clib_warning ("response_to_reply failed..."); */
2767 if (rnr->ip4_set == 0)
2769 /* clib_warning ("No A-record..."); */
2773 else if (pr->request_type == DNS_PEER_PENDING_IP_TO_NAME)
2775 memset (rir, 0, sizeof (*rir));
2776 if (vnet_dns_response_to_name (ep->dns_response, rir, &ttl))
2778 /* clib_warning ("response_to_name failed..."); */
2784 clib_warning ("Unknown request type %d", pr->request_type);
2788 /* Initialize a buffer */
2791 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2793 b0 = vlib_get_buffer (vm, bi);
2796 if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
2797 vlib_buffer_free_one (vm, b0->next_buffer);
2800 * Reset the buffer. We recycle the DNS request packet in the cache
2801 * hit case, and reply immediately from the request node.
2803 * In the resolution-required / deferred case, resetting a freshly-allocated
2804 * buffer won't hurt. We hope.
2806 b0->flags &= VLIB_BUFFER_FREE_LIST_INDEX_MASK;
2807 b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
2808 | VLIB_BUFFER_TOTAL_LENGTH_VALID);
2809 b0->current_data = 0;
2810 b0->current_length = 0;
2811 b0->total_length_not_including_first_buffer = 0;
2812 vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; /* "local0" */
2813 vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
2815 /* Find a FIB path to the peer we're trying to answer */
2816 clib_memcpy (&prefix.fp_addr.ip4, pr->dst_address, sizeof (ip4_address_t));
2817 prefix.fp_proto = FIB_PROTOCOL_IP4;
2820 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
2821 if (fib_index == (u32) ~ 0)
2823 clib_warning ("no fib table");
2827 fei = fib_table_lookup (fib_index, &prefix);
2829 /* Couldn't find route to destination. Bail out. */
2830 if (fei == FIB_NODE_INDEX_INVALID)
2832 clib_warning ("no route to DNS server");
2836 sw_if_index = fib_entry_get_resolving_interface (fei);
2838 if (sw_if_index == ~0)
2841 ("route to %U exists, fei %d, get_resolving_interface returned"
2842 " ~0", fei, format_ip4_address, &prefix.fp_addr);
2847 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnummbered */,
2849 src_address = ip_interface_address_get_address (lm4, ia);
2850 goto found_src_address;
2854 clib_warning ("FIB BUG");
2859 ip = vlib_buffer_get_current (b0);
2860 udp = (udp_header_t *) (ip + 1);
2861 dns_response = (u8 *) (udp + 1);
2862 memset (ip, 0, sizeof (*ip) + sizeof (*udp));
2865 * Start with the variadic portion of the exercise.
2866 * Turn the name into a set of DNS "labels". Max length
2867 * per label is 63, enforce that.
2869 reply = name_to_labels (pr->name);
2870 vec_free (pr->name);
2872 qp_offset = vec_len (reply);
2874 /* Add space for the query header */
2875 vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
2877 qp = (dns_query_t *) (reply + qp_offset);
2879 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2880 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
2882 qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2884 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
2886 /* Punch in space for the dns_header_t */
2887 vec_insert (reply, sizeof (dns_header_t), 0);
2889 dh = (dns_header_t *) reply;
2891 /* Transaction ID = pool index */
2894 /* Announce that we did a recursive lookup */
2895 tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
2897 tmp |= DNS_RCODE_NAME_ERROR;
2898 dh->flags = clib_host_to_net_u16 (tmp);
2899 dh->qdcount = clib_host_to_net_u16 (1);
2900 dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
2904 /* If the name resolution worked, cough up an appropriate RR */
2907 /* Add the answer. First, a name pointer (0xC00C) */
2908 vec_add1 (reply, 0xC0);
2909 vec_add1 (reply, 0x0C);
2911 /* Now, add single A-rec RR */
2912 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2914 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
2915 rr = (dns_rr_t *) rrptr;
2917 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
2918 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2919 rr->ttl = clib_host_to_net_u32 (ttl);
2920 rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
2921 clib_memcpy (rr->rdata, rnr->ip4_address, sizeof (ip4_address_t));
2925 /* Or a single PTR RR */
2926 u8 *vecname = format (0, "%s", rir->name);
2927 u8 *label_vec = name_to_labels (vecname);
2930 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
2931 rr = (dns_rr_t *) rrptr;
2932 rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2933 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2934 rr->ttl = clib_host_to_net_u32 (ttl);
2935 rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
2936 clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
2937 vec_free (label_vec);
2940 clib_memcpy (dns_response, reply, vec_len (reply));
2942 /* Set the packet length */
2943 b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
2946 ip->ip_version_and_header_length = 0x45;
2947 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
2949 ip->protocol = IP_PROTOCOL_UDP;
2950 ip->src_address.as_u32 = src_address->as_u32;
2951 clib_memcpy (ip->dst_address.as_u8, pr->dst_address,
2952 sizeof (ip4_address_t));
2953 ip->checksum = ip4_header_checksum (ip);
2956 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
2957 udp->dst_port = pr->dst_port;
2958 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
2963 /* Ship it to ip4_lookup */
2964 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
2965 to_next = vlib_frame_vector_args (f);
2968 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
2972 * fd.io coding-style-patch-verification: ON
2975 * eval: (c-set-style "gnu")