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