dns: keep AddressSanitizer happy
[vpp.git] / src / plugins / dns / dns.c
1 /*
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:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
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.
14  */
15
16 #include <vnet/vnet.h>
17 #include <vnet/udp/udp_local.h>
18 #include <vnet/plugin/plugin.h>
19 #include <dns/dns.h>
20 #include <vnet/ip/ip_sas.h>
21 #include <vlibapi/api.h>
22 #include <vlibmemory/api.h>
23 #include <vpp/app/version.h>
24 #include <stdbool.h>
25
26 /* define message IDs */
27 #include <dns/dns.api_enum.h>
28 #include <dns/dns.api_types.h>
29
30 #define REPLY_MSG_ID_BASE dm->msg_id_base
31 #include <vlibapi/api_helper_macros.h>
32
33 #define FINISH                                                                \
34   vec_add1 (s, 0);                                                            \
35   vlib_cli_output (handle, (char *) s);                                       \
36   vec_free (s);                                                               \
37   return handle;
38
39 dns_main_t dns_main;
40
41 /* the cache hashtable expects a NULL-terminated C-string but everywhere else
42  * expects a non-NULL terminated vector... The pattern of adding \0 but hiding
43  * it away drives AddressSanitizer crazy, this helper tries to bring some of
44  * its sanity back
45  */
46 static_always_inline void
47 dns_terminate_c_string (u8 **v)
48 {
49   vec_add1 (*v, 0);
50   vec_dec_len (*v, 1);
51   clib_mem_unpoison (vec_end (*v), 1);
52 }
53
54 static int
55 dns_cache_clear (dns_main_t * dm)
56 {
57   dns_cache_entry_t *ep;
58
59   if (dm->is_enabled == 0)
60     return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
61
62   dns_cache_lock (dm, 1);
63
64   /* *INDENT-OFF* */
65   pool_foreach (ep, dm->entries)
66    {
67     vec_free (ep->name);
68     vec_free (ep->pending_requests);
69   }
70   /* *INDENT-ON* */
71
72   pool_free (dm->entries);
73   hash_free (dm->cache_entry_by_name);
74   dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
75   vec_free (dm->unresolved_entries);
76   dns_cache_unlock (dm);
77   return 0;
78 }
79
80 static int
81 dns_enable_disable (vlib_main_t * vm, dns_main_t * dm, int is_enable)
82 {
83   vlib_thread_main_t *tm = &vlib_thread_main;
84   u32 n_vlib_mains = tm->n_vlib_mains;
85
86   /* Create the resolver process if not done already */
87   vnet_dns_create_resolver_process (vm, dm);
88
89   if (is_enable)
90     {
91       if (vec_len (dm->ip4_name_servers) == 0
92           && (vec_len (dm->ip6_name_servers) == 0))
93         return VNET_API_ERROR_NO_NAME_SERVERS;
94
95       if (dm->udp_ports_registered == 0)
96         {
97           udp_register_dst_port (vm, UDP_DST_PORT_dns_reply,
98                                  dns46_reply_node.index, 1 /* is_ip4 */ );
99
100           udp_register_dst_port (vm, UDP_DST_PORT_dns_reply6,
101                                  dns46_reply_node.index, 0 /* is_ip4 */ );
102
103           udp_register_dst_port (vm, UDP_DST_PORT_dns,
104                                  dns4_request_node.index, 1 /* is_ip4 */ );
105
106           udp_register_dst_port (vm, UDP_DST_PORT_dns6,
107                                  dns6_request_node.index, 0 /* is_ip4 */ );
108
109           dm->udp_ports_registered = 1;
110         }
111
112       if (dm->cache_entry_by_name == 0)
113         {
114           if (n_vlib_mains > 1)
115             clib_spinlock_init (&dm->cache_lock);
116
117           dm->cache_entry_by_name = hash_create_string (0, sizeof (uword));
118         }
119
120       dm->is_enabled = 1;
121     }
122   else
123     {
124       dns_cache_clear (dm);
125       dm->is_enabled = 0;
126     }
127   return 0;
128 }
129
130 static void vl_api_dns_enable_disable_t_handler
131   (vl_api_dns_enable_disable_t * mp)
132 {
133   vl_api_dns_enable_disable_reply_t *rmp;
134   vlib_main_t *vm = vlib_get_main ();
135   dns_main_t *dm = &dns_main;
136   int rv;
137
138   rv = dns_enable_disable (vm, dm, mp->enable);
139
140   REPLY_MACRO (VL_API_DNS_ENABLE_DISABLE_REPLY);
141 }
142
143 static int
144 dns6_name_server_add_del (dns_main_t * dm,
145                           u8 * server_address_as_u8, int is_add)
146 {
147   int i;
148   ip6_address_t *ap;
149
150   if (is_add)
151     {
152       /* Already there? done... */
153       for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
154         {
155           if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
156                        sizeof (ip6_address_t)))
157             return 0;
158         }
159
160       vec_add2 (dm->ip6_name_servers, ap, 1);
161       clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
162     }
163   else
164     {
165       for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
166         {
167           if (!memcmp (dm->ip6_name_servers + i, server_address_as_u8,
168                        sizeof (ip6_address_t)))
169             {
170               vec_delete (dm->ip6_name_servers, 1, i);
171               return 0;
172             }
173         }
174       return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
175     }
176   return 0;
177 }
178
179 static int
180 dns4_name_server_add_del (dns_main_t * dm,
181                           u8 * server_address_as_u8, int is_add)
182 {
183   int i;
184   ip4_address_t *ap;
185
186   if (is_add)
187     {
188       /* Already there? done... */
189       for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
190         {
191           if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
192                        sizeof (ip4_address_t)))
193             return 0;
194         }
195
196       vec_add2 (dm->ip4_name_servers, ap, 1);
197       clib_memcpy (ap, server_address_as_u8, sizeof (*ap));
198     }
199   else
200     {
201       for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
202         {
203           if (!memcmp (dm->ip4_name_servers + i, server_address_as_u8,
204                        sizeof (ip4_address_t)))
205             {
206               vec_delete (dm->ip4_name_servers, 1, i);
207               return 0;
208             }
209         }
210       return VNET_API_ERROR_NAME_SERVER_NOT_FOUND;
211     }
212   return 0;
213 }
214
215 static void vl_api_dns_name_server_add_del_t_handler
216   (vl_api_dns_name_server_add_del_t * mp)
217 {
218   dns_main_t *dm = &dns_main;
219   vl_api_dns_name_server_add_del_reply_t *rmp;
220   int rv;
221
222   if (mp->is_ip6)
223     rv = dns6_name_server_add_del (dm, mp->server_address, mp->is_add);
224   else
225     rv = dns4_name_server_add_del (dm, mp->server_address, mp->is_add);
226
227   REPLY_MACRO (VL_API_DNS_NAME_SERVER_ADD_DEL_REPLY);
228 }
229
230 void
231 vnet_dns_send_dns4_request (vlib_main_t * vm, dns_main_t * dm,
232                             dns_cache_entry_t * ep, ip4_address_t * server)
233 {
234   f64 now = vlib_time_now (vm);
235   u32 bi;
236   vlib_buffer_t *b;
237   ip4_header_t *ip;
238   udp_header_t *udp;
239   ip4_address_t src_address;
240   u8 *dns_request;
241   vlib_frame_t *f;
242   u32 *to_next;
243
244   ASSERT (ep->dns_request);
245
246   if (!ip4_sas (0 /* default VRF for now */, ~0, server, &src_address))
247     return;
248
249   /* Go get a buffer */
250   if (vlib_buffer_alloc (vm, &bi, 1) != 1)
251     return;
252
253   b = vlib_get_buffer (vm, bi);
254   b->current_length = sizeof (ip4_header_t) + sizeof (udp_header_t) +
255     vec_len (ep->dns_request);
256   b->total_length_not_including_first_buffer = 0;
257   b->flags =
258     VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
259   vnet_buffer (b)->sw_if_index[VLIB_RX] = 0;    /* "local0" */
260   vnet_buffer (b)->sw_if_index[VLIB_TX] = 0;    /* default VRF for now */
261
262   ip = vlib_buffer_get_current (b);
263   clib_memset (ip, 0, sizeof (*ip));
264   udp = (udp_header_t *) (ip + 1);
265   clib_memset (udp, 0, sizeof (*udp));
266
267   dns_request = (u8 *) (udp + 1);
268
269   /* IP header */
270   ip->ip_version_and_header_length = 0x45;
271   ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b));
272   ip->ttl = 255;
273   ip->protocol = IP_PROTOCOL_UDP;
274   ip->src_address.as_u32 = src_address.as_u32;
275   ip->dst_address.as_u32 = server->as_u32;
276   ip->checksum = ip4_header_checksum (ip);
277
278   /* UDP header */
279   udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
280   udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
281   udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
282                                       vec_len (ep->dns_request));
283   udp->checksum = 0;
284
285   /* The actual DNS request */
286   clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
287
288   /* Ship it to ip4_lookup */
289   f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
290   to_next = vlib_frame_vector_args (f);
291   to_next[0] = bi;
292   f->n_vectors = 1;
293   vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
294
295   ep->retry_timer = now + 2.0;
296 }
297
298 void
299 vnet_dns_send_dns6_request (vlib_main_t * vm, dns_main_t * dm,
300                             dns_cache_entry_t * ep, ip6_address_t * server)
301 {
302   f64 now = vlib_time_now (vm);
303   u32 bi;
304   vlib_buffer_t *b;
305   ip6_header_t *ip;
306   udp_header_t *udp;
307   ip6_address_t src_address;
308   u8 *dns_request;
309   vlib_frame_t *f;
310   u32 *to_next;
311   int junk __attribute__ ((unused));
312
313   ASSERT (ep->dns_request);
314
315   if (!ip6_sas (0 /* default VRF for now */, ~0, server, &src_address))
316     return;
317
318   /* Go get a buffer */
319   if (vlib_buffer_alloc (vm, &bi, 1) != 1)
320     return;
321
322   b = vlib_get_buffer (vm, bi);
323   b->current_length = sizeof (ip6_header_t) + sizeof (udp_header_t) +
324     vec_len (ep->dns_request);
325   b->total_length_not_including_first_buffer = 0;
326   b->flags =
327     VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_LOCALLY_ORIGINATED;
328
329   ip = vlib_buffer_get_current (b);
330   clib_memset (ip, 0, sizeof (*ip));
331   udp = (udp_header_t *) (ip + 1);
332   clib_memset (udp, 0, sizeof (*udp));
333
334   dns_request = (u8 *) (udp + 1);
335
336   /* IP header */
337   ip->ip_version_traffic_class_and_flow_label =
338     clib_host_to_net_u32 (0x6 << 28);
339
340   ip->payload_length =
341     clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b)
342                           - sizeof (ip6_header_t));
343   ip->hop_limit = 255;
344   ip->protocol = IP_PROTOCOL_UDP;
345   ip6_address_copy (&ip->src_address, &src_address);
346   clib_memcpy (&ip->dst_address, server, sizeof (ip6_address_t));
347
348   /* UDP header */
349   udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns_reply);
350   udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
351   udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
352                                       vec_len (ep->dns_request));
353   udp->checksum = 0;
354   udp->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ip, &junk);
355
356   /* The actual DNS request */
357   clib_memcpy (dns_request, ep->dns_request, vec_len (ep->dns_request));
358
359   /* Ship it to ip6_lookup */
360   f = vlib_get_frame_to_node (vm, ip6_lookup_node.index);
361   to_next = vlib_frame_vector_args (f);
362   to_next[0] = bi;
363   f->n_vectors = 1;
364
365   ep->retry_timer = now + 2.0;
366 }
367
368 /**
369  * Translate "foo.com" into "0x3 f o o 0x3 c o m 0x0"
370  * A historical / hysterical micro-TLV scheme. DGMS.
371  */
372 u8 *
373 name_to_labels (u8 * name)
374 {
375   int i;
376   int last_label_index;
377   u8 *rv;
378
379   rv = vec_dup (name);
380
381   /* punch in space for the first length */
382   vec_insert (rv, 1, 0);
383   last_label_index = 0;
384   i = 1;
385
386   while (i < vec_len (rv))
387     {
388       if (rv[i] == '.')
389         {
390           rv[last_label_index] = (i - last_label_index) - 1;
391           if ((i - last_label_index) > 63)
392             clib_warning ("stupid name, label length %d",
393                           i - last_label_index);
394           last_label_index = i;
395           rv[i] = 0;
396         }
397       i++;
398     }
399   /* Set the last real label length */
400   rv[last_label_index] = (i - last_label_index) - 1;
401
402   /*
403    * Add a [sic] NULL root label. Otherwise, the name parser can't figure out
404    * where to stop.
405    */
406   vec_add1 (rv, 0);
407   return rv;
408 }
409
410 /**
411  * arc-function for the above.
412  * Translate "0x3 f o o 0x3 c o m 0x0" into "foo.com"
413  * Produces a non-NULL-terminated u8 *vector. %v format is your friend.
414  */
415 u8 *
416 vnet_dns_labels_to_name (u8 * label, u8 * full_text, u8 ** parse_from_here)
417 {
418   u8 *reply = 0;
419   u16 offset;
420   u8 len;
421   int i;
422
423   *parse_from_here = 0;
424
425   /* chase initial pointer? */
426   if ((label[0] & 0xC0) == 0xC0)
427     {
428       *parse_from_here = label + 2;
429       offset = ((label[0] & 0x3f) << 8) + label[1];
430       label = full_text + offset;
431     }
432
433   len = *label++;
434
435   while (len)
436     {
437       for (i = 0; i < len; i++)
438         vec_add1 (reply, *label++);
439
440       /* chase pointer? */
441       if ((label[0] & 0xC0) == 0xC0)
442         {
443           *parse_from_here = label + 2;
444           offset = ((label[0] & 0x3f) << 8) + label[1];
445           label = full_text + offset;
446         }
447
448       len = *label++;
449       if (len)
450         vec_add1 (reply, '.');
451     }
452   if (*parse_from_here == 0)
453     *parse_from_here = label;
454   return reply;
455 }
456
457 void
458 vnet_send_dns_request (vlib_main_t * vm, dns_main_t * dm,
459                        dns_cache_entry_t * ep)
460 {
461   dns_header_t *h;
462   dns_query_t *qp;
463   u16 tmp;
464   u8 *request, *name_copy;
465   u32 qp_offset;
466
467   /* This can easily happen if sitting in GDB, etc. */
468   if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID || ep->server_fails > 1)
469     return;
470
471   /* Construct the dns request, if we haven't been here already */
472   if (vec_len (ep->dns_request) == 0)
473     {
474       /*
475        * Start with the variadic portion of the exercise.
476        * Turn the name into a set of DNS "labels". Max length
477        * per label is 63, enforce that.
478        */
479       request = name_to_labels (ep->name);
480       name_copy = vec_dup (request);
481       qp_offset = vec_len (request);
482
483       /*
484        * At least when testing against "known good" DNS servers:
485        * it turns out that sending 2x requests - one for an A-record
486        * and another for a AAAA-record - seems to work better than
487        * sending a DNS_TYPE_ALL request.
488        */
489
490       /* Add space for the query header */
491       vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
492
493       qp = (dns_query_t *) (request + qp_offset);
494
495       qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
496       qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
497       qp++;
498       clib_memcpy (qp, name_copy, vec_len (name_copy));
499       qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
500       vec_free (name_copy);
501
502       qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
503       qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
504
505       /* Punch in space for the dns_header_t */
506       vec_insert (request, sizeof (dns_header_t), 0);
507
508       h = (dns_header_t *) request;
509
510       /* Transaction ID = pool index */
511       h->id = clib_host_to_net_u16 (ep - dm->entries);
512
513       /* Ask for a recursive lookup */
514       tmp = DNS_RD | DNS_OPCODE_QUERY;
515       h->flags = clib_host_to_net_u16 (tmp);
516       h->qdcount = clib_host_to_net_u16 (2);
517       h->nscount = 0;
518       h->arcount = 0;
519
520       ep->dns_request = request;
521     }
522
523   /* Work out which server / address family we're going to use */
524
525   /* Retry using current server */
526   if (ep->retry_count++ < DNS_RETRIES_PER_SERVER)
527     {
528       if (ep->server_af == 1 /* ip6 */ )
529         {
530           if (vec_len (dm->ip6_name_servers))
531             {
532               vnet_dns_send_dns6_request
533                 (vm, dm, ep, dm->ip6_name_servers + ep->server_rotor);
534               goto out;
535             }
536           else
537             ep->server_af = 0;
538         }
539       if (vec_len (dm->ip4_name_servers))
540         {
541           vnet_dns_send_dns4_request
542             (vm, dm, ep, dm->ip4_name_servers + ep->server_rotor);
543           goto out;
544         }
545     }
546   else                          /* switch to a new server */
547     {
548       ep->retry_count = 1;
549       ep->server_rotor++;
550       if (ep->server_af == 1 /* ip6 */ )
551         {
552           if (ep->server_rotor >= vec_len (dm->ip6_name_servers))
553             {
554               ep->server_rotor = 0;
555               ep->server_af = vec_len (dm->ip4_name_servers) > 0 ? 0 : 1;
556             }
557         }
558       else
559         {
560           if (ep->server_rotor >= vec_len (dm->ip4_name_servers))
561             {
562               ep->server_rotor = 0;
563               ep->server_af = vec_len (dm->ip6_name_servers) > 0 ? 1 : 0;
564             }
565         }
566     }
567
568   if (ep->server_af == 1 /* ip6 */ )
569     vnet_dns_send_dns6_request
570       (vm, dm, ep, dm->ip6_name_servers + ep->server_rotor);
571   else
572     vnet_dns_send_dns4_request
573       (vm, dm, ep, dm->ip4_name_servers + ep->server_rotor);
574
575 out:
576
577   vlib_process_signal_event_mt (vm,
578                                 dm->resolver_process_node_index,
579                                 DNS_RESOLVER_EVENT_PENDING, 0);
580 }
581
582 int
583 vnet_dns_delete_entry_by_index_nolock (dns_main_t * dm, u32 index)
584 {
585   dns_cache_entry_t *ep;
586   int i;
587
588   if (dm->is_enabled == 0)
589     return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
590
591   if (pool_is_free_index (dm->entries, index))
592     return VNET_API_ERROR_NO_SUCH_ENTRY;
593
594   ep = pool_elt_at_index (dm->entries, index);
595   if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_VALID))
596     {
597       for (i = 0; i < vec_len (dm->unresolved_entries); i++)
598         if (index == dm->unresolved_entries[i])
599           {
600             vec_delete (dm->unresolved_entries, 1, i);
601             goto found;
602           }
603       clib_warning ("pool elt %d supposedly pending, but not found...",
604                     index);
605     }
606
607 found:
608   hash_unset_mem (dm->cache_entry_by_name, ep->name);
609   vec_free (ep->name);
610   vec_free (ep->pending_requests);
611   pool_put (dm->entries, ep);
612
613   return 0;
614 }
615
616 static int
617 dns_delete_by_name (dns_main_t * dm, u8 * name)
618 {
619   int rv;
620   uword *p;
621
622   if (dm->is_enabled == 0)
623     return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
624
625   dns_cache_lock (dm, 2);
626   p = hash_get_mem (dm->cache_entry_by_name, name);
627   if (!p)
628     {
629       dns_cache_unlock (dm);
630       return VNET_API_ERROR_NO_SUCH_ENTRY;
631     }
632   rv = vnet_dns_delete_entry_by_index_nolock (dm, p[0]);
633
634   dns_cache_unlock (dm);
635
636   return rv;
637 }
638
639 static int
640 delete_random_entry (dns_main_t * dm)
641 {
642   int rv;
643   u32 victim_index, start_index, i;
644   u32 limit;
645   dns_cache_entry_t *ep;
646
647   if (dm->is_enabled == 0)
648     return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
649
650   /*
651    * Silence spurious coverity warning. We know pool_elts >> 0, or
652    * we wouldn't be here...
653    */
654 #ifdef __COVERITY__
655   if (pool_elts (dm->entries) == 0)
656     return VNET_API_ERROR_UNSPECIFIED;
657 #endif
658
659   dns_cache_lock (dm, 3);
660   limit = pool_elts (dm->entries);
661   start_index = random_u32 (&dm->random_seed) % limit;
662
663   for (i = 0; i < limit; i++)
664     {
665       victim_index = (start_index + i) % limit;
666
667       if (!pool_is_free_index (dm->entries, victim_index))
668         {
669           ep = pool_elt_at_index (dm->entries, victim_index);
670           /* Delete only valid, non-static entries */
671           if ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
672               && ((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0))
673             {
674               rv = vnet_dns_delete_entry_by_index_nolock (dm, victim_index);
675               dns_cache_unlock (dm);
676               return rv;
677             }
678         }
679     }
680   dns_cache_unlock (dm);
681
682   clib_warning ("Couldn't find an entry to delete?");
683   return VNET_API_ERROR_UNSPECIFIED;
684 }
685
686 static int
687 dns_add_static_entry (dns_main_t * dm, u8 * name, u8 * dns_reply_data)
688 {
689   dns_cache_entry_t *ep;
690   uword *p;
691   int rv;
692
693   if (dm->is_enabled == 0)
694     return VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED;
695
696   dns_cache_lock (dm, 4);
697   p = hash_get_mem (dm->cache_entry_by_name, name);
698   if (p)
699     {
700       dns_cache_unlock (dm);
701       return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
702     }
703
704   if (pool_elts (dm->entries) == dm->name_cache_size)
705     {
706       /* Will only fail if the cache is totally filled w/ static entries... */
707       rv = delete_random_entry (dm);
708       if (rv)
709         {
710           dns_cache_unlock (dm);
711           return rv;
712         }
713     }
714
715   pool_get (dm->entries, ep);
716   clib_memset (ep, 0, sizeof (*ep));
717
718   /* Note: consumes the name vector */
719   ep->name = name;
720   /* make sure it NULL-terminated as hash_set_mem will use strlen() */
721   vec_terminate_c_string (ep->name);
722   hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
723   ep->flags = DNS_CACHE_ENTRY_FLAG_VALID | DNS_CACHE_ENTRY_FLAG_STATIC;
724   ep->dns_response = dns_reply_data;
725
726   dns_cache_unlock (dm);
727   return 0;
728 }
729
730 int
731 vnet_dns_resolve_name (vlib_main_t * vm, dns_main_t * dm, u8 * name,
732                        dns_pending_request_t * t, dns_cache_entry_t ** retp)
733 {
734   dns_cache_entry_t *ep;
735   int rv;
736   f64 now;
737   uword *p;
738   dns_pending_request_t *pr;
739   int count;
740
741   now = vlib_time_now (vm);
742
743   /* In case we can't actually answer the question right now... */
744   *retp = 0;
745
746   /* binary API caller might forget to set the name. Guess how we know. */
747   if (name[0] == 0)
748     return VNET_API_ERROR_INVALID_VALUE;
749
750   dns_cache_lock (dm, 5);
751 search_again:
752   p = hash_get_mem (dm->cache_entry_by_name, name);
753   if (p)
754     {
755       ep = pool_elt_at_index (dm->entries, p[0]);
756       if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
757         {
758           /* Has the entry expired? */
759           if (((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0)
760               && (now > ep->expiration_time))
761             {
762               int i;
763               u32 *indices_to_delete = 0;
764
765               /*
766                * Take out the rest of the resolution chain
767                * This isn't optimal, but it won't happen very often.
768                */
769               while (ep)
770                 {
771                   if ((ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME))
772                     {
773                       vec_add1 (indices_to_delete, ep - dm->entries);
774
775                       p = hash_get_mem (dm->cache_entry_by_name, ep->cname);
776                       if (!p)
777                         break;
778                       ep = pool_elt_at_index (dm->entries, p[0]);
779                     }
780                   else
781                     {
782                       vec_add1 (indices_to_delete, ep - dm->entries);
783                       break;
784                     }
785                 }
786               for (i = 0; i < vec_len (indices_to_delete); i++)
787                 {
788                   /* Reenable to watch re-resolutions */
789                   if (0)
790                     {
791                       ep = pool_elt_at_index (dm->entries,
792                                               indices_to_delete[i]);
793                       clib_warning ("Re-resolve %s", ep->name);
794                     }
795
796                   vnet_dns_delete_entry_by_index_nolock
797                     (dm, indices_to_delete[i]);
798                 }
799               vec_free (indices_to_delete);
800               /* Yes, kill it... */
801               goto re_resolve;
802             }
803
804           if (ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
805             {
806               name = ep->cname;
807               goto search_again;
808             }
809           *retp = ep;
810           dns_cache_unlock (dm);
811           return (0);
812         }
813       else
814         {
815           /*
816            * Resolution pending. Add request to the pending vector
817            * by copying the template request
818            */
819           vec_add2 (ep->pending_requests, pr, 1);
820           memcpy (pr, t, sizeof (*pr));
821           dns_cache_unlock (dm);
822           return (0);
823         }
824     }
825
826 re_resolve:
827   if (pool_elts (dm->entries) == dm->name_cache_size)
828     {
829       /* Will only fail if the cache is totally filled w/ static entries... */
830       rv = delete_random_entry (dm);
831       if (rv)
832         {
833           dns_cache_unlock (dm);
834           return rv;
835         }
836     }
837
838   /* add new hash table entry */
839   pool_get (dm->entries, ep);
840   clib_memset (ep, 0, sizeof (*ep));
841
842   ep->name = format (0, "%s", name);
843   dns_terminate_c_string (&ep->name);
844
845   hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
846
847   vec_add1 (dm->unresolved_entries, ep - dm->entries);
848   vec_add2 (ep->pending_requests, pr, 1);
849
850   pr->request_type = t->request_type;
851
852   /* Remember details so we can reply later... */
853   if (t->request_type == DNS_API_PENDING_NAME_TO_IP ||
854       t->request_type == DNS_API_PENDING_IP_TO_NAME)
855     {
856       pr->client_index = t->client_index;
857       pr->client_context = t->client_context;
858     }
859   else
860     {
861       pr->client_index = ~0;
862       pr->is_ip6 = t->is_ip6;
863       pr->dst_port = t->dst_port;
864       pr->id = t->id;
865       pr->name = t->name;
866       if (t->is_ip6)
867         count = 16;
868       else
869         count = 4;
870       clib_memcpy (pr->dst_address, t->dst_address, count);
871     }
872
873   vnet_send_dns_request (vm, dm, ep);
874   dns_cache_unlock (dm);
875   return 0;
876 }
877
878 #define foreach_notification_to_move            \
879 _(pending_requests)
880
881 /**
882  * Handle cname indirection. JFC. Called with the cache locked.
883  * returns 0 if the reply is not a CNAME.
884  */
885
886 int
887 vnet_dns_cname_indirection_nolock (vlib_main_t * vm, dns_main_t * dm,
888                                    u32 ep_index, u8 * reply)
889 {
890   dns_header_t *h;
891   dns_query_t *qp;
892   dns_rr_t *rr;
893   u8 *curpos;
894   u8 *pos, *pos2;
895   u8 *cname_pos = 0;
896   int len, i;
897   u8 *cname = 0;
898   u8 *request = 0;
899   u8 *name_copy;
900   u32 qp_offset;
901   u16 flags;
902   u16 rcode;
903   dns_cache_entry_t *ep, *next_ep;
904   f64 now;
905
906   h = (dns_header_t *) reply;
907   flags = clib_net_to_host_u16 (h->flags);
908   rcode = flags & DNS_RCODE_MASK;
909
910   /* See if the response is OK */
911   switch (rcode)
912     {
913     case DNS_RCODE_NO_ERROR:
914       break;
915
916     case DNS_RCODE_NAME_ERROR:
917     case DNS_RCODE_FORMAT_ERROR:
918     case DNS_RCODE_SERVER_FAILURE:
919     case DNS_RCODE_NOT_IMPLEMENTED:
920     case DNS_RCODE_REFUSED:
921       return -1;
922     }
923
924   curpos = (u8 *) (h + 1);
925   pos = curpos;
926   len = *pos++;
927
928   /* Skip the questions */
929   for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
930     {
931       while (len)
932         {
933           pos += len;
934           len = *pos++;
935         }
936       pos += sizeof (dns_query_t);
937     }
938   pos2 = pos;
939   /* expect a pointer chase here for a CNAME record */
940   if ((pos2[0] & 0xC0) == 0xC0)
941     pos += 2;
942   else
943     return 0;
944
945   /* Walk the answer(s) to see what to do next */
946   for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
947     {
948       rr = (dns_rr_t *) pos;
949       switch (clib_net_to_host_u16 (rr->type))
950         {
951           /* Real address record? Done.. */
952         case DNS_TYPE_A:
953         case DNS_TYPE_AAAA:
954           return 0;
955           /*
956            * Maybe chase a CNAME pointer?
957            * It's not unheard-of for name-servers to return
958            * both CNAME and A/AAAA records...
959            */
960         case DNS_TYPE_CNAME:
961           cname_pos = pos;
962           break;
963
964           /* Some other junk, e.g. a nameserver... */
965         default:
966           break;
967         }
968       pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
969       /* Skip name... */
970       if ((pos2[0] & 0xc0) == 0xc0)
971         pos += 2;
972     }
973
974   /* Neither a CNAME nor a real address. Try another server */
975   if (cname_pos == 0)
976     {
977       flags &= ~DNS_RCODE_MASK;
978       flags |= DNS_RCODE_NAME_ERROR;
979       h->flags = clib_host_to_net_u16 (flags);
980       return -1;
981     }
982
983   /* This is a CNAME record, chase the name chain. */
984   pos = cname_pos;
985
986   /* The last request is no longer pending.. */
987   for (i = 0; i < vec_len (dm->unresolved_entries); i++)
988     if (ep_index == dm->unresolved_entries[i])
989       {
990         vec_delete (dm->unresolved_entries, 1, i);
991         goto found_last_request;
992       }
993   clib_warning ("pool elt %d supposedly pending, but not found...", ep_index);
994   return -1;
995
996 found_last_request:
997
998   now = vlib_time_now (vm);
999   cname = vnet_dns_labels_to_name (rr->rdata, reply, &pos2);
1000   /* Save the cname */
1001   dns_terminate_c_string (&cname);
1002   ep = pool_elt_at_index (dm->entries, ep_index);
1003   ep->cname = cname;
1004   ep->flags |= (DNS_CACHE_ENTRY_FLAG_CNAME | DNS_CACHE_ENTRY_FLAG_VALID);
1005   /* Save the response */
1006   if (ep->dns_response)
1007     vec_free (ep->dns_response);
1008   ep->dns_response = reply;
1009   /* Set up expiration time */
1010   ep->expiration_time = now + clib_net_to_host_u32 (rr->ttl);
1011
1012   pool_get (dm->entries, next_ep);
1013
1014   /* Need to recompute ep post pool-get */
1015   ep = pool_elt_at_index (dm->entries, ep_index);
1016
1017   clib_memset (next_ep, 0, sizeof (*next_ep));
1018   next_ep->name = vec_dup (cname);
1019   dns_terminate_c_string (&next_ep->name);
1020
1021   hash_set_mem (dm->cache_entry_by_name, next_ep->name,
1022                 next_ep - dm->entries);
1023
1024   /* Use the same server */
1025   next_ep->server_rotor = ep->server_rotor;
1026   next_ep->server_af = ep->server_af;
1027
1028   /* Move notification data to the next name in the chain */
1029 #define _(a) next_ep->a = ep->a; ep->a = 0;
1030   foreach_notification_to_move;
1031 #undef _
1032
1033   request = name_to_labels (cname);
1034   name_copy = vec_dup (request);
1035
1036   qp_offset = vec_len (request);
1037
1038   /* Add space for the query header */
1039   vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
1040
1041   qp = (dns_query_t *) (request + qp_offset);
1042
1043   qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
1044   qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1045   clib_memcpy (qp, name_copy, vec_len (name_copy));
1046   qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
1047   vec_free (name_copy);
1048
1049   qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1050   qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1051
1052   /* Punch in space for the dns_header_t */
1053   vec_insert (request, sizeof (dns_header_t), 0);
1054
1055   h = (dns_header_t *) request;
1056
1057   /* Transaction ID = pool index */
1058   h->id = clib_host_to_net_u16 (next_ep - dm->entries);
1059
1060   /* Ask for a recursive lookup */
1061   h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
1062   h->qdcount = clib_host_to_net_u16 (2);
1063   h->nscount = 0;
1064   h->arcount = 0;
1065
1066   next_ep->dns_request = request;
1067   next_ep->retry_timer = now + 2.0;
1068   next_ep->retry_count = 0;
1069
1070   /*
1071    * Enable this to watch recursive resolution happen...
1072    * fformat (stdout, "%U", format_dns_reply, request, 2);
1073    */
1074
1075   vec_add1 (dm->unresolved_entries, next_ep - dm->entries);
1076   vnet_send_dns_request (vm, dm, next_ep);
1077   return (1);
1078 }
1079
1080 int
1081 vnet_dns_response_to_reply (u8 *response, dns_resolve_name_t *rn,
1082                             u32 *min_ttlp)
1083 {
1084   dns_header_t *h;
1085   dns_query_t *qp;
1086   dns_rr_t *rr;
1087   int i, limit;
1088   u8 len;
1089   u8 *curpos, *pos, *pos2;
1090   u16 flags;
1091   u16 rcode;
1092   u32 ttl;
1093   int pointer_chase, addr_set = 0;
1094
1095   h = (dns_header_t *) response;
1096   flags = clib_net_to_host_u16 (h->flags);
1097   rcode = flags & DNS_RCODE_MASK;
1098
1099   /* See if the response is OK, etc. */
1100   switch (rcode)
1101     {
1102     default:
1103     case DNS_RCODE_NO_ERROR:
1104       break;
1105
1106     case DNS_RCODE_NAME_ERROR:
1107     case DNS_RCODE_FORMAT_ERROR:
1108       return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1109
1110     case DNS_RCODE_SERVER_FAILURE:
1111     case DNS_RCODE_NOT_IMPLEMENTED:
1112     case DNS_RCODE_REFUSED:
1113       return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1114     }
1115
1116   /* No answers? Loser... */
1117   if (clib_net_to_host_u16 (h->anscount) < 1)
1118     return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1119
1120   curpos = (u8 *) (h + 1);
1121
1122   /* Skip the name we asked about */
1123   pos = curpos;
1124   len = *pos++;
1125   /* Should never happen, but stil... */
1126   if ((len & 0xC0) == 0xC0)
1127     curpos += 2;
1128   else
1129     {
1130       /* skip the name / label-set */
1131       while (len)
1132         {
1133           pos += len;
1134           len = *pos++;
1135         }
1136       curpos = pos;
1137     }
1138   /* Skip queries */
1139   limit = clib_net_to_host_u16 (h->qdcount);
1140   qp = (dns_query_t *) curpos;
1141   qp += limit;
1142   curpos = (u8 *) qp;
1143
1144   /* Parse answers */
1145   limit = clib_net_to_host_u16 (h->anscount);
1146
1147   for (i = 0; i < limit; i++)
1148     {
1149       pos = pos2 = curpos;
1150       pointer_chase = 0;
1151
1152       /* Expect pointer chases in the answer section... */
1153       if ((pos2[0] & 0xC0) == 0xC0)
1154         {
1155           pos = pos2 + 2;
1156           pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1157           pointer_chase = 1;
1158         }
1159
1160       len = *pos2++;
1161
1162       while (len)
1163         {
1164           pos2 += len;
1165           if ((pos2[0] & 0xc0) == 0xc0)
1166             {
1167               /*
1168                * If we've already done one pointer chase,
1169                * do not move the pos pointer.
1170                */
1171               if (pointer_chase == 0)
1172                 pos = pos2 + 2;
1173               pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1174               len = *pos2++;
1175               pointer_chase = 1;
1176             }
1177           else
1178             len = *pos2++;
1179         }
1180
1181       if (pointer_chase == 0)
1182         pos = pos2;
1183
1184       rr = (dns_rr_t *) pos;
1185
1186       switch (clib_net_to_host_u16 (rr->type))
1187         {
1188         case DNS_TYPE_A:
1189           /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1190           ip_address_set (&rn->address, rr->rdata, AF_IP4);
1191           ttl = clib_net_to_host_u32 (rr->ttl);
1192           addr_set += 1;
1193           if (min_ttlp && *min_ttlp > ttl)
1194             *min_ttlp = ttl;
1195           break;
1196         case DNS_TYPE_AAAA:
1197           /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1198           ip_address_set (&rn->address, rr->rdata, AF_IP6);
1199           ttl = clib_net_to_host_u32 (rr->ttl);
1200           if (min_ttlp && *min_ttlp > ttl)
1201             *min_ttlp = ttl;
1202           addr_set += 1;
1203           break;
1204
1205         default:
1206           break;
1207         }
1208       /* Might as well stop ASAP */
1209       if (addr_set > 1)
1210         break;
1211       pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1212       curpos = pos;
1213     }
1214
1215   if (addr_set == 0)
1216     return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1217   return 0;
1218 }
1219
1220 int
1221 vnet_dns_response_to_name (u8 * response,
1222                            vl_api_dns_resolve_ip_reply_t * rmp,
1223                            u32 * min_ttlp)
1224 {
1225   dns_header_t *h;
1226   dns_query_t *qp;
1227   dns_rr_t *rr;
1228   int i, limit;
1229   u8 len;
1230   u8 *curpos, *pos, *pos2;
1231   u16 flags;
1232   u16 rcode;
1233   u8 *name;
1234   u32 ttl;
1235   u8 *junk __attribute__ ((unused));
1236   int name_set = 0;
1237   int pointer_chase;
1238
1239   h = (dns_header_t *) response;
1240   flags = clib_net_to_host_u16 (h->flags);
1241   rcode = flags & DNS_RCODE_MASK;
1242
1243   /* See if the response is OK, etc. */
1244   switch (rcode)
1245     {
1246     default:
1247     case DNS_RCODE_NO_ERROR:
1248       break;
1249
1250     case DNS_RCODE_NAME_ERROR:
1251     case DNS_RCODE_FORMAT_ERROR:
1252       return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1253
1254     case DNS_RCODE_SERVER_FAILURE:
1255     case DNS_RCODE_NOT_IMPLEMENTED:
1256     case DNS_RCODE_REFUSED:
1257       return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1258     }
1259
1260   /* No answers? Loser... */
1261   if (clib_net_to_host_u16 (h->anscount) < 1)
1262     return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1263
1264   curpos = (u8 *) (h + 1);
1265
1266   /* Skip the name we asked about */
1267   pos = curpos;
1268   len = *pos++;
1269   /* Should never happen, but stil... */
1270   if ((len & 0xC0) == 0xC0)
1271     curpos += 2;
1272   else
1273     {
1274       /* skip the name / label-set */
1275       while (len)
1276         {
1277           pos += len;
1278           len = *pos++;
1279         }
1280       curpos = pos;
1281     }
1282   /* Skip queries */
1283   limit = clib_net_to_host_u16 (h->qdcount);
1284   qp = (dns_query_t *) curpos;
1285   qp += limit;
1286   curpos = (u8 *) qp;
1287
1288   /* Parse answers */
1289   limit = clib_net_to_host_u16 (h->anscount);
1290
1291   for (i = 0; i < limit; i++)
1292     {
1293       pos = pos2 = curpos;
1294       pointer_chase = 0;
1295
1296       /* Expect pointer chases in the answer section... */
1297       if ((pos2[0] & 0xC0) == 0xC0)
1298         {
1299           pos = pos2 + 2;
1300           pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1301           pointer_chase = 1;
1302         }
1303
1304       len = *pos2++;
1305
1306       while (len)
1307         {
1308           pos2 += len;
1309           if ((pos2[0] & 0xc0) == 0xc0)
1310             {
1311               /*
1312                * If we've already done one pointer chase,
1313                * do not move the pos pointer.
1314                */
1315               if (pointer_chase == 0)
1316                 pos = pos2 + 2;
1317               pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1318               len = *pos2++;
1319               pointer_chase = 1;
1320             }
1321           else
1322             len = *pos2++;
1323         }
1324
1325       if (pointer_chase == 0)
1326         pos = pos2;
1327
1328       rr = (dns_rr_t *) pos;
1329
1330       switch (clib_net_to_host_u16 (rr->type))
1331         {
1332         case DNS_TYPE_PTR:
1333           name = vnet_dns_labels_to_name (rr->rdata, response, &junk);
1334           memcpy (rmp->name, name, vec_len (name));
1335           ttl = clib_net_to_host_u32 (rr->ttl);
1336           if (min_ttlp)
1337             *min_ttlp = ttl;
1338           rmp->name[vec_len (name)] = 0;
1339           name_set = 1;
1340           break;
1341         default:
1342           break;
1343         }
1344       /* Might as well stop ASAP */
1345       if (name_set == 1)
1346         break;
1347       pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1348       curpos = pos;
1349     }
1350
1351   if (name_set == 0)
1352     return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1353   return 0;
1354 }
1355
1356 __clib_export int
1357 dns_resolve_name (u8 *name, dns_cache_entry_t **ep, dns_pending_request_t *t0,
1358                   dns_resolve_name_t *rn)
1359 {
1360   dns_main_t *dm = &dns_main;
1361   vlib_main_t *vm = vlib_get_main ();
1362
1363   int rv = vnet_dns_resolve_name (vm, dm, name, t0, ep);
1364
1365   /* Error, e.g. not enabled? Tell the user */
1366   if (rv < 0)
1367     return rv;
1368
1369   /* Resolution pending? Don't reply... */
1370   if (ep[0] == 0)
1371     return 0;
1372
1373   return vnet_dns_response_to_reply (ep[0]->dns_response, rn, 0 /* ttl-ptr */);
1374 }
1375
1376 static void
1377 vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1378 {
1379   dns_main_t *dm = &dns_main;
1380   vl_api_dns_resolve_name_reply_t *rmp;
1381   dns_cache_entry_t *ep = 0;
1382   dns_pending_request_t _t0 = { 0 }, *t0 = &_t0;
1383   int rv;
1384   dns_resolve_name_t rn;
1385
1386   /* Sanitize the name slightly */
1387   mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1388
1389   t0->request_type = DNS_API_PENDING_NAME_TO_IP;
1390   t0->client_index = mp->client_index;
1391   t0->client_context = mp->context;
1392
1393   rv = dns_resolve_name (mp->name, &ep, t0, &rn);
1394
1395   /* Error, e.g. not enabled? Tell the user */
1396   if (rv < 0)
1397     {
1398       REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1399       return;
1400     }
1401
1402   /* Resolution pending? Don't reply... */
1403   if (ep == 0)
1404     return;
1405
1406   /* *INDENT-OFF* */
1407   REPLY_MACRO2 (VL_API_DNS_RESOLVE_NAME_REPLY, ({
1408                   ip_address_copy_addr (rmp->ip4_address, &rn.address);
1409                   if (ip_addr_version (&rn.address) == AF_IP4)
1410                     rmp->ip4_set = 1;
1411                   else
1412                     rmp->ip6_set = 1;
1413                 }));
1414   /* *INDENT-ON* */
1415 }
1416
1417 static void
1418 vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
1419 {
1420   vlib_main_t *vm = vlib_get_main ();
1421   dns_main_t *dm = &dns_main;
1422   vl_api_dns_resolve_ip_reply_t *rmp;
1423   dns_cache_entry_t *ep;
1424   int rv;
1425   int i, len;
1426   u8 *lookup_name = 0;
1427   u8 digit, nybble;
1428   dns_pending_request_t _t0 = { 0 }, *t0 = &_t0;
1429
1430   if (mp->is_ip6)
1431     {
1432       for (i = 15; i >= 0; i--)
1433         {
1434           digit = mp->address[i];
1435           nybble = (digit & 0x0F);
1436           if (nybble > 9)
1437             vec_add1 (lookup_name, (nybble - 10) + 'a');
1438           else
1439             vec_add1 (lookup_name, nybble + '0');
1440           vec_add1 (lookup_name, '.');
1441           nybble = (digit & 0xF0) >> 4;
1442           if (nybble > 9)
1443             vec_add1 (lookup_name, (nybble - 10) + 'a');
1444           else
1445             vec_add1 (lookup_name, nybble + '0');
1446           vec_add1 (lookup_name, '.');
1447         }
1448       len = vec_len (lookup_name);
1449       vec_validate (lookup_name, len + 8);
1450       memcpy (lookup_name + len, "ip6.arpa", 8);
1451     }
1452   else
1453     {
1454       for (i = 3; i >= 0; i--)
1455         {
1456           digit = mp->address[i];
1457           lookup_name = format (lookup_name, "%d.", digit);
1458         }
1459       lookup_name = format (lookup_name, "in-addr.arpa");
1460     }
1461
1462   vec_add1 (lookup_name, 0);
1463
1464   t0->request_type = DNS_API_PENDING_IP_TO_NAME;
1465   t0->client_index = mp->client_index;
1466   t0->client_context = mp->context;
1467
1468   rv = vnet_dns_resolve_name (vm, dm, lookup_name, t0, &ep);
1469
1470   vec_free (lookup_name);
1471
1472   /* Error, e.g. not enabled? Tell the user */
1473   if (rv < 0)
1474     {
1475       REPLY_MACRO (VL_API_DNS_RESOLVE_IP_REPLY);
1476       return;
1477     }
1478
1479   /* Resolution pending? Don't reply... */
1480   if (ep == 0)
1481     return;
1482
1483   /* *INDENT-OFF* */
1484   REPLY_MACRO2(VL_API_DNS_RESOLVE_IP_REPLY,
1485   ({
1486     rv = vnet_dns_response_to_name (ep->dns_response, rmp, 0 /* ttl-ptr */);
1487     rmp->retval = clib_host_to_net_u32 (rv);
1488   }));
1489   /* *INDENT-ON* */
1490 }
1491
1492 static clib_error_t *
1493 dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1494 {
1495   dns_main_t *dm = &dns_main;
1496
1497   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1498     {
1499       if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1500         ;
1501       else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1502         ;
1503       else
1504         return clib_error_return (0, "unknown input `%U'",
1505                                   format_unformat_error, input);
1506     }
1507   return 0;
1508 }
1509
1510 VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1511
1512 uword
1513 unformat_dns_reply (unformat_input_t * input, va_list * args)
1514 {
1515   u8 **result = va_arg (*args, u8 **);
1516   u8 **namep = va_arg (*args, u8 **);
1517   ip4_address_t a4;
1518   ip6_address_t a6;
1519   int a4_set = 0;
1520   int a6_set = 0;
1521   u8 *name;
1522   int name_set = 0;
1523   u8 *ce;
1524   u32 qp_offset;
1525   dns_header_t *h;
1526   dns_query_t *qp;
1527   dns_rr_t *rr;
1528   u8 *rru8;
1529
1530   if (unformat (input, "%v", &name))
1531     name_set = 1;
1532
1533   if (unformat (input, "%U", unformat_ip4_address, &a4))
1534     {
1535       a4_set = 1;
1536       if (unformat (input, "%U", unformat_ip6_address, &a6))
1537         a6_set = 1;
1538     }
1539
1540   if (unformat (input, "%U", unformat_ip6_address, &a6))
1541     {
1542       a6_set = 1;
1543       if (unformat (input, "%U", unformat_ip4_address, &a6))
1544         a4_set = 1;
1545     }
1546
1547   /* Must have a name */
1548   if (!name_set)
1549     return 0;
1550
1551   /* Must have at least one address */
1552   if (!(a4_set + a6_set))
1553     return 0;
1554
1555   /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1556   ce = name_to_labels (name);
1557   qp_offset = vec_len (ce);
1558
1559   /* Add space for the query header */
1560   vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1561   qp = (dns_query_t *) (ce + qp_offset);
1562
1563   qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1564   qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1565
1566   /* Punch in space for the dns_header_t */
1567   vec_insert (ce, sizeof (dns_header_t), 0);
1568
1569   h = (dns_header_t *) ce;
1570
1571   /* Fake Transaction ID */
1572   h->id = 0xFFFF;
1573
1574   h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1575   h->qdcount = clib_host_to_net_u16 (1);
1576   h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1577   h->nscount = 0;
1578   h->arcount = 0;
1579
1580   /* Now append one or two A/AAAA RR's... */
1581   if (a4_set)
1582     {
1583       /* Pointer to the name (DGMS) */
1584       vec_add1 (ce, 0xC0);
1585       vec_add1 (ce, 0x0C);
1586       vec_add2 (ce, rru8, sizeof (*rr) + 4);
1587       rr = (void *) rru8;
1588       rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1589       rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1590       rr->ttl = clib_host_to_net_u32 (86400);
1591       rr->rdlength = clib_host_to_net_u16 (4);
1592       memcpy (rr->rdata, &a4, sizeof (a4));
1593     }
1594   if (a6_set)
1595     {
1596       /* Pointer to the name (DGMS) */
1597       vec_add1 (ce, 0xC0);
1598       vec_add1 (ce, 0x0C);
1599       vec_add2 (ce, rru8, sizeof (*rr) + 16);
1600       rr = (void *) rru8;
1601       rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1602       rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1603       rr->ttl = clib_host_to_net_u32 (86400);
1604       rr->rdlength = clib_host_to_net_u16 (16);
1605       memcpy (rr->rdata, &a6, sizeof (a6));
1606     }
1607   *result = ce;
1608   if (namep)
1609     *namep = name;
1610   else
1611     vec_free (name);
1612
1613   return 1;
1614 }
1615
1616 u8 *
1617 format_dns_query (u8 * s, va_list * args)
1618 {
1619   u8 **curpos = va_arg (*args, u8 **);
1620   int verbose = va_arg (*args, int);
1621   u8 *pos;
1622   dns_query_t *qp;
1623   int len, i;
1624   if (verbose > 1)
1625     s = format (s, "    Name: ");
1626
1627   /* Unwind execrated counted-label sheit */
1628   pos = *curpos;
1629   len = *pos++;
1630
1631   while (len)
1632     {
1633       for (i = 0; i < len; i++)
1634         vec_add1 (s, *pos++);
1635
1636       len = *pos++;
1637       if (len)
1638         vec_add1 (s, '.');
1639       else
1640         {
1641           vec_add1 (s, ':');
1642           vec_add1 (s, ' ');
1643         }
1644     }
1645
1646   qp = (dns_query_t *) pos;
1647   if (verbose > 1)
1648     {
1649       switch (clib_net_to_host_u16 (qp->type))
1650         {
1651         case DNS_TYPE_A:
1652           s = format (s, "type A\n");
1653           break;
1654         case DNS_TYPE_AAAA:
1655           s = format (s, "type AAAA\n");
1656           break;
1657         case DNS_TYPE_ALL:
1658           s = format (s, "type ALL\n");
1659           break;
1660
1661         default:
1662           s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1663           break;
1664         }
1665     }
1666
1667   pos += sizeof (*qp);
1668
1669   *curpos = pos;
1670   return s;
1671 }
1672
1673 /**
1674  * format dns reply data
1675  * verbose > 1, dump everything
1676  * verbose == 1, dump all A and AAAA records
1677  * verbose == 0, dump one A record, and one AAAA record
1678  */
1679
1680 u8 *
1681 format_dns_reply_data (u8 * s, va_list * args)
1682 {
1683   u8 *reply = va_arg (*args, u8 *);
1684   u8 **curpos = va_arg (*args, u8 **);
1685   int verbose = va_arg (*args, int);
1686   int *print_ip4 = va_arg (*args, int *);
1687   int *print_ip6 = va_arg (*args, int *);
1688   int len;
1689   u8 *pos, *pos2;
1690   dns_rr_t *rr;
1691   int i;
1692   int pointer_chase = 0;
1693   u16 *tp;
1694   u16 rrtype_host_byte_order;
1695
1696   pos = pos2 = *curpos;
1697
1698   if (verbose > 1)
1699     s = format (s, "    ");
1700
1701   /* chase pointer? almost always yes here... */
1702   if ((pos2[0] & 0xc0) == 0xc0)
1703     {
1704       pos = pos2 + 2;
1705       pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1706       pointer_chase = 1;
1707     }
1708
1709   len = *pos2++;
1710
1711   while (len)
1712     {
1713       for (i = 0; i < len; i++)
1714         {
1715           if (verbose > 1)
1716             vec_add1 (s, *pos2);
1717           pos2++;
1718         }
1719       if ((pos2[0] & 0xc0) == 0xc0)
1720         {
1721           /*
1722            * If we've already done one pointer chase,
1723            * do not move the pos pointer.
1724            */
1725           if (pointer_chase == 0)
1726             pos = pos2 + 2;
1727           pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1728           len = *pos2++;
1729           pointer_chase = 1;
1730         }
1731       else
1732         len = *pos2++;
1733       if (len)
1734         {
1735           if (verbose > 1)
1736             vec_add1 (s, '.');
1737         }
1738       else
1739         {
1740           if (verbose > 1)
1741             vec_add1 (s, ' ');
1742         }
1743     }
1744
1745   if (pointer_chase == 0)
1746     pos = pos2;
1747
1748   rr = (dns_rr_t *) pos;
1749   rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
1750
1751   switch (rrtype_host_byte_order)
1752     {
1753     case DNS_TYPE_A:
1754       if (verbose > 1)
1755         {
1756           s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1757                       format_ip4_address, rr->rdata);
1758         }
1759       else
1760         {
1761           if (*print_ip4)
1762             s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1763                         clib_net_to_host_u32 (rr->ttl));
1764           if (verbose == 0)
1765             *print_ip4 = 0;
1766
1767         }
1768       pos += sizeof (*rr) + 4;
1769       break;
1770
1771     case DNS_TYPE_AAAA:
1772       if (verbose > 1)
1773         {
1774           s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1775                       format_ip6_address, rr->rdata);
1776         }
1777       else
1778         {
1779           if (*print_ip6)
1780             s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1781                         clib_net_to_host_u32 (rr->ttl));
1782           if (verbose == 0)
1783             *print_ip6 = 0;
1784         }
1785       pos += sizeof (*rr) + 16;
1786       break;
1787
1788     case DNS_TYPE_TEXT:
1789       if (verbose > 1)
1790         {
1791           s = format (s, "TEXT: ");
1792           for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1793             vec_add1 (s, rr->rdata[i]);
1794           vec_add1 (s, '\n');
1795         }
1796       pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1797       break;
1798
1799     case DNS_TYPE_HINFO:
1800       {
1801         /* Two counted strings. DGMS */
1802         u8 *len;
1803         u8 *curpos;
1804         int i;
1805         if (verbose > 1)
1806           {
1807             s = format (s, "HINFO: ");
1808             len = rr->rdata;
1809             curpos = len + 1;
1810             for (i = 0; i < *len; i++)
1811               vec_add1 (s, *curpos++);
1812
1813             vec_add1 (s, ' ');
1814             len = curpos++;
1815             for (i = 0; i < *len; i++)
1816               vec_add1 (s, *curpos++);
1817
1818             vec_add1 (s, '\n');
1819           }
1820       }
1821       pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1822       break;
1823
1824     case DNS_TYPE_NAMESERVER:
1825       if (verbose > 1)
1826         {
1827           s = format (s, "Nameserver: ");
1828           pos2 = rr->rdata;
1829
1830           /* chase pointer? */
1831           if ((pos2[0] & 0xc0) == 0xc0)
1832             {
1833               pos = pos2 + 2;
1834               pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1835             }
1836
1837           len = *pos2++;
1838
1839           while (len)
1840             {
1841               for (i = 0; i < len; i++)
1842                 vec_add1 (s, *pos2++);
1843
1844               /* chase pointer, typically to offset 12... */
1845               if (pos2[0] == 0xC0)
1846                 pos2 = reply + pos2[1];
1847
1848               len = *pos2++;
1849               if (len)
1850                 vec_add1 (s, '.');
1851               else
1852                 vec_add1 (s, '\n');
1853             }
1854         }
1855       pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1856       break;
1857
1858     case DNS_TYPE_MAIL_EXCHANGE:
1859       if (verbose > 1)
1860         {
1861           tp = (u16 *) rr->rdata;
1862
1863           s = format (s, "Mail Exchange: Preference %d ", (u32)
1864                       clib_net_to_host_u16 (*tp));
1865
1866           pos2 = rr->rdata + 2;
1867
1868           /* chase pointer? */
1869           if (pos2[0] == 0xc0)
1870             pos2 = reply + pos2[1];
1871
1872           len = *pos2++;
1873
1874           while (len)
1875             {
1876               for (i = 0; i < len; i++)
1877                 vec_add1 (s, *pos2++);
1878
1879               /* chase pointer */
1880               if (pos2[0] == 0xC0)
1881                 pos2 = reply + pos2[1];
1882
1883               len = *pos2++;
1884               if (len)
1885                 vec_add1 (s, '.');
1886               else
1887                 vec_add1 (s, '\n');
1888             }
1889         }
1890
1891       pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1892       break;
1893
1894     case DNS_TYPE_PTR:
1895     case DNS_TYPE_CNAME:
1896       if (verbose > 1)
1897         {
1898           tp = (u16 *) rr->rdata;
1899
1900           if (rrtype_host_byte_order == DNS_TYPE_CNAME)
1901             s = format (s, "CNAME: ");
1902           else
1903             s = format (s, "PTR: ");
1904
1905           pos2 = rr->rdata;
1906
1907           /* chase pointer? */
1908           if (pos2[0] == 0xc0)
1909             pos2 = reply + pos2[1];
1910
1911           len = *pos2++;
1912
1913           while (len)
1914             {
1915               for (i = 0; i < len; i++)
1916                 vec_add1 (s, *pos2++);
1917
1918               /* chase pointer */
1919               if (pos2[0] == 0xC0)
1920                 pos2 = reply + pos2[1];
1921
1922               len = *pos2++;
1923               if (len)
1924                 vec_add1 (s, '.');
1925               else
1926                 vec_add1 (s, '\n');
1927             }
1928         }
1929       pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1930       break;
1931
1932     default:
1933       if (verbose > 1)
1934         s = format (s, "type %d: len %d\n",
1935                     (int) clib_net_to_host_u16 (rr->type),
1936                     sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
1937       pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1938       break;
1939     }
1940
1941   *curpos = pos;
1942
1943   return s;
1944 }
1945
1946 u8 *
1947 format_dns_reply (u8 * s, va_list * args)
1948 {
1949   u8 *reply_as_u8 = va_arg (*args, u8 *);
1950   int verbose = va_arg (*args, int);
1951   dns_header_t *h;
1952   u16 id, flags;
1953   u8 *curpos;
1954   int i;
1955   int print_ip4 = 1;
1956   int print_ip6 = 1;
1957
1958   h = (dns_header_t *) reply_as_u8;
1959   id = clib_net_to_host_u16 (h->id);
1960   flags = clib_net_to_host_u16 (h->flags);
1961
1962   if (verbose > 1)
1963     {
1964       s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
1965                   id);
1966       s = format (s, "  %s %s %s %s\n",
1967                   (flags & DNS_RA) ? "recur" : "no-recur",
1968                   (flags & DNS_RD) ? "recur-des" : "no-recur-des",
1969                   (flags & DNS_TC) ? "trunc" : "no-trunc",
1970                   (flags & DNS_AA) ? "auth" : "non-auth");
1971       s = format (s, "  %d queries, %d answers, %d name-servers,"
1972                   " %d add'l recs\n",
1973                   clib_net_to_host_u16 (h->qdcount),
1974                   clib_net_to_host_u16 (h->anscount),
1975                   clib_net_to_host_u16 (h->nscount),
1976                   clib_net_to_host_u16 (h->arcount));
1977     }
1978
1979   curpos = (u8 *) (h + 1);
1980
1981   if (h->qdcount)
1982     {
1983       if (verbose > 1)
1984         s = format (s, "  Queries:\n");
1985       for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
1986         {
1987           /* The query is variable-length, so curpos is a value-result parm */
1988           s = format (s, "%U", format_dns_query, &curpos, verbose);
1989         }
1990     }
1991   if (h->anscount)
1992     {
1993       if (verbose > 1)
1994         s = format (s, "  Replies:\n");
1995
1996       for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
1997         {
1998           /* curpos is a value-result parm */
1999           s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
2000                       verbose, &print_ip4, &print_ip6);
2001         }
2002     }
2003   return s;
2004 }
2005
2006 u8 *
2007 format_dns_cache (u8 * s, va_list * args)
2008 {
2009   dns_main_t *dm = va_arg (*args, dns_main_t *);
2010   f64 now = va_arg (*args, f64);
2011   int verbose = va_arg (*args, int);
2012   u8 *name = va_arg (*args, u8 *);
2013   dns_cache_entry_t *ep;
2014   char *ss;
2015   uword *p;
2016
2017   if (dm->is_enabled == 0)
2018     {
2019       s = format (s, "The DNS cache is disabled...");
2020       return s;
2021     }
2022
2023   if (pool_elts (dm->entries) == 0)
2024     {
2025       s = format (s, "The DNS cache is empty...");
2026       return s;
2027     }
2028
2029   dns_cache_lock (dm, 6);
2030
2031   if (name)
2032     {
2033       p = hash_get_mem (dm->cache_entry_by_name, name);
2034       if (!p)
2035         {
2036           s = format (s, "%s is not in the cache...", name);
2037           dns_cache_unlock (dm);
2038           return (s);
2039         }
2040
2041       ep = pool_elt_at_index (dm->entries, p[0]);
2042       /* Magic to spit out a C-initializer to research hemorrhoids... */
2043       if (verbose == 3)
2044         {
2045           int i, j;
2046           s = format (s, "static u8 dns_reply_data_initializer[] =\n");
2047           s = format (s, "{\n");
2048           j = 0;
2049           for (i = 0; i < vec_len (ep->dns_response); i++)
2050             {
2051               if (j++ == 8)
2052                 {
2053                   j = 0;
2054                   vec_add1 (s, '\n');
2055                 }
2056               s = format (s, "0x%02x, ", ep->dns_response[i]);
2057             }
2058           s = format (s, "};\n");
2059         }
2060       else
2061         {
2062           if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2063             {
2064               ASSERT (ep->dns_response);
2065               if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2066                 ss = "[S] ";
2067               else
2068                 ss = "    ";
2069
2070               if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2071                 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2072               else
2073                 s = format (s, "%s%s -> %U", ss, ep->name,
2074                             format_dns_reply, ep->dns_response, verbose);
2075               if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2076                 {
2077                   f64 time_left = ep->expiration_time - now;
2078                   if (time_left > 0.0)
2079                     s = format (s, "  TTL left %.1f", time_left);
2080                   else
2081                     s = format (s, "  EXPIRED");
2082                 }
2083             }
2084           else
2085             {
2086               ASSERT (ep->dns_request);
2087               s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2088                           verbose);
2089             }
2090           vec_add1 (s, '\n');
2091         }
2092       return s;
2093     }
2094
2095   s = format (s, "DNS cache contains %d entries\n", pool_elts (dm->entries));
2096
2097   if (verbose > 0)
2098     {
2099       /* *INDENT-OFF* */
2100       pool_foreach (ep, dm->entries)
2101        {
2102         if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2103           {
2104             ASSERT (ep->dns_response);
2105             if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2106               ss = "[S] ";
2107             else
2108               ss = "    ";
2109
2110             if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2111               s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2112             else
2113               s = format (s, "%s%s -> %U", ss, ep->name,
2114                           format_dns_reply,
2115                           ep->dns_response,
2116                           verbose);
2117             if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2118               {
2119                 f64 time_left = ep->expiration_time - now;
2120                 if (time_left > 0.0)
2121                   s = format (s, "  TTL left %.1f", time_left);
2122                 else
2123                   s = format (s, "  EXPIRED");
2124
2125                 if (verbose > 2)
2126                   s = format (s, "    %d client notifications pending\n",
2127                               vec_len(ep->pending_requests));
2128               }
2129           }
2130         else
2131           {
2132             ASSERT (ep->dns_request);
2133             s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2134                         verbose);
2135           }
2136         vec_add1 (s, '\n');
2137       }
2138       /* *INDENT-ON* */
2139     }
2140
2141   dns_cache_unlock (dm);
2142
2143   return s;
2144 }
2145
2146 static clib_error_t *
2147 show_dns_cache_command_fn (vlib_main_t * vm,
2148                            unformat_input_t * input, vlib_cli_command_t * cmd)
2149 {
2150   dns_main_t *dm = &dns_main;
2151   int verbose = 0;
2152   u8 *name = 0;
2153   f64 now = vlib_time_now (vm);
2154
2155   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2156     {
2157       if (unformat (input, "verbose %d", &verbose))
2158         ;
2159       else if (unformat (input, "verbose"))
2160         verbose = 1;
2161       else if (unformat (input, "name %s", &name))
2162         ;
2163       else
2164         return clib_error_return (0, "unknown input `%U'",
2165                                   format_unformat_error, input);
2166     }
2167
2168   vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
2169
2170   return 0;
2171 }
2172
2173 /* *INDENT-OFF* */
2174 VLIB_CLI_COMMAND (show_dns_cache_command) =
2175 {
2176   .path = "show dns cache",
2177   .short_help = "show dns cache [verbose [nn]]",
2178   .function = show_dns_cache_command_fn,
2179 };
2180 /* *INDENT-ON* */
2181
2182 static clib_error_t *
2183 show_dns_servers_command_fn (vlib_main_t * vm,
2184                              unformat_input_t * input,
2185                              vlib_cli_command_t * cmd)
2186 {
2187   dns_main_t *dm = &dns_main;
2188   int i;
2189
2190   if ((vec_len (dm->ip4_name_servers) + vec_len (dm->ip6_name_servers)) == 0)
2191     return clib_error_return (0, "No name servers configured...");
2192
2193   if (vec_len (dm->ip4_name_servers))
2194     {
2195       vlib_cli_output (vm, "ip4 name servers:");
2196       for (i = 0; i < vec_len (dm->ip4_name_servers); i++)
2197         vlib_cli_output (vm, "%U", format_ip4_address,
2198                          dm->ip4_name_servers + i);
2199     }
2200   if (vec_len (dm->ip6_name_servers))
2201     {
2202       vlib_cli_output (vm, "ip6 name servers:");
2203       for (i = 0; i < vec_len (dm->ip6_name_servers); i++)
2204         vlib_cli_output (vm, "%U", format_ip6_address,
2205                          dm->ip4_name_servers + i);
2206     }
2207   return 0;
2208 }
2209
2210 /* *INDENT-OFF* */
2211 VLIB_CLI_COMMAND (show_dns_server_command) =
2212 {
2213   .path = "show dns servers",
2214   .short_help = "show dns servers",
2215   .function = show_dns_servers_command_fn,
2216 };
2217 /* *INDENT-ON* */
2218
2219
2220 static clib_error_t *
2221 dns_cache_add_del_command_fn (vlib_main_t * vm,
2222                               unformat_input_t * input,
2223                               vlib_cli_command_t * cmd)
2224 {
2225   dns_main_t *dm = &dns_main;
2226   u8 *dns_reply_data;
2227   u8 *name;
2228   int is_add = -1;
2229   int is_clear = -1;
2230   int rv;
2231   clib_error_t *error;
2232
2233   if (unformat (input, "add"))
2234     is_add = 1;
2235   if (unformat (input, "del"))
2236     is_add = 0;
2237   if (unformat (input, "clear"))
2238     is_clear = 1;
2239
2240   if (is_add == -1 && is_clear == -1)
2241     return clib_error_return (0, "add / del / clear required...");
2242
2243   if (is_clear == 1)
2244     {
2245       rv = dns_cache_clear (dm);
2246       switch (rv)
2247         {
2248         case 0:
2249           return 0;
2250
2251         case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2252           error = clib_error_return (0, "Name resolution not enabled");
2253           return error;
2254         }
2255     }
2256
2257   /* Delete (by name)? */
2258   if (is_add == 0)
2259     {
2260       if (unformat (input, "%v", &name))
2261         {
2262           rv = dns_delete_by_name (dm, name);
2263           switch (rv)
2264             {
2265             case VNET_API_ERROR_NO_SUCH_ENTRY:
2266               error = clib_error_return (0, "%v not in the cache...", name);
2267               vec_free (name);
2268               return error;
2269
2270             case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2271               error = clib_error_return (0, "Name resolution not enabled");
2272               vec_free (name);
2273               return error;
2274
2275             case 0:
2276               vec_free (name);
2277               return 0;
2278
2279             default:
2280               error = clib_error_return (0, "dns_delete_by_name returned %d",
2281                                          rv);
2282               vec_free (name);
2283               return error;
2284             }
2285         }
2286       return clib_error_return (0, "unknown input `%U'",
2287                                 format_unformat_error, input);
2288     }
2289
2290   /* Note: dns_add_static_entry consumes the name vector if OK... */
2291   if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2292     {
2293       rv = dns_add_static_entry (dm, name, dns_reply_data);
2294       switch (rv)
2295         {
2296         case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2297           vec_free (name);
2298           vec_free (dns_reply_data);
2299           return clib_error_return (0, "%v already in the cache...", name);
2300         case 0:
2301           return 0;
2302
2303         default:
2304           return clib_error_return (0, "dns_add_static_entry returned %d",
2305                                     rv);
2306         }
2307     }
2308
2309   return 0;
2310 }
2311
2312 /* *INDENT-OFF* */
2313 VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2314 {
2315   .path = "dns cache",
2316   .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2317   .function = dns_cache_add_del_command_fn,
2318 };
2319 /* *INDENT-ON* */
2320
2321 #define DNS_FORMAT_TEST 1
2322
2323 #if DNS_FORMAT_TEST > 0
2324 #if 0
2325 /* yahoo.com */
2326 static u8 dns_reply_data_initializer[] =
2327   { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2328   0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2329   0x0,                          /* null lbl */
2330   0x0, 0xff,                    /* type ALL */
2331   0x0, 0x1,                     /* class IN */
2332   0xc0, 0xc,                    /* pointer to yahoo.com name */
2333   0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2334   0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2335   0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2336   0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2337   0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2338   0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2339   0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2340   0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2341   0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2342   0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2343   0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2344   0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2345   0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2346   0x6e,
2347   0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2348   0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2349   0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2350   0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2351   0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2352   0x0,
2353   0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2354   0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2355   0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2356   0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2357   0x0,
2358   0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2359   0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2360   0x0,
2361   0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2362   0x0,
2363   0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2364   0x0,
2365   0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2366   0x6f,
2367   0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2368   0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2369   0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2370   0x2, 0x58
2371 };
2372
2373 /* www.cisco.com, has no addresses in reply */
2374 static u8 dns_reply_data_initializer[] = {
2375   0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2376   0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2377   0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2378
2379   0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2380   0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2381   0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2382   0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2383   0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2384 };
2385
2386 /* bind8 (linux widget, w/ nasty double pointer chasees */
2387 static u8 dns_reply_data_initializer[] = {
2388   /* 0 */
2389   0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08,
2390   /* 8 */
2391   0x00, 0x06, 0x00, 0x06, 0x0a, 0x6f, 0x72, 0x69,
2392   /* 16 */
2393   0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77, 0x77, 0x05,
2394   /* 24 */
2395   0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f,
2396   /* 32 */
2397   0x6d, 0x00, 0x00, 0xff, 0x00, 0x01, 0x0a, 0x6f,
2398   /* 40 */
2399   0x72, 0x69, 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77,
2400   /* 48 */
2401   0x77, 0x05, 0x43, 0x49, 0x53, 0x43, 0x4f, 0xc0,
2402
2403   /* 56 */
2404   0x1d, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2405
2406   /* 64 */
2407   0x9a, 0x00, 0x18, 0x15, 0x72, 0x63, 0x64,
2408   0x6e, 0x39, 0x2d, 0x31, 0x34, 0x70, 0x2d, 0x64, 0x63,
2409   0x7a, 0x30, 0x35, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31,
2410   0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00, 0x01, 0x00,
2411   0x00, 0x05, 0x9a, 0x00, 0x1a, 0x17, 0x61, 0x6c, 0x6c,
2412   0x6e, 0x30, 0x31, 0x2d, 0x61, 0x67, 0x30, 0x39, 0x2d,
2413   0x64, 0x63, 0x7a, 0x30, 0x33, 0x6e, 0x2d, 0x67, 0x73,
2414   0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00,
2415   0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x10, 0x0d, 0x72,
2416   0x74, 0x70, 0x35, 0x2d, 0x64, 0x6d, 0x7a, 0x2d, 0x67,
2417   0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2418   0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x18, 0x15,
2419   0x6d, 0x74, 0x76, 0x35, 0x2d, 0x61, 0x70, 0x31, 0x30,
2420   0x2d, 0x64, 0x63, 0x7a, 0x30, 0x36, 0x6e, 0x2d, 0x67,
2421   0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2422   0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x1b, 0x18,
2423   0x73, 0x6e, 0x67, 0x64, 0x63, 0x30, 0x31, 0x2d, 0x61,
2424   0x62, 0x30, 0x37, 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x31,
2425   0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0,
2426   0x26, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a,
2427   0x00, 0x1a, 0x17, 0x61, 0x65, 0x72, 0x30, 0x31, 0x2d,
2428   0x72, 0x34, 0x63, 0x32, 0x35, 0x2d, 0x64, 0x63, 0x7a,
2429   0x30, 0x31, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0,
2430   0x17, 0xc0, 0x26, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2431   0x00, 0x81, 0x00, 0x04, 0x48, 0xa3, 0x04, 0xa1, 0xc0,
2432   0x26, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82,
2433   0x00, 0x10, 0x20, 0x01, 0x04, 0x20, 0x12, 0x01, 0x00,
2434   0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
2435   0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2436   0x9a, 0x00, 0x02, 0xc0, 0xf4, 0xc0, 0x0c, 0x00, 0x02,
2437   0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0,
2438   0xcd, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00,
2439   0x05, 0x9a, 0x00, 0x02, 0xc0, 0x8d, 0xc0, 0x0c, 0x00,
2440   0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02,
2441   0xc0, 0x43, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00,
2442   0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0, 0xa9, 0xc0, 0x0c,
2443   0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00,
2444   0x02, 0xc0, 0x67, 0xc0, 0x8d, 0x00, 0x01, 0x00, 0x01,
2445   0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0x40, 0x66, 0xf6,
2446   0x05, 0xc0, 0xa9, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2447   0x07, 0x08, 0x00, 0x04, 0xad, 0x24, 0xe0, 0x64, 0xc0,
2448   0x43, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08,
2449   0x00, 0x04, 0x48, 0xa3, 0x04, 0x1c, 0xc0, 0xf4, 0x00,
2450   0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04,
2451   0xad, 0x26, 0xd4, 0x6c, 0xc0, 0x67, 0x00, 0x01, 0x00,
2452   0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x25,
2453   0x90, 0x64, 0xc0, 0xcd, 0x00, 0x01, 0x00, 0x01, 0x00,
2454   0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x27, 0x70, 0x44,
2455 };
2456
2457 /* google.com */
2458 static u8 dns_reply_data_initializer[] =
2459   { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
2460   0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
2461   0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
2462   0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
2463   0x2b,
2464   0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
2465   0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
2466   0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
2467   0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
2468   0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
2469   0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
2470   0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
2471   0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
2472   0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
2473   0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
2474   0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
2475   0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
2476   0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
2477   0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
2478   0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
2479   0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
2480   0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2481   0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
2482   0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
2483   0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
2484   0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
2485   0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
2486   0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
2487   0x57,
2488   0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2489 };
2490
2491 #else
2492 /* www.weatherlink.com */
2493 static u8 dns_reply_data_initializer[] = {
2494   0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2495   0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x0b,
2496   0x77, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x6c, 0x69,
2497   0x6e, 0x6b, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0xff,
2498   0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00,
2499   0x00, 0x0c, 0x9e, 0x00, 0x1f, 0x0e, 0x64, 0x33, 0x6b,
2500   0x72, 0x30, 0x67, 0x75, 0x62, 0x61, 0x31, 0x64, 0x76,
2501   0x77, 0x66, 0x0a, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x66,
2502   0x72, 0x6f, 0x6e, 0x74, 0x03, 0x6e, 0x65, 0x74, 0x00,
2503 };
2504
2505 #endif
2506
2507 static clib_error_t *
2508 test_dns_fmt_command_fn (vlib_main_t * vm,
2509                          unformat_input_t * input, vlib_cli_command_t * cmd)
2510 {
2511   dns_resolve_name_t _rn, *rn = &_rn;
2512   u8 *dns_reply_data = 0;
2513   int verbose = 0;
2514   int rv;
2515   vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2516
2517   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2518     {
2519       if (unformat (input, "verbose %d", &verbose))
2520         ;
2521       else if (unformat (input, "verbose"))
2522         verbose = 1;
2523       else
2524         return clib_error_return (0, "unknown input `%U'",
2525                                   format_unformat_error, input);
2526     }
2527
2528   vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2529
2530   memcpy (dns_reply_data, dns_reply_data_initializer,
2531           ARRAY_LEN (dns_reply_data_initializer));
2532
2533   vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2534
2535   clib_memset (rmp, 0, sizeof (*rmp));
2536
2537   rv = vnet_dns_response_to_reply (dns_reply_data, rn, 0 /* ttl-ptr */);
2538
2539   switch (rv)
2540     {
2541     case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2542       vlib_cli_output (vm, "no addresses found...");
2543       break;
2544
2545     default:
2546       vlib_cli_output (vm, "response to reply returned %d", rv);
2547       break;
2548
2549     case 0:
2550       vlib_cli_output (vm, "ip address: %U", format_ip_address, &rn->address);
2551       break;
2552     }
2553
2554   vec_free (dns_reply_data);
2555
2556   return 0;
2557 }
2558
2559
2560 /* *INDENT-OFF* */
2561 VLIB_CLI_COMMAND (test_dns_fmt_command) =
2562 {
2563   .path = "test dns format",
2564   .short_help = "test dns format",
2565   .function = test_dns_fmt_command_fn,
2566 };
2567 /* *INDENT-ON* */
2568
2569 static clib_error_t *
2570 test_dns_unfmt_command_fn (vlib_main_t * vm,
2571                            unformat_input_t * input, vlib_cli_command_t * cmd)
2572 {
2573   u8 *dns_reply_data = 0;
2574   int verbose = 0;
2575   int reply_set = 0;
2576
2577   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2578     {
2579       if (unformat (input, "verbose %d", &verbose))
2580         ;
2581       else if (unformat (input, "verbose"))
2582         verbose = 1;
2583       else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2584         reply_set = 1;
2585       else
2586         return clib_error_return (0, "unknown input `%U'",
2587                                   format_unformat_error, input);
2588     }
2589
2590   if (reply_set == 0)
2591     return clib_error_return (0, "dns data not set...");
2592
2593   vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2594
2595   vec_free (dns_reply_data);
2596
2597   return 0;
2598 }
2599
2600 /* *INDENT-OFF* */
2601 VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2602 {
2603   .path = "test dns unformat",
2604   .short_help = "test dns unformat <name> [ip4][ip6]",
2605   .function = test_dns_unfmt_command_fn,
2606 };
2607 /* *INDENT-ON* */
2608
2609 static clib_error_t *
2610 test_dns_expire_command_fn (vlib_main_t * vm,
2611                             unformat_input_t * input,
2612                             vlib_cli_command_t * cmd)
2613 {
2614   dns_main_t *dm = &dns_main;
2615   u8 *name = 0;
2616   uword *p;
2617   clib_error_t *e;
2618   dns_cache_entry_t *ep;
2619
2620   if (unformat (input, "%v", &name))
2621     dns_terminate_c_string (&name);
2622   else
2623     return clib_error_return (0, "no name provided");
2624
2625   dns_cache_lock (dm, 7);
2626
2627   p = hash_get_mem (dm->cache_entry_by_name, name);
2628   if (!p)
2629     {
2630       dns_cache_unlock (dm);
2631       e = clib_error_return (0, "%s is not in the cache...", name);
2632       vec_free (name);
2633       return e;
2634     }
2635
2636   ep = pool_elt_at_index (dm->entries, p[0]);
2637
2638   ep->expiration_time = 0;
2639
2640   return 0;
2641 }
2642
2643 /* *INDENT-OFF* */
2644 VLIB_CLI_COMMAND (test_dns_expire_command) =
2645 {
2646   .path = "test dns expire",
2647   .short_help = "test dns expire <name>",
2648   .function = test_dns_expire_command_fn,
2649 };
2650 /* *INDENT-ON* */
2651 #endif
2652
2653 void
2654 vnet_send_dns6_reply (vlib_main_t * vm, dns_main_t * dm,
2655                       dns_pending_request_t * pr, dns_cache_entry_t * ep,
2656                       vlib_buffer_t * b0)
2657 {
2658   clib_warning ("Unimplemented...");
2659 }
2660
2661
2662 void
2663 vnet_send_dns4_reply (vlib_main_t * vm, dns_main_t * dm,
2664                       dns_pending_request_t * pr, dns_cache_entry_t * ep,
2665                       vlib_buffer_t * b0)
2666 {
2667   u32 bi = 0;
2668   ip4_address_t src_address;
2669   ip4_header_t *ip;
2670   udp_header_t *udp;
2671   dns_header_t *dh;
2672   vlib_frame_t *f;
2673   u32 *to_next;
2674   u8 *dns_response;
2675   u8 *reply;
2676   /* vl_api_dns_resolve_name_reply_t _rnr, *rnr = &_rnr; */
2677   dns_resolve_name_t _rn, *rn = &_rn;
2678   vl_api_dns_resolve_ip_reply_t _rir, *rir = &_rir;
2679   u32 ttl = 64, tmp;
2680   u32 qp_offset;
2681   dns_query_t *qp;
2682   dns_rr_t *rr;
2683   u8 *rrptr;
2684   int is_fail = 0;
2685   int is_recycle = (b0 != 0);
2686
2687   ASSERT (ep && ep->dns_response);
2688
2689   if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2690     {
2691       /* Quick and dirty way to dig up the A-record address. $$ FIXME */
2692       clib_memset (rn, 0, sizeof (*rn));
2693       if (vnet_dns_response_to_reply (ep->dns_response, rn, &ttl))
2694         {
2695           /* clib_warning ("response_to_reply failed..."); */
2696           is_fail = 1;
2697         }
2698       else if (ip_addr_version (&rn->address) != AF_IP4)
2699         {
2700           /* clib_warning ("No A-record..."); */
2701           is_fail = 1;
2702         }
2703     }
2704   else if (pr->request_type == DNS_PEER_PENDING_IP_TO_NAME)
2705     {
2706       clib_memset (rir, 0, sizeof (*rir));
2707       if (vnet_dns_response_to_name (ep->dns_response, rir, &ttl))
2708         {
2709           /* clib_warning ("response_to_name failed..."); */
2710           is_fail = 1;
2711         }
2712     }
2713   else
2714     {
2715       clib_warning ("Unknown request type %d", pr->request_type);
2716       return;
2717     }
2718
2719   /* Initialize a buffer */
2720   if (b0 == 0)
2721     {
2722       if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2723         return;
2724       b0 = vlib_get_buffer (vm, bi);
2725     }
2726   else
2727     {
2728       /* Use the buffer we were handed. Reinitialize it... */
2729       vlib_buffer_t bt = { };
2730       /* push/pop the reference count */
2731       u8 save_ref_count = b0->ref_count;
2732       vlib_buffer_copy_template (b0, &bt);
2733       b0->ref_count = save_ref_count;
2734       bi = vlib_get_buffer_index (vm, b0);
2735     }
2736
2737   if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
2738     vlib_buffer_free_one (vm, b0->next_buffer);
2739
2740   /*
2741    * Reset the buffer. We recycle the DNS request packet in the cache
2742    * hit case, and reply immediately from the request node.
2743    *
2744    * In the resolution-required / deferred case, resetting a freshly-allocated
2745    * buffer won't hurt. We hope.
2746    */
2747   b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
2748                 | VLIB_BUFFER_TOTAL_LENGTH_VALID);
2749   vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;   /* "local0" */
2750   vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0;   /* default VRF for now */
2751
2752   if (!ip4_sas (0 /* default VRF for now */, ~0,
2753                 (const ip4_address_t *) &pr->dst_address, &src_address))
2754     return;
2755
2756   ip = vlib_buffer_get_current (b0);
2757   udp = (udp_header_t *) (ip + 1);
2758   dns_response = (u8 *) (udp + 1);
2759   clib_memset (ip, 0, sizeof (*ip) + sizeof (*udp));
2760
2761   /*
2762    * Start with the variadic portion of the exercise.
2763    * Turn the name into a set of DNS "labels". Max length
2764    * per label is 63, enforce that.
2765    */
2766   reply = name_to_labels (pr->name);
2767   vec_free (pr->name);
2768
2769   qp_offset = vec_len (reply);
2770
2771   /* Add space for the query header */
2772   vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
2773
2774   qp = (dns_query_t *) (reply + qp_offset);
2775
2776   if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2777     qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
2778   else
2779     qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2780
2781   qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
2782
2783   /* Punch in space for the dns_header_t */
2784   vec_insert (reply, sizeof (dns_header_t), 0);
2785
2786   dh = (dns_header_t *) reply;
2787
2788   /* Transaction ID = pool index */
2789   dh->id = pr->id;
2790
2791   /* Announce that we did a recursive lookup */
2792   tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
2793   if (is_fail)
2794     tmp |= DNS_RCODE_NAME_ERROR;
2795   dh->flags = clib_host_to_net_u16 (tmp);
2796   dh->qdcount = clib_host_to_net_u16 (1);
2797   dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
2798   dh->nscount = 0;
2799   dh->arcount = 0;
2800
2801   /* If the name resolution worked, cough up an appropriate RR */
2802   if (is_fail == 0)
2803     {
2804       /* Add the answer. First, a name pointer (0xC00C) */
2805       vec_add1 (reply, 0xC0);
2806       vec_add1 (reply, 0x0C);
2807
2808       /* Now, add single A-rec RR */
2809       if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2810         {
2811           vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
2812           rr = (dns_rr_t *) rrptr;
2813
2814           rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
2815           rr->class = clib_host_to_net_u16 (1 /* internet */ );
2816           rr->ttl = clib_host_to_net_u32 (ttl);
2817           rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
2818           ip_address_copy_addr (rr->rdata, &rn->address);
2819         }
2820       else
2821         {
2822           /* Or a single PTR RR */
2823           u8 *vecname = format (0, "%s", rir->name);
2824           u8 *label_vec = name_to_labels (vecname);
2825           vec_free (vecname);
2826
2827           vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
2828           rr = (dns_rr_t *) rrptr;
2829           rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2830           rr->class = clib_host_to_net_u16 (1 /* internet */ );
2831           rr->ttl = clib_host_to_net_u32 (ttl);
2832           rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
2833           clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
2834           vec_free (label_vec);
2835         }
2836     }
2837   clib_memcpy (dns_response, reply, vec_len (reply));
2838
2839   /* Set the packet length */
2840   b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
2841
2842   /* IP header */
2843   ip->ip_version_and_header_length = 0x45;
2844   ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
2845   ip->ttl = 255;
2846   ip->protocol = IP_PROTOCOL_UDP;
2847   ip->src_address.as_u32 = src_address.as_u32;
2848   clib_memcpy (ip->dst_address.as_u8, pr->dst_address,
2849                sizeof (ip4_address_t));
2850   ip->checksum = ip4_header_checksum (ip);
2851
2852   /* UDP header */
2853   udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
2854   udp->dst_port = pr->dst_port;
2855   udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
2856                                       vec_len (reply));
2857   udp->checksum = 0;
2858   vec_free (reply);
2859
2860   /*
2861    * Ship pkts made out of whole cloth to ip4_lookup
2862    * Caller will ship recycled dns reply packets to ip4_lookup
2863    */
2864   if (is_recycle == 0)
2865     {
2866       f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
2867       to_next = vlib_frame_vector_args (f);
2868       to_next[0] = bi;
2869       f->n_vectors = 1;
2870       vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
2871     }
2872 }
2873
2874 #include <dns/dns.api.c>
2875 static clib_error_t *
2876 dns_init (vlib_main_t * vm)
2877 {
2878   dns_main_t *dm = &dns_main;
2879
2880   dm->vnet_main = vnet_get_main ();
2881   dm->name_cache_size = 1000;
2882   dm->max_ttl_in_seconds = 86400;
2883   dm->random_seed = 0xDEADDABE;
2884   dm->api_main = vlibapi_get_main ();
2885
2886   /* Ask for a correctly-sized block of API message decode slots */
2887   dm->msg_id_base = setup_message_id_table ();
2888
2889   return 0;
2890 }
2891
2892 /* *INDENT-OFF* */
2893 VLIB_INIT_FUNCTION (dns_init) = {
2894   .init_order = VLIB_INITS ("flow_classify_init", "dns_init"),
2895 };
2896
2897 VLIB_PLUGIN_REGISTER () =
2898 {
2899   .version = VPP_BUILD_VER,
2900   .description = "Simple DNS name resolver",
2901 };
2902 /* *INDENT-ON* */
2903
2904
2905 /*
2906  * fd.io coding-style-patch-verification: ON
2907  *
2908  * Local Variables:
2909  * eval: (c-set-style "gnu")
2910  * End:
2911  */