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