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