4f4875a44144a4c0a36bcf947ae43b23b151b063
[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     rh->proc (rh->proc_cls, rd_count - skip, rd);
920     GNS_resolver_lookup_cancel (rh);
921   }
922   GNUNET_DNSPARSER_free_packet (p);
923 }
924
925
926 /**
927  * Perform recursive DNS resolution.  Asks the given DNS resolver to
928  * resolve "rh->dns_name", possibly recursively proceeding following
929  * NS delegations, CNAMES, etc., until 'rh->loop_limiter' bounds us or
930  * we find the answer.
931  *
932  * @param rh resolution information
933  */
934 static void
935 recursive_dns_resolution (struct GNS_ResolverHandle *rh)
936 {
937   struct AuthorityChain *ac;
938   socklen_t sa_len;
939   struct GNUNET_DNSPARSER_Query *query;
940   struct GNUNET_DNSPARSER_Packet *p;
941   char *dns_request;
942   size_t dns_request_length;
943
944   ac = rh->ac_tail;
945   GNUNET_assert (NULL != ac);
946   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
947               "Starting DNS lookup for `%s'\n",
948               ac->label);
949   GNUNET_assert (GNUNET_NO == ac->gns_authority);
950   switch (((const struct sockaddr *) &ac->authority_info.dns_authority.dns_ip)->sa_family)
951   {
952   case AF_INET:
953     sa_len = sizeof (struct sockaddr_in);
954     break;
955   case AF_INET6:
956     sa_len = sizeof (struct sockaddr_in6);
957     break;
958   default:
959     GNUNET_break (0);
960     rh->proc (rh->proc_cls, 0, NULL);
961     GNS_resolver_lookup_cancel (rh);
962     return;
963   }
964   query = GNUNET_new (struct GNUNET_DNSPARSER_Query);
965   query->name = GNUNET_strdup (ac->label);
966   query->type = rh->record_type;
967   query->dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
968   p = GNUNET_new (struct GNUNET_DNSPARSER_Packet);
969   p->queries = query;
970   p->num_queries = 1;
971   p->id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
972                                                UINT16_MAX);
973   p->flags.opcode = GNUNET_TUN_DNS_OPCODE_QUERY;
974   p->flags.recursion_desired = 1;
975   if (GNUNET_OK !=
976       GNUNET_DNSPARSER_pack (p, 1024, &dns_request, &dns_request_length))
977   {
978     GNUNET_break (0);
979     rh->proc (rh->proc_cls, 0, NULL);
980     GNS_resolver_lookup_cancel (rh);
981   }
982   else
983   {
984     rh->dns_request = GNUNET_DNSSTUB_resolve (dns_handle,
985                                               (const struct sockaddr *) &ac->authority_info.dns_authority.dns_ip,
986                                               sa_len,
987                                               dns_request,
988                                               dns_request_length,
989                                               &dns_result_parser,
990                                               rh);
991     rh->task_id = GNUNET_SCHEDULER_add_delayed (DNS_LOOKUP_TIMEOUT,
992                                                 &fail_resolution,
993                                                 rh);
994   }
995   GNUNET_free (dns_request);
996   GNUNET_DNSPARSER_free_packet (p);
997 }
998
999
1000 /**
1001  * We encountered a CNAME record during our resolution.
1002  * Merge it into our chain.
1003  *
1004  * @param rh resolution we are performing
1005  * @param cname value of the cname record we got for the current
1006  *        authority chain tail
1007  */
1008 static void
1009 handle_gns_cname_result (struct GNS_ResolverHandle *rh,
1010                          const char *cname)
1011 {
1012   size_t nlen;
1013   char *res;
1014   struct AuthorityChain *ac;
1015
1016   nlen = strlen (cname);
1017   if ( (nlen > 2) &&
1018        (0 == strcmp (".+",
1019                      &cname[nlen - 2])) )
1020   {
1021     /* CNAME resolution continues relative to current domain */
1022     if (0 == rh->name_resolution_pos)
1023     {
1024       res = GNUNET_strndup (cname, nlen - 2);
1025       rh->name_resolution_pos = nlen - 2;
1026     }
1027     else
1028     {
1029       GNUNET_asprintf (&res,
1030                        "%.*s.%.*s",
1031                        (int) rh->name_resolution_pos,
1032                        rh->name,
1033                        (int) (nlen - 2),
1034                        cname);
1035       rh->name_resolution_pos = strlen (res);
1036     }
1037     GNUNET_free (rh->name);
1038     rh->name = res;
1039     ac = GNUNET_new (struct AuthorityChain);
1040     ac->rh = rh;
1041     ac->gns_authority = GNUNET_YES;
1042     ac->authority_info.gns_authority = rh->ac_tail->authority_info.gns_authority;
1043     ac->label = resolver_lookup_get_next_label (rh);
1044     /* tigger shortening */
1045     if (NULL != rh->shorten_key)
1046       GNS_shorten_start (rh->ac_tail->label,
1047                          &ac->authority_info.gns_authority,
1048                          rh->shorten_key);
1049     /* add AC to tail */
1050     GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1051                                       rh->ac_tail,
1052                                       ac);
1053     rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1054                                             rh);
1055     return;
1056   }
1057   /* name is absolute, start from the beginning */
1058   GNUNET_free (rh->name);
1059   rh->name = GNUNET_strdup (cname);
1060   start_resolver_lookup (rh);
1061 }
1062
1063
1064 /**
1065  * Process a records that were decrypted from a block.
1066  *
1067  * @param cls closure with the 'struct GNS_ResolverHandle'
1068  * @param rd_count number of entries in @a rd array
1069  * @param rd array of records with data to store
1070  */
1071 static void
1072 handle_gns_resolution_result (void *cls,
1073                               unsigned int rd_count,
1074                               const struct GNUNET_GNSRECORD_Data *rd);
1075
1076
1077 /**
1078  * Callback invoked from the VPN service once a redirection is
1079  * available.  Provides the IP address that can now be used to
1080  * reach the requested destination.  Replaces the "VPN" record
1081  * with the respective A/AAAA record and continues processing.
1082  *
1083  * @param cls closure
1084  * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error;
1085  *                will match 'result_af' from the request
1086  * @param address IP address (struct in_addr or struct in_addr6, depending on 'af')
1087  *                that the VPN allocated for the redirection;
1088  *                traffic to this IP will now be redirected to the
1089  *                specified target peer; NULL on error
1090  */
1091 static void
1092 vpn_allocation_cb (void *cls,
1093                    int af,
1094                    const void *address)
1095 {
1096   struct VpnContext *vpn_ctx = cls;
1097   struct GNS_ResolverHandle *rh = vpn_ctx->rh;
1098   struct GNUNET_GNSRECORD_Data rd[vpn_ctx->rd_count];
1099   unsigned int i;
1100
1101   vpn_ctx->vpn_request = NULL;
1102   rh->vpn_ctx = NULL;
1103   GNUNET_assert (GNUNET_OK ==
1104                  GNUNET_GNSRECORD_records_deserialize (vpn_ctx->rd_data_size,
1105                                                        vpn_ctx->rd_data,
1106                                                        vpn_ctx->rd_count,
1107                                                        rd));
1108   for (i=0;i<vpn_ctx->rd_count;i++)
1109   {
1110     if (GNUNET_GNSRECORD_TYPE_VPN == rd[i].record_type)
1111     {
1112       switch (af)
1113       {
1114       case AF_INET:
1115         rd[i].record_type = GNUNET_DNSPARSER_TYPE_A;
1116         rd[i].data_size = sizeof (struct in_addr);
1117         rd[i].expiration_time = GNUNET_TIME_relative_to_absolute (VPN_TIMEOUT).abs_value_us;
1118         rd[i].flags = 0;
1119         rd[i].data = address;
1120         break;
1121       case AF_INET6:
1122         rd[i].record_type = GNUNET_DNSPARSER_TYPE_AAAA;
1123         rd[i].expiration_time = GNUNET_TIME_relative_to_absolute (VPN_TIMEOUT).abs_value_us;
1124         rd[i].flags = 0;
1125         rd[i].data = address;
1126         rd[i].data_size = sizeof (struct in6_addr);
1127         break;
1128       default:
1129         GNUNET_assert (0);
1130       }
1131       break;
1132     }
1133   }
1134   GNUNET_assert (i < vpn_ctx->rd_count);
1135   handle_gns_resolution_result (rh,
1136                                 vpn_ctx->rd_count,
1137                                 rd);
1138   GNUNET_free (vpn_ctx->rd_data);
1139   GNUNET_free (vpn_ctx);
1140 }
1141
1142
1143 /**
1144  * Process a records that were decrypted from a block.
1145  *
1146  * @param cls closure with the `struct GNS_ResolverHandle`
1147  * @param rd_count number of entries in @a rd array
1148  * @param rd array of records with data to store
1149  */
1150 static void
1151 handle_gns_resolution_result (void *cls,
1152                               unsigned int rd_count,
1153                               const struct GNUNET_GNSRECORD_Data *rd)
1154 {
1155   struct GNS_ResolverHandle *rh = cls;
1156   struct AuthorityChain *ac;
1157   unsigned int i;
1158   unsigned int j;
1159   struct sockaddr *sa;
1160   struct sockaddr_in v4;
1161   struct sockaddr_in6 v6;
1162   size_t sa_len;
1163   char *cname;
1164   struct VpnContext *vpn_ctx;
1165   const struct GNUNET_TUN_GnsVpnRecord *vpn;
1166   const char *vname;
1167   struct GNUNET_HashCode vhash;
1168   int af;
1169   char scratch[UINT16_MAX];
1170   size_t scratch_off;
1171   size_t scratch_start;
1172   size_t off;
1173   struct GNUNET_GNSRECORD_Data rd_new[rd_count];
1174   unsigned int rd_off;
1175
1176   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1177               "Resolution succeeded for `%s' in zone %s, got %u records\n",
1178               rh->ac_tail->label,
1179               GNUNET_GNSRECORD_z2s (&rh->ac_tail->authority_info.gns_authority),
1180               rd_count);
1181   if (0 == rh->name_resolution_pos)
1182   {
1183     /* top-level match, are we done yet? */
1184     if ( (rd_count > 0) &&
1185          (GNUNET_DNSPARSER_TYPE_CNAME == rd[0].record_type) &&
1186          (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type) )
1187     {
1188       off = 0;
1189       cname = GNUNET_DNSPARSER_parse_name (rd[0].data,
1190                                            rd[0].data_size,
1191                                            &off);
1192       if ( (NULL == cname) ||
1193            (off != rd[0].data_size) )
1194       {
1195         GNUNET_break_op (0);
1196         rh->proc (rh->proc_cls, 0, NULL);
1197         GNS_resolver_lookup_cancel (rh);
1198         GNUNET_free_non_null (cname);
1199         return;
1200       }
1201       handle_gns_cname_result (rh,
1202                                cname);
1203       GNUNET_free (cname);
1204       return;
1205     }
1206     /* If A/AAAA was requested, but we got a VPN
1207        record, we convert it to A/AAAA using GNUnet VPN */
1208     if ( (GNUNET_DNSPARSER_TYPE_A == rh->record_type) ||
1209          (GNUNET_DNSPARSER_TYPE_AAAA == rh->record_type) )
1210     {
1211       for (i=0;i<rd_count;i++)
1212       {
1213         switch (rd[i].record_type)
1214         {
1215         case GNUNET_GNSRECORD_TYPE_VPN:
1216           {
1217             af = (GNUNET_DNSPARSER_TYPE_A == rh->record_type) ? AF_INET : AF_INET6;
1218             if (sizeof (struct GNUNET_TUN_GnsVpnRecord) <
1219                 rd[i].data_size)
1220             {
1221               GNUNET_break_op (0);
1222               rh->proc (rh->proc_cls, 0, NULL);
1223               GNS_resolver_lookup_cancel (rh);
1224               return;
1225             }
1226             vpn = (const struct GNUNET_TUN_GnsVpnRecord *) rd[i].data;
1227             vname = (const char *) &vpn[1];
1228             if ('\0' != vname[rd[i].data_size - 1 - sizeof (struct GNUNET_TUN_GnsVpnRecord)])
1229             {
1230               GNUNET_break_op (0);
1231               rh->proc (rh->proc_cls, 0, NULL);
1232               GNS_resolver_lookup_cancel (rh);
1233               return;
1234             }
1235             GNUNET_CRYPTO_hash (vname,
1236                                 strlen (vname), // FIXME: +1?
1237                                 &vhash);
1238             vpn_ctx = GNUNET_new (struct VpnContext);
1239             rh->vpn_ctx = vpn_ctx;
1240             vpn_ctx->rh = rh;
1241             vpn_ctx->rd_data_size = GNUNET_GNSRECORD_records_get_size (rd_count,
1242                                                                        rd);
1243             vpn_ctx->rd_data = GNUNET_malloc (vpn_ctx->rd_data_size);
1244             (void) GNUNET_GNSRECORD_records_serialize (rd_count,
1245                                                        rd,
1246                                                        vpn_ctx->rd_data_size,
1247                                                        vpn_ctx->rd_data);
1248             vpn_ctx->vpn_request = GNUNET_VPN_redirect_to_peer (vpn_handle,
1249                                                                 af,
1250                                                                 ntohs (vpn->proto),
1251                                                                 &vpn->peer,
1252                                                                 &vhash,
1253                                                                 GNUNET_TIME_relative_to_absolute (VPN_TIMEOUT),
1254                                                                 &vpn_allocation_cb,
1255                                                                 rh);
1256             return;
1257           }
1258         case GNUNET_GNSRECORD_TYPE_GNS2DNS:
1259           {
1260             /* delegation to DNS */
1261             goto do_recurse;
1262           }
1263         default:
1264           break;
1265         }
1266       }
1267     }
1268     /* convert relative names in record values to absolute names,
1269        using 'scratch' array for memory allocations */
1270     scratch_off = 0;
1271     rd_off = 0;
1272     for (i=0;i<rd_count;i++)
1273     {
1274       rd_new[rd_off] = rd[i];
1275       /* Check if the embedded name(s) end in "+", and if so,
1276          replace the "+" with the zone at "ac_tail", changing the name
1277          to a ".zkey".  The name is allocated on the 'scratch' array,
1278          so we can free it afterwards. */
1279       switch (rd[i].record_type)
1280       {
1281       case GNUNET_DNSPARSER_TYPE_CNAME:
1282         {
1283           char *cname;
1284
1285           off = 0;
1286           cname = GNUNET_DNSPARSER_parse_name (rd[i].data,
1287                                                rd[i].data_size,
1288                                                &off);
1289           if ( (NULL == cname) ||
1290                (off != rd[i].data_size) )
1291           {
1292             GNUNET_break_op (0); /* record not well-formed */
1293           }
1294           else
1295           {
1296             cname = translate_dot_plus (rh, cname);
1297             GNUNET_break (NULL != cname);
1298             scratch_start = scratch_off;
1299             if (GNUNET_OK !=
1300                 GNUNET_DNSPARSER_builder_add_name (scratch,
1301                                                    sizeof (scratch),
1302                                                    &scratch_off,
1303                                                    cname))
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           GNUNET_free_non_null (cname);
1315         }
1316         break;
1317       case GNUNET_DNSPARSER_TYPE_SOA:
1318         {
1319           struct GNUNET_DNSPARSER_SoaRecord *soa;
1320
1321           off = 0;
1322           soa = GNUNET_DNSPARSER_parse_soa (rd[i].data,
1323                                             rd[i].data_size,
1324                                             &off);
1325           if ( (NULL == soa) ||
1326                (off != rd[i].data_size) )
1327           {
1328             GNUNET_break_op (0); /* record not well-formed */
1329           }
1330           else
1331           {
1332             soa->mname = translate_dot_plus (rh, soa->mname);
1333             soa->rname = translate_dot_plus (rh, soa->rname);
1334             scratch_start = scratch_off;
1335             if (GNUNET_OK !=
1336                 GNUNET_DNSPARSER_builder_add_soa (scratch,
1337                                                   sizeof (scratch),
1338                                                   &scratch_off,
1339                                                   soa))
1340             {
1341               GNUNET_break (0);
1342             }
1343             else
1344             {
1345               rd_new[rd_off].data = &scratch[scratch_start];
1346               rd_new[rd_off].data_size = scratch_off - scratch_start;
1347               rd_off++;
1348             }
1349           }
1350           if (NULL != soa)
1351             GNUNET_DNSPARSER_free_soa (soa);
1352         }
1353         break;
1354       case GNUNET_DNSPARSER_TYPE_MX:
1355         {
1356           struct GNUNET_DNSPARSER_MxRecord *mx;
1357
1358           off = 0;
1359           mx = GNUNET_DNSPARSER_parse_mx (rd[i].data,
1360                                           rd[i].data_size,
1361                                           &off);
1362           if ( (NULL == mx) ||
1363                (off != rd[i].data_size) )
1364           {
1365             GNUNET_break_op (0); /* record not well-formed */
1366           }
1367           else
1368           {
1369             mx->mxhost = translate_dot_plus (rh, mx->mxhost);
1370             scratch_start = scratch_off;
1371             if (GNUNET_OK !=
1372                 GNUNET_DNSPARSER_builder_add_mx (scratch,
1373                                                  sizeof (scratch),
1374                                                  &scratch_off,
1375                                                  mx))
1376             {
1377               GNUNET_break (0);
1378             }
1379             else
1380             {
1381               rd_new[rd_off].data = &scratch[scratch_start];
1382               rd_new[rd_off].data_size = scratch_off - scratch_start;
1383               rd_off++;
1384             }
1385           }
1386           if (NULL != mx)
1387             GNUNET_DNSPARSER_free_mx (mx);
1388         }
1389         break;
1390       case GNUNET_DNSPARSER_TYPE_SRV:
1391         {
1392           struct GNUNET_DNSPARSER_SrvRecord *srv;
1393
1394           off = 0;
1395           /* FIXME: passing rh->name here is is not necessarily what we want
1396              (SRV support not finished) */
1397           srv = GNUNET_DNSPARSER_parse_srv (rh->name,
1398                                             rd[i].data,
1399                                             rd[i].data_size,
1400                                             &off);
1401           if ( (NULL == srv) ||
1402                (off != rd[i].data_size) )
1403           {
1404             GNUNET_break_op (0); /* record not well-formed */
1405           }
1406           else
1407           {
1408             srv->domain_name = translate_dot_plus (rh, srv->domain_name);
1409             srv->target = translate_dot_plus (rh, srv->target);
1410             scratch_start = scratch_off;
1411             if (GNUNET_OK !=
1412                 GNUNET_DNSPARSER_builder_add_srv (scratch,
1413                                                   sizeof (scratch),
1414                                                   &scratch_off,
1415                                                   srv))
1416             {
1417               GNUNET_break (0);
1418             }
1419             else
1420             {
1421               rd_new[rd_off].data = &scratch[scratch_start];
1422               rd_new[rd_off].data_size = scratch_off - scratch_start;
1423               rd_off++;
1424             }
1425           }
1426           if (NULL != srv)
1427             GNUNET_DNSPARSER_free_srv (srv);
1428         }
1429         break;
1430       case GNUNET_GNSRECORD_TYPE_PKEY:
1431         {
1432           struct GNUNET_CRYPTO_EcdsaPublicKey pub;
1433
1434           if (rd[i].data_size != sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))
1435           {
1436             GNUNET_break_op (0);
1437             break;
1438           }
1439           memcpy (&pub, rd[i].data, rd[i].data_size);
1440
1441           /* tigger shortening */
1442           if (NULL != rh->shorten_key)
1443           {
1444             GNS_shorten_start (rh->ac_tail->label,
1445                                &pub,
1446                                rh->shorten_key);
1447           }
1448           rd_off++;
1449           if (GNUNET_GNSRECORD_TYPE_PKEY != rh->record_type)
1450           {
1451             /* try to resolve "+" */
1452             struct AuthorityChain *ac;
1453
1454             ac = GNUNET_new (struct AuthorityChain);
1455             ac->rh = rh;
1456             ac->gns_authority = GNUNET_YES;
1457             ac->authority_info.gns_authority = pub;
1458             ac->label = GNUNET_strdup (GNUNET_GNS_MASTERZONE_STR);
1459             GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1460                                               rh->ac_tail,
1461                                               ac);
1462             rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1463                                                     rh);
1464             return;
1465           }
1466         }
1467         break;
1468       default:
1469         rd_off++;
1470         break;
1471       }
1472     }
1473
1474     /* yes, we are done, return result */
1475     rh->proc (rh->proc_cls, rd_off, rd_new);
1476     GNS_resolver_lookup_cancel (rh);
1477     return;
1478   }
1479  do_recurse:
1480   /* need to recurse, check if we can */
1481   for (i=0;i<rd_count;i++)
1482   {
1483     switch (rd[i].record_type)
1484     {
1485     case GNUNET_GNSRECORD_TYPE_PKEY:
1486       /* delegation to another zone */
1487       if (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) !=
1488           rd[i].data_size)
1489       {
1490         GNUNET_break_op (0);
1491         rh->proc (rh->proc_cls, 0, NULL);
1492         GNS_resolver_lookup_cancel (rh);
1493         return;
1494       }
1495       /* expand authority chain */
1496       ac = GNUNET_new (struct AuthorityChain);
1497       ac->rh = rh;
1498       ac->gns_authority = GNUNET_YES;
1499       memcpy (&ac->authority_info.gns_authority,
1500               rd[i].data,
1501               sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1502       ac->label = resolver_lookup_get_next_label (rh);
1503       /* tigger shortening */
1504       if (NULL != rh->shorten_key)
1505         GNS_shorten_start (rh->ac_tail->label,
1506                            &ac->authority_info.gns_authority,
1507                            rh->shorten_key);
1508       /* add AC to tail */
1509       GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1510                                         rh->ac_tail,
1511                                         ac);
1512       /* recurse */
1513       rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1514                                               rh);
1515       return;
1516     case GNUNET_GNSRECORD_TYPE_GNS2DNS:
1517       {
1518         char *ns;
1519         /* resolution continues within DNS */
1520         if (GNUNET_DNSPARSER_MAX_NAME_LENGTH < rd[i].data_size)
1521         {
1522           GNUNET_break_op (0);
1523           rh->proc (rh->proc_cls, 0, NULL);
1524           GNS_resolver_lookup_cancel (rh);
1525           return;
1526         }
1527         /* find associated A/AAAA record */
1528         sa = NULL;
1529         sa_len = 0;
1530         for (j=0;j<rd_count;j++)
1531         {
1532           switch (rd[j].record_type)
1533             {
1534             case GNUNET_DNSPARSER_TYPE_A:
1535               if (sizeof (struct in_addr) != rd[j].data_size)
1536               {
1537                 GNUNET_break_op (0);
1538                 rh->proc (rh->proc_cls, 0, NULL);
1539                 GNS_resolver_lookup_cancel (rh);
1540                 return;
1541               }
1542               /* FIXME: might want to check if we support IPv4 here,
1543                  and otherwise skip this one and hope we find another */
1544               memset (&v4, 0, sizeof (v4));
1545               sa_len = sizeof (v4);
1546               v4.sin_family = AF_INET;
1547               v4.sin_port = htons (53);
1548 #if HAVE_SOCKADDR_IN_SIN_LEN
1549               v4.sin_len = (u_char) sa_len;
1550 #endif
1551               memcpy (&v4.sin_addr,
1552                       rd[j].data,
1553                       sizeof (struct in_addr));
1554               sa = (struct sockaddr *) &v4;
1555               break;
1556             case GNUNET_DNSPARSER_TYPE_AAAA:
1557               if (sizeof (struct in6_addr) != rd[j].data_size)
1558               {
1559                 GNUNET_break_op (0);
1560                 rh->proc (rh->proc_cls, 0, NULL);
1561                 GNS_resolver_lookup_cancel (rh);
1562                 return;
1563               }
1564               /* FIXME: might want to check if we support IPv6 here,
1565                  and otherwise skip this one and hope we find another */
1566               memset (&v6, 0, sizeof (v6));
1567               sa_len = sizeof (v6);
1568               v6.sin6_family = AF_INET6;
1569               v6.sin6_port = htons (53);
1570 #if HAVE_SOCKADDR_IN_SIN_LEN
1571               v6.sin6_len = (u_char) sa_len;
1572 #endif
1573               memcpy (&v6.sin6_addr,
1574                       rd[j].data,
1575                       sizeof (struct in6_addr));
1576               sa = (struct sockaddr *) &v6;
1577               break;
1578             default:
1579               break;
1580             }
1581           if (NULL != sa)
1582             break;
1583         }
1584         if (NULL == sa)
1585         {
1586           /* we cannot continue; NS without A/AAAA */
1587           rh->proc (rh->proc_cls, 0, NULL);
1588           GNS_resolver_lookup_cancel (rh);
1589           return;
1590         }
1591         /* expand authority chain */
1592         ac = GNUNET_new (struct AuthorityChain);
1593         ac->rh = rh;
1594         off = 0;
1595         ns = GNUNET_DNSPARSER_parse_name (rd[i].data,
1596                                           rd[i].data_size,
1597                                           &off);
1598         if ( (NULL == ns) ||
1599              (off != rd[i].data_size) )
1600         {
1601           GNUNET_break_op (0); /* record not well-formed */
1602           rh->proc (rh->proc_cls, 0, NULL);
1603           GNS_resolver_lookup_cancel (rh);
1604           GNUNET_free_non_null (ns);
1605           GNUNET_free (ac);
1606           return;
1607         }
1608         strcpy (ac->authority_info.dns_authority.name,
1609                 ns);
1610         memcpy (&ac->authority_info.dns_authority.dns_ip,
1611                 sa,
1612                 sa_len);
1613         /* for DNS recursion, the label is the full DNS name,
1614            created from the remainder of the GNS name and the
1615            name in the NS record */
1616         GNUNET_asprintf (&ac->label,
1617                          "%.*s%s%s",
1618                          (int) rh->name_resolution_pos,
1619                          rh->name,
1620                          (0 != rh->name_resolution_pos) ? "." : "",
1621                          ns);
1622         GNUNET_free (ns);
1623         GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1624                                           rh->ac_tail,
1625                                           ac);
1626         if (strlen (ac->label) > GNUNET_DNSPARSER_MAX_NAME_LENGTH)
1627         {
1628           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1629                       _("GNS lookup resulted in DNS name that is too long (`%s')\n"),
1630                       ac->label);
1631           rh->proc (rh->proc_cls, 0, NULL);
1632           GNS_resolver_lookup_cancel (rh);
1633           return;
1634         }
1635         /* recurse */
1636         rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1637                                                 rh);
1638         return;
1639       }
1640     case GNUNET_DNSPARSER_TYPE_CNAME:
1641       {
1642         char *cname;
1643
1644         off = 0;
1645         cname = GNUNET_DNSPARSER_parse_name (rd[i].data,
1646                                              rd[i].data_size,
1647                                              &off);
1648         if ( (NULL == cname) ||
1649              (off != rd[i].data_size) )
1650         {
1651           GNUNET_break_op (0); /* record not well-formed */
1652           rh->proc (rh->proc_cls, 0, NULL);
1653           GNS_resolver_lookup_cancel (rh);
1654           GNUNET_free_non_null (cname);
1655           return;
1656         }
1657         handle_gns_cname_result (rh,
1658                                  cname);
1659         GNUNET_free (cname);
1660         return;
1661       }
1662       /* FIXME: handle DNAME */
1663     default:
1664       /* skip */
1665       break;
1666     }
1667   }
1668   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1669               _("GNS lookup recursion failed (no delegation record found)\n"));
1670   rh->proc (rh->proc_cls, 0, NULL);
1671   GNS_resolver_lookup_cancel (rh);
1672 }
1673
1674
1675 /**
1676  * Function called once the namestore has completed the request for
1677  * caching a block.
1678  *
1679  * @param cls closure with the `struct CacheOps`
1680  * @param success #GNUNET_OK on success
1681  * @param emsg error message
1682  */
1683 static void
1684 namecache_cache_continuation (void *cls,
1685                               int32_t success,
1686                               const char *emsg)
1687 {
1688   struct CacheOps *co = cls;
1689
1690   co->namecache_qe_cache = NULL;
1691   if (NULL != emsg)
1692     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1693                 _("Failed to cache GNS resolution: %s\n"),
1694                 emsg);
1695   GNUNET_CONTAINER_DLL_remove (co_head,
1696                                co_tail,
1697                                co);
1698   GNUNET_free (co);
1699 }
1700
1701
1702 /**
1703  * Iterator called on each result obtained for a DHT
1704  * operation that expects a reply
1705  *
1706  * @param cls closure with the `struct GNS_ResolverHandle`
1707  * @param exp when will this value expire
1708  * @param key key of the result
1709  * @param get_path peers on reply path (or NULL if not recorded)
1710  *                 [0] = datastore's first neighbor, [length - 1] = local peer
1711  * @param get_path_length number of entries in @a get_path
1712  * @param put_path peers on the PUT path (or NULL if not recorded)
1713  *                 [0] = origin, [length - 1] = datastore
1714  * @param put_path_length number of entries in @a put_path
1715  * @param type type of the result
1716  * @param size number of bytes in data
1717  * @param data pointer to the result data
1718  */
1719 static void
1720 handle_dht_response (void *cls,
1721                      struct GNUNET_TIME_Absolute exp,
1722                      const struct GNUNET_HashCode *key,
1723                      const struct GNUNET_PeerIdentity *get_path,
1724                      unsigned int get_path_length,
1725                      const struct GNUNET_PeerIdentity *put_path,
1726                      unsigned int put_path_length,
1727                      enum GNUNET_BLOCK_Type type,
1728                      size_t size, const void *data)
1729 {
1730   struct GNS_ResolverHandle *rh = cls;
1731   struct AuthorityChain *ac = rh->ac_tail;
1732   const struct GNUNET_GNSRECORD_Block *block;
1733   struct CacheOps *co;
1734
1735   GNUNET_DHT_get_stop (rh->get_handle);
1736   rh->get_handle = NULL;
1737   GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
1738   rh->dht_heap_node = NULL;
1739   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1740               "Handling response from the DHT\n");
1741   if (size < sizeof (struct GNUNET_GNSRECORD_Block))
1742   {
1743     /* how did this pass DHT block validation!? */
1744     GNUNET_break (0);
1745     rh->proc (rh->proc_cls, 0, NULL);
1746     GNS_resolver_lookup_cancel (rh);
1747     return;
1748   }
1749   block = data;
1750   if (size !=
1751       ntohl (block->purpose.size) +
1752       sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) +
1753       sizeof (struct GNUNET_CRYPTO_EcdsaSignature))
1754   {
1755     /* how did this pass DHT block validation!? */
1756     GNUNET_break (0);
1757     rh->proc (rh->proc_cls, 0, NULL);
1758     GNS_resolver_lookup_cancel (rh);
1759     return;
1760   }
1761   if (GNUNET_OK !=
1762       GNUNET_GNSRECORD_block_decrypt (block,
1763                                       &ac->authority_info.gns_authority,
1764                                       ac->label,
1765                                       &handle_gns_resolution_result,
1766                                       rh))
1767   {
1768     GNUNET_break_op (0); /* block was ill-formed */
1769     rh->proc (rh->proc_cls, 0, NULL);
1770     GNS_resolver_lookup_cancel (rh);
1771     return;
1772   }
1773   if (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (block->expiration_time)).rel_value_us)
1774   {
1775     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1776                 "Received expired block from the DHT, will not cache it.\n");
1777     return;
1778   }
1779   /* Cache well-formed blocks */
1780   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1781               "Caching response from the DHT in namestore\n");
1782   co = GNUNET_new (struct CacheOps);
1783   co->namecache_qe_cache = GNUNET_NAMECACHE_block_cache (namecache_handle,
1784                                                          block,
1785                                                          &namecache_cache_continuation,
1786                                                          co);
1787   GNUNET_CONTAINER_DLL_insert (co_head,
1788                                co_tail,
1789                                co);
1790 }
1791
1792
1793 /**
1794  * Process a record that was stored in the namestore.
1795  *
1796  * @param cls closure with the `struct GNS_ResolverHandle`
1797  * @param block block that was stored in the namestore
1798  */
1799 static void
1800 handle_namestore_block_response (void *cls,
1801                                  const struct GNUNET_GNSRECORD_Block *block)
1802 {
1803   struct GNS_ResolverHandle *rh = cls;
1804   struct GNS_ResolverHandle *rx;
1805   struct AuthorityChain *ac = rh->ac_tail;
1806   const char *label = ac->label;
1807   const struct GNUNET_CRYPTO_EcdsaPublicKey *auth = &ac->authority_info.gns_authority;
1808   struct GNUNET_HashCode query;
1809
1810   GNUNET_GNSRECORD_query_from_public_key (auth,
1811                                           label,
1812                                           &query);
1813   GNUNET_assert (NULL != rh->namecache_qe);
1814   rh->namecache_qe = NULL;
1815   if ( (GNUNET_NO == rh->only_cached) &&
1816        ( (NULL == block) ||
1817          (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (block->expiration_time)).rel_value_us) ) )
1818   {
1819     /* Namestore knows nothing; try DHT lookup */
1820     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1821                 "Starting DHT lookup for `%s' in zone %s\n",
1822                 ac->label,
1823                 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
1824     GNUNET_assert (NULL == rh->get_handle);
1825     rh->get_handle = GNUNET_DHT_get_start (dht_handle,
1826                                            GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1827                                            &query,
1828                                            DHT_GNS_REPLICATION_LEVEL,
1829                                            GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
1830                                            NULL, 0,
1831                                            &handle_dht_response, rh);
1832     rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
1833                                                       rh,
1834                                                       GNUNET_TIME_absolute_get ().abs_value_us);
1835     if (GNUNET_CONTAINER_heap_get_size (dht_lookup_heap) > max_allowed_background_queries)
1836     {
1837       /* fail longest-standing DHT request */
1838       rx = GNUNET_CONTAINER_heap_peek (dht_lookup_heap);
1839       GNUNET_assert (NULL != rx);
1840       rx->proc (rx->proc_cls, 0, NULL);
1841       GNS_resolver_lookup_cancel (rx);
1842     }
1843     return;
1844   }
1845   if ( (NULL == block) ||
1846        (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (block->expiration_time)).rel_value_us) )
1847   {
1848     /* DHT not permitted and no local result, fail */
1849     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1850                 "Resolution failed for `%s' in zone %s (DHT lookup not permitted by configuration)\n",
1851                 ac->label,
1852                 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
1853     rh->proc (rh->proc_cls, 0, NULL);
1854     GNS_resolver_lookup_cancel (rh);
1855     return;
1856   }
1857   if (GNUNET_OK !=
1858       GNUNET_GNSRECORD_block_decrypt (block,
1859                                       auth,
1860                                       label,
1861                                       &handle_gns_resolution_result,
1862                                       rh))
1863   {
1864     GNUNET_break_op (0); /* block was ill-formed */
1865     rh->proc (rh->proc_cls, 0, NULL);
1866     GNS_resolver_lookup_cancel (rh);
1867     return;
1868   }
1869 }
1870
1871
1872 /**
1873  * Lookup tail of our authority chain in the namestore.
1874  *
1875  * @param rh query we are processing
1876  */
1877 static void
1878 recursive_gns_resolution_namestore (struct GNS_ResolverHandle *rh)
1879 {
1880   struct AuthorityChain *ac = rh->ac_tail;
1881   struct GNUNET_HashCode query;
1882
1883   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1884               "Starting GNS resolution for `%s' in zone %s\n",
1885               ac->label,
1886               GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
1887   GNUNET_GNSRECORD_query_from_public_key (&ac->authority_info.gns_authority,
1888                                           ac->label,
1889                                           &query);
1890   rh->namecache_qe = GNUNET_NAMECACHE_lookup_block (namecache_handle,
1891                                                     &query,
1892                                                     &handle_namestore_block_response,
1893                                                     rh);
1894   GNUNET_assert (NULL != rh->namecache_qe);
1895 }
1896
1897
1898 /**
1899  * Function called with the result from a revocation check.
1900  *
1901  * @param cls the `struct GNS_ResovlerHandle`
1902  * @param is_valid #GNUNET_YES if the zone was not yet revoked
1903  */
1904 static void
1905 handle_revocation_result (void *cls,
1906                           int is_valid)
1907 {
1908   struct GNS_ResolverHandle *rh = cls;
1909   struct AuthorityChain *ac = rh->ac_tail;
1910
1911   rh->rev_check = NULL;
1912   if (GNUNET_YES != is_valid)
1913   {
1914     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1915                 _("Zone %s was revoked, resolution fails\n"),
1916                 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
1917     rh->proc (rh->proc_cls, 0, NULL);
1918     GNS_resolver_lookup_cancel (rh);
1919     return;
1920   }
1921   recursive_gns_resolution_namestore (rh);
1922 }
1923
1924
1925 /**
1926  * Perform revocation check on tail of our authority chain.
1927  *
1928  * @param rh query we are processing
1929  */
1930 static void
1931 recursive_gns_resolution_revocation (struct GNS_ResolverHandle *rh)
1932 {
1933   struct AuthorityChain *ac = rh->ac_tail;
1934
1935   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1936               "Starting revocation check for zone %s\n",
1937               GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
1938   rh->rev_check = GNUNET_REVOCATION_query (cfg,
1939                                            &ac->authority_info.gns_authority,
1940                                            &handle_revocation_result,
1941                                            rh);
1942   GNUNET_assert (NULL != rh->rev_check);
1943 }
1944
1945
1946 /**
1947  * Task scheduled to continue with the resolution process.
1948  *
1949  * @param cls the `struct GNS_ResolverHandle` of the resolution
1950  * @param tc task context
1951  */
1952 static void
1953 recursive_resolution (void *cls,
1954                       const struct GNUNET_SCHEDULER_TaskContext *tc)
1955 {
1956   struct GNS_ResolverHandle *rh = cls;
1957
1958   rh->task_id = GNUNET_SCHEDULER_NO_TASK;
1959   if (MAX_RECURSION < rh->loop_limiter++)
1960   {
1961     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1962                 "Encountered unbounded recursion resolving `%s'\n",
1963                 rh->name);
1964     rh->proc (rh->proc_cls, 0, NULL);
1965     GNS_resolver_lookup_cancel (rh);
1966     return;
1967   }
1968   if (GNUNET_YES == rh->ac_tail->gns_authority)
1969     recursive_gns_resolution_revocation (rh);
1970   else
1971     recursive_dns_resolution (rh);
1972 }
1973
1974
1975 /**
1976  * Begin the resolution process from 'name', starting with
1977  * the identification of the zone specified by 'name'.
1978  *
1979  * @param rh resolution to perform
1980  */
1981 static void
1982 start_resolver_lookup (struct GNS_ResolverHandle *rh)
1983 {
1984   struct AuthorityChain *ac;
1985   char *x;
1986   char *y;
1987   char *pkey;
1988
1989   if ( ( (GNUNET_YES == is_canonical (rh->name)) &&
1990          (0 != strcmp (GNUNET_GNS_TLD, rh->name)) ) ||
1991        ( (GNUNET_YES != is_gnu_tld (rh->name)) &&
1992          (GNUNET_YES != is_zkey_tld (rh->name)) ) )
1993   {
1994     /* use standard DNS lookup */
1995     int af;
1996
1997     switch (rh->record_type)
1998     {
1999     case GNUNET_DNSPARSER_TYPE_A:
2000       af = AF_INET;
2001       break;
2002     case GNUNET_DNSPARSER_TYPE_AAAA:
2003       af = AF_INET6;
2004       break;
2005     default:
2006       af = AF_UNSPEC;
2007       break;
2008     }
2009     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2010                 "Doing standard DNS lookup for `%s'\n",
2011                 rh->name);
2012     rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name,
2013                                               af,
2014                                               DNS_LOOKUP_TIMEOUT,
2015                                               &handle_dns_result,
2016                                               rh);
2017     return;
2018   }
2019   if (is_zkey_tld (rh->name))
2020   {
2021     /* Name ends with ".zkey", try to replace authority zone with zkey
2022        authority */
2023     GNUNET_free (resolver_lookup_get_next_label (rh)); /* will return "zkey" */
2024     x = resolver_lookup_get_next_label (rh); /* will return 'x' coordinate */
2025     y = resolver_lookup_get_next_label (rh); /* will return 'y' coordinate */
2026     GNUNET_asprintf (&pkey,
2027                      "%s%s",
2028                      x, y);
2029     if ( (NULL == x) ||
2030          (NULL == y) ||
2031          (GNUNET_OK !=
2032           GNUNET_CRYPTO_ecdsa_public_key_from_string (pkey,
2033                                                     strlen (pkey),
2034                                                     &rh->authority_zone)) )
2035     {
2036       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2037                   _("Hostname `%s' is not well-formed, resolution fails\n"),
2038                   rh->name);
2039       rh->task_id = GNUNET_SCHEDULER_add_now (&fail_resolution, rh);
2040     }
2041     GNUNET_free_non_null (x);
2042     GNUNET_free_non_null (y);
2043     GNUNET_free (pkey);
2044   }
2045   else
2046   {
2047     /* Name ends with ".gnu", eat ".gnu" and continue with resolution */
2048     GNUNET_free (resolver_lookup_get_next_label (rh));
2049   }
2050   ac = GNUNET_new (struct AuthorityChain);
2051   ac->rh = rh;
2052   ac->label = resolver_lookup_get_next_label (rh);
2053   if (NULL == ac->label)
2054     /* name was just "gnu", so we default to label '+' */
2055     ac->label = GNUNET_strdup (GNUNET_GNS_MASTERZONE_STR);
2056   ac->gns_authority = GNUNET_YES;
2057   ac->authority_info.gns_authority = rh->authority_zone;
2058   GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
2059                                     rh->ac_tail,
2060                                     ac);
2061   rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
2062                                           rh);
2063 }
2064
2065
2066 /**
2067  * Lookup of a record in a specific zone calls lookup result processor
2068  * on result.
2069  *
2070  * @param zone the zone to perform the lookup in
2071  * @param record_type the record type to look up
2072  * @param name the name to look up
2073  * @param shorten_key a private key for use with PSEU import (can be NULL)
2074  * @param only_cached #GNUNET_NO to only check locally not DHT for performance
2075  * @param proc the processor to call on result
2076  * @param proc_cls the closure to pass to @a proc
2077  * @return handle to cancel operation
2078  */
2079 struct GNS_ResolverHandle *
2080 GNS_resolver_lookup (const struct GNUNET_CRYPTO_EcdsaPublicKey *zone,
2081                      uint32_t record_type,
2082                      const char *name,
2083                      const struct GNUNET_CRYPTO_EcdsaPrivateKey *shorten_key,
2084                      int only_cached,
2085                      GNS_ResultProcessor proc, void *proc_cls)
2086 {
2087   struct GNS_ResolverHandle *rh;
2088
2089   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2090               (NULL == shorten_key)
2091               ? "Starting lookup for `%s' with shortening disabled\n"
2092               : "Starting lookup for `%s' with shortening enabled\n",
2093               name);
2094   rh = GNUNET_new (struct GNS_ResolverHandle);
2095   GNUNET_CONTAINER_DLL_insert (rlh_head,
2096                                rlh_tail,
2097                                rh);
2098   rh->authority_zone = *zone;
2099   rh->proc = proc;
2100   rh->proc_cls = proc_cls;
2101   rh->only_cached = only_cached;
2102   rh->record_type = record_type;
2103   rh->name = GNUNET_strdup (name);
2104   rh->name_resolution_pos = strlen (name);
2105   if (NULL != shorten_key)
2106   {
2107     rh->shorten_key = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
2108     *rh->shorten_key = *shorten_key;
2109   }
2110   start_resolver_lookup (rh);
2111   return rh;
2112 }
2113
2114
2115 /**
2116  * Cancel active resolution (i.e. client disconnected).
2117  *
2118  * @param rh resolution to abort
2119  */
2120 void
2121 GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
2122 {
2123   struct DnsResult *dr;
2124   struct AuthorityChain *ac;
2125   struct VpnContext *vpn_ctx;
2126
2127   GNUNET_CONTAINER_DLL_remove (rlh_head,
2128                                rlh_tail,
2129                                rh);
2130   while (NULL != (ac = rh->ac_head))
2131   {
2132     GNUNET_CONTAINER_DLL_remove (rh->ac_head,
2133                                  rh->ac_tail,
2134                                  ac);
2135     GNUNET_free (ac->label);
2136     GNUNET_free (ac);
2137   }
2138   if (GNUNET_SCHEDULER_NO_TASK != rh->task_id)
2139   {
2140     GNUNET_SCHEDULER_cancel (rh->task_id);
2141     rh->task_id = GNUNET_SCHEDULER_NO_TASK;
2142   }
2143   if (NULL != rh->get_handle)
2144   {
2145     GNUNET_DHT_get_stop (rh->get_handle);
2146     rh->get_handle = NULL;
2147   }
2148   if (NULL != rh->dht_heap_node)
2149   {
2150     GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
2151     rh->dht_heap_node = NULL;
2152   }
2153   if (NULL != (vpn_ctx = rh->vpn_ctx))
2154   {
2155     GNUNET_VPN_cancel_request (vpn_ctx->vpn_request);
2156     GNUNET_free (vpn_ctx->rd_data);
2157     GNUNET_free (vpn_ctx);
2158   }
2159   if (NULL != rh->dns_request)
2160   {
2161     GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
2162     rh->dns_request = NULL;
2163   }
2164   if (NULL != rh->namecache_qe)
2165   {
2166     GNUNET_NAMECACHE_cancel (rh->namecache_qe);
2167     rh->namecache_qe = NULL;
2168   }
2169   if (NULL != rh->rev_check)
2170   {
2171     GNUNET_REVOCATION_query_cancel (rh->rev_check);
2172     rh->rev_check = NULL;
2173   }
2174   if (NULL != rh->std_resolve)
2175   {
2176     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2177                 "Canceling standard DNS resolution\n");
2178     GNUNET_RESOLVER_request_cancel (rh->std_resolve);
2179     rh->std_resolve = NULL;
2180   }
2181   while (NULL != (dr = rh->dns_result_head))
2182   {
2183     GNUNET_CONTAINER_DLL_remove (rh->dns_result_head,
2184                                  rh->dns_result_tail,
2185                                  dr);
2186     GNUNET_free (dr);
2187   }
2188   GNUNET_free_non_null (rh->shorten_key);
2189   GNUNET_free (rh->name);
2190   GNUNET_free (rh);
2191 }
2192
2193
2194 /* ***************** Resolver initialization ********************* */
2195
2196
2197 /**
2198  * Initialize the resolver
2199  *
2200  * @param nc the namecache handle
2201  * @param dht the dht handle
2202  * @param c configuration handle
2203  * @param max_bg_queries maximum number of parallel background queries in dht
2204  */
2205 void
2206 GNS_resolver_init (struct GNUNET_NAMECACHE_Handle *nc,
2207                    struct GNUNET_DHT_Handle *dht,
2208                    const struct GNUNET_CONFIGURATION_Handle *c,
2209                    unsigned long long max_bg_queries)
2210 {
2211   char *dns_ip;
2212
2213   cfg = c;
2214   namecache_handle = nc;
2215   dht_handle = dht;
2216   dht_lookup_heap =
2217     GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
2218   max_allowed_background_queries = max_bg_queries;
2219   if (GNUNET_OK !=
2220       GNUNET_CONFIGURATION_get_value_string (c,
2221                                              "gns",
2222                                              "DNS_RESOLVER",
2223                                              &dns_ip))
2224   {
2225     /* user did not specify DNS resolver, use 8.8.8.8 */
2226     dns_ip = GNUNET_strdup ("8.8.8.8");
2227   }
2228   dns_handle = GNUNET_DNSSTUB_start (dns_ip);
2229   GNUNET_free (dns_ip);
2230   vpn_handle = GNUNET_VPN_connect (cfg);
2231 }
2232
2233
2234 /**
2235  * Shutdown resolver
2236  */
2237 void
2238 GNS_resolver_done ()
2239 {
2240   struct GNS_ResolverHandle *rh;
2241   struct CacheOps *co;
2242
2243   /* abort active resolutions */
2244   while (NULL != (rh = rlh_head))
2245   {
2246     rh->proc (rh->proc_cls, 0, NULL);
2247     GNS_resolver_lookup_cancel (rh);
2248   }
2249   while (NULL != (co = co_head))
2250   {
2251     GNUNET_CONTAINER_DLL_remove (co_head,
2252                                  co_tail,
2253                                  co);
2254     GNUNET_NAMECACHE_cancel (co->namecache_qe_cache);
2255     GNUNET_free (co);
2256   }
2257   GNUNET_CONTAINER_heap_destroy (dht_lookup_heap);
2258   dht_lookup_heap = NULL;
2259   GNUNET_DNSSTUB_stop (dns_handle);
2260   dns_handle = NULL;
2261   GNUNET_VPN_disconnect (vpn_handle);
2262   vpn_handle = NULL;
2263   dht_handle = NULL;
2264   namecache_handle = NULL;
2265 }
2266
2267
2268 /* *************** common helper functions (do not really belong here) *********** */
2269
2270 /**
2271  * Checks if @a name ends in ".TLD"
2272  *
2273  * @param name the name to check
2274  * @param tld the TLD to check for
2275  * @return GNUNET_YES or GNUNET_NO
2276  */
2277 int
2278 is_tld (const char* name, const char* tld)
2279 {
2280   size_t offset = 0;
2281
2282   if (strlen (name) <= strlen (tld))
2283     return GNUNET_NO;
2284   offset = strlen (name) - strlen (tld);
2285   if (0 != strcmp (name + offset, tld))
2286     return GNUNET_NO;
2287   return GNUNET_YES;
2288 }
2289
2290
2291 /* end of gnunet-service-gns_resolver.c */