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