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