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