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