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