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