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