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