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