-towards translating .+ names in GNS records
[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 GNUnet GNS resolver logic
24  * @author Martin Schanzenbach
25  * @author Christian Grothoff
26  *
27  * TODO:
28  * - GNS: handle special SRV names --- no delegation, direct lookup;
29  *        can likely be done in 'resolver_lookup_get_next_label'.
30  * - GNS: expand ".+" in returned values to the respective absolute
31  *        name using '.zkey'
32  * - shortening triggers
33  * - revocation checks (make optional: privacy!)
34  * - DNAME support
35  *
36  * Issues:
37  * - We currently go to the DHT simply if we find no local reply; this
38  *   is incorrect; the correct rules for going to DHT are:
39  *
40  * 1. The entry in the DHT is RSL_RECORD_EXPIRED OR
41  * 2. No entry in the NS existed AND
42  * 3. The zone queried is not the local resolver's zone AND
43  * 4. The name that was looked up is '+'
44  *    because if it was any other canonical name we either already queried
45  *    the DHT for the authority in the authority lookup phase (and thus
46  *    would already have an entry in the NS for the record)
47  * 5. We are not in cache only mode
48  *
49  * - We currently never look "into" the records; for example,
50  *   MX, SRV and SOA records may include ".+" that need to be
51  *   handled
52  *
53  */
54 #include "platform.h"
55 #include "gnunet_util_lib.h"
56 #include "gnunet_dnsstub_lib.h"
57 #include "gnunet_dht_service.h"
58 #include "gnunet_namestore_service.h"
59 #include "gnunet_dns_service.h"
60 #include "gnunet_resolver_service.h"
61 #include "gnunet_dnsparser_lib.h"
62 #include "gnunet_gns_service.h"
63 #include "gns.h"
64 #include "gnunet-service-gns_resolver.h"
65 #include "gnunet-service-gns_shorten.h"
66 #include "gnunet_vpn_service.h"
67
68
69 /**
70  * Default DHT timeout for lookups.
71  */
72 #define DHT_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
73
74 /**
75  * Default timeout for DNS lookups.
76  */
77 #define DNS_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
78
79 /**
80  * Default timeout for VPN redirections.
81  */
82 #define VPN_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
83
84 /**
85  * DHT replication level
86  */
87 #define DHT_GNS_REPLICATION_LEVEL 5
88
89 /**
90  * How deep do we allow recursions to go before we abort?
91  */
92 #define MAX_RECURSION 256
93
94
95 /**
96  * DLL to hold the authority chain we had to pass in the resolution
97  * process.
98  */
99 struct AuthorityChain
100 {
101   /**
102    * This is a DLL.
103    */
104   struct AuthorityChain *prev;
105
106   /**
107    * This is a DLL.
108    */
109   struct AuthorityChain *next;
110
111   /**
112    * Resolver handle this entry in the chain belongs to.
113    */
114   struct GNS_ResolverHandle *rh;
115
116   /**
117    * label/name corresponding to the authority 
118    */
119   char *label;
120   
121   /**
122    * #GNUNET_YES if the authority was a GNS authority,
123    * #GNUNET_NO if the authority was a DNS authority.
124    */
125   int gns_authority;
126
127   /**
128    * Information about the resolver authority for this label.
129    */
130   union
131   {
132
133     /**
134      * The zone of the GNS authority 
135      */
136     struct GNUNET_CRYPTO_EccPublicKey gns_authority;
137
138     struct
139     {
140       /**
141        * Domain of the DNS resolver that is the authority.
142        * (appended to construct the DNS name to resolve;
143        * this is NOT the DNS name of the DNS server!).
144        */
145       char name[GNUNET_DNSPARSER_MAX_NAME_LENGTH + 1];
146
147       /**
148        * IP address of the DNS resolver that is authoritative.
149        * (this implementation currently only supports one
150        * IP at a time).
151        */
152       struct sockaddr_storage dns_ip;
153
154     } dns_authority;
155
156   } authority_info;
157   
158 };
159
160
161 /**
162  * A result we got from DNS.
163  */
164 struct DnsResult
165 {
166
167   /**
168    * Kept in DLL.
169    */
170   struct DnsResult *next;
171
172   /**
173    * Kept in DLL.
174    */
175   struct DnsResult *prev;
176
177   /**
178    * Binary value stored in the DNS record (appended to this struct)
179    */
180   const void *data;
181
182   /**
183    * Expiration time for the DNS record, 0 if we didn't
184    * get anything useful (i.e. 'gethostbyname' was used).
185    */
186   uint64_t expiration_time;
187
188   /**
189    * Number of bytes in 'data'.
190    */
191   size_t data_size;
192
193   /**
194    * Type of the GNS/DNS record.
195    */
196   uint32_t record_type;
197
198 };
199
200
201 /**
202  * Closure for #vpn_allocation_cb.
203  */
204 struct VpnContext 
205 {
206
207   /** 
208    * Which resolution process are we processing.
209    */
210   struct GNS_ResolverHandle *rh;
211
212   /**
213    * Handle to the VPN request that we were performing.
214    */
215   struct GNUNET_VPN_RedirectionRequest *vpn_request;
216
217   /**
218    * Number of records serialized in 'rd_data'.
219    */
220   unsigned int rd_count;
221   
222   /**
223    * Serialized records.
224    */
225   char *rd_data;
226   
227   /**
228    * Number of bytes in 'rd_data'.
229    */
230   size_t rd_data_size;
231 };
232
233
234 /**
235  * Handle to a currenty pending resolution.  On result (positive or
236  * negative) the #GNS_ResultProcessor is called.  
237  */
238 struct GNS_ResolverHandle
239 {
240
241   /**
242    * DLL 
243    */
244   struct GNS_ResolverHandle *next;
245
246   /**
247    * DLL 
248    */
249   struct GNS_ResolverHandle *prev;
250
251   /**
252    * The top-level GNS authoritative zone to query 
253    */
254   struct GNUNET_CRYPTO_EccPublicKey authority_zone;
255
256   /**
257    * called when resolution phase finishes 
258    */
259   GNS_ResultProcessor proc;
260   
261   /**
262    * closure passed to proc 
263    */
264   void* proc_cls;
265
266   /**
267    * Handle for DHT lookups. should be NULL if no lookups are in progress 
268    */
269   struct GNUNET_DHT_GetHandle *get_handle;
270
271   /**
272    * Handle to a VPN request, NULL if none is active.
273    */
274   struct VpnContext *vpn_ctx;
275
276   /**
277    * Socket for a DNS request, NULL if none is active.
278    */
279   struct GNUNET_DNSSTUB_RequestSocket *dns_request;
280
281   /**
282    * Handle for standard DNS resolution, NULL if none is active.
283    */
284   struct GNUNET_RESOLVER_RequestHandle *std_resolve;
285
286   /**
287    * Pending Namestore task
288    */
289   struct GNUNET_NAMESTORE_QueueEntry *namestore_qe;
290
291   /**
292    * Heap node associated with this lookup.  Used to limit number of
293    * concurrent requests.
294    */
295   struct GNUNET_CONTAINER_HeapNode *dht_heap_node;
296
297   /**
298    * DLL to store the authority chain 
299    */
300   struct AuthorityChain *ac_head;
301
302   /**
303    * DLL to store the authority chain 
304    */
305   struct AuthorityChain *ac_tail;
306
307   /**
308    * Private key of the shorten zone, NULL to not shorten.
309    */
310   struct GNUNET_CRYPTO_EccPrivateKey *shorten_key;
311
312   /**
313    * ID of a task associated with the resolution process.
314    */
315   GNUNET_SCHEDULER_TaskIdentifier task_id;
316
317   /**
318    * The name to resolve 
319    */
320   char *name;
321
322   /**
323    * DLL of results we got from DNS.
324    */
325   struct DnsResult *dns_result_head;
326
327   /**
328    * DLL of results we got from DNS.
329    */
330   struct DnsResult *dns_result_tail;
331
332   /**
333    * Current offset in 'name' where we are resolving.
334    */
335   size_t name_resolution_pos;
336
337   /**
338    * Use only cache 
339    */
340   int only_cached;
341
342   /**
343    * Desired type for the resolution.
344    */
345   int record_type;
346
347   /**
348    * We increment the loop limiter for each step in a recursive
349    * resolution.  If it passes our threshold (i.e. due to 
350    * self-recursion in the resolution, i.e CNAME fun), we stop.
351    */
352   unsigned int loop_limiter;
353
354 };
355
356
357 /**
358  * Our handle to the namestore service
359  */
360 static struct GNUNET_NAMESTORE_Handle *namestore_handle;
361
362 /**
363  * Our handle to the vpn service
364  */
365 static struct GNUNET_VPN_Handle *vpn_handle;
366
367 /**
368  * Resolver handle to the dht
369  */
370 static struct GNUNET_DHT_Handle *dht_handle;
371
372 /**
373  * Handle to perform DNS lookups.
374  */
375 static struct GNUNET_DNSSTUB_Context *dns_handle;
376
377 /**
378  * Heap for limiting parallel DHT lookups
379  */
380 static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
381
382 /**
383  * Maximum amount of parallel queries to the DHT
384  */
385 static unsigned long long max_allowed_background_queries;
386
387 /**
388  * Head of resolver lookup list
389  */
390 static struct GNS_ResolverHandle *rlh_head;
391
392 /**
393  * Tail of resolver lookup list
394  */
395 static struct GNS_ResolverHandle *rlh_tail;
396
397 /**
398  * Global configuration.
399  */
400 static const struct GNUNET_CONFIGURATION_Handle *cfg;
401
402
403 /**
404  * Check if name is in srv format (_x._y.xxx)
405  *
406  * @param name
407  * @return GNUNET_YES if true
408  */
409 static int
410 is_srv (const char *name)
411 {
412   char *ndup;
413   int ret;
414
415   if (*name != '_')
416     return GNUNET_NO;
417   if (NULL == strstr (name, "._"))
418     return GNUNET_NO;
419   ret = GNUNET_YES;
420   ndup = GNUNET_strdup (name);
421   strtok (ndup, ".");
422   if (NULL == strtok (NULL, "."))
423     ret = GNUNET_NO;
424   if (NULL == strtok (NULL, "."))
425     ret = GNUNET_NO;
426   if (NULL != strtok (NULL, "."))
427     ret = GNUNET_NO;
428   GNUNET_free (ndup);
429   return ret;
430 }
431
432
433 /**
434  * Determine if this name is canonical (is a legal name in a zone, without delegation);
435  * note that we do not test that the name does not contain illegal characters, we only
436  * test for delegation.  Note that service records (i.e. _foo._srv) are canonical names
437  * even though they consist of multiple labels.
438  *
439  * Examples:
440  * a.b.gnu  = not canonical
441  * a         = canonical
442  * _foo._srv = canonical
443  * _f.bar    = not canonical
444  *
445  * @param name the name to test
446  * @return GNUNET_YES if canonical
447  */
448 static int
449 is_canonical (const char *name)
450 {
451   const char *pos;
452   const char *dot;
453
454   if (NULL == strchr (name, '.'))
455     return GNUNET_YES;
456   if ('_' != name[0])
457     return GNUNET_NO;
458   pos = &name[1];
459   while (NULL != (dot = strchr (pos, '.')))    
460     if ('_' != dot[1])
461       return GNUNET_NO;
462     else
463       pos = dot + 1;
464   return GNUNET_YES;
465 }
466
467
468
469 /* ************************** Resolution **************************** */
470
471 #if 0
472
473
474 //FIXME maybe define somewhere else?
475 #define MAX_SOA_LENGTH sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)\
476                         +(GNUNET_DNSPARSER_MAX_NAME_LENGTH*2)
477 #define MAX_MX_LENGTH sizeof(uint16_t)+GNUNET_DNSPARSER_MAX_NAME_LENGTH
478 #define MAX_SRV_LENGTH (sizeof(uint16_t)*3)+GNUNET_DNSPARSER_MAX_NAME_LENGTH
479
480
481 /**
482  * Exands a name ending in .+ with the zone of origin.
483  * FIXME: funky api: 'dest' must be large enough to hold
484  * the result; this is a bit yucky...
485  *
486  * @param dest destination buffer
487  * @param src the .+ name
488  * @param repl the string to replace the + with
489  */
490 static void
491 expand_plus (char* dest, 
492              const char* src, 
493              const char* repl)
494 {
495   char* pos;
496   size_t s_len = strlen (src) + 1;
497
498   //Eh? I guess this is at least strlen ('x.+') == 3 FIXME
499   if (3 > s_len)
500   {
501     /* no postprocessing */
502     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
503                "GNS_POSTPROCESS: %s too short\n", src);
504     memcpy (dest, src, s_len);
505     return;
506   }
507   if (0 == strcmp (src + s_len - 3, ".+"))
508   {
509     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
510                 "GNS_POSTPROCESS: Expanding .+ in %s\n", 
511                 src);
512     memset (dest, 0, s_len + strlen (repl) + strlen(GNUNET_GNS_TLD));
513     strcpy (dest, src);
514     pos = dest + s_len - 2;
515     strcpy (pos, repl);
516     pos += strlen (repl);
517     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
518                 "GNS_POSTPROCESS: Expanded to %s\n", 
519                 dest);
520   }
521   else
522   {
523     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
524                "GNS_POSTPROCESS: No postprocessing for %s\n", src);
525     memcpy (dest, src, s_len);
526   }
527 }
528
529
530 #endif
531
532 ///////////////////////////////////////////////////////////////////////////////////////////////////
533 ///////////////////////////////////////////////////////////////////////////////////////////////////
534 ///////////////////////////////////////////////////////////////////////////////////////////////////
535 ///////////////////////////////////////////////////////////////////////////////////////////////////
536 ///////////////////////////////////////////////////////////////////////////////////////////////////
537
538
539 /**
540  * Task scheduled to asynchronously fail a resolution.
541  *
542  * @param cls the 'struct GNS_ResolverHandle' of the resolution to fail
543  * @param tc task context
544  */
545 static void
546 fail_resolution (void *cls,
547                  const struct GNUNET_SCHEDULER_TaskContext *tc)
548 {
549   struct GNS_ResolverHandle *rh = cls;
550
551   rh->task_id = GNUNET_SCHEDULER_NO_TASK;
552   rh->proc (rh->proc_cls, 0, NULL);
553   GNS_resolver_lookup_cancel (rh);
554 }
555
556 #if (defined WINDOWS) || (defined DARWIN)
557 /* Don't have this on W32, here's a naive implementation
558  * Was somehow removed on OS X ...  */
559 void *
560 memrchr (const void *s, int c, size_t n)
561 {
562   size_t i;
563   unsigned char *ucs = (unsigned char *) s;
564
565   for (i = n - 1; i >= 0; i--)
566     if (ucs[i] == c)
567       return (void *) &ucs[i];
568   return NULL;
569 }
570 #endif
571
572 /**
573  * Get the next, rightmost label from the name that we are trying to resolve,
574  * and update the resolution position accordingly.
575  *
576  * @param rh handle to the resolution operation to get the next label from
577  * @return NULL if there are no more labels
578  */
579 static char *
580 resolver_lookup_get_next_label (struct GNS_ResolverHandle *rh)
581 {
582   const char *rp;
583   const char *dot;
584   size_t len;
585
586   if (0 == rh->name_resolution_pos)
587     return NULL;
588   dot = memrchr (rh->name, (int) '.', rh->name_resolution_pos);
589   if (NULL == dot)
590   {
591     /* done, this was the last one */
592     len = rh->name_resolution_pos;
593     rp = rh->name;
594     rh->name_resolution_pos = 0; 
595   }
596   else
597   {
598     /* advance by one label */
599     len = rh->name_resolution_pos - (dot - rh->name) - 1;
600     rp = dot + 1;
601     rh->name_resolution_pos = dot - rh->name;
602   }  
603   return GNUNET_strndup (rp, len);  
604 }
605
606
607 /**
608  * Gives the cummulative result obtained to the callback and clean up the request.
609  *
610  * @param rh resolution process that has culminated in a result
611  */
612 static void
613 transmit_lookup_dns_result (struct GNS_ResolverHandle *rh)
614 {
615   struct DnsResult *pos;
616   unsigned int n;
617   unsigned int i;
618
619   n = 0;
620   for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
621     n++;
622   {
623     struct GNUNET_NAMESTORE_RecordData rd[n];
624
625     i = 0;
626     for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
627     {
628       rd[i].data = pos->data;
629       rd[i].data_size = pos->data_size;
630       rd[i].record_type = pos->record_type;
631       if (0 == pos->expiration_time)
632       {
633         rd[i].flags = GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION;
634         rd[i].expiration_time = 0;
635       }
636       else
637       {
638         rd[i].flags = GNUNET_NAMESTORE_RF_NONE;
639         rd[i].expiration_time = pos->expiration_time;
640       }
641     }      
642     rh->proc (rh->proc_cls,
643               n,
644               rd);
645   }
646   GNS_resolver_lookup_cancel (rh);
647 }
648
649
650 /**
651  * Add a result from DNS to the records to be returned to the application.
652  *
653  * @param rh resolution request to extend with a result
654  * @param expiration_time expiration time for the answer
655  * @param record_type DNS record type of the answer
656  * @param data_size number of bytes in @a data
657  * @param data binary data to return in DNS record
658  */
659 static void
660 add_dns_result (struct GNS_ResolverHandle *rh,
661                 uint64_t expiration_time,
662                 uint32_t record_type,
663                 size_t data_size,
664                 const void *data)
665 {
666   struct DnsResult *res;
667
668   res = GNUNET_malloc (sizeof (struct DnsResult) + data_size);
669   res->expiration_time = expiration_time;
670   res->data_size = data_size;
671   res->record_type = record_type;
672   res->data = &res[1];
673   memcpy (&res[1], data, data_size);
674   GNUNET_CONTAINER_DLL_insert (rh->dns_result_head,
675                                rh->dns_result_tail,
676                                res);
677 }
678
679
680 /**
681  * We had to do a DNS lookup.  Convert the result (if any) and return
682  * it.
683  *
684  * @param cls closure with the 'struct GNS_ResolverHandle'
685  * @param addr one of the addresses of the host, NULL for the last address
686  * @param addrlen length of the address
687  */
688 static void
689 handle_dns_result (void *cls,
690                    const struct sockaddr *addr,
691                    socklen_t addrlen)
692 {
693   struct GNS_ResolverHandle *rh = cls;
694   const struct sockaddr_in *sa4;
695   const struct sockaddr_in6 *sa6;
696
697   rh->std_resolve = NULL;
698   if (NULL == addr)
699   {
700     transmit_lookup_dns_result (rh);
701     return;
702   }
703   switch (addr->sa_family)
704   {
705   case AF_INET:
706     sa4 = (const struct sockaddr_in *) addr;
707     add_dns_result (rh,
708                     0 /* expiration time is unknown */,
709                     GNUNET_DNSPARSER_TYPE_A,
710                     sizeof (struct in_addr),
711                     &sa4->sin_addr);
712     break;
713   case AF_INET6:
714     sa6 = (const struct sockaddr_in6 *) addr;
715     add_dns_result (rh,
716                     0 /* expiration time is unknown */,
717                     GNUNET_DNSPARSER_TYPE_AAAA,
718                     sizeof (struct in6_addr),
719                     &sa6->sin6_addr);
720     break;
721   default:
722     GNUNET_break (0);
723     break;
724   }
725 }
726
727
728 /**
729  * Task scheduled to continue with the resolution process.
730  *
731  * @param cls the 'struct GNS_ResolverHandle' of the resolution
732  * @param tc task context
733  */
734 static void
735 recursive_resolution (void *cls,
736                       const struct GNUNET_SCHEDULER_TaskContext *tc);
737
738
739 /**
740  * Begin the resolution process from 'name', starting with
741  * the identification of the zone specified by 'name'.
742  *
743  * @param rh resolution to perform
744  */
745 static void
746 start_resolver_lookup (struct GNS_ResolverHandle *rh);
747
748
749 /**
750  * Function called with the result of a DNS resolution.
751  *
752  * @param cls the request handle of the resolution that
753  *        we were attempting to make
754  * @param rs socket that received the response
755  * @param dns dns response, never NULL
756  * @param dns_len number of bytes in 'dns'
757  */
758 static void
759 dns_result_parser (void *cls,
760                    struct GNUNET_DNSSTUB_RequestSocket *rs,
761                    const struct GNUNET_TUN_DnsHeader *dns,
762                    size_t dns_len)
763 {
764   struct GNS_ResolverHandle *rh = cls;
765   struct GNUNET_DNSPARSER_Packet *p;
766   const struct GNUNET_DNSPARSER_Record *rec;
767   unsigned int rd_count;
768   unsigned int i;
769
770   rh->dns_request = NULL;
771   GNUNET_SCHEDULER_cancel (rh->task_id);
772   rh->task_id = GNUNET_SCHEDULER_NO_TASK;
773   p = GNUNET_DNSPARSER_parse ((const char *) dns, 
774                               dns_len);
775   if (NULL == p)
776   {
777     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
778                 _("Failed to parse DNS response\n"));
779     rh->proc (rh->proc_cls, 0, NULL);
780     GNS_resolver_lookup_cancel (rh);
781     return;
782   }
783
784   if ( (p->num_answers > 0) &&
785        (GNUNET_DNSPARSER_TYPE_CNAME == p->answers[0].type) &&
786        (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type) )
787     {
788       GNUNET_free (rh->name);
789       rh->name = GNUNET_strdup (p->answers[0].data.hostname);
790       start_resolver_lookup (rh);
791       return;     
792     }
793   /* FIXME: add DNAME support */
794
795   /* convert from (parsed) DNS to (binary) GNS format! */
796   rd_count = p->num_answers + p->num_authority_records + p->num_additional_records;
797   {
798     struct GNUNET_NAMESTORE_RecordData rd[rd_count];
799     unsigned int skip;
800     char buf[UINT16_MAX];
801     size_t buf_off;
802
803     buf_off = 0;
804     skip = 0;
805     memset (rd, 0, sizeof (rd));
806     for (i=0;i<rd_count;i++)
807     {
808       if (i < p->num_answers)
809         rec = &p->answers[i];
810       else if (i < p->num_answers + p->num_authority_records)
811         rec = &p->authority_records[i - p->num_answers];
812       else 
813         rec = &p->authority_records[i - p->num_answers - p->num_authority_records];
814       /* As we copied the full DNS name to 'rh->ac_tail->label', this
815          should be the correct check to see if this record is actually
816          a record for our label... */
817       if (0 != strcmp (rec->name,
818                        rh->ac_tail->label))
819       {
820         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
821                     "Dropping record `%s', does not match desired name `%s'\n",
822                     rec->name,
823                     rh->ac_tail->label);
824         skip++;
825         continue;
826       }
827       rd[i - skip].record_type = rec->type;
828       rd[i - skip].expiration_time = rec->expiration_time.abs_value_us;
829       switch (rec->type)
830       {
831       case GNUNET_DNSPARSER_TYPE_A:
832         if (rec->data.raw.data_len != sizeof (struct in_addr))
833         {
834           GNUNET_break_op (0);
835           skip++;
836           continue;
837         }
838         rd[i - skip].data_size = rec->data.raw.data_len;
839         rd[i - skip].data = rec->data.raw.data;
840         break;
841       case GNUNET_DNSPARSER_TYPE_AAAA:
842         if (rec->data.raw.data_len != sizeof (struct in6_addr))
843         {
844           GNUNET_break_op (0);
845           skip++;
846           continue;
847         }
848         rd[i - skip].data_size = rec->data.raw.data_len;
849         rd[i - skip].data = rec->data.raw.data;
850         break;
851       case GNUNET_DNSPARSER_TYPE_CNAME:
852       case GNUNET_DNSPARSER_TYPE_PTR:
853       case GNUNET_DNSPARSER_TYPE_NS:
854         if (GNUNET_OK !=
855             GNUNET_DNSPARSER_builder_add_name (buf,
856                                                sizeof (buf),
857                                                &buf_off,
858                                                rec->data.hostname))
859         {
860           GNUNET_break (0);
861           skip++;
862           continue;
863         }
864         break;
865       case GNUNET_DNSPARSER_TYPE_SOA:
866         if (GNUNET_OK !=
867             GNUNET_DNSPARSER_builder_add_soa (buf,
868                                                sizeof (buf),
869                                                &buf_off,
870                                                rec->data.soa))
871         {
872           GNUNET_break (0);
873           skip++;
874           continue;
875         }
876         break;
877       case GNUNET_DNSPARSER_TYPE_MX:
878         if (GNUNET_OK !=
879             GNUNET_DNSPARSER_builder_add_mx (buf,
880                                              sizeof (buf),
881                                              &buf_off,
882                                              rec->data.mx))
883         {
884           GNUNET_break (0);
885           skip++;
886           continue;
887         }
888         break;
889       case GNUNET_DNSPARSER_TYPE_SRV:
890         if (GNUNET_OK !=
891             GNUNET_DNSPARSER_builder_add_srv (buf,
892                                               sizeof (buf),
893                                               &buf_off,
894                                               rec->data.srv))
895         {
896           GNUNET_break (0);
897           skip++;
898           continue;
899         }
900         break;
901       default:
902         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
903                     _("Skipping record of unsupported type %d\n"),
904                     rec->type);
905         skip++;
906         continue;
907       }
908     }
909     rh->proc (rh->proc_cls, rd_count - skip, rd);
910     GNS_resolver_lookup_cancel (rh);
911   }  
912   GNUNET_DNSPARSER_free_packet (p);
913 }
914
915
916 /**
917  * Perform recursive DNS resolution.  Asks the given DNS resolver to
918  * resolve "rh->dns_name", possibly recursively proceeding following
919  * NS delegations, CNAMES, etc., until 'rh->loop_limiter' bounds us or
920  * we find the answer.
921  *
922  * @param rh resolution information
923  */
924 static void
925 recursive_dns_resolution (struct GNS_ResolverHandle *rh)
926 {
927   struct AuthorityChain *ac;
928   socklen_t sa_len;
929   struct GNUNET_DNSPARSER_Query *query;
930   struct GNUNET_DNSPARSER_Packet *p;
931   char *dns_request;
932   size_t dns_request_length;
933
934   ac = rh->ac_tail;
935   GNUNET_assert (NULL != ac);
936   GNUNET_assert (GNUNET_NO == ac->gns_authority);
937   switch (((const struct sockaddr *) &ac->authority_info.dns_authority.dns_ip)->sa_family)
938   {
939   case AF_INET:
940     sa_len = sizeof (struct sockaddr_in);
941     break;
942   case AF_INET6:
943     sa_len = sizeof (struct sockaddr_in6);
944     break;
945   default:
946     GNUNET_break (0);
947     rh->proc (rh->proc_cls, 0, NULL);
948     GNS_resolver_lookup_cancel (rh);
949     return;
950   }
951   query = GNUNET_new (struct GNUNET_DNSPARSER_Query);
952   query->name = GNUNET_strdup (ac->label);
953   query->type = rh->record_type;
954   query->class = GNUNET_TUN_DNS_CLASS_INTERNET;
955   p = GNUNET_new (struct GNUNET_DNSPARSER_Packet);
956   p->queries = query;
957   p->num_queries = 1;
958   p->id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
959                                                UINT16_MAX);
960   p->flags.opcode = GNUNET_TUN_DNS_OPCODE_QUERY;
961   p->flags.recursion_desired = 1;
962   if (GNUNET_OK != 
963       GNUNET_DNSPARSER_pack (p, 1024, &dns_request, &dns_request_length))
964   {
965     GNUNET_break (0);
966     rh->proc (rh->proc_cls, 0, NULL);
967     GNS_resolver_lookup_cancel (rh);
968   }
969   else
970   {
971     rh->dns_request = GNUNET_DNSSTUB_resolve (dns_handle,
972                                               (const struct sockaddr *) &ac->authority_info.dns_authority.dns_ip,
973                                               sa_len,
974                                               dns_request,
975                                               dns_request_length,
976                                               &dns_result_parser,
977                                               rh);
978     rh->task_id = GNUNET_SCHEDULER_add_delayed (DNS_LOOKUP_TIMEOUT,
979                                                 &fail_resolution,
980                                                 rh);
981   }
982   GNUNET_free (dns_request);
983   GNUNET_DNSPARSER_free_packet (p);
984 }
985
986
987 /**
988  * We encountered a CNAME record during our resolution.
989  * Merge it into our chain.
990  *
991  * @param rh resolution we are performing
992  * @param cname value of the cname record we got for the current 
993  *        authority chain tail
994  */
995 static void
996 handle_gns_cname_result (struct GNS_ResolverHandle *rh,
997                          const char *cname)
998 {
999   size_t nlen;
1000   char *res;
1001
1002   nlen = strlen (cname);
1003   if ( (nlen > 2) &&
1004        (0 == strcmp (".+",
1005                      &cname[nlen - 2])) )
1006   {
1007     /* CNAME resolution continues relative to current domain */
1008     if (0 == rh->name_resolution_pos)
1009     {
1010       res = GNUNET_strndup (cname, nlen - 2);
1011       rh->name_resolution_pos = nlen - 2;
1012     }
1013     else
1014     {
1015       GNUNET_asprintf (&res,
1016                        "%.*s.%.*s",
1017                        (int) rh->name_resolution_pos,
1018                        rh->name,
1019                        (int) (nlen - 2),
1020                        cname);
1021       rh->name_resolution_pos = strlen (res);
1022     }
1023     GNUNET_free (rh->name);
1024     rh->name = res;
1025     rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1026                                             rh);
1027     return;
1028   }
1029   /* name is absolute, start from the beginning */
1030   GNUNET_free (rh->name);
1031   rh->name = GNUNET_strdup (cname);
1032   start_resolver_lookup (rh);
1033 }
1034
1035
1036 /**
1037  * Process a records that were decrypted from a block.
1038  *
1039  * @param cls closure with the 'struct GNS_ResolverHandle'
1040  * @param rd_count number of entries in @a rd array
1041  * @param rd array of records with data to store
1042  */
1043 static void
1044 handle_gns_resolution_result (void *cls,
1045                               unsigned int rd_count,
1046                               const struct GNUNET_NAMESTORE_RecordData *rd);
1047
1048
1049 /**
1050  * Callback invoked from the VPN service once a redirection is
1051  * available.  Provides the IP address that can now be used to
1052  * reach the requested destination.  Replaces the "VPN" record
1053  * with the respective A/AAAA record and continues processing.
1054  *
1055  * @param cls closure
1056  * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error;
1057  *                will match 'result_af' from the request
1058  * @param address IP address (struct in_addr or struct in_addr6, depending on 'af')
1059  *                that the VPN allocated for the redirection;
1060  *                traffic to this IP will now be redirected to the 
1061  *                specified target peer; NULL on error
1062  */
1063 static void
1064 vpn_allocation_cb (void *cls,
1065                    int af,
1066                    const void *address)
1067 {
1068   struct VpnContext *vpn_ctx = cls;
1069   struct GNS_ResolverHandle *rh = vpn_ctx->rh;
1070   struct GNUNET_NAMESTORE_RecordData rd[vpn_ctx->rd_count];
1071   unsigned int i;
1072
1073   vpn_ctx->vpn_request = NULL;
1074   rh->vpn_ctx = NULL;
1075   GNUNET_assert (GNUNET_OK ==
1076                  GNUNET_NAMESTORE_records_deserialize (vpn_ctx->rd_data_size,
1077                                                        vpn_ctx->rd_data,
1078                                                        vpn_ctx->rd_count,
1079                                                        rd));
1080   for (i=0;i<vpn_ctx->rd_count;i++)
1081   {
1082     if (GNUNET_NAMESTORE_TYPE_VPN == rd[i].record_type)
1083     {
1084       switch (af)
1085       {
1086       case AF_INET: 
1087         rd[i].record_type = GNUNET_DNSPARSER_TYPE_A;
1088         rd[i].data_size = sizeof (struct in_addr);
1089         rd[i].expiration_time = GNUNET_TIME_relative_to_absolute (VPN_TIMEOUT).abs_value_us;
1090         rd[i].flags = 0;
1091         rd[i].data = address;
1092         break;
1093       case AF_INET6:
1094         rd[i].record_type = GNUNET_DNSPARSER_TYPE_AAAA;
1095         rd[i].expiration_time = GNUNET_TIME_relative_to_absolute (VPN_TIMEOUT).abs_value_us;
1096         rd[i].flags = 0;
1097         rd[i].data = address;
1098         rd[i].data_size = sizeof (struct in6_addr);
1099         break;
1100       default:
1101         GNUNET_assert (0);
1102       }     
1103       break;
1104     }
1105   }
1106   GNUNET_assert (i < vpn_ctx->rd_count);
1107   handle_gns_resolution_result (rh, 
1108                                 vpn_ctx->rd_count,
1109                                 rd);
1110   GNUNET_free (vpn_ctx->rd_data);
1111   GNUNET_free (vpn_ctx);
1112 }
1113
1114
1115 /**
1116  * Process a records that were decrypted from a block.
1117  *
1118  * @param cls closure with the 'struct GNS_ResolverHandle'
1119  * @param rd_count number of entries in @a rd array
1120  * @param rd array of records with data to store
1121  */
1122 static void
1123 handle_gns_resolution_result (void *cls,
1124                               unsigned int rd_count,
1125                               const struct GNUNET_NAMESTORE_RecordData *rd)
1126 {
1127   struct GNS_ResolverHandle *rh = cls;
1128   struct AuthorityChain *ac;
1129   unsigned int i;
1130   unsigned int j;
1131   struct sockaddr *sa;
1132   struct sockaddr_in v4;
1133   struct sockaddr_in6 v6;
1134   size_t sa_len;
1135   char *cname;
1136   struct VpnContext *vpn_ctx;
1137   const struct GNUNET_TUN_GnsVpnRecord *vpn;
1138   const char *vname;
1139   struct GNUNET_HashCode vhash;
1140   int af;
1141   char scratch[UINT16_MAX];
1142   size_t scratch_off;
1143   size_t scratch_start;
1144   size_t off;
1145   struct GNUNET_NAMESTORE_RecordData rd_new[rd_count];
1146   unsigned int rd_off;
1147   
1148   if (0 == rh->name_resolution_pos)
1149   {
1150     /* top-level match, are we done yet? */
1151     if ( (rd_count > 0) &&
1152          (GNUNET_DNSPARSER_TYPE_CNAME == rd[0].record_type) &&
1153          (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type) )
1154     {
1155       cname = GNUNET_strndup (rd[0].data,
1156                               rd[0].data_size);
1157       handle_gns_cname_result (rh, 
1158                                cname);
1159       GNUNET_free (cname);
1160       return;     
1161     }
1162     /* If A/AAAA was requested, but we got a VPN
1163        record, we convert it to A/AAAA using GNUnet VPN */
1164     if ( (GNUNET_DNSPARSER_TYPE_A == rh->record_type) ||
1165          (GNUNET_DNSPARSER_TYPE_AAAA == rh->record_type) )
1166     {
1167       for (i=0;i<rd_count;i++)
1168       {
1169         if (GNUNET_NAMESTORE_TYPE_VPN == rd[i].record_type)
1170         {
1171           af = (GNUNET_DNSPARSER_TYPE_A == rh->record_type) ? AF_INET : AF_INET6;
1172           if (sizeof (struct GNUNET_TUN_GnsVpnRecord) <
1173               rd[i].data_size)
1174           {
1175             GNUNET_break_op (0);
1176             rh->proc (rh->proc_cls, 0, NULL);
1177             GNS_resolver_lookup_cancel (rh);
1178             return;         
1179           }
1180           vpn = (const struct GNUNET_TUN_GnsVpnRecord *) rd[i].data;
1181           vname = (const char *) &vpn[1];
1182           if ('\0' != vname[rd[i].data_size - 1 - sizeof (struct GNUNET_TUN_GnsVpnRecord)])
1183           {
1184             GNUNET_break_op (0);
1185             rh->proc (rh->proc_cls, 0, NULL);
1186             GNS_resolver_lookup_cancel (rh);
1187             return;
1188           }
1189           GNUNET_CRYPTO_hash (vname,
1190                               strlen (vname), // FIXME: +1?
1191                               &vhash);
1192           vpn_ctx = GNUNET_new (struct VpnContext);
1193           rh->vpn_ctx = vpn_ctx;
1194           vpn_ctx->rh = rh;
1195           vpn_ctx->rd_data_size = GNUNET_NAMESTORE_records_get_size (rd_count,
1196                                                                      rd);
1197           vpn_ctx->rd_data = GNUNET_malloc (vpn_ctx->rd_data_size);
1198           (void) GNUNET_NAMESTORE_records_serialize (rd_count,
1199                                                      rd,
1200                                                      vpn_ctx->rd_data_size,
1201                                                      vpn_ctx->rd_data);
1202           vpn_ctx->vpn_request = GNUNET_VPN_redirect_to_peer (vpn_handle,
1203                                                               af,
1204                                                               ntohs (vpn->proto),
1205                                                               &vpn->peer,
1206                                                               &vhash,
1207                                                               GNUNET_NO,
1208                                                               GNUNET_TIME_relative_to_absolute (VPN_TIMEOUT),
1209                                                               &vpn_allocation_cb,
1210                                                               rh);
1211           return;
1212         }
1213       }
1214     }
1215     /* convert relative names in record values to absolute names,
1216        using 'scratch' array for memory allocations */
1217     scratch_off = 0;
1218     rd_off = 0;
1219     for (i=0;i<rd_count;i++)
1220     {
1221       rd_new[rd_off] = rd[i];
1222       /* Check if the embedded name(s) end in "+", and if so,
1223          replace the "+" with the zone at "ac_tail", changing the name
1224          to a ".zkey".  The name is allocated on the 'scratch' array,
1225          so we can free it afterwards. */
1226       switch (rd[i].record_type)
1227       {
1228       case GNUNET_DNSPARSER_TYPE_CNAME:
1229         {
1230           char *cname;
1231
1232           off = 0;
1233           cname = GNUNET_DNSPARSER_parse_name (rd[i].data,
1234                                                rd[i].data_size,
1235                                                &off);
1236           if ( (NULL == cname) ||
1237                (off != rd[i].data_size) )
1238           {
1239             GNUNET_break_op (0); /* record not well-formed */
1240           }
1241           else
1242           {
1243             // FIXME: do 'cname' transformation here!
1244             // cname = translate_dot_plus (rh, cname);
1245             scratch_start = scratch_off;
1246             if (GNUNET_OK !=
1247                 GNUNET_DNSPARSER_builder_add_name (scratch,
1248                                                    sizeof (scratch),
1249                                                    &scratch_off,
1250                                                    cname))
1251             {
1252               GNUNET_break (0);
1253             }
1254             else
1255             {
1256               rd_new[rd_off].data = &scratch[scratch_start];
1257               rd_new[rd_off].data_size = scratch_off - scratch_start;
1258               rd_off++;
1259             }
1260             GNUNET_free (cname);
1261           }
1262         }
1263         break;
1264       case GNUNET_DNSPARSER_TYPE_SOA:
1265         GNUNET_break (0); // FIXME: not implemented
1266         break;
1267       case GNUNET_DNSPARSER_TYPE_MX:
1268         GNUNET_break (0); // FIXME: not implemented
1269         break;
1270       case GNUNET_DNSPARSER_TYPE_SRV:
1271         GNUNET_break (0); // FIXME: not implemented
1272         break;
1273       default:
1274         break;
1275       }
1276     }
1277     
1278     /* yes, we are done, return result */
1279     rh->proc (rh->proc_cls, rd_off, rd_new);
1280     GNS_resolver_lookup_cancel (rh);
1281     return;         
1282   }
1283   /* need to recurse, check if we can */
1284   for (i=0;i<rd_count;i++)
1285   {
1286     switch (rd[i].record_type)
1287     {
1288     case GNUNET_NAMESTORE_TYPE_PKEY:
1289       /* delegation to another zone */
1290       if (sizeof (struct GNUNET_CRYPTO_EccPublicKey) !=
1291           rd[i].data_size)
1292       {
1293         GNUNET_break_op (0);
1294         rh->proc (rh->proc_cls, 0, NULL);
1295         GNS_resolver_lookup_cancel (rh);
1296         return;     
1297       }
1298       /* expand authority chain */
1299       ac = GNUNET_new (struct AuthorityChain);
1300       ac->rh = rh;
1301       ac->gns_authority = GNUNET_YES;
1302       memcpy (&ac->authority_info.gns_authority,
1303               rd[i].data,
1304               sizeof (struct GNUNET_CRYPTO_EccPublicKey));
1305       ac->label = resolver_lookup_get_next_label (rh);
1306       GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1307                                         rh->ac_tail,
1308                                         ac);
1309       /* recurse */
1310       rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1311                                               rh);
1312       break;
1313     case GNUNET_DNSPARSER_TYPE_NS:
1314       /* resolution continues within DNS */
1315       if (GNUNET_DNSPARSER_MAX_NAME_LENGTH < rd[i].data_size)
1316       {
1317         GNUNET_break_op (0);
1318         rh->proc (rh->proc_cls, 0, NULL);
1319         GNS_resolver_lookup_cancel (rh);
1320         return;     
1321       }
1322       /* find associated A/AAAA record */
1323       sa = NULL;
1324       for (j=0;j<rd_count;j++)
1325       {
1326         switch (rd[j].record_type)
1327         {
1328         case GNUNET_DNSPARSER_TYPE_A:
1329           if (sizeof (struct in_addr) != rd[i].data_size)
1330           {
1331             GNUNET_break_op (0);
1332             rh->proc (rh->proc_cls, 0, NULL);
1333             GNS_resolver_lookup_cancel (rh);
1334             return;     
1335           }
1336           /* FIXME: might want to check if we support IPv4 here,
1337              and otherwise skip this one and hope we find another */
1338           memset (&v4, 0, sizeof (v4));
1339           sa_len = sizeof (v4);
1340           v4.sin_family = AF_INET;
1341           v4.sin_port = htons (53);
1342 #if HAVE_SOCKADDR_IN_SIN_LEN
1343           v4.sin_len = (u_char) sa_len;
1344 #endif
1345           memcpy (&v4.sin_addr,
1346                   rd[j].data,
1347                   sizeof (struct in_addr));
1348           sa = (struct sockaddr *) &v4;
1349           break;
1350         case GNUNET_DNSPARSER_TYPE_AAAA:
1351           if (sizeof (struct in6_addr) != rd[i].data_size)
1352           {
1353             GNUNET_break_op (0);
1354             rh->proc (rh->proc_cls, 0, NULL);
1355             GNS_resolver_lookup_cancel (rh);
1356             return;     
1357           }
1358           /* FIXME: might want to check if we support IPv6 here,
1359              and otherwise skip this one and hope we find another */
1360           memset (&v6, 0, sizeof (v6));
1361           sa_len = sizeof (v6);
1362           v6.sin6_family = AF_INET6;
1363           v6.sin6_port = htons (53);
1364 #if HAVE_SOCKADDR_IN_SIN_LEN
1365           v6.sin6_len = (u_char) sa_len;
1366 #endif
1367           memcpy (&v6.sin6_addr,
1368                   rd[j].data,
1369                   sizeof (struct in6_addr));
1370           sa = (struct sockaddr *) &v6;
1371           break;
1372         }
1373         if (NULL != sa)
1374           break;
1375       }
1376       /* expand authority chain */
1377       ac = GNUNET_new (struct AuthorityChain);
1378       ac->rh = rh;
1379       strncpy (ac->authority_info.dns_authority.name,
1380                rd[i].data,
1381                rd[i].data_size);
1382       ac->authority_info.dns_authority.name[rd[i].data_size] = '\0';
1383       memcpy (&ac->authority_info.dns_authority.dns_ip,
1384               sa,
1385               sa_len);
1386       /* for DNS recursion, the label is the full DNS name,
1387          created from the remainder of the GNS name and the
1388          name in the NS record */
1389       GNUNET_asprintf (&ac->label,
1390                        "%.*s%s",
1391                        (int) rh->name_resolution_pos,
1392                        rh->name,
1393                        ac->authority_info.dns_authority.name);
1394       GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1395                                         rh->ac_tail,
1396                                         ac);
1397       if (strlen (ac->label) > GNUNET_DNSPARSER_MAX_NAME_LENGTH)
1398       {
1399         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1400                     _("GNS lookup resulted in DNS name that is too long (`%s')\n"),
1401                     ac->label);
1402         rh->proc (rh->proc_cls, 0, NULL);
1403         GNS_resolver_lookup_cancel (rh);
1404         return;
1405       }
1406       /* recurse */
1407       rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1408                                               rh);
1409       return;
1410     case GNUNET_DNSPARSER_TYPE_CNAME:
1411       cname = GNUNET_strndup (rd[i].data,
1412                               rd[i].data_size);
1413       handle_gns_cname_result (rh, 
1414                                cname);
1415       GNUNET_free (cname);
1416       return;
1417       /* FIXME: handle DNAME */
1418     default:
1419       /* skip */
1420       break;
1421     }
1422   }
1423   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1424               _("GNS lookup recursion failed (no delegation record found)\n"));
1425   rh->proc (rh->proc_cls, 0, NULL);
1426   GNS_resolver_lookup_cancel (rh);
1427 }
1428
1429
1430 /**
1431  * Function called once the namestore has completed the request for
1432  * caching a block.
1433  *
1434  * @param cls closure with the 'struct GNS_ResolverHandle'
1435  * @param success #GNUNET_OK on success
1436  * @param emsg error message
1437  */
1438 static void
1439 namestore_cache_continuation (void *cls,
1440                               int32_t success,
1441                               const char *emsg)
1442 {
1443   struct GNS_ResolverHandle *rh = cls;
1444
1445   rh->namestore_qe = NULL;
1446   if (NULL != emsg)
1447     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1448                 _("Failed to cache GNS resolution: %s\n"),
1449                 emsg);
1450 }
1451
1452
1453 /**
1454  * Iterator called on each result obtained for a DHT
1455  * operation that expects a reply
1456  *
1457  * @param cls closure with the 'struct GNS_ResolverHandle'
1458  * @param exp when will this value expire
1459  * @param key key of the result
1460  * @param get_path peers on reply path (or NULL if not recorded)
1461  *                 [0] = datastore's first neighbor, [length - 1] = local peer
1462  * @param get_path_length number of entries in get_path
1463  * @param put_path peers on the PUT path (or NULL if not recorded)
1464  *                 [0] = origin, [length - 1] = datastore
1465  * @param put_path_length number of entries in get_path
1466  * @param type type of the result
1467  * @param size number of bytes in data
1468  * @param data pointer to the result data
1469  */
1470 static void
1471 handle_dht_response (void *cls,
1472                      struct GNUNET_TIME_Absolute exp,
1473                      const struct GNUNET_HashCode * key,
1474                      const struct GNUNET_PeerIdentity *get_path,
1475                      unsigned int get_path_length,
1476                      const struct GNUNET_PeerIdentity *put_path, 
1477                      unsigned int put_path_length,
1478                      enum GNUNET_BLOCK_Type type,
1479                      size_t size, const void *data)
1480 {
1481   struct GNS_ResolverHandle *rh = cls;
1482   struct AuthorityChain *ac = rh->ac_tail;
1483   const struct GNUNET_NAMESTORE_Block *block;
1484   
1485   GNUNET_DHT_get_stop (rh->get_handle);
1486   rh->get_handle = NULL;
1487   GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
1488   rh->dht_heap_node = NULL;  
1489   if (size < sizeof (struct GNUNET_NAMESTORE_Block))
1490   {
1491     /* how did this pass DHT block validation!? */
1492     GNUNET_break (0);
1493     rh->proc (rh->proc_cls, 0, NULL);
1494     GNS_resolver_lookup_cancel (rh);
1495     return;   
1496   }
1497   block = data; 
1498   if (size !=
1499       ntohs (block->purpose.size) + 
1500       sizeof (struct GNUNET_CRYPTO_EccPublicKey) +
1501       sizeof (struct GNUNET_CRYPTO_EccSignature))
1502   {
1503     /* how did this pass DHT block validation!? */
1504     GNUNET_break (0);
1505     rh->proc (rh->proc_cls, 0, NULL);
1506     GNS_resolver_lookup_cancel (rh);
1507     return;   
1508   }
1509   if (GNUNET_OK !=
1510       GNUNET_NAMESTORE_block_decrypt (block,
1511                                       &ac->authority_info.gns_authority,
1512                                       ac->label,
1513                                       &handle_gns_resolution_result,
1514                                       rh))
1515   {
1516     GNUNET_break_op (0); /* block was ill-formed */
1517     rh->proc (rh->proc_cls, 0, NULL);
1518     GNS_resolver_lookup_cancel (rh);
1519     return;
1520   }
1521   /* Cache well-formed blocks */
1522   rh->namestore_qe = GNUNET_NAMESTORE_block_cache (namestore_handle,
1523                                                    block,
1524                                                    &namestore_cache_continuation,
1525                                                    rh);
1526 }
1527
1528
1529 /**
1530  * Process a record that was stored in the namestore.
1531  *
1532  * @param cls closure with the `struct GNS_ResolverHandle`
1533  * @param block block that was stored in the namestore
1534  */
1535 static void 
1536 handle_namestore_block_response (void *cls,
1537                                  const struct GNUNET_NAMESTORE_Block *block)
1538 {
1539   struct GNS_ResolverHandle *rh = cls;
1540   struct GNS_ResolverHandle *rx;
1541   struct AuthorityChain *ac = rh->ac_tail;
1542   const char *label = ac->label;
1543   const struct GNUNET_CRYPTO_EccPublicKey *auth = &ac->authority_info.gns_authority;
1544   struct GNUNET_HashCode query;
1545
1546   GNUNET_NAMESTORE_query_from_public_key (auth,
1547                                           label,
1548                                           &query);
1549   rh->namestore_qe = NULL;
1550   if (NULL == block)
1551   {
1552     /* Namestore knows nothing; try DHT lookup */
1553     rh->get_handle = GNUNET_DHT_get_start (dht_handle,
1554                                            GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1555                                            &query,
1556                                            DHT_GNS_REPLICATION_LEVEL,
1557                                            GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
1558                                            NULL, 0,
1559                                            &handle_dht_response, rh);
1560     rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
1561                                                       rh,
1562                                                       GNUNET_TIME_absolute_get ().abs_value_us);
1563     if (GNUNET_CONTAINER_heap_get_size (dht_lookup_heap) > max_allowed_background_queries)
1564     {
1565       /* fail longest-standing DHT request */
1566       rx = GNUNET_CONTAINER_heap_peek (dht_lookup_heap);
1567       rx->proc (rx->proc_cls, 0, NULL);
1568       GNS_resolver_lookup_cancel (rx);
1569     }
1570     return;
1571   }
1572   if (GNUNET_OK !=
1573       GNUNET_NAMESTORE_block_decrypt (block,
1574                                       auth,
1575                                       label,
1576                                       &handle_gns_resolution_result,
1577                                       rh))
1578   {
1579     GNUNET_break_op (0); /* block was ill-formed */
1580     rh->proc (rh->proc_cls, 0, NULL);
1581     GNS_resolver_lookup_cancel (rh);
1582     return;
1583   }
1584 }
1585
1586
1587 /**
1588  * Lookup tail of our authority chain in the namestore.
1589  *
1590  * @param rh query we are processing
1591  */
1592 static void
1593 recursive_gns_resolution_namestore (struct GNS_ResolverHandle *rh)
1594 {
1595   struct AuthorityChain *ac = rh->ac_tail;
1596   struct GNUNET_HashCode query;
1597
1598   GNUNET_NAMESTORE_query_from_public_key (&ac->authority_info.gns_authority,
1599                                           ac->label,
1600                                           &query);
1601   rh->namestore_qe = GNUNET_NAMESTORE_lookup_block (namestore_handle,
1602                                                     &query,
1603                                                     &handle_namestore_block_response,
1604                                                     rh);
1605 }
1606
1607
1608 /**
1609  * Task scheduled to continue with the resolution process.
1610  *
1611  * @param cls the `struct GNS_ResolverHandle` of the resolution
1612  * @param tc task context
1613  */
1614 static void
1615 recursive_resolution (void *cls,
1616                       const struct GNUNET_SCHEDULER_TaskContext *tc)
1617 {
1618   struct GNS_ResolverHandle *rh = cls;
1619
1620   rh->task_id = GNUNET_SCHEDULER_NO_TASK;
1621   if (MAX_RECURSION < rh->loop_limiter++)
1622   {
1623     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1624                 "Encountered unbounded recursion resolving `%s'\n",
1625                 rh->name);
1626     rh->proc (rh->proc_cls, 0, NULL);
1627     GNS_resolver_lookup_cancel (rh);
1628     return;
1629   }
1630   if (GNUNET_YES == rh->ac_tail->gns_authority)
1631     recursive_gns_resolution_namestore (rh);
1632   else
1633     recursive_dns_resolution (rh);
1634 }
1635
1636
1637 /**
1638  * Begin the resolution process from 'name', starting with
1639  * the identification of the zone specified by 'name'.
1640  *
1641  * @param rh resolution to perform
1642  */
1643 static void
1644 start_resolver_lookup (struct GNS_ResolverHandle *rh)
1645 {
1646   struct AuthorityChain *ac;
1647   char *x;
1648   char *y;
1649   char *pkey;
1650
1651   if ( ( (GNUNET_YES == is_canonical (rh->name)) &&
1652          (0 != strcmp (GNUNET_GNS_TLD, rh->name)) ) ||
1653        ( (GNUNET_YES != is_gnu_tld (rh->name)) &&
1654          (GNUNET_YES != is_zkey_tld (rh->name)) ) )
1655   {
1656     /* use standard DNS lookup */
1657     int af;
1658
1659     switch (rh->record_type)
1660     {
1661     case GNUNET_DNSPARSER_TYPE_A:
1662       af = AF_INET;
1663       break;
1664     case GNUNET_DNSPARSER_TYPE_AAAA:
1665       af = AF_INET6;
1666       break;
1667     default:
1668       af = AF_UNSPEC;
1669       break;
1670     }
1671     rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name, 
1672                                               af,
1673                                               DNS_LOOKUP_TIMEOUT,
1674                                               &handle_dns_result,
1675                                               rh);
1676     return;
1677   }
1678   if (is_zkey_tld (rh->name))
1679   {
1680     /* Name ends with ".zkey", try to replace authority zone with zkey
1681        authority */
1682     GNUNET_free (resolver_lookup_get_next_label (rh)); /* will return "zkey" */
1683     x = resolver_lookup_get_next_label (rh); /* will return 'x' coordinate */
1684     y = resolver_lookup_get_next_label (rh); /* will return 'y' coordinate */
1685     GNUNET_asprintf (&pkey,
1686                      "%s%s",
1687                      x, y);
1688     if ( (NULL == x) ||
1689          (NULL == y) ||
1690          (GNUNET_OK !=
1691           GNUNET_CRYPTO_ecc_public_key_from_string (pkey,
1692                                                     strlen (pkey),
1693                                                     &rh->authority_zone)) )
1694     {
1695       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1696                   _("Hostname `%s' is not well-formed, resolution fails\n"),
1697                   rh->name);
1698       rh->task_id = GNUNET_SCHEDULER_add_now (&fail_resolution, rh);
1699     }
1700     GNUNET_free_non_null (x);
1701     GNUNET_free_non_null (y);
1702     GNUNET_free (pkey);
1703   }
1704   else
1705   {
1706     /* Name ends with ".gnu", eat ".gnu" and continue with resolution */
1707     GNUNET_free (resolver_lookup_get_next_label (rh));
1708   }
1709   ac = GNUNET_new (struct AuthorityChain);
1710   ac->rh = rh;
1711   ac->label = resolver_lookup_get_next_label (rh);
1712   if (NULL == ac->label)
1713     /* name was just "gnu", so we default to label '+' */
1714     ac->label = GNUNET_strdup (GNUNET_GNS_MASTERZONE_STR);
1715   ac->gns_authority = GNUNET_YES;
1716   ac->authority_info.gns_authority = rh->authority_zone;
1717   GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1718                                     rh->ac_tail,
1719                                     ac);
1720   rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1721                                           rh);
1722 }
1723
1724
1725 /**
1726  * Lookup of a record in a specific zone calls lookup result processor
1727  * on result.
1728  *
1729  * @param zone the zone to perform the lookup in
1730  * @param record_type the record type to look up
1731  * @param name the name to look up
1732  * @param shorten_key a private key for use with PSEU import (can be NULL)
1733  * @param only_cached #GNUNET_NO to only check locally not DHT for performance
1734  * @param proc the processor to call on result
1735  * @param proc_cls the closure to pass to @a proc
1736  * @return handle to cancel operation
1737  */
1738 struct GNS_ResolverHandle *
1739 GNS_resolver_lookup (const struct GNUNET_CRYPTO_EccPublicKey *zone,
1740                      uint32_t record_type,
1741                      const char *name,
1742                      const struct GNUNET_CRYPTO_EccPrivateKey *shorten_key,
1743                      int only_cached,
1744                      GNS_ResultProcessor proc, void *proc_cls)
1745 {
1746   struct GNS_ResolverHandle *rh;
1747
1748   rh = GNUNET_new (struct GNS_ResolverHandle);
1749   GNUNET_CONTAINER_DLL_insert (rlh_head,
1750                                rlh_tail,
1751                                rh);
1752   rh->authority_zone = *zone;
1753   rh->proc = proc;
1754   rh->proc_cls = proc_cls;
1755   rh->only_cached = only_cached;
1756   rh->record_type = record_type;
1757   rh->name = GNUNET_strdup (name);
1758   rh->name_resolution_pos = strlen (name);
1759   if (NULL != shorten_key)
1760   {
1761     rh->shorten_key = GNUNET_new (struct GNUNET_CRYPTO_EccPrivateKey);
1762     *rh->shorten_key = *shorten_key;
1763   }
1764   start_resolver_lookup (rh);
1765   return rh;
1766 }
1767
1768
1769 /**
1770  * Cancel active resolution (i.e. client disconnected).
1771  *
1772  * @param rh resolution to abort
1773  */
1774 void
1775 GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
1776 {
1777   struct DnsResult *dr;
1778   struct AuthorityChain *ac;
1779   struct VpnContext *vpn_ctx;
1780
1781   GNUNET_CONTAINER_DLL_remove (rlh_head,
1782                                rlh_tail,
1783                                rh);
1784   while (NULL != (ac = rh->ac_head))
1785   {
1786     GNUNET_CONTAINER_DLL_remove (rh->ac_head,
1787                                  rh->ac_tail,
1788                                  ac);
1789     GNUNET_free (ac->label);
1790     GNUNET_free (ac);
1791   }
1792   if (GNUNET_SCHEDULER_NO_TASK != rh->task_id)
1793   {
1794     GNUNET_SCHEDULER_cancel (rh->task_id);
1795     rh->task_id = GNUNET_SCHEDULER_NO_TASK;
1796   }
1797   if (NULL != rh->get_handle)
1798   {
1799     GNUNET_DHT_get_stop (rh->get_handle);
1800     rh->get_handle = NULL;
1801   }
1802   if (NULL != rh->dht_heap_node)
1803   {
1804     GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
1805     rh->dht_heap_node = NULL;
1806   }
1807   if (NULL != (vpn_ctx = rh->vpn_ctx))
1808   {
1809     GNUNET_VPN_cancel_request (vpn_ctx->vpn_request);
1810     GNUNET_free (vpn_ctx->rd_data);
1811     GNUNET_free (vpn_ctx);
1812   }
1813   if (NULL != rh->dns_request)
1814   {
1815     GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
1816     rh->dns_request = NULL;
1817   }
1818   if (NULL != rh->namestore_qe)
1819   {
1820     GNUNET_NAMESTORE_cancel (rh->namestore_qe);
1821     rh->namestore_qe = NULL;
1822   }
1823   if (NULL != rh->std_resolve)
1824   {
1825     GNUNET_RESOLVER_request_cancel (rh->std_resolve);
1826     rh->std_resolve = NULL;
1827   }
1828   while (NULL != (dr = rh->dns_result_head))
1829   {
1830     GNUNET_CONTAINER_DLL_remove (rh->dns_result_head,
1831                                  rh->dns_result_tail,
1832                                  dr);
1833     GNUNET_free (dr);
1834   }
1835   GNUNET_free_non_null (rh->shorten_key);
1836   GNUNET_free (rh->name);
1837   GNUNET_free (rh);
1838 }
1839
1840
1841 /* ***************** Resolver initialization ********************* */
1842
1843
1844 /**
1845  * Initialize the resolver
1846  *
1847  * @param nh the namestore handle
1848  * @param dht the dht handle
1849  * @param c configuration handle
1850  * @param max_bg_queries maximum number of parallel background queries in dht
1851  */
1852 void
1853 GNS_resolver_init (struct GNUNET_NAMESTORE_Handle *nh,
1854                    struct GNUNET_DHT_Handle *dht,
1855                    const struct GNUNET_CONFIGURATION_Handle *c,
1856                    unsigned long long max_bg_queries)
1857 {
1858   char *dns_ip;
1859
1860   cfg = c;
1861   namestore_handle = nh;
1862   dht_handle = dht;
1863   dht_lookup_heap =
1864     GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1865   max_allowed_background_queries = max_bg_queries;
1866   if (GNUNET_OK !=
1867       GNUNET_CONFIGURATION_get_value_string (c,
1868                                              "gns",
1869                                              "DNS_RESOLVER",
1870                                              &dns_ip))
1871   {
1872     /* user did not specify DNS resolver, use 8.8.8.8 */
1873     dns_ip = GNUNET_strdup ("8.8.8.8");
1874   }
1875   dns_handle = GNUNET_DNSSTUB_start (dns_ip);
1876   GNUNET_free (dns_ip);
1877   vpn_handle = GNUNET_VPN_connect (cfg);
1878 }
1879
1880
1881 /**
1882  * Shutdown resolver
1883  */
1884 void
1885 GNS_resolver_done ()
1886 {
1887   struct GNS_ResolverHandle *rh;
1888
1889   /* abort active resolutions */
1890   while (NULL != (rh = rlh_head))
1891   {
1892     rh->proc (rh->proc_cls, 0, NULL);
1893     GNS_resolver_lookup_cancel (rh);    
1894   }
1895   GNUNET_CONTAINER_heap_destroy (dht_lookup_heap);
1896   dht_lookup_heap = NULL;
1897   GNUNET_DNSSTUB_stop (dns_handle);
1898   dns_handle = NULL;
1899   GNUNET_VPN_disconnect (vpn_handle);
1900   vpn_handle = NULL;
1901   dht_handle = NULL;
1902   namestore_handle = NULL;
1903 }
1904
1905
1906 /* *************** common helper functions (do not really belong here) *********** */
1907
1908 /**
1909  * Checks if @a name ends in ".TLD"
1910  *
1911  * @param name the name to check
1912  * @param tld the TLD to check for
1913  * @return GNUNET_YES or GNUNET_NO
1914  */
1915 int
1916 is_tld (const char* name, const char* tld)
1917 {
1918   size_t offset = 0;
1919
1920   if (strlen (name) <= strlen (tld))
1921     return GNUNET_NO;
1922   offset = strlen (name) - strlen (tld);
1923   if (0 != strcmp (name + offset, tld))
1924     return GNUNET_NO;
1925   return GNUNET_YES;
1926 }
1927
1928
1929 /* end of gnunet-service-gns_resolver.c */