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