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