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