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