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