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