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