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