a5db51db3fe6badb4c24a6b0d7afad52fe7984c1
[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  * - recurive GNS resulution
29  * - recursive DNS resolution
30  * - shortening triggers
31  * - revocation checks (privacy!?)
32  */
33 #include "platform.h"
34 #include "gnunet_util_lib.h"
35 #include "gnunet_transport_service.h"
36 #include "gnunet_dnsstub_lib.h"
37 #include "gnunet_dht_service.h"
38 #include "gnunet_namestore_service.h"
39 #include "gnunet_dns_service.h"
40 #include "gnunet_resolver_service.h"
41 #include "gnunet_dnsparser_lib.h"
42 #include "gns_protocol.h"
43 #include "gnunet_gns_service.h"
44 #include "gns_common.h"
45 #include "gns.h"
46 #include "gnunet-service-gns_resolver.h"
47 #include "gnunet_vpn_service.h"
48
49
50 /**
51  * Default DHT timeout for lookups.
52  */
53 #define DHT_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
54
55 /**
56  * Default timeout for DNS lookups.
57  */
58 #define DNS_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
59
60 /**
61  * DHT replication level
62  */
63 #define DHT_GNS_REPLICATION_LEVEL 5
64
65 /**
66  * How deep do we allow recursions to go before we abort?
67  */
68 #define MAX_RECURSION 256
69
70
71 /**
72  * DLL to hold the authority chain we had to pass in the resolution
73  * process.
74  */
75 struct AuthorityChain
76 {
77   /**
78    * This is a DLL.
79    */
80   struct AuthorityChain *prev;
81
82   /**
83    * This is a DLL.
84    */
85   struct AuthorityChain *next;
86
87   /**
88    * Resolver handle this entry in the chain belongs to.
89    */
90   struct GNS_ResolverHandle *rh;
91
92   /**
93    * label/name corresponding to the authority 
94    */
95   char *label;
96   
97   /**
98    * #GNUNET_YES if the authority was a GNS authority,
99    * #GNUNET_NO if the authority was a DNS authority.
100    */
101   int gns_authority;
102
103   /**
104    * Information about the resolver authority for this label.
105    */
106   union
107   {
108
109     /**
110      * The zone of the GNS authority 
111      */
112     struct GNUNET_CRYPTO_EccPublicKey gns_authority;
113
114     struct
115     {
116       /**
117        * Domain of the DNS resolver that is the authority.
118        * (appended to construct the DNS name to resolve;
119        * this is NOT the DNS name of the DNS server!).
120        */
121       char name[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
122
123       /**
124        * IP address of the DNS resolver that is authoritative.
125        * (this implementation currently only supports one
126        * IP at a time).
127        */
128       struct sockaddr_storage dns_ip;
129
130     } dns_authority;
131
132   } authority_info;
133   
134 };
135
136
137 /**
138  * Resolution status indicator
139  */
140 enum ResolutionStatus
141 {
142   /**
143    * the name to lookup exists
144    */
145   RSL_RECORD_EXISTS = 1,
146
147   /**
148    * the name in the record expired
149    */
150   RSL_RECORD_EXPIRED = 2,
151  
152   /**
153    * resolution timed out
154    */
155   RSL_TIMED_OUT = 4,
156  
157   /**
158    * Found VPN delegation
159    */
160   RSL_DELEGATE_VPN = 8,
161  
162   /**
163    * Found NS delegation
164    */
165   RSL_DELEGATE_NS = 16,
166  
167   /**
168    * Found PKEY delegation
169    */
170   RSL_DELEGATE_PKEY = 32,
171   
172   /**
173    * Found CNAME record
174    */
175   RSL_CNAME_FOUND = 64,
176   
177   /**
178    * Found PKEY has been revoked
179    */
180   RSL_PKEY_REVOKED = 128
181 };
182
183
184 /**
185  * A result we got from DNS.
186  */
187 struct DnsResult
188 {
189
190   /**
191    * Kept in DLL.
192    */
193   struct DnsResult *next;
194
195   /**
196    * Kept in DLL.
197    */
198   struct DnsResult *prev;
199
200   /**
201    * Binary value stored in the DNS record (appended to this struct)
202    */
203   const void *data;
204
205   /**
206    * Expiration time for the DNS record, 0 if we didn't
207    * get anything useful (i.e. 'gethostbyname' was used).
208    */
209   uint64_t expiration_time;
210
211   /**
212    * Number of bytes in 'data'.
213    */
214   size_t data_size;
215
216   /**
217    * Type of the GNS/DNS record.
218    */
219   uint32_t record_type;
220
221 };
222
223
224 /**
225  * Handle to a currenty pending resolution.  On result (positive or
226  * negative) the #GNS_ResultProcessor is called.  
227  */
228 struct GNS_ResolverHandle
229 {
230
231   /**
232    * DLL 
233    */
234   struct GNS_ResolverHandle *next;
235
236   /**
237    * DLL 
238    */
239   struct GNS_ResolverHandle *prev;
240
241   /**
242    * The top-level GNS authoritative zone to query 
243    */
244   struct GNUNET_CRYPTO_EccPublicKey authority_zone;
245
246   /**
247    * called when resolution phase finishes 
248    */
249   GNS_ResultProcessor proc;
250   
251   /**
252    * closure passed to proc 
253    */
254   void* proc_cls;
255
256   /**
257    * Handle for DHT lookups. should be NULL if no lookups are in progress 
258    */
259   struct GNUNET_DHT_GetHandle *get_handle;
260
261   /**
262    * Handle to a VPN request, NULL if none is active.
263    */
264   struct GNUNET_VPN_RedirectionRequest *vpn_handle;
265
266   /**
267    * Socket for a DNS request, NULL if none is active.
268    */
269   struct GNUNET_DNSSTUB_RequestSocket *dns_request;
270
271   /**
272    * Handle for standard DNS resolution, NULL if none is active.
273    */
274   struct GNUNET_RESOLVER_RequestHandle *std_resolve;
275
276   /**
277    * Pending Namestore task
278    */
279   struct GNUNET_NAMESTORE_QueueEntry *namestore_qe;
280
281   /**
282    * Heap node associated with this lookup.  Used to limit number of
283    * concurrent requests.
284    */
285   struct GNUNET_CONTAINER_HeapNode *dht_heap_node;
286
287   /**
288    * DLL to store the authority chain 
289    */
290   struct AuthorityChain *ac_head;
291
292   /**
293    * DLL to store the authority chain 
294    */
295   struct AuthorityChain *ac_tail;
296
297   /**
298    * Private key of the shorten zone, NULL to not shorten.
299    */
300   struct GNUNET_CRYPTO_EccPrivateKey *shorten_key;
301
302   /**
303    * ID of a task associated with the resolution process.
304    */
305   GNUNET_SCHEDULER_TaskIdentifier task_id;
306
307   /**
308    * The name to resolve 
309    */
310   char *name;
311
312   /**
313    * DLL of results we got from DNS.
314    */
315   struct DnsResult *dns_result_head;
316
317   /**
318    * DLL of results we got from DNS.
319    */
320   struct DnsResult *dns_result_tail;
321
322   /**
323    * Current offset in 'name' where we are resolving.
324    */
325   size_t name_resolution_pos;
326
327   /**
328    * Use only cache 
329    */
330   int only_cached;
331
332   /**
333    * Desired type for the resolution.
334    */
335   int record_type;
336
337   /**
338    * We increment the loop limiter for each step in a recursive
339    * resolution.  If it passes our threshold (i.e. due to 
340    * self-recursion in the resolution, i.e CNAME fun), we stop.
341    */
342   unsigned int loop_limiter;
343
344 };
345
346
347 /**
348  * Handle for a PSEU lookup used to shorten names.
349  */
350 struct GetPseuAuthorityHandle
351 {
352   /**
353    * DLL
354    */
355   struct GetPseuAuthorityHandle *next;
356
357   /**
358    * DLL
359    */
360   struct GetPseuAuthorityHandle *prev;
361
362   /**
363    * Private key of the (shorten) zone to store the resulting
364    * pseudonym in.
365    */
366   struct GNUNET_CRYPTO_EccPrivateKey shorten_zone_key;
367
368   /**
369    * Original label (used if no PSEU record is found).
370    */
371   char label[GNUNET_DNSPARSER_MAX_LABEL_LENGTH + 1];
372
373   /**
374    * Label we are currently trying out (during #perform_pseu_lookup).
375    */
376   char *current_label;
377
378   /**
379    * The zone for which we are trying to find the PSEU record.
380    */
381   struct GNUNET_CRYPTO_EccPublicKey target_zone;
382
383   /**
384    * Handle for DHT lookups. Should be NULL if no lookups are in progress 
385    */
386   struct GNUNET_DHT_GetHandle *get_handle;
387
388   /**
389    * Handle to namestore request 
390    */
391   struct GNUNET_NAMESTORE_QueueEntry *namestore_task;
392
393   /**
394    * Task to abort DHT lookup operation.
395    */
396   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
397
398 };
399
400
401 /**
402  * Our handle to the namestore service
403  */
404 static struct GNUNET_NAMESTORE_Handle *namestore_handle;
405
406 /**
407  * Our handle to the vpn service
408  */
409 static struct GNUNET_VPN_Handle *vpn_handle;
410
411 /**
412  * Resolver handle to the dht
413  */
414 static struct GNUNET_DHT_Handle *dht_handle;
415
416 /**
417  * Handle to perform DNS lookups.
418  */
419 static struct GNUNET_DNSSTUB_Context *dns_handle;
420
421 /**
422  * Heap for limiting parallel DHT lookups
423  */
424 static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
425
426 /**
427  * Maximum amount of parallel queries to the DHT
428  */
429 static unsigned long long max_allowed_background_queries;
430
431 /**
432  * Head of PSEU/shorten operations list.
433  */
434 struct GetPseuAuthorityHandle *gph_head;
435
436 /**
437  * Tail of PSEU/shorten operations list.
438  */
439 struct GetPseuAuthorityHandle *gph_tail;
440
441 /**
442  * Head of resolver lookup list
443  */
444 static struct GNS_ResolverHandle *rlh_head;
445
446 /**
447  * Tail of resolver lookup list
448  */
449 static struct GNS_ResolverHandle *rlh_tail;
450
451 /**
452  * Global configuration.
453  */
454 static const struct GNUNET_CONFIGURATION_Handle *cfg;
455
456
457 /**
458  * Check if name is in srv format (_x._y.xxx)
459  *
460  * @param name
461  * @return GNUNET_YES if true
462  */
463 static int
464 is_srv (const char *name)
465 {
466   char *ndup;
467   int ret;
468
469   if (*name != '_')
470     return GNUNET_NO;
471   if (NULL == strstr (name, "._"))
472     return GNUNET_NO;
473   ret = GNUNET_YES;
474   ndup = GNUNET_strdup (name);
475   strtok (ndup, ".");
476   if (NULL == strtok (NULL, "."))
477     ret = GNUNET_NO;
478   if (NULL == strtok (NULL, "."))
479     ret = GNUNET_NO;
480   if (NULL != strtok (NULL, "."))
481     ret = GNUNET_NO;
482   GNUNET_free (ndup);
483   return ret;
484 }
485
486
487 /**
488  * Determine if this name is canonical (is a legal name in a zone, without delegation);
489  * note that we do not test that the name does not contain illegal characters, we only
490  * test for delegation.  Note that service records (i.e. _foo._srv) are canonical names
491  * even though they consist of multiple labels.
492  *
493  * Examples:
494  * a.b.gads  = not canonical
495  * a         = canonical
496  * _foo._srv = canonical
497  * _f.bar    = not canonical
498  *
499  * @param name the name to test
500  * @return GNUNET_YES if canonical
501  */
502 static int
503 is_canonical (const char *name)
504 {
505   const char *pos;
506   const char *dot;
507
508   if (NULL == strchr (name, '.'))
509     return GNUNET_YES;
510   if ('_' != name[0])
511     return GNUNET_NO;
512   pos = &name[1];
513   while (NULL != (dot = strchr (pos, '.')))    
514     if ('_' != dot[1])
515       return GNUNET_NO;
516     else
517       pos = dot + 1;
518   return GNUNET_YES;
519 }
520
521
522 /* ******************** Shortening logic ************************ */
523
524
525 /**
526  * Cleanup a 'struct GetPseuAuthorityHandle', terminating all
527  * pending activities.
528  *
529  * @param gph handle to terminate
530  */
531 static void
532 free_get_pseu_authority_handle (struct GetPseuAuthorityHandle *gph)
533 {
534   if (NULL != gph->get_handle)
535   {
536     GNUNET_DHT_get_stop (gph->get_handle);
537     gph->get_handle = NULL;
538   }
539   if (NULL != gph->namestore_task)
540   {
541     GNUNET_NAMESTORE_cancel (gph->namestore_task);
542     gph->namestore_task = NULL;
543   }
544   if (GNUNET_SCHEDULER_NO_TASK != gph->timeout_task)
545   {
546     GNUNET_SCHEDULER_cancel (gph->timeout_task);
547     gph->timeout_task = GNUNET_SCHEDULER_NO_TASK;
548   }
549   GNUNET_CONTAINER_DLL_remove (gph_head, gph_tail, gph);
550   GNUNET_free_non_null (gph->current_label);
551   GNUNET_free (gph);
552 }
553
554
555 /**
556  * Continuation for pkey record creation (shorten)
557  *
558  * @param cls a GetPseuAuthorityHandle
559  * @param success unused
560  * @param emsg unused
561  */
562 static void
563 create_pkey_cont (void* cls, 
564                   int32_t success, 
565                   const char *emsg)
566 {
567   struct GetPseuAuthorityHandle* gph = cls;
568
569   gph->namestore_task = NULL;
570   free_get_pseu_authority_handle (gph);
571 }
572
573
574 /**
575  * Namestore calls this function if we have record for this name.
576  * (or with rd_count=0 to indicate no matches).
577  *
578  * @param cls the pending query
579  * @param rd_count the number of records with 'name'
580  * @param rd the record data
581  */
582 static void
583 process_pseu_lookup_ns (void *cls,
584                         unsigned int rd_count,
585                         const struct GNUNET_NAMESTORE_RecordData *rd);
586
587
588 /**
589  * We obtained a result for our query to the shorten zone from
590  * the namestore.  Try to decrypt.
591  *
592  * @param cls the handle to our shorten operation
593  * @param block resulting encrypted block
594  */
595 static void
596 process_pseu_block_ns (void *cls,
597                        const struct GNUNET_NAMESTORE_Block *block)
598 {
599   struct GetPseuAuthorityHandle *gph = cls;
600   struct GNUNET_CRYPTO_EccPublicKey pub;
601
602   gph->namestore_task = NULL;
603   if (NULL == block)
604   {
605     process_pseu_lookup_ns (gph, 0, NULL);
606     return;
607   }
608   GNUNET_CRYPTO_ecc_key_get_public (&gph->shorten_zone_key,
609                                     &pub);
610   if (GNUNET_OK != 
611       GNUNET_NAMESTORE_block_decrypt (block,
612                                       &pub,
613                                       gph->current_label,
614                                       &process_pseu_lookup_ns,
615                                       gph))
616   {
617     GNUNET_break (0);
618     free_get_pseu_authority_handle (gph);
619     return;
620   }
621 }
622
623
624 /**
625  * Lookup in the namestore for the shorten zone the given label.
626  *
627  * @param gph the handle to our shorten operation
628  * @param label the label to lookup
629  */
630 static void 
631 perform_pseu_lookup (struct GetPseuAuthorityHandle *gph,
632                      const char *label)
633
634   struct GNUNET_CRYPTO_EccPublicKey pub;
635   struct GNUNET_HashCode query;
636
637   GNUNET_CRYPTO_ecc_key_get_public (&gph->shorten_zone_key,
638                                     &pub);
639   GNUNET_free_non_null (gph->current_label);
640   gph->current_label = GNUNET_strdup (label);
641   GNUNET_NAMESTORE_query_from_public_key (&pub,
642                                           label,
643                                           &query);
644   gph->namestore_task = GNUNET_NAMESTORE_lookup_block (namestore_handle,
645                                                        &query,
646                                                        &process_pseu_block_ns,
647                                                        gph);
648 }
649
650
651 /**
652  * Namestore calls this function if we have record for this name.
653  * (or with rd_count=0 to indicate no matches).
654  *
655  * @param cls the pending query
656  * @param rd_count the number of records with 'name'
657  * @param rd the record data
658  */
659 static void
660 process_pseu_lookup_ns (void *cls,
661                         unsigned int rd_count,
662                         const struct GNUNET_NAMESTORE_RecordData *rd)
663 {
664   struct GetPseuAuthorityHandle *gph = cls;
665   struct GNUNET_NAMESTORE_RecordData new_pkey;
666
667   gph->namestore_task = NULL;
668   if (rd_count > 0)
669   {
670     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
671                "Name `%s' already taken, cannot shorten.\n", 
672                gph->current_label);
673     /* if this was not yet the original label, try one more
674        time, this time not using PSEU but the original label */
675     if (0 == strcmp (gph->current_label,
676                      gph->label))
677     {
678       free_get_pseu_authority_handle (gph);
679     }
680     else
681     {
682       perform_pseu_lookup (gph, gph->label);
683     }
684     return;
685   }
686   /* name is available */
687   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
688               "Shortening `%s' to `%s'\n", 
689               GNUNET_NAMESTORE_z2s (&gph->target_zone),
690               gph->current_label);
691   new_pkey.expiration_time = UINT64_MAX;
692   new_pkey.data_size = sizeof (struct GNUNET_CRYPTO_EccPublicKey);
693   new_pkey.data = &gph->target_zone;
694   new_pkey.record_type = GNUNET_NAMESTORE_TYPE_PKEY;
695   new_pkey.flags = GNUNET_NAMESTORE_RF_AUTHORITY
696                  | GNUNET_NAMESTORE_RF_PRIVATE
697                  | GNUNET_NAMESTORE_RF_PENDING;
698   gph->namestore_task 
699     = GNUNET_NAMESTORE_records_store (namestore_handle,
700                                       &gph->shorten_zone_key,
701                                       gph->current_label,
702                                       1, &new_pkey,
703                                       &create_pkey_cont, gph);
704 }
705
706
707 /**
708  * Process result of a DHT lookup for a PSEU record.
709  *
710  * @param gph the handle to our shorten operation
711  * @param pseu the pseu result or NULL
712  */
713 static void
714 process_pseu_result (struct GetPseuAuthorityHandle* gph, 
715                      const char *pseu)
716 {
717   if (NULL == pseu)
718   {
719     /* no PSEU found, try original label */
720     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
721                 "No PSEU found, trying original label `%s' instead.\n",
722                 gph->label);
723     perform_pseu_lookup (gph, gph->label);
724     return;
725   }  
726   /* check if 'pseu' is taken */
727   perform_pseu_lookup (gph, pseu);
728 }
729
730
731 /**
732  * Handle timeout for DHT request during shortening.
733  *
734  * @param cls the request handle as closure
735  * @param tc the task context
736  */
737 static void
738 handle_auth_discovery_timeout (void *cls,
739                                const struct GNUNET_SCHEDULER_TaskContext *tc)
740 {
741   struct GetPseuAuthorityHandle *gph = cls;
742
743   gph->timeout_task = GNUNET_SCHEDULER_NO_TASK;
744   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
745               "DHT lookup for PSEU query timed out.\n");
746   GNUNET_DHT_get_stop (gph->get_handle);
747   gph->get_handle = NULL;
748   process_pseu_result (gph, NULL);
749 }
750
751
752 /**
753  * Handle decrypted records from DHT result.
754  *
755  * @param cls closure with our 'struct GetPseuAuthorityHandle'
756  * @param rd_count number of entries in 'rd' array
757  * @param rd array of records with data to store
758  */
759 static void
760 process_auth_records (void *cls,
761                       unsigned int rd_count,
762                       const struct GNUNET_NAMESTORE_RecordData *rd)
763 {
764   struct GetPseuAuthorityHandle *gph = cls;
765   unsigned int i;
766
767   for (i=0; i < rd_count; i++)
768   {
769     if (GNUNET_NAMESTORE_TYPE_PSEU == rd[i].record_type)
770     {
771       /* found pseu */
772       process_pseu_result (gph, 
773                            (const char *) rd[i].data);
774       return;
775     }
776   }
777   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
778               "No PSEU record found in DHT reply.\n");
779   process_pseu_result (gph, NULL);
780 }
781
782
783 /**
784  * Function called when we find a PSEU entry in the DHT
785  *
786  * @param cls the request handle
787  * @param exp lifetime
788  * @param key the key the record was stored under
789  * @param get_path get path
790  * @param get_path_length get path length
791  * @param put_path put path
792  * @param put_path_length put path length
793  * @param type the block type
794  * @param size the size of the record
795  * @param data the record data
796  */
797 static void
798 process_auth_discovery_dht_result (void* cls,
799                                    struct GNUNET_TIME_Absolute exp,
800                                    const struct GNUNET_HashCode *key,
801                                    const struct GNUNET_PeerIdentity *get_path,
802                                    unsigned int get_path_length,
803                                    const struct GNUNET_PeerIdentity *put_path,
804                                    unsigned int put_path_length,
805                                    enum GNUNET_BLOCK_Type type,
806                                    size_t size,
807                                    const void *data)
808 {
809   struct GetPseuAuthorityHandle *gph = cls;
810   const struct GNUNET_NAMESTORE_Block *block;
811
812   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
813               "Got DHT result for PSEU request\n");
814   GNUNET_DHT_get_stop (gph->get_handle);
815   gph->get_handle = NULL;
816   GNUNET_SCHEDULER_cancel (gph->timeout_task);
817   gph->timeout_task = GNUNET_SCHEDULER_NO_TASK;
818
819   if (NULL == data)
820   {
821     /* is this allowed!? */
822     GNUNET_break (0);
823     process_pseu_result (gph, NULL);
824     return;
825   }
826   if (size < sizeof (struct GNUNET_NAMESTORE_Block))
827   {
828     /* how did this pass DHT block validation!? */
829     GNUNET_break (0);
830     process_pseu_result (gph, NULL);
831     return;   
832   }
833   block = data;
834   if (size !=
835       ntohs (block->purpose.size) + 
836       sizeof (struct GNUNET_CRYPTO_EccPublicKey) +
837       sizeof (struct GNUNET_CRYPTO_EccSignature))
838   {
839     /* how did this pass DHT block validation!? */
840     GNUNET_break (0);
841     process_pseu_result (gph, NULL);
842     return;   
843   }
844   if (GNUNET_OK !=
845       GNUNET_NAMESTORE_block_decrypt (block,
846                                       &gph->target_zone,
847                                       GNUNET_GNS_TLD_PLUS,
848                                       &process_auth_records,
849                                       gph))
850   {
851     /* other peer encrypted invalid block, complain */
852     GNUNET_break_op (0);
853     process_pseu_result (gph, NULL);
854     return;   
855   }
856 }
857
858
859 /**
860  * Callback called by namestore for a zone to name result.  We're
861  * trying to see if a short name for a given zone already exists.
862  *
863  * @param cls the closure
864  * @param zone_key the zone we queried
865  * @param name the name found or NULL
866  * @param rd_len number of records for the name
867  * @param rd the record data (PKEY) for the name
868  */
869 static void
870 process_zone_to_name_discover (void *cls,
871                                const struct GNUNET_CRYPTO_EccPrivateKey *zone_key,
872                                const char *name,
873                                unsigned int rd_len,
874                                const struct GNUNET_NAMESTORE_RecordData *rd)
875 {
876   struct GetPseuAuthorityHandle* gph = cls;
877   struct GNUNET_HashCode lookup_key;
878   
879   gph->namestore_task = NULL;
880   if (0 != rd_len)
881   {
882     /* we found a match in our own zone */
883     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
884                 "Shortening aborted, name `%s' already reserved for the zone\n",
885                 name);
886     free_get_pseu_authority_handle (gph);
887     return;
888   }
889   /* record does not yet exist, go into DHT to find PSEU record */
890   GNUNET_NAMESTORE_query_from_public_key (&gph->target_zone,
891                                           GNUNET_GNS_TLD_PLUS,                                    
892                                           &lookup_key);
893   gph->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
894                                                     &handle_auth_discovery_timeout, 
895                                                     gph);
896   gph->get_handle = GNUNET_DHT_get_start (dht_handle,
897                                           GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
898                                           &lookup_key,
899                                           DHT_GNS_REPLICATION_LEVEL,
900                                           GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
901                                           NULL, 0,
902                                           &process_auth_discovery_dht_result,
903                                           gph);
904 }
905
906
907 /**
908  * Start shortening algorithm, try to allocate a nice short
909  * canonical name for @a pub in @a shorten_zone, using
910  * @a original_label as one possible suggestion.
911  *
912  * @param original_label original label for the zone
913  * @param pub public key of the zone to shorten
914  * @param shorten_zone private key of the target zone for the new record
915  */
916 static void
917 start_shorten (const char *original_label,
918                const struct GNUNET_CRYPTO_EccPublicKey *pub,
919                const struct GNUNET_CRYPTO_EccPrivateKey *shorten_zone)
920 {
921   struct GetPseuAuthorityHandle *gph;
922   
923   if (strlen (original_label) > GNUNET_DNSPARSER_MAX_LABEL_LENGTH)
924   {
925     GNUNET_break (0);
926     return;
927   }
928   gph = GNUNET_new (struct GetPseuAuthorityHandle);
929   gph->shorten_zone_key = *shorten_zone;
930   gph->target_zone = *pub;
931   strcpy (gph->label, original_label);
932   GNUNET_CONTAINER_DLL_insert (gph_head, gph_tail, gph);
933   /* first, check if we *already* have a record for this zone */
934   gph->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
935                                                        shorten_zone,
936                                                        pub,
937                                                        &process_zone_to_name_discover,
938                                                        gph);
939 }
940
941
942 /* ************************** Resolution **************************** */
943
944 #if 0
945
946
947 /**
948  * Namestore calls this function if we have record for this name.
949  * (or with rd_count=0 to indicate no matches)
950  *
951  * @param cls the pending query
952  * @param key the key of the zone we did the lookup
953  * @param expiration expiration date of the namestore entry
954  * @param name the name for which we need an authority
955  * @param rd_count the number of records with 'name'
956  * @param rd the record data
957  * @param signature the signature of the authority for the record data
958  */
959 static void
960 process_record_result_ns (void* cls,
961                           const struct GNUNET_CRYPTO_EccPublicKey *key,
962                           struct GNUNET_TIME_Absolute expiration,
963                           const char *name, unsigned int rd_count,
964                           const struct GNUNET_NAMESTORE_RecordData *rd,
965                           const struct GNUNET_CRYPTO_EccSignature *signature)
966 {
967   struct ResolverHandle *rh = cls;
968   struct RecordLookupHandle *rlh = rh->proc_cls;
969   struct GNUNET_TIME_Relative remaining_time;
970   struct GNUNET_CRYPTO_ShortHashCode zone;
971   struct GNUNET_TIME_Absolute et;
972   unsigned int i;
973
974   rh->namestore_task = NULL;
975   GNUNET_CRYPTO_short_hash (key,
976                             sizeof (struct GNUNET_CRYPTO_EccPublicKey),
977                             &zone);
978   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
979   rh->status = 0;
980   if (NULL != name)
981   {
982     rh->status |= RSL_RECORD_EXISTS;
983     if (remaining_time.rel_value_us == 0)
984       rh->status |= RSL_RECORD_EXPIRED;
985   }
986   if (0 == rd_count)
987   {
988     /**
989      * Lookup terminated and no results
990      */
991     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
992                "GNS_PHASE_REC-%llu: Namestore lookup for %s terminated without results\n",
993                rh->id, name);
994
995     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
996                "GNS_PHASE_REC-%llu: Record %s unknown in namestore\n",
997                rh->id, rh->name);
998     /**
999      * Our zone and no result? Cannot resolve TT
1000      */
1001     rh->proc(rh->proc_cls, rh, 0, NULL);
1002     return;
1003
1004   }
1005   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1006              "GNS_PHASE_REC-%llu: Processing additional result %s from namestore\n",
1007              rh->id, name);
1008   for (i = 0; i < rd_count;i++)
1009   {
1010     if (rd[i].record_type != rlh->record_type)
1011       continue;
1012
1013     if (ignore_pending_records &&
1014         (rd[i].flags & GNUNET_NAMESTORE_RF_PENDING))
1015     {
1016       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1017                  "GNS_PHASE_REC-%llu: Record %s is awaiting user confirmation. Skipping\n",
1018                  rh->id, name);
1019       continue;
1020     }
1021     
1022     //FIXME: eh? do I have to handle this here?
1023     GNUNET_break (0 == (rd[i].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION));
1024     et.abs_value_us = rd[i].expiration_time;
1025     if (0 == (GNUNET_TIME_absolute_get_remaining (et)).rel_value_us)
1026     {
1027       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1028                  "GNS_PHASE_REC-%llu: This record is expired. Skipping\n",
1029                  rh->id);
1030       continue;
1031     }
1032     rh->answered++;
1033   }
1034
1035   /**
1036    * no answers found
1037    */
1038   if (0 == rh->answered)
1039   {
1040     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
1041                "GNS_PHASE_REC-%llu: No answers found. This is odd!\n", rh->id);
1042     rh->proc(rh->proc_cls, rh, 0, NULL);
1043     return;
1044   }
1045
1046   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1047              "GNS_PHASE_REC-%llu: Found %d answer(s) to query in %d records!\n",
1048              rh->id, rh->answered, rd_count);
1049   rh->proc(rh->proc_cls, rh, rd_count, rd);
1050 }
1051
1052
1053 /**
1054  * VPN redirect result callback
1055  *
1056  * @param cls the resolver handle
1057  * @param af the requested address family
1058  * @param address in_addr(6) respectively
1059  */
1060 static void
1061 process_record_result_vpn (void* cls, int af, const void *address)
1062 {
1063   struct ResolverHandle *rh = cls;
1064   struct RecordLookupHandle *rlh = rh->proc_cls;
1065   struct GNUNET_NAMESTORE_RecordData rd;
1066
1067   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1068              "GNS_PHASE_REC_VPN-%llu: Got answer from VPN to query!\n",
1069              rh->id);
1070   if (AF_INET == af)
1071   {
1072     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1073                "GNS_PHASE_REC-%llu: Answer is IPv4!\n",
1074                rh->id);
1075     if (GNUNET_DNSPARSER_TYPE_A != rlh->record_type)
1076     {
1077       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1078                  "GNS_PHASE_REC-%llu: Requested record is not IPv4!\n",
1079                  rh->id);
1080       rh->proc (rh->proc_cls, rh, 0, NULL);
1081       return;
1082     }
1083     rd.record_type = GNUNET_DNSPARSER_TYPE_A;
1084     rd.expiration_time = UINT64_MAX; /* FIXME: should probably pick something shorter... */
1085     rd.data = address;
1086     rd.data_size = sizeof (struct in_addr);
1087     rd.flags = 0;
1088     rh->proc (rh->proc_cls, rh, 1, &rd);
1089     return;
1090   }
1091   else if (AF_INET6 == af)
1092   {
1093     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1094                "GNS_PHASE_REC-%llu: Answer is IPv6!\n",
1095                rh->id);
1096     if (GNUNET_DNSPARSER_TYPE_AAAA != rlh->record_type)
1097     {
1098       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1099                  "GNS_PHASE_REC-%llu: Requested record is not IPv6!\n",
1100                  rh->id);
1101       rh->proc (rh->proc_cls, rh, 0, NULL);
1102       return;
1103     }
1104     rd.record_type = GNUNET_DNSPARSER_TYPE_AAAA;
1105     rd.expiration_time = UINT64_MAX; /* FIXME: should probably pick something shorter... */
1106     rd.data = address;
1107     rd.data_size = sizeof (struct in6_addr);
1108     rd.flags = 0;
1109     rh->proc (rh->proc_cls, rh, 1, &rd);
1110     return;
1111   }
1112
1113   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1114              "GNS_PHASE_REC-%llu: Got garbage from VPN!\n",
1115              rh->id);
1116   rh->proc (rh->proc_cls, rh, 0, NULL);
1117 }
1118
1119
1120 /**
1121  * Process VPN lookup result for record
1122  *
1123  * @param cls the record lookup handle
1124  * @param rh resolver handle
1125  * @param rd_count number of results (1)
1126  * @param rd record data containing the result
1127  */
1128 static void
1129 handle_record_vpn (void* cls, struct ResolverHandle *rh,
1130                    unsigned int rd_count,
1131                    const struct GNUNET_NAMESTORE_RecordData *rd)
1132 {
1133   struct RecordLookupHandle* rlh = cls;
1134   
1135   if (0 == rd_count)
1136   {
1137     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1138                "GNS_PHASE_REC_VPN-%llu: VPN returned no records. (status: %d)!\n",
1139                rh->id,
1140                rh->status);
1141     /* give up, cannot resolve */
1142     finish_lookup(rh, rlh, 0, NULL);
1143     return;
1144   }
1145
1146   /* results found yay */
1147   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1148              "GNS_PHASE_REC_VPN-%llu: Record resolved from VPN!\n",
1149              rh->id);
1150
1151   finish_lookup(rh, rlh, rd_count, rd);
1152 }
1153
1154
1155 /**
1156  * The final phase of resoution.
1157  * We found a NS RR and want to resolve via DNS
1158  *
1159  * @param rh the pending lookup handle
1160  * @param rd_count length of record data
1161  * @param rd record data containing VPN RR
1162  */
1163 static void
1164 resolve_record_dns (struct ResolverHandle *rh,
1165                     unsigned int rd_count,
1166                     const struct GNUNET_NAMESTORE_RecordData *rd)
1167 {
1168   struct RecordLookupHandle *rlh = rh->proc_cls;
1169   struct GNUNET_DNSPARSER_Query query;
1170   struct GNUNET_DNSPARSER_Packet packet;
1171   struct GNUNET_DNSPARSER_Flags flags;
1172   struct in_addr dnsip;
1173   struct sockaddr_in addr;
1174   struct sockaddr *sa;
1175   unsigned int i;
1176
1177   memset (&packet, 0, sizeof (struct GNUNET_DNSPARSER_Packet));
1178   memset (rh->dns_name, 0, sizeof (rh->dns_name));
1179   
1180   /* We cancel here as to not include the ns lookup in the timeout */
1181   if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
1182   {
1183     GNUNET_SCHEDULER_cancel(rh->timeout_task);
1184     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1185   }
1186   /* Start shortening */
1187   if ((NULL != rh->priv_key) &&
1188       (GNUNET_YES == is_canonical (rh->name)))
1189   {
1190     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1191              "GNS_PHASE_REC_DNS-%llu: Trying to shorten authority chain\n",
1192              rh->id);
1193     start_shorten (rh->authority_chain_head,
1194                    rh->priv_key);
1195   }
1196
1197   for (i = 0; i < rd_count; i++)
1198   {
1199     /* Synthesize dns name */
1200     if (GNUNET_DNSPARSER_TYPE_NS == rd[i].record_type)
1201     {
1202       strcpy (rh->dns_zone, (char*)rd[i].data);
1203       if (0 == strcmp (rh->name, ""))
1204         strcpy (rh->dns_name, (char*)rd[i].data);
1205       else
1206         sprintf (rh->dns_name, "%s.%s", rh->name, (char*)rd[i].data);
1207     }
1208     /* The glue */
1209     if (GNUNET_DNSPARSER_TYPE_A == rd[i].record_type)
1210       /* need to use memcpy as .data may be unaligned */
1211       memcpy (&dnsip, rd[i].data, sizeof (dnsip));
1212   }
1213   
1214   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1215               "GNS_PHASE_REC_DNS-%llu: Looking up `%s' from `%s'\n",
1216               rh->id,
1217               rh->dns_name,
1218               inet_ntoa (dnsip));
1219   rh->dns_sock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0);
1220   if (NULL == rh->dns_sock)
1221   {
1222     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1223                 "GNS_PHASE_REC_DNS-%llu: Error creating udp socket for dns!\n",
1224                 rh->id);
1225     finish_lookup (rh, rlh, 0, NULL);
1226     return;
1227   }
1228
1229   memset (&addr, 0, sizeof (struct sockaddr_in));
1230   sa = (struct sockaddr *) &addr;
1231   sa->sa_family = AF_INET;
1232   if (GNUNET_OK != GNUNET_NETWORK_socket_bind (rh->dns_sock,
1233                                                sa,
1234                                                sizeof (struct sockaddr_in),
1235                                                0))
1236   {
1237     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1238                 "GNS_PHASE_REC_DNS-%llu: Error binding UDP socket for DNS lookup!\n",
1239                 rh->id);
1240     finish_lookup (rh, rlh, 0, NULL);
1241     return;
1242   }
1243   query.name = rh->dns_name;
1244   query.type = rlh->record_type;
1245   query.class = GNUNET_DNSPARSER_CLASS_INTERNET;
1246   memset (&flags, 0, sizeof (flags));
1247   flags.recursion_desired = 1;
1248   flags.checking_disabled = 1;
1249   packet.queries = &query;
1250   packet.answers = NULL;
1251   packet.authority_records = NULL;
1252   packet.num_queries = 1;
1253   packet.num_answers = 0;
1254   packet.num_authority_records = 0;
1255   packet.num_additional_records = 0;
1256   packet.flags = flags;
1257   packet.id = rh->id;
1258   if (GNUNET_OK != GNUNET_DNSPARSER_pack (&packet,
1259                                           UINT16_MAX,
1260                                           &rh->dns_raw_packet,
1261                                           &rh->dns_raw_packet_size))
1262   {
1263     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1264                 "GNS_PHASE_REC_DNS-%llu: Creating raw dns packet!\n",
1265                 rh->id);
1266     GNUNET_NETWORK_socket_close (rh->dns_sock);
1267     finish_lookup (rh, rlh, 0, NULL);
1268     return;
1269   }
1270
1271   rh->dns_addr.sin_family = AF_INET;
1272   rh->dns_addr.sin_port = htons (53); //domain
1273   rh->dns_addr.sin_addr = dnsip;
1274 #if HAVE_SOCKADDR_IN_SIN_LEN
1275   rh->dns_addr.sin_len = (u_char) sizeof (struct sockaddr_in);
1276 #endif
1277   send_dns_packet (rh);
1278 }
1279
1280
1281 /**
1282  * The final phase of resoution.
1283  * We found a VPN RR and want to request an IPv4/6 address
1284  *
1285  * @param rh the pending lookup handle
1286  * @param rd_count length of record data
1287  * @param rd record data containing VPN RR
1288  */
1289 static void
1290 resolve_record_vpn (struct ResolverHandle *rh,
1291                     unsigned int rd_count,
1292                     const struct GNUNET_NAMESTORE_RecordData *rd)
1293 {
1294   struct RecordLookupHandle *rlh = rh->proc_cls;
1295   struct GNUNET_HashCode serv_desc;
1296   struct vpn_data* vpn;
1297   int af;
1298   
1299   /* We cancel here as to not include the ns lookup in the timeout */
1300   if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
1301   {
1302     GNUNET_SCHEDULER_cancel(rh->timeout_task);
1303     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1304   }
1305   /* Start shortening */
1306   if ((NULL != rh->priv_key) &&
1307       (GNUNET_YES == is_canonical (rh->name)))
1308   {
1309     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1310              "GNS_PHASE_REC_VPN-%llu: Trying to shorten authority chain\n",
1311              rh->id);
1312     start_shorten (rh->authority_chain_head,
1313                    rh->priv_key);
1314   }
1315
1316   vpn = (struct vpn_data*)rd->data;
1317   GNUNET_CRYPTO_hash ((char*)&vpn[1],
1318                       strlen ((char*)&vpn[1]) + 1,
1319                       &serv_desc);
1320   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1321               "GNS_PHASE_REC_VPN-%llu: proto %hu peer %s!\n",
1322               rh->id,
1323               ntohs (vpn->proto),
1324               GNUNET_h2s (&vpn->peer));
1325
1326   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1327               "GNS_PHASE_REC_VPN-%llu: service %s -> %s!\n",
1328               rh->id,
1329               (char*)&vpn[1],
1330               GNUNET_h2s (&serv_desc));
1331   rh->proc = &handle_record_vpn;
1332   if (GNUNET_DNSPARSER_TYPE_A == rlh->record_type)
1333     af = AF_INET;
1334   else
1335     af = AF_INET6;
1336 #ifndef WINDOWS
1337   if (NULL == vpn_handle)
1338   {
1339     vpn_handle = GNUNET_VPN_connect (cfg);
1340     if (NULL == vpn_handle)
1341     {
1342       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1343                   "GNS_PHASE_INIT: Error connecting to VPN!\n");
1344       finish_lookup (rh, rh->proc_cls, 0, NULL);
1345       return;
1346     }
1347   }
1348
1349   rh->vpn_handle = GNUNET_VPN_redirect_to_peer (vpn_handle,
1350                                                 af, ntohs (vpn->proto),
1351                                                 (struct GNUNET_PeerIdentity *)&vpn->peer,
1352                                                 &serv_desc,
1353                                                 GNUNET_NO, //nac
1354                                                 GNUNET_TIME_UNIT_FOREVER_ABS, //FIXME
1355                                                 &process_record_result_vpn,
1356                                                 rh);
1357 #else
1358   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1359               "Error connecting to VPN (not available on W32 yet)\n");
1360   finish_lookup (rh, rh->proc_cls, 0, NULL);  
1361 #endif
1362 }
1363
1364
1365 /**
1366  * The final phase of resolution.
1367  * rh->name is a name that is canonical and we do not have a delegation.
1368  * Query namestore for this record
1369  *
1370  * @param rh the pending lookup handle
1371  */
1372 static void
1373 resolve_record_ns(struct ResolverHandle *rh)
1374 {
1375   struct RecordLookupHandle *rlh = rh->proc_cls;
1376   
1377   /* We cancel here as to not include the ns lookup in the timeout */
1378   if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
1379   {
1380     GNUNET_SCHEDULER_cancel(rh->timeout_task);
1381     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1382   }
1383   /* Start shortening */
1384   if ((NULL != rh->priv_key) &&
1385      (GNUNET_YES == is_canonical (rh->name)))
1386   {
1387     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1388              "GNS_PHASE_REC-%llu: Trying to shorten authority chain\n",
1389              rh->id);
1390     start_shorten (rh->authority_chain_head,
1391                    rh->priv_key);
1392   }
1393   
1394   /**
1395    * Try to resolve this record in our namestore.
1396    * The name to resolve is now in rh->authority_name
1397    * since we tried to resolve it to an authority
1398    * and failed.
1399    **/
1400   rh->namestore_task = GNUNET_NAMESTORE_lookup_record(namestore_handle,
1401                                  &rh->authority,
1402                                  rh->name,
1403                                  rlh->record_type,
1404                                  &process_record_result_ns,
1405                                  rh);
1406 }
1407
1408
1409 /**
1410  * This is a callback function that checks for key revocation
1411  *
1412  * @param cls the pending query
1413  * @param key the key of the zone we did the lookup
1414  * @param expiration expiration date of the record data set in the namestore
1415  * @param name the name for which we need an authority
1416  * @param rd_count the number of records with 'name'
1417  * @param rd the record data
1418  * @param signature the signature of the authority for the record data
1419  */
1420 static void
1421 process_pkey_revocation_result_ns (void *cls,
1422                                    const struct GNUNET_CRYPTO_EccPublicKey *key,
1423                                    struct GNUNET_TIME_Absolute expiration,
1424                                    const char *name,
1425                                    unsigned int rd_count,
1426                                    const struct GNUNET_NAMESTORE_RecordData *rd,
1427                                    const struct GNUNET_CRYPTO_EccSignature *signature)
1428 {
1429   struct ResolverHandle *rh = cls;
1430   struct GNUNET_TIME_Relative remaining_time;
1431   int i;
1432   
1433   rh->namestore_task = NULL;
1434   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1435   
1436   for (i = 0; i < rd_count; i++)
1437   {
1438     if (GNUNET_NAMESTORE_TYPE_REV == rd[i].record_type)
1439     {
1440       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1441                  "GNS_PHASE_DELEGATE_REV-%llu: Zone has been revoked.\n",
1442                  rh->id);
1443       rh->status |= RSL_PKEY_REVOKED;
1444       rh->proc (rh->proc_cls, rh, 0, NULL);
1445       return;
1446     }
1447   }
1448   
1449   if ((NULL == name) ||
1450       (0 == remaining_time.rel_value_us))
1451   {
1452     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1453           "GNS_PHASE_DELEGATE_REV-%llu: + Records don't exist or are expired.\n",
1454           rh->id, name);
1455
1456     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != rh->timeout.rel_value_us)
1457     {
1458       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1459         "GNS_PHASE_DELEGATE_REV-%llu: Starting background lookup for %s type %d\n",
1460         rh->id, "+.gads", GNUNET_NAMESTORE_TYPE_REV);
1461
1462       gns_resolver_lookup_record(rh->authority,
1463                                  rh->private_local_zone,
1464                                  GNUNET_NAMESTORE_TYPE_REV,
1465                                  GNUNET_GNS_TLD,
1466                                  NULL,
1467                                  GNUNET_TIME_UNIT_FOREVER_REL,
1468                                  GNUNET_NO,
1469                                  &background_lookup_result_processor,
1470                                  NULL);
1471     }
1472   }
1473  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1474              "GNS_PHASE_DELEGATE_REV-%llu: Revocation check passed\n",
1475              rh->id);
1476   /**
1477    * We are done with PKEY resolution if name is empty
1478    * else resolve again with new authority
1479    */
1480   if (strcmp (rh->name, "") == 0)
1481     rh->proc (rh->proc_cls, rh, rh->rd_count, &rh->rd);
1482   else
1483     resolve_delegation_ns (rh);
1484 }
1485
1486
1487 /**
1488  * Function called when we get a result from the dht
1489  * for our query. Recursively tries to resolve authorities
1490  * for name in DHT.
1491  *
1492  * @param cls the request handle
1493  * @param exp lifetime
1494  * @param key the key the record was stored under
1495  * @param get_path get path
1496  * @param get_path_length get path length
1497  * @param put_path put path
1498  * @param put_path_length put path length
1499  * @param type the block type
1500  * @param size the size of the record
1501  * @param data the record data
1502  */
1503 static void
1504 process_delegation_result_dht (void* cls,
1505                                struct GNUNET_TIME_Absolute exp,
1506                                const struct GNUNET_HashCode * key,
1507                                const struct GNUNET_PeerIdentity *get_path,
1508                                unsigned int get_path_length,
1509                                const struct GNUNET_PeerIdentity *put_path,
1510                                unsigned int put_path_length,
1511                                enum GNUNET_BLOCK_Type type,
1512                                size_t size, const void *data)
1513 {
1514   struct ResolverHandle *rh = cls;
1515   const struct GNSNameRecordBlock *nrb = data;
1516   const char* rd_data;
1517   uint32_t num_records;
1518   const char* name;
1519   uint32_t i;
1520   int rd_size;
1521   struct GNUNET_CRYPTO_ShortHashCode zone;
1522
1523   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1524               "GNS_PHASE_DELEGATE_DHT-%llu: Got DHT result\n",
1525               rh->id);
1526   if (data == NULL)
1527     return;
1528    /* stop dht lookup and timeout task */
1529   GNUNET_DHT_get_stop (rh->get_handle);
1530   rh->get_handle = NULL;
1531   if (rh->dht_heap_node != NULL)
1532   {
1533     GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
1534     rh->dht_heap_node = NULL;
1535   }
1536
1537   num_records = ntohl(nrb->rd_count);
1538   name = (const char*) &nrb[1];
1539   {
1540     struct GNUNET_NAMESTORE_RecordData rd[num_records];
1541     struct NamestoreBGTask *ns_heap_root;
1542     struct NamestoreBGTask *namestore_bg_task;
1543     
1544     rd_data = name + strlen(name) + 1;
1545     rd_size = size - strlen(name) - 1 - sizeof (struct GNSNameRecordBlock);
1546     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
1547                                                                rd_data,
1548                                                                num_records,
1549                                                                rd))
1550     {
1551       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1552                  "GNS_PHASE_DELEGATE_DHT-%llu: Error deserializing data!\n",
1553                  rh->id);
1554       return;
1555     }
1556
1557     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1558                "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n",
1559                rh->id, name, rh->authority_name);
1560     for (i=0; i<num_records; i++)
1561     {
1562       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1563                   "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n",
1564                   rh->id, name, rh->authority_name);
1565       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1566                  "GNS_PHASE_DELEGATE_DHT-%llu: Got type: %d (wanted %d)\n",
1567                  rh->id, rd[i].record_type, GNUNET_NAMESTORE_TYPE_PKEY);
1568       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1569                  "GNS_PHASE_DELEGATE_DHT-%llu: Got data length: %d\n",
1570                  rh->id, rd[i].data_size);
1571       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1572                  "GNS_PHASE_DELEGATE_DHT-%llu: Got flag %d\n",
1573                  rh->id, rd[i].flags);
1574       
1575       if ((GNUNET_NAMESTORE_TYPE_VPN == rd[i].record_type) ||
1576           (GNUNET_DNSPARSER_TYPE_NS == rd[i].record_type) ||
1577           (GNUNET_DNSPARSER_TYPE_CNAME == rd[i].record_type))
1578       {
1579         /**
1580          * This is a VPN,NS,CNAME entry. Let namestore handle this after caching
1581          */
1582         if (0 == strcmp(rh->name, ""))
1583           strcpy(rh->name, rh->authority_name);
1584         else
1585           GNUNET_snprintf(rh->name, GNUNET_DNSPARSER_MAX_NAME_LENGTH, "%s.%s",
1586                  rh->name, rh->authority_name); //FIXME ret
1587         rh->answered = 1;
1588         break;
1589       }
1590
1591       if ((0 == strcmp(name, rh->authority_name)) &&
1592           (GNUNET_NAMESTORE_TYPE_PKEY == rd[i].record_type))
1593       {
1594         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1595                    "GNS_PHASE_DELEGATE_DHT-%llu: Authority found in DHT\n",
1596                    rh->id);
1597         rh->answered = 1;
1598         memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1599         struct AuthorityChain *auth =
1600           GNUNET_malloc(sizeof(struct AuthorityChain));
1601         auth->zone = rh->authority;
1602         memset(auth->name, 0, strlen(rh->authority_name)+1);
1603         strcpy(auth->name, rh->authority_name);
1604         GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1605                                      rh->authority_chain_tail,
1606                                      auth);
1607
1608         if (NULL != rh->rd.data)
1609           GNUNET_free ((void*)rh->rd.data);
1610         
1611         memcpy (&rh->rd, &rd[i], sizeof (struct GNUNET_NAMESTORE_RecordData));
1612         rh->rd.data = GNUNET_malloc (rd[i].data_size);
1613         memcpy ((void*)(rh->rd.data), rd[i].data, rd[i].data_size);
1614         rh->rd_count = 1;
1615
1616         /** try to import pkey if private key available */
1617         //if (rh->priv_key && is_canonical (rh->name))
1618         //  process_discovered_authority(name, auth->zone,
1619         //                               rh->authority_chain_tail->zone,
1620         //                               rh->priv_key);
1621       }
1622
1623     }
1624     GNUNET_GNS_get_zone_from_key (name, key, &zone);
1625
1626
1627     /* Save to namestore
1628     if (0 != GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1629                                           &zone))
1630     {*/
1631       if (max_allowed_ns_tasks <=
1632           GNUNET_CONTAINER_heap_get_size (ns_task_heap))
1633       {
1634         ns_heap_root = GNUNET_CONTAINER_heap_remove_root (ns_task_heap);
1635         GNUNET_NAMESTORE_cancel (ns_heap_root->qe);
1636
1637         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1638                    "GNS_PHASE_DELEGATE_DHT-%llu: Replacing oldest background ns task\n",
1639                    rh->id);
1640       }
1641       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1642                   "GNS_PHASE_DELEGATE_DHT-%llu: Caching record for %s\n",
1643                   rh->id, name);
1644       namestore_bg_task = GNUNET_malloc (sizeof (struct NamestoreBGTask));
1645
1646       namestore_bg_task->node = GNUNET_CONTAINER_heap_insert (ns_task_heap,
1647                                     namestore_bg_task,
1648                                     GNUNET_TIME_absolute_get().abs_value_us);
1649       namestore_bg_task->qe = GNUNET_NAMESTORE_record_put (namestore_handle,
1650                                  &nrb->public_key,
1651                                  name,
1652                                  exp,
1653                                  num_records,
1654                                  rd,
1655                                  &nrb->signature,
1656                                  &on_namestore_delegation_put_result, //cont
1657                                  namestore_bg_task); //cls
1658     }
1659   //}
1660
1661   if (0 != rh->answered)
1662   {
1663     rh->answered = 0;
1664     /**
1665      * delegate
1666      * FIXME in this case. should we ask namestore again?
1667      */
1668     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1669     "GNS_PHASE_DELEGATE_DHT-%llu: Answer from DHT for %s. Yet to resolve: %s\n",
1670     rh->id, rh->authority_name, rh->name);
1671
1672     if (0 == strcmp(rh->name, ""))
1673     {
1674       /* Start shortening */
1675       if ((NULL != rh->priv_key) &&
1676           (GNUNET_YES == is_canonical (rh->name)))
1677       {
1678         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1679              "GNS_PHASE_DELEGATE_DHT-%llu: Trying to shorten authority chain\n",
1680              rh->id);
1681         start_shorten (rh->authority_chain_head,
1682                        rh->priv_key);
1683       }
1684     }
1685     else
1686       rh->proc = &handle_delegation_ns;
1687
1688
1689     /* Check for key revocation and delegate */
1690     rh->namestore_task = GNUNET_NAMESTORE_lookup (namestore_handle,
1691                                                   &rh->authority,
1692                                                   GNUNET_GNS_MASTERZONE_STR,
1693                                                   GNUNET_NAMESTORE_TYPE_REV,
1694                                                   &process_pkey_revocation_result_ns,
1695                                                   rh);
1696
1697     return;
1698   }
1699   
1700   /**
1701    * No pkey but name exists
1702    * promote back
1703    */
1704   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1705              "GNS_PHASE_DELEGATE_DHT-%llu: Adding %s back to %s\n",
1706              rh->id, rh->authority_name, rh->name);
1707   if (0 == strcmp(rh->name, ""))
1708     strcpy(rh->name, rh->authority_name);
1709   else
1710     GNUNET_snprintf(rh->name, GNUNET_DNSPARSER_MAX_NAME_LENGTH, "%s.%s",
1711                   rh->name, rh->authority_name); //FIXME ret
1712   
1713   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1714              "GNS_PHASE_DELEGATE_DHT-%llu: %s restored\n", rh->id, rh->name);
1715   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1716           "GNS_PHASE_DELEGATE_DHT-%llu: DHT authority lookup found no match!\n",
1717            rh->id);
1718   rh->proc(rh->proc_cls, rh, 0, NULL);
1719 }
1720
1721 //FIXME maybe define somewhere else?
1722 #define MAX_SOA_LENGTH sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)\
1723                         +(GNUNET_DNSPARSER_MAX_NAME_LENGTH*2)
1724 #define MAX_MX_LENGTH sizeof(uint16_t)+GNUNET_DNSPARSER_MAX_NAME_LENGTH
1725 #define MAX_SRV_LENGTH (sizeof(uint16_t)*3)+GNUNET_DNSPARSER_MAX_NAME_LENGTH
1726
1727
1728 /**
1729  * Exands a name ending in .+ with the zone of origin.
1730  * FIXME: funky api: 'dest' must be large enough to hold
1731  * the result; this is a bit yucky...
1732  *
1733  * @param dest destination buffer
1734  * @param src the .+ name
1735  * @param repl the string to replace the + with
1736  */
1737 static void
1738 expand_plus (char* dest, 
1739              const char* src, 
1740              const char* repl)
1741 {
1742   char* pos;
1743   size_t s_len = strlen (src) + 1;
1744
1745   //Eh? I guess this is at least strlen ('x.+') == 3 FIXME
1746   if (3 > s_len)
1747   {
1748     /* no postprocessing */
1749     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1750                "GNS_POSTPROCESS: %s too short\n", src);
1751     memcpy (dest, src, s_len);
1752     return;
1753   }
1754   if (0 == strcmp (src + s_len - 3, ".+"))
1755   {
1756     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1757                 "GNS_POSTPROCESS: Expanding .+ in %s\n", 
1758                 src);
1759     memset (dest, 0, s_len + strlen (repl) + strlen(GNUNET_GNS_TLD));
1760     strcpy (dest, src);
1761     pos = dest + s_len - 2;
1762     strcpy (pos, repl);
1763     pos += strlen (repl);
1764     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1765                 "GNS_POSTPROCESS: Expanded to %s\n", 
1766                 dest);
1767   }
1768   else
1769   {
1770     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1771                "GNS_POSTPROCESS: No postprocessing for %s\n", src);
1772     memcpy (dest, src, s_len);
1773   }
1774 }
1775
1776
1777 /**
1778  * finish lookup
1779  */
1780 static void
1781 finish_lookup (struct ResolverHandle *rh,
1782                struct RecordLookupHandle* rlh,
1783                unsigned int rd_count,
1784                const struct GNUNET_NAMESTORE_RecordData *rd)
1785 {
1786   unsigned int i;
1787   char new_rr_data[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
1788   char new_mx_data[MAX_MX_LENGTH];
1789   char new_soa_data[MAX_SOA_LENGTH];
1790   char new_srv_data[MAX_SRV_LENGTH];
1791   struct srv_data *old_srv;
1792   struct srv_data *new_srv;
1793   struct soa_data *old_soa;
1794   struct soa_data *new_soa;
1795   struct GNUNET_NAMESTORE_RecordData p_rd[rd_count];
1796   char* repl_string;
1797   char* pos;
1798   unsigned int offset;
1799
1800   if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
1801   {
1802     GNUNET_SCHEDULER_cancel(rh->timeout_task);
1803     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1804   }
1805
1806   GNUNET_CONTAINER_DLL_remove (rlh_head, rlh_tail, rh);
1807
1808   if (0 < rd_count)
1809     memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData));
1810
1811   for (i = 0; i < rd_count; i++)
1812   {
1813     
1814     if ((GNUNET_DNSPARSER_TYPE_NS != rd[i].record_type) &&
1815         (GNUNET_DNSPARSER_TYPE_PTR != rd[i].record_type) &&
1816         (GNUNET_DNSPARSER_TYPE_CNAME != rd[i].record_type) &&
1817         (GNUNET_DNSPARSER_TYPE_MX != rd[i].record_type) &&
1818         (GNUNET_DNSPARSER_TYPE_SOA != rd[i].record_type) &&
1819         (GNUNET_DNSPARSER_TYPE_SRV != rd[i].record_type))
1820     {
1821       p_rd[i].data = rd[i].data;
1822       continue;
1823     }
1824
1825     /**
1826      * for all those records we 'should'
1827      * also try to resolve the A/AAAA records (RFC1035)
1828      * This is a feature and not important
1829      */
1830     
1831     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1832                "GNS_POSTPROCESS: Postprocessing\n");
1833     if (0 == strcmp(rh->name, GNUNET_GNS_MASTERZONE_STR))
1834       repl_string = rlh->name;
1835     else
1836       repl_string = rlh->name+strlen(rh->name)+1;
1837
1838     offset = 0;
1839     if (GNUNET_DNSPARSER_TYPE_MX == rd[i].record_type)
1840     {
1841       memcpy (new_mx_data, (char*)rd[i].data, sizeof(uint16_t));
1842       offset = sizeof (uint16_t);
1843       pos = new_mx_data + offset;
1844       // FIXME: how do we know that 'pos' has enough space for the new name?
1845       expand_plus (pos, (char*)rd[i].data+sizeof(uint16_t),
1846                    repl_string);
1847       offset += strlen(new_mx_data+sizeof(uint16_t)) + 1;
1848       p_rd[i].data = new_mx_data;
1849       p_rd[i].data_size = offset;
1850     }
1851     else if (GNUNET_DNSPARSER_TYPE_SRV == rd[i].record_type)
1852     {
1853       /*
1854        * Prio, weight and port
1855        */
1856       new_srv = (struct srv_data*)new_srv_data;
1857       old_srv = (struct srv_data*)rd[i].data;
1858       new_srv->prio = old_srv->prio;
1859       new_srv->weight = old_srv->weight;
1860       new_srv->port = old_srv->port;
1861       // FIXME: how do we know that '&new_srv[1]' has enough space for the new name?
1862       expand_plus((char*)&new_srv[1], (char*)&old_srv[1],
1863                   repl_string);
1864       p_rd[i].data = new_srv_data;
1865       p_rd[i].data_size = sizeof (struct srv_data) + strlen ((char*)&new_srv[1]) + 1;
1866     }
1867     else if (GNUNET_DNSPARSER_TYPE_SOA == rd[i].record_type)
1868     {
1869       /* expand mname and rname */
1870       old_soa = (struct soa_data*)rd[i].data;
1871       new_soa = (struct soa_data*)new_soa_data;
1872       memcpy (new_soa, old_soa, sizeof (struct soa_data));
1873       // FIXME: how do we know that 'new_soa[1]' has enough space for the new name?
1874       expand_plus((char*)&new_soa[1], (char*)&old_soa[1], repl_string);
1875       offset = strlen ((char*)&new_soa[1]) + 1;
1876       // FIXME: how do we know that 'new_soa[1]' has enough space for the new name?
1877       expand_plus((char*)&new_soa[1] + offset,
1878                   (char*)&old_soa[1] + strlen ((char*)&old_soa[1]) + 1,
1879                   repl_string);
1880       p_rd[i].data_size = sizeof (struct soa_data)
1881                           + offset
1882                           + strlen ((char*)&new_soa[1] + offset);
1883       p_rd[i].data = new_soa_data;
1884     }
1885     else
1886     {
1887       pos = new_rr_data;
1888       // FIXME: how do we know that 'rd[i].data' has enough space for the new name?
1889       expand_plus(pos, (char*)rd[i].data, repl_string);
1890       p_rd[i].data_size = strlen(new_rr_data)+1;
1891       p_rd[i].data = new_rr_data;
1892     }
1893     
1894   }
1895
1896   rlh->proc(rlh->proc_cls, rd_count, p_rd);
1897   GNUNET_free(rlh);
1898   free_resolver_handle (rh);
1899 }
1900
1901
1902 /**
1903  * Process DHT lookup result for record.
1904  *
1905  * @param cls the closure
1906  * @param rh resolver handle
1907  * @param rd_count number of results
1908  * @param rd record data
1909  */
1910 static void
1911 handle_record_dht (void* cls, struct ResolverHandle *rh,
1912                    unsigned int rd_count,
1913                    const struct GNUNET_NAMESTORE_RecordData *rd)
1914 {
1915   struct RecordLookupHandle* rlh = cls;
1916
1917   if (0 == rd_count)
1918   {
1919     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1920                "GNS_PHASE_REC-%llu: No records for %s found in DHT. Aborting\n",
1921                rh->id, rh->name);
1922     /* give up, cannot resolve */
1923     finish_lookup (rh, rlh, 0, NULL);
1924     return;
1925   }
1926   /* results found yay */
1927   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1928              "GNS_PHASE_REC-%llu: Record resolved from DHT!", rh->id);
1929   finish_lookup (rh, rlh, rd_count, rd);
1930 }
1931
1932
1933 /**
1934  * Process namestore lookup result for record.
1935  *
1936  * @param cls the closure
1937  * @param rh resolver handle
1938  * @param rd_count number of results
1939  * @param rd record data
1940  */
1941 static void
1942 handle_record_ns (void* cls, struct ResolverHandle *rh,
1943                   unsigned int rd_count,
1944                   const struct GNUNET_NAMESTORE_RecordData *rd)
1945 {
1946   struct RecordLookupHandle* rlh = cls;
1947   int check_dht = GNUNET_YES;
1948   
1949   if (0 != rd_count)
1950   {
1951     /* results found yay */
1952     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1953                "GNS_PHASE_REC-%llu: Record resolved from namestore!\n", rh->id);
1954     finish_lookup (rh, rlh, rd_count, rd);
1955     return;
1956   }
1957   
1958   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1959               "GNS_PHASE_REC-%llu: NS returned no records. (status: %d)!\n",
1960               rh->id,
1961               rh->status);
1962   /**
1963    * There are 5 conditions that have to met for us to consult the DHT:
1964    * 1. The entry in the DHT is RSL_RECORD_EXPIRED OR
1965    * 2. No entry in the NS existed AND
1966    * 3. The zone queried is not the local resolver's zone AND
1967    * 4. The name that was looked up is '+'
1968    *    because if it was any other canonical name we either already queried
1969    *    the DHT for the authority in the authority lookup phase (and thus
1970    *    would already have an entry in the NS for the record)
1971    * 5. We are not in cache only mode
1972    */
1973   if ((0 != (rh->status & RSL_RECORD_EXPIRED)) &&
1974       (0 == (rh->status & RSL_RECORD_EXISTS)) )
1975   {
1976     
1977     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1978               "GNS_PHASE_REC-%llu: Not expired and exists!\n",
1979               rh->id);
1980     check_dht = GNUNET_NO;
1981   }
1982   
1983   if (0 == GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1984                                         &rh->private_local_zone))
1985   {
1986
1987     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1988               "GNS_PHASE_REC-%llu: Our zone!\n",
1989               rh->id);
1990     check_dht = GNUNET_NO;
1991   }
1992   
1993   if ((0 != strcmp (rh->name, GNUNET_GNS_MASTERZONE_STR)) && (GNUNET_YES == is_srv (rh->name)))
1994       check_dht = GNUNET_NO;
1995
1996   if (GNUNET_YES == rh->only_cached)
1997     check_dht = GNUNET_NO;
1998   
1999   if (GNUNET_YES == check_dht)
2000   {
2001     rh->proc = &handle_record_dht;
2002     resolve_record_dht(rh);
2003     return;
2004   }
2005   /* give up, cannot resolve */
2006   finish_lookup (rh, rlh, 0, NULL);
2007 }
2008
2009
2010 /**
2011  * Move one level up in the domain hierarchy and return the
2012  * passed top level domain.
2013  *
2014  * FIXME: funky API: not only 'dest' is updated, so is 'name'!
2015  *
2016  * @param name the domain
2017  * @param dest the destination where the tld will be put
2018  */
2019 static void
2020 pop_tld (char* name, char* dest)
2021 {
2022   uint32_t len;
2023
2024   if (GNUNET_YES == is_canonical (name))
2025   {
2026     strcpy (dest, name);
2027     strcpy (name, "");
2028     return;
2029   }
2030
2031   for (len = strlen(name); 0 < len; len--)
2032   {
2033     if (*(name+len) == '.')
2034       break;
2035   }
2036   
2037   //Was canonical?
2038   if (0 == len)
2039     return;
2040   name[len] = '\0';
2041   strcpy (dest, (name+len+1));
2042 }
2043
2044
2045 /**
2046  * DHT resolution for delegation finished. Processing result.
2047  *
2048  * @param cls the closure
2049  * @param rh resolver handle
2050  * @param rd_count number of results (always 0)
2051  * @param rd record data (always NULL)
2052  */
2053 static void
2054 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
2055                           unsigned int rd_count,
2056                           const struct GNUNET_NAMESTORE_RecordData *rd)
2057 {
2058   struct RecordLookupHandle* rlh = cls;
2059   
2060   if (0 == strcmp(rh->name, ""))
2061   {
2062     if (GNUNET_NAMESTORE_TYPE_PKEY == rlh->record_type)
2063     {
2064       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2065                  "GNS_PHASE_DELEGATE_DHT-%llu: Resolved queried PKEY via DHT.\n",
2066                  rh->id);
2067       finish_lookup(rh, rlh, rd_count, rd);
2068       return;
2069     }
2070     /* We resolved full name for delegation. resolving record */
2071     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2072      "GNS_PHASE_DELEGATE_DHT-%llu: Resolved full name for delegation via DHT.\n",
2073      rh->id);
2074     strcpy(rh->name, "+\0");
2075     rh->proc = &handle_record_ns;
2076     resolve_record_ns(rh);
2077     return;
2078   }
2079
2080   /**
2081    * we still have some left
2082    **/
2083   if (GNUNET_YES == is_canonical (rh->name))
2084   {
2085     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2086              "GNS_PHASE_DELEGATE_DHT-%llu: Resolving canonical record %s in ns\n",
2087              rh->id,
2088              rh->name);
2089     rh->proc = &handle_record_ns;
2090     resolve_record_ns(rh);
2091     return;
2092   }
2093   /* give up, cannot resolve */
2094   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2095  "GNS_PHASE_DELEGATE_DHT-%llu: Cannot fully resolve delegation for %s via DHT!\n",
2096  rh->id, rh->name);
2097   finish_lookup(rh, rlh, 0, NULL);
2098 }
2099
2100
2101 /**
2102  * Start DHT lookup for a name -> PKEY (compare NS) record in
2103  * rh->authority's zone
2104  *
2105  * @param rh the pending gns query
2106  */
2107 static void
2108 resolve_delegation_dht (struct ResolverHandle *rh)
2109 {
2110   uint32_t xquery;
2111   struct GNUNET_HashCode lookup_key;
2112   struct ResolverHandle *rh_heap_root;
2113   
2114   pop_tld (rh->name, rh->authority_name);
2115   GNUNET_GNS_get_key_for_record (rh->authority_name,
2116                                  &rh->authority, 
2117                                  &lookup_key);
2118   rh->dht_heap_node = NULL;
2119   if (rh->timeout.rel_value_us != GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
2120   {
2121     rh->timeout_cont = &dht_authority_lookup_timeout;
2122     rh->timeout_cont_cls = rh;
2123   }
2124   else 
2125   {
2126     if (max_allowed_background_queries <=
2127         GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
2128     {
2129       /* terminate oldest lookup */
2130       rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
2131       GNUNET_DHT_get_stop (rh_heap_root->get_handle);
2132       rh_heap_root->get_handle = NULL;
2133       rh_heap_root->dht_heap_node = NULL;
2134       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2135                   "GNS_PHASE_DELEGATE_DHT-%llu: Replacing oldest background query for %s\n",
2136                   rh->id, 
2137                   rh_heap_root->authority_name);
2138       rh_heap_root->proc (rh_heap_root->proc_cls,
2139                           rh_heap_root,
2140                           0,
2141                           NULL);
2142     }
2143     rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
2144                                                       rh,
2145                                                       GNUNET_TIME_absolute_get().abs_value_us);
2146   }
2147   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2148               "Beginning DHT lookup for %s in zone %s for request %llu\n",
2149               rh->authority_name,
2150               GNUNET_short_h2s (&rh->authority),
2151               rh->id);
2152   xquery = htonl (GNUNET_NAMESTORE_TYPE_PKEY);
2153   GNUNET_assert (rh->get_handle == NULL);
2154   rh->get_handle = GNUNET_DHT_get_start (dht_handle,
2155                                          GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
2156                                          &lookup_key,
2157                                          DHT_GNS_REPLICATION_LEVEL,
2158                                          GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
2159                                          &xquery,
2160                                          sizeof(xquery),
2161                                          &process_delegation_result_dht,
2162                                          rh);
2163 }
2164
2165
2166 /**
2167  * Namestore resolution for delegation finished. Processing result.
2168  *
2169  * @param cls the closure
2170  * @param rh resolver handle
2171  * @param rd_count number of results (always 0)
2172  * @param rd record data (always NULL)
2173  */
2174 static void
2175 handle_delegation_ns (void* cls, struct ResolverHandle *rh,
2176                       unsigned int rd_count,
2177                       const struct GNUNET_NAMESTORE_RecordData *rd)
2178 {
2179   struct RecordLookupHandle* rlh = cls;
2180   int check_dht;
2181   size_t s_len;
2182
2183   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2184               "GNS_PHASE_DELEGATE_NS-%llu: Resolution status: %d.\n",
2185               rh->id, rh->status);
2186
2187   if (rh->status & RSL_PKEY_REVOKED)
2188   {
2189     finish_lookup (rh, rlh, 0, NULL);
2190     return;
2191   }
2192   
2193   if (0 == strcmp(rh->name, ""))
2194   {
2195     
2196     /* We resolved full name for delegation. resolving record */
2197     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2198               "GNS_PHASE_DELEGATE_NS-%llu: Resolved full name for delegation.\n",
2199               rh->id);
2200     if (rh->status & RSL_CNAME_FOUND)
2201     {
2202       if (GNUNET_DNSPARSER_TYPE_CNAME == rlh->record_type)
2203       {
2204         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2205                   "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried CNAME in NS.\n",
2206                   rh->id);
2207         strcpy (rh->name, rh->authority_name);
2208         finish_lookup (rh, rlh, rd_count, rd);
2209         return;
2210       }
2211       
2212       /* A .+ CNAME  */
2213       if (GNUNET_YES == is_tld ((char*)rd->data, GNUNET_GNS_TLD_PLUS))
2214       {
2215         s_len = strlen (rd->data) - 2;
2216         memcpy (rh->name, rd->data, s_len);
2217         rh->name[s_len] = '\0';
2218         resolve_delegation_ns (rh);
2219         return;
2220       }
2221       else if (GNUNET_YES == is_tld ((char*)rd->data, GNUNET_GNS_TLD_ZKEY))
2222       {
2223         gns_resolver_lookup_record (rh->authority,
2224                                     rh->private_local_zone,
2225                                     rlh->record_type,
2226                                     (char*)rd->data,
2227                                     rh->priv_key,
2228                                     rh->timeout,
2229                                     rh->only_cached,
2230                                     rlh->proc,
2231                                     rlh->proc_cls);
2232         GNUNET_free (rlh);
2233         GNUNET_CONTAINER_DLL_remove (rlh_head, rlh_tail, rh);
2234         free_resolver_handle (rh);
2235         return;
2236       }
2237       else
2238       {
2239         //Try DNS resolver
2240         strcpy (rh->dns_name, (char*)rd->data);
2241         resolve_dns_name (rh);
2242         return;
2243       }
2244
2245     }
2246     else if (rh->status & RSL_DELEGATE_VPN)
2247     {
2248       if (GNUNET_NAMESTORE_TYPE_VPN == rlh->record_type)
2249       {
2250         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2251                  "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried VPNRR in NS.\n",
2252                  rh->id);
2253         finish_lookup(rh, rlh, rd_count, rd);
2254         return;
2255       }
2256       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2257              "GNS_PHASE_DELEGATE_NS-%llu: VPN delegation starting.\n",
2258              rh->id);
2259       GNUNET_assert (NULL != rd);
2260       rh->proc = &handle_record_vpn;
2261       resolve_record_vpn (rh, rd_count, rd);
2262       return;
2263     }
2264     else if (rh->status & RSL_DELEGATE_NS)
2265     {
2266       if (GNUNET_DNSPARSER_TYPE_NS == rlh->record_type)
2267       {
2268         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2269                     "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried NSRR in NS.\n",
2270                     rh->id);
2271         finish_lookup (rh, rlh, rd_count, rd);
2272         return;
2273       }      
2274       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2275                   "GNS_PHASE_DELEGATE_NS-%llu: NS delegation starting.\n",
2276                   rh->id);
2277       GNUNET_assert (NULL != rd);
2278       rh->proc = &handle_record_ns;
2279       resolve_record_dns (rh, rd_count, rd);
2280       return;
2281     }
2282     else if (rh->status & RSL_DELEGATE_PKEY)
2283     {
2284       if (rh->status & RSL_PKEY_REVOKED)
2285       {
2286         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2287                    "GNS_PHASE_DELEGATE_NS-%llu: Resolved PKEY is revoked.\n",
2288                    rh->id);
2289         finish_lookup (rh, rlh, 0, NULL);
2290         return;
2291       }
2292       else if (GNUNET_NAMESTORE_TYPE_PKEY == rlh->record_type)
2293       {
2294         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2295                    "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried PKEY in NS.\n",
2296                    rh->id);
2297         finish_lookup(rh, rlh, rd_count, rd);
2298         return;
2299       }
2300     }
2301     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2302                "GNS_PHASE_DELEGATE_NS-%llu: Resolving record +\n",
2303                rh->id);
2304     strcpy(rh->name, "+\0");
2305     rh->proc = &handle_record_ns;
2306     resolve_record_ns(rh);
2307     return;
2308   }
2309   
2310   if (rh->status & RSL_DELEGATE_NS)
2311   {
2312     if (GNUNET_DNSPARSER_TYPE_NS == rlh->record_type)
2313     {
2314       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2315                  "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried NSRR in NS.\n",
2316                  rh->id);
2317       finish_lookup(rh, rlh, rd_count, rd);
2318       return;
2319     }
2320     
2321     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2322                "GNS_PHASE_DELEGATE_NS-%llu: NS delegation starting.\n",
2323                rh->id);
2324     GNUNET_assert (NULL != rd);
2325     rh->proc = &handle_record_ns;
2326     resolve_record_dns (rh, rd_count, rd);
2327     return;
2328   }
2329   
2330   /**
2331    * we still have some left
2332    * check if authority in ns is fresh
2333    * and exists
2334    * or we are authority
2335    **/
2336
2337   check_dht = GNUNET_YES;
2338   if ((rh->status & RSL_RECORD_EXISTS) &&
2339        !(rh->status & RSL_RECORD_EXPIRED))
2340     check_dht = GNUNET_NO;
2341
2342   if (0 == GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2343                                         &rh->private_local_zone))
2344     check_dht = GNUNET_NO;
2345
2346   if (GNUNET_YES == rh->only_cached)
2347     check_dht = GNUNET_NO;
2348
2349   if (GNUNET_YES == check_dht)
2350   {
2351
2352     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2353         "GNS_PHASE_DELEGATE_NS-%llu: Trying to resolve delegation for %s via DHT\n",
2354         rh->id, rh->name);
2355     rh->proc = &handle_delegation_dht;
2356     resolve_delegation_dht(rh);
2357     return;
2358   }
2359   
2360   if (GNUNET_NO == is_canonical (rh->name))
2361   {
2362     /* give up, cannot resolve */
2363     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2364         "GNS_PHASE_DELEGATE_NS-%llu: Cannot fully resolve delegation for %s!\n",
2365         rh->id,
2366         rh->name);
2367     finish_lookup(rh, rlh, rd_count, rd);
2368     return;
2369   }
2370   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2371              "GNS_PHASE_DELEGATE_NS-%llu: Resolving canonical record %s\n",
2372              rh->id,
2373              rh->name);
2374   rh->proc = &handle_record_ns;
2375   resolve_record_ns(rh);
2376 }
2377
2378
2379 /**
2380  * This is a callback function that should give us only PKEY
2381  * records. Used to query the namestore for the authority (PKEY)
2382  * for 'name'. It will recursively try to resolve the
2383  * authority for a given name from the namestore.
2384  *
2385  * @param cls the pending query
2386  * @param key the key of the zone we did the lookup
2387  * @param expiration expiration date of the record data set in the namestore
2388  * @param name the name for which we need an authority
2389  * @param rd_count the number of records with 'name'
2390  * @param rd the record data
2391  * @param signature the signature of the authority for the record data
2392  */
2393 static void
2394 process_delegation_result_ns (void* cls,
2395                               const struct GNUNET_CRYPTO_EccPublicKey *key,
2396                               struct GNUNET_TIME_Absolute expiration,
2397                               const char *name,
2398                               unsigned int rd_count,
2399                               const struct GNUNET_NAMESTORE_RecordData *rd,
2400                               const struct GNUNET_CRYPTO_EccSignature *signature)
2401 {
2402   struct ResolverHandle *rh = cls;
2403   struct GNUNET_TIME_Relative remaining_time;
2404   struct GNUNET_CRYPTO_ShortHashCode zone;
2405   char new_name[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
2406   unsigned int i;
2407   struct GNUNET_TIME_Absolute et;
2408   struct AuthorityChain *auth;
2409  
2410   rh->namestore_task = NULL;
2411   GNUNET_CRYPTO_short_hash (key,
2412                             sizeof (struct GNUNET_CRYPTO_EccPublicKey),
2413                             &zone);
2414   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2415               "GNS_PHASE_DELEGATE_NS-%llu: Got %d records from authority lookup for `%s' in zone %s\n",
2416               rh->id, rd_count,
2417               name,
2418               GNUNET_short_h2s (&zone));
2419
2420   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
2421   
2422   rh->status = 0;
2423   
2424   if (NULL != name)
2425   {
2426     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2427                 "GNS_PHASE_DELEGATE_NS-%llu: Records with name `%s' exist in zone %s.\n",
2428                 rh->id, name,
2429                 GNUNET_short_h2s (&zone));
2430     rh->status |= RSL_RECORD_EXISTS;
2431   
2432     if (0 == remaining_time.rel_value_us)
2433     {
2434       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2435                   "GNS_PHASE_DELEGATE_NS-%llu: Record set %s expired.\n",
2436                   rh->id, name);
2437       rh->status |= RSL_RECORD_EXPIRED;
2438     }
2439   }
2440   
2441   /**
2442    * No authority found in namestore.
2443    */
2444   if (0 == rd_count)
2445   {
2446     /**
2447      * We did not find an authority in the namestore
2448      */
2449     
2450     /**
2451      * No PKEY in zone.
2452      * Promote this authority back to a name maybe it is
2453      * our record.
2454      */
2455     if (strcmp (rh->name, "") == 0)
2456     {
2457       /* simply promote back */
2458       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2459                   "GNS_PHASE_DELEGATE_NS-%llu: Promoting %s back to name\n",
2460                   rh->id, rh->authority_name);
2461       strcpy (rh->name, rh->authority_name);
2462     }
2463     else
2464     {
2465       /* add back to existing name */
2466       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2467                   "GNS_PHASE_DELEGATE_NS-%llu: Adding %s back to %s\n",
2468                   rh->id, rh->authority_name, rh->name);
2469       GNUNET_snprintf (new_name, GNUNET_DNSPARSER_MAX_NAME_LENGTH, "%s.%s",
2470                        rh->name, rh->authority_name);
2471       strcpy (rh->name, new_name);
2472       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2473                   "GNS_PHASE_DELEGATE_NS-%llu: %s restored\n",
2474                   rh->id, rh->name);
2475     }
2476
2477     rh->proc (rh->proc_cls, rh, 0, NULL);
2478     return;
2479   }
2480
2481   /**
2482    * We found an authority that may be able to help us
2483    * move on with query
2484    * Note only 1 pkey should have been returned.. anything else would be strange
2485    */
2486   for (i=0; i < rd_count;i++)
2487   {
2488     switch (rd[i].record_type)
2489     {
2490     case GNUNET_DNSPARSER_TYPE_CNAME:
2491       /* Like in regular DNS this should mean that there is no other
2492        * record for this name.  */
2493
2494       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2495                   "GNS_PHASE_DELEGATE_NS-%llu: CNAME `%.*s' found.\n",
2496                   rh->id,
2497                   (int) rd[i].data_size,
2498                   rd[i].data);
2499       rh->status |= RSL_CNAME_FOUND;
2500       rh->proc (rh->proc_cls, rh, rd_count, rd);
2501       return;
2502     case GNUNET_NAMESTORE_TYPE_VPN:
2503       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2504                   "GNS_PHASE_DELEGATE_NS-%llu: VPN found.\n",
2505                   rh->id);
2506       rh->status |= RSL_DELEGATE_VPN;
2507       rh->proc (rh->proc_cls, rh, rd_count, rd);
2508       return;
2509     case GNUNET_DNSPARSER_TYPE_NS:
2510       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2511                   "GNS_PHASE_DELEGATE_NS-%llu: NS `%.*s' found.\n",
2512                   rh->id,
2513                   (int) rd[i].data_size,
2514                   rd[i].data);
2515       rh->status |= RSL_DELEGATE_NS;
2516       rh->proc (rh->proc_cls, rh, rd_count, rd);
2517       return;
2518     case GNUNET_NAMESTORE_TYPE_PKEY:
2519       rh->status |= RSL_DELEGATE_PKEY;
2520       if ((ignore_pending_records != 0) &&
2521           (rd[i].flags & GNUNET_NAMESTORE_RF_PENDING))
2522       {
2523         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2524                     "GNS_PHASE_DELEGATE_NS-%llu: PKEY for %s is pending user confirmation.\n",
2525                     rh->id,
2526                     name);
2527         continue;
2528       }    
2529       GNUNET_break (0 == (rd[i].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION));
2530       et.abs_value_us = rd[i].expiration_time;
2531       if (0 == (GNUNET_TIME_absolute_get_remaining (et)).rel_value_us)
2532       {
2533         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2534                     "GNS_PHASE_DELEGATE_NS-%llu: This pkey is expired.\n",
2535                     rh->id);
2536         if (remaining_time.rel_value_us == 0)
2537         {
2538           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2539                       "GNS_PHASE_DELEGATE_NS-%llu: This dht entry is expired.\n",
2540                       rh->id);
2541           rh->authority_chain_head->fresh = 0;
2542           rh->proc (rh->proc_cls, rh, 0, NULL);
2543           return;
2544         }       
2545         continue;
2546       }
2547       /* Resolve rest of query with new authority */
2548       memcpy (&rh->authority, rd[i].data,
2549               sizeof (struct GNUNET_CRYPTO_ShortHashCode));
2550       auth = GNUNET_malloc(sizeof (struct AuthorityChain));
2551       auth->zone = rh->authority;
2552       memset (auth->name, 0, strlen (rh->authority_name)+1);
2553       strcpy (auth->name, rh->authority_name);
2554       GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
2555                                    rh->authority_chain_tail,
2556                                    auth);
2557       if (NULL != rh->rd.data)
2558         GNUNET_free ((void*)(rh->rd.data));      
2559       memcpy (&rh->rd, &rd[i], sizeof (struct GNUNET_NAMESTORE_RecordData));
2560       rh->rd.data = GNUNET_malloc (rd[i].data_size);
2561       memcpy ((void*)rh->rd.data, rd[i].data, rd[i].data_size);
2562       rh->rd_count = 1;
2563       /* Check for key revocation and delegate */
2564       rh->namestore_task = GNUNET_NAMESTORE_lookup (namestore_handle,
2565                                                     &rh->authority,
2566                                                     GNUNET_GNS_MASTERZONE_STR,
2567                                                     GNUNET_NAMESTORE_TYPE_REV,
2568                                                     &process_pkey_revocation_result_ns,
2569                                                     rh);
2570       return;
2571     default:
2572       /* ignore, move to next result */
2573       break;
2574     }
2575   }
2576   
2577   /* no answers that would cause delegation were found */
2578   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2579              "GNS_PHASE_DELEGATE_NS-%llu: Authority lookup failed (no PKEY record)\n", 
2580              rh->id);
2581   /**
2582    * If we have found some records for the LAST label
2583    * we return the results. Else NULL.
2584    */
2585   if (0 == strcmp (rh->name, ""))
2586   {
2587     /* Start shortening */
2588     if ((rh->priv_key != NULL) &&
2589         (is_canonical (rh->name) == GNUNET_YES))
2590     {
2591       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2592               "GNS_PHASE_DELEGATE_NS-%llu: Trying to shorten authority chain\n",
2593               rh->id);
2594       start_shorten (rh->authority_chain_head,
2595                     rh->priv_key);
2596     }
2597     /* simply promote back */
2598     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2599                 "GNS_PHASE_DELEGATE_NS-%llu: Promoting %s back to name\n",
2600                 rh->id, rh->authority_name);
2601     strcpy (rh->name, rh->authority_name);
2602     rh->proc (rh->proc_cls, rh, rd_count, rd);
2603   }
2604   else
2605   {
2606     GNUNET_snprintf (new_name, GNUNET_DNSPARSER_MAX_NAME_LENGTH,
2607                      "%s.%s", rh->name, rh->authority_name);
2608     strcpy (rh->name, new_name);
2609     rh->proc (rh->proc_cls, rh, 0, NULL);
2610   }
2611 }
2612
2613
2614 #endif
2615
2616 ///////////////////////////////////////////////////////////////////////////////////////////////////
2617 ///////////////////////////////////////////////////////////////////////////////////////////////////
2618 ///////////////////////////////////////////////////////////////////////////////////////////////////
2619 ///////////////////////////////////////////////////////////////////////////////////////////////////
2620 ///////////////////////////////////////////////////////////////////////////////////////////////////
2621
2622
2623 /**
2624  * Task scheduled to asynchronously fail a resolution.
2625  *
2626  * @param cls the 'struct GNS_ResolverHandle' of the resolution to fail
2627  * @param tc task context
2628  */
2629 static void
2630 fail_resolution (void *cls,
2631                  const struct GNUNET_SCHEDULER_TaskContext *tc)
2632 {
2633   struct GNS_ResolverHandle *rh = cls;
2634
2635   rh->task_id = GNUNET_SCHEDULER_NO_TASK;
2636   rh->proc (rh->proc_cls, 0, NULL);
2637   GNS_resolver_lookup_cancel (rh);
2638 }
2639
2640
2641 /**
2642  * Get the next, rightmost label from the name that we are trying to resolve,
2643  * and update the resolution position accordingly.
2644  *
2645  * @param rh handle to the resolution operation to get the next label from
2646  * @return NULL if there are no more labels
2647  */
2648 static char *
2649 resolver_lookup_get_next_label (struct GNS_ResolverHandle *rh)
2650 {
2651   const char *rp;
2652   const char *dot;
2653   size_t len;
2654
2655   if (0 == rh->name_resolution_pos)
2656     return NULL;
2657   dot = memrchr (rh->name, (int) '.', rh->name_resolution_pos);
2658   if (NULL == dot)
2659   {
2660     /* done, this was the last one */
2661     len = rh->name_resolution_pos;
2662     rp = rh->name;
2663     rh->name_resolution_pos = 0; 
2664   }
2665   else
2666   {
2667     /* advance by one label */
2668     len = rh->name_resolution_pos - (dot - rh->name) - 1;
2669     rp = dot + 1;
2670     rh->name_resolution_pos = dot - rh->name;
2671   }  
2672   return GNUNET_strndup (rp, len);  
2673 }
2674
2675
2676 /**
2677  * Gives the cummulative result obtained to the callback and clean up the request.
2678  *
2679  * @param rh resolution process that has culminated in a result
2680  */
2681 static void
2682 transmit_lookup_dns_result (struct GNS_ResolverHandle *rh)
2683 {
2684   struct DnsResult *pos;
2685   unsigned int n;
2686   unsigned int i;
2687
2688   n = 0;
2689   for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
2690     n++;
2691   {
2692     struct GNUNET_NAMESTORE_RecordData rd[n];
2693
2694     i = 0;
2695     for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
2696     {
2697       rd[i].data = pos->data;
2698       rd[i].data_size = pos->data_size;
2699       rd[i].record_type = pos->record_type;
2700       if (0 == pos->expiration_time)
2701       {
2702         rd[i].flags = GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION;
2703         rd[i].expiration_time = 0;
2704       }
2705       else
2706       {
2707         rd[i].flags = GNUNET_NAMESTORE_RF_NONE;
2708         rd[i].expiration_time = pos->expiration_time;
2709       }
2710     }      
2711     rh->proc (rh->proc_cls,
2712               n,
2713               rd);
2714   }
2715   GNS_resolver_lookup_cancel (rh);
2716 }
2717
2718
2719 /**
2720  * Add a result from DNS to the records to be returned to the application.
2721  *
2722  * @param rh resolution request to extend with a result
2723  * @param expiration_time expiration time for the answer
2724  * @param record_type DNS record type of the answer
2725  * @param data_size number of bytes in @a data
2726  * @param data binary data to return in DNS record
2727  */
2728 static void
2729 add_dns_result (struct GNS_ResolverHandle *rh,
2730                 uint64_t expiration_time,
2731                 uint32_t record_type,
2732                 size_t data_size,
2733                 const void *data)
2734 {
2735   struct DnsResult *res;
2736
2737   res = GNUNET_malloc (sizeof (struct DnsResult) + data_size);
2738   res->expiration_time = expiration_time;
2739   res->data_size = data_size;
2740   res->record_type = record_type;
2741   res->data = &res[1];
2742   memcpy (&res[1], data, data_size);
2743   GNUNET_CONTAINER_DLL_insert (rh->dns_result_head,
2744                                rh->dns_result_tail,
2745                                res);
2746 }
2747
2748
2749 /**
2750  * We had to do a DNS lookup.  Convert the result (if any) and return
2751  * it.
2752  *
2753  * @param cls closure with the 'struct GNS_ResolverHandle'
2754  * @param addr one of the addresses of the host, NULL for the last address
2755  * @param addrlen length of the address
2756  */
2757 static void
2758 handle_dns_result (void *cls,
2759                    const struct sockaddr *addr,
2760                    socklen_t addrlen)
2761 {
2762   struct GNS_ResolverHandle *rh = cls;
2763   const struct sockaddr_in *sa4;
2764   const struct sockaddr_in6 *sa6;
2765
2766   rh->std_resolve = NULL;
2767   if (NULL == addr)
2768   {
2769     transmit_lookup_dns_result (rh);
2770     return;
2771   }
2772   switch (addr->sa_family)
2773   {
2774   case AF_INET:
2775     sa4 = (const struct sockaddr_in *) addr;
2776     add_dns_result (rh,
2777                     0 /* expiration time is unknown */,
2778                     GNUNET_DNSPARSER_TYPE_A,
2779                     sizeof (struct in_addr),
2780                     &sa4->sin_addr);
2781     break;
2782   case AF_INET6:
2783     sa6 = (const struct sockaddr_in6 *) addr;
2784     add_dns_result (rh,
2785                     0 /* expiration time is unknown */,
2786                     GNUNET_DNSPARSER_TYPE_AAAA,
2787                     sizeof (struct in6_addr),
2788                     &sa6->sin6_addr);
2789     break;
2790   default:
2791     GNUNET_break (0);
2792     break;
2793   }
2794 }
2795
2796
2797 /**
2798  * Task scheduled to continue with the resolution process.
2799  *
2800  * @param cls the 'struct GNS_ResolverHandle' of the resolution
2801  * @param tc task context
2802  */
2803 static void
2804 recursive_resolution (void *cls,
2805                       const struct GNUNET_SCHEDULER_TaskContext *tc);
2806
2807
2808 /**
2809  * Function called with the result of a DNS resolution.
2810  *
2811  * @param cls the request handle of the resolution that
2812  *        we were attempting to make
2813  * @param rs socket that received the response
2814  * @param dns dns response, never NULL
2815  * @param dns_len number of bytes in 'dns'
2816  */
2817 static void
2818 dns_result_parser (void *cls,
2819                    struct GNUNET_DNSSTUB_RequestSocket *rs,
2820                    const struct GNUNET_TUN_DnsHeader *dns,
2821                    size_t dns_len)
2822 {
2823   struct GNS_ResolverHandle *rh = cls;
2824   struct GNUNET_DNSPARSER_Packet *p;
2825
2826   rh->dns_request = NULL;
2827   GNUNET_SCHEDULER_cancel (rh->task_id);
2828   rh->task_id = GNUNET_SCHEDULER_NO_TASK;
2829   p = GNUNET_DNSPARSER_parse ((const char *) dns, 
2830                               dns_len);
2831   if (NULL == p)
2832   {
2833     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2834                 _("Failed to parse DNS response\n"));
2835     rh->proc (rh->proc_cls, 0, NULL);
2836     GNS_resolver_lookup_cancel (rh);
2837     return;
2838   }
2839   // FIXME: 
2840   // Check if the packet is the final answer, or
2841   // just pointing us to another NS or another name (CNAME), or another domain (DNAME);
2842   // then do the right thing (TM) -- possibly using "recursive_dns_resolution".
2843   GNUNET_break (0);
2844   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2845               _("NOT IMPLEMENTED\n"));
2846   rh->proc (rh->proc_cls, 0, NULL);
2847   GNS_resolver_lookup_cancel (rh);
2848
2849   
2850   GNUNET_DNSPARSER_free_packet (p);
2851 }
2852
2853
2854 /**
2855  * Perform recursive DNS resolution.  Asks the given DNS resolver to
2856  * resolve "rh->dns_name", possibly recursively proceeding following
2857  * NS delegations, CNAMES, etc., until 'rh->loop_limiter' bounds us or
2858  * we find the answer.
2859  *
2860  * @param rh resolution information
2861  */
2862 static void
2863 recursive_dns_resolution (struct GNS_ResolverHandle *rh)
2864 {
2865   struct AuthorityChain *ac;
2866   socklen_t sa_len;
2867   struct GNUNET_DNSPARSER_Query *query;
2868   struct GNUNET_DNSPARSER_Packet *p;
2869   char *dns_request;
2870   size_t dns_request_length;
2871
2872   ac = rh->ac_tail;
2873   GNUNET_assert (NULL != ac);
2874   GNUNET_assert (GNUNET_NO == ac->gns_authority);
2875   switch (((const struct sockaddr *) &ac->authority_info.dns_authority.dns_ip)->sa_family)
2876   {
2877   case AF_INET:
2878     sa_len = sizeof (struct sockaddr_in);
2879     break;
2880   case AF_INET6:
2881     sa_len = sizeof (struct sockaddr_in6);
2882     break;
2883   default:
2884     GNUNET_break (0);
2885     rh->proc (rh->proc_cls, 0, NULL);
2886     GNS_resolver_lookup_cancel (rh);
2887     return;
2888   }
2889   query = GNUNET_new (struct GNUNET_DNSPARSER_Query);
2890   query->name = GNUNET_strdup (ac->label);
2891   query->type = rh->record_type;
2892   query->class = GNUNET_DNSPARSER_CLASS_INTERNET;
2893   p = GNUNET_new (struct GNUNET_DNSPARSER_Packet);
2894   p->queries = query;
2895   p->num_queries = 1;
2896   p->id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
2897                                                UINT16_MAX);
2898   p->flags.opcode = GNUNET_DNSPARSER_OPCODE_QUERY;
2899   p->flags.recursion_desired = 1;
2900   if (GNUNET_OK != 
2901       GNUNET_DNSPARSER_pack (p, 1024, &dns_request, &dns_request_length))
2902   {
2903     GNUNET_break (0);
2904     rh->proc (rh->proc_cls, 0, NULL);
2905     GNS_resolver_lookup_cancel (rh);
2906   }
2907   else
2908   {
2909     rh->dns_request = GNUNET_DNSSTUB_resolve (dns_handle,
2910                                               (const struct sockaddr *) &ac->authority_info.dns_authority.dns_ip,
2911                                               sa_len,
2912                                               dns_request,
2913                                               dns_request_length,
2914                                               &dns_result_parser,
2915                                               rh);
2916     rh->task_id = GNUNET_SCHEDULER_add_delayed (DNS_LOOKUP_TIMEOUT,
2917                                                 &fail_resolution,
2918                                                 rh);
2919   }
2920   GNUNET_free (dns_request);
2921   GNUNET_DNSPARSER_free_packet (p);
2922 }
2923
2924
2925 /**
2926  * Process a records that were decrypted from a block.
2927  *
2928  * @param cls closure with the 'struct GNS_ResolverHandle'
2929  * @param rd_count number of entries in @a rd array
2930  * @param rd array of records with data to store
2931  */
2932 static void
2933 handle_gns_resolution_result (void *cls,
2934                               unsigned int rd_count,
2935                               const struct GNUNET_NAMESTORE_RecordData *rd)
2936 {
2937   struct GNS_ResolverHandle *rh = cls;
2938    
2939   // FIXME: not implemented
2940   // if this was the last label, return 'rd' to application
2941   // (possibly first checking about converting records
2942   //  to requested type, if possible).
2943   // if not, look for PKEY, CNAME, DNAME or NS to extend
2944   // auth chain and continue with recursion
2945   GNUNET_break (0);
2946   rh->proc (rh->proc_cls, 0, NULL);
2947   GNS_resolver_lookup_cancel (rh);
2948 }
2949
2950
2951 /**
2952  * Function called once the namestore has completed the request for
2953  * caching a block.
2954  *
2955  * @param cls closure with the 'struct GNS_ResolverHandle'
2956  * @param success #GNUNET_OK on success
2957  * @param emsg error message
2958  */
2959 static void
2960 namestore_cache_continuation (void *cls,
2961                               int32_t success,
2962                               const char *emsg)
2963 {
2964   struct GNS_ResolverHandle *rh = cls;
2965
2966   rh->namestore_qe = NULL;
2967   if (NULL != emsg)
2968     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2969                 _("Failed to cache GNS resolution: %s\n"),
2970                 emsg);
2971 }
2972
2973
2974 /**
2975  * Iterator called on each result obtained for a DHT
2976  * operation that expects a reply
2977  *
2978  * @param cls closure with the 'struct GNS_ResolverHandle'
2979  * @param exp when will this value expire
2980  * @param key key of the result
2981  * @param get_path peers on reply path (or NULL if not recorded)
2982  *                 [0] = datastore's first neighbor, [length - 1] = local peer
2983  * @param get_path_length number of entries in get_path
2984  * @param put_path peers on the PUT path (or NULL if not recorded)
2985  *                 [0] = origin, [length - 1] = datastore
2986  * @param put_path_length number of entries in get_path
2987  * @param type type of the result
2988  * @param size number of bytes in data
2989  * @param data pointer to the result data
2990  */
2991 static void
2992 handle_dht_response (void *cls,
2993                      struct GNUNET_TIME_Absolute exp,
2994                      const struct GNUNET_HashCode * key,
2995                      const struct GNUNET_PeerIdentity *get_path,
2996                      unsigned int get_path_length,
2997                      const struct GNUNET_PeerIdentity *put_path, 
2998                      unsigned int put_path_length,
2999                      enum GNUNET_BLOCK_Type type,
3000                      size_t size, const void *data)
3001 {
3002   struct GNS_ResolverHandle *rh = cls;
3003   struct AuthorityChain *ac = rh->ac_tail;
3004   const struct GNUNET_NAMESTORE_Block *block;
3005   
3006   GNUNET_DHT_get_stop (rh->get_handle);
3007   rh->get_handle = NULL;
3008   GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
3009   rh->dht_heap_node = NULL;  
3010   if (size < sizeof (struct GNUNET_NAMESTORE_Block))
3011   {
3012     /* how did this pass DHT block validation!? */
3013     GNUNET_break (0);
3014     rh->proc (rh->proc_cls, 0, NULL);
3015     GNS_resolver_lookup_cancel (rh);
3016     return;   
3017   }
3018   block = data; 
3019   if (size !=
3020       ntohs (block->purpose.size) + 
3021       sizeof (struct GNUNET_CRYPTO_EccPublicKey) +
3022       sizeof (struct GNUNET_CRYPTO_EccSignature))
3023   {
3024     /* how did this pass DHT block validation!? */
3025     GNUNET_break (0);
3026     rh->proc (rh->proc_cls, 0, NULL);
3027     GNS_resolver_lookup_cancel (rh);
3028     return;   
3029   }
3030   if (GNUNET_OK !=
3031       GNUNET_NAMESTORE_block_decrypt (block,
3032                                       &ac->authority_info.gns_authority,
3033                                       ac->label,
3034                                       &handle_gns_resolution_result,
3035                                       rh))
3036   {
3037     GNUNET_break_op (0); /* block was ill-formed */
3038     rh->proc (rh->proc_cls, 0, NULL);
3039     GNS_resolver_lookup_cancel (rh);
3040     return;
3041   }
3042   /* Cache well-formed blocks */
3043   rh->namestore_qe = GNUNET_NAMESTORE_block_cache (namestore_handle,
3044                                                    block,
3045                                                    &namestore_cache_continuation,
3046                                                    rh);
3047 }
3048
3049
3050 /**
3051  * Process a record that was stored in the namestore.
3052  *
3053  * @param cls closure with the 'struct GNS_ResolverHandle'
3054  * @param block block that was stored in the namestore
3055  */
3056 static void 
3057 handle_namestore_block_response (void *cls,
3058                                  const struct GNUNET_NAMESTORE_Block *block)
3059 {
3060   struct GNS_ResolverHandle *rh = cls;
3061   struct GNS_ResolverHandle *rx;
3062   struct AuthorityChain *ac = rh->ac_tail;
3063   const char *label = ac->label;
3064   const struct GNUNET_CRYPTO_EccPublicKey *auth = &ac->authority_info.gns_authority;
3065   struct GNUNET_HashCode query;
3066
3067   GNUNET_NAMESTORE_query_from_public_key (auth,
3068                                           label,
3069                                           &query);
3070   rh->namestore_qe = NULL;
3071   if (NULL == block)
3072   {
3073     /* Namestore knows nothing; try DHT lookup */
3074     rh->get_handle = GNUNET_DHT_get_start (dht_handle,
3075                                            GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
3076                                            &query,
3077                                            DHT_GNS_REPLICATION_LEVEL,
3078                                            GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
3079                                            NULL, 0,
3080                                            &handle_dht_response, rh);
3081     rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
3082                                                       rh,
3083                                                       GNUNET_TIME_absolute_get ().abs_value_us);
3084     if (GNUNET_CONTAINER_heap_get_size (dht_lookup_heap) > max_allowed_background_queries)
3085     {
3086       /* fail longest-standing DHT request */
3087       rx = GNUNET_CONTAINER_heap_peek (dht_lookup_heap);
3088       rx->proc (rx->proc_cls, 0, NULL);
3089       GNS_resolver_lookup_cancel (rx);
3090     }
3091     return;
3092   }
3093   if (GNUNET_OK !=
3094       GNUNET_NAMESTORE_block_decrypt (block,
3095                                       auth,
3096                                       label,
3097                                       &handle_gns_resolution_result,
3098                                       rh))
3099   {
3100     GNUNET_break_op (0); /* block was ill-formed */
3101     rh->proc (rh->proc_cls, 0, NULL);
3102     GNS_resolver_lookup_cancel (rh);
3103     return;
3104   }
3105 }
3106
3107
3108 /**
3109  * Lookup tail of our authority chain in the namestore.
3110  *
3111  * @param rh query we are processing
3112  */
3113 static void
3114 recursive_gns_resolution_namestore (struct GNS_ResolverHandle *rh)
3115 {
3116   struct AuthorityChain *ac = rh->ac_tail;
3117   struct GNUNET_HashCode query;
3118
3119   GNUNET_NAMESTORE_query_from_public_key (&ac->authority_info.gns_authority,
3120                                           ac->label,
3121                                           &query);
3122   rh->namestore_qe = GNUNET_NAMESTORE_lookup_block (namestore_handle,
3123                                                     &query,
3124                                                     &handle_namestore_block_response,
3125                                                     rh);
3126 }
3127
3128
3129 /**
3130  * Task scheduled to continue with the resolution process.
3131  *
3132  * @param cls the 'struct GNS_ResolverHandle' of the resolution
3133  * @param tc task context
3134  */
3135 static void
3136 recursive_resolution (void *cls,
3137                      const struct GNUNET_SCHEDULER_TaskContext *tc)
3138 {
3139   struct GNS_ResolverHandle *rh = cls;
3140
3141   rh->task_id = GNUNET_SCHEDULER_NO_TASK;
3142   if (MAX_RECURSION < rh->loop_limiter++)
3143   {
3144     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3145                 "Encountered unbounded recursion resolving `%s'\n",
3146                 rh->name);
3147     rh->proc (rh->proc_cls, 0, NULL);
3148     GNS_resolver_lookup_cancel (rh);
3149     return;
3150   }
3151   if (GNUNET_YES == rh->ac_tail->gns_authority)
3152     recursive_gns_resolution_namestore (rh);
3153   else
3154     recursive_dns_resolution (rh);
3155 }
3156
3157
3158 /**
3159  * Lookup of a record in a specific zone calls lookup result processor
3160  * on result.
3161  *
3162  * @param zone the zone to perform the lookup in
3163  * @param record_type the record type to look up
3164  * @param name the name to look up
3165  * @param shorten_key a private key for use with PSEU import (can be NULL)
3166  * @param only_cached GNUNET_NO to only check locally not DHT for performance
3167  * @param proc the processor to call on result
3168  * @param proc_cls the closure to pass to @a proc
3169  * @return handle to cancel operation
3170  */
3171 struct GNS_ResolverHandle *
3172 GNS_resolver_lookup (const struct GNUNET_CRYPTO_EccPublicKey *zone,
3173                      uint32_t record_type,
3174                      const char *name,
3175                      const struct GNUNET_CRYPTO_EccPrivateKey *shorten_key,
3176                      int only_cached,
3177                      GNS_ResultProcessor proc, void *proc_cls)
3178 {
3179   struct GNS_ResolverHandle *rh;
3180   struct AuthorityChain *ac;
3181   char *x;
3182   char *y;
3183   char *pkey;
3184
3185   rh = GNUNET_new (struct GNS_ResolverHandle);
3186   GNUNET_CONTAINER_DLL_insert (rlh_head,
3187                                rlh_tail,
3188                                rh);
3189   rh->authority_zone = *zone;
3190   rh->proc = proc;
3191   rh->proc_cls = proc_cls;
3192   rh->only_cached = only_cached;
3193   rh->record_type = record_type;
3194   rh->name = GNUNET_strdup (name);
3195   rh->name_resolution_pos = strlen (name);
3196   if (NULL != shorten_key)
3197   {
3198     rh->shorten_key = GNUNET_new (struct GNUNET_CRYPTO_EccPrivateKey);
3199     *rh->shorten_key = *shorten_key;
3200   }
3201
3202   if ( ( (GNUNET_YES == is_canonical (name)) &&
3203          (0 != strcmp (GNUNET_GNS_TLD, name)) ) ||
3204        ( (GNUNET_YES != is_gads_tld (name)) &&
3205          (GNUNET_YES != is_zkey_tld (name)) ) )
3206   {
3207     /* use standard DNS lookup */
3208     int af;
3209
3210     switch (record_type)
3211     {
3212     case GNUNET_DNSPARSER_TYPE_A:
3213       af = AF_INET;
3214       break;
3215     case GNUNET_DNSPARSER_TYPE_AAAA:
3216       af = AF_INET6;
3217       break;
3218     default:
3219       af = AF_UNSPEC;
3220       break;
3221     }
3222     rh->std_resolve = GNUNET_RESOLVER_ip_get (name, 
3223                                               af,
3224                                               DNS_LOOKUP_TIMEOUT,
3225                                               &handle_dns_result,
3226                                               rh);
3227     return rh;
3228   }
3229   if (is_zkey_tld (name))
3230   {
3231     /* Name ends with ".zkey", try to replace authority zone with zkey
3232        authority */
3233     GNUNET_free (resolver_lookup_get_next_label (rh)); /* will return "zkey" */
3234     x = resolver_lookup_get_next_label (rh); /* will return 'x' coordinate */
3235     y = resolver_lookup_get_next_label (rh); /* will return 'y' coordinate */
3236     GNUNET_asprintf (&pkey,
3237                      "%s%s",
3238                      x, y);
3239     if ( (NULL == x) ||
3240          (NULL == y) ||
3241          (GNUNET_OK !=
3242           GNUNET_CRYPTO_ecc_public_key_from_string (pkey,
3243                                                     strlen (pkey),
3244                                                     &rh->authority_zone)) )
3245     {
3246       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3247                   _("Hostname `%s' is not well-formed, resolution fails\n"),
3248                   name);
3249       rh->task_id = GNUNET_SCHEDULER_add_now (&fail_resolution, rh);
3250     }
3251     GNUNET_free_non_null (x);
3252     GNUNET_free_non_null (y);
3253     GNUNET_free (pkey);
3254   }
3255   else
3256   {
3257     /* Name ends with ".gnu", eat ".gnu" and continue with resolution */
3258     GNUNET_free (resolver_lookup_get_next_label (rh));
3259   }
3260   ac = GNUNET_new (struct AuthorityChain);
3261   ac->rh = rh;
3262   ac->label = resolver_lookup_get_next_label (rh);
3263   if (NULL == ac->label)
3264     /* name was just "gnu", so we default to label '+' */
3265     ac->label = GNUNET_strdup (GNUNET_GNS_MASTERZONE_STR);
3266   ac->gns_authority = GNUNET_YES;
3267   ac->authority_info.gns_authority = rh->authority_zone;
3268   GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
3269                                     rh->ac_tail,
3270                                     ac);
3271   rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
3272                                           rh);
3273   return rh;
3274 }
3275
3276
3277 /**
3278  * Cancel active resolution (i.e. client disconnected).
3279  *
3280  * @param rh resolution to abort
3281  */
3282 void
3283 GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
3284 {
3285   struct DnsResult *dr;
3286   struct AuthorityChain *ac;
3287
3288   GNUNET_CONTAINER_DLL_remove (rlh_head,
3289                                rlh_tail,
3290                                rh);
3291   while (NULL != (ac = rh->ac_head))
3292   {
3293     GNUNET_CONTAINER_DLL_remove (rh->ac_head,
3294                                  rh->ac_tail,
3295                                  ac);
3296     GNUNET_free (ac->label);
3297     GNUNET_free (ac);
3298   }
3299   if (GNUNET_SCHEDULER_NO_TASK != rh->task_id)
3300   {
3301     GNUNET_SCHEDULER_cancel (rh->task_id);
3302     rh->task_id = GNUNET_SCHEDULER_NO_TASK;
3303   }
3304   if (NULL != rh->get_handle)
3305   {
3306     GNUNET_DHT_get_stop (rh->get_handle);
3307     rh->get_handle = NULL;
3308   }
3309   if (NULL != rh->dht_heap_node)
3310   {
3311     GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
3312     rh->dht_heap_node = NULL;
3313   }
3314   if (NULL != rh->dns_request)
3315   {
3316     GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
3317     rh->dns_request = NULL;
3318   }
3319   if (NULL != rh->namestore_qe)
3320   {
3321     GNUNET_NAMESTORE_cancel (rh->namestore_qe);
3322     rh->namestore_qe = NULL;
3323   }
3324   if (NULL != rh->std_resolve)
3325   {
3326     GNUNET_RESOLVER_request_cancel (rh->std_resolve);
3327     rh->std_resolve = NULL;
3328   }
3329   while (NULL != (dr = rh->dns_result_head))
3330   {
3331     GNUNET_CONTAINER_DLL_remove (rh->dns_result_head,
3332                                  rh->dns_result_tail,
3333                                  dr);
3334     GNUNET_free (dr);
3335   }
3336   GNUNET_free_non_null (rh->shorten_key);
3337   GNUNET_free (rh->name);
3338   GNUNET_free (rh);
3339 }
3340
3341
3342 /* ***************** Resolver initialization ********************* */
3343
3344
3345 /**
3346  * Initialize the resolver
3347  *
3348  * @param nh the namestore handle
3349  * @param dht the dht handle
3350  * @param c configuration handle
3351  * @param max_bg_queries maximum number of parallel background queries in dht
3352  */
3353 void
3354 GNS_resolver_init (struct GNUNET_NAMESTORE_Handle *nh,
3355                    struct GNUNET_DHT_Handle *dht,
3356                    const struct GNUNET_CONFIGURATION_Handle *c,
3357                    unsigned long long max_bg_queries)
3358 {
3359   char *dns_ip;
3360
3361   cfg = c;
3362   namestore_handle = nh;
3363   dht_handle = dht;
3364   dht_lookup_heap =
3365     GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3366   max_allowed_background_queries = max_bg_queries;
3367   if (GNUNET_OK !=
3368       GNUNET_CONFIGURATION_get_value_string (c,
3369                                              "gns",
3370                                              "DNS_RESOLVER",
3371                                              &dns_ip))
3372   {
3373     /* user did not specify DNS resolver, use 8.8.8.8 */
3374     dns_ip = GNUNET_strdup ("8.8.8.8");
3375   }
3376   dns_handle = GNUNET_DNSSTUB_start (dns_ip);
3377   GNUNET_free (dns_ip);
3378 }
3379
3380
3381 /**
3382  * Shutdown resolver
3383  */
3384 void
3385 GNS_resolver_done ()
3386 {
3387   struct GNS_ResolverHandle *rh;
3388
3389   /* abort active resolutions */
3390   while (NULL != (rh = rlh_head))
3391   {
3392     rh->proc (rh->proc_cls, 0, NULL);
3393     GNS_resolver_lookup_cancel (rh);    
3394   }
3395   /* abort active shorten operations */
3396   while (NULL != gph_head)
3397     free_get_pseu_authority_handle (gph_head);
3398   GNUNET_CONTAINER_heap_destroy (dht_lookup_heap);
3399   dht_lookup_heap = NULL;
3400   GNUNET_DNSSTUB_stop (dns_handle);
3401   dns_handle = NULL;
3402 }
3403
3404
3405 /* *************** common helper functions (do not really belong here) *********** */
3406
3407 /**
3408  * Checks if "name" ends in ".tld"
3409  *
3410  * @param name the name to check
3411  * @param tld the TLD to check for
3412  * @return GNUNET_YES or GNUNET_NO
3413  */
3414 int
3415 is_tld (const char* name, const char* tld)
3416 {
3417   size_t offset = 0;
3418
3419   if (strlen (name) <= strlen (tld))
3420     return GNUNET_NO;
3421   offset = strlen (name) - strlen (tld);
3422   if (0 != strcmp (name + offset, tld))
3423     return GNUNET_NO;
3424   return GNUNET_YES;
3425 }
3426
3427
3428
3429
3430 /* end of gnunet-service-gns_resolver.c */