fix only cache variable long/short
[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 got from
1977  * the namecache.  Simply calls #handle_gns_resolution_result().
1978  *
1979  * @param cls closure with the `struct GNS_ResolverHandle`
1980  * @param rd_count number of entries in @a rd array
1981  * @param rd array of records with data to store
1982  */
1983 static void
1984 handle_gns_namecache_resolution_result (void *cls,
1985                                         unsigned int rd_count,
1986                                         const struct GNUNET_GNSRECORD_Data *rd)
1987 {
1988   struct GNS_ResolverHandle *rh = cls;
1989
1990   handle_gns_resolution_result (rh,
1991                                 rd_count,
1992                                 rd);
1993 }
1994
1995
1996 /**
1997  * Process a record that was stored in the namecache.
1998  *
1999  * @param cls closure with the `struct GNS_ResolverHandle`
2000  * @param block block that was stored in the namecache
2001  */
2002 static void
2003 handle_namecache_block_response (void *cls,
2004                                  const struct GNUNET_GNSRECORD_Block *block)
2005 {
2006   struct GNS_ResolverHandle *rh = cls;
2007   struct AuthorityChain *ac = rh->ac_tail;
2008   const char *label = ac->label;
2009   const struct GNUNET_CRYPTO_EcdsaPublicKey *auth = &ac->authority_info.gns_authority;
2010   struct GNUNET_HashCode query;
2011
2012   GNUNET_assert (NULL != rh->namecache_qe);
2013   rh->namecache_qe = NULL;
2014   if ( (GNUNET_NO == rh->only_cached) &&
2015        ( (NULL == block) ||
2016          (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (block->expiration_time)).rel_value_us) ) )
2017   {
2018     /* namecache knows nothing; try DHT lookup */
2019     GNUNET_GNSRECORD_query_from_public_key (auth,
2020                                             label,
2021                                             &query);
2022     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2023                 "Starting DHT lookup for `%s' in zone `%s' under key `%s'\n",
2024                 ac->label,
2025                 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority),
2026                 GNUNET_h2s (&query));
2027     start_dht_request (rh, &query);
2028     return;
2029   }
2030
2031   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2032               "Received result from namecache for label `%s'\n",
2033               ac->label);
2034
2035   if ( (NULL == block) ||
2036        (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (block->expiration_time)).rel_value_us) )
2037   {
2038     /* DHT not permitted and no local result, fail */
2039     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2040                 "Resolution failed for `%s' in zone %s (DHT lookup not permitted by configuration)\n",
2041                 ac->label,
2042                 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2043     rh->proc (rh->proc_cls, 0, NULL);
2044     GNS_resolver_lookup_cancel (rh);
2045     return;
2046   }
2047   if (GNUNET_OK !=
2048       GNUNET_GNSRECORD_block_decrypt (block,
2049                                       auth,
2050                                       label,
2051                                       &handle_gns_namecache_resolution_result,
2052                                       rh))
2053   {
2054     GNUNET_break_op (0); /* block was ill-formed */
2055     /* try DHT instead */
2056     GNUNET_GNSRECORD_query_from_public_key (auth,
2057                                             label,
2058                                             &query);
2059     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2060                 "Starting DHT lookup for `%s' in zone `%s' under key `%s'\n",
2061                 ac->label,
2062                 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority),
2063                 GNUNET_h2s (&query));
2064     start_dht_request (rh, &query);
2065     return;
2066   }
2067 }
2068
2069
2070 /**
2071  * Lookup tail of our authority chain in the namecache.
2072  *
2073  * @param rh query we are processing
2074  */
2075 static void
2076 recursive_gns_resolution_namecache (struct GNS_ResolverHandle *rh)
2077 {
2078   struct AuthorityChain *ac = rh->ac_tail;
2079   struct GNUNET_HashCode query;
2080
2081   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2082               "Starting GNS resolution for `%s' in zone %s\n",
2083               ac->label,
2084               GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2085   GNUNET_GNSRECORD_query_from_public_key (&ac->authority_info.gns_authority,
2086                                           ac->label,
2087                                           &query);
2088   if (GNUNET_YES == use_cache)
2089   {
2090     rh->namecache_qe
2091       = GNUNET_NAMECACHE_lookup_block (namecache_handle,
2092                                        &query,
2093                                        &handle_namecache_block_response,
2094                                        rh);
2095     GNUNET_assert (NULL != rh->namecache_qe);
2096   }
2097   else
2098   {
2099     start_dht_request (rh, &query);
2100   }
2101 }
2102
2103
2104 /**
2105  * Function called with the result from a revocation check.
2106  *
2107  * @param cls the `struct GNS_ResovlerHandle`
2108  * @param is_valid #GNUNET_YES if the zone was not yet revoked
2109  */
2110 static void
2111 handle_revocation_result (void *cls,
2112                           int is_valid)
2113 {
2114   struct GNS_ResolverHandle *rh = cls;
2115   struct AuthorityChain *ac = rh->ac_tail;
2116
2117   rh->rev_check = NULL;
2118   if (GNUNET_YES != is_valid)
2119   {
2120     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2121                 _("Zone %s was revoked, resolution fails\n"),
2122                 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2123     rh->proc (rh->proc_cls, 0, NULL);
2124     GNS_resolver_lookup_cancel (rh);
2125     return;
2126   }
2127   recursive_gns_resolution_namecache (rh);
2128 }
2129
2130
2131 /**
2132  * Perform revocation check on tail of our authority chain.
2133  *
2134  * @param rh query we are processing
2135  */
2136 static void
2137 recursive_gns_resolution_revocation (struct GNS_ResolverHandle *rh)
2138 {
2139   struct AuthorityChain *ac = rh->ac_tail;
2140
2141   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2142               "Starting revocation check for zone %s\n",
2143               GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2144   rh->rev_check = GNUNET_REVOCATION_query (cfg,
2145                                            &ac->authority_info.gns_authority,
2146                                            &handle_revocation_result,
2147                                            rh);
2148   GNUNET_assert (NULL != rh->rev_check);
2149 }
2150
2151
2152 /**
2153  * Task scheduled to continue with the resolution process.
2154  *
2155  * @param cls the `struct GNS_ResolverHandle` of the resolution
2156  * @param tc task context
2157  */
2158 static void
2159 recursive_resolution (void *cls,
2160                       const struct GNUNET_SCHEDULER_TaskContext *tc)
2161 {
2162   struct GNS_ResolverHandle *rh = cls;
2163
2164   rh->task_id = GNUNET_SCHEDULER_NO_TASK;
2165   if (MAX_RECURSION < rh->loop_limiter++)
2166   {
2167     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2168                 "Encountered unbounded recursion resolving `%s'\n",
2169                 rh->name);
2170     rh->proc (rh->proc_cls, 0, NULL);
2171     GNS_resolver_lookup_cancel (rh);
2172     return;
2173   }
2174   if (GNUNET_YES == rh->ac_tail->gns_authority)
2175     recursive_gns_resolution_revocation (rh);
2176   else
2177     recursive_dns_resolution (rh);
2178 }
2179
2180
2181 /**
2182  * Begin the resolution process from 'name', starting with
2183  * the identification of the zone specified by 'name'.
2184  *
2185  * @param rh resolution to perform
2186  */
2187 static void
2188 start_resolver_lookup (struct GNS_ResolverHandle *rh)
2189 {
2190   struct AuthorityChain *ac;
2191   char *y;
2192   struct in_addr v4;
2193   struct in6_addr v6;
2194
2195   if (1 == inet_pton (AF_INET,
2196                       rh->name,
2197                       &v4))
2198   {
2199     /* name is IPv4 address, pretend it's an A record */
2200     struct GNUNET_GNSRECORD_Data rd;
2201
2202     rd.data = &v4;
2203     rd.data_size = sizeof (v4);
2204     rd.expiration_time = UINT64_MAX;
2205     rd.record_type = GNUNET_DNSPARSER_TYPE_A;
2206     rd.flags = 0;
2207     rh->proc (rh->proc_cls, 1, &rd);
2208     GNS_resolver_lookup_cancel (rh);
2209     return;
2210   }
2211   if (1 == inet_pton (AF_INET6,
2212                       rh->name,
2213                       &v6))
2214   {
2215     /* name is IPv6 address, pretend it's an AAAA record */
2216     struct GNUNET_GNSRECORD_Data rd;
2217
2218     rd.data = &v6;
2219     rd.data_size = sizeof (v6);
2220     rd.expiration_time = UINT64_MAX;
2221     rd.record_type = GNUNET_DNSPARSER_TYPE_AAAA;
2222     rd.flags = 0;
2223     rh->proc (rh->proc_cls, 1, &rd);
2224     GNS_resolver_lookup_cancel (rh);
2225     return;
2226   }
2227   if ( ( (GNUNET_YES == is_canonical (rh->name)) &&
2228          (0 != strcmp (GNUNET_GNS_TLD, rh->name)) ) ||
2229        ( (GNUNET_YES != is_gnu_tld (rh->name)) &&
2230          (GNUNET_YES != is_zkey_tld (rh->name)) ) )
2231   {
2232     /* use standard DNS lookup */
2233     int af;
2234
2235     switch (rh->record_type)
2236     {
2237     case GNUNET_DNSPARSER_TYPE_A:
2238       af = AF_INET;
2239       break;
2240     case GNUNET_DNSPARSER_TYPE_AAAA:
2241       af = AF_INET6;
2242       break;
2243     default:
2244       af = AF_UNSPEC;
2245       break;
2246     }
2247     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2248                 "Doing standard DNS lookup for `%s'\n",
2249                 rh->name);
2250     rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name,
2251                                               af,
2252                                               DNS_LOOKUP_TIMEOUT,
2253                                               &handle_dns_result,
2254                                               rh);
2255     return;
2256   }
2257   if (is_zkey_tld (rh->name))
2258   {
2259     /* Name ends with ".zkey", try to replace authority zone with zkey
2260        authority */
2261     GNUNET_free (resolver_lookup_get_next_label (rh)); /* will return "zkey" */
2262     y = resolver_lookup_get_next_label (rh); /* will return 'y' coordinate */
2263     if ( (NULL == y) ||
2264          (GNUNET_OK !=
2265           GNUNET_CRYPTO_ecdsa_public_key_from_string (y,
2266                                                       strlen (y),
2267                                                       &rh->authority_zone)) )
2268     {
2269       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2270                   _("Hostname `%s' is not well-formed, resolution fails\n"),
2271                   rh->name);
2272       rh->task_id = GNUNET_SCHEDULER_add_now (&fail_resolution, rh);
2273     }
2274     GNUNET_free_non_null (y);
2275   }
2276   else
2277   {
2278     /* Name ends with ".gnu", eat ".gnu" and continue with resolution */
2279     GNUNET_free (resolver_lookup_get_next_label (rh));
2280   }
2281   ac = GNUNET_new (struct AuthorityChain);
2282   ac->rh = rh;
2283   ac->label = resolver_lookup_get_next_label (rh);
2284   ac->suggested_shortening_label = NULL;
2285   if (NULL == ac->label)
2286     /* name was just "gnu", so we default to label '+' */
2287     ac->label = GNUNET_strdup (GNUNET_GNS_MASTERZONE_STR);
2288   ac->gns_authority = GNUNET_YES;
2289   ac->authority_info.gns_authority = rh->authority_zone;
2290   GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
2291                                     rh->ac_tail,
2292                                     ac);
2293   rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
2294                                           rh);
2295 }
2296
2297
2298 /**
2299  * Lookup of a record in a specific zone calls lookup result processor
2300  * on result.
2301  *
2302  * @param zone the zone to perform the lookup in
2303  * @param record_type the record type to look up
2304  * @param name the name to look up
2305  * @param shorten_key a private key for use with PSEU import (can be NULL)
2306  * @param only_cached #GNUNET_NO to only check locally not DHT for performance
2307  * @param proc the processor to call on result
2308  * @param proc_cls the closure to pass to @a proc
2309  * @return handle to cancel operation
2310  */
2311 struct GNS_ResolverHandle *
2312 GNS_resolver_lookup (const struct GNUNET_CRYPTO_EcdsaPublicKey *zone,
2313                      uint32_t record_type,
2314                      const char *name,
2315                      const struct GNUNET_CRYPTO_EcdsaPrivateKey *shorten_key,
2316                      int only_cached,
2317                      GNS_ResultProcessor proc, void *proc_cls)
2318 {
2319   struct GNS_ResolverHandle *rh;
2320
2321   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2322               (NULL == shorten_key)
2323               ? "Starting lookup for `%s' with shortening disabled\n"
2324               : "Starting lookup for `%s' with shortening enabled\n",
2325               name);
2326   rh = GNUNET_new (struct GNS_ResolverHandle);
2327   GNUNET_CONTAINER_DLL_insert (rlh_head,
2328                                rlh_tail,
2329                                rh);
2330   rh->authority_zone = *zone;
2331   rh->proc = proc;
2332   rh->proc_cls = proc_cls;
2333   rh->only_cached = only_cached;
2334   rh->record_type = record_type;
2335   rh->name = GNUNET_strdup (name);
2336   rh->name_resolution_pos = strlen (name);
2337   if (NULL != shorten_key)
2338   {
2339     rh->shorten_key = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
2340     *rh->shorten_key = *shorten_key;
2341   }
2342   start_resolver_lookup (rh);
2343   return rh;
2344 }
2345
2346
2347 /**
2348  * Cancel active resolution (i.e. client disconnected).
2349  *
2350  * @param rh resolution to abort
2351  */
2352 void
2353 GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
2354 {
2355   struct DnsResult *dr;
2356   struct AuthorityChain *ac;
2357   struct VpnContext *vpn_ctx;
2358
2359   GNUNET_CONTAINER_DLL_remove (rlh_head,
2360                                rlh_tail,
2361                                rh);
2362   while (NULL != (ac = rh->ac_head))
2363   {
2364     GNUNET_CONTAINER_DLL_remove (rh->ac_head,
2365                                  rh->ac_tail,
2366                                  ac);
2367     GNUNET_free (ac->label);
2368     GNUNET_free_non_null (ac->suggested_shortening_label);
2369     GNUNET_free (ac);
2370   }
2371   if (NULL != rh->g2dc)
2372   {
2373     /* rh->g2dc->rh is NOT in the DLL yet, so to enable us
2374        using GNS_resolver_lookup_cancel here, we need to
2375        add it first... */
2376     if (NULL != rh->g2dc->rh)
2377     {
2378       GNUNET_CONTAINER_DLL_insert (rlh_head,
2379                                    rlh_tail,
2380                                    rh->g2dc->rh);
2381       GNS_resolver_lookup_cancel (rh->g2dc->rh);
2382       rh->g2dc->rh = NULL;
2383     }
2384     GNUNET_free (rh->g2dc->ns);
2385     GNUNET_free (rh->g2dc);
2386     rh->g2dc = NULL;
2387   }
2388   if (GNUNET_SCHEDULER_NO_TASK != rh->task_id)
2389   {
2390     GNUNET_SCHEDULER_cancel (rh->task_id);
2391     rh->task_id = GNUNET_SCHEDULER_NO_TASK;
2392   }
2393   if (NULL != rh->get_handle)
2394   {
2395     GNUNET_DHT_get_stop (rh->get_handle);
2396     rh->get_handle = NULL;
2397   }
2398   if (NULL != rh->dht_heap_node)
2399   {
2400     GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
2401     rh->dht_heap_node = NULL;
2402   }
2403   if (NULL != (vpn_ctx = rh->vpn_ctx))
2404   {
2405     GNUNET_VPN_cancel_request (vpn_ctx->vpn_request);
2406     GNUNET_free (vpn_ctx->rd_data);
2407     GNUNET_free (vpn_ctx);
2408   }
2409   if (NULL != rh->dns_request)
2410   {
2411     GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
2412     rh->dns_request = NULL;
2413   }
2414   if (NULL != rh->namecache_qe)
2415   {
2416     GNUNET_NAMECACHE_cancel (rh->namecache_qe);
2417     rh->namecache_qe = NULL;
2418   }
2419   if (NULL != rh->rev_check)
2420   {
2421     GNUNET_REVOCATION_query_cancel (rh->rev_check);
2422     rh->rev_check = NULL;
2423   }
2424   if (NULL != rh->std_resolve)
2425   {
2426     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2427                 "Canceling standard DNS resolution\n");
2428     GNUNET_RESOLVER_request_cancel (rh->std_resolve);
2429     rh->std_resolve = NULL;
2430   }
2431   while (NULL != (dr = rh->dns_result_head))
2432   {
2433     GNUNET_CONTAINER_DLL_remove (rh->dns_result_head,
2434                                  rh->dns_result_tail,
2435                                  dr);
2436     GNUNET_free (dr);
2437   }
2438   GNUNET_free_non_null (rh->shorten_key);
2439   GNUNET_free (rh->name);
2440   GNUNET_free (rh);
2441 }
2442
2443
2444 /* ***************** Resolver initialization ********************* */
2445
2446
2447 /**
2448  * Initialize the resolver
2449  *
2450  * @param nc the namecache handle
2451  * @param dht the dht handle
2452  * @param c configuration handle
2453  * @param max_bg_queries maximum number of parallel background queries in dht
2454  */
2455 void
2456 GNS_resolver_init (struct GNUNET_NAMECACHE_Handle *nc,
2457                    struct GNUNET_DHT_Handle *dht,
2458                    const struct GNUNET_CONFIGURATION_Handle *c,
2459                    unsigned long long max_bg_queries)
2460 {
2461   char *dns_ip;
2462
2463   cfg = c;
2464   namecache_handle = nc;
2465   dht_handle = dht;
2466   dht_lookup_heap =
2467     GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
2468   max_allowed_background_queries = max_bg_queries;
2469   if (GNUNET_SYSERR == (use_cache = GNUNET_CONFIGURATION_get_value_yesno (c,
2470                                              "gns",
2471                                              "USE_CACHE")))
2472     use_cache = GNUNET_YES;
2473   if (GNUNET_NO == use_cache)
2474     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Namecache disabled\n");
2475
2476   if (GNUNET_OK !=
2477       GNUNET_CONFIGURATION_get_value_string (c,
2478                                              "gns",
2479                                              "DNS_RESOLVER",
2480                                              &dns_ip))
2481   {
2482     /* user did not specify DNS resolver, use 8.8.8.8 */
2483     dns_ip = GNUNET_strdup ("8.8.8.8");
2484   }
2485   dns_handle = GNUNET_DNSSTUB_start (dns_ip);
2486   GNUNET_free (dns_ip);
2487   vpn_handle = GNUNET_VPN_connect (cfg);
2488 }
2489
2490
2491 /**
2492  * Shutdown resolver
2493  */
2494 void
2495 GNS_resolver_done ()
2496 {
2497   struct GNS_ResolverHandle *rh;
2498   struct CacheOps *co;
2499
2500   /* abort active resolutions */
2501   while (NULL != (rh = rlh_head))
2502   {
2503     rh->proc (rh->proc_cls, 0, NULL);
2504     GNS_resolver_lookup_cancel (rh);
2505   }
2506   while (NULL != (co = co_head))
2507   {
2508     GNUNET_CONTAINER_DLL_remove (co_head,
2509                                  co_tail,
2510                                  co);
2511     GNUNET_NAMECACHE_cancel (co->namecache_qe_cache);
2512     GNUNET_free (co);
2513   }
2514   GNUNET_CONTAINER_heap_destroy (dht_lookup_heap);
2515   dht_lookup_heap = NULL;
2516   GNUNET_DNSSTUB_stop (dns_handle);
2517   dns_handle = NULL;
2518   GNUNET_VPN_disconnect (vpn_handle);
2519   vpn_handle = NULL;
2520   dht_handle = NULL;
2521   namecache_handle = NULL;
2522 }
2523
2524
2525 /* *************** common helper functions (do not really belong here) *********** */
2526
2527 /**
2528  * Checks if @a name ends in ".TLD"
2529  *
2530  * @param name the name to check
2531  * @param tld the TLD to check for
2532  * @return GNUNET_YES or GNUNET_NO
2533  */
2534 int
2535 is_tld (const char* name, const char* tld)
2536 {
2537   size_t offset = 0;
2538
2539   if (strlen (name) <= strlen (tld))
2540     return GNUNET_NO;
2541   offset = strlen (name) - strlen (tld);
2542   if (0 != strcmp (name + offset, tld))
2543     return GNUNET_NO;
2544   return GNUNET_YES;
2545 }
2546
2547
2548 /* end of gnunet-service-gns_resolver.c */