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