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