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