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