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