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