-cleaner shutdown
[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     rh->proc (rh->proc_cls,
584               n,
585               rd);
586   }
587   GNS_resolver_lookup_cancel (rh);
588 }
589
590
591 /**
592  * Add a result from DNS to the records to be returned to the application.
593  *
594  * @param rh resolution request to extend with a result
595  * @param expiration_time expiration time for the answer
596  * @param record_type DNS record type of the answer
597  * @param data_size number of bytes in @a data
598  * @param data binary data to return in DNS record
599  */
600 static void
601 add_dns_result (struct GNS_ResolverHandle *rh,
602                 uint64_t expiration_time,
603                 uint32_t record_type,
604                 size_t data_size,
605                 const void *data)
606 {
607   struct DnsResult *res;
608
609   res = GNUNET_malloc (sizeof (struct DnsResult) + data_size);
610   res->expiration_time = expiration_time;
611   res->data_size = data_size;
612   res->record_type = record_type;
613   res->data = &res[1];
614   memcpy (&res[1], data, data_size);
615   GNUNET_CONTAINER_DLL_insert (rh->dns_result_head,
616                                rh->dns_result_tail,
617                                res);
618 }
619
620
621 /**
622  * We had to do a DNS lookup.  Convert the result (if any) and return
623  * it.
624  *
625  * @param cls closure with the 'struct GNS_ResolverHandle'
626  * @param addr one of the addresses of the host, NULL for the last address
627  * @param addrlen length of the address
628  */
629 static void
630 handle_dns_result (void *cls,
631                    const struct sockaddr *addr,
632                    socklen_t addrlen)
633 {
634   struct GNS_ResolverHandle *rh = cls;
635   const struct sockaddr_in *sa4;
636   const struct sockaddr_in6 *sa6;
637
638   rh->std_resolve = NULL;
639   if (NULL == addr)
640   {
641     transmit_lookup_dns_result (rh);
642     return;
643   }
644   switch (addr->sa_family)
645   {
646   case AF_INET:
647     sa4 = (const struct sockaddr_in *) addr;
648     add_dns_result (rh,
649                     0 /* expiration time is unknown */,
650                     GNUNET_DNSPARSER_TYPE_A,
651                     sizeof (struct in_addr),
652                     &sa4->sin_addr);
653     break;
654   case AF_INET6:
655     sa6 = (const struct sockaddr_in6 *) addr;
656     add_dns_result (rh,
657                     0 /* expiration time is unknown */,
658                     GNUNET_DNSPARSER_TYPE_AAAA,
659                     sizeof (struct in6_addr),
660                     &sa6->sin6_addr);
661     break;
662   default:
663     GNUNET_break (0);
664     break;
665   }
666 }
667
668
669 /**
670  * Task scheduled to continue with the resolution process.
671  *
672  * @param cls the 'struct GNS_ResolverHandle' of the resolution
673  * @param tc task context
674  */
675 static void
676 recursive_resolution (void *cls,
677                       const struct GNUNET_SCHEDULER_TaskContext *tc);
678
679
680 /**
681  * Begin the resolution process from 'name', starting with
682  * the identification of the zone specified by 'name'.
683  *
684  * @param rh resolution to perform
685  */
686 static void
687 start_resolver_lookup (struct GNS_ResolverHandle *rh);
688
689
690 /**
691  * Function called with the result of a DNS resolution.
692  *
693  * @param cls the request handle of the resolution that
694  *        we were attempting to make
695  * @param rs socket that received the response
696  * @param dns dns response, never NULL
697  * @param dns_len number of bytes in @a dns
698  */
699 static void
700 dns_result_parser (void *cls,
701                    struct GNUNET_DNSSTUB_RequestSocket *rs,
702                    const struct GNUNET_TUN_DnsHeader *dns,
703                    size_t dns_len)
704 {
705   struct GNS_ResolverHandle *rh = cls;
706   struct GNUNET_DNSPARSER_Packet *p;
707   const struct GNUNET_DNSPARSER_Record *rec;
708   unsigned int rd_count;
709   unsigned int i;
710
711   rh->dns_request = NULL;
712   GNUNET_SCHEDULER_cancel (rh->task_id);
713   rh->task_id = GNUNET_SCHEDULER_NO_TASK;
714   p = GNUNET_DNSPARSER_parse ((const char *) dns, 
715                               dns_len);
716   if (NULL == p)
717   {
718     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
719                 _("Failed to parse DNS response\n"));
720     rh->proc (rh->proc_cls, 0, NULL);
721     GNS_resolver_lookup_cancel (rh);
722     return;
723   }
724
725   if ( (p->num_answers > 0) &&
726        (GNUNET_DNSPARSER_TYPE_CNAME == p->answers[0].type) &&
727        (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type) )
728     {
729       GNUNET_free (rh->name);
730       rh->name = GNUNET_strdup (p->answers[0].data.hostname);
731       start_resolver_lookup (rh);
732       GNUNET_DNSPARSER_free_packet (p);
733       return;     
734     }
735   /* FIXME: add DNAME support */
736
737   /* convert from (parsed) DNS to (binary) GNS format! */
738   rd_count = p->num_answers + p->num_authority_records + p->num_additional_records;
739   {
740     struct GNUNET_NAMESTORE_RecordData rd[rd_count];
741     unsigned int skip;
742     char buf[UINT16_MAX];
743     size_t buf_off;
744
745     buf_off = 0;
746     skip = 0;
747     memset (rd, 0, sizeof (rd));
748     for (i=0;i<rd_count;i++)
749     {
750       if (i < p->num_answers)
751         rec = &p->answers[i];
752       else if (i < p->num_answers + p->num_authority_records)
753         rec = &p->authority_records[i - p->num_answers];
754       else 
755         rec = &p->authority_records[i - p->num_answers - p->num_authority_records];
756       /* As we copied the full DNS name to 'rh->ac_tail->label', this
757          should be the correct check to see if this record is actually
758          a record for our label... */
759       if (0 != strcmp (rec->name,
760                        rh->ac_tail->label))
761       {
762         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
763                     "Dropping record `%s', does not match desired name `%s'\n",
764                     rec->name,
765                     rh->ac_tail->label);
766         skip++;
767         continue;
768       }
769       rd[i - skip].record_type = rec->type;
770       rd[i - skip].expiration_time = rec->expiration_time.abs_value_us;
771       switch (rec->type)
772       {
773       case GNUNET_DNSPARSER_TYPE_A:
774         if (rec->data.raw.data_len != sizeof (struct in_addr))
775         {
776           GNUNET_break_op (0);
777           skip++;
778           continue;
779         }
780         rd[i - skip].data_size = rec->data.raw.data_len;
781         rd[i - skip].data = rec->data.raw.data;
782         break;
783       case GNUNET_DNSPARSER_TYPE_AAAA:
784         if (rec->data.raw.data_len != sizeof (struct in6_addr))
785         {
786           GNUNET_break_op (0);
787           skip++;
788           continue;
789         }
790         rd[i - skip].data_size = rec->data.raw.data_len;
791         rd[i - skip].data = rec->data.raw.data;
792         break;
793       case GNUNET_DNSPARSER_TYPE_CNAME:
794       case GNUNET_DNSPARSER_TYPE_PTR:
795       case GNUNET_DNSPARSER_TYPE_NS:
796         if (GNUNET_OK !=
797             GNUNET_DNSPARSER_builder_add_name (buf,
798                                                sizeof (buf),
799                                                &buf_off,
800                                                rec->data.hostname))
801         {
802           GNUNET_break (0);
803           skip++;
804           continue;
805         }
806         break;
807       case GNUNET_DNSPARSER_TYPE_SOA:
808         if (GNUNET_OK !=
809             GNUNET_DNSPARSER_builder_add_soa (buf,
810                                                sizeof (buf),
811                                                &buf_off,
812                                                rec->data.soa))
813         {
814           GNUNET_break (0);
815           skip++;
816           continue;
817         }
818         break;
819       case GNUNET_DNSPARSER_TYPE_MX:
820         if (GNUNET_OK !=
821             GNUNET_DNSPARSER_builder_add_mx (buf,
822                                              sizeof (buf),
823                                              &buf_off,
824                                              rec->data.mx))
825         {
826           GNUNET_break (0);
827           skip++;
828           continue;
829         }
830         break;
831       case GNUNET_DNSPARSER_TYPE_SRV:
832         if (GNUNET_OK !=
833             GNUNET_DNSPARSER_builder_add_srv (buf,
834                                               sizeof (buf),
835                                               &buf_off,
836                                               rec->data.srv))
837         {
838           GNUNET_break (0);
839           skip++;
840           continue;
841         }
842         break;
843       default:
844         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
845                     _("Skipping record of unsupported type %d\n"),
846                     rec->type);
847         skip++;
848         continue;
849       }
850     }
851     rh->proc (rh->proc_cls, rd_count - skip, rd);
852     GNS_resolver_lookup_cancel (rh);
853   }  
854   GNUNET_DNSPARSER_free_packet (p);
855 }
856
857
858 /**
859  * Perform recursive DNS resolution.  Asks the given DNS resolver to
860  * resolve "rh->dns_name", possibly recursively proceeding following
861  * NS delegations, CNAMES, etc., until 'rh->loop_limiter' bounds us or
862  * we find the answer.
863  *
864  * @param rh resolution information
865  */
866 static void
867 recursive_dns_resolution (struct GNS_ResolverHandle *rh)
868 {
869   struct AuthorityChain *ac;
870   socklen_t sa_len;
871   struct GNUNET_DNSPARSER_Query *query;
872   struct GNUNET_DNSPARSER_Packet *p;
873   char *dns_request;
874   size_t dns_request_length;
875
876   ac = rh->ac_tail;
877   GNUNET_assert (NULL != ac);
878   GNUNET_assert (GNUNET_NO == ac->gns_authority);
879   switch (((const struct sockaddr *) &ac->authority_info.dns_authority.dns_ip)->sa_family)
880   {
881   case AF_INET:
882     sa_len = sizeof (struct sockaddr_in);
883     break;
884   case AF_INET6:
885     sa_len = sizeof (struct sockaddr_in6);
886     break;
887   default:
888     GNUNET_break (0);
889     rh->proc (rh->proc_cls, 0, NULL);
890     GNS_resolver_lookup_cancel (rh);
891     return;
892   }
893   query = GNUNET_new (struct GNUNET_DNSPARSER_Query);
894   query->name = GNUNET_strdup (ac->label);
895   query->type = rh->record_type;
896   query->class = GNUNET_TUN_DNS_CLASS_INTERNET;
897   p = GNUNET_new (struct GNUNET_DNSPARSER_Packet);
898   p->queries = query;
899   p->num_queries = 1;
900   p->id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
901                                                UINT16_MAX);
902   p->flags.opcode = GNUNET_TUN_DNS_OPCODE_QUERY;
903   p->flags.recursion_desired = 1;
904   if (GNUNET_OK != 
905       GNUNET_DNSPARSER_pack (p, 1024, &dns_request, &dns_request_length))
906   {
907     GNUNET_break (0);
908     rh->proc (rh->proc_cls, 0, NULL);
909     GNS_resolver_lookup_cancel (rh);
910   }
911   else
912   {
913     rh->dns_request = GNUNET_DNSSTUB_resolve (dns_handle,
914                                               (const struct sockaddr *) &ac->authority_info.dns_authority.dns_ip,
915                                               sa_len,
916                                               dns_request,
917                                               dns_request_length,
918                                               &dns_result_parser,
919                                               rh);
920     rh->task_id = GNUNET_SCHEDULER_add_delayed (DNS_LOOKUP_TIMEOUT,
921                                                 &fail_resolution,
922                                                 rh);
923   }
924   GNUNET_free (dns_request);
925   GNUNET_DNSPARSER_free_packet (p);
926 }
927
928
929 /**
930  * We encountered a CNAME record during our resolution.
931  * Merge it into our chain.
932  *
933  * @param rh resolution we are performing
934  * @param cname value of the cname record we got for the current 
935  *        authority chain tail
936  */
937 static void
938 handle_gns_cname_result (struct GNS_ResolverHandle *rh,
939                          const char *cname)
940 {
941   size_t nlen;
942   char *res;
943
944   nlen = strlen (cname);
945   if ( (nlen > 2) &&
946        (0 == strcmp (".+",
947                      &cname[nlen - 2])) )
948   {
949     /* CNAME resolution continues relative to current domain */
950     if (0 == rh->name_resolution_pos)
951     {
952       res = GNUNET_strndup (cname, nlen - 2);
953       rh->name_resolution_pos = nlen - 2;
954     }
955     else
956     {
957       GNUNET_asprintf (&res,
958                        "%.*s.%.*s",
959                        (int) rh->name_resolution_pos,
960                        rh->name,
961                        (int) (nlen - 2),
962                        cname);
963       rh->name_resolution_pos = strlen (res);
964     }
965     GNUNET_free (rh->name);
966     rh->name = res;
967     rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
968                                             rh);
969     return;
970   }
971   /* name is absolute, start from the beginning */
972   GNUNET_free (rh->name);
973   rh->name = GNUNET_strdup (cname);
974   start_resolver_lookup (rh);
975 }
976
977
978 /**
979  * Process a records that were decrypted from a block.
980  *
981  * @param cls closure with the 'struct GNS_ResolverHandle'
982  * @param rd_count number of entries in @a rd array
983  * @param rd array of records with data to store
984  */
985 static void
986 handle_gns_resolution_result (void *cls,
987                               unsigned int rd_count,
988                               const struct GNUNET_NAMESTORE_RecordData *rd);
989
990
991 /**
992  * Callback invoked from the VPN service once a redirection is
993  * available.  Provides the IP address that can now be used to
994  * reach the requested destination.  Replaces the "VPN" record
995  * with the respective A/AAAA record and continues processing.
996  *
997  * @param cls closure
998  * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error;
999  *                will match 'result_af' from the request
1000  * @param address IP address (struct in_addr or struct in_addr6, depending on 'af')
1001  *                that the VPN allocated for the redirection;
1002  *                traffic to this IP will now be redirected to the 
1003  *                specified target peer; NULL on error
1004  */
1005 static void
1006 vpn_allocation_cb (void *cls,
1007                    int af,
1008                    const void *address)
1009 {
1010   struct VpnContext *vpn_ctx = cls;
1011   struct GNS_ResolverHandle *rh = vpn_ctx->rh;
1012   struct GNUNET_NAMESTORE_RecordData rd[vpn_ctx->rd_count];
1013   unsigned int i;
1014
1015   vpn_ctx->vpn_request = NULL;
1016   rh->vpn_ctx = NULL;
1017   GNUNET_assert (GNUNET_OK ==
1018                  GNUNET_NAMESTORE_records_deserialize (vpn_ctx->rd_data_size,
1019                                                        vpn_ctx->rd_data,
1020                                                        vpn_ctx->rd_count,
1021                                                        rd));
1022   for (i=0;i<vpn_ctx->rd_count;i++)
1023   {
1024     if (GNUNET_NAMESTORE_TYPE_VPN == rd[i].record_type)
1025     {
1026       switch (af)
1027       {
1028       case AF_INET: 
1029         rd[i].record_type = GNUNET_DNSPARSER_TYPE_A;
1030         rd[i].data_size = sizeof (struct in_addr);
1031         rd[i].expiration_time = GNUNET_TIME_relative_to_absolute (VPN_TIMEOUT).abs_value_us;
1032         rd[i].flags = 0;
1033         rd[i].data = address;
1034         break;
1035       case AF_INET6:
1036         rd[i].record_type = GNUNET_DNSPARSER_TYPE_AAAA;
1037         rd[i].expiration_time = GNUNET_TIME_relative_to_absolute (VPN_TIMEOUT).abs_value_us;
1038         rd[i].flags = 0;
1039         rd[i].data = address;
1040         rd[i].data_size = sizeof (struct in6_addr);
1041         break;
1042       default:
1043         GNUNET_assert (0);
1044       }     
1045       break;
1046     }
1047   }
1048   GNUNET_assert (i < vpn_ctx->rd_count);
1049   handle_gns_resolution_result (rh, 
1050                                 vpn_ctx->rd_count,
1051                                 rd);
1052   GNUNET_free (vpn_ctx->rd_data);
1053   GNUNET_free (vpn_ctx);
1054 }
1055
1056
1057 /**
1058  * Process a records that were decrypted from a block.
1059  *
1060  * @param cls closure with the 'struct GNS_ResolverHandle'
1061  * @param rd_count number of entries in @a rd array
1062  * @param rd array of records with data to store
1063  */
1064 static void
1065 handle_gns_resolution_result (void *cls,
1066                               unsigned int rd_count,
1067                               const struct GNUNET_NAMESTORE_RecordData *rd)
1068 {
1069   struct GNS_ResolverHandle *rh = cls;
1070   struct AuthorityChain *ac;
1071   unsigned int i;
1072   unsigned int j;
1073   struct sockaddr *sa;
1074   struct sockaddr_in v4;
1075   struct sockaddr_in6 v6;
1076   size_t sa_len;
1077   char *cname;
1078   struct VpnContext *vpn_ctx;
1079   const struct GNUNET_TUN_GnsVpnRecord *vpn;
1080   const char *vname;
1081   struct GNUNET_HashCode vhash;
1082   int af;
1083   char scratch[UINT16_MAX];
1084   size_t scratch_off;
1085   size_t scratch_start;
1086   size_t off;
1087   struct GNUNET_NAMESTORE_RecordData rd_new[rd_count];
1088   unsigned int rd_off;
1089   
1090   if (0 == rh->name_resolution_pos)
1091   {
1092     /* top-level match, are we done yet? */
1093     if ( (rd_count > 0) &&
1094          (GNUNET_DNSPARSER_TYPE_CNAME == rd[0].record_type) &&
1095          (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type) )
1096     {
1097       cname = GNUNET_strndup (rd[0].data,
1098                               rd[0].data_size);
1099       handle_gns_cname_result (rh, 
1100                                cname);
1101       GNUNET_free (cname);
1102       return;     
1103     }
1104     /* If A/AAAA was requested, but we got a VPN
1105        record, we convert it to A/AAAA using GNUnet VPN */
1106     if ( (GNUNET_DNSPARSER_TYPE_A == rh->record_type) ||
1107          (GNUNET_DNSPARSER_TYPE_AAAA == rh->record_type) )
1108     {
1109       for (i=0;i<rd_count;i++)
1110       {
1111         if (GNUNET_NAMESTORE_TYPE_VPN == rd[i].record_type)
1112         {
1113           af = (GNUNET_DNSPARSER_TYPE_A == rh->record_type) ? AF_INET : AF_INET6;
1114           if (sizeof (struct GNUNET_TUN_GnsVpnRecord) <
1115               rd[i].data_size)
1116           {
1117             GNUNET_break_op (0);
1118             rh->proc (rh->proc_cls, 0, NULL);
1119             GNS_resolver_lookup_cancel (rh);
1120             return;         
1121           }
1122           vpn = (const struct GNUNET_TUN_GnsVpnRecord *) rd[i].data;
1123           vname = (const char *) &vpn[1];
1124           if ('\0' != vname[rd[i].data_size - 1 - sizeof (struct GNUNET_TUN_GnsVpnRecord)])
1125           {
1126             GNUNET_break_op (0);
1127             rh->proc (rh->proc_cls, 0, NULL);
1128             GNS_resolver_lookup_cancel (rh);
1129             return;
1130           }
1131           GNUNET_CRYPTO_hash (vname,
1132                               strlen (vname), // FIXME: +1?
1133                               &vhash);
1134           vpn_ctx = GNUNET_new (struct VpnContext);
1135           rh->vpn_ctx = vpn_ctx;
1136           vpn_ctx->rh = rh;
1137           vpn_ctx->rd_data_size = GNUNET_NAMESTORE_records_get_size (rd_count,
1138                                                                      rd);
1139           vpn_ctx->rd_data = GNUNET_malloc (vpn_ctx->rd_data_size);
1140           (void) GNUNET_NAMESTORE_records_serialize (rd_count,
1141                                                      rd,
1142                                                      vpn_ctx->rd_data_size,
1143                                                      vpn_ctx->rd_data);
1144           vpn_ctx->vpn_request = GNUNET_VPN_redirect_to_peer (vpn_handle,
1145                                                               af,
1146                                                               ntohs (vpn->proto),
1147                                                               &vpn->peer,
1148                                                               &vhash,
1149                                                               GNUNET_NO,
1150                                                               GNUNET_TIME_relative_to_absolute (VPN_TIMEOUT),
1151                                                               &vpn_allocation_cb,
1152                                                               rh);
1153           return;
1154         }
1155       }
1156     }
1157     /* convert relative names in record values to absolute names,
1158        using 'scratch' array for memory allocations */
1159     scratch_off = 0;
1160     rd_off = 0;
1161     for (i=0;i<rd_count;i++)
1162     {
1163       rd_new[rd_off] = rd[i];
1164       /* Check if the embedded name(s) end in "+", and if so,
1165          replace the "+" with the zone at "ac_tail", changing the name
1166          to a ".zkey".  The name is allocated on the 'scratch' array,
1167          so we can free it afterwards. */
1168       switch (rd[i].record_type)
1169       {
1170       case GNUNET_DNSPARSER_TYPE_CNAME:
1171         {
1172           char *cname;
1173
1174           off = 0;
1175           cname = GNUNET_DNSPARSER_parse_name (rd[i].data,
1176                                                rd[i].data_size,
1177                                                &off);
1178           if ( (NULL == cname) ||
1179                (off != rd[i].data_size) )
1180           {
1181             GNUNET_break_op (0); /* record not well-formed */
1182           }
1183           else
1184           {
1185             cname = translate_dot_plus (rh, cname);
1186             scratch_start = scratch_off;
1187             if (GNUNET_OK !=
1188                 GNUNET_DNSPARSER_builder_add_name (scratch,
1189                                                    sizeof (scratch),
1190                                                    &scratch_off,
1191                                                    cname))
1192             {
1193               GNUNET_break (0);
1194             }
1195             else
1196             {
1197               rd_new[rd_off].data = &scratch[scratch_start];
1198               rd_new[rd_off].data_size = scratch_off - scratch_start;
1199               rd_off++;
1200             }
1201           }
1202           GNUNET_free_non_null (cname);   
1203         }
1204         break;
1205       case GNUNET_DNSPARSER_TYPE_SOA:
1206         {
1207           struct GNUNET_DNSPARSER_SoaRecord *soa;
1208
1209           off = 0;
1210           soa = GNUNET_DNSPARSER_parse_soa (rd[i].data,
1211                                             rd[i].data_size,
1212                                             &off);
1213           if ( (NULL == soa) ||
1214                (off != rd[i].data_size) )
1215           {
1216             GNUNET_break_op (0); /* record not well-formed */
1217           }
1218           else
1219           {
1220             soa->mname = translate_dot_plus (rh, soa->mname);
1221             soa->rname = translate_dot_plus (rh, soa->rname);
1222             scratch_start = scratch_off;
1223             if (GNUNET_OK !=
1224                 GNUNET_DNSPARSER_builder_add_soa (scratch,
1225                                                   sizeof (scratch),
1226                                                   &scratch_off,
1227                                                   soa))
1228             {
1229               GNUNET_break (0);
1230             }
1231             else
1232             {
1233               rd_new[rd_off].data = &scratch[scratch_start];
1234               rd_new[rd_off].data_size = scratch_off - scratch_start;
1235               rd_off++;
1236             }
1237           }
1238           if (NULL != soa)
1239             GNUNET_DNSPARSER_free_soa (soa);      
1240         }
1241         break;
1242       case GNUNET_DNSPARSER_TYPE_MX:
1243         {
1244           struct GNUNET_DNSPARSER_MxRecord *mx;
1245
1246           off = 0;
1247           mx = GNUNET_DNSPARSER_parse_mx (rd[i].data,
1248                                           rd[i].data_size,
1249                                           &off);
1250           if ( (NULL == mx) ||
1251                (off != rd[i].data_size) )
1252           {
1253             GNUNET_break_op (0); /* record not well-formed */
1254           }
1255           else
1256           {
1257             mx->mxhost = translate_dot_plus (rh, mx->mxhost);
1258             scratch_start = scratch_off;
1259             if (GNUNET_OK !=
1260                 GNUNET_DNSPARSER_builder_add_mx (scratch,
1261                                                  sizeof (scratch),
1262                                                  &scratch_off,
1263                                                  mx))
1264             {
1265               GNUNET_break (0);
1266             }
1267             else
1268             {
1269               rd_new[rd_off].data = &scratch[scratch_start];
1270               rd_new[rd_off].data_size = scratch_off - scratch_start;
1271               rd_off++;
1272             }
1273           }
1274           if (NULL != mx)
1275             GNUNET_DNSPARSER_free_mx (mx);        
1276         }       
1277         break;
1278       case GNUNET_DNSPARSER_TYPE_SRV:
1279         {
1280           struct GNUNET_DNSPARSER_SrvRecord *srv;
1281
1282           off = 0;
1283           /* FIXME: passing rh->name here is is not necessarily what we want 
1284              (SRV support not finished) */
1285           srv = GNUNET_DNSPARSER_parse_srv (rh->name,
1286                                             rd[i].data,
1287                                             rd[i].data_size,
1288                                             &off);
1289           if ( (NULL == srv) ||
1290                (off != rd[i].data_size) )
1291           {
1292             GNUNET_break_op (0); /* record not well-formed */
1293           }
1294           else
1295           {
1296             srv->domain_name = translate_dot_plus (rh, srv->domain_name);
1297             srv->target = translate_dot_plus (rh, srv->target);
1298             scratch_start = scratch_off;
1299             if (GNUNET_OK !=
1300                 GNUNET_DNSPARSER_builder_add_srv (scratch,
1301                                                   sizeof (scratch),
1302                                                   &scratch_off,
1303                                                   srv))
1304             {
1305               GNUNET_break (0);
1306             }
1307             else
1308             {
1309               rd_new[rd_off].data = &scratch[scratch_start];
1310               rd_new[rd_off].data_size = scratch_off - scratch_start;
1311               rd_off++;
1312             }
1313           }
1314           if (NULL != srv)
1315             GNUNET_DNSPARSER_free_srv (srv);      
1316         }
1317         break;
1318       case GNUNET_NAMESTORE_TYPE_PKEY:
1319         /* tigger shortening */
1320         if (NULL != rh->shorten_key)
1321         {
1322           struct GNUNET_CRYPTO_EccPublicSignKey pub;
1323           
1324           if (rd[i].data_size != sizeof (struct GNUNET_CRYPTO_EccPublicSignKey))
1325           {
1326             GNUNET_break_op (0);
1327             break;
1328           }
1329           memcpy (&pub, rd[i].data, rd[i].data_size);
1330           GNS_shorten_start (rh->ac_tail->label,
1331                              &pub,
1332                              rh->shorten_key);
1333         }
1334       default:
1335         break;
1336       }
1337     }
1338     
1339     /* yes, we are done, return result */
1340     rh->proc (rh->proc_cls, rd_off, rd_new);
1341     GNS_resolver_lookup_cancel (rh);
1342     return;         
1343   }
1344   /* need to recurse, check if we can */
1345   for (i=0;i<rd_count;i++)
1346   {
1347     switch (rd[i].record_type)
1348     {
1349     case GNUNET_NAMESTORE_TYPE_PKEY:
1350       /* delegation to another zone */
1351       if (sizeof (struct GNUNET_CRYPTO_EccPublicSignKey) !=
1352           rd[i].data_size)
1353       {
1354         GNUNET_break_op (0);
1355         rh->proc (rh->proc_cls, 0, NULL);
1356         GNS_resolver_lookup_cancel (rh);
1357         return;     
1358       }
1359       /* expand authority chain */
1360       ac = GNUNET_new (struct AuthorityChain);
1361       ac->rh = rh;
1362       ac->gns_authority = GNUNET_YES;
1363       memcpy (&ac->authority_info.gns_authority,
1364               rd[i].data,
1365               sizeof (struct GNUNET_CRYPTO_EccPublicSignKey));
1366       ac->label = resolver_lookup_get_next_label (rh);
1367       /* tigger shortening */
1368       if (NULL != rh->shorten_key)      
1369         GNS_shorten_start (rh->ac_tail->label,
1370                            &ac->authority_info.gns_authority,
1371                            rh->shorten_key);      
1372       /* add AC to tail */
1373       GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1374                                         rh->ac_tail,
1375                                         ac);
1376       /* recurse */
1377       rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1378                                               rh);
1379       break;
1380     case GNUNET_DNSPARSER_TYPE_NS:
1381       /* resolution continues within DNS */
1382       if (GNUNET_DNSPARSER_MAX_NAME_LENGTH < 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       /* find associated A/AAAA record */
1390       sa = NULL;
1391       sa_len = 0;
1392       for (j=0;j<rd_count;j++)
1393       {
1394         switch (rd[j].record_type)
1395         {
1396         case GNUNET_DNSPARSER_TYPE_A:
1397           if (sizeof (struct in_addr) != rd[i].data_size)
1398           {
1399             GNUNET_break_op (0);
1400             rh->proc (rh->proc_cls, 0, NULL);
1401             GNS_resolver_lookup_cancel (rh);
1402             return;     
1403           }
1404           /* FIXME: might want to check if we support IPv4 here,
1405              and otherwise skip this one and hope we find another */
1406           memset (&v4, 0, sizeof (v4));
1407           sa_len = sizeof (v4);
1408           v4.sin_family = AF_INET;
1409           v4.sin_port = htons (53);
1410 #if HAVE_SOCKADDR_IN_SIN_LEN
1411           v4.sin_len = (u_char) sa_len;
1412 #endif
1413           memcpy (&v4.sin_addr,
1414                   rd[j].data,
1415                   sizeof (struct in_addr));
1416           sa = (struct sockaddr *) &v4;
1417           break;
1418         case GNUNET_DNSPARSER_TYPE_AAAA:
1419           if (sizeof (struct in6_addr) != rd[i].data_size)
1420           {
1421             GNUNET_break_op (0);
1422             rh->proc (rh->proc_cls, 0, NULL);
1423             GNS_resolver_lookup_cancel (rh);
1424             return;     
1425           }
1426           /* FIXME: might want to check if we support IPv6 here,
1427              and otherwise skip this one and hope we find another */
1428           memset (&v6, 0, sizeof (v6));
1429           sa_len = sizeof (v6);
1430           v6.sin6_family = AF_INET6;
1431           v6.sin6_port = htons (53);
1432 #if HAVE_SOCKADDR_IN_SIN_LEN
1433           v6.sin6_len = (u_char) sa_len;
1434 #endif
1435           memcpy (&v6.sin6_addr,
1436                   rd[j].data,
1437                   sizeof (struct in6_addr));
1438           sa = (struct sockaddr *) &v6;
1439           break;
1440         default:
1441           break;
1442         }
1443         if (NULL != sa)
1444           break;
1445       }
1446       if (NULL == sa)
1447       {
1448         /* we cannot continue; NS without A/AAAA */
1449         rh->proc (rh->proc_cls, 0, NULL);
1450         GNS_resolver_lookup_cancel (rh);
1451         return;
1452       }
1453       /* expand authority chain */
1454       ac = GNUNET_new (struct AuthorityChain);
1455       ac->rh = rh;
1456       strncpy (ac->authority_info.dns_authority.name,
1457                rd[i].data,
1458                rd[i].data_size);
1459       ac->authority_info.dns_authority.name[rd[i].data_size] = '\0';
1460       memcpy (&ac->authority_info.dns_authority.dns_ip,
1461               sa,
1462               sa_len);
1463       /* for DNS recursion, the label is the full DNS name,
1464          created from the remainder of the GNS name and the
1465          name in the NS record */
1466       GNUNET_asprintf (&ac->label,
1467                        "%.*s%s",
1468                        (int) rh->name_resolution_pos,
1469                        rh->name,
1470                        ac->authority_info.dns_authority.name);
1471       GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1472                                         rh->ac_tail,
1473                                         ac);
1474       if (strlen (ac->label) > GNUNET_DNSPARSER_MAX_NAME_LENGTH)
1475       {
1476         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1477                     _("GNS lookup resulted in DNS name that is too long (`%s')\n"),
1478                     ac->label);
1479         rh->proc (rh->proc_cls, 0, NULL);
1480         GNS_resolver_lookup_cancel (rh);
1481         return;
1482       }
1483       /* recurse */
1484       rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1485                                               rh);
1486       return;
1487     case GNUNET_DNSPARSER_TYPE_CNAME:
1488       cname = GNUNET_strndup (rd[i].data,
1489                               rd[i].data_size);
1490       handle_gns_cname_result (rh, 
1491                                cname);
1492       GNUNET_free (cname);
1493       return;
1494       /* FIXME: handle DNAME */
1495     default:
1496       /* skip */
1497       break;
1498     }
1499   }
1500   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1501               _("GNS lookup recursion failed (no delegation record found)\n"));
1502   rh->proc (rh->proc_cls, 0, NULL);
1503   GNS_resolver_lookup_cancel (rh);
1504 }
1505
1506
1507 /**
1508  * Function called once the namestore has completed the request for
1509  * caching a block.
1510  *
1511  * @param cls closure with the 'struct GNS_ResolverHandle'
1512  * @param success #GNUNET_OK on success
1513  * @param emsg error message
1514  */
1515 static void
1516 namestore_cache_continuation (void *cls,
1517                               int32_t success,
1518                               const char *emsg)
1519 {
1520   struct GNS_ResolverHandle *rh = cls;
1521
1522   rh->namestore_qe = NULL;
1523   if (NULL != emsg)
1524     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1525                 _("Failed to cache GNS resolution: %s\n"),
1526                 emsg);
1527 }
1528
1529
1530 /**
1531  * Iterator called on each result obtained for a DHT
1532  * operation that expects a reply
1533  *
1534  * @param cls closure with the 'struct GNS_ResolverHandle'
1535  * @param exp when will this value expire
1536  * @param key key of the result
1537  * @param get_path peers on reply path (or NULL if not recorded)
1538  *                 [0] = datastore's first neighbor, [length - 1] = local peer
1539  * @param get_path_length number of entries in get_path
1540  * @param put_path peers on the PUT path (or NULL if not recorded)
1541  *                 [0] = origin, [length - 1] = datastore
1542  * @param put_path_length number of entries in get_path
1543  * @param type type of the result
1544  * @param size number of bytes in data
1545  * @param data pointer to the result data
1546  */
1547 static void
1548 handle_dht_response (void *cls,
1549                      struct GNUNET_TIME_Absolute exp,
1550                      const struct GNUNET_HashCode * key,
1551                      const struct GNUNET_PeerIdentity *get_path,
1552                      unsigned int get_path_length,
1553                      const struct GNUNET_PeerIdentity *put_path, 
1554                      unsigned int put_path_length,
1555                      enum GNUNET_BLOCK_Type type,
1556                      size_t size, const void *data)
1557 {
1558   struct GNS_ResolverHandle *rh = cls;
1559   struct AuthorityChain *ac = rh->ac_tail;
1560   const struct GNUNET_NAMESTORE_Block *block;
1561   
1562   GNUNET_DHT_get_stop (rh->get_handle);
1563   rh->get_handle = NULL;
1564   GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
1565   rh->dht_heap_node = NULL;  
1566   if (size < sizeof (struct GNUNET_NAMESTORE_Block))
1567   {
1568     /* how did this pass DHT block validation!? */
1569     GNUNET_break (0);
1570     rh->proc (rh->proc_cls, 0, NULL);
1571     GNS_resolver_lookup_cancel (rh);
1572     return;   
1573   }
1574   block = data; 
1575   if (size !=
1576       ntohs (block->purpose.size) + 
1577       sizeof (struct GNUNET_CRYPTO_EccPublicSignKey) +
1578       sizeof (struct GNUNET_CRYPTO_EccSignature))
1579   {
1580     /* how did this pass DHT block validation!? */
1581     GNUNET_break (0);
1582     rh->proc (rh->proc_cls, 0, NULL);
1583     GNS_resolver_lookup_cancel (rh);
1584     return;   
1585   }
1586   if (GNUNET_OK !=
1587       GNUNET_NAMESTORE_block_decrypt (block,
1588                                       &ac->authority_info.gns_authority,
1589                                       ac->label,
1590                                       &handle_gns_resolution_result,
1591                                       rh))
1592   {
1593     GNUNET_break_op (0); /* block was ill-formed */
1594     rh->proc (rh->proc_cls, 0, NULL);
1595     GNS_resolver_lookup_cancel (rh);
1596     return;
1597   }
1598   /* Cache well-formed blocks */
1599   rh->namestore_qe = GNUNET_NAMESTORE_block_cache (namestore_handle,
1600                                                    block,
1601                                                    &namestore_cache_continuation,
1602                                                    rh);
1603 }
1604
1605
1606 /**
1607  * Process a record that was stored in the namestore.
1608  *
1609  * @param cls closure with the `struct GNS_ResolverHandle`
1610  * @param block block that was stored in the namestore
1611  */
1612 static void 
1613 handle_namestore_block_response (void *cls,
1614                                  const struct GNUNET_NAMESTORE_Block *block)
1615 {
1616   struct GNS_ResolverHandle *rh = cls;
1617   struct GNS_ResolverHandle *rx;
1618   struct AuthorityChain *ac = rh->ac_tail;
1619   const char *label = ac->label;
1620   const struct GNUNET_CRYPTO_EccPublicSignKey *auth = &ac->authority_info.gns_authority;
1621   struct GNUNET_HashCode query;
1622
1623   GNUNET_NAMESTORE_query_from_public_key (auth,
1624                                           label,
1625                                           &query);
1626   rh->namestore_qe = NULL;
1627   if ( (GNUNET_NO == rh->only_cached) &&
1628        ( (NULL == block) ||
1629          (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (block->expiration_time)).rel_value_us) ) )
1630   {
1631     /* Namestore knows nothing; try DHT lookup */
1632     rh->get_handle = GNUNET_DHT_get_start (dht_handle,
1633                                            GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1634                                            &query,
1635                                            DHT_GNS_REPLICATION_LEVEL,
1636                                            GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
1637                                            NULL, 0,
1638                                            &handle_dht_response, rh);
1639     rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
1640                                                       rh,
1641                                                       GNUNET_TIME_absolute_get ().abs_value_us);
1642     if (GNUNET_CONTAINER_heap_get_size (dht_lookup_heap) > max_allowed_background_queries)
1643     {
1644       /* fail longest-standing DHT request */
1645       rx = GNUNET_CONTAINER_heap_peek (dht_lookup_heap);
1646       GNUNET_assert (NULL != rx);
1647       rx->proc (rx->proc_cls, 0, NULL);
1648       GNS_resolver_lookup_cancel (rx);
1649     }
1650     return;
1651   }
1652   if ( (NULL == block) ||
1653        (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (block->expiration_time)).rel_value_us) )
1654   {
1655     /* DHT not permitted and no local result, fail */
1656     rh->proc (rh->proc_cls, 0, NULL);
1657     GNS_resolver_lookup_cancel (rh);
1658     return;
1659   }
1660   if (GNUNET_OK !=
1661       GNUNET_NAMESTORE_block_decrypt (block,
1662                                       auth,
1663                                       label,
1664                                       &handle_gns_resolution_result,
1665                                       rh))
1666   {
1667     GNUNET_break_op (0); /* block was ill-formed */
1668     rh->proc (rh->proc_cls, 0, NULL);
1669     GNS_resolver_lookup_cancel (rh);
1670     return;
1671   }
1672 }
1673
1674
1675 /**
1676  * Lookup tail of our authority chain in the namestore.
1677  *
1678  * @param rh query we are processing
1679  */
1680 static void
1681 recursive_gns_resolution_namestore (struct GNS_ResolverHandle *rh)
1682 {
1683   struct AuthorityChain *ac = rh->ac_tail;
1684   struct GNUNET_HashCode query;
1685
1686   GNUNET_NAMESTORE_query_from_public_key (&ac->authority_info.gns_authority,
1687                                           ac->label,
1688                                           &query);
1689   rh->namestore_qe = GNUNET_NAMESTORE_lookup_block (namestore_handle,
1690                                                     &query,
1691                                                     &handle_namestore_block_response,
1692                                                     rh);
1693 }
1694
1695
1696 /**
1697  * Task scheduled to continue with the resolution process.
1698  *
1699  * @param cls the `struct GNS_ResolverHandle` of the resolution
1700  * @param tc task context
1701  */
1702 static void
1703 recursive_resolution (void *cls,
1704                       const struct GNUNET_SCHEDULER_TaskContext *tc)
1705 {
1706   struct GNS_ResolverHandle *rh = cls;
1707
1708   rh->task_id = GNUNET_SCHEDULER_NO_TASK;
1709   if (MAX_RECURSION < rh->loop_limiter++)
1710   {
1711     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1712                 "Encountered unbounded recursion resolving `%s'\n",
1713                 rh->name);
1714     rh->proc (rh->proc_cls, 0, NULL);
1715     GNS_resolver_lookup_cancel (rh);
1716     return;
1717   }
1718   if (GNUNET_YES == rh->ac_tail->gns_authority)
1719     recursive_gns_resolution_namestore (rh);
1720   else
1721     recursive_dns_resolution (rh);
1722 }
1723
1724
1725 /**
1726  * Begin the resolution process from 'name', starting with
1727  * the identification of the zone specified by 'name'.
1728  *
1729  * @param rh resolution to perform
1730  */
1731 static void
1732 start_resolver_lookup (struct GNS_ResolverHandle *rh)
1733 {
1734   struct AuthorityChain *ac;
1735   char *x;
1736   char *y;
1737   char *pkey;
1738
1739   if ( ( (GNUNET_YES == is_canonical (rh->name)) &&
1740          (0 != strcmp (GNUNET_GNS_TLD, rh->name)) ) ||
1741        ( (GNUNET_YES != is_gnu_tld (rh->name)) &&
1742          (GNUNET_YES != is_zkey_tld (rh->name)) ) )
1743   {
1744     /* use standard DNS lookup */
1745     int af;
1746
1747     switch (rh->record_type)
1748     {
1749     case GNUNET_DNSPARSER_TYPE_A:
1750       af = AF_INET;
1751       break;
1752     case GNUNET_DNSPARSER_TYPE_AAAA:
1753       af = AF_INET6;
1754       break;
1755     default:
1756       af = AF_UNSPEC;
1757       break;
1758     }
1759     rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name, 
1760                                               af,
1761                                               DNS_LOOKUP_TIMEOUT,
1762                                               &handle_dns_result,
1763                                               rh);
1764     return;
1765   }
1766   if (is_zkey_tld (rh->name))
1767   {
1768     /* Name ends with ".zkey", try to replace authority zone with zkey
1769        authority */
1770     GNUNET_free (resolver_lookup_get_next_label (rh)); /* will return "zkey" */
1771     x = resolver_lookup_get_next_label (rh); /* will return 'x' coordinate */
1772     y = resolver_lookup_get_next_label (rh); /* will return 'y' coordinate */
1773     GNUNET_asprintf (&pkey,
1774                      "%s%s",
1775                      x, y);
1776     if ( (NULL == x) ||
1777          (NULL == y) ||
1778          (GNUNET_OK !=
1779           GNUNET_CRYPTO_ecc_public_sign_key_from_string (pkey,
1780                                                     strlen (pkey),
1781                                                     &rh->authority_zone)) )
1782     {
1783       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1784                   _("Hostname `%s' is not well-formed, resolution fails\n"),
1785                   rh->name);
1786       rh->task_id = GNUNET_SCHEDULER_add_now (&fail_resolution, rh);
1787     }
1788     GNUNET_free_non_null (x);
1789     GNUNET_free_non_null (y);
1790     GNUNET_free (pkey);
1791   }
1792   else
1793   {
1794     /* Name ends with ".gnu", eat ".gnu" and continue with resolution */
1795     GNUNET_free (resolver_lookup_get_next_label (rh));
1796   }
1797   ac = GNUNET_new (struct AuthorityChain);
1798   ac->rh = rh;
1799   ac->label = resolver_lookup_get_next_label (rh);
1800   if (NULL == ac->label)
1801     /* name was just "gnu", so we default to label '+' */
1802     ac->label = GNUNET_strdup (GNUNET_GNS_MASTERZONE_STR);
1803   ac->gns_authority = GNUNET_YES;
1804   ac->authority_info.gns_authority = rh->authority_zone;
1805   GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1806                                     rh->ac_tail,
1807                                     ac);
1808   rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1809                                           rh);
1810 }
1811
1812
1813 /**
1814  * Lookup of a record in a specific zone calls lookup result processor
1815  * on result.
1816  *
1817  * @param zone the zone to perform the lookup in
1818  * @param record_type the record type to look up
1819  * @param name the name to look up
1820  * @param shorten_key a private key for use with PSEU import (can be NULL)
1821  * @param only_cached #GNUNET_NO to only check locally not DHT for performance
1822  * @param proc the processor to call on result
1823  * @param proc_cls the closure to pass to @a proc
1824  * @return handle to cancel operation
1825  */
1826 struct GNS_ResolverHandle *
1827 GNS_resolver_lookup (const struct GNUNET_CRYPTO_EccPublicSignKey *zone,
1828                      uint32_t record_type,
1829                      const char *name,
1830                      const struct GNUNET_CRYPTO_EccPrivateKey *shorten_key,
1831                      int only_cached,
1832                      GNS_ResultProcessor proc, void *proc_cls)
1833 {
1834   struct GNS_ResolverHandle *rh;
1835
1836   rh = GNUNET_new (struct GNS_ResolverHandle);
1837   GNUNET_CONTAINER_DLL_insert (rlh_head,
1838                                rlh_tail,
1839                                rh);
1840   rh->authority_zone = *zone;
1841   rh->proc = proc;
1842   rh->proc_cls = proc_cls;
1843   rh->only_cached = only_cached;
1844   rh->record_type = record_type;
1845   rh->name = GNUNET_strdup (name);
1846   rh->name_resolution_pos = strlen (name);
1847   if (NULL != shorten_key)
1848   {
1849     rh->shorten_key = GNUNET_new (struct GNUNET_CRYPTO_EccPrivateKey);
1850     *rh->shorten_key = *shorten_key;
1851   }
1852   start_resolver_lookup (rh);
1853   return rh;
1854 }
1855
1856
1857 /**
1858  * Cancel active resolution (i.e. client disconnected).
1859  *
1860  * @param rh resolution to abort
1861  */
1862 void
1863 GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
1864 {
1865   struct DnsResult *dr;
1866   struct AuthorityChain *ac;
1867   struct VpnContext *vpn_ctx;
1868
1869   GNUNET_CONTAINER_DLL_remove (rlh_head,
1870                                rlh_tail,
1871                                rh);
1872   while (NULL != (ac = rh->ac_head))
1873   {
1874     GNUNET_CONTAINER_DLL_remove (rh->ac_head,
1875                                  rh->ac_tail,
1876                                  ac);
1877     GNUNET_free (ac->label);
1878     GNUNET_free (ac);
1879   }
1880   if (GNUNET_SCHEDULER_NO_TASK != rh->task_id)
1881   {
1882     GNUNET_SCHEDULER_cancel (rh->task_id);
1883     rh->task_id = GNUNET_SCHEDULER_NO_TASK;
1884   }
1885   if (NULL != rh->get_handle)
1886   {
1887     GNUNET_DHT_get_stop (rh->get_handle);
1888     rh->get_handle = NULL;
1889   }
1890   if (NULL != rh->dht_heap_node)
1891   {
1892     GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
1893     rh->dht_heap_node = NULL;
1894   }
1895   if (NULL != (vpn_ctx = rh->vpn_ctx))
1896   {
1897     GNUNET_VPN_cancel_request (vpn_ctx->vpn_request);
1898     GNUNET_free (vpn_ctx->rd_data);
1899     GNUNET_free (vpn_ctx);
1900   }
1901   if (NULL != rh->dns_request)
1902   {
1903     GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
1904     rh->dns_request = NULL;
1905   }
1906   if (NULL != rh->namestore_qe)
1907   {
1908     GNUNET_NAMESTORE_cancel (rh->namestore_qe);
1909     rh->namestore_qe = NULL;
1910   }
1911   if (NULL != rh->std_resolve)
1912   {
1913     GNUNET_RESOLVER_request_cancel (rh->std_resolve);
1914     rh->std_resolve = NULL;
1915   }
1916   while (NULL != (dr = rh->dns_result_head))
1917   {
1918     GNUNET_CONTAINER_DLL_remove (rh->dns_result_head,
1919                                  rh->dns_result_tail,
1920                                  dr);
1921     GNUNET_free (dr);
1922   }
1923   GNUNET_free_non_null (rh->shorten_key);
1924   GNUNET_free (rh->name);
1925   GNUNET_free (rh);
1926 }
1927
1928
1929 /* ***************** Resolver initialization ********************* */
1930
1931
1932 /**
1933  * Initialize the resolver
1934  *
1935  * @param nh the namestore handle
1936  * @param dht the dht handle
1937  * @param c configuration handle
1938  * @param max_bg_queries maximum number of parallel background queries in dht
1939  */
1940 void
1941 GNS_resolver_init (struct GNUNET_NAMESTORE_Handle *nh,
1942                    struct GNUNET_DHT_Handle *dht,
1943                    const struct GNUNET_CONFIGURATION_Handle *c,
1944                    unsigned long long max_bg_queries)
1945 {
1946   char *dns_ip;
1947
1948   cfg = c;
1949   namestore_handle = nh;
1950   dht_handle = dht;
1951   dht_lookup_heap =
1952     GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1953   max_allowed_background_queries = max_bg_queries;
1954   if (GNUNET_OK !=
1955       GNUNET_CONFIGURATION_get_value_string (c,
1956                                              "gns",
1957                                              "DNS_RESOLVER",
1958                                              &dns_ip))
1959   {
1960     /* user did not specify DNS resolver, use 8.8.8.8 */
1961     dns_ip = GNUNET_strdup ("8.8.8.8");
1962   }
1963   dns_handle = GNUNET_DNSSTUB_start (dns_ip);
1964   GNUNET_free (dns_ip);
1965   vpn_handle = GNUNET_VPN_connect (cfg);
1966 }
1967
1968
1969 /**
1970  * Shutdown resolver
1971  */
1972 void
1973 GNS_resolver_done ()
1974 {
1975   struct GNS_ResolverHandle *rh;
1976
1977   /* abort active resolutions */
1978   while (NULL != (rh = rlh_head))
1979   {
1980     rh->proc (rh->proc_cls, 0, NULL);
1981     GNS_resolver_lookup_cancel (rh);    
1982   }
1983   GNUNET_CONTAINER_heap_destroy (dht_lookup_heap);
1984   dht_lookup_heap = NULL;
1985   GNUNET_DNSSTUB_stop (dns_handle);
1986   dns_handle = NULL;
1987   GNUNET_VPN_disconnect (vpn_handle);
1988   vpn_handle = NULL;
1989   dht_handle = NULL;
1990   namestore_handle = NULL;
1991 }
1992
1993
1994 /* *************** common helper functions (do not really belong here) *********** */
1995
1996 /**
1997  * Checks if @a name ends in ".TLD"
1998  *
1999  * @param name the name to check
2000  * @param tld the TLD to check for
2001  * @return GNUNET_YES or GNUNET_NO
2002  */
2003 int
2004 is_tld (const char* name, const char* tld)
2005 {
2006   size_t offset = 0;
2007
2008   if (strlen (name) <= strlen (tld))
2009     return GNUNET_NO;
2010   offset = strlen (name) - strlen (tld);
2011   if (0 != strcmp (name + offset, tld))
2012     return GNUNET_NO;
2013   return GNUNET_YES;
2014 }
2015
2016
2017 /* end of gnunet-service-gns_resolver.c */