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