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