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