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