e501fa3cb04c59fdbcc4410d453ea0de1d0e8fdf
[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 DNS to 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;
1142   unsigned int scratch_len;
1143    
1144   if (0 == rh->name_resolution_pos)
1145   {
1146     /* top-level match, are we done yet? */
1147     if ( (rd_count > 0) &&
1148          (GNUNET_DNSPARSER_TYPE_CNAME == rd[0].record_type) &&
1149          (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type) )
1150     {
1151       cname = GNUNET_strndup (rd[0].data,
1152                               rd[0].data_size);
1153       handle_gns_cname_result (rh, 
1154                                cname);
1155       GNUNET_free (cname);
1156       return;     
1157     }
1158     /* If A/AAAA was requested, but we got a VPN
1159        record, we convert it to A/AAAA using GNUnet VPN */
1160     if ( (GNUNET_DNSPARSER_TYPE_A == rh->record_type) ||
1161          (GNUNET_DNSPARSER_TYPE_AAAA == rh->record_type) )
1162     {
1163       for (i=0;i<rd_count;i++)
1164       {
1165         if (GNUNET_NAMESTORE_TYPE_VPN == rd[i].record_type)
1166         {
1167           af = (GNUNET_DNSPARSER_TYPE_A == rh->record_type) ? AF_INET : AF_INET6;
1168           if (sizeof (struct GNUNET_TUN_GnsVpnRecord) <
1169               rd[i].data_size)
1170           {
1171             GNUNET_break_op (0);
1172             rh->proc (rh->proc_cls, 0, NULL);
1173             GNS_resolver_lookup_cancel (rh);
1174             return;         
1175           }
1176           vpn = (const struct GNUNET_TUN_GnsVpnRecord *) rd[i].data;
1177           vname = (const char *) &vpn[1];
1178           if ('\0' != vname[rd[i].data_size - 1 - sizeof (struct GNUNET_TUN_GnsVpnRecord)])
1179           {
1180             GNUNET_break_op (0);
1181             rh->proc (rh->proc_cls, 0, NULL);
1182             GNS_resolver_lookup_cancel (rh);
1183             return;
1184           }
1185           GNUNET_CRYPTO_hash (vname,
1186                               strlen (vname), // FIXME: +1?
1187                               &vhash);
1188           vpn_ctx = GNUNET_new (struct VpnContext);
1189           rh->vpn_ctx = vpn_ctx;
1190           vpn_ctx->rh = rh;
1191           vpn_ctx->rd_data_size = GNUNET_NAMESTORE_records_get_size (rd_count,
1192                                                                      rd);
1193           vpn_ctx->rd_data = GNUNET_malloc (vpn_ctx->rd_data_size);
1194           (void) GNUNET_NAMESTORE_records_serialize (rd_count,
1195                                                      rd,
1196                                                      vpn_ctx->rd_data_size,
1197                                                      vpn_ctx->rd_data);
1198           vpn_ctx->vpn_request = GNUNET_VPN_redirect_to_peer (vpn_handle,
1199                                                               af,
1200                                                               ntohs (vpn->proto),
1201                                                               &vpn->peer,
1202                                                               &vhash,
1203                                                               GNUNET_NO,
1204                                                               GNUNET_TIME_relative_to_absolute (VPN_TIMEOUT),
1205                                                               &vpn_allocation_cb,
1206                                                               rh);
1207           return;
1208         }
1209       }
1210     }
1211     /* convert relative names in record values to absolute names,
1212        using 'scratch' array for memory allocations */
1213     scratch = NULL;
1214     scratch_len = 0;
1215     for (i=0;i<rd_count;i++)
1216     {
1217       /* Strategy: dnsparser should expose API to make it easier
1218          for us to parse all of these binary record values individually;
1219          then, we check if the embedded name(s) end in "+", and if so,
1220          replace the "+" with the zone at "ac_tail", changing the name
1221          to a ".zkey".  The name is allocated on the 'scratch' array,
1222          so we can free it afterwards. */
1223       switch (rd[i].record_type)
1224       {
1225       case GNUNET_DNSPARSER_TYPE_CNAME:
1226         GNUNET_break (0); // FIXME: not implemented
1227         break;
1228       case GNUNET_DNSPARSER_TYPE_SOA:
1229         GNUNET_break (0); // FIXME: not implemented
1230         break;
1231       case GNUNET_DNSPARSER_TYPE_MX:
1232         GNUNET_break (0); // FIXME: not implemented
1233         break;
1234       case GNUNET_DNSPARSER_TYPE_SRV:
1235         GNUNET_break (0); // FIXME: not implemented
1236         break;
1237       default:
1238         break;
1239       }
1240     }
1241     
1242     /* yes, we are done, return result */
1243     rh->proc (rh->proc_cls, rd_count, rd);
1244     GNS_resolver_lookup_cancel (rh);
1245     for (i=0;i<scratch_len;i++)
1246       GNUNET_free (scratch[i]);
1247     GNUNET_array_grow (scratch, 
1248                        scratch_len,
1249                        0);
1250     return;         
1251   }
1252   /* need to recurse, check if we can */
1253   for (i=0;i<rd_count;i++)
1254   {
1255     switch (rd[i].record_type)
1256     {
1257     case GNUNET_NAMESTORE_TYPE_PKEY:
1258       /* delegation to another zone */
1259       if (sizeof (struct GNUNET_CRYPTO_EccPublicKey) !=
1260           rd[i].data_size)
1261       {
1262         GNUNET_break_op (0);
1263         rh->proc (rh->proc_cls, 0, NULL);
1264         GNS_resolver_lookup_cancel (rh);
1265         return;     
1266       }
1267       /* expand authority chain */
1268       ac = GNUNET_new (struct AuthorityChain);
1269       ac->rh = rh;
1270       ac->gns_authority = GNUNET_YES;
1271       memcpy (&ac->authority_info.gns_authority,
1272               rd[i].data,
1273               sizeof (struct GNUNET_CRYPTO_EccPublicKey));
1274       ac->label = resolver_lookup_get_next_label (rh);
1275       GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1276                                         rh->ac_tail,
1277                                         ac);
1278       /* recurse */
1279       rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1280                                               rh);
1281       break;
1282     case GNUNET_DNSPARSER_TYPE_NS:
1283       /* resolution continues within DNS */
1284       if (GNUNET_DNSPARSER_MAX_NAME_LENGTH < rd[i].data_size)
1285       {
1286         GNUNET_break_op (0);
1287         rh->proc (rh->proc_cls, 0, NULL);
1288         GNS_resolver_lookup_cancel (rh);
1289         return;     
1290       }
1291       /* find associated A/AAAA record */
1292       sa = NULL;
1293       for (j=0;j<rd_count;j++)
1294       {
1295         switch (rd[j].record_type)
1296         {
1297         case GNUNET_DNSPARSER_TYPE_A:
1298           if (sizeof (struct in_addr) != rd[i].data_size)
1299           {
1300             GNUNET_break_op (0);
1301             rh->proc (rh->proc_cls, 0, NULL);
1302             GNS_resolver_lookup_cancel (rh);
1303             return;     
1304           }
1305           /* FIXME: might want to check if we support IPv4 here,
1306              and otherwise skip this one and hope we find another */
1307           memset (&v4, 0, sizeof (v4));
1308           sa_len = sizeof (v4);
1309           v4.sin_family = AF_INET;
1310           v4.sin_port = htons (53);
1311 #if HAVE_SOCKADDR_IN_SIN_LEN
1312           v4.sin_len = (u_char) sa_len;
1313 #endif
1314           memcpy (&v4.sin_addr,
1315                   rd[j].data,
1316                   sizeof (struct in_addr));
1317           sa = (struct sockaddr *) &v4;
1318           break;
1319         case GNUNET_DNSPARSER_TYPE_AAAA:
1320           if (sizeof (struct in6_addr) != rd[i].data_size)
1321           {
1322             GNUNET_break_op (0);
1323             rh->proc (rh->proc_cls, 0, NULL);
1324             GNS_resolver_lookup_cancel (rh);
1325             return;     
1326           }
1327           /* FIXME: might want to check if we support IPv6 here,
1328              and otherwise skip this one and hope we find another */
1329           memset (&v6, 0, sizeof (v6));
1330           sa_len = sizeof (v6);
1331           v6.sin6_family = AF_INET6;
1332           v6.sin6_port = htons (53);
1333 #if HAVE_SOCKADDR_IN_SIN_LEN
1334           v6.sin6_len = (u_char) sa_len;
1335 #endif
1336           memcpy (&v6.sin6_addr,
1337                   rd[j].data,
1338                   sizeof (struct in6_addr));
1339           sa = (struct sockaddr *) &v6;
1340           break;
1341         }
1342         if (NULL != sa)
1343           break;
1344       }
1345       /* expand authority chain */
1346       ac = GNUNET_new (struct AuthorityChain);
1347       ac->rh = rh;
1348       strncpy (ac->authority_info.dns_authority.name,
1349                rd[i].data,
1350                rd[i].data_size);
1351       ac->authority_info.dns_authority.name[rd[i].data_size] = '\0';
1352       memcpy (&ac->authority_info.dns_authority.dns_ip,
1353               sa,
1354               sa_len);
1355       /* for DNS recursion, the label is the full DNS name,
1356          created from the remainder of the GNS name and the
1357          name in the NS record */
1358       GNUNET_asprintf (&ac->label,
1359                        "%.*s%s",
1360                        (int) rh->name_resolution_pos,
1361                        rh->name,
1362                        ac->authority_info.dns_authority.name);
1363       GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1364                                         rh->ac_tail,
1365                                         ac);
1366       if (strlen (ac->label) > GNUNET_DNSPARSER_MAX_NAME_LENGTH)
1367       {
1368         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1369                     _("GNS lookup resulted in DNS name that is too long (`%s')\n"),
1370                     ac->label);
1371         rh->proc (rh->proc_cls, 0, NULL);
1372         GNS_resolver_lookup_cancel (rh);
1373         return;
1374       }
1375       /* recurse */
1376       rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1377                                               rh);
1378       return;
1379     case GNUNET_DNSPARSER_TYPE_CNAME:
1380       cname = GNUNET_strndup (rd[i].data,
1381                               rd[i].data_size);
1382       handle_gns_cname_result (rh, 
1383                                cname);
1384       GNUNET_free (cname);
1385       return;
1386       /* FIXME: handle DNAME */
1387     default:
1388       /* skip */
1389       break;
1390     }
1391   }
1392   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1393               _("GNS lookup recursion failed (no delegation record found)\n"));
1394   rh->proc (rh->proc_cls, 0, NULL);
1395   GNS_resolver_lookup_cancel (rh);
1396 }
1397
1398
1399 /**
1400  * Function called once the namestore has completed the request for
1401  * caching a block.
1402  *
1403  * @param cls closure with the 'struct GNS_ResolverHandle'
1404  * @param success #GNUNET_OK on success
1405  * @param emsg error message
1406  */
1407 static void
1408 namestore_cache_continuation (void *cls,
1409                               int32_t success,
1410                               const char *emsg)
1411 {
1412   struct GNS_ResolverHandle *rh = cls;
1413
1414   rh->namestore_qe = NULL;
1415   if (NULL != emsg)
1416     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1417                 _("Failed to cache GNS resolution: %s\n"),
1418                 emsg);
1419 }
1420
1421
1422 /**
1423  * Iterator called on each result obtained for a DHT
1424  * operation that expects a reply
1425  *
1426  * @param cls closure with the 'struct GNS_ResolverHandle'
1427  * @param exp when will this value expire
1428  * @param key key of the result
1429  * @param get_path peers on reply path (or NULL if not recorded)
1430  *                 [0] = datastore's first neighbor, [length - 1] = local peer
1431  * @param get_path_length number of entries in get_path
1432  * @param put_path peers on the PUT path (or NULL if not recorded)
1433  *                 [0] = origin, [length - 1] = datastore
1434  * @param put_path_length number of entries in get_path
1435  * @param type type of the result
1436  * @param size number of bytes in data
1437  * @param data pointer to the result data
1438  */
1439 static void
1440 handle_dht_response (void *cls,
1441                      struct GNUNET_TIME_Absolute exp,
1442                      const struct GNUNET_HashCode * key,
1443                      const struct GNUNET_PeerIdentity *get_path,
1444                      unsigned int get_path_length,
1445                      const struct GNUNET_PeerIdentity *put_path, 
1446                      unsigned int put_path_length,
1447                      enum GNUNET_BLOCK_Type type,
1448                      size_t size, const void *data)
1449 {
1450   struct GNS_ResolverHandle *rh = cls;
1451   struct AuthorityChain *ac = rh->ac_tail;
1452   const struct GNUNET_NAMESTORE_Block *block;
1453   
1454   GNUNET_DHT_get_stop (rh->get_handle);
1455   rh->get_handle = NULL;
1456   GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
1457   rh->dht_heap_node = NULL;  
1458   if (size < sizeof (struct GNUNET_NAMESTORE_Block))
1459   {
1460     /* how did this pass DHT block validation!? */
1461     GNUNET_break (0);
1462     rh->proc (rh->proc_cls, 0, NULL);
1463     GNS_resolver_lookup_cancel (rh);
1464     return;   
1465   }
1466   block = data; 
1467   if (size !=
1468       ntohs (block->purpose.size) + 
1469       sizeof (struct GNUNET_CRYPTO_EccPublicKey) +
1470       sizeof (struct GNUNET_CRYPTO_EccSignature))
1471   {
1472     /* how did this pass DHT block validation!? */
1473     GNUNET_break (0);
1474     rh->proc (rh->proc_cls, 0, NULL);
1475     GNS_resolver_lookup_cancel (rh);
1476     return;   
1477   }
1478   if (GNUNET_OK !=
1479       GNUNET_NAMESTORE_block_decrypt (block,
1480                                       &ac->authority_info.gns_authority,
1481                                       ac->label,
1482                                       &handle_gns_resolution_result,
1483                                       rh))
1484   {
1485     GNUNET_break_op (0); /* block was ill-formed */
1486     rh->proc (rh->proc_cls, 0, NULL);
1487     GNS_resolver_lookup_cancel (rh);
1488     return;
1489   }
1490   /* Cache well-formed blocks */
1491   rh->namestore_qe = GNUNET_NAMESTORE_block_cache (namestore_handle,
1492                                                    block,
1493                                                    &namestore_cache_continuation,
1494                                                    rh);
1495 }
1496
1497
1498 /**
1499  * Process a record that was stored in the namestore.
1500  *
1501  * @param cls closure with the `struct GNS_ResolverHandle`
1502  * @param block block that was stored in the namestore
1503  */
1504 static void 
1505 handle_namestore_block_response (void *cls,
1506                                  const struct GNUNET_NAMESTORE_Block *block)
1507 {
1508   struct GNS_ResolverHandle *rh = cls;
1509   struct GNS_ResolverHandle *rx;
1510   struct AuthorityChain *ac = rh->ac_tail;
1511   const char *label = ac->label;
1512   const struct GNUNET_CRYPTO_EccPublicKey *auth = &ac->authority_info.gns_authority;
1513   struct GNUNET_HashCode query;
1514
1515   GNUNET_NAMESTORE_query_from_public_key (auth,
1516                                           label,
1517                                           &query);
1518   rh->namestore_qe = NULL;
1519   if (NULL == block)
1520   {
1521     /* Namestore knows nothing; try DHT lookup */
1522     rh->get_handle = GNUNET_DHT_get_start (dht_handle,
1523                                            GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1524                                            &query,
1525                                            DHT_GNS_REPLICATION_LEVEL,
1526                                            GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
1527                                            NULL, 0,
1528                                            &handle_dht_response, rh);
1529     rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
1530                                                       rh,
1531                                                       GNUNET_TIME_absolute_get ().abs_value_us);
1532     if (GNUNET_CONTAINER_heap_get_size (dht_lookup_heap) > max_allowed_background_queries)
1533     {
1534       /* fail longest-standing DHT request */
1535       rx = GNUNET_CONTAINER_heap_peek (dht_lookup_heap);
1536       rx->proc (rx->proc_cls, 0, NULL);
1537       GNS_resolver_lookup_cancel (rx);
1538     }
1539     return;
1540   }
1541   if (GNUNET_OK !=
1542       GNUNET_NAMESTORE_block_decrypt (block,
1543                                       auth,
1544                                       label,
1545                                       &handle_gns_resolution_result,
1546                                       rh))
1547   {
1548     GNUNET_break_op (0); /* block was ill-formed */
1549     rh->proc (rh->proc_cls, 0, NULL);
1550     GNS_resolver_lookup_cancel (rh);
1551     return;
1552   }
1553 }
1554
1555
1556 /**
1557  * Lookup tail of our authority chain in the namestore.
1558  *
1559  * @param rh query we are processing
1560  */
1561 static void
1562 recursive_gns_resolution_namestore (struct GNS_ResolverHandle *rh)
1563 {
1564   struct AuthorityChain *ac = rh->ac_tail;
1565   struct GNUNET_HashCode query;
1566
1567   GNUNET_NAMESTORE_query_from_public_key (&ac->authority_info.gns_authority,
1568                                           ac->label,
1569                                           &query);
1570   rh->namestore_qe = GNUNET_NAMESTORE_lookup_block (namestore_handle,
1571                                                     &query,
1572                                                     &handle_namestore_block_response,
1573                                                     rh);
1574 }
1575
1576
1577 /**
1578  * Task scheduled to continue with the resolution process.
1579  *
1580  * @param cls the `struct GNS_ResolverHandle` of the resolution
1581  * @param tc task context
1582  */
1583 static void
1584 recursive_resolution (void *cls,
1585                       const struct GNUNET_SCHEDULER_TaskContext *tc)
1586 {
1587   struct GNS_ResolverHandle *rh = cls;
1588
1589   rh->task_id = GNUNET_SCHEDULER_NO_TASK;
1590   if (MAX_RECURSION < rh->loop_limiter++)
1591   {
1592     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1593                 "Encountered unbounded recursion resolving `%s'\n",
1594                 rh->name);
1595     rh->proc (rh->proc_cls, 0, NULL);
1596     GNS_resolver_lookup_cancel (rh);
1597     return;
1598   }
1599   if (GNUNET_YES == rh->ac_tail->gns_authority)
1600     recursive_gns_resolution_namestore (rh);
1601   else
1602     recursive_dns_resolution (rh);
1603 }
1604
1605
1606 /**
1607  * Begin the resolution process from 'name', starting with
1608  * the identification of the zone specified by 'name'.
1609  *
1610  * @param rh resolution to perform
1611  */
1612 static void
1613 start_resolver_lookup (struct GNS_ResolverHandle *rh)
1614 {
1615   struct AuthorityChain *ac;
1616   char *x;
1617   char *y;
1618   char *pkey;
1619
1620   if ( ( (GNUNET_YES == is_canonical (rh->name)) &&
1621          (0 != strcmp (GNUNET_GNS_TLD, rh->name)) ) ||
1622        ( (GNUNET_YES != is_gnu_tld (rh->name)) &&
1623          (GNUNET_YES != is_zkey_tld (rh->name)) ) )
1624   {
1625     /* use standard DNS lookup */
1626     int af;
1627
1628     switch (rh->record_type)
1629     {
1630     case GNUNET_DNSPARSER_TYPE_A:
1631       af = AF_INET;
1632       break;
1633     case GNUNET_DNSPARSER_TYPE_AAAA:
1634       af = AF_INET6;
1635       break;
1636     default:
1637       af = AF_UNSPEC;
1638       break;
1639     }
1640     rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name, 
1641                                               af,
1642                                               DNS_LOOKUP_TIMEOUT,
1643                                               &handle_dns_result,
1644                                               rh);
1645     return;
1646   }
1647   if (is_zkey_tld (rh->name))
1648   {
1649     /* Name ends with ".zkey", try to replace authority zone with zkey
1650        authority */
1651     GNUNET_free (resolver_lookup_get_next_label (rh)); /* will return "zkey" */
1652     x = resolver_lookup_get_next_label (rh); /* will return 'x' coordinate */
1653     y = resolver_lookup_get_next_label (rh); /* will return 'y' coordinate */
1654     GNUNET_asprintf (&pkey,
1655                      "%s%s",
1656                      x, y);
1657     if ( (NULL == x) ||
1658          (NULL == y) ||
1659          (GNUNET_OK !=
1660           GNUNET_CRYPTO_ecc_public_key_from_string (pkey,
1661                                                     strlen (pkey),
1662                                                     &rh->authority_zone)) )
1663     {
1664       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1665                   _("Hostname `%s' is not well-formed, resolution fails\n"),
1666                   rh->name);
1667       rh->task_id = GNUNET_SCHEDULER_add_now (&fail_resolution, rh);
1668     }
1669     GNUNET_free_non_null (x);
1670     GNUNET_free_non_null (y);
1671     GNUNET_free (pkey);
1672   }
1673   else
1674   {
1675     /* Name ends with ".gnu", eat ".gnu" and continue with resolution */
1676     GNUNET_free (resolver_lookup_get_next_label (rh));
1677   }
1678   ac = GNUNET_new (struct AuthorityChain);
1679   ac->rh = rh;
1680   ac->label = resolver_lookup_get_next_label (rh);
1681   if (NULL == ac->label)
1682     /* name was just "gnu", so we default to label '+' */
1683     ac->label = GNUNET_strdup (GNUNET_GNS_MASTERZONE_STR);
1684   ac->gns_authority = GNUNET_YES;
1685   ac->authority_info.gns_authority = rh->authority_zone;
1686   GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1687                                     rh->ac_tail,
1688                                     ac);
1689   rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1690                                           rh);
1691 }
1692
1693
1694 /**
1695  * Lookup of a record in a specific zone calls lookup result processor
1696  * on result.
1697  *
1698  * @param zone the zone to perform the lookup in
1699  * @param record_type the record type to look up
1700  * @param name the name to look up
1701  * @param shorten_key a private key for use with PSEU import (can be NULL)
1702  * @param only_cached #GNUNET_NO to only check locally not DHT for performance
1703  * @param proc the processor to call on result
1704  * @param proc_cls the closure to pass to @a proc
1705  * @return handle to cancel operation
1706  */
1707 struct GNS_ResolverHandle *
1708 GNS_resolver_lookup (const struct GNUNET_CRYPTO_EccPublicKey *zone,
1709                      uint32_t record_type,
1710                      const char *name,
1711                      const struct GNUNET_CRYPTO_EccPrivateKey *shorten_key,
1712                      int only_cached,
1713                      GNS_ResultProcessor proc, void *proc_cls)
1714 {
1715   struct GNS_ResolverHandle *rh;
1716
1717   rh = GNUNET_new (struct GNS_ResolverHandle);
1718   GNUNET_CONTAINER_DLL_insert (rlh_head,
1719                                rlh_tail,
1720                                rh);
1721   rh->authority_zone = *zone;
1722   rh->proc = proc;
1723   rh->proc_cls = proc_cls;
1724   rh->only_cached = only_cached;
1725   rh->record_type = record_type;
1726   rh->name = GNUNET_strdup (name);
1727   rh->name_resolution_pos = strlen (name);
1728   if (NULL != shorten_key)
1729   {
1730     rh->shorten_key = GNUNET_new (struct GNUNET_CRYPTO_EccPrivateKey);
1731     *rh->shorten_key = *shorten_key;
1732   }
1733   start_resolver_lookup (rh);
1734   return rh;
1735 }
1736
1737
1738 /**
1739  * Cancel active resolution (i.e. client disconnected).
1740  *
1741  * @param rh resolution to abort
1742  */
1743 void
1744 GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
1745 {
1746   struct DnsResult *dr;
1747   struct AuthorityChain *ac;
1748   struct VpnContext *vpn_ctx;
1749
1750   GNUNET_CONTAINER_DLL_remove (rlh_head,
1751                                rlh_tail,
1752                                rh);
1753   while (NULL != (ac = rh->ac_head))
1754   {
1755     GNUNET_CONTAINER_DLL_remove (rh->ac_head,
1756                                  rh->ac_tail,
1757                                  ac);
1758     GNUNET_free (ac->label);
1759     GNUNET_free (ac);
1760   }
1761   if (GNUNET_SCHEDULER_NO_TASK != rh->task_id)
1762   {
1763     GNUNET_SCHEDULER_cancel (rh->task_id);
1764     rh->task_id = GNUNET_SCHEDULER_NO_TASK;
1765   }
1766   if (NULL != rh->get_handle)
1767   {
1768     GNUNET_DHT_get_stop (rh->get_handle);
1769     rh->get_handle = NULL;
1770   }
1771   if (NULL != rh->dht_heap_node)
1772   {
1773     GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
1774     rh->dht_heap_node = NULL;
1775   }
1776   if (NULL != (vpn_ctx = rh->vpn_ctx))
1777   {
1778     GNUNET_VPN_cancel_request (vpn_ctx->vpn_request);
1779     GNUNET_free (vpn_ctx->rd_data);
1780     GNUNET_free (vpn_ctx);
1781   }
1782   if (NULL != rh->dns_request)
1783   {
1784     GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
1785     rh->dns_request = NULL;
1786   }
1787   if (NULL != rh->namestore_qe)
1788   {
1789     GNUNET_NAMESTORE_cancel (rh->namestore_qe);
1790     rh->namestore_qe = NULL;
1791   }
1792   if (NULL != rh->std_resolve)
1793   {
1794     GNUNET_RESOLVER_request_cancel (rh->std_resolve);
1795     rh->std_resolve = NULL;
1796   }
1797   while (NULL != (dr = rh->dns_result_head))
1798   {
1799     GNUNET_CONTAINER_DLL_remove (rh->dns_result_head,
1800                                  rh->dns_result_tail,
1801                                  dr);
1802     GNUNET_free (dr);
1803   }
1804   GNUNET_free_non_null (rh->shorten_key);
1805   GNUNET_free (rh->name);
1806   GNUNET_free (rh);
1807 }
1808
1809
1810 /* ***************** Resolver initialization ********************* */
1811
1812
1813 /**
1814  * Initialize the resolver
1815  *
1816  * @param nh the namestore handle
1817  * @param dht the dht handle
1818  * @param c configuration handle
1819  * @param max_bg_queries maximum number of parallel background queries in dht
1820  */
1821 void
1822 GNS_resolver_init (struct GNUNET_NAMESTORE_Handle *nh,
1823                    struct GNUNET_DHT_Handle *dht,
1824                    const struct GNUNET_CONFIGURATION_Handle *c,
1825                    unsigned long long max_bg_queries)
1826 {
1827   char *dns_ip;
1828
1829   cfg = c;
1830   namestore_handle = nh;
1831   dht_handle = dht;
1832   dht_lookup_heap =
1833     GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1834   max_allowed_background_queries = max_bg_queries;
1835   if (GNUNET_OK !=
1836       GNUNET_CONFIGURATION_get_value_string (c,
1837                                              "gns",
1838                                              "DNS_RESOLVER",
1839                                              &dns_ip))
1840   {
1841     /* user did not specify DNS resolver, use 8.8.8.8 */
1842     dns_ip = GNUNET_strdup ("8.8.8.8");
1843   }
1844   dns_handle = GNUNET_DNSSTUB_start (dns_ip);
1845   GNUNET_free (dns_ip);
1846   vpn_handle = GNUNET_VPN_connect (cfg);
1847 }
1848
1849
1850 /**
1851  * Shutdown resolver
1852  */
1853 void
1854 GNS_resolver_done ()
1855 {
1856   struct GNS_ResolverHandle *rh;
1857
1858   /* abort active resolutions */
1859   while (NULL != (rh = rlh_head))
1860   {
1861     rh->proc (rh->proc_cls, 0, NULL);
1862     GNS_resolver_lookup_cancel (rh);    
1863   }
1864   GNUNET_CONTAINER_heap_destroy (dht_lookup_heap);
1865   dht_lookup_heap = NULL;
1866   GNUNET_DNSSTUB_stop (dns_handle);
1867   dns_handle = NULL;
1868   GNUNET_VPN_disconnect (vpn_handle);
1869   vpn_handle = NULL;
1870   dht_handle = NULL;
1871   namestore_handle = NULL;
1872 }
1873
1874
1875 /* *************** common helper functions (do not really belong here) *********** */
1876
1877 /**
1878  * Checks if @a name ends in ".TLD"
1879  *
1880  * @param name the name to check
1881  * @param tld the TLD to check for
1882  * @return GNUNET_YES or GNUNET_NO
1883  */
1884 int
1885 is_tld (const char* name, const char* tld)
1886 {
1887   size_t offset = 0;
1888
1889   if (strlen (name) <= strlen (tld))
1890     return GNUNET_NO;
1891   offset = strlen (name) - strlen (tld);
1892   if (0 != strcmp (name + offset, tld))
1893     return GNUNET_NO;
1894   return GNUNET_YES;
1895 }
1896
1897
1898 /* end of gnunet-service-gns_resolver.c */