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