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