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