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