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