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