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)
950 dns_cache_entry_t *ep, *next_ep;
953 h = (dns_header_t *) reply;
954 flags = clib_net_to_host_u16 (h->flags);
955 rcode = flags & DNS_RCODE_MASK;
957 /* See if the response is OK */
960 case DNS_RCODE_NO_ERROR:
963 case DNS_RCODE_NAME_ERROR:
964 case DNS_RCODE_FORMAT_ERROR:
965 case DNS_RCODE_SERVER_FAILURE:
966 case DNS_RCODE_NOT_IMPLEMENTED:
967 case DNS_RCODE_REFUSED:
971 curpos = (u8 *) (h + 1);
975 /* Skip the questions */
976 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
983 pos += sizeof (dns_query_t);
986 /* expect a pointer chase here for a CNAME record */
987 if ((pos2[0] & 0xC0) == 0xC0)
992 /* Walk the answer(s) to see what to do next */
993 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
995 rr = (dns_rr_t *) pos;
996 switch (clib_net_to_host_u16 (rr->type))
998 /* Real address record? Done.. */
1002 /* Chase a CNAME pointer? */
1003 case DNS_TYPE_CNAME:
1006 /* Some other junk, e.g. a nameserver... */
1010 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1013 /* Neither a CNAME nor a real address. Try another server */
1014 flags &= ~DNS_RCODE_MASK;
1015 flags |= DNS_RCODE_NAME_ERROR;
1016 h->flags = clib_host_to_net_u16 (flags);
1020 /* This is a CNAME record, chase the name chain. */
1022 /* The last request is no longer pending.. */
1023 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
1024 if (ep_index == dm->unresolved_entries[i])
1026 vec_delete (dm->unresolved_entries, 1, i);
1027 goto found_last_request;
1029 clib_warning ("pool elt %d supposedly pending, but not found...", ep_index);
1033 now = vlib_time_now (dm->vlib_main);
1034 cname = vnet_dns_labels_to_name (rr->rdata, reply, &pos2);
1035 /* Save the cname */
1036 vec_add1 (cname, 0);
1037 _vec_len (cname) -= 1;
1038 ep = pool_elt_at_index (dm->entries, ep_index);
1040 ep->flags |= (DNS_CACHE_ENTRY_FLAG_CNAME | DNS_CACHE_ENTRY_FLAG_VALID);
1041 /* Save the response */
1042 if (ep->dns_response)
1043 vec_free (ep->dns_response);
1044 ep->dns_response = reply;
1045 /* Set up expiration time */
1046 ep->expiration_time = now + clib_net_to_host_u32 (rr->ttl);
1048 pool_get (dm->entries, next_ep);
1050 /* Need to recompute ep post pool-get */
1051 ep = pool_elt_at_index (dm->entries, ep_index);
1053 memset (next_ep, 0, sizeof (*next_ep));
1054 next_ep->name = vec_dup (cname);
1055 vec_add1 (next_ep->name, 0);
1056 _vec_len (next_ep->name) -= 1;
1058 hash_set_mem (dm->cache_entry_by_name, next_ep->name,
1059 next_ep - dm->entries);
1061 /* Use the same server */
1062 next_ep->server_rotor = ep->server_rotor;
1063 next_ep->server_af = ep->server_af;
1065 /* Move notification data to the next name in the chain */
1066 #define _(a) next_ep->a = ep->a; ep->a = 0;
1067 foreach_notification_to_move;
1070 request = name_to_labels (cname);
1072 qp_offset = vec_len (request);
1074 /* Add space for the query header */
1075 vec_validate (request, qp_offset + sizeof (dns_query_t) - 1);
1077 qp = (dns_query_t *) (request + qp_offset);
1079 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1080 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1082 /* Punch in space for the dns_header_t */
1083 vec_insert (request, sizeof (dns_header_t), 0);
1085 h = (dns_header_t *) request;
1087 /* Transaction ID = pool index */
1088 h->id = clib_host_to_net_u16 (next_ep - dm->entries);
1090 /* Ask for a recursive lookup */
1091 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
1092 h->qdcount = clib_host_to_net_u16 (1);
1096 next_ep->dns_request = request;
1097 next_ep->retry_timer = now + 2.0;
1098 next_ep->retry_count = 0;
1101 * Enable this to watch recursive resolution happen...
1102 * fformat (stdout, "%U", format_dns_reply, request, 2);
1105 vec_add1 (dm->unresolved_entries, next_ep - dm->entries);
1106 vnet_send_dns_request (dm, next_ep);
1111 vnet_dns_response_to_reply (u8 * response,
1112 vl_api_dns_resolve_name_reply_t * rmp,
1120 u8 *curpos, *pos, *pos2;
1126 h = (dns_header_t *) response;
1127 flags = clib_net_to_host_u16 (h->flags);
1128 rcode = flags & DNS_RCODE_MASK;
1130 /* See if the response is OK, etc. */
1134 case DNS_RCODE_NO_ERROR:
1137 case DNS_RCODE_NAME_ERROR:
1138 case DNS_RCODE_FORMAT_ERROR:
1139 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1141 case DNS_RCODE_SERVER_FAILURE:
1142 case DNS_RCODE_NOT_IMPLEMENTED:
1143 case DNS_RCODE_REFUSED:
1144 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1147 /* No answers? Loser... */
1148 if (clib_net_to_host_u16 (h->anscount) < 1)
1149 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1151 curpos = (u8 *) (h + 1);
1153 /* Skip the name we asked about */
1156 /* Should never happen, but stil... */
1157 if ((len & 0xC0) == 0xC0)
1161 /* skip the name / label-set */
1170 limit = clib_net_to_host_u16 (h->qdcount);
1171 qp = (dns_query_t *) curpos;
1176 limit = clib_net_to_host_u16 (h->anscount);
1178 for (i = 0; i < limit; i++)
1180 pos = pos2 = curpos;
1183 /* Expect pointer chases in the answer section... */
1184 if ((pos2[0] & 0xC0) == 0xC0)
1187 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1196 if ((pos2[0] & 0xc0) == 0xc0)
1199 * If we've already done one pointer chase,
1200 * do not move the pos pointer.
1202 if (pointer_chase == 0)
1204 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1212 if (pointer_chase == 0)
1215 rr = (dns_rr_t *) pos;
1217 switch (clib_net_to_host_u16 (rr->type))
1220 /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1221 memcpy (rmp->ip4_address, rr->rdata, sizeof (ip4_address_t));
1223 ttl = clib_net_to_host_u32 (rr->ttl);
1224 if (min_ttlp && *min_ttlp > ttl)
1228 /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1229 memcpy (rmp->ip6_address, rr->rdata, sizeof (ip6_address_t));
1230 ttl = clib_net_to_host_u32 (rr->ttl);
1231 if (min_ttlp && *min_ttlp > ttl)
1239 /* Might as well stop ASAP */
1240 if (rmp->ip4_set && rmp->ip6_set)
1242 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1246 if ((rmp->ip4_set + rmp->ip6_set) == 0)
1247 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1252 vnet_dns_response_to_name (u8 * response,
1253 vl_api_dns_resolve_ip_reply_t * rmp,
1261 u8 *curpos, *pos, *pos2;
1266 u8 *junk __attribute__ ((unused));
1270 h = (dns_header_t *) response;
1271 flags = clib_net_to_host_u16 (h->flags);
1272 rcode = flags & DNS_RCODE_MASK;
1274 /* See if the response is OK, etc. */
1278 case DNS_RCODE_NO_ERROR:
1281 case DNS_RCODE_NAME_ERROR:
1282 case DNS_RCODE_FORMAT_ERROR:
1283 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1285 case DNS_RCODE_SERVER_FAILURE:
1286 case DNS_RCODE_NOT_IMPLEMENTED:
1287 case DNS_RCODE_REFUSED:
1288 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1291 /* No answers? Loser... */
1292 if (clib_net_to_host_u16 (h->anscount) < 1)
1293 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1295 curpos = (u8 *) (h + 1);
1297 /* Skip the name we asked about */
1300 /* Should never happen, but stil... */
1301 if ((len & 0xC0) == 0xC0)
1305 /* skip the name / label-set */
1314 limit = clib_net_to_host_u16 (h->qdcount);
1315 qp = (dns_query_t *) curpos;
1320 limit = clib_net_to_host_u16 (h->anscount);
1322 for (i = 0; i < limit; i++)
1324 pos = pos2 = curpos;
1327 /* Expect pointer chases in the answer section... */
1328 if ((pos2[0] & 0xC0) == 0xC0)
1331 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1340 if ((pos2[0] & 0xc0) == 0xc0)
1343 * If we've already done one pointer chase,
1344 * do not move the pos pointer.
1346 if (pointer_chase == 0)
1348 pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1356 if (pointer_chase == 0)
1359 rr = (dns_rr_t *) pos;
1361 switch (clib_net_to_host_u16 (rr->type))
1364 name = vnet_dns_labels_to_name (rr->rdata, response, &junk);
1365 memcpy (rmp->name, name, vec_len (name));
1366 ttl = clib_net_to_host_u32 (rr->ttl);
1369 rmp->name[vec_len (name)] = 0;
1375 /* Might as well stop ASAP */
1378 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1383 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1388 vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1390 dns_main_t *dm = &dns_main;
1391 vl_api_dns_resolve_name_reply_t *rmp;
1392 dns_cache_entry_t *ep;
1393 dns_pending_request_t _t0, *t0 = &_t0;
1396 /* Sanitize the name slightly */
1397 mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1399 t0->request_type = DNS_API_PENDING_NAME_TO_IP;
1400 t0->client_index = mp->client_index;
1401 t0->client_context = mp->context;
1403 rv = vnet_dns_resolve_name (dm, mp->name, t0, &ep);
1405 /* Error, e.g. not enabled? Tell the user */
1408 REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1412 /* Resolution pending? Don't reply... */
1417 REPLY_MACRO2(VL_API_DNS_RESOLVE_NAME_REPLY,
1419 rv = vnet_dns_response_to_reply (ep->dns_response, rmp, 0 /* ttl-ptr */);
1420 rmp->retval = clib_host_to_net_u32 (rv);
1425 * dns_resolve_name leaves the cache locked when it returns
1426 * a cached result, so unlock it here.
1428 dns_cache_unlock (dm);
1432 vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
1434 dns_main_t *dm = &dns_main;
1435 vl_api_dns_resolve_ip_reply_t *rmp;
1436 dns_cache_entry_t *ep;
1439 u8 *lookup_name = 0;
1441 dns_pending_request_t _t0, *t0 = &_t0;
1445 for (i = 15; i >= 0; i--)
1447 digit = mp->address[i];
1448 nybble = (digit & 0x0F);
1450 vec_add1 (lookup_name, (nybble - 10) + 'a');
1452 vec_add1 (lookup_name, nybble + '0');
1453 vec_add1 (lookup_name, '.');
1454 nybble = (digit & 0xF0) >> 4;
1456 vec_add1 (lookup_name, (nybble - 10) + 'a');
1458 vec_add1 (lookup_name, nybble + '0');
1459 vec_add1 (lookup_name, '.');
1461 len = vec_len (lookup_name);
1462 vec_validate (lookup_name, len + 8);
1463 memcpy (lookup_name + len, "ip6.arpa", 8);
1467 for (i = 3; i >= 0; i--)
1469 digit = mp->address[i];
1470 lookup_name = format (lookup_name, "%d.", digit);
1472 lookup_name = format (lookup_name, "in-addr.arpa");
1475 vec_add1 (lookup_name, 0);
1477 t0->request_type = DNS_API_PENDING_IP_TO_NAME;
1478 t0->client_index = mp->client_index;
1479 t0->client_context = mp->context;
1481 rv = vnet_dns_resolve_name (dm, lookup_name, t0, &ep);
1483 vec_free (lookup_name);
1485 /* Error, e.g. not enabled? Tell the user */
1488 REPLY_MACRO (VL_API_DNS_RESOLVE_IP_REPLY);
1492 /* Resolution pending? Don't reply... */
1497 REPLY_MACRO2(VL_API_DNS_RESOLVE_IP_REPLY,
1499 rv = vnet_dns_response_to_name (ep->dns_response, rmp, 0 /* ttl-ptr */);
1500 rmp->retval = clib_host_to_net_u32 (rv);
1505 * vnet_dns_resolve_name leaves the cache locked when it returns
1506 * a cached result, so unlock it here.
1508 dns_cache_unlock (dm);
1511 #define vl_msg_name_crc_list
1512 #include <vpp/api/vpe_all_api_h.h>
1513 #undef vl_msg_name_crc_list
1516 setup_message_id_table (api_main_t * am)
1518 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1519 foreach_vl_msg_name_crc_dns;
1523 #define foreach_dns_api_msg \
1524 _(DNS_ENABLE_DISABLE, dns_enable_disable) \
1525 _(DNS_NAME_SERVER_ADD_DEL, dns_name_server_add_del) \
1526 _(DNS_RESOLVE_NAME, dns_resolve_name) \
1527 _(DNS_RESOLVE_IP, dns_resolve_ip)
1529 static clib_error_t *
1530 dns_api_hookup (vlib_main_t * vm)
1533 vl_msg_api_set_handlers(VL_API_##N, #n, \
1534 vl_api_##n##_t_handler, \
1536 vl_api_##n##_t_endian, \
1537 vl_api_##n##_t_print, \
1538 sizeof(vl_api_##n##_t), 1);
1539 foreach_dns_api_msg;
1542 setup_message_id_table (&api_main);
1546 VLIB_API_INIT_FUNCTION (dns_api_hookup);
1549 static clib_error_t *
1550 dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1552 dns_main_t *dm = &dns_main;
1554 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1556 if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1558 else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1561 return clib_error_return (0, "unknown input `%U'",
1562 format_unformat_error, input);
1567 VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1569 static clib_error_t *
1570 dns_init (vlib_main_t * vm)
1572 dns_main_t *dm = &dns_main;
1575 dm->vnet_main = vnet_get_main ();
1576 dm->name_cache_size = 65535;
1577 dm->max_ttl_in_seconds = 86400;
1578 dm->random_seed = 0xDEADDABE;
1580 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply, dns46_reply_node.index,
1583 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply6, dns46_reply_node.index,
1586 udp_register_dst_port (vm, UDP_DST_PORT_dns, dns4_request_node.index,
1589 udp_register_dst_port (vm, UDP_DST_PORT_dns6, dns6_request_node.index,
1594 VLIB_INIT_FUNCTION (dns_init);
1597 unformat_dns_reply (unformat_input_t * input, va_list * args)
1599 u8 **result = va_arg (*args, u8 **);
1600 u8 **namep = va_arg (*args, u8 **);
1614 if (unformat (input, "%v", &name))
1617 if (unformat (input, "%U", unformat_ip4_address, &a4))
1620 if (unformat (input, "%U", unformat_ip6_address, &a6))
1624 if (unformat (input, "%U", unformat_ip6_address, &a6))
1627 if (unformat (input, "%U", unformat_ip4_address, &a6))
1631 /* Must have a name */
1635 /* Must have at least one address */
1636 if (!(a4_set + a6_set))
1639 /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1640 ce = name_to_labels (name);
1641 qp_offset = vec_len (ce);
1643 /* Add space for the query header */
1644 vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1645 qp = (dns_query_t *) (ce + qp_offset);
1647 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1648 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1650 /* Punch in space for the dns_header_t */
1651 vec_insert (ce, sizeof (dns_header_t), 0);
1653 h = (dns_header_t *) ce;
1655 /* Fake Transaction ID */
1658 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1659 h->qdcount = clib_host_to_net_u16 (1);
1660 h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1664 /* Now append one or two A/AAAA RR's... */
1667 /* Pointer to the name (DGMS) */
1668 vec_add1 (ce, 0xC0);
1669 vec_add1 (ce, 0x0C);
1670 vec_add2 (ce, rru8, sizeof (*rr) + 4);
1672 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1673 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1674 rr->ttl = clib_host_to_net_u32 (86400);
1675 rr->rdlength = clib_host_to_net_u16 (4);
1676 memcpy (rr->rdata, &a4, sizeof (a4));
1680 /* Pointer to the name (DGMS) */
1681 vec_add1 (ce, 0xC0);
1682 vec_add1 (ce, 0x0C);
1683 vec_add2 (ce, rru8, sizeof (*rr) + 16);
1685 rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1686 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1687 rr->ttl = clib_host_to_net_u32 (86400);
1688 rr->rdlength = clib_host_to_net_u16 (16);
1689 memcpy (rr->rdata, &a6, sizeof (a6));
1701 format_dns_query (u8 * s, va_list * args)
1703 u8 **curpos = va_arg (*args, u8 **);
1704 int verbose = va_arg (*args, int);
1709 s = format (s, " Name: ");
1711 /* Unwind execrated counted-label sheit */
1717 for (i = 0; i < len; i++)
1718 vec_add1 (s, *pos++);
1730 qp = (dns_query_t *) pos;
1733 switch (clib_net_to_host_u16 (qp->type))
1736 s = format (s, "type A\n");
1739 s = format (s, "type AAAA\n");
1742 s = format (s, "type ALL\n");
1746 s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1751 pos += sizeof (*qp);
1758 * format dns reply data
1759 * verbose > 1, dump everything
1760 * verbose == 1, dump all A and AAAA records
1761 * verbose == 0, dump one A record, and one AAAA record
1765 format_dns_reply_data (u8 * s, va_list * args)
1767 u8 *reply = va_arg (*args, u8 *);
1768 u8 **curpos = va_arg (*args, u8 **);
1769 int verbose = va_arg (*args, int);
1770 int *print_ip4 = va_arg (*args, int *);
1771 int *print_ip6 = va_arg (*args, int *);
1776 int pointer_chase = 0;
1778 u16 rrtype_host_byte_order;
1780 pos = pos2 = *curpos;
1783 s = format (s, " ");
1785 /* chase pointer? almost always yes here... */
1786 if ((pos2[0] & 0xc0) == 0xc0)
1789 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1797 for (i = 0; i < len; i++)
1800 vec_add1 (s, *pos2);
1803 if ((pos2[0] & 0xc0) == 0xc0)
1806 * If we've already done one pointer chase,
1807 * do not move the pos pointer.
1809 if (pointer_chase == 0)
1811 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1829 if (pointer_chase == 0)
1832 rr = (dns_rr_t *) pos;
1833 rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
1835 switch (rrtype_host_byte_order)
1840 s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1841 format_ip4_address, rr->rdata);
1846 s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1847 clib_net_to_host_u32 (rr->ttl));
1852 pos += sizeof (*rr) + 4;
1858 s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1859 format_ip6_address, rr->rdata);
1864 s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1865 clib_net_to_host_u32 (rr->ttl));
1869 pos += sizeof (*rr) + 16;
1875 s = format (s, "TEXT: ");
1876 for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1877 vec_add1 (s, rr->rdata[i]);
1880 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1883 case DNS_TYPE_HINFO:
1885 /* Two counted strings. DGMS */
1891 s = format (s, "HINFO: ");
1894 for (i = 0; i < *len; i++)
1895 vec_add1 (s, *curpos++);
1899 for (i = 0; i < *len; i++)
1900 vec_add1 (s, *curpos++);
1905 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1908 case DNS_TYPE_NAMESERVER:
1911 s = format (s, "Nameserver: ");
1914 /* chase pointer? */
1915 if ((pos2[0] & 0xc0) == 0xc0)
1918 pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1925 for (i = 0; i < len; i++)
1926 vec_add1 (s, *pos2++);
1928 /* chase pointer, typically to offset 12... */
1929 if (pos2[0] == 0xC0)
1930 pos2 = reply + pos2[1];
1939 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1942 case DNS_TYPE_MAIL_EXCHANGE:
1945 tp = (u16 *) rr->rdata;
1947 s = format (s, "Mail Exchange: Preference %d ", (u32)
1948 clib_net_to_host_u16 (*tp));
1950 pos2 = rr->rdata + 2;
1952 /* chase pointer? */
1953 if (pos2[0] == 0xc0)
1954 pos2 = reply + pos2[1];
1960 for (i = 0; i < len; i++)
1961 vec_add1 (s, *pos2++);
1964 if (pos2[0] == 0xC0)
1965 pos2 = reply + pos2[1];
1975 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1979 case DNS_TYPE_CNAME:
1982 tp = (u16 *) rr->rdata;
1984 if (rrtype_host_byte_order == DNS_TYPE_CNAME)
1985 s = format (s, "CNAME: ");
1987 s = format (s, "PTR: ");
1991 /* chase pointer? */
1992 if (pos2[0] == 0xc0)
1993 pos2 = reply + pos2[1];
1999 for (i = 0; i < len; i++)
2000 vec_add1 (s, *pos2++);
2003 if (pos2[0] == 0xC0)
2004 pos2 = reply + pos2[1];
2013 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2018 s = format (s, "type %d: len %d\n",
2019 (int) clib_net_to_host_u16 (rr->type),
2020 sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
2021 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2031 format_dns_reply (u8 * s, va_list * args)
2033 u8 *reply_as_u8 = va_arg (*args, u8 *);
2034 int verbose = va_arg (*args, int);
2042 h = (dns_header_t *) reply_as_u8;
2043 id = clib_net_to_host_u16 (h->id);
2044 flags = clib_net_to_host_u16 (h->flags);
2048 s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
2050 s = format (s, " %s %s %s %s\n",
2051 (flags & DNS_RA) ? "recur" : "no-recur",
2052 (flags & DNS_RD) ? "recur-des" : "no-recur-des",
2053 (flags & DNS_TC) ? "trunc" : "no-trunc",
2054 (flags & DNS_AA) ? "auth" : "non-auth");
2055 s = format (s, " %d queries, %d answers, %d name-servers,"
2057 clib_net_to_host_u16 (h->qdcount),
2058 clib_net_to_host_u16 (h->anscount),
2059 clib_net_to_host_u16 (h->nscount),
2060 clib_net_to_host_u16 (h->arcount));
2063 curpos = (u8 *) (h + 1);
2068 s = format (s, " Queries:\n");
2069 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
2071 /* The query is variable-length, so curpos is a value-result parm */
2072 s = format (s, "%U", format_dns_query, &curpos, verbose);
2078 s = format (s, " Replies:\n");
2080 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
2082 /* curpos is a value-result parm */
2083 s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
2084 verbose, &print_ip4, &print_ip6);
2091 format_dns_cache (u8 * s, va_list * args)
2093 dns_main_t *dm = va_arg (*args, dns_main_t *);
2094 f64 now = va_arg (*args, f64);
2095 int verbose = va_arg (*args, int);
2096 u8 *name = va_arg (*args, u8 *);
2097 dns_cache_entry_t *ep;
2101 if (dm->is_enabled == 0)
2103 s = format (s, "The DNS cache is disabled...");
2107 if (pool_elts (dm->entries) == 0)
2109 s = format (s, "The DNS cache is empty...");
2113 dns_cache_lock (dm);
2117 p = hash_get_mem (dm->cache_entry_by_name, name);
2120 s = format (s, "%s is not in the cache...", name);
2121 dns_cache_unlock (dm);
2125 ep = pool_elt_at_index (dm->entries, p[0]);
2126 /* Magic to spit out a C-initializer to research hemorrhoids... */
2130 s = format (s, "static u8 dns_reply_data_initializer[] =\n");
2131 s = format (s, "{\n");
2133 for (i = 0; i < vec_len (ep->dns_response); i++)
2140 s = format (s, "0x%02x, ", ep->dns_response[i]);
2142 s = format (s, "};\n");
2146 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2148 ASSERT (ep->dns_response);
2149 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2154 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2155 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2157 s = format (s, "%s%s -> %U", ss, ep->name,
2158 format_dns_reply, ep->dns_response, verbose);
2159 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2161 f64 time_left = ep->expiration_time - now;
2162 if (time_left > 0.0)
2163 s = format (s, " TTL left %.1f", time_left);
2165 s = format (s, " EXPIRED");
2170 ASSERT (ep->dns_request);
2171 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2180 pool_foreach (ep, dm->entries,
2182 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2184 ASSERT (ep->dns_response);
2185 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2190 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2191 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2193 s = format (s, "%s%s -> %U", ss, ep->name,
2197 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2199 f64 time_left = ep->expiration_time - now;
2200 if (time_left > 0.0)
2201 s = format (s, " TTL left %.1f", time_left);
2203 s = format (s, " EXPIRED");
2206 s = format (s, " %d client notifications pending\n",
2207 vec_len(ep->pending_requests));
2212 ASSERT (ep->dns_request);
2213 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2220 dns_cache_unlock (dm);
2225 static clib_error_t *
2226 show_dns_cache_command_fn (vlib_main_t * vm,
2227 unformat_input_t * input, vlib_cli_command_t * cmd)
2229 dns_main_t *dm = &dns_main;
2232 f64 now = vlib_time_now (vm);
2234 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2236 if (unformat (input, "verbose %d", &verbose))
2238 else if (unformat (input, "verbose"))
2240 else if (unformat (input, "name %s", &name))
2243 return clib_error_return (0, "unknown input `%U'",
2244 format_unformat_error, input);
2247 vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
2253 VLIB_CLI_COMMAND (show_dns_cache_command) =
2255 .path = "show dns cache",
2256 .short_help = "show dns cache [verbose [nn]]",
2257 .function = show_dns_cache_command_fn,
2261 static clib_error_t *
2262 dns_cache_add_del_command_fn (vlib_main_t * vm,
2263 unformat_input_t * input,
2264 vlib_cli_command_t * cmd)
2266 dns_main_t *dm = &dns_main;
2272 clib_error_t *error;
2274 if (unformat (input, "add"))
2276 if (unformat (input, "del"))
2278 if (unformat (input, "clear"))
2281 if (is_add == -1 && is_clear == -1)
2282 return clib_error_return (0, "add / del / clear required...");
2286 rv = dns_cache_clear (dm);
2292 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2293 error = clib_error_return (0, "Name resolution not enabled");
2298 /* Delete (by name)? */
2301 if (unformat (input, "%v", &name))
2303 rv = dns_delete_by_name (dm, name);
2306 case VNET_API_ERROR_NO_SUCH_ENTRY:
2307 error = clib_error_return (0, "%v not in the cache...", name);
2311 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2312 error = clib_error_return (0, "Name resolution not enabled");
2321 error = clib_error_return (0, "dns_delete_by_name returned %d",
2327 return clib_error_return (0, "unknown input `%U'",
2328 format_unformat_error, input);
2331 /* Note: dns_add_static_entry consumes the name vector if OK... */
2332 if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2334 rv = dns_add_static_entry (dm, name, dns_reply_data);
2337 case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2339 vec_free (dns_reply_data);
2340 return clib_error_return (0, "%v already in the cache...", name);
2345 return clib_error_return (0, "dns_add_static_entry returned %d",
2354 VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2356 .path = "dns cache",
2357 .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2358 .function = dns_cache_add_del_command_fn,
2362 #define DNS_FORMAT_TEST 1
2364 #if DNS_FORMAT_TEST > 0
2367 static u8 dns_reply_data_initializer[] =
2368 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2369 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2371 0x0, 0xff, /* type ALL */
2372 0x0, 0x1, /* class IN */
2373 0xc0, 0xc, /* pointer to yahoo.com name */
2374 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2375 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2376 0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2377 0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2378 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2379 0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2380 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2381 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2382 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2383 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2384 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2385 0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2386 0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2388 0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2389 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2390 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2391 0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2392 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2394 0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2395 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2396 0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2397 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2399 0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2400 0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2402 0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2404 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2406 0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2408 0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2409 0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2410 0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2414 /* www.cisco.com, has no addresses in reply */
2415 static u8 dns_reply_data_initializer[] = {
2416 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2417 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2418 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2420 0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2421 0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2422 0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2423 0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2424 0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2427 /* bind8 (linux widget, w/ nasty double pointer chasees */
2428 static u8 dns_reply_data_initializer[] = {
2430 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08,
2432 0x00, 0x06, 0x00, 0x06, 0x0a, 0x6f, 0x72, 0x69,
2434 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77, 0x77, 0x05,
2436 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f,
2438 0x6d, 0x00, 0x00, 0xff, 0x00, 0x01, 0x0a, 0x6f,
2440 0x72, 0x69, 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77,
2442 0x77, 0x05, 0x43, 0x49, 0x53, 0x43, 0x4f, 0xc0,
2445 0x1d, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2448 0x9a, 0x00, 0x18, 0x15, 0x72, 0x63, 0x64,
2449 0x6e, 0x39, 0x2d, 0x31, 0x34, 0x70, 0x2d, 0x64, 0x63,
2450 0x7a, 0x30, 0x35, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31,
2451 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00, 0x01, 0x00,
2452 0x00, 0x05, 0x9a, 0x00, 0x1a, 0x17, 0x61, 0x6c, 0x6c,
2453 0x6e, 0x30, 0x31, 0x2d, 0x61, 0x67, 0x30, 0x39, 0x2d,
2454 0x64, 0x63, 0x7a, 0x30, 0x33, 0x6e, 0x2d, 0x67, 0x73,
2455 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00,
2456 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x10, 0x0d, 0x72,
2457 0x74, 0x70, 0x35, 0x2d, 0x64, 0x6d, 0x7a, 0x2d, 0x67,
2458 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2459 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x18, 0x15,
2460 0x6d, 0x74, 0x76, 0x35, 0x2d, 0x61, 0x70, 0x31, 0x30,
2461 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x36, 0x6e, 0x2d, 0x67,
2462 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2463 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x1b, 0x18,
2464 0x73, 0x6e, 0x67, 0x64, 0x63, 0x30, 0x31, 0x2d, 0x61,
2465 0x62, 0x30, 0x37, 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x31,
2466 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0,
2467 0x26, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a,
2468 0x00, 0x1a, 0x17, 0x61, 0x65, 0x72, 0x30, 0x31, 0x2d,
2469 0x72, 0x34, 0x63, 0x32, 0x35, 0x2d, 0x64, 0x63, 0x7a,
2470 0x30, 0x31, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0,
2471 0x17, 0xc0, 0x26, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2472 0x00, 0x81, 0x00, 0x04, 0x48, 0xa3, 0x04, 0xa1, 0xc0,
2473 0x26, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82,
2474 0x00, 0x10, 0x20, 0x01, 0x04, 0x20, 0x12, 0x01, 0x00,
2475 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
2476 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2477 0x9a, 0x00, 0x02, 0xc0, 0xf4, 0xc0, 0x0c, 0x00, 0x02,
2478 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0,
2479 0xcd, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00,
2480 0x05, 0x9a, 0x00, 0x02, 0xc0, 0x8d, 0xc0, 0x0c, 0x00,
2481 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02,
2482 0xc0, 0x43, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00,
2483 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0, 0xa9, 0xc0, 0x0c,
2484 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00,
2485 0x02, 0xc0, 0x67, 0xc0, 0x8d, 0x00, 0x01, 0x00, 0x01,
2486 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0x40, 0x66, 0xf6,
2487 0x05, 0xc0, 0xa9, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2488 0x07, 0x08, 0x00, 0x04, 0xad, 0x24, 0xe0, 0x64, 0xc0,
2489 0x43, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08,
2490 0x00, 0x04, 0x48, 0xa3, 0x04, 0x1c, 0xc0, 0xf4, 0x00,
2491 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04,
2492 0xad, 0x26, 0xd4, 0x6c, 0xc0, 0x67, 0x00, 0x01, 0x00,
2493 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x25,
2494 0x90, 0x64, 0xc0, 0xcd, 0x00, 0x01, 0x00, 0x01, 0x00,
2495 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x27, 0x70, 0x44,
2499 static u8 dns_reply_data_initializer[] =
2500 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
2501 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
2502 0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
2503 0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
2505 0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
2506 0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
2507 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
2508 0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
2509 0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
2510 0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
2511 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
2512 0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
2513 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
2514 0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
2515 0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
2516 0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
2517 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
2518 0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
2519 0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
2520 0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
2521 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2522 0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
2523 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
2524 0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
2525 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
2526 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
2527 0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
2529 0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2533 /* www.weatherlink.com */
2534 static u8 dns_reply_data_initializer[] = {
2535 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2536 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x0b,
2537 0x77, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x6c, 0x69,
2538 0x6e, 0x6b, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0xff,
2539 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00,
2540 0x00, 0x0c, 0x9e, 0x00, 0x1f, 0x0e, 0x64, 0x33, 0x6b,
2541 0x72, 0x30, 0x67, 0x75, 0x62, 0x61, 0x31, 0x64, 0x76,
2542 0x77, 0x66, 0x0a, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x66,
2543 0x72, 0x6f, 0x6e, 0x74, 0x03, 0x6e, 0x65, 0x74, 0x00,
2548 static clib_error_t *
2549 test_dns_fmt_command_fn (vlib_main_t * vm,
2550 unformat_input_t * input, vlib_cli_command_t * cmd)
2552 u8 *dns_reply_data = 0;
2555 vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2557 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2559 if (unformat (input, "verbose %d", &verbose))
2561 else if (unformat (input, "verbose"))
2564 return clib_error_return (0, "unknown input `%U'",
2565 format_unformat_error, input);
2568 vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2570 memcpy (dns_reply_data, dns_reply_data_initializer,
2571 ARRAY_LEN (dns_reply_data_initializer));
2573 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2575 memset (rmp, 0, sizeof (*rmp));
2577 rv = vnet_dns_response_to_reply (dns_reply_data, rmp, 0 /* ttl-ptr */ );
2581 case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2582 vlib_cli_output (vm, "no addresses found...");
2586 vlib_cli_output (vm, "response to reply returned %d", rv);
2591 vlib_cli_output (vm, "ip4 address: %U", format_ip4_address,
2592 (ip4_address_t *) rmp->ip4_address);
2594 vlib_cli_output (vm, "ip6 address: %U", format_ip6_address,
2595 (ip6_address_t *) rmp->ip6_address);
2599 vec_free (dns_reply_data);
2606 VLIB_CLI_COMMAND (test_dns_fmt_command) =
2608 .path = "test dns format",
2609 .short_help = "test dns format",
2610 .function = test_dns_fmt_command_fn,
2614 static clib_error_t *
2615 test_dns_unfmt_command_fn (vlib_main_t * vm,
2616 unformat_input_t * input, vlib_cli_command_t * cmd)
2618 u8 *dns_reply_data = 0;
2622 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2624 if (unformat (input, "verbose %d", &verbose))
2626 else if (unformat (input, "verbose"))
2628 else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2631 return clib_error_return (0, "unknown input `%U'",
2632 format_unformat_error, input);
2636 return clib_error_return (0, "dns data not set...");
2638 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2640 vec_free (dns_reply_data);
2646 VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2648 .path = "test dns unformat",
2649 .short_help = "test dns unformat <name> [ip4][ip6]",
2650 .function = test_dns_unfmt_command_fn,
2654 static clib_error_t *
2655 test_dns_expire_command_fn (vlib_main_t * vm,
2656 unformat_input_t * input,
2657 vlib_cli_command_t * cmd)
2659 dns_main_t *dm = &dns_main;
2663 dns_cache_entry_t *ep;
2665 if (unformat (input, "%v", &name))
2668 _vec_len (name) -= 1;
2671 dns_cache_lock (dm);
2673 p = hash_get_mem (dm->cache_entry_by_name, name);
2676 dns_cache_unlock (dm);
2677 e = clib_error_return (0, "%s is not in the cache...", name);
2682 ep = pool_elt_at_index (dm->entries, p[0]);
2684 ep->expiration_time = 0;
2690 VLIB_CLI_COMMAND (test_dns_expire_command) =
2692 .path = "test dns expire",
2693 .short_help = "test dns expire <name>",
2694 .function = test_dns_expire_command_fn,
2700 vnet_send_dns6_reply (dns_main_t * dm, dns_pending_request_t * pr,
2701 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2703 clib_warning ("Unimplemented...");
2708 vnet_send_dns4_reply (dns_main_t * dm, dns_pending_request_t * pr,
2709 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2711 vlib_main_t *vm = dm->vlib_main;
2713 fib_prefix_t prefix;
2714 fib_node_index_t fei;
2715 u32 sw_if_index, fib_index;
2716 ip4_main_t *im4 = &ip4_main;
2717 ip_lookup_main_t *lm4 = &im4->lookup_main;
2718 ip_interface_address_t *ia = 0;
2719 ip4_address_t *src_address;
2727 vl_api_dns_resolve_name_reply_t _rnr, *rnr = &_rnr;
2728 vl_api_dns_resolve_ip_reply_t _rir, *rir = &_rir;
2736 ASSERT (ep && ep->dns_response);
2738 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2740 /* Quick and dirty way to dig up the A-record address. $$ FIXME */
2741 memset (rnr, 0, sizeof (*rnr));
2742 if (vnet_dns_response_to_reply (ep->dns_response, rnr, &ttl))
2744 /* clib_warning ("response_to_reply failed..."); */
2747 if (rnr->ip4_set == 0)
2749 /* clib_warning ("No A-record..."); */
2753 else if (pr->request_type == DNS_PEER_PENDING_IP_TO_NAME)
2755 memset (rir, 0, sizeof (*rir));
2756 if (vnet_dns_response_to_name (ep->dns_response, rir, &ttl))
2758 /* clib_warning ("response_to_name failed..."); */
2764 clib_warning ("Unknown request type %d", pr->request_type);
2768 /* Initialize a buffer */
2771 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2773 b0 = vlib_get_buffer (vm, bi);
2776 if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
2777 vlib_buffer_free_one (vm, b0->next_buffer);
2780 * Reset the buffer. We recycle the DNS request packet in the cache
2781 * hit case, and reply immediately from the request node.
2783 * In the resolution-required / deferred case, resetting a freshly-allocated
2784 * buffer won't hurt. We hope.
2786 b0->flags &= VLIB_BUFFER_FREE_LIST_INDEX_MASK;
2787 b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
2788 | VLIB_BUFFER_TOTAL_LENGTH_VALID);
2789 b0->current_data = 0;
2790 b0->current_length = 0;
2791 b0->total_length_not_including_first_buffer = 0;
2792 vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; /* "local0" */
2793 vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
2795 /* Find a FIB path to the peer we're trying to answer */
2796 clib_memcpy (&prefix.fp_addr.ip4, pr->dst_address, sizeof (ip4_address_t));
2797 prefix.fp_proto = FIB_PROTOCOL_IP4;
2800 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
2801 if (fib_index == (u32) ~ 0)
2803 clib_warning ("no fib table");
2807 fei = fib_table_lookup (fib_index, &prefix);
2809 /* Couldn't find route to destination. Bail out. */
2810 if (fei == FIB_NODE_INDEX_INVALID)
2812 clib_warning ("no route to DNS server");
2816 sw_if_index = fib_entry_get_resolving_interface (fei);
2818 if (sw_if_index == ~0)
2821 ("route to %U exists, fei %d, get_resolving_interface returned"
2822 " ~0", fei, format_ip4_address, &prefix.fp_addr);
2827 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnummbered */,
2829 src_address = ip_interface_address_get_address (lm4, ia);
2830 goto found_src_address;
2834 clib_warning ("FIB BUG");
2839 ip = vlib_buffer_get_current (b0);
2840 udp = (udp_header_t *) (ip + 1);
2841 dns_response = (u8 *) (udp + 1);
2842 memset (ip, 0, sizeof (*ip) + sizeof (*udp));
2845 * Start with the variadic portion of the exercise.
2846 * Turn the name into a set of DNS "labels". Max length
2847 * per label is 63, enforce that.
2849 reply = name_to_labels (pr->name);
2850 vec_free (pr->name);
2852 qp_offset = vec_len (reply);
2854 /* Add space for the query header */
2855 vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
2857 qp = (dns_query_t *) (reply + qp_offset);
2859 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2860 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
2862 qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2864 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
2866 /* Punch in space for the dns_header_t */
2867 vec_insert (reply, sizeof (dns_header_t), 0);
2869 dh = (dns_header_t *) reply;
2871 /* Transaction ID = pool index */
2874 /* Announce that we did a recursive lookup */
2875 tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
2877 tmp |= DNS_RCODE_NAME_ERROR;
2878 dh->flags = clib_host_to_net_u16 (tmp);
2879 dh->qdcount = clib_host_to_net_u16 (1);
2880 dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
2884 /* If the name resolution worked, cough up an appropriate RR */
2887 /* Add the answer. First, a name pointer (0xC00C) */
2888 vec_add1 (reply, 0xC0);
2889 vec_add1 (reply, 0x0C);
2891 /* Now, add single A-rec RR */
2892 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2894 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
2895 rr = (dns_rr_t *) rrptr;
2897 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
2898 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2899 rr->ttl = clib_host_to_net_u32 (ttl);
2900 rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
2901 clib_memcpy (rr->rdata, rnr->ip4_address, sizeof (ip4_address_t));
2905 /* Or a single PTR RR */
2906 u8 *vecname = format (0, "%s", rir->name);
2907 u8 *label_vec = name_to_labels (vecname);
2910 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
2911 rr = (dns_rr_t *) rrptr;
2912 rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2913 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2914 rr->ttl = clib_host_to_net_u32 (ttl);
2915 rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
2916 clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
2917 vec_free (label_vec);
2920 clib_memcpy (dns_response, reply, vec_len (reply));
2922 /* Set the packet length */
2923 b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
2926 ip->ip_version_and_header_length = 0x45;
2927 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
2929 ip->protocol = IP_PROTOCOL_UDP;
2930 ip->src_address.as_u32 = src_address->as_u32;
2931 clib_memcpy (ip->dst_address.as_u8, pr->dst_address,
2932 sizeof (ip4_address_t));
2933 ip->checksum = ip4_header_checksum (ip);
2936 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
2937 udp->dst_port = pr->dst_port;
2938 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
2943 /* Ship it to ip4_lookup */
2944 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
2945 to_next = vlib_frame_vector_args (f);
2948 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
2952 * fd.io coding-style-patch-verification: ON
2955 * eval: (c-set-style "gnu")