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