0fb6ffbd182d0a3886bb0a4d53e7dffa74ec55a4
[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 GNUnet GNS 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'.
30  * - GNS: expand ".+" in returned values to the respective absolute
31  *        name using '.zkey'
32  * - recursive DNS resolution
33  * - shortening triggers
34  * - revocation checks (make optional: privacy!)
35  *
36  * Issues:
37  * - We currently go to the DHT simply if we find no local reply; this
38  *   is incorrect; the correct rules for going to DHT are:
39  *
40  * 1. The entry in the DHT is RSL_RECORD_EXPIRED OR
41  * 2. No entry in the NS existed AND
42  * 3. The zone queried is not the local resolver's zone AND
43  * 4. The name that was looked up is '+'
44  *    because if it was any other canonical name we either already queried
45  *    the DHT for the authority in the authority lookup phase (and thus
46  *    would already have an entry in the NS for the record)
47  * 5. We are not in cache only mode
48  *
49  * - We currently never look "into" the records; for example,
50  *   MX, SRV and SOA records may include ".+" that need to be
51  *   handled
52  *
53  */
54 #include "platform.h"
55 #include "gnunet_util_lib.h"
56 #include "gnunet_dnsstub_lib.h"
57 #include "gnunet_dht_service.h"
58 #include "gnunet_namestore_service.h"
59 #include "gnunet_dns_service.h"
60 #include "gnunet_resolver_service.h"
61 #include "gnunet_dnsparser_lib.h"
62 #include "gnunet_gns_service.h"
63 #include "gns.h"
64 #include "gnunet-service-gns_resolver.h"
65 #include "gnunet-service-gns_shorten.h"
66 #include "gnunet_vpn_service.h"
67
68
69 /**
70  * Default DHT timeout for lookups.
71  */
72 #define DHT_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
73
74 /**
75  * Default timeout for DNS lookups.
76  */
77 #define DNS_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
78
79 /**
80  * Default timeout for VPN redirections.
81  */
82 #define VPN_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
83
84 /**
85  * DHT replication level
86  */
87 #define DHT_GNS_REPLICATION_LEVEL 5
88
89 /**
90  * How deep do we allow recursions to go before we abort?
91  */
92 #define MAX_RECURSION 256
93
94
95 /**
96  * DLL to hold the authority chain we had to pass in the resolution
97  * process.
98  */
99 struct AuthorityChain
100 {
101   /**
102    * This is a DLL.
103    */
104   struct AuthorityChain *prev;
105
106   /**
107    * This is a DLL.
108    */
109   struct AuthorityChain *next;
110
111   /**
112    * Resolver handle this entry in the chain belongs to.
113    */
114   struct GNS_ResolverHandle *rh;
115
116   /**
117    * label/name corresponding to the authority 
118    */
119   char *label;
120   
121   /**
122    * #GNUNET_YES if the authority was a GNS authority,
123    * #GNUNET_NO if the authority was a DNS authority.
124    */
125   int gns_authority;
126
127   /**
128    * Information about the resolver authority for this label.
129    */
130   union
131   {
132
133     /**
134      * The zone of the GNS authority 
135      */
136     struct GNUNET_CRYPTO_EccPublicKey gns_authority;
137
138     struct
139     {
140       /**
141        * Domain of the DNS resolver that is the authority.
142        * (appended to construct the DNS name to resolve;
143        * this is NOT the DNS name of the DNS server!).
144        */
145       char name[GNUNET_DNSPARSER_MAX_NAME_LENGTH + 1];
146
147       /**
148        * IP address of the DNS resolver that is authoritative.
149        * (this implementation currently only supports one
150        * IP at a time).
151        */
152       struct sockaddr_storage dns_ip;
153
154     } dns_authority;
155
156   } authority_info;
157   
158 };
159
160
161 /**
162  * A result we got from DNS.
163  */
164 struct DnsResult
165 {
166
167   /**
168    * Kept in DLL.
169    */
170   struct DnsResult *next;
171
172   /**
173    * Kept in DLL.
174    */
175   struct DnsResult *prev;
176
177   /**
178    * Binary value stored in the DNS record (appended to this struct)
179    */
180   const void *data;
181
182   /**
183    * Expiration time for the DNS record, 0 if we didn't
184    * get anything useful (i.e. 'gethostbyname' was used).
185    */
186   uint64_t expiration_time;
187
188   /**
189    * Number of bytes in 'data'.
190    */
191   size_t data_size;
192
193   /**
194    * Type of the GNS/DNS record.
195    */
196   uint32_t record_type;
197
198 };
199
200
201 /**
202  * Closure for #vpn_allocation_cb.
203  */
204 struct VpnContext 
205 {
206
207   /** 
208    * Which resolution process are we processing.
209    */
210   struct GNS_ResolverHandle *rh;
211
212   /**
213    * Handle to the VPN request that we were performing.
214    */
215   struct GNUNET_VPN_RedirectionRequest *vpn_request;
216
217   /**
218    * Number of records serialized in 'rd_data'.
219    */
220   unsigned int rd_count;
221   
222   /**
223    * Serialized records.
224    */
225   char *rd_data;
226   
227   /**
228    * Number of bytes in 'rd_data'.
229    */
230   size_t rd_data_size;
231 };
232
233
234 /**
235  * Handle to a currenty pending resolution.  On result (positive or
236  * negative) the #GNS_ResultProcessor is called.  
237  */
238 struct GNS_ResolverHandle
239 {
240
241   /**
242    * DLL 
243    */
244   struct GNS_ResolverHandle *next;
245
246   /**
247    * DLL 
248    */
249   struct GNS_ResolverHandle *prev;
250
251   /**
252    * The top-level GNS authoritative zone to query 
253    */
254   struct GNUNET_CRYPTO_EccPublicKey authority_zone;
255
256   /**
257    * called when resolution phase finishes 
258    */
259   GNS_ResultProcessor proc;
260   
261   /**
262    * closure passed to proc 
263    */
264   void* proc_cls;
265
266   /**
267    * Handle for DHT lookups. should be NULL if no lookups are in progress 
268    */
269   struct GNUNET_DHT_GetHandle *get_handle;
270
271   /**
272    * Handle to a VPN request, NULL if none is active.
273    */
274   struct VpnContext *vpn_ctx;
275
276   /**
277    * Socket for a DNS request, NULL if none is active.
278    */
279   struct GNUNET_DNSSTUB_RequestSocket *dns_request;
280
281   /**
282    * Handle for standard DNS resolution, NULL if none is active.
283    */
284   struct GNUNET_RESOLVER_RequestHandle *std_resolve;
285
286   /**
287    * Pending Namestore task
288    */
289   struct GNUNET_NAMESTORE_QueueEntry *namestore_qe;
290
291   /**
292    * Heap node associated with this lookup.  Used to limit number of
293    * concurrent requests.
294    */
295   struct GNUNET_CONTAINER_HeapNode *dht_heap_node;
296
297   /**
298    * DLL to store the authority chain 
299    */
300   struct AuthorityChain *ac_head;
301
302   /**
303    * DLL to store the authority chain 
304    */
305   struct AuthorityChain *ac_tail;
306
307   /**
308    * Private key of the shorten zone, NULL to not shorten.
309    */
310   struct GNUNET_CRYPTO_EccPrivateKey *shorten_key;
311
312   /**
313    * ID of a task associated with the resolution process.
314    */
315   GNUNET_SCHEDULER_TaskIdentifier task_id;
316
317   /**
318    * The name to resolve 
319    */
320   char *name;
321
322   /**
323    * DLL of results we got from DNS.
324    */
325   struct DnsResult *dns_result_head;
326
327   /**
328    * DLL of results we got from DNS.
329    */
330   struct DnsResult *dns_result_tail;
331
332   /**
333    * Current offset in 'name' where we are resolving.
334    */
335   size_t name_resolution_pos;
336
337   /**
338    * Use only cache 
339    */
340   int only_cached;
341
342   /**
343    * Desired type for the resolution.
344    */
345   int record_type;
346
347   /**
348    * We increment the loop limiter for each step in a recursive
349    * resolution.  If it passes our threshold (i.e. due to 
350    * self-recursion in the resolution, i.e CNAME fun), we stop.
351    */
352   unsigned int loop_limiter;
353
354 };
355
356
357 /**
358  * Our handle to the namestore service
359  */
360 static struct GNUNET_NAMESTORE_Handle *namestore_handle;
361
362 /**
363  * Our handle to the vpn service
364  */
365 static struct GNUNET_VPN_Handle *vpn_handle;
366
367 /**
368  * Resolver handle to the dht
369  */
370 static struct GNUNET_DHT_Handle *dht_handle;
371
372 /**
373  * Handle to perform DNS lookups.
374  */
375 static struct GNUNET_DNSSTUB_Context *dns_handle;
376
377 /**
378  * Heap for limiting parallel DHT lookups
379  */
380 static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
381
382 /**
383  * Maximum amount of parallel queries to the DHT
384  */
385 static unsigned long long max_allowed_background_queries;
386
387 /**
388  * Head of resolver lookup list
389  */
390 static struct GNS_ResolverHandle *rlh_head;
391
392 /**
393  * Tail of resolver lookup list
394  */
395 static struct GNS_ResolverHandle *rlh_tail;
396
397 /**
398  * Global configuration.
399  */
400 static const struct GNUNET_CONFIGURATION_Handle *cfg;
401
402
403 /**
404  * Check if name is in srv format (_x._y.xxx)
405  *
406  * @param name
407  * @return GNUNET_YES if true
408  */
409 static int
410 is_srv (const char *name)
411 {
412   char *ndup;
413   int ret;
414
415   if (*name != '_')
416     return GNUNET_NO;
417   if (NULL == strstr (name, "._"))
418     return GNUNET_NO;
419   ret = GNUNET_YES;
420   ndup = GNUNET_strdup (name);
421   strtok (ndup, ".");
422   if (NULL == strtok (NULL, "."))
423     ret = GNUNET_NO;
424   if (NULL == strtok (NULL, "."))
425     ret = GNUNET_NO;
426   if (NULL != strtok (NULL, "."))
427     ret = GNUNET_NO;
428   GNUNET_free (ndup);
429   return ret;
430 }
431
432
433 /**
434  * Determine if this name is canonical (is a legal name in a zone, without delegation);
435  * note that we do not test that the name does not contain illegal characters, we only
436  * test for delegation.  Note that service records (i.e. _foo._srv) are canonical names
437  * even though they consist of multiple labels.
438  *
439  * Examples:
440  * a.b.gnu  = not canonical
441  * a         = canonical
442  * _foo._srv = canonical
443  * _f.bar    = not canonical
444  *
445  * @param name the name to test
446  * @return GNUNET_YES if canonical
447  */
448 static int
449 is_canonical (const char *name)
450 {
451   const char *pos;
452   const char *dot;
453
454   if (NULL == strchr (name, '.'))
455     return GNUNET_YES;
456   if ('_' != name[0])
457     return GNUNET_NO;
458   pos = &name[1];
459   while (NULL != (dot = strchr (pos, '.')))    
460     if ('_' != dot[1])
461       return GNUNET_NO;
462     else
463       pos = dot + 1;
464   return GNUNET_YES;
465 }
466
467
468
469 /* ************************** Resolution **************************** */
470
471 #if 0
472
473
474 //FIXME maybe define somewhere else?
475 #define MAX_SOA_LENGTH sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)\
476                         +(GNUNET_DNSPARSER_MAX_NAME_LENGTH*2)
477 #define MAX_MX_LENGTH sizeof(uint16_t)+GNUNET_DNSPARSER_MAX_NAME_LENGTH
478 #define MAX_SRV_LENGTH (sizeof(uint16_t)*3)+GNUNET_DNSPARSER_MAX_NAME_LENGTH
479
480
481 /**
482  * Exands a name ending in .+ with the zone of origin.
483  * FIXME: funky api: 'dest' must be large enough to hold
484  * the result; this is a bit yucky...
485  *
486  * @param dest destination buffer
487  * @param src the .+ name
488  * @param repl the string to replace the + with
489  */
490 static void
491 expand_plus (char* dest, 
492              const char* src, 
493              const char* repl)
494 {
495   char* pos;
496   size_t s_len = strlen (src) + 1;
497
498   //Eh? I guess this is at least strlen ('x.+') == 3 FIXME
499   if (3 > s_len)
500   {
501     /* no postprocessing */
502     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
503                "GNS_POSTPROCESS: %s too short\n", src);
504     memcpy (dest, src, s_len);
505     return;
506   }
507   if (0 == strcmp (src + s_len - 3, ".+"))
508   {
509     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
510                 "GNS_POSTPROCESS: Expanding .+ in %s\n", 
511                 src);
512     memset (dest, 0, s_len + strlen (repl) + strlen(GNUNET_GNS_TLD));
513     strcpy (dest, src);
514     pos = dest + s_len - 2;
515     strcpy (pos, repl);
516     pos += strlen (repl);
517     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
518                 "GNS_POSTPROCESS: Expanded to %s\n", 
519                 dest);
520   }
521   else
522   {
523     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
524                "GNS_POSTPROCESS: No postprocessing for %s\n", src);
525     memcpy (dest, src, s_len);
526   }
527 }
528
529
530 /**
531  * finish lookup
532  */
533 static void
534 finish_lookup (struct ResolverHandle *rh,
535                struct RecordLookupHandle* rlh,
536                unsigned int rd_count,
537                const struct GNUNET_NAMESTORE_RecordData *rd)
538 {
539   unsigned int i;
540   char new_rr_data[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
541   char new_mx_data[MAX_MX_LENGTH];
542   char new_soa_data[MAX_SOA_LENGTH];
543   char new_srv_data[MAX_SRV_LENGTH];
544   struct GNUNET_TUN_DnsSrvRecord *old_srv;
545   struct GNUNET_TUN_DnsSrvRecord *new_srv;
546   struct GNUNET_TUN_DnsSoaRecord *old_soa;
547   struct GNUNET_TUN_DnsSoaRecord *new_soa;
548   struct GNUNET_NAMESTORE_RecordData p_rd[rd_count];
549   char* repl_string;
550   char* pos;
551   unsigned int offset;
552
553   if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
554   {
555     GNUNET_SCHEDULER_cancel(rh->timeout_task);
556     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
557   }
558
559   GNUNET_CONTAINER_DLL_remove (rlh_head, rlh_tail, rh);
560
561   if (0 < rd_count)
562     memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData));
563
564   for (i = 0; i < rd_count; i++)
565   {
566     
567     if ((GNUNET_DNSPARSER_TYPE_NS != rd[i].record_type) &&
568         (GNUNET_DNSPARSER_TYPE_PTR != rd[i].record_type) &&
569         (GNUNET_DNSPARSER_TYPE_CNAME != rd[i].record_type) &&
570         (GNUNET_DNSPARSER_TYPE_MX != rd[i].record_type) &&
571         (GNUNET_DNSPARSER_TYPE_SOA != rd[i].record_type) &&
572         (GNUNET_DNSPARSER_TYPE_SRV != rd[i].record_type))
573     {
574       p_rd[i].data = rd[i].data;
575       continue;
576     }
577
578     /**
579      * for all those records we 'should'
580      * also try to resolve the A/AAAA records (RFC1035)
581      * This is a feature and not important
582      */
583     
584     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
585                "GNS_POSTPROCESS: Postprocessing\n");
586     if (0 == strcmp(rh->name, GNUNET_GNS_MASTERZONE_STR))
587       repl_string = rlh->name;
588     else
589       repl_string = rlh->name+strlen(rh->name)+1;
590
591     offset = 0;
592     if (GNUNET_DNSPARSER_TYPE_MX == rd[i].record_type)
593     {
594       memcpy (new_mx_data, (char*)rd[i].data, sizeof(uint16_t));
595       offset = sizeof (uint16_t);
596       pos = new_mx_data + offset;
597       // FIXME: how do we know that 'pos' has enough space for the new name?
598       expand_plus (pos, (char*)rd[i].data+sizeof(uint16_t),
599                    repl_string);
600       offset += strlen(new_mx_data+sizeof(uint16_t)) + 1;
601       p_rd[i].data = new_mx_data;
602       p_rd[i].data_size = offset;
603     }
604     else if (GNUNET_DNSPARSER_TYPE_SRV == rd[i].record_type)
605     {
606       /*
607        * Prio, weight and port
608        */
609       new_srv = (struct GNUNET_TUN_DnsSrvRecord*)new_srv_data;
610       old_srv = (struct GNUNET_TUN_DnsSrvRecord*)rd[i].data;
611       new_srv->prio = old_srv->prio;
612       new_srv->weight = old_srv->weight;
613       new_srv->port = old_srv->port;
614       // FIXME: how do we know that '&new_srv[1]' has enough space for the new name?
615       expand_plus((char*)&new_srv[1], (char*)&old_srv[1],
616                   repl_string);
617       p_rd[i].data = new_srv_data;
618       p_rd[i].data_size = sizeof (struct GNUNET_TUN_DnsSrvRecord) + strlen ((char*)&new_srv[1]) + 1;
619     }
620     else if (GNUNET_DNSPARSER_TYPE_SOA == rd[i].record_type)
621     {
622       /* expand mname and rname */
623       old_soa = (struct GNUNET_TUN_DnsSoaRecord*)rd[i].data;
624       new_soa = (struct GNUNET_TUN_DnsSoaRecord*)new_soa_data;
625       memcpy (new_soa, old_soa, sizeof (struct GNUNET_TUN_DnsSoaRecord));
626       // FIXME: how do we know that 'new_soa[1]' has enough space for the new name?
627       expand_plus((char*)&new_soa[1], (char*)&old_soa[1], repl_string);
628       offset = strlen ((char*)&new_soa[1]) + 1;
629       // FIXME: how do we know that 'new_soa[1]' has enough space for the new name?
630       expand_plus((char*)&new_soa[1] + offset,
631                   (char*)&old_soa[1] + strlen ((char*)&old_soa[1]) + 1,
632                   repl_string);
633       p_rd[i].data_size = sizeof (struct GNUNET_TUN_DnsSoaRecord)
634                           + offset
635                           + strlen ((char*)&new_soa[1] + offset);
636       p_rd[i].data = new_soa_data;
637     }
638     else
639     {
640       pos = new_rr_data;
641       // FIXME: how do we know that 'rd[i].data' has enough space for the new name?
642       expand_plus(pos, (char*)rd[i].data, repl_string);
643       p_rd[i].data_size = strlen(new_rr_data)+1;
644       p_rd[i].data = new_rr_data;
645     }
646     
647   }
648
649   rlh->proc(rlh->proc_cls, rd_count, p_rd);
650   GNUNET_free(rlh);
651   free_resolver_handle (rh);
652 }
653
654
655 #endif
656
657 ///////////////////////////////////////////////////////////////////////////////////////////////////
658 ///////////////////////////////////////////////////////////////////////////////////////////////////
659 ///////////////////////////////////////////////////////////////////////////////////////////////////
660 ///////////////////////////////////////////////////////////////////////////////////////////////////
661 ///////////////////////////////////////////////////////////////////////////////////////////////////
662
663
664 /**
665  * Task scheduled to asynchronously fail a resolution.
666  *
667  * @param cls the 'struct GNS_ResolverHandle' of the resolution to fail
668  * @param tc task context
669  */
670 static void
671 fail_resolution (void *cls,
672                  const struct GNUNET_SCHEDULER_TaskContext *tc)
673 {
674   struct GNS_ResolverHandle *rh = cls;
675
676   rh->task_id = GNUNET_SCHEDULER_NO_TASK;
677   rh->proc (rh->proc_cls, 0, NULL);
678   GNS_resolver_lookup_cancel (rh);
679 }
680
681 #ifdef WINDOWS
682 /* Don't have this on W32, here's a naive implementation */
683 void *
684 memrchr (const void *s, int c, size_t n)
685 {
686   size_t i;
687   unsigned char *ucs = (unsigned char *) s;
688
689   for (i = n - 1; i >= 0; i--)
690     if (ucs[i] == c)
691       return (void *) &ucs[i];
692   return NULL;
693 }
694 #endif
695
696 /**
697  * Get the next, rightmost label from the name that we are trying to resolve,
698  * and update the resolution position accordingly.
699  *
700  * @param rh handle to the resolution operation to get the next label from
701  * @return NULL if there are no more labels
702  */
703 static char *
704 resolver_lookup_get_next_label (struct GNS_ResolverHandle *rh)
705 {
706   const char *rp;
707   const char *dot;
708   size_t len;
709
710   if (0 == rh->name_resolution_pos)
711     return NULL;
712   dot = memrchr (rh->name, (int) '.', rh->name_resolution_pos);
713   if (NULL == dot)
714   {
715     /* done, this was the last one */
716     len = rh->name_resolution_pos;
717     rp = rh->name;
718     rh->name_resolution_pos = 0; 
719   }
720   else
721   {
722     /* advance by one label */
723     len = rh->name_resolution_pos - (dot - rh->name) - 1;
724     rp = dot + 1;
725     rh->name_resolution_pos = dot - rh->name;
726   }  
727   return GNUNET_strndup (rp, len);  
728 }
729
730
731 /**
732  * Gives the cummulative result obtained to the callback and clean up the request.
733  *
734  * @param rh resolution process that has culminated in a result
735  */
736 static void
737 transmit_lookup_dns_result (struct GNS_ResolverHandle *rh)
738 {
739   struct DnsResult *pos;
740   unsigned int n;
741   unsigned int i;
742
743   n = 0;
744   for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
745     n++;
746   {
747     struct GNUNET_NAMESTORE_RecordData rd[n];
748
749     i = 0;
750     for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
751     {
752       rd[i].data = pos->data;
753       rd[i].data_size = pos->data_size;
754       rd[i].record_type = pos->record_type;
755       if (0 == pos->expiration_time)
756       {
757         rd[i].flags = GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION;
758         rd[i].expiration_time = 0;
759       }
760       else
761       {
762         rd[i].flags = GNUNET_NAMESTORE_RF_NONE;
763         rd[i].expiration_time = pos->expiration_time;
764       }
765     }      
766     rh->proc (rh->proc_cls,
767               n,
768               rd);
769   }
770   GNS_resolver_lookup_cancel (rh);
771 }
772
773
774 /**
775  * Add a result from DNS to the records to be returned to the application.
776  *
777  * @param rh resolution request to extend with a result
778  * @param expiration_time expiration time for the answer
779  * @param record_type DNS record type of the answer
780  * @param data_size number of bytes in @a data
781  * @param data binary data to return in DNS record
782  */
783 static void
784 add_dns_result (struct GNS_ResolverHandle *rh,
785                 uint64_t expiration_time,
786                 uint32_t record_type,
787                 size_t data_size,
788                 const void *data)
789 {
790   struct DnsResult *res;
791
792   res = GNUNET_malloc (sizeof (struct DnsResult) + data_size);
793   res->expiration_time = expiration_time;
794   res->data_size = data_size;
795   res->record_type = record_type;
796   res->data = &res[1];
797   memcpy (&res[1], data, data_size);
798   GNUNET_CONTAINER_DLL_insert (rh->dns_result_head,
799                                rh->dns_result_tail,
800                                res);
801 }
802
803
804 /**
805  * We had to do a DNS lookup.  Convert the result (if any) and return
806  * it.
807  *
808  * @param cls closure with the 'struct GNS_ResolverHandle'
809  * @param addr one of the addresses of the host, NULL for the last address
810  * @param addrlen length of the address
811  */
812 static void
813 handle_dns_result (void *cls,
814                    const struct sockaddr *addr,
815                    socklen_t addrlen)
816 {
817   struct GNS_ResolverHandle *rh = cls;
818   const struct sockaddr_in *sa4;
819   const struct sockaddr_in6 *sa6;
820
821   rh->std_resolve = NULL;
822   if (NULL == addr)
823   {
824     transmit_lookup_dns_result (rh);
825     return;
826   }
827   switch (addr->sa_family)
828   {
829   case AF_INET:
830     sa4 = (const struct sockaddr_in *) addr;
831     add_dns_result (rh,
832                     0 /* expiration time is unknown */,
833                     GNUNET_DNSPARSER_TYPE_A,
834                     sizeof (struct in_addr),
835                     &sa4->sin_addr);
836     break;
837   case AF_INET6:
838     sa6 = (const struct sockaddr_in6 *) addr;
839     add_dns_result (rh,
840                     0 /* expiration time is unknown */,
841                     GNUNET_DNSPARSER_TYPE_AAAA,
842                     sizeof (struct in6_addr),
843                     &sa6->sin6_addr);
844     break;
845   default:
846     GNUNET_break (0);
847     break;
848   }
849 }
850
851
852 /**
853  * Task scheduled to continue with the resolution process.
854  *
855  * @param cls the 'struct GNS_ResolverHandle' of the resolution
856  * @param tc task context
857  */
858 static void
859 recursive_resolution (void *cls,
860                       const struct GNUNET_SCHEDULER_TaskContext *tc);
861
862
863 /**
864  * Function called with the result of a DNS resolution.
865  *
866  * @param cls the request handle of the resolution that
867  *        we were attempting to make
868  * @param rs socket that received the response
869  * @param dns dns response, never NULL
870  * @param dns_len number of bytes in 'dns'
871  */
872 static void
873 dns_result_parser (void *cls,
874                    struct GNUNET_DNSSTUB_RequestSocket *rs,
875                    const struct GNUNET_TUN_DnsHeader *dns,
876                    size_t dns_len)
877 {
878   struct GNS_ResolverHandle *rh = cls;
879   struct GNUNET_DNSPARSER_Packet *p;
880
881   rh->dns_request = NULL;
882   GNUNET_SCHEDULER_cancel (rh->task_id);
883   rh->task_id = GNUNET_SCHEDULER_NO_TASK;
884   p = GNUNET_DNSPARSER_parse ((const char *) dns, 
885                               dns_len);
886   if (NULL == p)
887   {
888     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
889                 _("Failed to parse DNS response\n"));
890     rh->proc (rh->proc_cls, 0, NULL);
891     GNS_resolver_lookup_cancel (rh);
892     return;
893   }
894   // FIXME: 
895   // Check if the packet is the final answer, or
896   // just pointing us to another NS or another name (CNAME), or another domain (DNAME);
897   // then do the right thing (TM) -- possibly using "recursive_dns_resolution".
898   GNUNET_break (0);
899   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
900               _("NOT IMPLEMENTED\n"));
901   rh->proc (rh->proc_cls, 0, NULL);
902   GNS_resolver_lookup_cancel (rh);
903
904   
905   GNUNET_DNSPARSER_free_packet (p);
906 }
907
908
909 /**
910  * Perform recursive DNS resolution.  Asks the given DNS resolver to
911  * resolve "rh->dns_name", possibly recursively proceeding following
912  * NS delegations, CNAMES, etc., until 'rh->loop_limiter' bounds us or
913  * we find the answer.
914  *
915  * @param rh resolution information
916  */
917 static void
918 recursive_dns_resolution (struct GNS_ResolverHandle *rh)
919 {
920   struct AuthorityChain *ac;
921   socklen_t sa_len;
922   struct GNUNET_DNSPARSER_Query *query;
923   struct GNUNET_DNSPARSER_Packet *p;
924   char *dns_request;
925   size_t dns_request_length;
926
927   ac = rh->ac_tail;
928   GNUNET_assert (NULL != ac);
929   GNUNET_assert (GNUNET_NO == ac->gns_authority);
930   switch (((const struct sockaddr *) &ac->authority_info.dns_authority.dns_ip)->sa_family)
931   {
932   case AF_INET:
933     sa_len = sizeof (struct sockaddr_in);
934     break;
935   case AF_INET6:
936     sa_len = sizeof (struct sockaddr_in6);
937     break;
938   default:
939     GNUNET_break (0);
940     rh->proc (rh->proc_cls, 0, NULL);
941     GNS_resolver_lookup_cancel (rh);
942     return;
943   }
944   query = GNUNET_new (struct GNUNET_DNSPARSER_Query);
945   query->name = GNUNET_strdup (ac->label);
946   query->type = rh->record_type;
947   query->class = GNUNET_TUN_DNS_CLASS_INTERNET;
948   p = GNUNET_new (struct GNUNET_DNSPARSER_Packet);
949   p->queries = query;
950   p->num_queries = 1;
951   p->id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
952                                                UINT16_MAX);
953   p->flags.opcode = GNUNET_TUN_DNS_OPCODE_QUERY;
954   p->flags.recursion_desired = 1;
955   if (GNUNET_OK != 
956       GNUNET_DNSPARSER_pack (p, 1024, &dns_request, &dns_request_length))
957   {
958     GNUNET_break (0);
959     rh->proc (rh->proc_cls, 0, NULL);
960     GNS_resolver_lookup_cancel (rh);
961   }
962   else
963   {
964     rh->dns_request = GNUNET_DNSSTUB_resolve (dns_handle,
965                                               (const struct sockaddr *) &ac->authority_info.dns_authority.dns_ip,
966                                               sa_len,
967                                               dns_request,
968                                               dns_request_length,
969                                               &dns_result_parser,
970                                               rh);
971     rh->task_id = GNUNET_SCHEDULER_add_delayed (DNS_LOOKUP_TIMEOUT,
972                                                 &fail_resolution,
973                                                 rh);
974   }
975   GNUNET_free (dns_request);
976   GNUNET_DNSPARSER_free_packet (p);
977 }
978
979
980 /**
981  * Begin the resolution process from 'name', starting with
982  * the identification of the zone specified by 'name'.
983  *
984  * @param rh resolution to perform
985  */
986 static void
987 start_resolver_lookup (struct GNS_ResolverHandle *rh);
988
989
990 /**
991  * We encountered a CNAME record during our resolution.
992  * Merge it into our chain.
993  *
994  * @param rh resolution we are performing
995  * @param cname value of the cname record we got for the current 
996  *        authority chain tail
997  */
998 static void
999 handle_gns_cname_result (struct GNS_ResolverHandle *rh,
1000                          const char *cname)
1001 {
1002   size_t nlen;
1003   char *res;
1004
1005   nlen = strlen (cname);
1006   if ( (nlen > 2) &&
1007        (0 == strcmp (".+",
1008                      &cname[nlen - 2])) )
1009   {
1010     /* CNAME resolution continues relative to current domain */
1011     if (0 == rh->name_resolution_pos)
1012     {
1013       res = GNUNET_strndup (cname, nlen - 2);
1014       rh->name_resolution_pos = nlen - 2;
1015     }
1016     else
1017     {
1018       GNUNET_asprintf (&res,
1019                        "%.*s.%.*s",
1020                        (int) rh->name_resolution_pos,
1021                        rh->name,
1022                        (int) (nlen - 2),
1023                        cname);
1024       rh->name_resolution_pos = strlen (res);
1025     }
1026     GNUNET_free (rh->name);
1027     rh->name = res;
1028     rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1029                                             rh);
1030     return;
1031   }
1032   /* name is absolute, start from the beginning */
1033   GNUNET_free (rh->name);
1034   rh->name = GNUNET_strdup (cname);
1035   start_resolver_lookup (rh);
1036 }
1037
1038
1039 /**
1040  * Process a records that were decrypted from a block.
1041  *
1042  * @param cls closure with the 'struct GNS_ResolverHandle'
1043  * @param rd_count number of entries in @a rd array
1044  * @param rd array of records with data to store
1045  */
1046 static void
1047 handle_gns_resolution_result (void *cls,
1048                               unsigned int rd_count,
1049                               const struct GNUNET_NAMESTORE_RecordData *rd);
1050
1051
1052 /**
1053  * Callback invoked from the VPN service once a redirection is
1054  * available.  Provides the IP address that can now be used to
1055  * reach the requested destination.  Replaces the "VPN" record
1056  * with the respective A/AAAA record and continues processing.
1057  *
1058  * @param cls closure
1059  * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error;
1060  *                will match 'result_af' from the request
1061  * @param address IP address (struct in_addr or struct in_addr6, depending on 'af')
1062  *                that the VPN allocated for the redirection;
1063  *                traffic to this IP will now be redirected to the 
1064  *                specified target peer; NULL on error
1065  */
1066 static void
1067 vpn_allocation_cb (void *cls,
1068                    int af,
1069                    const void *address)
1070 {
1071   struct VpnContext *vpn_ctx = cls;
1072   struct GNS_ResolverHandle *rh = vpn_ctx->rh;
1073   struct GNUNET_NAMESTORE_RecordData rd[vpn_ctx->rd_count];
1074   unsigned int i;
1075
1076   vpn_ctx->vpn_request = NULL;
1077   rh->vpn_ctx = NULL;
1078   GNUNET_assert (GNUNET_OK ==
1079                  GNUNET_NAMESTORE_records_deserialize (vpn_ctx->rd_data_size,
1080                                                        vpn_ctx->rd_data,
1081                                                        vpn_ctx->rd_count,
1082                                                        rd));
1083   for (i=0;i<vpn_ctx->rd_count;i++)
1084   {
1085     if (GNUNET_NAMESTORE_TYPE_VPN == rd[i].record_type)
1086     {
1087       switch (af)
1088       {
1089       case AF_INET: 
1090         rd[i].record_type = GNUNET_DNSPARSER_TYPE_A;
1091         rd[i].data_size = sizeof (struct in_addr);
1092         rd[i].expiration_time = GNUNET_TIME_relative_to_absolute (VPN_TIMEOUT).abs_value_us;
1093         rd[i].flags = 0;
1094         rd[i].data = address;
1095         break;
1096       case AF_INET6:
1097         rd[i].record_type = GNUNET_DNSPARSER_TYPE_AAAA;
1098         rd[i].expiration_time = GNUNET_TIME_relative_to_absolute (VPN_TIMEOUT).abs_value_us;
1099         rd[i].flags = 0;
1100         rd[i].data = address;
1101         rd[i].data_size = sizeof (struct in6_addr);
1102         break;
1103       default:
1104         GNUNET_assert (0);
1105       }     
1106       break;
1107     }
1108   }
1109   GNUNET_assert (i < vpn_ctx->rd_count);
1110   handle_gns_resolution_result (rh, 
1111                                 vpn_ctx->rd_count,
1112                                 rd);
1113   GNUNET_free (vpn_ctx->rd_data);
1114   GNUNET_free (vpn_ctx);
1115 }
1116
1117
1118 /**
1119  * Process a records that were decrypted from a block.
1120  *
1121  * @param cls closure with the 'struct GNS_ResolverHandle'
1122  * @param rd_count number of entries in @a rd array
1123  * @param rd array of records with data to store
1124  */
1125 static void
1126 handle_gns_resolution_result (void *cls,
1127                               unsigned int rd_count,
1128                               const struct GNUNET_NAMESTORE_RecordData *rd)
1129 {
1130   struct GNS_ResolverHandle *rh = cls;
1131   struct AuthorityChain *ac;
1132   unsigned int i;
1133   unsigned int j;
1134   struct sockaddr *sa;
1135   struct sockaddr_in v4;
1136   struct sockaddr_in6 v6;
1137   size_t sa_len;
1138   char *cname;
1139   struct VpnContext *vpn_ctx;
1140   const struct GNUNET_TUN_GnsVpnRecord *vpn;
1141   const char *vname;
1142   struct GNUNET_HashCode vhash;
1143   int af;
1144   char **scratch;
1145   unsigned int scratch_len;
1146    
1147   if (0 == rh->name_resolution_pos)
1148   {
1149     /* top-level match, are we done yet? */
1150     if ( (rd_count > 0) &&
1151          (GNUNET_DNSPARSER_TYPE_CNAME == rd[0].record_type) &&
1152          (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type) )
1153     {
1154       cname = GNUNET_strndup (rd[0].data,
1155                               rd[0].data_size);
1156       handle_gns_cname_result (rh, 
1157                                cname);
1158       GNUNET_free (cname);
1159       return;     
1160     }
1161     /* If A/AAAA was requested, but we got a VPN
1162        record, we convert it to A/AAAA using GNUnet VPN */
1163     if ( (GNUNET_DNSPARSER_TYPE_A == rh->record_type) ||
1164          (GNUNET_DNSPARSER_TYPE_AAAA == rh->record_type) )
1165     {
1166       for (i=0;i<rd_count;i++)
1167       {
1168         if (GNUNET_NAMESTORE_TYPE_VPN == rd[i].record_type)
1169         {
1170           af = (GNUNET_DNSPARSER_TYPE_A == rh->record_type) ? AF_INET : AF_INET6;
1171           if (sizeof (struct GNUNET_TUN_GnsVpnRecord) <
1172               rd[i].data_size)
1173           {
1174             GNUNET_break_op (0);
1175             rh->proc (rh->proc_cls, 0, NULL);
1176             GNS_resolver_lookup_cancel (rh);
1177             return;         
1178           }
1179           vpn = (const struct GNUNET_TUN_GnsVpnRecord *) rd[i].data;
1180           vname = (const char *) &vpn[1];
1181           if ('\0' != vname[rd[i].data_size - 1 - sizeof (struct GNUNET_TUN_GnsVpnRecord)])
1182           {
1183             GNUNET_break_op (0);
1184             rh->proc (rh->proc_cls, 0, NULL);
1185             GNS_resolver_lookup_cancel (rh);
1186             return;
1187           }
1188           GNUNET_CRYPTO_hash (vname,
1189                               strlen (vname), // FIXME: +1?
1190                               &vhash);
1191           vpn_ctx = GNUNET_new (struct VpnContext);
1192           rh->vpn_ctx = vpn_ctx;
1193           vpn_ctx->rh = rh;
1194           vpn_ctx->rd_data_size = GNUNET_NAMESTORE_records_get_size (rd_count,
1195                                                                      rd);
1196           vpn_ctx->rd_data = GNUNET_malloc (vpn_ctx->rd_data_size);
1197           (void) GNUNET_NAMESTORE_records_serialize (rd_count,
1198                                                      rd,
1199                                                      vpn_ctx->rd_data_size,
1200                                                      vpn_ctx->rd_data);
1201           vpn_ctx->vpn_request = GNUNET_VPN_redirect_to_peer (vpn_handle,
1202                                                               af,
1203                                                               ntohs (vpn->proto),
1204                                                               &vpn->peer,
1205                                                               &vhash,
1206                                                               GNUNET_NO,
1207                                                               GNUNET_TIME_relative_to_absolute (VPN_TIMEOUT),
1208                                                               &vpn_allocation_cb,
1209                                                               rh);
1210           return;
1211         }
1212       }
1213     }
1214     /* convert relative names in record values to absolute names,
1215        using 'scratch' array for memory allocations */
1216     scratch = NULL;
1217     scratch_len = 0;
1218     for (i=0;i<rd_count;i++)
1219     {
1220       /* Strategy: dnsparser should expose API to make it easier
1221          for us to parse all of these binary record values individually;
1222          then, we check if the embedded name(s) end in "+", and if so,
1223          replace the "+" with the zone at "ac_tail", changing the name
1224          to a ".zkey".  The name is allocated on the 'scratch' array,
1225          so we can free it afterwards. */
1226       switch (rd[i].record_type)
1227       {
1228       case GNUNET_DNSPARSER_TYPE_CNAME:
1229         GNUNET_break (0); // FIXME: not implemented
1230         break;
1231       case GNUNET_DNSPARSER_TYPE_SOA:
1232         GNUNET_break (0); // FIXME: not implemented
1233         break;
1234       case GNUNET_DNSPARSER_TYPE_MX:
1235         GNUNET_break (0); // FIXME: not implemented
1236         break;
1237       case GNUNET_DNSPARSER_TYPE_SRV:
1238         GNUNET_break (0); // FIXME: not implemented
1239         break;
1240       default:
1241         break;
1242       }
1243     }
1244     
1245     /* yes, we are done, return result */
1246     rh->proc (rh->proc_cls, rd_count, rd);
1247     GNS_resolver_lookup_cancel (rh);
1248     for (i=0;i<scratch_len;i++)
1249       GNUNET_free (scratch[i]);
1250     GNUNET_array_grow (scratch, 
1251                        scratch_len,
1252                        0);
1253     return;         
1254   }
1255   /* need to recurse, check if we can */
1256   for (i=0;i<rd_count;i++)
1257   {
1258     switch (rd[i].record_type)
1259     {
1260     case GNUNET_NAMESTORE_TYPE_PKEY:
1261       /* delegation to another zone */
1262       if (sizeof (struct GNUNET_CRYPTO_EccPublicKey) !=
1263           rd[i].data_size)
1264       {
1265         GNUNET_break_op (0);
1266         rh->proc (rh->proc_cls, 0, NULL);
1267         GNS_resolver_lookup_cancel (rh);
1268         return;     
1269       }
1270       /* expand authority chain */
1271       ac = GNUNET_new (struct AuthorityChain);
1272       ac->rh = rh;
1273       ac->gns_authority = GNUNET_YES;
1274       memcpy (&ac->authority_info.gns_authority,
1275               rd[i].data,
1276               sizeof (struct GNUNET_CRYPTO_EccPublicKey));
1277       ac->label = resolver_lookup_get_next_label (rh);
1278       GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1279                                         rh->ac_tail,
1280                                         ac);
1281       /* recurse */
1282       rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1283                                               rh);
1284       break;
1285     case GNUNET_DNSPARSER_TYPE_NS:
1286       /* resolution continues within DNS */
1287       if (GNUNET_DNSPARSER_MAX_NAME_LENGTH < rd[i].data_size)
1288       {
1289         GNUNET_break_op (0);
1290         rh->proc (rh->proc_cls, 0, NULL);
1291         GNS_resolver_lookup_cancel (rh);
1292         return;     
1293       }
1294       /* find associated A/AAAA record */
1295       sa = NULL;
1296       for (j=0;j<rd_count;j++)
1297       {
1298         switch (rd[j].record_type)
1299         {
1300         case GNUNET_DNSPARSER_TYPE_A:
1301           if (sizeof (struct in_addr) != rd[i].data_size)
1302           {
1303             GNUNET_break_op (0);
1304             rh->proc (rh->proc_cls, 0, NULL);
1305             GNS_resolver_lookup_cancel (rh);
1306             return;     
1307           }
1308           /* FIXME: might want to check if we support IPv4 here,
1309              and otherwise skip this one and hope we find another */
1310           memset (&v4, 0, sizeof (v4));
1311           sa_len = sizeof (v4);
1312           v4.sin_family = AF_INET;
1313           v4.sin_port = htons (53);
1314 #if HAVE_SOCKADDR_IN_SIN_LEN
1315           v4.sin_len = (u_char) sa_len;
1316 #endif
1317           memcpy (&v4.sin_addr,
1318                   rd[j].data,
1319                   sizeof (struct in_addr));
1320           sa = (struct sockaddr *) &v4;
1321           break;
1322         case GNUNET_DNSPARSER_TYPE_AAAA:
1323           if (sizeof (struct in6_addr) != rd[i].data_size)
1324           {
1325             GNUNET_break_op (0);
1326             rh->proc (rh->proc_cls, 0, NULL);
1327             GNS_resolver_lookup_cancel (rh);
1328             return;     
1329           }
1330           /* FIXME: might want to check if we support IPv6 here,
1331              and otherwise skip this one and hope we find another */
1332           memset (&v6, 0, sizeof (v6));
1333           sa_len = sizeof (v6);
1334           v6.sin6_family = AF_INET6;
1335           v6.sin6_port = htons (53);
1336 #if HAVE_SOCKADDR_IN_SIN_LEN
1337           v6.sin6_len = (u_char) sa_len;
1338 #endif
1339           memcpy (&v6.sin6_addr,
1340                   rd[j].data,
1341                   sizeof (struct in6_addr));
1342           sa = (struct sockaddr *) &v6;
1343           break;
1344         }
1345         if (NULL != sa)
1346           break;
1347       }
1348       /* expand authority chain */
1349       ac = GNUNET_new (struct AuthorityChain);
1350       ac->rh = rh;
1351       strncpy (ac->authority_info.dns_authority.name,
1352                rd[i].data,
1353                rd[i].data_size);
1354       ac->authority_info.dns_authority.name[rd[i].data_size] = '\0';
1355       memcpy (&ac->authority_info.dns_authority.dns_ip,
1356               sa,
1357               sa_len);
1358       /* for DNS recursion, the label is the full DNS name,
1359          created from the remainder of the GNS name and the
1360          name in the NS record */
1361       GNUNET_asprintf (&ac->label,
1362                        "%.*s%s",
1363                        (int) rh->name_resolution_pos,
1364                        rh->name,
1365                        ac->authority_info.dns_authority.name);
1366       GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1367                                         rh->ac_tail,
1368                                         ac);
1369       if (strlen (ac->label) > GNUNET_DNSPARSER_MAX_NAME_LENGTH)
1370       {
1371         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1372                     _("GNS lookup resulted in DNS name that is too long (`%s')\n"),
1373                     ac->label);
1374         rh->proc (rh->proc_cls, 0, NULL);
1375         GNS_resolver_lookup_cancel (rh);
1376         return;
1377       }
1378       /* recurse */
1379       rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1380                                               rh);
1381       return;
1382     case GNUNET_DNSPARSER_TYPE_CNAME:
1383       cname = GNUNET_strndup (rd[i].data,
1384                               rd[i].data_size);
1385       handle_gns_cname_result (rh, 
1386                                cname);
1387       GNUNET_free (cname);
1388       return;
1389       /* FIXME: handle DNAME */
1390     default:
1391       /* skip */
1392       break;
1393     }
1394   }
1395   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1396               _("GNS lookup recursion failed (no delegation record found)\n"));
1397   rh->proc (rh->proc_cls, 0, NULL);
1398   GNS_resolver_lookup_cancel (rh);
1399 }
1400
1401
1402 /**
1403  * Function called once the namestore has completed the request for
1404  * caching a block.
1405  *
1406  * @param cls closure with the 'struct GNS_ResolverHandle'
1407  * @param success #GNUNET_OK on success
1408  * @param emsg error message
1409  */
1410 static void
1411 namestore_cache_continuation (void *cls,
1412                               int32_t success,
1413                               const char *emsg)
1414 {
1415   struct GNS_ResolverHandle *rh = cls;
1416
1417   rh->namestore_qe = NULL;
1418   if (NULL != emsg)
1419     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1420                 _("Failed to cache GNS resolution: %s\n"),
1421                 emsg);
1422 }
1423
1424
1425 /**
1426  * Iterator called on each result obtained for a DHT
1427  * operation that expects a reply
1428  *
1429  * @param cls closure with the 'struct GNS_ResolverHandle'
1430  * @param exp when will this value expire
1431  * @param key key of the result
1432  * @param get_path peers on reply path (or NULL if not recorded)
1433  *                 [0] = datastore's first neighbor, [length - 1] = local peer
1434  * @param get_path_length number of entries in get_path
1435  * @param put_path peers on the PUT path (or NULL if not recorded)
1436  *                 [0] = origin, [length - 1] = datastore
1437  * @param put_path_length number of entries in get_path
1438  * @param type type of the result
1439  * @param size number of bytes in data
1440  * @param data pointer to the result data
1441  */
1442 static void
1443 handle_dht_response (void *cls,
1444                      struct GNUNET_TIME_Absolute exp,
1445                      const struct GNUNET_HashCode * key,
1446                      const struct GNUNET_PeerIdentity *get_path,
1447                      unsigned int get_path_length,
1448                      const struct GNUNET_PeerIdentity *put_path, 
1449                      unsigned int put_path_length,
1450                      enum GNUNET_BLOCK_Type type,
1451                      size_t size, const void *data)
1452 {
1453   struct GNS_ResolverHandle *rh = cls;
1454   struct AuthorityChain *ac = rh->ac_tail;
1455   const struct GNUNET_NAMESTORE_Block *block;
1456   
1457   GNUNET_DHT_get_stop (rh->get_handle);
1458   rh->get_handle = NULL;
1459   GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
1460   rh->dht_heap_node = NULL;  
1461   if (size < sizeof (struct GNUNET_NAMESTORE_Block))
1462   {
1463     /* how did this pass DHT block validation!? */
1464     GNUNET_break (0);
1465     rh->proc (rh->proc_cls, 0, NULL);
1466     GNS_resolver_lookup_cancel (rh);
1467     return;   
1468   }
1469   block = data; 
1470   if (size !=
1471       ntohs (block->purpose.size) + 
1472       sizeof (struct GNUNET_CRYPTO_EccPublicKey) +
1473       sizeof (struct GNUNET_CRYPTO_EccSignature))
1474   {
1475     /* how did this pass DHT block validation!? */
1476     GNUNET_break (0);
1477     rh->proc (rh->proc_cls, 0, NULL);
1478     GNS_resolver_lookup_cancel (rh);
1479     return;   
1480   }
1481   if (GNUNET_OK !=
1482       GNUNET_NAMESTORE_block_decrypt (block,
1483                                       &ac->authority_info.gns_authority,
1484                                       ac->label,
1485                                       &handle_gns_resolution_result,
1486                                       rh))
1487   {
1488     GNUNET_break_op (0); /* block was ill-formed */
1489     rh->proc (rh->proc_cls, 0, NULL);
1490     GNS_resolver_lookup_cancel (rh);
1491     return;
1492   }
1493   /* Cache well-formed blocks */
1494   rh->namestore_qe = GNUNET_NAMESTORE_block_cache (namestore_handle,
1495                                                    block,
1496                                                    &namestore_cache_continuation,
1497                                                    rh);
1498 }
1499
1500
1501 /**
1502  * Process a record that was stored in the namestore.
1503  *
1504  * @param cls closure with the 'struct GNS_ResolverHandle'
1505  * @param block block that was stored in the namestore
1506  */
1507 static void 
1508 handle_namestore_block_response (void *cls,
1509                                  const struct GNUNET_NAMESTORE_Block *block)
1510 {
1511   struct GNS_ResolverHandle *rh = cls;
1512   struct GNS_ResolverHandle *rx;
1513   struct AuthorityChain *ac = rh->ac_tail;
1514   const char *label = ac->label;
1515   const struct GNUNET_CRYPTO_EccPublicKey *auth = &ac->authority_info.gns_authority;
1516   struct GNUNET_HashCode query;
1517
1518   GNUNET_NAMESTORE_query_from_public_key (auth,
1519                                           label,
1520                                           &query);
1521   rh->namestore_qe = NULL;
1522   if (NULL == block)
1523   {
1524     /* Namestore knows nothing; try DHT lookup */
1525     rh->get_handle = GNUNET_DHT_get_start (dht_handle,
1526                                            GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1527                                            &query,
1528                                            DHT_GNS_REPLICATION_LEVEL,
1529                                            GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
1530                                            NULL, 0,
1531                                            &handle_dht_response, rh);
1532     rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
1533                                                       rh,
1534                                                       GNUNET_TIME_absolute_get ().abs_value_us);
1535     if (GNUNET_CONTAINER_heap_get_size (dht_lookup_heap) > max_allowed_background_queries)
1536     {
1537       /* fail longest-standing DHT request */
1538       rx = GNUNET_CONTAINER_heap_peek (dht_lookup_heap);
1539       rx->proc (rx->proc_cls, 0, NULL);
1540       GNS_resolver_lookup_cancel (rx);
1541     }
1542     return;
1543   }
1544   if (GNUNET_OK !=
1545       GNUNET_NAMESTORE_block_decrypt (block,
1546                                       auth,
1547                                       label,
1548                                       &handle_gns_resolution_result,
1549                                       rh))
1550   {
1551     GNUNET_break_op (0); /* block was ill-formed */
1552     rh->proc (rh->proc_cls, 0, NULL);
1553     GNS_resolver_lookup_cancel (rh);
1554     return;
1555   }
1556 }
1557
1558
1559 /**
1560  * Lookup tail of our authority chain in the namestore.
1561  *
1562  * @param rh query we are processing
1563  */
1564 static void
1565 recursive_gns_resolution_namestore (struct GNS_ResolverHandle *rh)
1566 {
1567   struct AuthorityChain *ac = rh->ac_tail;
1568   struct GNUNET_HashCode query;
1569
1570   GNUNET_NAMESTORE_query_from_public_key (&ac->authority_info.gns_authority,
1571                                           ac->label,
1572                                           &query);
1573   rh->namestore_qe = GNUNET_NAMESTORE_lookup_block (namestore_handle,
1574                                                     &query,
1575                                                     &handle_namestore_block_response,
1576                                                     rh);
1577 }
1578
1579
1580 /**
1581  * Task scheduled to continue with the resolution process.
1582  *
1583  * @param cls the 'struct GNS_ResolverHandle' of the resolution
1584  * @param tc task context
1585  */
1586 static void
1587 recursive_resolution (void *cls,
1588                       const struct GNUNET_SCHEDULER_TaskContext *tc)
1589 {
1590   struct GNS_ResolverHandle *rh = cls;
1591
1592   rh->task_id = GNUNET_SCHEDULER_NO_TASK;
1593   if (MAX_RECURSION < rh->loop_limiter++)
1594   {
1595     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1596                 "Encountered unbounded recursion resolving `%s'\n",
1597                 rh->name);
1598     rh->proc (rh->proc_cls, 0, NULL);
1599     GNS_resolver_lookup_cancel (rh);
1600     return;
1601   }
1602   if (GNUNET_YES == rh->ac_tail->gns_authority)
1603     recursive_gns_resolution_namestore (rh);
1604   else
1605     recursive_dns_resolution (rh);
1606 }
1607
1608
1609 /**
1610  * Begin the resolution process from 'name', starting with
1611  * the identification of the zone specified by 'name'.
1612  *
1613  * @param rh resolution to perform
1614  */
1615 static void
1616 start_resolver_lookup (struct GNS_ResolverHandle *rh)
1617 {
1618   struct AuthorityChain *ac;
1619   char *x;
1620   char *y;
1621   char *pkey;
1622
1623   if ( ( (GNUNET_YES == is_canonical (rh->name)) &&
1624          (0 != strcmp (GNUNET_GNS_TLD, rh->name)) ) ||
1625        ( (GNUNET_YES != is_gnu_tld (rh->name)) &&
1626          (GNUNET_YES != is_zkey_tld (rh->name)) ) )
1627   {
1628     /* use standard DNS lookup */
1629     int af;
1630
1631     switch (rh->record_type)
1632     {
1633     case GNUNET_DNSPARSER_TYPE_A:
1634       af = AF_INET;
1635       break;
1636     case GNUNET_DNSPARSER_TYPE_AAAA:
1637       af = AF_INET6;
1638       break;
1639     default:
1640       af = AF_UNSPEC;
1641       break;
1642     }
1643     rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name, 
1644                                               af,
1645                                               DNS_LOOKUP_TIMEOUT,
1646                                               &handle_dns_result,
1647                                               rh);
1648     return;
1649   }
1650   if (is_zkey_tld (rh->name))
1651   {
1652     /* Name ends with ".zkey", try to replace authority zone with zkey
1653        authority */
1654     GNUNET_free (resolver_lookup_get_next_label (rh)); /* will return "zkey" */
1655     x = resolver_lookup_get_next_label (rh); /* will return 'x' coordinate */
1656     y = resolver_lookup_get_next_label (rh); /* will return 'y' coordinate */
1657     GNUNET_asprintf (&pkey,
1658                      "%s%s",
1659                      x, y);
1660     if ( (NULL == x) ||
1661          (NULL == y) ||
1662          (GNUNET_OK !=
1663           GNUNET_CRYPTO_ecc_public_key_from_string (pkey,
1664                                                     strlen (pkey),
1665                                                     &rh->authority_zone)) )
1666     {
1667       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1668                   _("Hostname `%s' is not well-formed, resolution fails\n"),
1669                   rh->name);
1670       rh->task_id = GNUNET_SCHEDULER_add_now (&fail_resolution, rh);
1671     }
1672     GNUNET_free_non_null (x);
1673     GNUNET_free_non_null (y);
1674     GNUNET_free (pkey);
1675   }
1676   else
1677   {
1678     /* Name ends with ".gnu", eat ".gnu" and continue with resolution */
1679     GNUNET_free (resolver_lookup_get_next_label (rh));
1680   }
1681   ac = GNUNET_new (struct AuthorityChain);
1682   ac->rh = rh;
1683   ac->label = resolver_lookup_get_next_label (rh);
1684   if (NULL == ac->label)
1685     /* name was just "gnu", so we default to label '+' */
1686     ac->label = GNUNET_strdup (GNUNET_GNS_MASTERZONE_STR);
1687   ac->gns_authority = GNUNET_YES;
1688   ac->authority_info.gns_authority = rh->authority_zone;
1689   GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1690                                     rh->ac_tail,
1691                                     ac);
1692   rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1693                                           rh);
1694 }
1695
1696
1697 /**
1698  * Lookup of a record in a specific zone calls lookup result processor
1699  * on result.
1700  *
1701  * @param zone the zone to perform the lookup in
1702  * @param record_type the record type to look up
1703  * @param name the name to look up
1704  * @param shorten_key a private key for use with PSEU import (can be NULL)
1705  * @param only_cached GNUNET_NO to only check locally not DHT for performance
1706  * @param proc the processor to call on result
1707  * @param proc_cls the closure to pass to @a proc
1708  * @return handle to cancel operation
1709  */
1710 struct GNS_ResolverHandle *
1711 GNS_resolver_lookup (const struct GNUNET_CRYPTO_EccPublicKey *zone,
1712                      uint32_t record_type,
1713                      const char *name,
1714                      const struct GNUNET_CRYPTO_EccPrivateKey *shorten_key,
1715                      int only_cached,
1716                      GNS_ResultProcessor proc, void *proc_cls)
1717 {
1718   struct GNS_ResolverHandle *rh;
1719
1720   rh = GNUNET_new (struct GNS_ResolverHandle);
1721   GNUNET_CONTAINER_DLL_insert (rlh_head,
1722                                rlh_tail,
1723                                rh);
1724   rh->authority_zone = *zone;
1725   rh->proc = proc;
1726   rh->proc_cls = proc_cls;
1727   rh->only_cached = only_cached;
1728   rh->record_type = record_type;
1729   rh->name = GNUNET_strdup (name);
1730   rh->name_resolution_pos = strlen (name);
1731   if (NULL != shorten_key)
1732   {
1733     rh->shorten_key = GNUNET_new (struct GNUNET_CRYPTO_EccPrivateKey);
1734     *rh->shorten_key = *shorten_key;
1735   }
1736   start_resolver_lookup (rh);
1737   return rh;
1738 }
1739
1740
1741 /**
1742  * Cancel active resolution (i.e. client disconnected).
1743  *
1744  * @param rh resolution to abort
1745  */
1746 void
1747 GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
1748 {
1749   struct DnsResult *dr;
1750   struct AuthorityChain *ac;
1751   struct VpnContext *vpn_ctx;
1752
1753   GNUNET_CONTAINER_DLL_remove (rlh_head,
1754                                rlh_tail,
1755                                rh);
1756   while (NULL != (ac = rh->ac_head))
1757   {
1758     GNUNET_CONTAINER_DLL_remove (rh->ac_head,
1759                                  rh->ac_tail,
1760                                  ac);
1761     GNUNET_free (ac->label);
1762     GNUNET_free (ac);
1763   }
1764   if (GNUNET_SCHEDULER_NO_TASK != rh->task_id)
1765   {
1766     GNUNET_SCHEDULER_cancel (rh->task_id);
1767     rh->task_id = GNUNET_SCHEDULER_NO_TASK;
1768   }
1769   if (NULL != rh->get_handle)
1770   {
1771     GNUNET_DHT_get_stop (rh->get_handle);
1772     rh->get_handle = NULL;
1773   }
1774   if (NULL != rh->dht_heap_node)
1775   {
1776     GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
1777     rh->dht_heap_node = NULL;
1778   }
1779   if (NULL != (vpn_ctx = rh->vpn_ctx))
1780   {
1781     GNUNET_VPN_cancel_request (vpn_ctx->vpn_request);
1782     GNUNET_free (vpn_ctx->rd_data);
1783     GNUNET_free (vpn_ctx);
1784   }
1785   if (NULL != rh->dns_request)
1786   {
1787     GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
1788     rh->dns_request = NULL;
1789   }
1790   if (NULL != rh->namestore_qe)
1791   {
1792     GNUNET_NAMESTORE_cancel (rh->namestore_qe);
1793     rh->namestore_qe = NULL;
1794   }
1795   if (NULL != rh->std_resolve)
1796   {
1797     GNUNET_RESOLVER_request_cancel (rh->std_resolve);
1798     rh->std_resolve = NULL;
1799   }
1800   while (NULL != (dr = rh->dns_result_head))
1801   {
1802     GNUNET_CONTAINER_DLL_remove (rh->dns_result_head,
1803                                  rh->dns_result_tail,
1804                                  dr);
1805     GNUNET_free (dr);
1806   }
1807   GNUNET_free_non_null (rh->shorten_key);
1808   GNUNET_free (rh->name);
1809   GNUNET_free (rh);
1810 }
1811
1812
1813 /* ***************** Resolver initialization ********************* */
1814
1815
1816 /**
1817  * Initialize the resolver
1818  *
1819  * @param nh the namestore handle
1820  * @param dht the dht handle
1821  * @param c configuration handle
1822  * @param max_bg_queries maximum number of parallel background queries in dht
1823  */
1824 void
1825 GNS_resolver_init (struct GNUNET_NAMESTORE_Handle *nh,
1826                    struct GNUNET_DHT_Handle *dht,
1827                    const struct GNUNET_CONFIGURATION_Handle *c,
1828                    unsigned long long max_bg_queries)
1829 {
1830   char *dns_ip;
1831
1832   cfg = c;
1833   namestore_handle = nh;
1834   dht_handle = dht;
1835   dht_lookup_heap =
1836     GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1837   max_allowed_background_queries = max_bg_queries;
1838   if (GNUNET_OK !=
1839       GNUNET_CONFIGURATION_get_value_string (c,
1840                                              "gns",
1841                                              "DNS_RESOLVER",
1842                                              &dns_ip))
1843   {
1844     /* user did not specify DNS resolver, use 8.8.8.8 */
1845     dns_ip = GNUNET_strdup ("8.8.8.8");
1846   }
1847   dns_handle = GNUNET_DNSSTUB_start (dns_ip);
1848   GNUNET_free (dns_ip);
1849   vpn_handle = GNUNET_VPN_connect (cfg);
1850 }
1851
1852
1853 /**
1854  * Shutdown resolver
1855  */
1856 void
1857 GNS_resolver_done ()
1858 {
1859   struct GNS_ResolverHandle *rh;
1860
1861   /* abort active resolutions */
1862   while (NULL != (rh = rlh_head))
1863   {
1864     rh->proc (rh->proc_cls, 0, NULL);
1865     GNS_resolver_lookup_cancel (rh);    
1866   }
1867   GNUNET_CONTAINER_heap_destroy (dht_lookup_heap);
1868   dht_lookup_heap = NULL;
1869   GNUNET_DNSSTUB_stop (dns_handle);
1870   dns_handle = NULL;
1871   GNUNET_VPN_disconnect (vpn_handle);
1872   vpn_handle = NULL;
1873   dht_handle = NULL;
1874   namestore_handle = NULL;
1875 }
1876
1877
1878 /* *************** common helper functions (do not really belong here) *********** */
1879
1880 /**
1881  * Checks if @a name ends in ".TLD"
1882  *
1883  * @param name the name to check
1884  * @param tld the TLD to check for
1885  * @return GNUNET_YES or GNUNET_NO
1886  */
1887 int
1888 is_tld (const char* name, const char* tld)
1889 {
1890   size_t offset = 0;
1891
1892   if (strlen (name) <= strlen (tld))
1893     return GNUNET_NO;
1894   offset = strlen (name) - strlen (tld);
1895   if (0 != strcmp (name + offset, tld))
1896     return GNUNET_NO;
1897   return GNUNET_YES;
1898 }
1899
1900
1901 /* end of gnunet-service-gns_resolver.c */