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 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", fei, format_ip4_address, &prefix.fp_addr);
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 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)
523 /* This can easily happen if sitting in GDB, etc. */
524 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
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 qp_offset = vec_len (request);
538 /* Add space for the query header */
539 vec_validate (request, qp_offset + sizeof (dns_query_t) - 1);
541 qp = (dns_query_t *) (request + qp_offset);
543 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
544 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
546 /* Punch in space for the dns_header_t */
547 vec_insert (request, sizeof (dns_header_t), 0);
549 h = (dns_header_t *) request;
551 /* Transaction ID = pool index */
552 h->id = clib_host_to_net_u16 (ep - dm->entries);
554 /* Ask for a recursive lookup */
555 tmp = DNS_RD | DNS_OPCODE_QUERY;
556 h->flags = clib_host_to_net_u16 (tmp);
557 h->qdcount = clib_host_to_net_u16 (1);
561 ep->dns_request = request;
564 /* Work out which server / address family we're going to use */
566 /* Retry using current server */
567 if (ep->retry_count++ < DNS_RETRIES_PER_SERVER)
569 if (ep->server_af == 1 /* ip6 */ )
571 if (vec_len (dm->ip6_name_servers))
573 send_dns6_request (dm, ep,
574 dm->ip6_name_servers + ep->server_rotor);
580 if (vec_len (dm->ip4_name_servers))
582 send_dns4_request (dm, ep, dm->ip4_name_servers + ep->server_rotor);
586 else /* switch to a new server */
590 if (ep->server_af == 1 /* ip6 */ )
592 if (ep->server_rotor >= vec_len (dm->ip6_name_servers))
594 ep->server_rotor = 0;
595 ep->server_af = vec_len (dm->ip4_name_servers) > 0 ? 0 : 1;
600 if (ep->server_rotor >= vec_len (dm->ip4_name_servers))
602 ep->server_rotor = 0;
603 ep->server_af = vec_len (dm->ip6_name_servers) > 0 ? 1 : 0;
608 if (ep->server_af == 1 /* ip6 */ )
609 send_dns6_request (dm, ep, dm->ip6_name_servers + ep->server_rotor);
611 send_dns4_request (dm, ep, dm->ip4_name_servers + ep->server_rotor);
615 vlib_process_signal_event_mt (dm->vlib_main, dns_resolver_node.index,
616 DNS_RESOLVER_EVENT_PENDING, 0);
620 vnet_dns_delete_entry_by_index_nolock (dns_main_t * dm, u32 index)
622 dns_cache_entry_t *ep;
625 if (dm->is_enabled == 0)
626 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
628 if (pool_is_free_index (dm->entries, index))
629 return VNET_API_ERROR_NO_SUCH_ENTRY;
631 ep = pool_elt_at_index (dm->entries, index);
632 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_VALID))
634 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
635 if (index == dm->unresolved_entries[i])
637 vec_delete (dm->unresolved_entries, 1, i);
640 clib_warning ("pool elt %d supposedly pending, but not found...",
645 hash_unset_mem (dm->cache_entry_by_name, ep->name);
647 vec_free (ep->pending_requests);
648 pool_put (dm->entries, ep);
654 dns_delete_by_name (dns_main_t * dm, u8 * name)
659 if (dm->is_enabled == 0)
660 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
663 p = hash_get_mem (dm->cache_entry_by_name, name);
666 dns_cache_unlock (dm);
667 return VNET_API_ERROR_NO_SUCH_ENTRY;
669 rv = vnet_dns_delete_entry_by_index_nolock (dm, p[0]);
671 dns_cache_unlock (dm);
677 delete_random_entry (dns_main_t * dm)
680 u32 victim_index, start_index, i;
682 dns_cache_entry_t *ep;
684 if (dm->is_enabled == 0)
685 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
688 * Silence spurious coverity warning. We know pool_elts >> 0, or
689 * we wouldn't be here...
692 if (pool_elts (dm->entries) == 0)
693 return VNET_API_ERROR_UNSPECIFIED;
697 limit = pool_elts (dm->entries);
698 start_index = random_u32 (&dm->random_seed) % limit;
700 for (i = 0; i < limit; i++)
702 victim_index = (start_index + i) % limit;
704 if (!pool_is_free_index (dm->entries, victim_index))
706 ep = pool_elt_at_index (dm->entries, victim_index);
707 /* Delete only valid, non-static entries */
708 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
709 && ((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0))
711 rv = vnet_dns_delete_entry_by_index_nolock (dm, victim_index);
712 dns_cache_unlock (dm);
717 dns_cache_unlock (dm);
719 clib_warning ("Couldn't find an entry to delete?");
720 return VNET_API_ERROR_UNSPECIFIED;
724 dns_add_static_entry (dns_main_t * dm, u8 * name, u8 * dns_reply_data)
726 dns_cache_entry_t *ep;
730 if (dm->is_enabled == 0)
731 return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
734 p = hash_get_mem (dm->cache_entry_by_name, name);
737 dns_cache_unlock (dm);
738 return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
741 if (pool_elts (dm->entries) == dm->name_cache_size)
743 /* Will only fail if the cache is totally filled w/ static entries... */
744 rv = delete_random_entry (dm);
747 dns_cache_unlock (dm);
752 pool_get (dm->entries, ep);
753 memset (ep, 0, sizeof (*ep));
755 /* Note: consumes the name vector */
757 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
758 ep->flags = DNS_CACHE_ENTRY_FLAG_VALID | DNS_CACHE_ENTRY_FLAG_STATIC;
759 ep->dns_response = dns_reply_data;
761 dns_cache_unlock (dm);
766 vnet_dns_resolve_name (dns_main_t * dm, u8 * name, dns_pending_request_t * t,
767 dns_cache_entry_t ** retp)
769 dns_cache_entry_t *ep;
773 dns_pending_request_t *pr;
776 now = vlib_time_now (dm->vlib_main);
778 /* In case we can't actually answer the question right now... */
783 p = hash_get_mem (dm->cache_entry_by_name, name);
786 ep = pool_elt_at_index (dm->entries, p[0]);
787 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
789 /* Has the entry expired? */
790 if (((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0)
791 && (now > ep->expiration_time))
794 u32 *indices_to_delete = 0;
797 * Take out the rest of the resolution chain
798 * This isn't optimal, but it won't happen very often.
802 if ((ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME))
804 vec_add1 (indices_to_delete, ep - dm->entries);
806 p = hash_get_mem (dm->cache_entry_by_name, ep->cname);
809 ep = pool_elt_at_index (dm->entries, p[0]);
813 vec_add1 (indices_to_delete, ep - dm->entries);
817 for (i = 0; i < vec_len (indices_to_delete); i++)
819 /* Reenable to watch re-resolutions */
822 ep = pool_elt_at_index (dm->entries,
823 indices_to_delete[i]);
824 clib_warning ("Re-resolve %s", ep->name);
827 vnet_dns_delete_entry_by_index_nolock
828 (dm, indices_to_delete[i]);
830 vec_free (indices_to_delete);
831 /* Yes, kill it... */
835 if (ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
841 /* Note: caller must drop the lock! */
848 * Resolution pending. Add request to the pending vector
849 * by copying the template request
851 vec_add2 (ep->pending_requests, pr, 1);
852 memcpy (pr, t, sizeof (*pr));
853 dns_cache_unlock (dm);
859 if (pool_elts (dm->entries) == dm->name_cache_size)
861 /* Will only fail if the cache is totally filled w/ static entries... */
862 rv = delete_random_entry (dm);
865 dns_cache_unlock (dm);
870 /* add new hash table entry */
871 pool_get (dm->entries, ep);
872 memset (ep, 0, sizeof (*ep));
874 ep->name = format (0, "%s%c", name, 0);
875 _vec_len (ep->name) = vec_len (ep->name) - 1;
877 hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
879 vec_add1 (dm->unresolved_entries, ep - dm->entries);
880 vec_add2 (ep->pending_requests, pr, 1);
882 pr->request_type = t->request_type;
884 /* Remember details so we can reply later... */
885 if (t->request_type == DNS_API_PENDING_NAME_TO_IP ||
886 t->request_type == DNS_API_PENDING_IP_TO_NAME)
888 pr->client_index = t->client_index;
889 pr->client_context = t->client_context;
893 pr->client_index = ~0;
894 pr->is_ip6 = t->is_ip6;
895 pr->dst_port = t->dst_port;
902 clib_memcpy (pr->dst_address, t->dst_address, count);
905 vnet_send_dns_request (dm, ep);
906 dns_cache_unlock (dm);
910 #define foreach_notification_to_move \
914 * Handle cname indirection. JFC. Called with the cache locked.
915 * returns 0 if the reply is not a CNAME.
919 vnet_dns_cname_indirection_nolock (dns_main_t * dm, u32 ep_index, u8 * reply)
932 dns_cache_entry_t *ep, *next_ep;
935 h = (dns_header_t *) reply;
936 flags = clib_net_to_host_u16 (h->flags);
937 rcode = flags & DNS_RCODE_MASK;
939 /* See if the response is OK */
942 case DNS_RCODE_NO_ERROR:
945 case DNS_RCODE_NAME_ERROR:
946 case DNS_RCODE_FORMAT_ERROR:
947 case DNS_RCODE_SERVER_FAILURE:
948 case DNS_RCODE_NOT_IMPLEMENTED:
949 case DNS_RCODE_REFUSED:
953 curpos = (u8 *) (h + 1);
957 /* Skip the questions */
958 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
965 pos += sizeof (dns_query_t);
968 /* expect a pointer chase here for a CNAME record */
969 if ((pos2[0] & 0xC0) == 0xC0)
974 rr = (dns_rr_t *) pos;
976 /* This is a real record, not a CNAME record */
977 if (clib_net_to_host_u16 (rr->type) != DNS_TYPE_CNAME)
980 /* This is a CNAME record, chase the name chain. */
982 /* The last request is no longer pending.. */
983 for (i = 0; i < vec_len (dm->unresolved_entries); i++)
984 if (ep_index == dm->unresolved_entries[i])
986 vec_delete (dm->unresolved_entries, 1, i);
987 goto found_last_request;
989 clib_warning ("pool elt %d supposedly pending, but not found...", ep_index);
993 now = vlib_time_now (dm->vlib_main);
994 cname = vnet_dns_labels_to_name (rr->rdata, reply, &pos2);
997 _vec_len (cname) -= 1;
998 ep = pool_elt_at_index (dm->entries, ep_index);
1000 ep->flags |= (DNS_CACHE_ENTRY_FLAG_CNAME | DNS_CACHE_ENTRY_FLAG_VALID);
1001 /* Save the response */
1002 ep->dns_response = reply;
1003 /* Set up expiration time */
1004 ep->expiration_time = now + clib_net_to_host_u32 (rr->ttl);
1006 pool_get (dm->entries, next_ep);
1008 /* Need to recompute ep post pool-get */
1009 ep = pool_elt_at_index (dm->entries, ep_index);
1011 memset (next_ep, 0, sizeof (*next_ep));
1012 next_ep->name = vec_dup (cname);
1013 vec_add1 (next_ep->name, 0);
1014 _vec_len (next_ep->name) -= 1;
1016 hash_set_mem (dm->cache_entry_by_name, next_ep->name,
1017 next_ep - dm->entries);
1019 /* Use the same server */
1020 next_ep->server_rotor = ep->server_rotor;
1021 next_ep->server_af = ep->server_af;
1023 /* Move notification data to the next name in the chain */
1024 #define _(a) next_ep->a = ep->a; ep->a = 0;
1025 foreach_notification_to_move;
1028 request = name_to_labels (cname);
1030 qp_offset = vec_len (request);
1032 /* Add space for the query header */
1033 vec_validate (request, qp_offset + sizeof (dns_query_t) - 1);
1035 qp = (dns_query_t *) (request + qp_offset);
1037 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1038 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1040 /* Punch in space for the dns_header_t */
1041 vec_insert (request, sizeof (dns_header_t), 0);
1043 h = (dns_header_t *) request;
1045 /* Transaction ID = pool index */
1046 h->id = clib_host_to_net_u16 (next_ep - dm->entries);
1048 /* Ask for a recursive lookup */
1049 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
1050 h->qdcount = clib_host_to_net_u16 (1);
1054 next_ep->dns_request = request;
1055 next_ep->retry_timer = now + 2.0;
1056 next_ep->retry_count = 0;
1059 * Enable this to watch recursive resolution happen...
1060 * fformat (stdout, "%U", format_dns_reply, request, 2);
1063 vec_add1 (dm->unresolved_entries, next_ep - dm->entries);
1064 vnet_send_dns_request (dm, next_ep);
1069 vnet_dns_response_to_reply (u8 * response,
1070 vl_api_dns_resolve_name_reply_t * rmp,
1083 h = (dns_header_t *) response;
1084 flags = clib_net_to_host_u16 (h->flags);
1085 rcode = flags & DNS_RCODE_MASK;
1087 /* See if the response is OK, etc. */
1091 case DNS_RCODE_NO_ERROR:
1094 case DNS_RCODE_NAME_ERROR:
1095 case DNS_RCODE_FORMAT_ERROR:
1096 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1098 case DNS_RCODE_SERVER_FAILURE:
1099 case DNS_RCODE_NOT_IMPLEMENTED:
1100 case DNS_RCODE_REFUSED:
1101 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1104 /* No answers? Loser... */
1105 if (clib_net_to_host_u16 (h->anscount) < 1)
1106 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1108 curpos = (u8 *) (h + 1);
1110 /* Skip the name we asked about */
1113 /* Should never happen, but stil... */
1114 if ((len & 0xC0) == 0xC0)
1118 /* skip the name / label-set */
1127 limit = clib_net_to_host_u16 (h->qdcount);
1128 qp = (dns_query_t *) curpos;
1133 limit = clib_net_to_host_u16 (h->anscount);
1135 for (i = 0; i < limit; i++)
1139 /* Expect pointer chases in the answer section... */
1140 if ((pos[0] & 0xC0) == 0xC0)
1147 if ((pos[0] & 0xC0) == 0xC0)
1159 rr = (dns_rr_t *) curpos;
1161 switch (clib_net_to_host_u16 (rr->type))
1164 /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1165 memcpy (rmp->ip4_address, rr->rdata, sizeof (ip4_address_t));
1167 ttl = clib_net_to_host_u32 (rr->ttl);
1168 if (min_ttlp && *min_ttlp > ttl)
1172 /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1173 memcpy (rmp->ip6_address, rr->rdata, sizeof (ip6_address_t));
1174 ttl = clib_net_to_host_u32 (rr->ttl);
1175 if (min_ttlp && *min_ttlp > ttl)
1182 /* Might as well stop ASAP */
1183 if (rmp->ip4_set && rmp->ip6_set)
1185 curpos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1188 if ((rmp->ip4_set + rmp->ip6_set) == 0)
1189 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1194 vnet_dns_response_to_name (u8 * response,
1195 vl_api_dns_resolve_ip_reply_t * rmp,
1208 u8 *junk __attribute__ ((unused));
1211 h = (dns_header_t *) response;
1212 flags = clib_net_to_host_u16 (h->flags);
1213 rcode = flags & DNS_RCODE_MASK;
1215 /* See if the response is OK, etc. */
1219 case DNS_RCODE_NO_ERROR:
1222 case DNS_RCODE_NAME_ERROR:
1223 case DNS_RCODE_FORMAT_ERROR:
1224 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1226 case DNS_RCODE_SERVER_FAILURE:
1227 case DNS_RCODE_NOT_IMPLEMENTED:
1228 case DNS_RCODE_REFUSED:
1229 return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1232 /* No answers? Loser... */
1233 if (clib_net_to_host_u16 (h->anscount) < 1)
1234 return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1236 curpos = (u8 *) (h + 1);
1238 /* Skip the name we asked about */
1241 /* Should never happen, but stil... */
1242 if ((len & 0xC0) == 0xC0)
1246 /* skip the name / label-set */
1255 limit = clib_net_to_host_u16 (h->qdcount);
1256 qp = (dns_query_t *) curpos;
1261 limit = clib_net_to_host_u16 (h->anscount);
1263 for (i = 0; i < limit; i++)
1267 /* Expect pointer chases in the answer section... */
1268 if ((pos[0] & 0xC0) == 0xC0)
1275 if ((pos[0] & 0xC0) == 0xC0)
1287 rr = (dns_rr_t *) curpos;
1289 switch (clib_net_to_host_u16 (rr->type))
1292 name = vnet_dns_labels_to_name (rr->rdata, response, &junk);
1293 memcpy (rmp->name, name, vec_len (name));
1294 ttl = clib_net_to_host_u32 (rr->ttl);
1297 rmp->name[vec_len (name)] = 0;
1303 /* Might as well stop ASAP */
1306 curpos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1310 return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1315 vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1317 dns_main_t *dm = &dns_main;
1318 vl_api_dns_resolve_name_reply_t *rmp;
1319 dns_cache_entry_t *ep;
1320 dns_pending_request_t _t0, *t0 = &_t0;
1323 /* Sanitize the name slightly */
1324 mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1326 t0->request_type = DNS_API_PENDING_NAME_TO_IP;
1327 t0->client_index = mp->client_index;
1328 t0->client_context = mp->context;
1330 rv = vnet_dns_resolve_name (dm, mp->name, t0, &ep);
1332 /* Error, e.g. not enabled? Tell the user */
1335 REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1339 /* Resolution pending? Don't reply... */
1344 REPLY_MACRO2(VL_API_DNS_RESOLVE_NAME_REPLY,
1346 rv = vnet_dns_response_to_reply (ep->dns_response, rmp, 0 /* ttl-ptr */);
1347 rmp->retval = clib_host_to_net_u32 (rv);
1352 * dns_resolve_name leaves the cache locked when it returns
1353 * a cached result, so unlock it here.
1355 dns_cache_unlock (dm);
1359 vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
1361 dns_main_t *dm = &dns_main;
1362 vl_api_dns_resolve_ip_reply_t *rmp;
1363 dns_cache_entry_t *ep;
1366 u8 *lookup_name = 0;
1368 dns_pending_request_t _t0, *t0 = &_t0;
1372 for (i = 15; i >= 0; i--)
1374 digit = mp->address[i];
1375 nybble = (digit & 0x0F);
1377 vec_add1 (lookup_name, (nybble - 10) + 'a');
1379 vec_add1 (lookup_name, nybble + '0');
1380 vec_add1 (lookup_name, '.');
1381 nybble = (digit & 0xF0) >> 4;
1383 vec_add1 (lookup_name, (nybble - 10) + 'a');
1385 vec_add1 (lookup_name, nybble + '0');
1386 vec_add1 (lookup_name, '.');
1388 len = vec_len (lookup_name);
1389 vec_validate (lookup_name, len + 8);
1390 memcpy (lookup_name + len, "ip6.arpa", 8);
1394 for (i = 3; i >= 0; i--)
1396 digit = mp->address[i];
1397 lookup_name = format (lookup_name, "%d.", digit);
1399 lookup_name = format (lookup_name, "in-addr.arpa");
1402 vec_add1 (lookup_name, 0);
1404 t0->request_type = DNS_API_PENDING_IP_TO_NAME;
1405 t0->client_index = mp->client_index;
1406 t0->client_context = mp->context;
1408 rv = vnet_dns_resolve_name (dm, lookup_name, t0, &ep);
1410 vec_free (lookup_name);
1412 /* Error, e.g. not enabled? Tell the user */
1415 REPLY_MACRO (VL_API_DNS_RESOLVE_IP_REPLY);
1419 /* Resolution pending? Don't reply... */
1424 REPLY_MACRO2(VL_API_DNS_RESOLVE_IP_REPLY,
1426 rv = vnet_dns_response_to_name (ep->dns_response, rmp, 0 /* ttl-ptr */);
1427 rmp->retval = clib_host_to_net_u32 (rv);
1432 * vnet_dns_resolve_name leaves the cache locked when it returns
1433 * a cached result, so unlock it here.
1435 dns_cache_unlock (dm);
1438 #define vl_msg_name_crc_list
1439 #include <vpp/api/vpe_all_api_h.h>
1440 #undef vl_msg_name_crc_list
1443 setup_message_id_table (api_main_t * am)
1445 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1446 foreach_vl_msg_name_crc_dns;
1450 #define foreach_dns_api_msg \
1451 _(DNS_ENABLE_DISABLE, dns_enable_disable) \
1452 _(DNS_NAME_SERVER_ADD_DEL, dns_name_server_add_del) \
1453 _(DNS_RESOLVE_NAME, dns_resolve_name) \
1454 _(DNS_RESOLVE_IP, dns_resolve_ip)
1456 static clib_error_t *
1457 dns_api_hookup (vlib_main_t * vm)
1460 vl_msg_api_set_handlers(VL_API_##N, #n, \
1461 vl_api_##n##_t_handler, \
1463 vl_api_##n##_t_endian, \
1464 vl_api_##n##_t_print, \
1465 sizeof(vl_api_##n##_t), 1);
1466 foreach_dns_api_msg;
1469 setup_message_id_table (&api_main);
1473 VLIB_API_INIT_FUNCTION (dns_api_hookup);
1476 static clib_error_t *
1477 dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1479 dns_main_t *dm = &dns_main;
1481 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1483 if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1485 else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1488 return clib_error_return (0, "unknown input `%U'",
1489 format_unformat_error, input);
1494 VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1496 static clib_error_t *
1497 dns_init (vlib_main_t * vm)
1499 dns_main_t *dm = &dns_main;
1502 dm->vnet_main = vnet_get_main ();
1503 dm->name_cache_size = 65535;
1504 dm->max_ttl_in_seconds = 86400;
1505 dm->random_seed = 0xDEADDABE;
1507 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply, dns46_reply_node.index,
1510 udp_register_dst_port (vm, UDP_DST_PORT_dns_reply6, dns46_reply_node.index,
1513 udp_register_dst_port (vm, UDP_DST_PORT_dns, dns4_request_node.index,
1516 udp_register_dst_port (vm, UDP_DST_PORT_dns6, dns6_request_node.index,
1521 VLIB_INIT_FUNCTION (dns_init);
1524 unformat_dns_reply (unformat_input_t * input, va_list * args)
1526 u8 **result = va_arg (*args, u8 **);
1527 u8 **namep = va_arg (*args, u8 **);
1541 if (unformat (input, "%v", &name))
1544 if (unformat (input, "%U", unformat_ip4_address, &a4))
1547 if (unformat (input, "%U", unformat_ip6_address, &a6))
1551 if (unformat (input, "%U", unformat_ip6_address, &a6))
1554 if (unformat (input, "%U", unformat_ip4_address, &a6))
1558 /* Must have a name */
1562 /* Must have at least one address */
1563 if (!(a4_set + a6_set))
1566 /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1567 ce = name_to_labels (name);
1568 qp_offset = vec_len (ce);
1570 /* Add space for the query header */
1571 vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1572 qp = (dns_query_t *) (ce + qp_offset);
1574 qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1575 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1577 /* Punch in space for the dns_header_t */
1578 vec_insert (ce, sizeof (dns_header_t), 0);
1580 h = (dns_header_t *) ce;
1582 /* Fake Transaction ID */
1585 h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1586 h->qdcount = clib_host_to_net_u16 (1);
1587 h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1591 /* Now append one or two A/AAAA RR's... */
1594 /* Pointer to the name (DGMS) */
1595 vec_add1 (ce, 0xC0);
1596 vec_add1 (ce, 0x0C);
1597 vec_add2 (ce, rru8, sizeof (*rr) + 4);
1599 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1600 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1601 rr->ttl = clib_host_to_net_u32 (86400);
1602 rr->rdlength = clib_host_to_net_u16 (4);
1603 memcpy (rr->rdata, &a4, sizeof (a4));
1607 /* Pointer to the name (DGMS) */
1608 vec_add1 (ce, 0xC0);
1609 vec_add1 (ce, 0x0C);
1610 vec_add2 (ce, rru8, sizeof (*rr) + 16);
1612 rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1613 rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1614 rr->ttl = clib_host_to_net_u32 (86400);
1615 rr->rdlength = clib_host_to_net_u16 (16);
1616 memcpy (rr->rdata, &a6, sizeof (a6));
1628 format_dns_query (u8 * s, va_list * args)
1630 u8 **curpos = va_arg (*args, u8 **);
1631 int verbose = va_arg (*args, int);
1636 s = format (s, " Name: ");
1638 /* Unwind execrated counted-label sheit */
1644 for (i = 0; i < len; i++)
1645 vec_add1 (s, *pos++);
1657 qp = (dns_query_t *) pos;
1660 switch (clib_net_to_host_u16 (qp->type))
1663 s = format (s, "type A\n");
1666 s = format (s, "type AAAA\n");
1669 s = format (s, "type ALL\n");
1673 s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1678 pos += sizeof (*qp);
1685 * format dns reply data
1686 * verbose > 1, dump everything
1687 * verbose == 1, dump all A and AAAA records
1688 * verbose == 0, dump one A record, and one AAAA record
1692 format_dns_reply_data (u8 * s, va_list * args)
1694 u8 *reply = va_arg (*args, u8 *);
1695 u8 **curpos = va_arg (*args, u8 **);
1696 int verbose = va_arg (*args, int);
1697 int *print_ip4 = va_arg (*args, int *);
1698 int *print_ip6 = va_arg (*args, int *);
1703 int initial_pointer_chase = 0;
1705 u16 rrtype_host_byte_order;
1707 pos = pos2 = *curpos;
1710 s = format (s, " ");
1712 /* chase pointer? almost always yes here... */
1713 if (pos2[0] == 0xc0)
1715 pos2 = reply + pos2[1];
1717 initial_pointer_chase = 1;
1724 for (i = 0; i < len; i++)
1727 vec_add1 (s, *pos2);
1743 if (initial_pointer_chase == 0)
1746 rr = (dns_rr_t *) pos;
1747 rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
1749 switch (rrtype_host_byte_order)
1754 s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1755 format_ip4_address, rr->rdata);
1760 s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1761 clib_net_to_host_u32 (rr->ttl));
1766 pos += sizeof (*rr) + 4;
1772 s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1773 format_ip6_address, rr->rdata);
1778 s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1779 clib_net_to_host_u32 (rr->ttl));
1783 pos += sizeof (*rr) + 16;
1789 s = format (s, "TEXT: ");
1790 for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1791 vec_add1 (s, rr->rdata[i]);
1794 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1797 case DNS_TYPE_HINFO:
1799 /* Two counted strings. DGMS */
1805 s = format (s, "HINFO: ");
1808 for (i = 0; i < *len; i++)
1809 vec_add1 (s, *curpos++);
1813 for (i = 0; i < *len; i++)
1814 vec_add1 (s, *curpos++);
1819 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1822 case DNS_TYPE_NAMESERVER:
1825 s = format (s, "Nameserver: ");
1828 /* chase pointer? */
1829 if (pos2[0] == 0xc0)
1830 pos2 = reply + pos2[1];
1836 for (i = 0; i < len; i++)
1837 vec_add1 (s, *pos2++);
1839 /* chase pointer, typically to offset 12... */
1840 if (pos2[0] == 0xC0)
1841 pos2 = reply + pos2[1];
1850 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1853 case DNS_TYPE_MAIL_EXCHANGE:
1856 tp = (u16 *) rr->rdata;
1858 s = format (s, "Mail Exchange: Preference %d ", (u32)
1859 clib_net_to_host_u16 (*tp));
1861 pos2 = rr->rdata + 2;
1863 /* chase pointer? */
1864 if (pos2[0] == 0xc0)
1865 pos2 = reply + pos2[1];
1871 for (i = 0; i < len; i++)
1872 vec_add1 (s, *pos2++);
1875 if (pos2[0] == 0xC0)
1876 pos2 = reply + pos2[1];
1886 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1890 case DNS_TYPE_CNAME:
1893 tp = (u16 *) rr->rdata;
1895 if (rrtype_host_byte_order == DNS_TYPE_CNAME)
1896 s = format (s, "CNAME: ");
1898 s = format (s, "PTR: ");
1902 /* chase pointer? */
1903 if (pos2[0] == 0xc0)
1904 pos2 = reply + pos2[1];
1910 for (i = 0; i < len; i++)
1911 vec_add1 (s, *pos2++);
1914 if (pos2[0] == 0xC0)
1915 pos2 = reply + pos2[1];
1924 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1929 s = format (s, "type %d: len %d\n",
1930 (int) clib_net_to_host_u16 (rr->type),
1931 sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
1932 pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1942 format_dns_reply (u8 * s, va_list * args)
1944 u8 *reply_as_u8 = va_arg (*args, u8 *);
1945 int verbose = va_arg (*args, int);
1953 h = (dns_header_t *) reply_as_u8;
1954 id = clib_net_to_host_u16 (h->id);
1955 flags = clib_net_to_host_u16 (h->flags);
1959 s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
1961 s = format (s, " %s %s %s %s\n",
1962 (flags & DNS_RA) ? "recur" : "no-recur",
1963 (flags & DNS_RD) ? "recur-des" : "no-recur-des",
1964 (flags & DNS_TC) ? "trunc" : "no-trunc",
1965 (flags & DNS_AA) ? "auth" : "non-auth");
1966 s = format (s, " %d queries, %d answers, %d name-servers,"
1968 clib_net_to_host_u16 (h->qdcount),
1969 clib_net_to_host_u16 (h->anscount),
1970 clib_net_to_host_u16 (h->nscount),
1971 clib_net_to_host_u16 (h->arcount));
1974 curpos = (u8 *) (h + 1);
1979 s = format (s, " Queries:\n");
1980 for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
1982 /* The query is variable-length, so curpos is a value-result parm */
1983 s = format (s, "%U", format_dns_query, &curpos, verbose);
1989 s = format (s, " Replies:\n");
1991 for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
1993 /* curpos is a value-result parm */
1994 s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
1995 verbose, &print_ip4, &print_ip6);
2002 format_dns_cache (u8 * s, va_list * args)
2004 dns_main_t *dm = va_arg (*args, dns_main_t *);
2005 f64 now = va_arg (*args, f64);
2006 int verbose = va_arg (*args, int);
2007 u8 *name = va_arg (*args, u8 *);
2008 dns_cache_entry_t *ep;
2012 if (dm->is_enabled == 0)
2014 s = format (s, "The DNS cache is disabled...");
2018 if (pool_elts (dm->entries) == 0)
2020 s = format (s, "The DNS cache is empty...");
2024 dns_cache_lock (dm);
2028 p = hash_get_mem (dm->cache_entry_by_name, name);
2031 s = format (s, "%s is not in the cache...", name);
2032 dns_cache_unlock (dm);
2036 ep = pool_elt_at_index (dm->entries, p[0]);
2037 /* Magic to spit out a C-initializer to research hemorrhoids... */
2041 s = format (s, "static u8 dns_reply_data_initializer[] =\n");
2042 s = format (s, "{\n");
2044 for (i = 0; i < vec_len (ep->dns_response); i++)
2051 s = format (s, "0x%02x, ", ep->dns_response[i]);
2053 s = format (s, "};\n");
2057 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2059 ASSERT (ep->dns_response);
2060 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2065 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2066 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2068 s = format (s, "%s%s -> %U", ss, ep->name,
2069 format_dns_reply, ep->dns_response, verbose);
2070 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2072 f64 time_left = ep->expiration_time - now;
2073 if (time_left > 0.0)
2074 s = format (s, " TTL left %.1f", time_left);
2076 s = format (s, " EXPIRED");
2081 ASSERT (ep->dns_request);
2082 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2091 pool_foreach (ep, dm->entries,
2093 if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2095 ASSERT (ep->dns_response);
2096 if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2101 if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2102 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2104 s = format (s, "%s%s -> %U", ss, ep->name,
2108 if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2110 f64 time_left = ep->expiration_time - now;
2111 if (time_left > 0.0)
2112 s = format (s, " TTL left %.1f", time_left);
2114 s = format (s, " EXPIRED");
2117 s = format (s, " %d client notifications pending\n",
2118 vec_len(ep->pending_requests));
2123 ASSERT (ep->dns_request);
2124 s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2131 dns_cache_unlock (dm);
2136 static clib_error_t *
2137 show_dns_cache_command_fn (vlib_main_t * vm,
2138 unformat_input_t * input, vlib_cli_command_t * cmd)
2140 dns_main_t *dm = &dns_main;
2143 f64 now = vlib_time_now (vm);
2145 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2147 if (unformat (input, "verbose %d", &verbose))
2149 else if (unformat (input, "verbose"))
2151 else if (unformat (input, "name %s", &name))
2154 return clib_error_return (0, "unknown input `%U'",
2155 format_unformat_error, input);
2158 vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
2164 VLIB_CLI_COMMAND (show_dns_cache_command) =
2166 .path = "show dns cache",
2167 .short_help = "show dns cache [verbose [nn]]",
2168 .function = show_dns_cache_command_fn,
2172 static clib_error_t *
2173 dns_cache_add_del_command_fn (vlib_main_t * vm,
2174 unformat_input_t * input,
2175 vlib_cli_command_t * cmd)
2177 dns_main_t *dm = &dns_main;
2183 clib_error_t *error;
2185 if (unformat (input, "add"))
2187 if (unformat (input, "del"))
2189 if (unformat (input, "clear"))
2192 if (is_add == -1 && is_clear == -1)
2193 return clib_error_return (0, "add / del / clear required...");
2197 rv = dns_cache_clear (dm);
2203 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2204 error = clib_error_return (0, "Name resolution not enabled");
2209 /* Delete (by name)? */
2212 if (unformat (input, "%v", &name))
2214 rv = dns_delete_by_name (dm, name);
2217 case VNET_API_ERROR_NO_SUCH_ENTRY:
2218 error = clib_error_return (0, "%v not in the cache...", name);
2222 case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2223 error = clib_error_return (0, "Name resolution not enabled");
2232 error = clib_error_return (0, "dns_delete_by_name returned %d",
2238 return clib_error_return (0, "unknown input `%U'",
2239 format_unformat_error, input);
2242 /* Note: dns_add_static_entry consumes the name vector if OK... */
2243 if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2245 rv = dns_add_static_entry (dm, name, dns_reply_data);
2248 case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2250 vec_free (dns_reply_data);
2251 return clib_error_return (0, "%v already in the cache...", name);
2256 return clib_error_return (0, "dns_add_static_entry returned %d",
2265 VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2267 .path = "dns cache",
2268 .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2269 .function = dns_cache_add_del_command_fn,
2273 #define DNS_FORMAT_TEST 1
2275 #if DNS_FORMAT_TEST > 0
2278 static u8 dns_reply_data_initializer[] =
2279 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2280 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2282 0x0, 0xff, /* type ALL */
2283 0x0, 0x1, /* class IN */
2284 0xc0, 0xc, /* pointer to yahoo.com name */
2285 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2286 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2287 0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2288 0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2289 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2290 0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2291 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2292 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2293 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2294 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2295 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2296 0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2297 0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2299 0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2300 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2301 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2302 0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2303 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2305 0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2306 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2307 0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2308 0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2310 0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2311 0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2313 0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2315 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2317 0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2319 0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2320 0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2321 0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2325 /* www.cisco.com, has no addresses in reply */
2326 static u8 dns_reply_data_initializer[] = {
2327 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2328 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2329 0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2331 0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2332 0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2333 0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2334 0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2335 0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2339 static u8 dns_reply_data_initializer[] =
2340 { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
2341 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
2342 0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
2343 0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
2345 0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
2346 0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
2347 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
2348 0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
2349 0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
2350 0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
2351 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
2352 0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
2353 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
2354 0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
2355 0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
2356 0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
2357 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
2358 0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
2359 0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
2360 0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
2361 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2362 0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
2363 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
2364 0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
2365 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
2366 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
2367 0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
2369 0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2373 static clib_error_t *
2374 test_dns_fmt_command_fn (vlib_main_t * vm,
2375 unformat_input_t * input, vlib_cli_command_t * cmd)
2377 u8 *dns_reply_data = 0;
2380 vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2382 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2384 if (unformat (input, "verbose %d", &verbose))
2386 else if (unformat (input, "verbose"))
2389 return clib_error_return (0, "unknown input `%U'",
2390 format_unformat_error, input);
2393 vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2395 memcpy (dns_reply_data, dns_reply_data_initializer,
2396 ARRAY_LEN (dns_reply_data_initializer));
2398 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2400 memset (rmp, 0, sizeof (*rmp));
2402 rv = vnet_dns_response_to_reply (dns_reply_data, rmp, 0 /* ttl-ptr */ );
2406 case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2407 vlib_cli_output (vm, "no addresses found...");
2411 vlib_cli_output (vm, "response to reply returned %d", rv);
2416 vlib_cli_output (vm, "ip4 address: %U", format_ip4_address,
2417 (ip4_address_t *) rmp->ip4_address);
2419 vlib_cli_output (vm, "ip6 address: %U", format_ip6_address,
2420 (ip6_address_t *) rmp->ip6_address);
2424 vec_free (dns_reply_data);
2431 VLIB_CLI_COMMAND (test_dns_fmt_command) =
2433 .path = "test dns format",
2434 .short_help = "test dns format",
2435 .function = test_dns_fmt_command_fn,
2439 static clib_error_t *
2440 test_dns_unfmt_command_fn (vlib_main_t * vm,
2441 unformat_input_t * input, vlib_cli_command_t * cmd)
2443 u8 *dns_reply_data = 0;
2447 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2449 if (unformat (input, "verbose %d", &verbose))
2451 else if (unformat (input, "verbose"))
2453 else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2456 return clib_error_return (0, "unknown input `%U'",
2457 format_unformat_error, input);
2461 return clib_error_return (0, "dns data not set...");
2463 vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2465 vec_free (dns_reply_data);
2471 VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2473 .path = "test dns unformat",
2474 .short_help = "test dns unformat <name> [ip4][ip6]",
2475 .function = test_dns_unfmt_command_fn,
2479 static clib_error_t *
2480 test_dns_expire_command_fn (vlib_main_t * vm,
2481 unformat_input_t * input,
2482 vlib_cli_command_t * cmd)
2484 dns_main_t *dm = &dns_main;
2488 dns_cache_entry_t *ep;
2490 if (unformat (input, "%v", &name))
2493 _vec_len (name) -= 1;
2496 dns_cache_lock (dm);
2498 p = hash_get_mem (dm->cache_entry_by_name, name);
2501 dns_cache_unlock (dm);
2502 e = clib_error_return (0, "%s is not in the cache...", name);
2507 ep = pool_elt_at_index (dm->entries, p[0]);
2509 ep->expiration_time = 0;
2515 VLIB_CLI_COMMAND (test_dns_expire_command) =
2517 .path = "test dns expire",
2518 .short_help = "test dns expire <name>",
2519 .function = test_dns_expire_command_fn,
2525 vnet_send_dns6_reply (dns_main_t * dm, dns_pending_request_t * pr,
2526 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2528 clib_warning ("Unimplemented...");
2533 vnet_send_dns4_reply (dns_main_t * dm, dns_pending_request_t * pr,
2534 dns_cache_entry_t * ep, vlib_buffer_t * b0)
2536 vlib_main_t *vm = dm->vlib_main;
2538 fib_prefix_t prefix;
2539 fib_node_index_t fei;
2540 u32 sw_if_index, fib_index;
2541 ip4_main_t *im4 = &ip4_main;
2542 ip_lookup_main_t *lm4 = &im4->lookup_main;
2543 ip_interface_address_t *ia = 0;
2544 ip4_address_t *src_address;
2552 vl_api_dns_resolve_name_reply_t _rnr, *rnr = &_rnr;
2553 vl_api_dns_resolve_ip_reply_t _rir, *rir = &_rir;
2561 ASSERT (ep && ep->dns_response);
2563 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2565 /* Quick and dirty way to dig up the A-record address. $$ FIXME */
2566 memset (rnr, 0, sizeof (*rnr));
2567 if (vnet_dns_response_to_reply (ep->dns_response, rnr, &ttl))
2569 /* clib_warning ("response_to_reply failed..."); */
2572 if (rnr->ip4_set == 0)
2574 /* clib_warning ("No A-record..."); */
2578 else if (pr->request_type == DNS_PEER_PENDING_IP_TO_NAME)
2580 memset (rir, 0, sizeof (*rir));
2581 if (vnet_dns_response_to_name (ep->dns_response, rir, &ttl))
2583 /* clib_warning ("response_to_name failed..."); */
2589 clib_warning ("Unknown request type %d", pr->request_type);
2593 /* Initialize a buffer */
2596 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2598 b0 = vlib_get_buffer (vm, bi);
2601 if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
2602 vlib_buffer_free_one (vm, b0->next_buffer);
2605 * Reset the buffer. We recycle the DNS request packet in the cache
2606 * hit case, and reply immediately from the request node.
2608 * In the resolution-required / deferred case, resetting a freshly-allocated
2609 * buffer won't hurt. We hope.
2611 b0->flags &= VLIB_BUFFER_FREE_LIST_INDEX_MASK;
2612 b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
2613 | VLIB_BUFFER_TOTAL_LENGTH_VALID);
2614 b0->current_data = 0;
2615 b0->current_length = 0;
2616 b0->total_length_not_including_first_buffer = 0;
2617 vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; /* "local0" */
2618 vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0; /* default VRF for now */
2620 /* Find a FIB path to the peer we're trying to answer */
2621 clib_memcpy (&prefix.fp_addr.ip4, pr->dst_address, sizeof (ip4_address_t));
2622 prefix.fp_proto = FIB_PROTOCOL_IP4;
2625 fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
2626 if (fib_index == (u32) ~ 0)
2628 clib_warning ("no fib table");
2632 fei = fib_table_lookup (fib_index, &prefix);
2634 /* Couldn't find route to destination. Bail out. */
2635 if (fei == FIB_NODE_INDEX_INVALID)
2637 clib_warning ("no route to DNS server");
2641 sw_if_index = fib_entry_get_resolving_interface (fei);
2643 if (sw_if_index == ~0)
2646 ("route to %U exists, fei %d, get_resolving_interface returned"
2647 " ~0", fei, format_ip4_address, &prefix.fp_addr);
2652 foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnummbered */,
2654 src_address = ip_interface_address_get_address (lm4, ia);
2655 goto found_src_address;
2659 clib_warning ("FIB BUG");
2664 ip = vlib_buffer_get_current (b0);
2665 udp = (udp_header_t *) (ip + 1);
2666 dns_response = (u8 *) (udp + 1);
2667 memset (ip, 0, sizeof (*ip) + sizeof (*udp));
2670 * Start with the variadic portion of the exercise.
2671 * Turn the name into a set of DNS "labels". Max length
2672 * per label is 63, enforce that.
2674 reply = name_to_labels (pr->name);
2675 vec_free (pr->name);
2677 qp_offset = vec_len (reply);
2679 /* Add space for the query header */
2680 vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
2682 qp = (dns_query_t *) (reply + qp_offset);
2684 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2685 qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
2687 qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2689 qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
2691 /* Punch in space for the dns_header_t */
2692 vec_insert (reply, sizeof (dns_header_t), 0);
2694 dh = (dns_header_t *) reply;
2696 /* Transaction ID = pool index */
2699 /* Announce that we did a recursive lookup */
2700 tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
2702 tmp |= DNS_RCODE_NAME_ERROR;
2703 dh->flags = clib_host_to_net_u16 (tmp);
2704 dh->qdcount = clib_host_to_net_u16 (1);
2705 dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
2709 /* If the name resolution worked, cough up an appropriate RR */
2712 /* Add the answer. First, a name pointer (0xC00C) */
2713 vec_add1 (reply, 0xC0);
2714 vec_add1 (reply, 0x0C);
2716 /* Now, add single A-rec RR */
2717 if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2719 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
2720 rr = (dns_rr_t *) rrptr;
2722 rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
2723 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2724 rr->ttl = clib_host_to_net_u32 (ttl);
2725 rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
2726 clib_memcpy (rr->rdata, rnr->ip4_address, sizeof (ip4_address_t));
2730 /* Or a single PTR RR */
2731 u8 *vecname = format (0, "%s", rir->name);
2732 u8 *label_vec = name_to_labels (vecname);
2735 vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
2736 rr = (dns_rr_t *) rrptr;
2737 rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2738 rr->class = clib_host_to_net_u16 (1 /* internet */ );
2739 rr->ttl = clib_host_to_net_u32 (ttl);
2740 rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
2741 clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
2742 vec_free (label_vec);
2745 clib_memcpy (dns_response, reply, vec_len (reply));
2747 /* Set the packet length */
2748 b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
2751 ip->ip_version_and_header_length = 0x45;
2752 ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
2754 ip->protocol = IP_PROTOCOL_UDP;
2755 ip->src_address.as_u32 = src_address->as_u32;
2756 clib_memcpy (ip->dst_address.as_u8, pr->dst_address,
2757 sizeof (ip4_address_t));
2758 ip->checksum = ip4_header_checksum (ip);
2761 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
2762 udp->dst_port = pr->dst_port;
2763 udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
2768 /* Ship it to ip4_lookup */
2769 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
2770 to_next = vlib_frame_vector_args (f);
2773 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
2777 * fd.io coding-style-patch-verification: ON
2780 * eval: (c-set-style "gnu")