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