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