304aa1868fe65985476ce2f3a8881a35eb3462cc
[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   /* binary API caller might forget to set the name. Guess how we know. */
825   if (name[0] == 0)
826     return VNET_API_ERROR_INVALID_VALUE;
827
828   dns_cache_lock (dm);
829 search_again:
830   p = hash_get_mem (dm->cache_entry_by_name, name);
831   if (p)
832     {
833       ep = pool_elt_at_index (dm->entries, p[0]);
834       if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
835         {
836           /* Has the entry expired? */
837           if (((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0)
838               && (now > ep->expiration_time))
839             {
840               int i;
841               u32 *indices_to_delete = 0;
842
843               /*
844                * Take out the rest of the resolution chain
845                * This isn't optimal, but it won't happen very often.
846                */
847               while (ep)
848                 {
849                   if ((ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME))
850                     {
851                       vec_add1 (indices_to_delete, ep - dm->entries);
852
853                       p = hash_get_mem (dm->cache_entry_by_name, ep->cname);
854                       if (!p)
855                         break;
856                       ep = pool_elt_at_index (dm->entries, p[0]);
857                     }
858                   else
859                     {
860                       vec_add1 (indices_to_delete, ep - dm->entries);
861                       break;
862                     }
863                 }
864               for (i = 0; i < vec_len (indices_to_delete); i++)
865                 {
866                   /* Reenable to watch re-resolutions */
867                   if (0)
868                     {
869                       ep = pool_elt_at_index (dm->entries,
870                                               indices_to_delete[i]);
871                       clib_warning ("Re-resolve %s", ep->name);
872                     }
873
874                   vnet_dns_delete_entry_by_index_nolock
875                     (dm, indices_to_delete[i]);
876                 }
877               vec_free (indices_to_delete);
878               /* Yes, kill it... */
879               goto re_resolve;
880             }
881
882           if (ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
883             {
884               name = ep->cname;
885               goto search_again;
886             }
887
888           /* Note: caller must drop the lock! */
889           *retp = ep;
890           return (0);
891         }
892       else
893         {
894           /*
895            * Resolution pending. Add request to the pending vector
896            * by copying the template request
897            */
898           vec_add2 (ep->pending_requests, pr, 1);
899           memcpy (pr, t, sizeof (*pr));
900           dns_cache_unlock (dm);
901           return (0);
902         }
903     }
904
905 re_resolve:
906   if (pool_elts (dm->entries) == dm->name_cache_size)
907     {
908       /* Will only fail if the cache is totally filled w/ static entries... */
909       rv = delete_random_entry (dm);
910       if (rv)
911         {
912           dns_cache_unlock (dm);
913           return rv;
914         }
915     }
916
917   /* add new hash table entry */
918   pool_get (dm->entries, ep);
919   clib_memset (ep, 0, sizeof (*ep));
920
921   ep->name = format (0, "%s%c", name, 0);
922   _vec_len (ep->name) = vec_len (ep->name) - 1;
923
924   hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
925
926   vec_add1 (dm->unresolved_entries, ep - dm->entries);
927   vec_add2 (ep->pending_requests, pr, 1);
928
929   pr->request_type = t->request_type;
930
931   /* Remember details so we can reply later... */
932   if (t->request_type == DNS_API_PENDING_NAME_TO_IP ||
933       t->request_type == DNS_API_PENDING_IP_TO_NAME)
934     {
935       pr->client_index = t->client_index;
936       pr->client_context = t->client_context;
937     }
938   else
939     {
940       pr->client_index = ~0;
941       pr->is_ip6 = t->is_ip6;
942       pr->dst_port = t->dst_port;
943       pr->id = t->id;
944       pr->name = t->name;
945       if (t->is_ip6)
946         count = 16;
947       else
948         count = 4;
949       clib_memcpy (pr->dst_address, t->dst_address, count);
950     }
951
952   vnet_send_dns_request (dm, ep);
953   dns_cache_unlock (dm);
954   return 0;
955 }
956
957 #define foreach_notification_to_move            \
958 _(pending_requests)
959
960 /**
961  * Handle cname indirection. JFC. Called with the cache locked.
962  * returns 0 if the reply is not a CNAME.
963  */
964
965 int
966 vnet_dns_cname_indirection_nolock (dns_main_t * dm, u32 ep_index, u8 * reply)
967 {
968   dns_header_t *h;
969   dns_query_t *qp;
970   dns_rr_t *rr;
971   u8 *curpos;
972   u8 *pos, *pos2;
973   u8 *cname_pos = 0;
974   int len, i;
975   u8 *cname = 0;
976   u8 *request = 0;
977   u8 *name_copy;
978   u32 qp_offset;
979   u16 flags;
980   u16 rcode;
981   dns_cache_entry_t *ep, *next_ep;
982   f64 now;
983
984   h = (dns_header_t *) reply;
985   flags = clib_net_to_host_u16 (h->flags);
986   rcode = flags & DNS_RCODE_MASK;
987
988   /* See if the response is OK */
989   switch (rcode)
990     {
991     case DNS_RCODE_NO_ERROR:
992       break;
993
994     case DNS_RCODE_NAME_ERROR:
995     case DNS_RCODE_FORMAT_ERROR:
996     case DNS_RCODE_SERVER_FAILURE:
997     case DNS_RCODE_NOT_IMPLEMENTED:
998     case DNS_RCODE_REFUSED:
999       return -1;
1000     }
1001
1002   curpos = (u8 *) (h + 1);
1003   pos = curpos;
1004   len = *pos++;
1005
1006   /* Skip the questions */
1007   for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
1008     {
1009       while (len)
1010         {
1011           pos += len;
1012           len = *pos++;
1013         }
1014       pos += sizeof (dns_query_t);
1015     }
1016   pos2 = pos;
1017   /* expect a pointer chase here for a CNAME record */
1018   if ((pos2[0] & 0xC0) == 0xC0)
1019     pos += 2;
1020   else
1021     return 0;
1022
1023   /* Walk the answer(s) to see what to do next */
1024   for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
1025     {
1026       rr = (dns_rr_t *) pos;
1027       switch (clib_net_to_host_u16 (rr->type))
1028         {
1029           /* Real address record? Done.. */
1030         case DNS_TYPE_A:
1031         case DNS_TYPE_AAAA:
1032           return 0;
1033           /*
1034            * Maybe chase a CNAME pointer?
1035            * It's not unheard-of for name-servers to return
1036            * both CNAME and A/AAAA records...
1037            */
1038         case DNS_TYPE_CNAME:
1039           cname_pos = pos;
1040           break;
1041
1042           /* Some other junk, e.g. a nameserver... */
1043         default:
1044           break;
1045         }
1046       pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1047       /* Skip name... */
1048       if ((pos2[0] & 0xc0) == 0xc0)
1049         pos += 2;
1050     }
1051
1052   /* Neither a CNAME nor a real address. Try another server */
1053   if (cname_pos == 0)
1054     {
1055       flags &= ~DNS_RCODE_MASK;
1056       flags |= DNS_RCODE_NAME_ERROR;
1057       h->flags = clib_host_to_net_u16 (flags);
1058       return -1;
1059     }
1060
1061   /* This is a CNAME record, chase the name chain. */
1062   pos = cname_pos;
1063
1064   /* The last request is no longer pending.. */
1065   for (i = 0; i < vec_len (dm->unresolved_entries); i++)
1066     if (ep_index == dm->unresolved_entries[i])
1067       {
1068         vec_delete (dm->unresolved_entries, 1, i);
1069         goto found_last_request;
1070       }
1071   clib_warning ("pool elt %d supposedly pending, but not found...", ep_index);
1072   return -1;
1073
1074 found_last_request:
1075
1076   now = vlib_time_now (dm->vlib_main);
1077   cname = vnet_dns_labels_to_name (rr->rdata, reply, &pos2);
1078   /* Save the cname */
1079   vec_add1 (cname, 0);
1080   _vec_len (cname) -= 1;
1081   ep = pool_elt_at_index (dm->entries, ep_index);
1082   ep->cname = cname;
1083   ep->flags |= (DNS_CACHE_ENTRY_FLAG_CNAME | DNS_CACHE_ENTRY_FLAG_VALID);
1084   /* Save the response */
1085   if (ep->dns_response)
1086     vec_free (ep->dns_response);
1087   ep->dns_response = reply;
1088   /* Set up expiration time */
1089   ep->expiration_time = now + clib_net_to_host_u32 (rr->ttl);
1090
1091   pool_get (dm->entries, next_ep);
1092
1093   /* Need to recompute ep post pool-get */
1094   ep = pool_elt_at_index (dm->entries, ep_index);
1095
1096   clib_memset (next_ep, 0, sizeof (*next_ep));
1097   next_ep->name = vec_dup (cname);
1098   vec_add1 (next_ep->name, 0);
1099   _vec_len (next_ep->name) -= 1;
1100
1101   hash_set_mem (dm->cache_entry_by_name, next_ep->name,
1102                 next_ep - dm->entries);
1103
1104   /* Use the same server */
1105   next_ep->server_rotor = ep->server_rotor;
1106   next_ep->server_af = ep->server_af;
1107
1108   /* Move notification data to the next name in the chain */
1109 #define _(a) next_ep->a = ep->a; ep->a = 0;
1110   foreach_notification_to_move;
1111 #undef _
1112
1113   request = name_to_labels (cname);
1114   name_copy = vec_dup (request);
1115
1116   qp_offset = vec_len (request);
1117
1118   /* Add space for the query header */
1119   vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1);
1120
1121   qp = (dns_query_t *) (request + qp_offset);
1122
1123   qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
1124   qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1125   clib_memcpy (qp, name_copy, vec_len (name_copy));
1126   qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy));
1127   vec_free (name_copy);
1128
1129   qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1130   qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1131
1132   /* Punch in space for the dns_header_t */
1133   vec_insert (request, sizeof (dns_header_t), 0);
1134
1135   h = (dns_header_t *) request;
1136
1137   /* Transaction ID = pool index */
1138   h->id = clib_host_to_net_u16 (next_ep - dm->entries);
1139
1140   /* Ask for a recursive lookup */
1141   h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY);
1142   h->qdcount = clib_host_to_net_u16 (2);
1143   h->nscount = 0;
1144   h->arcount = 0;
1145
1146   next_ep->dns_request = request;
1147   next_ep->retry_timer = now + 2.0;
1148   next_ep->retry_count = 0;
1149
1150   /*
1151    * Enable this to watch recursive resolution happen...
1152    * fformat (stdout, "%U", format_dns_reply, request, 2);
1153    */
1154
1155   vec_add1 (dm->unresolved_entries, next_ep - dm->entries);
1156   vnet_send_dns_request (dm, next_ep);
1157   return (1);
1158 }
1159
1160 int
1161 vnet_dns_response_to_reply (u8 * response,
1162                             vl_api_dns_resolve_name_reply_t * rmp,
1163                             u32 * min_ttlp)
1164 {
1165   dns_header_t *h;
1166   dns_query_t *qp;
1167   dns_rr_t *rr;
1168   int i, limit;
1169   u8 len;
1170   u8 *curpos, *pos, *pos2;
1171   u16 flags;
1172   u16 rcode;
1173   u32 ttl;
1174   int pointer_chase;
1175
1176   h = (dns_header_t *) response;
1177   flags = clib_net_to_host_u16 (h->flags);
1178   rcode = flags & DNS_RCODE_MASK;
1179
1180   /* See if the response is OK, etc. */
1181   switch (rcode)
1182     {
1183     default:
1184     case DNS_RCODE_NO_ERROR:
1185       break;
1186
1187     case DNS_RCODE_NAME_ERROR:
1188     case DNS_RCODE_FORMAT_ERROR:
1189       return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1190
1191     case DNS_RCODE_SERVER_FAILURE:
1192     case DNS_RCODE_NOT_IMPLEMENTED:
1193     case DNS_RCODE_REFUSED:
1194       return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1195     }
1196
1197   /* No answers? Loser... */
1198   if (clib_net_to_host_u16 (h->anscount) < 1)
1199     return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1200
1201   curpos = (u8 *) (h + 1);
1202
1203   /* Skip the name we asked about */
1204   pos = curpos;
1205   len = *pos++;
1206   /* Should never happen, but stil... */
1207   if ((len & 0xC0) == 0xC0)
1208     curpos += 2;
1209   else
1210     {
1211       /* skip the name / label-set */
1212       while (len)
1213         {
1214           pos += len;
1215           len = *pos++;
1216         }
1217       curpos = pos;
1218     }
1219   /* Skip queries */
1220   limit = clib_net_to_host_u16 (h->qdcount);
1221   qp = (dns_query_t *) curpos;
1222   qp += limit;
1223   curpos = (u8 *) qp;
1224
1225   /* Parse answers */
1226   limit = clib_net_to_host_u16 (h->anscount);
1227
1228   for (i = 0; i < limit; i++)
1229     {
1230       pos = pos2 = curpos;
1231       pointer_chase = 0;
1232
1233       /* Expect pointer chases in the answer section... */
1234       if ((pos2[0] & 0xC0) == 0xC0)
1235         {
1236           pos = pos2 + 2;
1237           pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1238           pointer_chase = 1;
1239         }
1240
1241       len = *pos2++;
1242
1243       while (len)
1244         {
1245           pos2 += len;
1246           if ((pos2[0] & 0xc0) == 0xc0)
1247             {
1248               /*
1249                * If we've already done one pointer chase,
1250                * do not move the pos pointer.
1251                */
1252               if (pointer_chase == 0)
1253                 pos = pos2 + 2;
1254               pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1255               len = *pos2++;
1256               pointer_chase = 1;
1257             }
1258           else
1259             len = *pos2++;
1260         }
1261
1262       if (pointer_chase == 0)
1263         pos = pos2;
1264
1265       rr = (dns_rr_t *) pos;
1266
1267       switch (clib_net_to_host_u16 (rr->type))
1268         {
1269         case DNS_TYPE_A:
1270           /* Collect an ip4 address. Do not pass go. Do not collect $200 */
1271           memcpy (rmp->ip4_address, rr->rdata, sizeof (ip4_address_t));
1272           rmp->ip4_set = 1;
1273           ttl = clib_net_to_host_u32 (rr->ttl);
1274           if (min_ttlp && *min_ttlp > ttl)
1275             *min_ttlp = ttl;
1276           break;
1277         case DNS_TYPE_AAAA:
1278           /* Collect an ip6 address. Do not pass go. Do not collect $200 */
1279           memcpy (rmp->ip6_address, rr->rdata, sizeof (ip6_address_t));
1280           ttl = clib_net_to_host_u32 (rr->ttl);
1281           if (min_ttlp && *min_ttlp > ttl)
1282             *min_ttlp = ttl;
1283           rmp->ip6_set = 1;
1284           break;
1285
1286         default:
1287           break;
1288         }
1289       /* Might as well stop ASAP */
1290       if (rmp->ip4_set && rmp->ip6_set)
1291         break;
1292       pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1293       curpos = pos;
1294     }
1295
1296   if ((rmp->ip4_set + rmp->ip6_set) == 0)
1297     return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1298   return 0;
1299 }
1300
1301 int
1302 vnet_dns_response_to_name (u8 * response,
1303                            vl_api_dns_resolve_ip_reply_t * rmp,
1304                            u32 * min_ttlp)
1305 {
1306   dns_header_t *h;
1307   dns_query_t *qp;
1308   dns_rr_t *rr;
1309   int i, limit;
1310   u8 len;
1311   u8 *curpos, *pos, *pos2;
1312   u16 flags;
1313   u16 rcode;
1314   u8 *name;
1315   u32 ttl;
1316   u8 *junk __attribute__ ((unused));
1317   int name_set = 0;
1318   int pointer_chase;
1319
1320   h = (dns_header_t *) response;
1321   flags = clib_net_to_host_u16 (h->flags);
1322   rcode = flags & DNS_RCODE_MASK;
1323
1324   /* See if the response is OK, etc. */
1325   switch (rcode)
1326     {
1327     default:
1328     case DNS_RCODE_NO_ERROR:
1329       break;
1330
1331     case DNS_RCODE_NAME_ERROR:
1332     case DNS_RCODE_FORMAT_ERROR:
1333       return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1334
1335     case DNS_RCODE_SERVER_FAILURE:
1336     case DNS_RCODE_NOT_IMPLEMENTED:
1337     case DNS_RCODE_REFUSED:
1338       return VNET_API_ERROR_NAME_SERVER_NEXT_SERVER;
1339     }
1340
1341   /* No answers? Loser... */
1342   if (clib_net_to_host_u16 (h->anscount) < 1)
1343     return VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES;
1344
1345   curpos = (u8 *) (h + 1);
1346
1347   /* Skip the name we asked about */
1348   pos = curpos;
1349   len = *pos++;
1350   /* Should never happen, but stil... */
1351   if ((len & 0xC0) == 0xC0)
1352     curpos += 2;
1353   else
1354     {
1355       /* skip the name / label-set */
1356       while (len)
1357         {
1358           pos += len;
1359           len = *pos++;
1360         }
1361       curpos = pos;
1362     }
1363   /* Skip queries */
1364   limit = clib_net_to_host_u16 (h->qdcount);
1365   qp = (dns_query_t *) curpos;
1366   qp += limit;
1367   curpos = (u8 *) qp;
1368
1369   /* Parse answers */
1370   limit = clib_net_to_host_u16 (h->anscount);
1371
1372   for (i = 0; i < limit; i++)
1373     {
1374       pos = pos2 = curpos;
1375       pointer_chase = 0;
1376
1377       /* Expect pointer chases in the answer section... */
1378       if ((pos2[0] & 0xC0) == 0xC0)
1379         {
1380           pos = pos2 + 2;
1381           pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1382           pointer_chase = 1;
1383         }
1384
1385       len = *pos2++;
1386
1387       while (len)
1388         {
1389           pos2 += len;
1390           if ((pos2[0] & 0xc0) == 0xc0)
1391             {
1392               /*
1393                * If we've already done one pointer chase,
1394                * do not move the pos pointer.
1395                */
1396               if (pointer_chase == 0)
1397                 pos = pos2 + 2;
1398               pos2 = response + ((pos2[0] & 0x3f) << 8) + pos2[1];
1399               len = *pos2++;
1400               pointer_chase = 1;
1401             }
1402           else
1403             len = *pos2++;
1404         }
1405
1406       if (pointer_chase == 0)
1407         pos = pos2;
1408
1409       rr = (dns_rr_t *) pos;
1410
1411       switch (clib_net_to_host_u16 (rr->type))
1412         {
1413         case DNS_TYPE_PTR:
1414           name = vnet_dns_labels_to_name (rr->rdata, response, &junk);
1415           memcpy (rmp->name, name, vec_len (name));
1416           ttl = clib_net_to_host_u32 (rr->ttl);
1417           if (min_ttlp)
1418             *min_ttlp = ttl;
1419           rmp->name[vec_len (name)] = 0;
1420           name_set = 1;
1421           break;
1422         default:
1423           break;
1424         }
1425       /* Might as well stop ASAP */
1426       if (name_set == 1)
1427         break;
1428       pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1429       curpos = pos;
1430     }
1431
1432   if (name_set == 0)
1433     return VNET_API_ERROR_NAME_SERVER_NO_SUCH_NAME;
1434   return 0;
1435 }
1436
1437 static void
1438 vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
1439 {
1440   dns_main_t *dm = &dns_main;
1441   vl_api_dns_resolve_name_reply_t *rmp;
1442   dns_cache_entry_t *ep;
1443   dns_pending_request_t _t0, *t0 = &_t0;
1444   int rv;
1445
1446   /* Sanitize the name slightly */
1447   mp->name[ARRAY_LEN (mp->name) - 1] = 0;
1448
1449   t0->request_type = DNS_API_PENDING_NAME_TO_IP;
1450   t0->client_index = mp->client_index;
1451   t0->client_context = mp->context;
1452
1453   rv = vnet_dns_resolve_name (dm, mp->name, t0, &ep);
1454
1455   /* Error, e.g. not enabled? Tell the user */
1456   if (rv < 0)
1457     {
1458       REPLY_MACRO (VL_API_DNS_RESOLVE_NAME_REPLY);
1459       return;
1460     }
1461
1462   /* Resolution pending? Don't reply... */
1463   if (ep == 0)
1464     return;
1465
1466   /* *INDENT-OFF* */
1467   REPLY_MACRO2(VL_API_DNS_RESOLVE_NAME_REPLY,
1468   ({
1469     rv = vnet_dns_response_to_reply (ep->dns_response, rmp, 0 /* ttl-ptr */);
1470     rmp->retval = clib_host_to_net_u32 (rv);
1471   }));
1472   /* *INDENT-ON* */
1473
1474   /*
1475    * dns_resolve_name leaves the cache locked when it returns
1476    * a cached result, so unlock it here.
1477    */
1478   dns_cache_unlock (dm);
1479 }
1480
1481 static void
1482 vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
1483 {
1484   dns_main_t *dm = &dns_main;
1485   vl_api_dns_resolve_ip_reply_t *rmp;
1486   dns_cache_entry_t *ep;
1487   int rv;
1488   int i, len;
1489   u8 *lookup_name = 0;
1490   u8 digit, nybble;
1491   dns_pending_request_t _t0, *t0 = &_t0;
1492
1493   if (mp->is_ip6)
1494     {
1495       for (i = 15; i >= 0; i--)
1496         {
1497           digit = mp->address[i];
1498           nybble = (digit & 0x0F);
1499           if (nybble > 9)
1500             vec_add1 (lookup_name, (nybble - 10) + 'a');
1501           else
1502             vec_add1 (lookup_name, nybble + '0');
1503           vec_add1 (lookup_name, '.');
1504           nybble = (digit & 0xF0) >> 4;
1505           if (nybble > 9)
1506             vec_add1 (lookup_name, (nybble - 10) + 'a');
1507           else
1508             vec_add1 (lookup_name, nybble + '0');
1509           vec_add1 (lookup_name, '.');
1510         }
1511       len = vec_len (lookup_name);
1512       vec_validate (lookup_name, len + 8);
1513       memcpy (lookup_name + len, "ip6.arpa", 8);
1514     }
1515   else
1516     {
1517       for (i = 3; i >= 0; i--)
1518         {
1519           digit = mp->address[i];
1520           lookup_name = format (lookup_name, "%d.", digit);
1521         }
1522       lookup_name = format (lookup_name, "in-addr.arpa");
1523     }
1524
1525   vec_add1 (lookup_name, 0);
1526
1527   t0->request_type = DNS_API_PENDING_IP_TO_NAME;
1528   t0->client_index = mp->client_index;
1529   t0->client_context = mp->context;
1530
1531   rv = vnet_dns_resolve_name (dm, lookup_name, t0, &ep);
1532
1533   vec_free (lookup_name);
1534
1535   /* Error, e.g. not enabled? Tell the user */
1536   if (rv < 0)
1537     {
1538       REPLY_MACRO (VL_API_DNS_RESOLVE_IP_REPLY);
1539       return;
1540     }
1541
1542   /* Resolution pending? Don't reply... */
1543   if (ep == 0)
1544     return;
1545
1546   /* *INDENT-OFF* */
1547   REPLY_MACRO2(VL_API_DNS_RESOLVE_IP_REPLY,
1548   ({
1549     rv = vnet_dns_response_to_name (ep->dns_response, rmp, 0 /* ttl-ptr */);
1550     rmp->retval = clib_host_to_net_u32 (rv);
1551   }));
1552   /* *INDENT-ON* */
1553
1554   /*
1555    * vnet_dns_resolve_name leaves the cache locked when it returns
1556    * a cached result, so unlock it here.
1557    */
1558   dns_cache_unlock (dm);
1559 }
1560
1561 #define vl_msg_name_crc_list
1562 #include <vpp/api/vpe_all_api_h.h>
1563 #undef vl_msg_name_crc_list
1564
1565 static void
1566 setup_message_id_table (api_main_t * am)
1567 {
1568 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1569   foreach_vl_msg_name_crc_dns;
1570 #undef _
1571 }
1572
1573 #define foreach_dns_api_msg                             \
1574 _(DNS_ENABLE_DISABLE, dns_enable_disable)               \
1575 _(DNS_NAME_SERVER_ADD_DEL, dns_name_server_add_del)     \
1576 _(DNS_RESOLVE_NAME, dns_resolve_name)                   \
1577 _(DNS_RESOLVE_IP, dns_resolve_ip)
1578
1579 static clib_error_t *
1580 dns_api_hookup (vlib_main_t * vm)
1581 {
1582 #define _(N,n)                                                  \
1583     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
1584                            vl_api_##n##_t_handler,              \
1585                            vl_noop_handler,                     \
1586                            vl_api_##n##_t_endian,               \
1587                            vl_api_##n##_t_print,                \
1588                            sizeof(vl_api_##n##_t), 1);
1589   foreach_dns_api_msg;
1590 #undef _
1591
1592   setup_message_id_table (&api_main);
1593   return 0;
1594 }
1595
1596 VLIB_API_INIT_FUNCTION (dns_api_hookup);
1597
1598
1599 static clib_error_t *
1600 dns_config_fn (vlib_main_t * vm, unformat_input_t * input)
1601 {
1602   dns_main_t *dm = &dns_main;
1603
1604   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1605     {
1606       if (unformat (input, "max-cache-size %u", &dm->name_cache_size))
1607         ;
1608       else if (unformat (input, "max-ttl %u", &dm->max_ttl_in_seconds))
1609         ;
1610       else
1611         return clib_error_return (0, "unknown input `%U'",
1612                                   format_unformat_error, input);
1613     }
1614   return 0;
1615 }
1616
1617 VLIB_CONFIG_FUNCTION (dns_config_fn, "dns");
1618
1619 static clib_error_t *
1620 dns_init (vlib_main_t * vm)
1621 {
1622   dns_main_t *dm = &dns_main;
1623
1624   dm->vlib_main = vm;
1625   dm->vnet_main = vnet_get_main ();
1626   dm->name_cache_size = 65535;
1627   dm->max_ttl_in_seconds = 86400;
1628   dm->random_seed = 0xDEADDABE;
1629
1630   return 0;
1631 }
1632
1633 VLIB_INIT_FUNCTION (dns_init);
1634
1635 uword
1636 unformat_dns_reply (unformat_input_t * input, va_list * args)
1637 {
1638   u8 **result = va_arg (*args, u8 **);
1639   u8 **namep = va_arg (*args, u8 **);
1640   ip4_address_t a4;
1641   ip6_address_t a6;
1642   int a4_set = 0;
1643   int a6_set = 0;
1644   u8 *name;
1645   int name_set = 0;
1646   u8 *ce;
1647   u32 qp_offset;
1648   dns_header_t *h;
1649   dns_query_t *qp;
1650   dns_rr_t *rr;
1651   u8 *rru8;
1652
1653   if (unformat (input, "%v", &name))
1654     name_set = 1;
1655
1656   if (unformat (input, "%U", unformat_ip4_address, &a4))
1657     {
1658       a4_set = 1;
1659       if (unformat (input, "%U", unformat_ip6_address, &a6))
1660         a6_set = 1;
1661     }
1662
1663   if (unformat (input, "%U", unformat_ip6_address, &a6))
1664     {
1665       a6_set = 1;
1666       if (unformat (input, "%U", unformat_ip4_address, &a6))
1667         a4_set = 1;
1668     }
1669
1670   /* Must have a name */
1671   if (!name_set)
1672     return 0;
1673
1674   /* Must have at least one address */
1675   if (!(a4_set + a6_set))
1676     return 0;
1677
1678   /* Build a fake DNS cache entry string, one hemorrhoid at a time */
1679   ce = name_to_labels (name);
1680   qp_offset = vec_len (ce);
1681
1682   /* Add space for the query header */
1683   vec_validate (ce, qp_offset + sizeof (dns_query_t) - 1);
1684   qp = (dns_query_t *) (ce + qp_offset);
1685
1686   qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL);
1687   qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1688
1689   /* Punch in space for the dns_header_t */
1690   vec_insert (ce, sizeof (dns_header_t), 0);
1691
1692   h = (dns_header_t *) ce;
1693
1694   /* Fake Transaction ID */
1695   h->id = 0xFFFF;
1696
1697   h->flags = clib_host_to_net_u16 (DNS_RD | DNS_RA);
1698   h->qdcount = clib_host_to_net_u16 (1);
1699   h->anscount = clib_host_to_net_u16 (a4_set + a6_set);
1700   h->nscount = 0;
1701   h->arcount = 0;
1702
1703   /* Now append one or two A/AAAA RR's... */
1704   if (a4_set)
1705     {
1706       /* Pointer to the name (DGMS) */
1707       vec_add1 (ce, 0xC0);
1708       vec_add1 (ce, 0x0C);
1709       vec_add2 (ce, rru8, sizeof (*rr) + 4);
1710       rr = (void *) rru8;
1711       rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
1712       rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1713       rr->ttl = clib_host_to_net_u32 (86400);
1714       rr->rdlength = clib_host_to_net_u16 (4);
1715       memcpy (rr->rdata, &a4, sizeof (a4));
1716     }
1717   if (a6_set)
1718     {
1719       /* Pointer to the name (DGMS) */
1720       vec_add1 (ce, 0xC0);
1721       vec_add1 (ce, 0x0C);
1722       vec_add2 (ce, rru8, sizeof (*rr) + 16);
1723       rr = (void *) rru8;
1724       rr->type = clib_host_to_net_u16 (DNS_TYPE_AAAA);
1725       rr->class = clib_host_to_net_u16 (DNS_CLASS_IN);
1726       rr->ttl = clib_host_to_net_u32 (86400);
1727       rr->rdlength = clib_host_to_net_u16 (16);
1728       memcpy (rr->rdata, &a6, sizeof (a6));
1729     }
1730   *result = ce;
1731   if (namep)
1732     *namep = name;
1733   else
1734     vec_free (name);
1735
1736   return 1;
1737 }
1738
1739 u8 *
1740 format_dns_query (u8 * s, va_list * args)
1741 {
1742   u8 **curpos = va_arg (*args, u8 **);
1743   int verbose = va_arg (*args, int);
1744   u8 *pos;
1745   dns_query_t *qp;
1746   int len, i;
1747   if (verbose > 1)
1748     s = format (s, "    Name: ");
1749
1750   /* Unwind execrated counted-label sheit */
1751   pos = *curpos;
1752   len = *pos++;
1753
1754   while (len)
1755     {
1756       for (i = 0; i < len; i++)
1757         vec_add1 (s, *pos++);
1758
1759       len = *pos++;
1760       if (len)
1761         vec_add1 (s, '.');
1762       else
1763         {
1764           vec_add1 (s, ':');
1765           vec_add1 (s, ' ');
1766         }
1767     }
1768
1769   qp = (dns_query_t *) pos;
1770   if (verbose > 1)
1771     {
1772       switch (clib_net_to_host_u16 (qp->type))
1773         {
1774         case DNS_TYPE_A:
1775           s = format (s, "type A\n");
1776           break;
1777         case DNS_TYPE_AAAA:
1778           s = format (s, "type AAAA\n");
1779           break;
1780         case DNS_TYPE_ALL:
1781           s = format (s, "type ALL\n");
1782           break;
1783
1784         default:
1785           s = format (s, "type %d\n", clib_net_to_host_u16 (qp->type));
1786           break;
1787         }
1788     }
1789
1790   pos += sizeof (*qp);
1791
1792   *curpos = pos;
1793   return s;
1794 }
1795
1796 /**
1797  * format dns reply data
1798  * verbose > 1, dump everything
1799  * verbose == 1, dump all A and AAAA records
1800  * verbose == 0, dump one A record, and one AAAA record
1801  */
1802
1803 u8 *
1804 format_dns_reply_data (u8 * s, va_list * args)
1805 {
1806   u8 *reply = va_arg (*args, u8 *);
1807   u8 **curpos = va_arg (*args, u8 **);
1808   int verbose = va_arg (*args, int);
1809   int *print_ip4 = va_arg (*args, int *);
1810   int *print_ip6 = va_arg (*args, int *);
1811   int len;
1812   u8 *pos, *pos2;
1813   dns_rr_t *rr;
1814   int i;
1815   int pointer_chase = 0;
1816   u16 *tp;
1817   u16 rrtype_host_byte_order;
1818
1819   pos = pos2 = *curpos;
1820
1821   if (verbose > 1)
1822     s = format (s, "    ");
1823
1824   /* chase pointer? almost always yes here... */
1825   if ((pos2[0] & 0xc0) == 0xc0)
1826     {
1827       pos = pos2 + 2;
1828       pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1829       pointer_chase = 1;
1830     }
1831
1832   len = *pos2++;
1833
1834   while (len)
1835     {
1836       for (i = 0; i < len; i++)
1837         {
1838           if (verbose > 1)
1839             vec_add1 (s, *pos2);
1840           pos2++;
1841         }
1842       if ((pos2[0] & 0xc0) == 0xc0)
1843         {
1844           /*
1845            * If we've already done one pointer chase,
1846            * do not move the pos pointer.
1847            */
1848           if (pointer_chase == 0)
1849             pos = pos2 + 2;
1850           pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1851           len = *pos2++;
1852           pointer_chase = 1;
1853         }
1854       else
1855         len = *pos2++;
1856       if (len)
1857         {
1858           if (verbose > 1)
1859             vec_add1 (s, '.');
1860         }
1861       else
1862         {
1863           if (verbose > 1)
1864             vec_add1 (s, ' ');
1865         }
1866     }
1867
1868   if (pointer_chase == 0)
1869     pos = pos2;
1870
1871   rr = (dns_rr_t *) pos;
1872   rrtype_host_byte_order = clib_net_to_host_u16 (rr->type);
1873
1874   switch (rrtype_host_byte_order)
1875     {
1876     case DNS_TYPE_A:
1877       if (verbose > 1)
1878         {
1879           s = format (s, "A: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1880                       format_ip4_address, rr->rdata);
1881         }
1882       else
1883         {
1884           if (*print_ip4)
1885             s = format (s, "%U [%u] ", format_ip4_address, rr->rdata,
1886                         clib_net_to_host_u32 (rr->ttl));
1887           if (verbose == 0)
1888             *print_ip4 = 0;
1889
1890         }
1891       pos += sizeof (*rr) + 4;
1892       break;
1893
1894     case DNS_TYPE_AAAA:
1895       if (verbose > 1)
1896         {
1897           s = format (s, "AAAA: ttl %d %U\n", clib_net_to_host_u32 (rr->ttl),
1898                       format_ip6_address, rr->rdata);
1899         }
1900       else
1901         {
1902           if (*print_ip6)
1903             s = format (s, "%U [%u] ", format_ip6_address, rr->rdata,
1904                         clib_net_to_host_u32 (rr->ttl));
1905           if (verbose == 0)
1906             *print_ip6 = 0;
1907         }
1908       pos += sizeof (*rr) + 16;
1909       break;
1910
1911     case DNS_TYPE_TEXT:
1912       if (verbose > 1)
1913         {
1914           s = format (s, "TEXT: ");
1915           for (i = 0; i < clib_net_to_host_u16 (rr->rdlength); i++)
1916             vec_add1 (s, rr->rdata[i]);
1917           vec_add1 (s, '\n');
1918         }
1919       pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1920       break;
1921
1922     case DNS_TYPE_HINFO:
1923       {
1924         /* Two counted strings. DGMS */
1925         u8 *len;
1926         u8 *curpos;
1927         int i;
1928         if (verbose > 1)
1929           {
1930             s = format (s, "HINFO: ");
1931             len = rr->rdata;
1932             curpos = len + 1;
1933             for (i = 0; i < *len; i++)
1934               vec_add1 (s, *curpos++);
1935
1936             vec_add1 (s, ' ');
1937             len = curpos++;
1938             for (i = 0; i < *len; i++)
1939               vec_add1 (s, *curpos++);
1940
1941             vec_add1 (s, '\n');
1942           }
1943       }
1944       pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1945       break;
1946
1947     case DNS_TYPE_NAMESERVER:
1948       if (verbose > 1)
1949         {
1950           s = format (s, "Nameserver: ");
1951           pos2 = rr->rdata;
1952
1953           /* chase pointer? */
1954           if ((pos2[0] & 0xc0) == 0xc0)
1955             {
1956               pos = pos2 + 2;
1957               pos2 = reply + ((pos2[0] & 0x3f) << 8) + pos2[1];
1958             }
1959
1960           len = *pos2++;
1961
1962           while (len)
1963             {
1964               for (i = 0; i < len; i++)
1965                 vec_add1 (s, *pos2++);
1966
1967               /* chase pointer, typically to offset 12... */
1968               if (pos2[0] == 0xC0)
1969                 pos2 = reply + pos2[1];
1970
1971               len = *pos2++;
1972               if (len)
1973                 vec_add1 (s, '.');
1974               else
1975                 vec_add1 (s, '\n');
1976             }
1977         }
1978       pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
1979       break;
1980
1981     case DNS_TYPE_MAIL_EXCHANGE:
1982       if (verbose > 1)
1983         {
1984           tp = (u16 *) rr->rdata;
1985
1986           s = format (s, "Mail Exchange: Preference %d ", (u32)
1987                       clib_net_to_host_u16 (*tp));
1988
1989           pos2 = rr->rdata + 2;
1990
1991           /* chase pointer? */
1992           if (pos2[0] == 0xc0)
1993             pos2 = reply + pos2[1];
1994
1995           len = *pos2++;
1996
1997           while (len)
1998             {
1999               for (i = 0; i < len; i++)
2000                 vec_add1 (s, *pos2++);
2001
2002               /* chase pointer */
2003               if (pos2[0] == 0xC0)
2004                 pos2 = reply + pos2[1];
2005
2006               len = *pos2++;
2007               if (len)
2008                 vec_add1 (s, '.');
2009               else
2010                 vec_add1 (s, '\n');
2011             }
2012         }
2013
2014       pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2015       break;
2016
2017     case DNS_TYPE_PTR:
2018     case DNS_TYPE_CNAME:
2019       if (verbose > 1)
2020         {
2021           tp = (u16 *) rr->rdata;
2022
2023           if (rrtype_host_byte_order == DNS_TYPE_CNAME)
2024             s = format (s, "CNAME: ");
2025           else
2026             s = format (s, "PTR: ");
2027
2028           pos2 = rr->rdata;
2029
2030           /* chase pointer? */
2031           if (pos2[0] == 0xc0)
2032             pos2 = reply + pos2[1];
2033
2034           len = *pos2++;
2035
2036           while (len)
2037             {
2038               for (i = 0; i < len; i++)
2039                 vec_add1 (s, *pos2++);
2040
2041               /* chase pointer */
2042               if (pos2[0] == 0xC0)
2043                 pos2 = reply + pos2[1];
2044
2045               len = *pos2++;
2046               if (len)
2047                 vec_add1 (s, '.');
2048               else
2049                 vec_add1 (s, '\n');
2050             }
2051         }
2052       pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2053       break;
2054
2055     default:
2056       if (verbose > 1)
2057         s = format (s, "type %d: len %d\n",
2058                     (int) clib_net_to_host_u16 (rr->type),
2059                     sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength));
2060       pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength);
2061       break;
2062     }
2063
2064   *curpos = pos;
2065
2066   return s;
2067 }
2068
2069 u8 *
2070 format_dns_reply (u8 * s, va_list * args)
2071 {
2072   u8 *reply_as_u8 = va_arg (*args, u8 *);
2073   int verbose = va_arg (*args, int);
2074   dns_header_t *h;
2075   u16 id, flags;
2076   u8 *curpos;
2077   int i;
2078   int print_ip4 = 1;
2079   int print_ip6 = 1;
2080
2081   h = (dns_header_t *) reply_as_u8;
2082   id = clib_net_to_host_u16 (h->id);
2083   flags = clib_net_to_host_u16 (h->flags);
2084
2085   if (verbose > 1)
2086     {
2087       s = format (s, "DNS %s: id %d\n", (flags & DNS_QR) ? "reply" : "query",
2088                   id);
2089       s = format (s, "  %s %s %s %s\n",
2090                   (flags & DNS_RA) ? "recur" : "no-recur",
2091                   (flags & DNS_RD) ? "recur-des" : "no-recur-des",
2092                   (flags & DNS_TC) ? "trunc" : "no-trunc",
2093                   (flags & DNS_AA) ? "auth" : "non-auth");
2094       s = format (s, "  %d queries, %d answers, %d name-servers,"
2095                   " %d add'l recs\n",
2096                   clib_net_to_host_u16 (h->qdcount),
2097                   clib_net_to_host_u16 (h->anscount),
2098                   clib_net_to_host_u16 (h->nscount),
2099                   clib_net_to_host_u16 (h->arcount));
2100     }
2101
2102   curpos = (u8 *) (h + 1);
2103
2104   if (h->qdcount)
2105     {
2106       if (verbose > 1)
2107         s = format (s, "  Queries:\n");
2108       for (i = 0; i < clib_net_to_host_u16 (h->qdcount); i++)
2109         {
2110           /* The query is variable-length, so curpos is a value-result parm */
2111           s = format (s, "%U", format_dns_query, &curpos, verbose);
2112         }
2113     }
2114   if (h->anscount)
2115     {
2116       if (verbose > 1)
2117         s = format (s, "  Replies:\n");
2118
2119       for (i = 0; i < clib_net_to_host_u16 (h->anscount); i++)
2120         {
2121           /* curpos is a value-result parm */
2122           s = format (s, "%U", format_dns_reply_data, reply_as_u8, &curpos,
2123                       verbose, &print_ip4, &print_ip6);
2124         }
2125     }
2126   return s;
2127 }
2128
2129 u8 *
2130 format_dns_cache (u8 * s, va_list * args)
2131 {
2132   dns_main_t *dm = va_arg (*args, dns_main_t *);
2133   f64 now = va_arg (*args, f64);
2134   int verbose = va_arg (*args, int);
2135   u8 *name = va_arg (*args, u8 *);
2136   dns_cache_entry_t *ep;
2137   char *ss;
2138   uword *p;
2139
2140   if (dm->is_enabled == 0)
2141     {
2142       s = format (s, "The DNS cache is disabled...");
2143       return s;
2144     }
2145
2146   if (pool_elts (dm->entries) == 0)
2147     {
2148       s = format (s, "The DNS cache is empty...");
2149       return s;
2150     }
2151
2152   dns_cache_lock (dm);
2153
2154   if (name)
2155     {
2156       p = hash_get_mem (dm->cache_entry_by_name, name);
2157       if (!p)
2158         {
2159           s = format (s, "%s is not in the cache...", name);
2160           dns_cache_unlock (dm);
2161           return (s);
2162         }
2163
2164       ep = pool_elt_at_index (dm->entries, p[0]);
2165       /* Magic to spit out a C-initializer to research hemorrhoids... */
2166       if (verbose == 3)
2167         {
2168           int i, j;
2169           s = format (s, "static u8 dns_reply_data_initializer[] =\n");
2170           s = format (s, "{\n");
2171           j = 0;
2172           for (i = 0; i < vec_len (ep->dns_response); i++)
2173             {
2174               if (j++ == 8)
2175                 {
2176                   j = 0;
2177                   vec_add1 (s, '\n');
2178                 }
2179               s = format (s, "0x%02x, ", ep->dns_response[i]);
2180             }
2181           s = format (s, "};\n");
2182         }
2183       else
2184         {
2185           if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2186             {
2187               ASSERT (ep->dns_response);
2188               if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2189                 ss = "[S] ";
2190               else
2191                 ss = "    ";
2192
2193               if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2194                 s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2195               else
2196                 s = format (s, "%s%s -> %U", ss, ep->name,
2197                             format_dns_reply, ep->dns_response, verbose);
2198               if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2199                 {
2200                   f64 time_left = ep->expiration_time - now;
2201                   if (time_left > 0.0)
2202                     s = format (s, "  TTL left %.1f", time_left);
2203                   else
2204                     s = format (s, "  EXPIRED");
2205                 }
2206             }
2207           else
2208             {
2209               ASSERT (ep->dns_request);
2210               s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2211                           verbose);
2212             }
2213           vec_add1 (s, '\n');
2214         }
2215       return s;
2216     }
2217
2218   s = format (s, "DNS cache contains %d entries\n", pool_elts (dm->entries));
2219
2220   if (verbose > 0)
2221     {
2222       /* *INDENT-OFF* */
2223       pool_foreach (ep, dm->entries,
2224       ({
2225         if (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID)
2226           {
2227             ASSERT (ep->dns_response);
2228             if (ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC)
2229               ss = "[S] ";
2230             else
2231               ss = "    ";
2232
2233             if (verbose < 2 && ep->flags & DNS_CACHE_ENTRY_FLAG_CNAME)
2234               s = format (s, "%s%s -> %s", ss, ep->name, ep->cname);
2235             else
2236               s = format (s, "%s%s -> %U", ss, ep->name,
2237                           format_dns_reply,
2238                           ep->dns_response,
2239                           verbose);
2240             if (!(ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC))
2241               {
2242                 f64 time_left = ep->expiration_time - now;
2243                 if (time_left > 0.0)
2244                   s = format (s, "  TTL left %.1f", time_left);
2245                 else
2246                   s = format (s, "  EXPIRED");
2247
2248                 if (verbose > 2)
2249                   s = format (s, "    %d client notifications pending\n",
2250                               vec_len(ep->pending_requests));
2251               }
2252           }
2253         else
2254           {
2255             ASSERT (ep->dns_request);
2256             s = format (s, "[P] %U", format_dns_reply, ep->dns_request,
2257                         verbose);
2258           }
2259         vec_add1 (s, '\n');
2260       }));
2261       /* *INDENT-ON* */
2262     }
2263
2264   dns_cache_unlock (dm);
2265
2266   return s;
2267 }
2268
2269 static clib_error_t *
2270 show_dns_cache_command_fn (vlib_main_t * vm,
2271                            unformat_input_t * input, vlib_cli_command_t * cmd)
2272 {
2273   dns_main_t *dm = &dns_main;
2274   int verbose = 0;
2275   u8 *name = 0;
2276   f64 now = vlib_time_now (vm);
2277
2278   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2279     {
2280       if (unformat (input, "verbose %d", &verbose))
2281         ;
2282       else if (unformat (input, "verbose"))
2283         verbose = 1;
2284       else if (unformat (input, "name %s", &name))
2285         ;
2286       else
2287         return clib_error_return (0, "unknown input `%U'",
2288                                   format_unformat_error, input);
2289     }
2290
2291   vlib_cli_output (vm, "%U", format_dns_cache, dm, now, verbose, name);
2292
2293   return 0;
2294 }
2295
2296 /* *INDENT-OFF* */
2297 VLIB_CLI_COMMAND (show_dns_cache_command) =
2298 {
2299   .path = "show dns cache",
2300   .short_help = "show dns cache [verbose [nn]]",
2301   .function = show_dns_cache_command_fn,
2302 };
2303 /* *INDENT-ON* */
2304
2305 static clib_error_t *
2306 dns_cache_add_del_command_fn (vlib_main_t * vm,
2307                               unformat_input_t * input,
2308                               vlib_cli_command_t * cmd)
2309 {
2310   dns_main_t *dm = &dns_main;
2311   u8 *dns_reply_data;
2312   u8 *name;
2313   int is_add = -1;
2314   int is_clear = -1;
2315   int rv;
2316   clib_error_t *error;
2317
2318   if (unformat (input, "add"))
2319     is_add = 1;
2320   if (unformat (input, "del"))
2321     is_add = 0;
2322   if (unformat (input, "clear"))
2323     is_clear = 1;
2324
2325   if (is_add == -1 && is_clear == -1)
2326     return clib_error_return (0, "add / del / clear required...");
2327
2328   if (is_clear == 1)
2329     {
2330       rv = dns_cache_clear (dm);
2331       switch (rv)
2332         {
2333         case 0:
2334           return 0;
2335
2336         case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2337           error = clib_error_return (0, "Name resolution not enabled");
2338           return error;
2339         }
2340     }
2341
2342   /* Delete (by name)? */
2343   if (is_add == 0)
2344     {
2345       if (unformat (input, "%v", &name))
2346         {
2347           rv = dns_delete_by_name (dm, name);
2348           switch (rv)
2349             {
2350             case VNET_API_ERROR_NO_SUCH_ENTRY:
2351               error = clib_error_return (0, "%v not in the cache...", name);
2352               vec_free (name);
2353               return error;
2354
2355             case VNET_API_ERROR_NAME_RESOLUTION_NOT_ENABLED:
2356               error = clib_error_return (0, "Name resolution not enabled");
2357               vec_free (name);
2358               return error;
2359
2360             case 0:
2361               vec_free (name);
2362               return 0;
2363
2364             default:
2365               error = clib_error_return (0, "dns_delete_by_name returned %d",
2366                                          rv);
2367               vec_free (name);
2368               return error;
2369             }
2370         }
2371       return clib_error_return (0, "unknown input `%U'",
2372                                 format_unformat_error, input);
2373     }
2374
2375   /* Note: dns_add_static_entry consumes the name vector if OK... */
2376   if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data, &name))
2377     {
2378       rv = dns_add_static_entry (dm, name, dns_reply_data);
2379       switch (rv)
2380         {
2381         case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
2382           vec_free (name);
2383           vec_free (dns_reply_data);
2384           return clib_error_return (0, "%v already in the cache...", name);
2385         case 0:
2386           return 0;
2387
2388         default:
2389           return clib_error_return (0, "dns_add_static_entry returned %d",
2390                                     rv);
2391         }
2392     }
2393
2394   return 0;
2395 }
2396
2397 /* *INDENT-OFF* */
2398 VLIB_CLI_COMMAND (dns_cache_add_del_command) =
2399 {
2400   .path = "dns cache",
2401   .short_help = "dns cache [add|del|clear] <name> [ip4][ip6]",
2402   .function = dns_cache_add_del_command_fn,
2403 };
2404 /* *INDENT-ON* */
2405
2406 #define DNS_FORMAT_TEST 1
2407
2408 #if DNS_FORMAT_TEST > 0
2409 #if 0
2410 /* yahoo.com */
2411 static u8 dns_reply_data_initializer[] =
2412   { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x5,
2413   0x79, 0x61, 0x68, 0x6f, 0x6f, 0x3, 0x63, 0x6f, 0x6d,
2414   0x0,                          /* null lbl */
2415   0x0, 0xff,                    /* type ALL */
2416   0x0, 0x1,                     /* class IN */
2417   0xc0, 0xc,                    /* pointer to yahoo.com name */
2418   0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x24, 0x23,
2419   0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72,
2420   0x65, 0x63, 0x74, 0x3d, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x6d, 0x61, 0x69,
2421   0x6c, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0xc0,
2422   0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73,
2423   0x35, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0,
2424   0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2425   0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc,
2426   0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x32,
2427   0xc0, 0xc, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x50, 0xd4, 0x0, 0x6,
2428   0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0,
2429   0x6, 0x5c, 0x0, 0x19, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x36, 0x3, 0x61,
2430   0x6d, 0x30, 0x8, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x64, 0x6e, 0x73, 0x3,
2431   0x6e,
2432   0x65, 0x74, 0x0, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0,
2433   0x9, 0x0, 0x1, 0x4, 0x6d, 0x74, 0x61, 0x37, 0xc0, 0xb8, 0xc0, 0xc, 0x0,
2434   0xf, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x9, 0x0, 0x1, 0x4, 0x6d, 0x74,
2435   0x61, 0x35, 0xc0, 0xb8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2436   0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x44, 0x2, 0x4, 0x0, 0x0,
2437   0x0,
2438   0x0, 0x0, 0x0, 0x0, 0xa7, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2439   0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0xc, 0xa, 0x6, 0x0, 0x0, 0x0,
2440   0x0, 0x0, 0x2, 0x40, 0x8, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x6,
2441   0x5c, 0x0, 0x10, 0x20, 0x1, 0x49, 0x98, 0x0, 0x58, 0xc, 0x2, 0x0, 0x0,
2442   0x0,
2443   0x0, 0x0, 0x0, 0x0, 0xa9, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x6,
2444   0x5c, 0x0, 0x4, 0x62, 0x8a, 0xfd, 0x6d, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1,
2445   0x0,
2446   0x0, 0x6, 0x5c, 0x0, 0x4, 0xce, 0xbe, 0x24, 0x2d, 0xc0, 0xc, 0x0, 0x1,
2447   0x0,
2448   0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x4, 0x62, 0x8b, 0xb4, 0x95, 0xc0, 0xc,
2449   0x0,
2450   0x6, 0x0, 0x1, 0x0, 0x0, 0x6, 0x5c, 0x0, 0x2d, 0xc0, 0x7b, 0xa, 0x68,
2451   0x6f,
2452   0x73, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x9, 0x79, 0x61, 0x68,
2453   0x6f, 0x6f, 0x2d, 0x69, 0x6e, 0x63, 0xc0, 0x12, 0x78, 0x3a, 0x85, 0x44,
2454   0x0, 0x0, 0xe, 0x10, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x1b, 0xaf, 0x80, 0x0, 0x0,
2455   0x2, 0x58
2456 };
2457
2458 /* www.cisco.com, has no addresses in reply */
2459 static u8 dns_reply_data_initializer[] = {
2460   0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2461   0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x05,
2462   0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f, 0x6d,
2463
2464   0x00, 0x00, 0xff, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
2465   0x00, 0x01, 0x00, 0x00, 0x0b, 0xd3, 0x00, 0x1a, 0x03,
2466   0x77, 0x77, 0x77, 0x05, 0x63, 0x69, 0x73, 0x63, 0x6f,
2467   0x03, 0x63, 0x6f, 0x6d, 0x06, 0x61, 0x6b, 0x61, 0x64,
2468   0x6e, 0x73, 0x03, 0x6e, 0x65, 0x74, 0x00,
2469 };
2470
2471 /* bind8 (linux widget, w/ nasty double pointer chasees */
2472 static u8 dns_reply_data_initializer[] = {
2473   /* 0 */
2474   0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08,
2475   /* 8 */
2476   0x00, 0x06, 0x00, 0x06, 0x0a, 0x6f, 0x72, 0x69,
2477   /* 16 */
2478   0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77, 0x77, 0x05,
2479   /* 24 */
2480   0x63, 0x69, 0x73, 0x63, 0x6f, 0x03, 0x63, 0x6f,
2481   /* 32 */
2482   0x6d, 0x00, 0x00, 0xff, 0x00, 0x01, 0x0a, 0x6f,
2483   /* 40 */
2484   0x72, 0x69, 0x67, 0x69, 0x6e, 0x2d, 0x77, 0x77,
2485   /* 48 */
2486   0x77, 0x05, 0x43, 0x49, 0x53, 0x43, 0x4f, 0xc0,
2487
2488   /* 56 */
2489   0x1d, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2490
2491   /* 64 */
2492   0x9a, 0x00, 0x18, 0x15, 0x72, 0x63, 0x64,
2493   0x6e, 0x39, 0x2d, 0x31, 0x34, 0x70, 0x2d, 0x64, 0x63,
2494   0x7a, 0x30, 0x35, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31,
2495   0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00, 0x01, 0x00,
2496   0x00, 0x05, 0x9a, 0x00, 0x1a, 0x17, 0x61, 0x6c, 0x6c,
2497   0x6e, 0x30, 0x31, 0x2d, 0x61, 0x67, 0x30, 0x39, 0x2d,
2498   0x64, 0x63, 0x7a, 0x30, 0x33, 0x6e, 0x2d, 0x67, 0x73,
2499   0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02, 0x00,
2500   0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x10, 0x0d, 0x72,
2501   0x74, 0x70, 0x35, 0x2d, 0x64, 0x6d, 0x7a, 0x2d, 0x67,
2502   0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2503   0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x18, 0x15,
2504   0x6d, 0x74, 0x76, 0x35, 0x2d, 0x61, 0x70, 0x31, 0x30,
2505   0x2d, 0x64, 0x63, 0x7a, 0x30, 0x36, 0x6e, 0x2d, 0x67,
2506   0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0, 0x26, 0x00, 0x02,
2507   0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x1b, 0x18,
2508   0x73, 0x6e, 0x67, 0x64, 0x63, 0x30, 0x31, 0x2d, 0x61,
2509   0x62, 0x30, 0x37, 0x2d, 0x64, 0x63, 0x7a, 0x30, 0x31,
2510   0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0, 0x17, 0xc0,
2511   0x26, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a,
2512   0x00, 0x1a, 0x17, 0x61, 0x65, 0x72, 0x30, 0x31, 0x2d,
2513   0x72, 0x34, 0x63, 0x32, 0x35, 0x2d, 0x64, 0x63, 0x7a,
2514   0x30, 0x31, 0x6e, 0x2d, 0x67, 0x73, 0x73, 0x31, 0xc0,
2515   0x17, 0xc0, 0x26, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2516   0x00, 0x81, 0x00, 0x04, 0x48, 0xa3, 0x04, 0xa1, 0xc0,
2517   0x26, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82,
2518   0x00, 0x10, 0x20, 0x01, 0x04, 0x20, 0x12, 0x01, 0x00,
2519   0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
2520   0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05,
2521   0x9a, 0x00, 0x02, 0xc0, 0xf4, 0xc0, 0x0c, 0x00, 0x02,
2522   0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0,
2523   0xcd, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00,
2524   0x05, 0x9a, 0x00, 0x02, 0xc0, 0x8d, 0xc0, 0x0c, 0x00,
2525   0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00, 0x02,
2526   0xc0, 0x43, 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00,
2527   0x00, 0x05, 0x9a, 0x00, 0x02, 0xc0, 0xa9, 0xc0, 0x0c,
2528   0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x05, 0x9a, 0x00,
2529   0x02, 0xc0, 0x67, 0xc0, 0x8d, 0x00, 0x01, 0x00, 0x01,
2530   0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0x40, 0x66, 0xf6,
2531   0x05, 0xc0, 0xa9, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
2532   0x07, 0x08, 0x00, 0x04, 0xad, 0x24, 0xe0, 0x64, 0xc0,
2533   0x43, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08,
2534   0x00, 0x04, 0x48, 0xa3, 0x04, 0x1c, 0xc0, 0xf4, 0x00,
2535   0x01, 0x00, 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04,
2536   0xad, 0x26, 0xd4, 0x6c, 0xc0, 0x67, 0x00, 0x01, 0x00,
2537   0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x25,
2538   0x90, 0x64, 0xc0, 0xcd, 0x00, 0x01, 0x00, 0x01, 0x00,
2539   0x00, 0x07, 0x08, 0x00, 0x04, 0xad, 0x27, 0x70, 0x44,
2540 };
2541
2542 /* google.com */
2543 static u8 dns_reply_data_initializer[] =
2544   { 0x0, 0x0, 0x81, 0x80, 0x0, 0x1, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x6,
2545   0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0xff,
2546   0x0, 0x1, 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x4,
2547   0xac, 0xd9, 0x3, 0x2e, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x1,
2548   0x2b,
2549   0x0, 0x10, 0x26, 0x7, 0xf8, 0xb0, 0x40, 0x4, 0x8, 0xf, 0x0, 0x0, 0x0, 0x0,
2550   0x0, 0x0, 0x20, 0xe, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f,
2551   0x0, 0x6, 0x3, 0x6e, 0x73, 0x31, 0xc0, 0xc, 0xc0, 0xc, 0x0, 0x6, 0x0, 0x1,
2552   0x0, 0x0, 0x0, 0x3b, 0x0, 0x22, 0xc0, 0x54, 0x9, 0x64, 0x6e, 0x73, 0x2d,
2553   0x61, 0x64, 0x6d, 0x69, 0x6e, 0xc0, 0xc, 0xa, 0x3d, 0xc7, 0x30, 0x0, 0x0,
2554   0x3, 0x84, 0x0, 0x0, 0x3, 0x84, 0x0, 0x0, 0x7, 0x8, 0x0, 0x0, 0x0, 0x3c,
2555   0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x11, 0x0, 0x1e,
2556   0x4, 0x61, 0x6c, 0x74, 0x32, 0x5, 0x61, 0x73, 0x70, 0x6d, 0x78, 0x1, 0x6c,
2557   0xc0, 0xc, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x4,
2558   0x0, 0xa, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0xe, 0xf,
2559   0x0, 0x24, 0x23, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e,
2560   0x63, 0x6c, 0x75, 0x64, 0x65, 0x3a, 0x5f, 0x73, 0x70, 0x66, 0x2e, 0x67,
2561   0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x7e, 0x61,
2562   0x6c, 0x6c, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1, 0x51, 0x7f, 0x0, 0x6,
2563   0x3, 0x6e, 0x73, 0x32, 0xc0, 0xc, 0xc0, 0xc, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1,
2564   0x51, 0x7f, 0x0, 0xf, 0x0, 0x5, 0x69, 0x73, 0x73, 0x75, 0x65, 0x70, 0x6b,
2565   0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0,
2566   0x1, 0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x34, 0xc0, 0xc, 0xc0, 0xc,
2567   0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x28, 0x4, 0x61,
2568   0x6c, 0x74, 0x33, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x1,
2569   0x51, 0x7f, 0x0, 0x6, 0x3, 0x6e, 0x73, 0x33, 0xc0, 0xc, 0xc0, 0xc, 0x0,
2570   0xf, 0x0, 0x1, 0x0, 0x0, 0x2, 0x57, 0x0, 0x9, 0x0, 0x32, 0x4, 0x61, 0x6c,
2571   0x74, 0x34, 0xc0, 0x9b, 0xc0, 0xc, 0x0, 0xf, 0x0, 0x1, 0x0, 0x0, 0x2,
2572   0x57,
2573   0x0, 0x9, 0x0, 0x14, 0x4, 0x61, 0x6c, 0x74, 0x31, 0xc0, 0x9b
2574 };
2575
2576 #else
2577 /* www.weatherlink.com */
2578 static u8 dns_reply_data_initializer[] = {
2579   0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
2580   0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x0b,
2581   0x77, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x6c, 0x69,
2582   0x6e, 0x6b, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0xff,
2583   0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00,
2584   0x00, 0x0c, 0x9e, 0x00, 0x1f, 0x0e, 0x64, 0x33, 0x6b,
2585   0x72, 0x30, 0x67, 0x75, 0x62, 0x61, 0x31, 0x64, 0x76,
2586   0x77, 0x66, 0x0a, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x66,
2587   0x72, 0x6f, 0x6e, 0x74, 0x03, 0x6e, 0x65, 0x74, 0x00,
2588 };
2589
2590 #endif
2591
2592 static clib_error_t *
2593 test_dns_fmt_command_fn (vlib_main_t * vm,
2594                          unformat_input_t * input, vlib_cli_command_t * cmd)
2595 {
2596   u8 *dns_reply_data = 0;
2597   int verbose = 0;
2598   int rv;
2599   vl_api_dns_resolve_name_reply_t _rm, *rmp = &_rm;
2600
2601   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2602     {
2603       if (unformat (input, "verbose %d", &verbose))
2604         ;
2605       else if (unformat (input, "verbose"))
2606         verbose = 1;
2607       else
2608         return clib_error_return (0, "unknown input `%U'",
2609                                   format_unformat_error, input);
2610     }
2611
2612   vec_validate (dns_reply_data, ARRAY_LEN (dns_reply_data_initializer) - 1);
2613
2614   memcpy (dns_reply_data, dns_reply_data_initializer,
2615           ARRAY_LEN (dns_reply_data_initializer));
2616
2617   vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2618
2619   clib_memset (rmp, 0, sizeof (*rmp));
2620
2621   rv = vnet_dns_response_to_reply (dns_reply_data, rmp, 0 /* ttl-ptr */ );
2622
2623   switch (rv)
2624     {
2625     case VNET_API_ERROR_NAME_SERVER_NO_ADDRESSES:
2626       vlib_cli_output (vm, "no addresses found...");
2627       break;
2628
2629     default:
2630       vlib_cli_output (vm, "response to reply returned %d", rv);
2631       break;
2632
2633     case 0:
2634       if (rmp->ip4_set)
2635         vlib_cli_output (vm, "ip4 address: %U", format_ip4_address,
2636                          (ip4_address_t *) rmp->ip4_address);
2637       if (rmp->ip6_set)
2638         vlib_cli_output (vm, "ip6 address: %U", format_ip6_address,
2639                          (ip6_address_t *) rmp->ip6_address);
2640       break;
2641     }
2642
2643   vec_free (dns_reply_data);
2644
2645   return 0;
2646 }
2647
2648
2649 /* *INDENT-OFF* */
2650 VLIB_CLI_COMMAND (test_dns_fmt_command) =
2651 {
2652   .path = "test dns format",
2653   .short_help = "test dns format",
2654   .function = test_dns_fmt_command_fn,
2655 };
2656 /* *INDENT-ON* */
2657
2658 static clib_error_t *
2659 test_dns_unfmt_command_fn (vlib_main_t * vm,
2660                            unformat_input_t * input, vlib_cli_command_t * cmd)
2661 {
2662   u8 *dns_reply_data = 0;
2663   int verbose = 0;
2664   int reply_set = 0;
2665
2666   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2667     {
2668       if (unformat (input, "verbose %d", &verbose))
2669         ;
2670       else if (unformat (input, "verbose"))
2671         verbose = 1;
2672       else if (unformat (input, "%U", unformat_dns_reply, &dns_reply_data))
2673         reply_set = 1;
2674       else
2675         return clib_error_return (0, "unknown input `%U'",
2676                                   format_unformat_error, input);
2677     }
2678
2679   if (reply_set == 0)
2680     return clib_error_return (0, "dns data not set...");
2681
2682   vlib_cli_output (vm, "%U", format_dns_reply, dns_reply_data, verbose);
2683
2684   vec_free (dns_reply_data);
2685
2686   return 0;
2687 }
2688
2689 /* *INDENT-OFF* */
2690 VLIB_CLI_COMMAND (test_dns_unfmt_command) =
2691 {
2692   .path = "test dns unformat",
2693   .short_help = "test dns unformat <name> [ip4][ip6]",
2694   .function = test_dns_unfmt_command_fn,
2695 };
2696 /* *INDENT-ON* */
2697
2698 static clib_error_t *
2699 test_dns_expire_command_fn (vlib_main_t * vm,
2700                             unformat_input_t * input,
2701                             vlib_cli_command_t * cmd)
2702 {
2703   dns_main_t *dm = &dns_main;
2704   u8 *name = 0;
2705   uword *p;
2706   clib_error_t *e;
2707   dns_cache_entry_t *ep;
2708
2709   if (unformat (input, "%v", &name))
2710     {
2711       vec_add1 (name, 0);
2712       _vec_len (name) -= 1;
2713     }
2714   else
2715     return clib_error_return (0, "no name provided");
2716
2717   dns_cache_lock (dm);
2718
2719   p = hash_get_mem (dm->cache_entry_by_name, name);
2720   if (!p)
2721     {
2722       dns_cache_unlock (dm);
2723       e = clib_error_return (0, "%s is not in the cache...", name);
2724       vec_free (name);
2725       return e;
2726     }
2727
2728   ep = pool_elt_at_index (dm->entries, p[0]);
2729
2730   ep->expiration_time = 0;
2731
2732   return 0;
2733 }
2734
2735 /* *INDENT-OFF* */
2736 VLIB_CLI_COMMAND (test_dns_expire_command) =
2737 {
2738   .path = "test dns expire",
2739   .short_help = "test dns expire <name>",
2740   .function = test_dns_expire_command_fn,
2741 };
2742 /* *INDENT-ON* */
2743 #endif
2744
2745 void
2746 vnet_send_dns6_reply (dns_main_t * dm, dns_pending_request_t * pr,
2747                       dns_cache_entry_t * ep, vlib_buffer_t * b0)
2748 {
2749   clib_warning ("Unimplemented...");
2750 }
2751
2752
2753 void
2754 vnet_send_dns4_reply (dns_main_t * dm, dns_pending_request_t * pr,
2755                       dns_cache_entry_t * ep, vlib_buffer_t * b0)
2756 {
2757   vlib_main_t *vm = dm->vlib_main;
2758   u32 bi = 0;
2759   fib_prefix_t prefix;
2760   fib_node_index_t fei;
2761   u32 sw_if_index, fib_index;
2762   ip4_main_t *im4 = &ip4_main;
2763   ip_lookup_main_t *lm4 = &im4->lookup_main;
2764   ip_interface_address_t *ia = 0;
2765   ip4_address_t *src_address;
2766   ip4_header_t *ip;
2767   udp_header_t *udp;
2768   dns_header_t *dh;
2769   vlib_frame_t *f;
2770   u32 *to_next;
2771   u8 *dns_response;
2772   u8 *reply;
2773   vl_api_dns_resolve_name_reply_t _rnr, *rnr = &_rnr;
2774   vl_api_dns_resolve_ip_reply_t _rir, *rir = &_rir;
2775   u32 ttl, tmp;
2776   u32 qp_offset;
2777   dns_query_t *qp;
2778   dns_rr_t *rr;
2779   u8 *rrptr;
2780   int is_fail = 0;
2781   int is_recycle = (b0 != 0);
2782
2783   ASSERT (ep && ep->dns_response);
2784
2785   if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2786     {
2787       /* Quick and dirty way to dig up the A-record address. $$ FIXME */
2788       clib_memset (rnr, 0, sizeof (*rnr));
2789       if (vnet_dns_response_to_reply (ep->dns_response, rnr, &ttl))
2790         {
2791           /* clib_warning ("response_to_reply failed..."); */
2792           is_fail = 1;
2793         }
2794       if (rnr->ip4_set == 0)
2795         {
2796           /* clib_warning ("No A-record..."); */
2797           is_fail = 1;
2798         }
2799     }
2800   else if (pr->request_type == DNS_PEER_PENDING_IP_TO_NAME)
2801     {
2802       clib_memset (rir, 0, sizeof (*rir));
2803       if (vnet_dns_response_to_name (ep->dns_response, rir, &ttl))
2804         {
2805           /* clib_warning ("response_to_name failed..."); */
2806           is_fail = 1;
2807         }
2808     }
2809   else
2810     {
2811       clib_warning ("Unknown request type %d", pr->request_type);
2812       return;
2813     }
2814
2815   /* Initialize a buffer */
2816   if (b0 == 0)
2817     {
2818       if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2819         return;
2820       b0 = vlib_get_buffer (vm, bi);
2821     }
2822   else
2823     {
2824       /* Use the buffer we were handed. Reinitialize it... */
2825       vlib_buffer_t bt = { };
2826       /* push/pop the reference count */
2827       u8 save_ref_count = b0->ref_count;
2828       vlib_buffer_copy_template (b0, &bt);
2829       b0->ref_count = save_ref_count;
2830       bi = vlib_get_buffer_index (vm, b0);
2831     }
2832
2833   if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
2834     vlib_buffer_free_one (vm, b0->next_buffer);
2835
2836   /*
2837    * Reset the buffer. We recycle the DNS request packet in the cache
2838    * hit case, and reply immediately from the request node.
2839    *
2840    * In the resolution-required / deferred case, resetting a freshly-allocated
2841    * buffer won't hurt. We hope.
2842    */
2843   b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
2844                 | VLIB_BUFFER_TOTAL_LENGTH_VALID);
2845   vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;   /* "local0" */
2846   vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0;   /* default VRF for now */
2847
2848   /* Find a FIB path to the peer we're trying to answer */
2849   clib_memcpy (&prefix.fp_addr.ip4, pr->dst_address, sizeof (ip4_address_t));
2850   prefix.fp_proto = FIB_PROTOCOL_IP4;
2851   prefix.fp_len = 32;
2852
2853   fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
2854   if (fib_index == (u32) ~ 0)
2855     {
2856       clib_warning ("no fib table");
2857       return;
2858     }
2859
2860   fei = fib_table_lookup (fib_index, &prefix);
2861
2862   /* Couldn't find route to destination. Bail out. */
2863   if (fei == FIB_NODE_INDEX_INVALID)
2864     {
2865       clib_warning ("no route to DNS server");
2866       return;
2867     }
2868
2869   sw_if_index = fib_entry_get_resolving_interface (fei);
2870
2871   if (sw_if_index == ~0)
2872     {
2873       clib_warning
2874         ("route to %U exists, fei %d, get_resolving_interface returned"
2875          " ~0", fei, format_ip4_address, &prefix.fp_addr);
2876       return;
2877     }
2878
2879   /* *INDENT-OFF* */
2880   foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnumbered */,
2881   ({
2882     src_address = ip_interface_address_get_address (lm4, ia);
2883     goto found_src_address;
2884   }));
2885   /* *INDENT-ON* */
2886
2887   clib_warning ("FIB BUG");
2888   return;
2889
2890 found_src_address:
2891
2892   ip = vlib_buffer_get_current (b0);
2893   udp = (udp_header_t *) (ip + 1);
2894   dns_response = (u8 *) (udp + 1);
2895   clib_memset (ip, 0, sizeof (*ip) + sizeof (*udp));
2896
2897   /*
2898    * Start with the variadic portion of the exercise.
2899    * Turn the name into a set of DNS "labels". Max length
2900    * per label is 63, enforce that.
2901    */
2902   reply = name_to_labels (pr->name);
2903   vec_free (pr->name);
2904
2905   qp_offset = vec_len (reply);
2906
2907   /* Add space for the query header */
2908   vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
2909
2910   qp = (dns_query_t *) (reply + qp_offset);
2911
2912   if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2913     qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
2914   else
2915     qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2916
2917   qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
2918
2919   /* Punch in space for the dns_header_t */
2920   vec_insert (reply, sizeof (dns_header_t), 0);
2921
2922   dh = (dns_header_t *) reply;
2923
2924   /* Transaction ID = pool index */
2925   dh->id = pr->id;
2926
2927   /* Announce that we did a recursive lookup */
2928   tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
2929   if (is_fail)
2930     tmp |= DNS_RCODE_NAME_ERROR;
2931   dh->flags = clib_host_to_net_u16 (tmp);
2932   dh->qdcount = clib_host_to_net_u16 (1);
2933   dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
2934   dh->nscount = 0;
2935   dh->arcount = 0;
2936
2937   /* If the name resolution worked, cough up an appropriate RR */
2938   if (is_fail == 0)
2939     {
2940       /* Add the answer. First, a name pointer (0xC00C) */
2941       vec_add1 (reply, 0xC0);
2942       vec_add1 (reply, 0x0C);
2943
2944       /* Now, add single A-rec RR */
2945       if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
2946         {
2947           vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
2948           rr = (dns_rr_t *) rrptr;
2949
2950           rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
2951           rr->class = clib_host_to_net_u16 (1 /* internet */ );
2952           rr->ttl = clib_host_to_net_u32 (ttl);
2953           rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
2954           clib_memcpy (rr->rdata, rnr->ip4_address, sizeof (ip4_address_t));
2955         }
2956       else
2957         {
2958           /* Or a single PTR RR */
2959           u8 *vecname = format (0, "%s", rir->name);
2960           u8 *label_vec = name_to_labels (vecname);
2961           vec_free (vecname);
2962
2963           vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
2964           rr = (dns_rr_t *) rrptr;
2965           rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
2966           rr->class = clib_host_to_net_u16 (1 /* internet */ );
2967           rr->ttl = clib_host_to_net_u32 (ttl);
2968           rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
2969           clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
2970           vec_free (label_vec);
2971         }
2972     }
2973   clib_memcpy (dns_response, reply, vec_len (reply));
2974
2975   /* Set the packet length */
2976   b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
2977
2978   /* IP header */
2979   ip->ip_version_and_header_length = 0x45;
2980   ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
2981   ip->ttl = 255;
2982   ip->protocol = IP_PROTOCOL_UDP;
2983   ip->src_address.as_u32 = src_address->as_u32;
2984   clib_memcpy (ip->dst_address.as_u8, pr->dst_address,
2985                sizeof (ip4_address_t));
2986   ip->checksum = ip4_header_checksum (ip);
2987
2988   /* UDP header */
2989   udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
2990   udp->dst_port = pr->dst_port;
2991   udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
2992                                       vec_len (reply));
2993   udp->checksum = 0;
2994   vec_free (reply);
2995
2996   /*
2997    * Ship pkts made out of whole cloth to ip4_lookup
2998    * Caller will ship recycled dns reply packets to ip4_lookup
2999    */
3000   if (is_recycle == 0)
3001     {
3002       f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
3003       to_next = vlib_frame_vector_args (f);
3004       to_next[0] = bi;
3005       f->n_vectors = 1;
3006       vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
3007     }
3008 }
3009
3010 /*
3011  * fd.io coding-style-patch-verification: ON
3012  *
3013  * Local Variables:
3014  * eval: (c-set-style "gnu")
3015  * End:
3016  */