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