-merge branch 'master' of ssh://gnunet.org/gnunet into gsoc2018/rest_api
[oweals/gnunet.git] / src / gns / gnunet-service-gns_resolver.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2011-2013 GNUnet e.V.
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20
21 /**
22  * @file gns/gnunet-service-gns_resolver.c
23  * @brief GNU Name System resolver logic
24  * @author Martin Schanzenbach
25  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_dnsstub_lib.h"
30 #include "gnunet_dht_service.h"
31 #include "gnunet_gnsrecord_lib.h"
32 #include "gnunet_namecache_service.h"
33 #include "gnunet_dns_service.h"
34 #include "gnunet_resolver_service.h"
35 #include "gnunet_revocation_service.h"
36 #include "gnunet_dnsparser_lib.h"
37 #include "gnunet_tun_lib.h"
38 #include "gnunet_gns_service.h"
39 #include "gns.h"
40 #include "gnunet-service-gns.h"
41 #include "gnunet-service-gns_resolver.h"
42 #include "gnunet_vpn_service.h"
43
44
45 /**
46  * Default DHT timeout for lookups.
47  */
48 #define DHT_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
49
50 /**
51  * Default timeout for DNS lookups.
52  */
53 #define DNS_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
54
55 /**
56  * Default timeout for VPN redirections.
57  */
58 #define VPN_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
59
60 /**
61  * DHT replication level
62  */
63 #define DHT_GNS_REPLICATION_LEVEL 10
64
65 /**
66  * How deep do we allow recursions to go before we abort?
67  */
68 #define MAX_RECURSION 256
69
70
71 /**
72  * DLL to hold the authority chain we had to pass in the resolution
73  * process.
74  */
75 struct AuthorityChain;
76
77
78 /**
79  * Element of a resolution process for looking up the
80  * responsible DNS server hostname in a GNS2DNS recursive
81  * resolution.
82  */
83 struct Gns2DnsPending
84 {
85
86   /**
87    * Kept in a DLL.
88    */
89   struct Gns2DnsPending *next;
90
91   /**
92    * Kept in a DLL.
93    */
94   struct Gns2DnsPending *prev;
95
96   /**
97    * Context this activity belongs with.
98    */
99   struct AuthorityChain *ac;
100
101   /**
102    * Handle for the resolution of the IP part of the
103    * GNS2DNS record.  Will return to us the addresses
104    * of the DNS resolver to use.
105    */
106   struct GNS_ResolverHandle *rh;
107
108   /**
109    * Handle for DNS resolution of the DNS nameserver.
110    */
111   struct GNUNET_RESOLVER_RequestHandle *dns_rh;
112
113   /**
114    * How many results did we get?
115    */
116   unsigned int num_results;
117 };
118
119
120 /**
121  * Handle to a currenty pending resolution.  On result (positive or
122  * negative) the #GNS_ResultProcessor is called.
123  */
124 struct GNS_ResolverHandle;
125
126
127 /**
128  * DLL to hold the authority chain we had to pass in the resolution
129  * process.
130  */
131 struct AuthorityChain
132 {
133   /**
134    * This is a DLL.
135    */
136   struct AuthorityChain *prev;
137
138   /**
139    * This is a DLL.
140    */
141   struct AuthorityChain *next;
142
143   /**
144    * Resolver handle this entry in the chain belongs to.
145    */
146   struct GNS_ResolverHandle *rh;
147
148   /**
149    * label/name corresponding to the authority
150    */
151   char *label;
152
153   /**
154    * #GNUNET_YES if the authority was a GNS authority,
155    * #GNUNET_NO if the authority was a DNS authority.
156    */
157   int gns_authority;
158
159   /**
160    * Information about the resolver authority for this label.
161    */
162   union
163   {
164
165     /**
166      * The zone of the GNS authority
167      */
168     struct GNUNET_CRYPTO_EcdsaPublicKey gns_authority;
169
170     struct
171     {
172       /**
173        * Domain of the DNS resolver that is the authority.
174        * (appended to construct the DNS name to resolve;
175        * this is NOT the DNS name of the DNS server!).
176        */
177       char name[GNUNET_DNSPARSER_MAX_NAME_LENGTH + 1];
178
179       /**
180        * List of resolutions of the 'ip' of the name server that
181        * are still pending.
182        */
183       struct Gns2DnsPending *gp_head;
184
185       /**
186        * Tail of list of resolutions of the 'ip' of the name server that
187        * are still pending.
188        */
189       struct Gns2DnsPending *gp_tail;
190
191       /**
192        * Handle to perform DNS lookups with this authority (in GNS2DNS handling).
193        */
194       struct GNUNET_DNSSTUB_Context *dns_handle;
195
196       /**
197        * Did we succeed in getting an IP address for *any* of the DNS servers listed?
198        * Once we do, we can start with DNS queries.
199        */
200       int found;
201
202       /**
203        * Did we start the recursive resolution via DNS?
204        */
205       int launched;
206
207     } dns_authority;
208
209   } authority_info;
210
211 };
212
213
214 /**
215  * A result we got from DNS.
216  */
217 struct DnsResult
218 {
219
220   /**
221    * Kept in DLL.
222    */
223   struct DnsResult *next;
224
225   /**
226    * Kept in DLL.
227    */
228   struct DnsResult *prev;
229
230   /**
231    * Binary value stored in the DNS record (appended to this struct)
232    */
233   const void *data;
234
235   /**
236    * Expiration time for the DNS record, 0 if we didn't
237    * get anything useful (i.e. 'gethostbyname()' was used).
238    */
239   uint64_t expiration_time;
240
241   /**
242    * Number of bytes in @e data.
243    */
244   size_t data_size;
245
246   /**
247    * Type of the GNS/DNS record.
248    */
249   uint32_t record_type;
250
251 };
252
253
254 /**
255  * Closure for #vpn_allocation_cb.
256  */
257 struct VpnContext
258 {
259
260   /**
261    * Which resolution process are we processing.
262    */
263   struct GNS_ResolverHandle *rh;
264
265   /**
266    * Handle to the VPN request that we were performing.
267    */
268   struct GNUNET_VPN_RedirectionRequest *vpn_request;
269
270   /**
271    * Number of records serialized in @e rd_data.
272    */
273   unsigned int rd_count;
274
275   /**
276    * Serialized records.
277    */
278   char *rd_data;
279
280   /**
281    * Number of bytes in @e rd_data.
282    */
283   ssize_t rd_data_size;
284 };
285
286
287 /**
288  * Handle to a currenty pending resolution.  On result (positive or
289  * negative) the #GNS_ResultProcessor is called.
290  */
291 struct GNS_ResolverHandle
292 {
293
294   /**
295    * DLL
296    */
297   struct GNS_ResolverHandle *next;
298
299   /**
300    * DLL
301    */
302   struct GNS_ResolverHandle *prev;
303
304   /**
305    * The top-level GNS authoritative zone to query
306    */
307   struct GNUNET_CRYPTO_EcdsaPublicKey authority_zone;
308
309   /**
310    * called when resolution phase finishes
311    */
312   GNS_ResultProcessor proc;
313
314   /**
315    * closure passed to @e proc
316    */
317   void* proc_cls;
318
319   /**
320    * Handle for DHT lookups. should be NULL if no lookups are in progress
321    */
322   struct GNUNET_DHT_GetHandle *get_handle;
323
324   /**
325    * Handle to a VPN request, NULL if none is active.
326    */
327   struct VpnContext *vpn_ctx;
328
329   /**
330    * Socket for a DNS request, NULL if none is active.
331    */
332   struct GNUNET_DNSSTUB_RequestSocket *dns_request;
333
334   /**
335    * Handle for standard DNS resolution, NULL if none is active.
336    */
337   struct GNUNET_RESOLVER_RequestHandle *std_resolve;
338
339   /**
340    * Pending Namecache lookup task
341    */
342   struct GNUNET_NAMECACHE_QueueEntry *namecache_qe;
343
344   /**
345    * Pending revocation check.
346    */
347   struct GNUNET_REVOCATION_Query *rev_check;
348
349   /**
350    * Heap node associated with this lookup.  Used to limit number of
351    * concurrent requests.
352    */
353   struct GNUNET_CONTAINER_HeapNode *dht_heap_node;
354
355   /**
356    * DLL to store the authority chain
357    */
358   struct AuthorityChain *ac_head;
359
360   /**
361    * DLL to store the authority chain
362    */
363   struct AuthorityChain *ac_tail;
364
365   /**
366    * ID of a task associated with the resolution process.
367    */
368   struct GNUNET_SCHEDULER_Task *task_id;
369
370   /**
371    * The name to resolve
372    */
373   char *name;
374
375   /**
376    * DLL of results we got from DNS.
377    */
378   struct DnsResult *dns_result_head;
379
380   /**
381    * DLL of results we got from DNS.
382    */
383   struct DnsResult *dns_result_tail;
384
385   /**
386    * Current offset in 'name' where we are resolving.
387    */
388   size_t name_resolution_pos;
389
390   /**
391    * Use only cache
392    */
393   enum GNUNET_GNS_LocalOptions options;
394
395   /**
396    * For SRV and TLSA records, the number of the
397    * protocol specified in the name.  0 if no protocol was given.
398    */
399   int protocol;
400
401   /**
402    * For SRV and TLSA records, the number of the
403    * service specified in the name.  0 if no service was given.
404    */
405   int service;
406
407   /**
408    * Desired type for the resolution.
409    */
410   int record_type;
411
412   /**
413    * We increment the loop limiter for each step in a recursive
414    * resolution.  If it passes our threshold (i.e. due to
415    * self-recursion in the resolution, i.e CNAME fun), we stop.
416    */
417   unsigned int loop_limiter;
418
419   /**
420    * 16 bit random ID we used in the @e dns_request.
421    */
422   uint16_t original_dns_id;
423
424 };
425
426
427 /**
428  * Active namestore caching operations.
429  */
430 struct CacheOps
431 {
432
433   /**
434    * Organized in a DLL.
435    */
436   struct CacheOps *next;
437
438   /**
439    * Organized in a DLL.
440    */
441   struct CacheOps *prev;
442
443   /**
444    * Pending Namestore caching task.
445    */
446   struct GNUNET_NAMECACHE_QueueEntry *namecache_qe_cache;
447
448 };
449
450
451 /**
452  * Our handle to the namecache service
453  */
454 static struct GNUNET_NAMECACHE_Handle *namecache_handle;
455
456 /**
457  * Our handle to the vpn service
458  */
459 static struct GNUNET_VPN_Handle *vpn_handle;
460
461 /**
462  * Resolver handle to the dht
463  */
464 static struct GNUNET_DHT_Handle *dht_handle;
465
466 /**
467  * Heap for limiting parallel DHT lookups
468  */
469 static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
470
471 /**
472  * Maximum amount of parallel queries to the DHT
473  */
474 static unsigned long long max_allowed_background_queries;
475
476 /**
477  * Head of resolver lookup list
478  */
479 static struct GNS_ResolverHandle *rlh_head;
480
481 /**
482  * Tail of resolver lookup list
483  */
484 static struct GNS_ResolverHandle *rlh_tail;
485
486 /**
487  * Organized in a DLL.
488  */
489 static struct CacheOps *co_head;
490
491 /**
492  * Organized in a DLL.
493  */
494 static struct CacheOps *co_tail;
495
496 /**
497  * Use namecache
498  */
499 static int disable_cache;
500
501 /**
502  * Global configuration.
503  */
504 static const struct GNUNET_CONFIGURATION_Handle *cfg;
505
506
507 /**
508  * Determine if this name is canonical (is a legal name in a zone, without delegation);
509  * note that we do not test that the name does not contain illegal characters, we only
510  * test for delegation.  Note that service records (i.e. _foo._srv) are canonical names
511  * even though they consist of multiple labels.
512  *
513  * Examples:
514  * a.b.gnu   = not canonical
515  * a         = canonical
516  * _foo._srv = canonical
517  * _f.bar    = not canonical
518  *
519  * @param name the name to test
520  * @return #GNUNET_YES if canonical
521  */
522 /* dead, but keep for now */ int
523 is_canonical (const char *name)
524 {
525   const char *pos;
526   const char *dot;
527
528   if (NULL == strchr (name,
529                       (unsigned char) '.'))
530     return GNUNET_YES;
531   if ('_' != name[0])
532     return GNUNET_NO;
533   pos = &name[1];
534   while (NULL != (dot = strchr (pos,
535                                 (unsigned char) '.')))
536     if ('_' != dot[1])
537       return GNUNET_NO;
538     else
539       pos = dot + 1;
540   return GNUNET_YES;
541 }
542
543 /* ************************** Resolution **************************** */
544
545 /**
546  * Expands a name ending in .+ with the zone of origin.
547  *
548  * @param rh resolution context
549  * @param name name to modify (to be free'd or returned)
550  * @return updated name
551  */
552 static char *
553 translate_dot_plus (struct GNS_ResolverHandle *rh,
554                     char *name)
555 {
556   char *ret;
557   size_t s_len = strlen (name);
558
559   if (0 != strcmp (&name[s_len - 2],
560                    ".+"))
561     return name; /* did not end in ".+" */
562   GNUNET_assert (GNUNET_YES == rh->ac_tail->gns_authority);
563   GNUNET_asprintf (&ret,
564                    "%.*s.%s",
565                    (int) (s_len - 2),
566                    name,
567                    GNUNET_GNSRECORD_pkey_to_zkey (&rh->ac_tail->authority_info.gns_authority));
568   GNUNET_free (name);
569   return ret;
570 }
571
572
573 /**
574  * Wrapper around #GNS_resolver_lookup_cancel() as a task.
575  * Used for delayed cleanup so we can unwind the stack first.
576  *
577  * @param cls the `struct GNS_ResolverHandle`
578  */
579 static void
580 GNS_resolver_lookup_cancel_ (void *cls)
581 {
582   struct GNS_ResolverHandle *rh = cls;
583
584   rh->task_id = NULL;
585   GNS_resolver_lookup_cancel (rh);
586 }
587
588
589 /**
590  * Function called to asynchronously fail a resolution.
591  *
592  * @param rh the resolution to fail
593  */
594 static void
595 fail_resolution (struct GNS_ResolverHandle *rh)
596 {
597   rh->proc (rh->proc_cls,
598             0,
599             NULL);
600   GNUNET_assert (NULL == rh->task_id);
601   rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
602                                           rh);
603 }
604
605
606 /**
607  * Function called when a resolution times out.
608  *
609  * @param cls the `struct GNS_ResolverHandle`
610  */
611 static void
612 timeout_resolution (void *cls)
613 {
614   struct GNS_ResolverHandle *rh = cls;
615
616   rh->task_id = NULL;
617   fail_resolution (rh);
618 }
619
620
621 #if (defined WINDOWS) || (defined DARWIN)
622 /* Don't have this on W32, here's a naive implementation
623  * Was somehow removed on OS X ...  */
624 static void *
625 memrchr (const void *s,
626          int c,
627          size_t n)
628 {
629   const unsigned char *ucs = s;
630   ssize_t i;
631
632   for (i = n - 1; i >= 0; i--)
633     if (c == (int) ucs[i])
634       return (void *) &ucs[i];
635   return NULL;
636 }
637 #endif
638
639
640 /**
641  * Get the next, rightmost label from the name that we are trying to resolve,
642  * and update the resolution position accordingly.  Labels usually consist
643  * of up to 63 characters without a period ("."); however, we use a special
644  * convention to support SRV and TLSA records where the domain name
645  * includes an encoding for a service and protocol in the name.  The
646  * syntax (see RFC 2782) here is "_Service._Proto.Name" and in this
647  * special case we include the "_Service._Proto" in the rightmost label.
648  * Thus, for "_443._tcp.foo.bar" we first return the label "bar" and then
649  * the label "_443._tcp.foo".  The special case is detected by the
650  * presence of labels beginning with an underscore.  Whenever a label
651  * begins with an underscore, it is combined with the label to its right
652  * (and the "." is preserved).
653  *
654  * @param rh handle to the resolution operation to get the next label from
655  * @return NULL if there are no more labels
656  */
657 static char *
658 resolver_lookup_get_next_label (struct GNS_ResolverHandle *rh)
659 {
660   const char *rp;
661   const char *dot;
662   size_t len;
663   char *ret;
664   char *srv_name;
665   char *proto_name;
666   struct protoent *pe;
667   struct servent *se;
668
669   if (0 == rh->name_resolution_pos)
670     return NULL;
671   dot = memrchr (rh->name,
672                  (int) '.',
673                  rh->name_resolution_pos);
674   if (NULL == dot)
675   {
676     /* done, this was the last one */
677     len = rh->name_resolution_pos;
678     rp = rh->name;
679     rh->name_resolution_pos = 0;
680   }
681   else
682   {
683     /* advance by one label */
684     len = rh->name_resolution_pos - (dot - rh->name) - 1;
685     rp = dot + 1;
686     rh->name_resolution_pos = dot - rh->name;
687   }
688   rh->protocol = 0;
689   rh->service = 0;
690   ret = GNUNET_strndup (rp, len);
691   /* If we have labels starting with underscore with label on
692    * the right (SRV/DANE/BOX case), determine port/protocol;
693    * The format of `rh->name` must be "_PORT._PROTOCOL".
694    */
695   if ( ('_' == rh->name[0]) &&
696        (NULL != (dot = memrchr (rh->name,
697                                 (int) '.',
698                                 rh->name_resolution_pos))) &&
699        ('_' == dot[1]) &&
700        (NULL == memrchr (rh->name,
701                          (int) '.',
702                          dot - rh->name)) )
703   {
704     srv_name = GNUNET_strndup (&rh->name[1],
705                                (dot - rh->name) - 1);
706     proto_name = GNUNET_strndup (&dot[2],
707                                  rh->name_resolution_pos - (dot - rh->name) - 1);
708     rh->name_resolution_pos = 0;
709     pe = getprotobyname (proto_name);
710     if (NULL == pe)
711     {
712       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
713                   _("Protocol `%s' unknown, skipping labels.\n"),
714                   proto_name);
715       GNUNET_free (proto_name);
716       GNUNET_free (srv_name);
717       return ret;
718     }
719     se = getservbyname (srv_name,
720                         proto_name);
721     if (NULL == se)
722     {
723       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
724                   _("Service `%s' unknown for protocol `%s', skipping labels.\n"),
725                   srv_name,
726                   proto_name);
727       GNUNET_free (proto_name);
728       GNUNET_free (srv_name);
729       return ret;
730     }
731     rh->protocol = pe->p_proto;
732     rh->service = se->s_port;
733     GNUNET_free (proto_name);
734     GNUNET_free (srv_name);
735   }
736   return ret;
737 }
738
739
740 /**
741  * Gives the cummulative result obtained to the callback and clean up the request.
742  *
743  * @param rh resolution process that has culminated in a result
744  */
745 static void
746 transmit_lookup_dns_result (struct GNS_ResolverHandle *rh)
747 {
748   struct DnsResult *pos;
749   unsigned int n;
750   unsigned int i;
751
752   n = 0;
753   for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
754     n++;
755   {
756     struct GNUNET_GNSRECORD_Data rd[n];
757
758     i = 0;
759     for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
760     {
761       rd[i].data = pos->data;
762       rd[i].data_size = pos->data_size;
763       rd[i].record_type = pos->record_type;
764       if (0 == pos->expiration_time)
765       {
766         rd[i].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
767         rd[i].expiration_time = 0;
768       }
769       else
770       {
771         rd[i].flags = GNUNET_GNSRECORD_RF_NONE;
772         rd[i].expiration_time = pos->expiration_time;
773       }
774       i++;
775     }
776     GNUNET_assert (i == n);
777     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
778                 "Transmitting standard DNS result with %u records\n",
779                 n);
780     rh->proc (rh->proc_cls,
781               n,
782               rd);
783   }
784   GNS_resolver_lookup_cancel (rh);
785 }
786
787
788 /**
789  * Add a result from DNS to the records to be returned to the application.
790  *
791  * @param rh resolution request to extend with a result
792  * @param expiration_time expiration time for the answer
793  * @param record_type DNS record type of the answer
794  * @param data_size number of bytes in @a data
795  * @param data binary data to return in DNS record
796  */
797 static void
798 add_dns_result (struct GNS_ResolverHandle *rh,
799                 uint64_t expiration_time,
800                 uint32_t record_type,
801                 size_t data_size,
802                 const void *data)
803 {
804   struct DnsResult *res;
805
806   res = GNUNET_malloc (sizeof (struct DnsResult) + data_size);
807   res->expiration_time = expiration_time;
808   res->data_size = data_size;
809   res->record_type = record_type;
810   res->data = &res[1];
811   GNUNET_memcpy (&res[1],
812                  data,
813                  data_size);
814   GNUNET_CONTAINER_DLL_insert (rh->dns_result_head,
815                                rh->dns_result_tail,
816                                res);
817 }
818
819
820 /**
821  * We had to do a DNS lookup.  Convert the result (if any) and return
822  * it.
823  *
824  * @param cls closure with the `struct GNS_ResolverHandle`
825  * @param addr one of the addresses of the host, NULL for the last address
826  * @param addrlen length of the address
827  */
828 static void
829 handle_dns_result (void *cls,
830                    const struct sockaddr *addr,
831                    socklen_t addrlen)
832 {
833   struct GNS_ResolverHandle *rh = cls;
834   const struct sockaddr_in *sa4;
835   const struct sockaddr_in6 *sa6;
836
837   if (NULL == addr)
838   {
839     rh->std_resolve = NULL;
840     transmit_lookup_dns_result (rh);
841     return;
842   }
843   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
844               "Received %u bytes of DNS IP data\n",
845               addrlen);
846   switch (addr->sa_family)
847   {
848   case AF_INET:
849     sa4 = (const struct sockaddr_in *) addr;
850     add_dns_result (rh,
851                     0 /* expiration time is unknown */,
852                     GNUNET_DNSPARSER_TYPE_A,
853                     sizeof (struct in_addr),
854                     &sa4->sin_addr);
855     break;
856   case AF_INET6:
857     sa6 = (const struct sockaddr_in6 *) addr;
858     add_dns_result (rh,
859                     0 /* expiration time is unknown */,
860                     GNUNET_DNSPARSER_TYPE_AAAA,
861                     sizeof (struct in6_addr),
862                     &sa6->sin6_addr);
863     break;
864   default:
865     GNUNET_break (0);
866     break;
867   }
868 }
869
870
871 /**
872  * Task scheduled to continue with the resolution process.
873  *
874  * @param cls the 'struct GNS_ResolverHandle' of the resolution
875  * @param tc task context
876  */
877 static void
878 recursive_resolution (void *cls);
879
880
881 /**
882  * Begin the resolution process from 'name', starting with
883  * the identification of the zone specified by 'name'.
884  *
885  * @param cls closure with `struct GNS_ResolverHandle *rh`
886  */
887 static void
888 start_resolver_lookup (void *cls);
889
890
891 /**
892  * Function called with the result of a DNS resolution.
893  *
894  * @param cls the request handle of the resolution that
895  *        we were attempting to make
896  * @param dns dns response, never NULL
897  * @param dns_len number of bytes in @a dns
898  */
899 static void
900 dns_result_parser (void *cls,
901                    const struct GNUNET_TUN_DnsHeader *dns,
902                    size_t dns_len)
903 {
904   struct GNS_ResolverHandle *rh = cls;
905   struct GNUNET_DNSPARSER_Packet *p;
906   const struct GNUNET_DNSPARSER_Record *rec;
907   unsigned int rd_count;
908
909   if (NULL == dns)
910   {
911     rh->dns_request = NULL;
912     GNUNET_SCHEDULER_cancel (rh->task_id);
913     rh->task_id = NULL;
914     fail_resolution (rh);
915     return;
916   }
917   if (rh->original_dns_id != dns->id)
918   {
919     /* DNS answer, but for another query */
920     return;
921   }
922   p = GNUNET_DNSPARSER_parse ((const char *) dns,
923                               dns_len);
924   if (NULL == p)
925   {
926     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
927                 _("Failed to parse DNS response\n"));
928     return;
929   }
930
931   /* We got a result from DNS */
932   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
933               "Received DNS response for `%s' with %u answers\n",
934               rh->ac_tail->label,
935               (unsigned int) p->num_answers);
936   if ( (p->num_answers > 0) &&
937        (GNUNET_DNSPARSER_TYPE_CNAME == p->answers[0].type) &&
938        (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type) )
939   {
940     int af;
941
942     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
943                 "Got CNAME `%s' from DNS for `%s'\n",
944                 p->answers[0].data.hostname,
945                 rh->name);
946     if (NULL != rh->std_resolve)
947     {
948       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
949                   "Multiple CNAME results from DNS resolving `%s'! Not really allowed...\n",
950                   rh->name);
951       GNUNET_RESOLVER_request_cancel (rh->std_resolve);
952     }
953     GNUNET_free (rh->name);
954     rh->name = GNUNET_strdup (p->answers[0].data.hostname);
955     rh->name_resolution_pos = strlen (rh->name);
956     switch (rh->record_type)
957     {
958     case GNUNET_DNSPARSER_TYPE_A:
959       af = AF_INET;
960       break;
961     case GNUNET_DNSPARSER_TYPE_AAAA:
962       af = AF_INET6;
963       break;
964     default:
965       af = AF_UNSPEC;
966       break;
967     }
968     rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name,
969                                               af,
970                                               DNS_LOOKUP_TIMEOUT,
971                                               &handle_dns_result,
972                                               rh);
973     GNUNET_DNSPARSER_free_packet (p);
974     GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
975     rh->dns_request = NULL;
976     return;
977   }
978
979   /* convert from (parsed) DNS to (binary) GNS format! */
980   rd_count = p->num_answers + p->num_authority_records + p->num_additional_records;
981   {
982     struct GNUNET_GNSRECORD_Data rd[rd_count];
983     unsigned int skip;
984     char buf[UINT16_MAX];
985     size_t buf_off;
986     size_t buf_start;
987
988     buf_off = 0;
989     skip = 0;
990     memset (rd,
991             0,
992             sizeof (rd));
993     for (unsigned int i=0;i<rd_count;i++)
994     {
995       if (i < p->num_answers)
996         rec = &p->answers[i];
997       else if (i < p->num_answers + p->num_authority_records)
998         rec = &p->authority_records[i - p->num_answers];
999       else
1000         rec = &p->additional_records[i - p->num_answers - p->num_authority_records];
1001       /* As we copied the full DNS name to 'rh->ac_tail->label', this
1002          should be the correct check to see if this record is actually
1003          a record for our label... */
1004       if (0 != strcmp (rec->name,
1005                        rh->ac_tail->label))
1006       {
1007         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1008                     "Dropping record `%s', does not match desired name `%s'\n",
1009                     rec->name,
1010                     rh->ac_tail->label);
1011         skip++;
1012         continue;
1013       }
1014       rd[i - skip].record_type = rec->type;
1015       rd[i - skip].expiration_time = rec->expiration_time.abs_value_us;
1016       switch (rec->type)
1017       {
1018       case GNUNET_DNSPARSER_TYPE_A:
1019         if (rec->data.raw.data_len != sizeof (struct in_addr))
1020         {
1021           GNUNET_break_op (0);
1022           skip++;
1023           continue;
1024         }
1025         rd[i - skip].data_size = rec->data.raw.data_len;
1026         rd[i - skip].data = rec->data.raw.data;
1027         break;
1028       case GNUNET_DNSPARSER_TYPE_AAAA:
1029         if (rec->data.raw.data_len != sizeof (struct in6_addr))
1030         {
1031           GNUNET_break_op (0);
1032           skip++;
1033           continue;
1034         }
1035         rd[i - skip].data_size = rec->data.raw.data_len;
1036         rd[i - skip].data = rec->data.raw.data;
1037         break;
1038       case GNUNET_DNSPARSER_TYPE_CNAME:
1039       case GNUNET_DNSPARSER_TYPE_PTR:
1040       case GNUNET_DNSPARSER_TYPE_NS:
1041         buf_start = buf_off;
1042         if (GNUNET_OK !=
1043             GNUNET_DNSPARSER_builder_add_name (buf,
1044                                                sizeof (buf),
1045                                                &buf_off,
1046                                                rec->data.hostname))
1047         {
1048           GNUNET_break (0);
1049           skip++;
1050           continue;
1051         }
1052         rd[i - skip].data_size = buf_off - buf_start;
1053         rd[i - skip].data = &buf[buf_start];
1054         break;
1055       case GNUNET_DNSPARSER_TYPE_SOA:
1056         buf_start = buf_off;
1057         if (GNUNET_OK !=
1058             GNUNET_DNSPARSER_builder_add_soa (buf,
1059                                               sizeof (buf),
1060                                               &buf_off,
1061                                               rec->data.soa))
1062         {
1063           GNUNET_break (0);
1064           skip++;
1065           continue;
1066         }
1067         rd[i - skip].data_size = buf_off - buf_start;
1068         rd[i - skip].data = &buf[buf_start];
1069         break;
1070       case GNUNET_DNSPARSER_TYPE_MX:
1071         buf_start = buf_off;
1072         if (GNUNET_OK !=
1073             GNUNET_DNSPARSER_builder_add_mx (buf,
1074                                              sizeof (buf),
1075                                              &buf_off,
1076                                              rec->data.mx))
1077         {
1078           GNUNET_break (0);
1079           skip++;
1080           continue;
1081         }
1082         rd[i - skip].data_size = buf_off - buf_start;
1083         rd[i - skip].data = &buf[buf_start];
1084         break;
1085       case GNUNET_DNSPARSER_TYPE_SRV:
1086         buf_start = buf_off;
1087         if (GNUNET_OK !=
1088             GNUNET_DNSPARSER_builder_add_srv (buf,
1089                                               sizeof (buf),
1090                                               &buf_off,
1091                                               rec->data.srv))
1092         {
1093           GNUNET_break (0);
1094           skip++;
1095           continue;
1096         }
1097         rd[i - skip].data_size = buf_off - buf_start;
1098         rd[i - skip].data = &buf[buf_start];
1099         break;
1100       default:
1101         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1102                     _("Skipping record of unsupported type %d\n"),
1103                     rec->type);
1104         skip++;
1105         continue;
1106       }
1107     }
1108     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1109                 "Returning DNS response for `%s' with %u answers\n",
1110                 rh->ac_tail->label,
1111                 (unsigned int) p->num_answers);
1112     rh->proc (rh->proc_cls,
1113               rd_count - skip,
1114               rd);
1115     GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
1116     rh->dns_request = NULL;
1117   }
1118   GNUNET_DNSPARSER_free_packet (p);
1119   if (NULL != rh->task_id)
1120     GNUNET_SCHEDULER_cancel (rh->task_id); /* should be timeout task */
1121   rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
1122                                           rh);
1123 }
1124
1125
1126 /**
1127  * Perform recursive DNS resolution.  Asks the given DNS resolver to
1128  * resolve "rh->dns_name", possibly recursively proceeding following
1129  * NS delegations, CNAMES, etc., until 'rh->loop_limiter' bounds us or
1130  * we find the answer.
1131  *
1132  * @param rh resolution information
1133  */
1134 static void
1135 recursive_dns_resolution (struct GNS_ResolverHandle *rh)
1136 {
1137   struct AuthorityChain *ac;
1138   struct GNUNET_DNSPARSER_Query *query;
1139   struct GNUNET_DNSPARSER_Packet *p;
1140   char *dns_request;
1141   size_t dns_request_length;
1142   int ret;
1143
1144   ac = rh->ac_tail;
1145   GNUNET_assert (NULL != ac);
1146   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1147               "Starting DNS lookup for `%s'\n",
1148               ac->label);
1149   GNUNET_assert (GNUNET_NO == ac->gns_authority);
1150   query = GNUNET_new (struct GNUNET_DNSPARSER_Query);
1151   query->name = GNUNET_strdup (ac->label);
1152   query->type = rh->record_type;
1153   query->dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
1154   p = GNUNET_new (struct GNUNET_DNSPARSER_Packet);
1155   p->queries = query;
1156   p->num_queries = 1;
1157   p->id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1158                                                UINT16_MAX);
1159   p->flags.opcode = GNUNET_TUN_DNS_OPCODE_QUERY;
1160   p->flags.recursion_desired = 1;
1161   ret = GNUNET_DNSPARSER_pack (p,
1162                                1024,
1163                                &dns_request,
1164                                &dns_request_length);
1165   if (GNUNET_OK != ret)
1166   {
1167     GNUNET_break (0);
1168     rh->proc (rh->proc_cls,
1169               0,
1170               NULL);
1171     GNUNET_assert (NULL == rh->task_id);
1172     rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
1173                                             rh);
1174   }
1175   else
1176   {
1177     rh->original_dns_id = p->id;
1178     GNUNET_assert (NULL != ac->authority_info.dns_authority.dns_handle);
1179     GNUNET_assert (NULL == rh->dns_request);
1180     rh->dns_request = GNUNET_DNSSTUB_resolve (ac->authority_info.dns_authority.dns_handle,
1181                                               dns_request,
1182                                               dns_request_length,
1183                                               &dns_result_parser,
1184                                               rh);
1185     rh->task_id = GNUNET_SCHEDULER_add_delayed (DNS_LOOKUP_TIMEOUT,
1186                                                 &timeout_resolution,
1187                                                 rh);
1188   }
1189   if (GNUNET_SYSERR != ret)
1190     GNUNET_free (dns_request);
1191   GNUNET_DNSPARSER_free_packet (p);
1192 }
1193
1194
1195 /**
1196  * We encountered a CNAME record during our resolution.
1197  * Merge it into our chain.
1198  *
1199  * @param rh resolution we are performing
1200  * @param cname value of the cname record we got for the current
1201  *        authority chain tail
1202  */
1203 static void
1204 handle_gns_cname_result (struct GNS_ResolverHandle *rh,
1205                          const char *cname)
1206 {
1207   size_t nlen;
1208   char *res;
1209   struct AuthorityChain *ac;
1210   int af;
1211
1212   nlen = strlen (cname);
1213   if ( (nlen > 2) &&
1214        (0 == strcmp (".+",
1215                      &cname[nlen - 2])) )
1216   {
1217     /* CNAME resolution continues relative to current domain */
1218     if (0 == rh->name_resolution_pos)
1219     {
1220       res = GNUNET_strndup (cname, nlen - 2);
1221       rh->name_resolution_pos = nlen - 2;
1222     }
1223     else
1224     {
1225       GNUNET_asprintf (&res,
1226                        "%.*s.%.*s",
1227                        (int) rh->name_resolution_pos,
1228                        rh->name,
1229                        (int) (nlen - 2),
1230                        cname);
1231       rh->name_resolution_pos = strlen (res);
1232     }
1233     GNUNET_free (rh->name);
1234     rh->name = res;
1235     ac = GNUNET_new (struct AuthorityChain);
1236     ac->rh = rh;
1237     ac->gns_authority = GNUNET_YES;
1238     ac->authority_info.gns_authority = rh->ac_tail->authority_info.gns_authority;
1239     ac->label = resolver_lookup_get_next_label (rh);
1240     /* add AC to tail */
1241     GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1242                                       rh->ac_tail,
1243                                       ac);
1244     rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1245                                             rh);
1246     return;
1247   }
1248   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1249               "Got CNAME `%s' from GNS for `%s'\n",
1250               cname,
1251               rh->name);
1252   if (NULL != rh->std_resolve)
1253   {
1254     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1255                 "Multiple CNAME results from GNS resolving `%s'! Not really allowed...\n",
1256                 rh->name);
1257     GNUNET_RESOLVER_request_cancel (rh->std_resolve);
1258   }
1259   /* name is absolute, go to DNS */
1260   GNUNET_free (rh->name);
1261   rh->name = GNUNET_strdup (cname);
1262   rh->name_resolution_pos = strlen (rh->name);
1263   switch (rh->record_type)
1264   {
1265   case GNUNET_DNSPARSER_TYPE_A:
1266     af = AF_INET;
1267     break;
1268   case GNUNET_DNSPARSER_TYPE_AAAA:
1269     af = AF_INET6;
1270     break;
1271   default:
1272     af = AF_UNSPEC;
1273     break;
1274   }
1275   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1276               "Doing standard DNS lookup for `%s'\n",
1277               rh->name);
1278   rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name,
1279                                             af,
1280                                             DNS_LOOKUP_TIMEOUT,
1281                                             &handle_dns_result,
1282                                             rh);
1283 }
1284
1285
1286 /**
1287  * Process a records that were decrypted from a block.
1288  *
1289  * @param cls closure with the 'struct GNS_ResolverHandle'
1290  * @param rd_count number of entries in @a rd array
1291  * @param rd array of records with data to store
1292  */
1293 static void
1294 handle_gns_resolution_result (void *cls,
1295                               unsigned int rd_count,
1296                               const struct GNUNET_GNSRECORD_Data *rd);
1297
1298
1299 /**
1300  * Callback invoked from the VPN service once a redirection is
1301  * available.  Provides the IP address that can now be used to
1302  * reach the requested destination.  Replaces the "VPN" record
1303  * with the respective A/AAAA record and continues processing.
1304  *
1305  * @param cls closure
1306  * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error;
1307  *                will match 'result_af' from the request
1308  * @param address IP address (struct in_addr or struct in_addr6, depending on 'af')
1309  *                that the VPN allocated for the redirection;
1310  *                traffic to this IP will now be redirected to the
1311  *                specified target peer; NULL on error
1312  */
1313 static void
1314 vpn_allocation_cb (void *cls,
1315                    int af,
1316                    const void *address)
1317 {
1318   struct VpnContext *vpn_ctx = cls;
1319   struct GNS_ResolverHandle *rh = vpn_ctx->rh;
1320   struct GNUNET_GNSRECORD_Data rd[vpn_ctx->rd_count];
1321   unsigned int i;
1322
1323   vpn_ctx->vpn_request = NULL;
1324   rh->vpn_ctx = NULL;
1325   GNUNET_assert (GNUNET_OK ==
1326                  GNUNET_GNSRECORD_records_deserialize ((size_t) vpn_ctx->rd_data_size,
1327                                                        vpn_ctx->rd_data,
1328                                                        vpn_ctx->rd_count,
1329                                                        rd));
1330   for (i=0;i<vpn_ctx->rd_count;i++)
1331   {
1332     if (GNUNET_GNSRECORD_TYPE_VPN == rd[i].record_type)
1333     {
1334       switch (af)
1335       {
1336       case AF_INET:
1337         rd[i].record_type = GNUNET_DNSPARSER_TYPE_A;
1338         rd[i].data_size = sizeof (struct in_addr);
1339         rd[i].expiration_time = GNUNET_TIME_relative_to_absolute (VPN_TIMEOUT).abs_value_us;
1340         rd[i].flags = 0;
1341         rd[i].data = address;
1342         break;
1343       case AF_INET6:
1344         rd[i].record_type = GNUNET_DNSPARSER_TYPE_AAAA;
1345         rd[i].expiration_time = GNUNET_TIME_relative_to_absolute (VPN_TIMEOUT).abs_value_us;
1346         rd[i].flags = 0;
1347         rd[i].data = address;
1348         rd[i].data_size = sizeof (struct in6_addr);
1349         break;
1350       default:
1351         GNUNET_assert (0);
1352       }
1353       break;
1354     }
1355   }
1356   GNUNET_assert (i < vpn_ctx->rd_count);
1357   handle_gns_resolution_result (rh,
1358                                 vpn_ctx->rd_count,
1359                                 rd);
1360   GNUNET_free (vpn_ctx->rd_data);
1361   GNUNET_free (vpn_ctx);
1362 }
1363
1364
1365 /**
1366  * We have resolved one or more of the nameservers for a
1367  * GNS2DNS lookup.  Once we have some of them, begin using
1368  * the DNSSTUB resolver.
1369  *
1370  * @param ac context for GNS2DNS resolution
1371  */
1372 static void
1373 continue_with_gns2dns (struct AuthorityChain *ac)
1374 {
1375   struct GNS_ResolverHandle *rh = ac->rh;
1376
1377   if ( (NULL != ac->authority_info.dns_authority.gp_head) &&
1378        (GNUNET_NO == ac->authority_info.dns_authority.found) )
1379     return; /* more pending and none found yet */
1380   if (GNUNET_NO == ac->authority_info.dns_authority.found)
1381   {
1382     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1383                 "Failed to resolve DNS server for `%s' in GNS2DNS resolution\n",
1384                 ac->authority_info.dns_authority.name);
1385     fail_resolution (rh);
1386     return;
1387   }
1388   if (GNUNET_NO != ac->authority_info.dns_authority.launched)
1389     return; /* already running, do not launch again! */
1390   /* recurse */
1391   ac->authority_info.dns_authority.launched = GNUNET_YES;
1392   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1393               "Will continue resolution using DNS to resolve `%s'\n",
1394               ac->label);
1395   GNUNET_assert (NULL == rh->task_id);
1396   rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1397                                           rh);
1398
1399 }
1400
1401
1402 /**
1403  * We've resolved the IP address for the DNS resolver to use
1404  * after encountering a GNS2DNS record.
1405  *
1406  * @param cls the `struct Gns2DnsPending` used for this request
1407  * @param rd_count number of records in @a rd
1408  * @param rd addresses for the DNS resolver  (presumably)
1409  */
1410 static void
1411 handle_gns2dns_result (void *cls,
1412                        unsigned int rd_count,
1413                        const struct GNUNET_GNSRECORD_Data *rd)
1414 {
1415   struct Gns2DnsPending *gp = cls;
1416   struct AuthorityChain *ac = gp->ac;
1417
1418   GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
1419                                ac->authority_info.dns_authority.gp_tail,
1420                                gp);
1421   /* enable cleanup of 'rh' handle that automatically comes after we return,
1422      and which expects 'rh' to be in the #rlh_head DLL. */
1423   if (NULL != gp->rh)
1424   {
1425     GNUNET_CONTAINER_DLL_insert (rlh_head,
1426                                  rlh_tail,
1427                                  gp->rh);
1428     gp->rh = NULL;
1429   }
1430   GNUNET_free (gp);
1431   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1432               "Received %u results for IP address of DNS server for GNS2DNS transition\n",
1433               rd_count);
1434   /* find suitable A/AAAA record */
1435   for (unsigned int j=0;j<rd_count;j++)
1436   {
1437     switch (rd[j].record_type)
1438     {
1439     case GNUNET_DNSPARSER_TYPE_A:
1440       {
1441         struct sockaddr_in v4;
1442
1443         if (sizeof (struct in_addr) != rd[j].data_size)
1444         {
1445           GNUNET_break_op (0);
1446           continue;
1447         }
1448         memset (&v4,
1449                 0,
1450                 sizeof (v4));
1451         v4.sin_family = AF_INET;
1452         v4.sin_port = htons (53);
1453 #if HAVE_SOCKADDR_IN_SIN_LEN
1454         v4.sin_len = (u_char) sizeof (v4);
1455 #endif
1456         GNUNET_memcpy (&v4.sin_addr,
1457                        rd[j].data,
1458                        sizeof (struct in_addr));
1459         if (GNUNET_OK ==
1460             GNUNET_DNSSTUB_add_dns_sa (ac->authority_info.dns_authority.dns_handle,
1461                                        (const struct sockaddr *) &v4))
1462           ac->authority_info.dns_authority.found = GNUNET_YES;
1463         break;
1464       }
1465     case GNUNET_DNSPARSER_TYPE_AAAA:
1466       {
1467         struct sockaddr_in6 v6;
1468
1469         if (sizeof (struct in6_addr) != rd[j].data_size)
1470         {
1471           GNUNET_break_op (0);
1472           continue;
1473         }
1474         /* FIXME: might want to check if we support IPv6 here,
1475            and otherwise skip this one and hope we find another */
1476         memset (&v6,
1477                 0,
1478                 sizeof (v6));
1479         v6.sin6_family = AF_INET6;
1480         v6.sin6_port = htons (53);
1481 #if HAVE_SOCKADDR_IN_SIN_LEN
1482         v6.sin6_len = (u_char) sizeof (v6);
1483 #endif
1484         GNUNET_memcpy (&v6.sin6_addr,
1485                        rd[j].data,
1486                        sizeof (struct in6_addr));
1487         if (GNUNET_OK ==
1488             GNUNET_DNSSTUB_add_dns_sa (ac->authority_info.dns_authority.dns_handle,
1489                                        (const struct sockaddr *) &v6))
1490           ac->authority_info.dns_authority.found = GNUNET_YES;
1491         break;
1492       }
1493     default:
1494       break;
1495     }
1496   }
1497   continue_with_gns2dns (ac);
1498 }
1499
1500
1501 /**
1502  * Function called by the resolver for each address obtained from DNS.
1503  *
1504  * @param cls closure, a `struct Gns2DnsPending *`
1505  * @param addr one of the addresses of the host, NULL for the last address
1506  * @param addrlen length of @a addr
1507  */
1508 static void
1509 handle_gns2dns_ip (void *cls,
1510                    const struct sockaddr *addr,
1511                    socklen_t addrlen)
1512 {
1513   struct Gns2DnsPending *gp = cls;
1514   struct AuthorityChain *ac = gp->ac;
1515   struct sockaddr_storage ss;
1516   struct sockaddr_in *v4;
1517   struct sockaddr_in6 *v6;
1518
1519   if (NULL == addr)
1520   {
1521     /* DNS resolution finished */
1522     if (0 == gp->num_results)
1523       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1524                   "Failed to use DNS to resolve name of DNS resolver\n");
1525     GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
1526                                  ac->authority_info.dns_authority.gp_tail,
1527                                  gp);
1528     GNUNET_free (gp);
1529     continue_with_gns2dns (ac);
1530     return;
1531   }
1532   GNUNET_memcpy (&ss,
1533                  addr,
1534                  addrlen);
1535   switch (ss.ss_family)
1536   {
1537   case AF_INET:
1538     v4 = (struct sockaddr_in *) &ss;
1539     v4->sin_port = htons (53);
1540     gp->num_results++;
1541     break;
1542   case AF_INET6:
1543     v6 = (struct sockaddr_in6 *) &ss;
1544     v6->sin6_port = htons (53);
1545     gp->num_results++;
1546     break;
1547   default:
1548     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1549                 "Unsupported AF %d\n",
1550                 ss.ss_family);
1551     return;
1552   }
1553   if (GNUNET_OK ==
1554       GNUNET_DNSSTUB_add_dns_sa (ac->authority_info.dns_authority.dns_handle,
1555                                  (struct sockaddr *) &ss))
1556     ac->authority_info.dns_authority.found = GNUNET_YES;
1557 }
1558
1559
1560 /**
1561  * We found a CNAME record, perform recursive resolution on it.
1562  *
1563  * @param rh resolution handle
1564  * @param rd record with CNAME to resolve recursively
1565  */
1566 static void
1567 recursive_cname_resolution (struct GNS_ResolverHandle *rh,
1568                             const struct GNUNET_GNSRECORD_Data *rd)
1569 {
1570   char *cname;
1571   size_t off;
1572
1573   off = 0;
1574   cname = GNUNET_DNSPARSER_parse_name (rd->data,
1575                                        rd->data_size,
1576                                        &off);
1577   if ( (NULL == cname) ||
1578        (off != rd->data_size) )
1579   {
1580     GNUNET_break_op (0); /* record not well-formed */
1581     GNUNET_free_non_null (cname);
1582     fail_resolution (rh);
1583     return;
1584   }
1585   handle_gns_cname_result (rh,
1586                            cname);
1587   GNUNET_free (cname);
1588 }
1589
1590
1591 /**
1592  * We found a PKEY record, perform recursive resolution on it.
1593  *
1594  * @param rh resolution handle
1595  * @param rd record with PKEY to resolve recursively
1596  */
1597 static void
1598 recursive_pkey_resolution (struct GNS_ResolverHandle *rh,
1599                            const struct GNUNET_GNSRECORD_Data *rd)
1600 {
1601   struct AuthorityChain *ac;
1602
1603   /* delegation to another zone */
1604   if (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) !=
1605       rd->data_size)
1606   {
1607     GNUNET_break_op (0);
1608     fail_resolution (rh);
1609     return;
1610   }
1611   /* expand authority chain */
1612   ac = GNUNET_new (struct AuthorityChain);
1613   ac->rh = rh;
1614   ac->gns_authority = GNUNET_YES;
1615   GNUNET_memcpy (&ac->authority_info.gns_authority,
1616                  rd->data,
1617                  sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1618   ac->label = resolver_lookup_get_next_label (rh);
1619   /* add AC to tail */
1620   GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1621                                     rh->ac_tail,
1622                                     ac);
1623   /* recurse */
1624   rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1625                                           rh);
1626 }
1627
1628
1629 /**
1630  * We found one or more GNS2DNS records, perform recursive resolution on it.
1631  * (to be precise, one or more records in @a rd is GNS2DNS, there may be others,
1632  * so this function still needs to check which ones are GNS2DNS).
1633  *
1634  * @param rh resolution handle
1635  * @param rd_count length of the @a rd array
1636  * @param rd record with PKEY to resolve recursively
1637  * @return #GNUNET_OK if this worked, #GNUNET_SYSERR if no GNS2DNS records were in @a rd
1638  */
1639 static int
1640 recursive_gns2dns_resolution (struct GNS_ResolverHandle *rh,
1641                               unsigned int rd_count,
1642                               const struct GNUNET_GNSRECORD_Data *rd)
1643 {
1644   struct AuthorityChain *ac;
1645   const char *tld;
1646   char *ns;
1647
1648   ns = NULL;
1649   /* expand authority chain */
1650   ac = GNUNET_new (struct AuthorityChain);
1651   ac->rh = rh;
1652   ac->authority_info.dns_authority.dns_handle = GNUNET_DNSSTUB_start (4);
1653
1654   for (unsigned int i=0;i<rd_count;i++)
1655   {
1656     char *ip;
1657     char *n;
1658     size_t off;
1659     struct Gns2DnsPending *gp;
1660     struct GNUNET_CRYPTO_EcdsaPublicKey zone;
1661     struct sockaddr_in v4;
1662     struct sockaddr_in6 v6;
1663
1664     if (GNUNET_GNSRECORD_TYPE_GNS2DNS != rd[i].record_type)
1665       continue;
1666     off = 0;
1667     n = GNUNET_DNSPARSER_parse_name (rd[i].data,
1668                                      rd[i].data_size,
1669                                      &off);
1670     ip = GNUNET_DNSPARSER_parse_name (rd[i].data,
1671                                       rd[i].data_size,
1672                                       &off);
1673     if ( (NULL == n) ||
1674          (NULL == ip) ||
1675          (off != rd[i].data_size) )
1676     {
1677       GNUNET_break_op (0);
1678       GNUNET_free_non_null (n);
1679       GNUNET_free_non_null (ip);
1680       continue;
1681     }
1682     /* resolve 'ip' to determine the IP(s) of the DNS
1683        resolver to use for lookup of 'ns' */
1684     if (NULL != ns)
1685     {
1686       if (0 != strcasecmp (ns,
1687                            n))
1688       {
1689         /* NS values must all be the same for all GNS2DNS records,
1690            anything else leads to insanity */
1691         GNUNET_break_op (0);
1692         GNUNET_free (n);
1693         GNUNET_free (ip);
1694         continue;
1695       }
1696       GNUNET_free (n);
1697     }
1698     else
1699     {
1700       ns = n;
1701     }
1702
1703     /* check if 'ip' is already an IPv4/IPv6 address */
1704     if ( (1 == inet_pton (AF_INET,
1705                           ip,
1706                           &v4)) ||
1707          (1 == inet_pton (AF_INET6,
1708                           ip,
1709                           &v6)) )
1710     {
1711       GNUNET_break (GNUNET_OK ==
1712                     GNUNET_DNSSTUB_add_dns_ip (ac->authority_info.dns_authority.dns_handle,
1713                                                ip));
1714       ac->authority_info.dns_authority.found = GNUNET_YES;
1715       GNUNET_free (ip);
1716       continue;
1717     }
1718     tld = GNS_get_tld (ip);
1719     if (0 != strcmp (tld,
1720                      "+"))
1721     {
1722       /* 'ip' is a DNS name */
1723       gp = GNUNET_new (struct Gns2DnsPending);
1724       gp->ac = ac;
1725       GNUNET_CONTAINER_DLL_insert (ac->authority_info.dns_authority.gp_head,
1726                                    ac->authority_info.dns_authority.gp_tail,
1727                                    gp);
1728       gp->dns_rh = GNUNET_RESOLVER_ip_get (ip,
1729                                            AF_UNSPEC,
1730                                            GNUNET_TIME_UNIT_FOREVER_REL,
1731                                            &handle_gns2dns_ip,
1732                                            gp);
1733       GNUNET_free (ip);
1734       continue;
1735     }
1736     /* 'ip' should be a GNS name */
1737     gp = GNUNET_new (struct Gns2DnsPending);
1738     gp->ac = ac;
1739     GNUNET_CONTAINER_DLL_insert (ac->authority_info.dns_authority.gp_head,
1740                                  ac->authority_info.dns_authority.gp_tail,
1741                                  gp);
1742     gp->rh = GNUNET_new (struct GNS_ResolverHandle);
1743     ip = translate_dot_plus (rh,
1744                              ip);
1745     tld = GNS_get_tld (ip);
1746     if (GNUNET_OK !=
1747         GNUNET_GNSRECORD_zkey_to_pkey (tld,
1748                                        &zone))
1749     {
1750       GNUNET_break_op (0);
1751       GNUNET_free (ip);
1752       continue;
1753     }
1754     gp->rh->authority_zone = zone;
1755     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1756                 "Resolving `%s' to determine IP address of DNS server for GNS2DNS transition for `%s'\n",
1757                 ip,
1758                 ns);
1759     gp->rh->name = ip;
1760     gp->rh->name_resolution_pos = strlen (ip) - strlen (tld) - 1;
1761     gp->rh->proc = &handle_gns2dns_result;
1762     gp->rh->proc_cls = gp;
1763     gp->rh->record_type = GNUNET_GNSRECORD_TYPE_ANY;
1764     gp->rh->options = GNUNET_GNS_LO_DEFAULT;
1765     gp->rh->loop_limiter = rh->loop_limiter + 1;
1766     gp->rh->task_id
1767       = GNUNET_SCHEDULER_add_now (&start_resolver_lookup,
1768                                   gp->rh);
1769   } /* end 'for all records' */
1770
1771   if (NULL == ns)
1772   {
1773     /* not a single GNS2DNS record found */
1774     GNUNET_free (ac);
1775     return GNUNET_SYSERR;
1776   }
1777   GNUNET_assert (strlen (ns) <= GNUNET_DNSPARSER_MAX_NAME_LENGTH);
1778   strcpy (ac->authority_info.dns_authority.name,
1779           ns);
1780   /* for DNS recursion, the label is the full DNS name,
1781      created from the remainder of the GNS name and the
1782      name in the NS record */
1783   GNUNET_asprintf (&ac->label,
1784                    "%.*s%s%s",
1785                    (int) rh->name_resolution_pos,
1786                    rh->name,
1787                    (0 != rh->name_resolution_pos) ? "." : "",
1788                    ns);
1789   GNUNET_free (ns);
1790   GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1791                                     rh->ac_tail,
1792                                     ac);
1793   if (strlen (ac->label) > GNUNET_DNSPARSER_MAX_NAME_LENGTH)
1794   {
1795     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1796                 _("GNS lookup resulted in DNS name that is too long (`%s')\n"),
1797                 ac->label);
1798     return GNUNET_SYSERR;
1799   }
1800   continue_with_gns2dns (ac);
1801   return GNUNET_OK;
1802 }
1803
1804
1805 /**
1806  * Process a records that were decrypted from a block.
1807  *
1808  * @param cls closure with the `struct GNS_ResolverHandle`
1809  * @param rd_count number of entries in @a rd array
1810  * @param rd array of records with data to store
1811  */
1812 static void
1813 handle_gns_resolution_result (void *cls,
1814                               unsigned int rd_count,
1815                               const struct GNUNET_GNSRECORD_Data *rd)
1816 {
1817   struct GNS_ResolverHandle *rh = cls;
1818   char *cname;
1819   struct VpnContext *vpn_ctx;
1820   const struct GNUNET_TUN_GnsVpnRecord *vpn;
1821   const char *vname;
1822   struct GNUNET_HashCode vhash;
1823   int af;
1824   char scratch[UINT16_MAX];
1825   size_t scratch_off;
1826   size_t scratch_start;
1827   size_t off;
1828   struct GNUNET_GNSRECORD_Data rd_new[rd_count];
1829   unsigned int rd_off;
1830
1831   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1832               "Resolution succeeded for `%s' in zone %s, got %u records\n",
1833               rh->ac_tail->label,
1834               GNUNET_GNSRECORD_z2s (&rh->ac_tail->authority_info.gns_authority),
1835               rd_count);
1836   if (0 == rd_count)
1837   {
1838     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1839                 _("GNS lookup failed (zero records found)\n"));
1840     fail_resolution (rh);
1841     return;
1842   }
1843
1844   if (0 == rh->name_resolution_pos)
1845   {
1846     /* top-level match, are we done yet? */
1847     if ( (rd_count > 0) &&
1848          (GNUNET_DNSPARSER_TYPE_CNAME == rd[0].record_type) &&
1849          (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type) )
1850     {
1851       off = 0;
1852       cname = GNUNET_DNSPARSER_parse_name (rd[0].data,
1853                                            rd[0].data_size,
1854                                            &off);
1855       if ( (NULL == cname) ||
1856            (off != rd[0].data_size) )
1857       {
1858         GNUNET_break_op (0);
1859         GNUNET_free_non_null (cname);
1860         fail_resolution (rh);
1861         return;
1862       }
1863       handle_gns_cname_result (rh,
1864                                cname);
1865       GNUNET_free (cname);
1866       return;
1867     }
1868     /* If A/AAAA was requested, but we got a VPN
1869        record, we convert it to A/AAAA using GNUnet VPN */
1870     if ( (GNUNET_DNSPARSER_TYPE_A == rh->record_type) ||
1871          (GNUNET_DNSPARSER_TYPE_AAAA == rh->record_type) )
1872     {
1873       for (unsigned int i=0;i<rd_count;i++)
1874       {
1875         switch (rd[i].record_type)
1876         {
1877         case GNUNET_GNSRECORD_TYPE_VPN:
1878           {
1879             af = (GNUNET_DNSPARSER_TYPE_A == rh->record_type) ? AF_INET : AF_INET6;
1880             if (sizeof (struct GNUNET_TUN_GnsVpnRecord) >
1881                 rd[i].data_size)
1882             {
1883               GNUNET_break_op (0);
1884               fail_resolution (rh);
1885               return;
1886             }
1887             vpn = (const struct GNUNET_TUN_GnsVpnRecord *) rd[i].data;
1888             vname = (const char *) &vpn[1];
1889             if ('\0' != vname[rd[i].data_size - 1 - sizeof (struct GNUNET_TUN_GnsVpnRecord)])
1890             {
1891               GNUNET_break_op (0);
1892               fail_resolution (rh);
1893               return;
1894             }
1895             GNUNET_TUN_service_name_to_hash (vname,
1896                                              &vhash);
1897             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1898                         "Attempting VPN allocation for %s-%s (AF: %d, proto %d)\n",
1899                         GNUNET_i2s (&vpn->peer),
1900                         vname,
1901                         (int) af,
1902                         (int) ntohs (vpn->proto));
1903             vpn_ctx = GNUNET_new (struct VpnContext);
1904             rh->vpn_ctx = vpn_ctx;
1905             vpn_ctx->rh = rh;
1906             vpn_ctx->rd_data_size = GNUNET_GNSRECORD_records_get_size (rd_count,
1907                                                                        rd);
1908             if (vpn_ctx->rd_data_size < 0)
1909             {
1910               GNUNET_break_op (0);
1911               GNUNET_free (vpn_ctx);
1912               fail_resolution (rh);
1913               return;
1914             }
1915             vpn_ctx->rd_data = GNUNET_malloc ((size_t) vpn_ctx->rd_data_size);
1916             vpn_ctx->rd_count = rd_count;
1917             GNUNET_assert (vpn_ctx->rd_data_size ==
1918                            GNUNET_GNSRECORD_records_serialize (rd_count,
1919                                                                rd,
1920                                                                (size_t) vpn_ctx->rd_data_size,
1921                                                                vpn_ctx->rd_data));
1922             vpn_ctx->vpn_request = GNUNET_VPN_redirect_to_peer (vpn_handle,
1923                                                                 af,
1924                                                                 ntohs (vpn->proto),
1925                                                                 &vpn->peer,
1926                                                                 &vhash,
1927                                                                 GNUNET_TIME_relative_to_absolute (VPN_TIMEOUT),
1928                                                                 &vpn_allocation_cb,
1929                                                                 vpn_ctx);
1930             return;
1931           }
1932         case GNUNET_GNSRECORD_TYPE_GNS2DNS:
1933           {
1934             /* delegation to DNS */
1935             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1936                         "Found GNS2DNS record, delegating to DNS!\n");
1937             if (GNUNET_OK ==
1938                 recursive_gns2dns_resolution (rh,
1939                                               rd_count,
1940                                               rd))
1941               return;
1942             else
1943               goto fail;
1944           }
1945         default:
1946           break;
1947         } /* end: switch */
1948       } /* end: for rd */
1949     } /* end: name_resolution_pos */
1950     /* convert relative names in record values to absolute names,
1951        using 'scratch' array for memory allocations */
1952     scratch_off = 0;
1953     rd_off = 0;
1954     for (unsigned int i=0;i<rd_count;i++)
1955     {
1956       GNUNET_assert (rd_off <= i);
1957       if ( (0 != rh->protocol) &&
1958            (0 != rh->service) &&
1959            (GNUNET_GNSRECORD_TYPE_BOX != rd[i].record_type) )
1960         continue; /* we _only_ care about boxed records */
1961
1962       GNUNET_assert (rd_off < rd_count);
1963       rd_new[rd_off] = rd[i];
1964       /* Check if the embedded name(s) end in "+", and if so,
1965          replace the "+" with the zone at "ac_tail", changing the name
1966          to a ".ZONEKEY".  The name is allocated on the 'scratch' array,
1967          so we can free it afterwards. */
1968       switch (rd[i].record_type)
1969       {
1970       case GNUNET_DNSPARSER_TYPE_CNAME:
1971         {
1972           char *cname;
1973
1974           off = 0;
1975           cname = GNUNET_DNSPARSER_parse_name (rd[i].data,
1976                                                rd[i].data_size,
1977                                                &off);
1978           if ( (NULL == cname) ||
1979                (off != rd[i].data_size) )
1980           {
1981             GNUNET_break_op (0); /* record not well-formed */
1982           }
1983           else
1984           {
1985             cname = translate_dot_plus (rh, cname);
1986             GNUNET_break (NULL != cname);
1987             scratch_start = scratch_off;
1988             if (GNUNET_OK !=
1989                 GNUNET_DNSPARSER_builder_add_name (scratch,
1990                                                    sizeof (scratch),
1991                                                    &scratch_off,
1992                                                    cname))
1993             {
1994               GNUNET_break (0);
1995             }
1996             else
1997             {
1998               GNUNET_assert (rd_off < rd_count);
1999               rd_new[rd_off].data = &scratch[scratch_start];
2000               rd_new[rd_off].data_size = scratch_off - scratch_start;
2001               rd_off++;
2002             }
2003           }
2004           GNUNET_free_non_null (cname);
2005         }
2006         break;
2007       case GNUNET_DNSPARSER_TYPE_SOA:
2008         {
2009           struct GNUNET_DNSPARSER_SoaRecord *soa;
2010
2011           off = 0;
2012           soa = GNUNET_DNSPARSER_parse_soa (rd[i].data,
2013                                             rd[i].data_size,
2014                                             &off);
2015           if ( (NULL == soa) ||
2016                (off != rd[i].data_size) )
2017           {
2018             GNUNET_break_op (0); /* record not well-formed */
2019           }
2020           else
2021           {
2022             soa->mname = translate_dot_plus (rh, soa->mname);
2023             soa->rname = translate_dot_plus (rh, soa->rname);
2024             scratch_start = scratch_off;
2025             if (GNUNET_OK !=
2026                 GNUNET_DNSPARSER_builder_add_soa (scratch,
2027                                                   sizeof (scratch),
2028                                                   &scratch_off,
2029                                                   soa))
2030             {
2031               GNUNET_break (0);
2032             }
2033             else
2034             {
2035               GNUNET_assert (rd_off < rd_count);
2036               rd_new[rd_off].data = &scratch[scratch_start];
2037               rd_new[rd_off].data_size = scratch_off - scratch_start;
2038               rd_off++;
2039             }
2040           }
2041           if (NULL != soa)
2042             GNUNET_DNSPARSER_free_soa (soa);
2043         }
2044         break;
2045       case GNUNET_DNSPARSER_TYPE_MX:
2046         {
2047           struct GNUNET_DNSPARSER_MxRecord *mx;
2048
2049           off = 0;
2050           mx = GNUNET_DNSPARSER_parse_mx (rd[i].data,
2051                                           rd[i].data_size,
2052                                           &off);
2053           if ( (NULL == mx) ||
2054                (off != rd[i].data_size) )
2055           {
2056             GNUNET_break_op (0); /* record not well-formed */
2057           }
2058           else
2059           {
2060             mx->mxhost = translate_dot_plus (rh, mx->mxhost);
2061             scratch_start = scratch_off;
2062             if (GNUNET_OK !=
2063                 GNUNET_DNSPARSER_builder_add_mx (scratch,
2064                                                  sizeof (scratch),
2065                                                  &scratch_off,
2066                                                  mx))
2067             {
2068               GNUNET_break (0);
2069             }
2070             else
2071             {
2072               GNUNET_assert (rd_off < rd_count);
2073               rd_new[rd_off].data = &scratch[scratch_start];
2074               rd_new[rd_off].data_size = scratch_off - scratch_start;
2075               rd_off++;
2076             }
2077           }
2078           if (NULL != mx)
2079             GNUNET_DNSPARSER_free_mx (mx);
2080         }
2081         break;
2082       case GNUNET_DNSPARSER_TYPE_SRV:
2083         {
2084           struct GNUNET_DNSPARSER_SrvRecord *srv;
2085
2086           off = 0;
2087           srv = GNUNET_DNSPARSER_parse_srv (rd[i].data,
2088                                             rd[i].data_size,
2089                                             &off);
2090           if ( (NULL == srv) ||
2091                (off != rd[i].data_size) )
2092           {
2093             GNUNET_break_op (0); /* record not well-formed */
2094           }
2095           else
2096           {
2097             srv->target = translate_dot_plus (rh, srv->target);
2098             scratch_start = scratch_off;
2099             if (GNUNET_OK !=
2100                 GNUNET_DNSPARSER_builder_add_srv (scratch,
2101                                                   sizeof (scratch),
2102                                                   &scratch_off,
2103                                                   srv))
2104             {
2105               GNUNET_break (0);
2106             }
2107             else
2108             {
2109               GNUNET_assert (rd_off < rd_count);
2110               rd_new[rd_off].data = &scratch[scratch_start];
2111               rd_new[rd_off].data_size = scratch_off - scratch_start;
2112               rd_off++;
2113             }
2114           }
2115           if (NULL != srv)
2116             GNUNET_DNSPARSER_free_srv (srv);
2117         }
2118         break;
2119
2120       case GNUNET_GNSRECORD_TYPE_NICK:
2121         {
2122           const char *nick;
2123
2124           nick = rd[i].data;
2125           if ((rd[i].data_size > 0) &&
2126               (nick[rd[i].data_size -1] != '\0'))
2127           {
2128             GNUNET_break_op (0);
2129             break;
2130           }
2131           break;
2132         }
2133       case GNUNET_GNSRECORD_TYPE_PKEY:
2134         {
2135           struct GNUNET_CRYPTO_EcdsaPublicKey pub;
2136
2137           if (rd[i].data_size != sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))
2138           {
2139             GNUNET_break_op (0);
2140             break;
2141           }
2142           GNUNET_memcpy (&pub,
2143                          rd[i].data,
2144                          rd[i].data_size);
2145           rd_off++;
2146           if (GNUNET_GNSRECORD_TYPE_PKEY != rh->record_type)
2147           {
2148             /* try to resolve "@" */
2149             struct AuthorityChain *ac;
2150
2151             ac = GNUNET_new (struct AuthorityChain);
2152             ac->rh = rh;
2153             ac->gns_authority = GNUNET_YES;
2154             ac->authority_info.gns_authority = pub;
2155             ac->label = GNUNET_strdup (GNUNET_GNS_EMPTY_LABEL_AT);
2156             GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
2157                                               rh->ac_tail,
2158                                               ac);
2159             rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
2160                                                     rh);
2161             return;
2162           }
2163         }
2164         break;
2165       case GNUNET_GNSRECORD_TYPE_GNS2DNS:
2166         {
2167           /* delegation to DNS */
2168           if (GNUNET_GNSRECORD_TYPE_GNS2DNS == rh->record_type)
2169           {
2170             rd_off++;
2171             break; /* do not follow to DNS, we wanted the GNS2DNS record! */
2172           }
2173           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2174                       "Found GNS2DNS record, delegating to DNS!\n");
2175           if (GNUNET_OK ==
2176               recursive_gns2dns_resolution (rh,
2177                                             rd_count,
2178                                             rd))
2179             return;
2180           else
2181             goto fail;
2182         }
2183       case GNUNET_GNSRECORD_TYPE_BOX:
2184         {
2185           /* unbox SRV/TLSA records if a specific one was requested */
2186           if ( (0 != rh->protocol) &&
2187                (0 != rh->service) &&
2188                (rd[i].data_size >= sizeof (struct GNUNET_GNSRECORD_BoxRecord)) )
2189           {
2190             const struct GNUNET_GNSRECORD_BoxRecord *box;
2191
2192             box = rd[i].data;
2193             if ( (ntohs (box->protocol) == rh->protocol) &&
2194                  (ntohs (box->service) == rh->service) )
2195             {
2196               /* Box matches, unbox! */
2197               GNUNET_assert (rd_off < rd_count);
2198               rd_new[rd_off].record_type = ntohl (box->record_type);
2199               rd_new[rd_off].data_size -= sizeof (struct GNUNET_GNSRECORD_BoxRecord);
2200               rd_new[rd_off].data = &box[1];
2201               rd_off++;
2202             }
2203           }
2204           else
2205           {
2206             /* no specific protocol/service specified, preserve all BOX
2207                records (for modern, GNS-enabled applications) */
2208             rd_off++;
2209           }
2210           break;
2211         }
2212       default:
2213         rd_off++;
2214         break;
2215       } /* end: switch */
2216     } /* end: for rd_count */
2217
2218     /* yes, we are done, return result */
2219     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2220                 "Returning GNS response for `%s' with %u answers\n",
2221                 rh->ac_tail->label,
2222                 rd_off);
2223     rh->proc (rh->proc_cls,
2224               rd_off,
2225               rd_new);
2226     rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2227                                             rh);
2228     return;
2229   }
2230
2231   switch (rd[0].record_type)
2232   {
2233   case GNUNET_DNSPARSER_TYPE_CNAME:
2234     GNUNET_break_op (1 == rd_count); /* CNAME should be unique */
2235     recursive_cname_resolution (rh,
2236                                 &rd[0]);
2237     return;
2238   case GNUNET_GNSRECORD_TYPE_PKEY:
2239     GNUNET_break_op (1 == rd_count); /* PKEY should be unique */
2240     recursive_pkey_resolution (rh,
2241                                &rd[0]);
2242     return;
2243   default:
2244     if (GNUNET_OK ==
2245         recursive_gns2dns_resolution (rh,
2246                                       rd_count,
2247                                       rd))
2248       return;
2249     break;
2250   }
2251  fail:
2252   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2253               _("GNS lookup recursion failed (no delegation record found)\n"));
2254   fail_resolution (rh);
2255 }
2256
2257
2258 /**
2259  * Function called once the namestore has completed the request for
2260  * caching a block.
2261  *
2262  * @param cls closure with the `struct CacheOps`
2263  * @param success #GNUNET_OK on success
2264  * @param emsg error message
2265  */
2266 static void
2267 namecache_cache_continuation (void *cls,
2268                               int32_t success,
2269                               const char *emsg)
2270 {
2271   struct CacheOps *co = cls;
2272
2273   co->namecache_qe_cache = NULL;
2274   if (GNUNET_OK != success)
2275     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2276                 _("Failed to cache GNS resolution: %s\n"),
2277                 emsg);
2278   GNUNET_CONTAINER_DLL_remove (co_head,
2279                                co_tail,
2280                                co);
2281   GNUNET_free (co);
2282 }
2283
2284
2285 /**
2286  * Iterator called on each result obtained for a DHT
2287  * operation that expects a reply
2288  *
2289  * @param cls closure with the `struct GNS_ResolverHandle`
2290  * @param exp when will this value expire
2291  * @param key key of the result
2292  * @param get_path peers on reply path (or NULL if not recorded)
2293  *                 [0] = datastore's first neighbor, [length - 1] = local peer
2294  * @param get_path_length number of entries in @a get_path
2295  * @param put_path peers on the PUT path (or NULL if not recorded)
2296  *                 [0] = origin, [length - 1] = datastore
2297  * @param put_path_length number of entries in @a put_path
2298  * @param type type of the result
2299  * @param size number of bytes in data
2300  * @param data pointer to the result data
2301  */
2302 static void
2303 handle_dht_response (void *cls,
2304                      struct GNUNET_TIME_Absolute exp,
2305                      const struct GNUNET_HashCode *key,
2306                      const struct GNUNET_PeerIdentity *get_path,
2307                      unsigned int get_path_length,
2308                      const struct GNUNET_PeerIdentity *put_path,
2309                      unsigned int put_path_length,
2310                      enum GNUNET_BLOCK_Type type,
2311                      size_t size,
2312                      const void *data)
2313 {
2314   struct GNS_ResolverHandle *rh = cls;
2315   struct AuthorityChain *ac = rh->ac_tail;
2316   const struct GNUNET_GNSRECORD_Block *block;
2317   struct CacheOps *co;
2318
2319   (void) exp;
2320   (void) key;
2321   (void) get_path;
2322   (void) get_path_length;
2323   (void) put_path;
2324   (void) put_path_length;
2325   (void) type;
2326   GNUNET_DHT_get_stop (rh->get_handle);
2327   rh->get_handle = NULL;
2328   GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
2329   rh->dht_heap_node = NULL;
2330   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2331               "Handling response from the DHT\n");
2332   if (size < sizeof (struct GNUNET_GNSRECORD_Block))
2333   {
2334     /* how did this pass DHT block validation!? */
2335     GNUNET_break (0);
2336     fail_resolution (rh);
2337     return;
2338   }
2339   block = data;
2340   if (size !=
2341       ntohl (block->purpose.size) +
2342       sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) +
2343       sizeof (struct GNUNET_CRYPTO_EcdsaSignature))
2344   {
2345     /* how did this pass DHT block validation!? */
2346     GNUNET_break (0);
2347     fail_resolution (rh);
2348     return;
2349   }
2350   if (GNUNET_OK !=
2351       GNUNET_GNSRECORD_block_decrypt (block,
2352                                       &ac->authority_info.gns_authority,
2353                                       ac->label,
2354                                       &handle_gns_resolution_result,
2355                                       rh))
2356   {
2357     GNUNET_break_op (0); /* block was ill-formed */
2358     fail_resolution (rh);
2359     return;
2360   }
2361   if (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (block->expiration_time)).rel_value_us)
2362   {
2363     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2364                 "Received expired block from the DHT, will not cache it.\n");
2365     return;
2366   }
2367   /* Cache well-formed blocks */
2368   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2369               "Caching response from the DHT in namecache\n");
2370   co = GNUNET_new (struct CacheOps);
2371   co->namecache_qe_cache = GNUNET_NAMECACHE_block_cache (namecache_handle,
2372                                                          block,
2373                                                          &namecache_cache_continuation,
2374                                                          co);
2375   GNUNET_CONTAINER_DLL_insert (co_head,
2376                                co_tail,
2377                                co);
2378 }
2379
2380
2381 /**
2382  * Initiate a DHT query for a set of GNS records.
2383  *
2384  * @param rh resolution handle
2385  * @param query key to use in the DHT lookup
2386  */
2387 static void
2388 start_dht_request (struct GNS_ResolverHandle *rh,
2389                    const struct GNUNET_HashCode *query)
2390 {
2391   struct GNS_ResolverHandle *rx;
2392
2393   GNUNET_assert (NULL == rh->get_handle);
2394   rh->get_handle = GNUNET_DHT_get_start (dht_handle,
2395                                          GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
2396                                          query,
2397                                          DHT_GNS_REPLICATION_LEVEL,
2398                                          GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
2399                                          NULL, 0,
2400                                          &handle_dht_response, rh);
2401   rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
2402                                                     rh,
2403                                                     GNUNET_TIME_absolute_get ().abs_value_us);
2404   if (GNUNET_CONTAINER_heap_get_size (dht_lookup_heap) > max_allowed_background_queries)
2405   {
2406     /* fail longest-standing DHT request */
2407     rx = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
2408     rx->dht_heap_node = NULL;
2409     GNUNET_assert (NULL != rx);
2410     fail_resolution (rx);
2411   }
2412 }
2413
2414
2415 /**
2416  * Process a records that were decrypted from a block that we got from
2417  * the namecache.  Simply calls #handle_gns_resolution_result().
2418  *
2419  * @param cls closure with the `struct GNS_ResolverHandle`
2420  * @param rd_count number of entries in @a rd array
2421  * @param rd array of records with data to store
2422  */
2423 static void
2424 handle_gns_namecache_resolution_result (void *cls,
2425                                         unsigned int rd_count,
2426                                         const struct GNUNET_GNSRECORD_Data *rd)
2427 {
2428   struct GNS_ResolverHandle *rh = cls;
2429
2430   handle_gns_resolution_result (rh,
2431                                 rd_count,
2432                                 rd);
2433 }
2434
2435
2436 /**
2437  * Process a record that was stored in the namecache.
2438  *
2439  * @param cls closure with the `struct GNS_ResolverHandle`
2440  * @param block block that was stored in the namecache
2441  */
2442 static void
2443 handle_namecache_block_response (void *cls,
2444                                  const struct GNUNET_GNSRECORD_Block *block)
2445 {
2446   struct GNS_ResolverHandle *rh = cls;
2447   struct AuthorityChain *ac = rh->ac_tail;
2448   const char *label = ac->label;
2449   const struct GNUNET_CRYPTO_EcdsaPublicKey *auth = &ac->authority_info.gns_authority;
2450   struct GNUNET_HashCode query;
2451
2452   GNUNET_assert (NULL != rh->namecache_qe);
2453   rh->namecache_qe = NULL;
2454   if ( ( (GNUNET_GNS_LO_DEFAULT == rh->options) ||
2455          ( (GNUNET_GNS_LO_LOCAL_MASTER == rh->options) &&
2456            (ac != rh->ac_head) ) ) &&
2457        ( (NULL == block) ||
2458          (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (block->expiration_time)).rel_value_us) ) )
2459   {
2460     /* namecache knows nothing; try DHT lookup */
2461     GNUNET_GNSRECORD_query_from_public_key (auth,
2462                                             label,
2463                                             &query);
2464     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2465                 "Starting DHT lookup for `%s' in zone `%s' under key `%s'\n",
2466                 ac->label,
2467                 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority),
2468                 GNUNET_h2s (&query));
2469     start_dht_request (rh, &query);
2470     return;
2471   }
2472
2473   if ( (NULL == block) ||
2474        (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (block->expiration_time)).rel_value_us) )
2475   {
2476     /* DHT not permitted and no local result, fail */
2477     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2478                 "Resolution failed for `%s' in zone %s (DHT lookup not permitted by configuration)\n",
2479                 ac->label,
2480                 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2481     fail_resolution (rh);
2482     return;
2483   }
2484   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2485               "Received result from namecache for label `%s'\n",
2486               ac->label);
2487
2488   if (GNUNET_OK !=
2489       GNUNET_GNSRECORD_block_decrypt (block,
2490                                       auth,
2491                                       label,
2492                                       &handle_gns_namecache_resolution_result,
2493                                       rh))
2494   {
2495     GNUNET_break_op (0); /* block was ill-formed */
2496     /* try DHT instead */
2497     GNUNET_GNSRECORD_query_from_public_key (auth,
2498                                             label,
2499                                             &query);
2500     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2501                 "Starting DHT lookup for `%s' in zone `%s' under key `%s'\n",
2502                 ac->label,
2503                 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority),
2504                 GNUNET_h2s (&query));
2505     start_dht_request (rh, &query);
2506     return;
2507   }
2508 }
2509
2510
2511 /**
2512  * Lookup tail of our authority chain in the namecache.
2513  *
2514  * @param rh query we are processing
2515  */
2516 static void
2517 recursive_gns_resolution_namecache (struct GNS_ResolverHandle *rh)
2518 {
2519   struct AuthorityChain *ac = rh->ac_tail;
2520   struct GNUNET_HashCode query;
2521
2522   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2523               "Starting GNS resolution for `%s' in zone %s\n",
2524               ac->label,
2525               GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2526   GNUNET_GNSRECORD_query_from_public_key (&ac->authority_info.gns_authority,
2527                                           ac->label,
2528                                           &query);
2529   if (GNUNET_YES != disable_cache)
2530   {
2531     rh->namecache_qe
2532       = GNUNET_NAMECACHE_lookup_block (namecache_handle,
2533                                        &query,
2534                                        &handle_namecache_block_response,
2535                                        rh);
2536     GNUNET_assert (NULL != rh->namecache_qe);
2537   }
2538   else
2539   {
2540     start_dht_request (rh,
2541                        &query);
2542   }
2543 }
2544
2545
2546 /**
2547  * Function called with the result from a revocation check.
2548  *
2549  * @param cls the `struct GNS_ResovlerHandle`
2550  * @param is_valid #GNUNET_YES if the zone was not yet revoked
2551  */
2552 static void
2553 handle_revocation_result (void *cls,
2554                           int is_valid)
2555 {
2556   struct GNS_ResolverHandle *rh = cls;
2557   struct AuthorityChain *ac = rh->ac_tail;
2558
2559   rh->rev_check = NULL;
2560   if (GNUNET_YES != is_valid)
2561   {
2562     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2563                 _("Zone %s was revoked, resolution fails\n"),
2564                 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2565     fail_resolution (rh);
2566     return;
2567   }
2568   recursive_gns_resolution_namecache (rh);
2569 }
2570
2571
2572 /**
2573  * Perform revocation check on tail of our authority chain.
2574  *
2575  * @param rh query we are processing
2576  */
2577 static void
2578 recursive_gns_resolution_revocation (struct GNS_ResolverHandle *rh)
2579 {
2580   struct AuthorityChain *ac = rh->ac_tail;
2581
2582   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2583               "Starting revocation check for zone %s\n",
2584               GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2585   rh->rev_check = GNUNET_REVOCATION_query (cfg,
2586                                            &ac->authority_info.gns_authority,
2587                                            &handle_revocation_result,
2588                                            rh);
2589   GNUNET_assert (NULL != rh->rev_check);
2590 }
2591
2592
2593 /**
2594  * Task scheduled to continue with the resolution process.
2595  *
2596  * @param cls the `struct GNS_ResolverHandle` of the resolution
2597  */
2598 static void
2599 recursive_resolution (void *cls)
2600 {
2601   struct GNS_ResolverHandle *rh = cls;
2602
2603   rh->task_id = NULL;
2604   if (MAX_RECURSION < rh->loop_limiter++)
2605   {
2606     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2607                 "Encountered unbounded recursion resolving `%s'\n",
2608                 rh->name);
2609     fail_resolution (rh);
2610     return;
2611   }
2612   if (GNUNET_YES == rh->ac_tail->gns_authority)
2613     recursive_gns_resolution_revocation (rh);
2614   else
2615     recursive_dns_resolution (rh);
2616 }
2617
2618
2619 /**
2620  * Begin the resolution process from 'name', starting with
2621  * the identification of the zone specified by 'name'.
2622  *
2623  * @param cls the `struct GNS_ResolverHandle`
2624  */
2625 static void
2626 start_resolver_lookup (void *cls)
2627 {
2628   struct GNS_ResolverHandle *rh = cls;
2629   struct AuthorityChain *ac;
2630   struct in_addr v4;
2631   struct in6_addr v6;
2632
2633   rh->task_id = NULL;
2634   if (1 == inet_pton (AF_INET,
2635                       rh->name,
2636                       &v4))
2637   {
2638     /* name is IPv4 address, pretend it's an A record */
2639     struct GNUNET_GNSRECORD_Data rd;
2640
2641     rd.data = &v4;
2642     rd.data_size = sizeof (v4);
2643     rd.expiration_time = UINT64_MAX;
2644     rd.record_type = GNUNET_DNSPARSER_TYPE_A;
2645     rd.flags = 0;
2646     rh->proc (rh->proc_cls,
2647               1,
2648               &rd);
2649     GNUNET_assert (NULL == rh->task_id);
2650     rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2651                                             rh);
2652     return;
2653   }
2654   if (1 == inet_pton (AF_INET6,
2655                       rh->name,
2656                       &v6))
2657   {
2658     /* name is IPv6 address, pretend it's an AAAA record */
2659     struct GNUNET_GNSRECORD_Data rd;
2660
2661     rd.data = &v6;
2662     rd.data_size = sizeof (v6);
2663     rd.expiration_time = UINT64_MAX;
2664     rd.record_type = GNUNET_DNSPARSER_TYPE_AAAA;
2665     rd.flags = 0;
2666     rh->proc (rh->proc_cls,
2667               1,
2668               &rd);
2669     GNUNET_assert (NULL == rh->task_id);
2670     rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2671                                             rh);
2672     return;
2673   }
2674
2675   ac = GNUNET_new (struct AuthorityChain);
2676   ac->rh = rh;
2677   ac->label = resolver_lookup_get_next_label (rh);
2678   if (NULL == ac->label)
2679     /* name was just the "TLD", so we default to label
2680        #GNUNET_GNS_EMPTY_LABEL_AT */
2681     ac->label = GNUNET_strdup (GNUNET_GNS_EMPTY_LABEL_AT);
2682   ac->gns_authority = GNUNET_YES;
2683   ac->authority_info.gns_authority = rh->authority_zone;
2684   GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
2685                                     rh->ac_tail,
2686                                     ac);
2687   rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
2688                                           rh);
2689 }
2690
2691
2692 /**
2693  * Lookup of a record in a specific zone calls lookup result processor
2694  * on result.
2695  *
2696  * @param zone the zone to perform the lookup in
2697  * @param record_type the record type to look up
2698  * @param name the name to look up
2699  * @param options local options to control local lookup
2700  * @param proc the processor to call on result
2701  * @param proc_cls the closure to pass to @a proc
2702  * @return handle to cancel operation
2703  */
2704 struct GNS_ResolverHandle *
2705 GNS_resolver_lookup (const struct GNUNET_CRYPTO_EcdsaPublicKey *zone,
2706                      uint32_t record_type,
2707                      const char *name,
2708                      enum GNUNET_GNS_LocalOptions options,
2709                      GNS_ResultProcessor proc,
2710                      void *proc_cls)
2711 {
2712   struct GNS_ResolverHandle *rh;
2713
2714   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2715               "Starting lookup for `%s'\n",
2716               name);
2717   rh = GNUNET_new (struct GNS_ResolverHandle);
2718   GNUNET_CONTAINER_DLL_insert (rlh_head,
2719                                rlh_tail,
2720                                rh);
2721   rh->authority_zone = *zone;
2722   rh->proc = proc;
2723   rh->proc_cls = proc_cls;
2724   rh->options = options;
2725   rh->record_type = record_type;
2726   rh->name = GNUNET_strdup (name);
2727   rh->name_resolution_pos = strlen (name);
2728   rh->task_id = GNUNET_SCHEDULER_add_now (&start_resolver_lookup,
2729                                           rh);
2730   return rh;
2731 }
2732
2733
2734 /**
2735  * Cancel active resolution (i.e. client disconnected).
2736  *
2737  * @param rh resolution to abort
2738  */
2739 void
2740 GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
2741 {
2742   struct DnsResult *dr;
2743   struct AuthorityChain *ac;
2744   struct VpnContext *vpn_ctx;
2745
2746   GNUNET_CONTAINER_DLL_remove (rlh_head,
2747                                rlh_tail,
2748                                rh);
2749   if (NULL != rh->dns_request)
2750   {
2751     GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
2752     rh->dns_request = NULL;
2753   }
2754   while (NULL != (ac = rh->ac_head))
2755   {
2756     GNUNET_CONTAINER_DLL_remove (rh->ac_head,
2757                                  rh->ac_tail,
2758                                  ac);
2759     if (GNUNET_NO == ac->gns_authority)
2760     {
2761       struct Gns2DnsPending *gp;
2762
2763       while (NULL != (gp = ac->authority_info.dns_authority.gp_head))
2764       {
2765         GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
2766                                      ac->authority_info.dns_authority.gp_tail,
2767                                      gp);
2768         if (NULL != gp->rh)
2769         {
2770           /* rh->g2dc->rh is NOT in the DLL yet, so to enable us
2771              using GNS_resolver_lookup_cancel here, we need to
2772              add it first... */
2773           GNUNET_CONTAINER_DLL_insert (rlh_head,
2774                                        rlh_tail,
2775                                        gp->rh);
2776           GNUNET_assert (NULL == gp->rh->task_id);
2777           gp->rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2778                                                       gp->rh);
2779           gp->rh = NULL;
2780         }
2781         if (NULL != gp->dns_rh)
2782         {
2783           GNUNET_RESOLVER_request_cancel (gp->dns_rh);
2784           gp->dns_rh = NULL;
2785         }
2786         GNUNET_free (gp);
2787       }
2788       GNUNET_DNSSTUB_stop (ac->authority_info.dns_authority.dns_handle);
2789     }
2790     GNUNET_free (ac->label);
2791     GNUNET_free (ac);
2792   }
2793   if (NULL != rh->task_id)
2794   {
2795     GNUNET_SCHEDULER_cancel (rh->task_id);
2796     rh->task_id = NULL;
2797   }
2798   if (NULL != rh->get_handle)
2799   {
2800     GNUNET_DHT_get_stop (rh->get_handle);
2801     rh->get_handle = NULL;
2802   }
2803   if (NULL != rh->dht_heap_node)
2804   {
2805     GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
2806     rh->dht_heap_node = NULL;
2807   }
2808   if (NULL != (vpn_ctx = rh->vpn_ctx))
2809   {
2810     GNUNET_VPN_cancel_request (vpn_ctx->vpn_request);
2811     GNUNET_free (vpn_ctx->rd_data);
2812     GNUNET_free (vpn_ctx);
2813   }
2814   if (NULL != rh->namecache_qe)
2815   {
2816     GNUNET_NAMECACHE_cancel (rh->namecache_qe);
2817     rh->namecache_qe = NULL;
2818   }
2819   if (NULL != rh->rev_check)
2820   {
2821     GNUNET_REVOCATION_query_cancel (rh->rev_check);
2822     rh->rev_check = NULL;
2823   }
2824   if (NULL != rh->std_resolve)
2825   {
2826     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2827                 "Canceling standard DNS resolution\n");
2828     GNUNET_RESOLVER_request_cancel (rh->std_resolve);
2829     rh->std_resolve = NULL;
2830   }
2831   while (NULL != (dr = rh->dns_result_head))
2832   {
2833     GNUNET_CONTAINER_DLL_remove (rh->dns_result_head,
2834                                  rh->dns_result_tail,
2835                                  dr);
2836     GNUNET_free (dr);
2837   }
2838   GNUNET_free (rh->name);
2839   GNUNET_free (rh);
2840 }
2841
2842
2843 /* ***************** Resolver initialization ********************* */
2844
2845
2846 /**
2847  * Initialize the resolver
2848  *
2849  * @param nc the namecache handle
2850  * @param dht the dht handle
2851  * @param c configuration handle
2852  * @param max_bg_queries maximum number of parallel background queries in dht
2853  */
2854 void
2855 GNS_resolver_init (struct GNUNET_NAMECACHE_Handle *nc,
2856                    struct GNUNET_DHT_Handle *dht,
2857                    const struct GNUNET_CONFIGURATION_Handle *c,
2858                    unsigned long long max_bg_queries)
2859 {
2860   cfg = c;
2861   namecache_handle = nc;
2862   dht_handle = dht;
2863   dht_lookup_heap =
2864     GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
2865   max_allowed_background_queries = max_bg_queries;
2866   disable_cache = GNUNET_CONFIGURATION_get_value_yesno (cfg,
2867                                                         "namecache",
2868                                                         "DISABLE");
2869   if (GNUNET_YES == disable_cache)
2870     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2871                 "Namecache disabled\n");
2872   vpn_handle = GNUNET_VPN_connect (cfg);
2873 }
2874
2875
2876 /**
2877  * Shutdown resolver
2878  */
2879 void
2880 GNS_resolver_done ()
2881 {
2882   struct GNS_ResolverHandle *rh;
2883   struct CacheOps *co;
2884
2885   /* abort active resolutions */
2886   while (NULL != (rh = rlh_head))
2887   {
2888     rh->proc (rh->proc_cls,
2889               0,
2890               NULL);
2891     GNS_resolver_lookup_cancel (rh);
2892   }
2893   while (NULL != (co = co_head))
2894   {
2895     GNUNET_CONTAINER_DLL_remove (co_head,
2896                                  co_tail,
2897                                  co);
2898     GNUNET_NAMECACHE_cancel (co->namecache_qe_cache);
2899     GNUNET_free (co);
2900   }
2901   GNUNET_CONTAINER_heap_destroy (dht_lookup_heap);
2902   dht_lookup_heap = NULL;
2903   GNUNET_VPN_disconnect (vpn_handle);
2904   vpn_handle = NULL;
2905   dht_handle = NULL;
2906   namecache_handle = NULL;
2907 }
2908
2909
2910 /* end of gnunet-service-gns_resolver.c */