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