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