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