c36fa8d17a6616b31313f9d9bfaa59453a3ad35c
[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  * - GNS: handle CNAME records (idea: manipulate rh->name)
29  * - GNS: handle VPN records (easy)
30  * - GNS: handle special SRV names --- no delegation, direct lookup;
31  *        can likely be done in 'resolver_lookup_get_next_label'.
32  * - recursive DNS resolution
33  * - shortening triggers
34  * - revocation checks (make optional: privacy!)
35  *
36  * Issues:
37  * - We currently go to the DHT simply if we find no local reply; this
38  *   is incorrect; the correct rules for going to DHT are:
39  *
40  * 1. The entry in the DHT is RSL_RECORD_EXPIRED OR
41  * 2. No entry in the NS existed AND
42  * 3. The zone queried is not the local resolver's zone AND
43  * 4. The name that was looked up is '+'
44  *    because if it was any other canonical name we either already queried
45  *    the DHT for the authority in the authority lookup phase (and thus
46  *    would already have an entry in the NS for the record)
47  * 5. We are not in cache only mode
48  *
49  * - We currently never look "into" the records; for example,
50  *   MX, SRV and SOA records may include ".+" that need to be
51  *   handled
52  *
53  */
54 #include "platform.h"
55 #include "gnunet_util_lib.h"
56 #include "gnunet_transport_service.h"
57 #include "gnunet_dnsstub_lib.h"
58 #include "gnunet_dht_service.h"
59 #include "gnunet_namestore_service.h"
60 #include "gnunet_dns_service.h"
61 #include "gnunet_resolver_service.h"
62 #include "gnunet_dnsparser_lib.h"
63 #include "gnunet_gns_service.h"
64 #include "gns.h"
65 #include "gnunet-service-gns_resolver.h"
66 #include "gnunet_vpn_service.h"
67
68
69 /**
70  * Default DHT timeout for lookups.
71  */
72 #define DHT_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
73
74 /**
75  * Default timeout for DNS lookups.
76  */
77 #define DNS_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
78
79 /**
80  * DHT replication level
81  */
82 #define DHT_GNS_REPLICATION_LEVEL 5
83
84 /**
85  * How deep do we allow recursions to go before we abort?
86  */
87 #define MAX_RECURSION 256
88
89
90 /**
91  * DLL to hold the authority chain we had to pass in the resolution
92  * process.
93  */
94 struct AuthorityChain
95 {
96   /**
97    * This is a DLL.
98    */
99   struct AuthorityChain *prev;
100
101   /**
102    * This is a DLL.
103    */
104   struct AuthorityChain *next;
105
106   /**
107    * Resolver handle this entry in the chain belongs to.
108    */
109   struct GNS_ResolverHandle *rh;
110
111   /**
112    * label/name corresponding to the authority 
113    */
114   char *label;
115   
116   /**
117    * #GNUNET_YES if the authority was a GNS authority,
118    * #GNUNET_NO if the authority was a DNS authority.
119    */
120   int gns_authority;
121
122   /**
123    * Information about the resolver authority for this label.
124    */
125   union
126   {
127
128     /**
129      * The zone of the GNS authority 
130      */
131     struct GNUNET_CRYPTO_EccPublicKey gns_authority;
132
133     struct
134     {
135       /**
136        * Domain of the DNS resolver that is the authority.
137        * (appended to construct the DNS name to resolve;
138        * this is NOT the DNS name of the DNS server!).
139        */
140       char name[GNUNET_DNSPARSER_MAX_NAME_LENGTH + 1];
141
142       /**
143        * IP address of the DNS resolver that is authoritative.
144        * (this implementation currently only supports one
145        * IP at a time).
146        */
147       struct sockaddr_storage dns_ip;
148
149     } dns_authority;
150
151   } authority_info;
152   
153 };
154
155
156 /**
157  * Resolution status indicator
158  */
159 enum ResolutionStatus
160 {
161   /**
162    * the name to lookup exists
163    */
164   RSL_RECORD_EXISTS = 1,
165
166   /**
167    * the name in the record expired
168    */
169   RSL_RECORD_EXPIRED = 2,
170  
171   /**
172    * resolution timed out
173    */
174   RSL_TIMED_OUT = 4,
175  
176   /**
177    * Found VPN delegation
178    */
179   RSL_DELEGATE_VPN = 8,
180  
181   /**
182    * Found NS delegation
183    */
184   RSL_DELEGATE_NS = 16,
185  
186   /**
187    * Found PKEY delegation
188    */
189   RSL_DELEGATE_PKEY = 32,
190   
191   /**
192    * Found CNAME record
193    */
194   RSL_CNAME_FOUND = 64,
195   
196   /**
197    * Found PKEY has been revoked
198    */
199   RSL_PKEY_REVOKED = 128
200 };
201
202
203 /**
204  * A result we got from DNS.
205  */
206 struct DnsResult
207 {
208
209   /**
210    * Kept in DLL.
211    */
212   struct DnsResult *next;
213
214   /**
215    * Kept in DLL.
216    */
217   struct DnsResult *prev;
218
219   /**
220    * Binary value stored in the DNS record (appended to this struct)
221    */
222   const void *data;
223
224   /**
225    * Expiration time for the DNS record, 0 if we didn't
226    * get anything useful (i.e. 'gethostbyname' was used).
227    */
228   uint64_t expiration_time;
229
230   /**
231    * Number of bytes in 'data'.
232    */
233   size_t data_size;
234
235   /**
236    * Type of the GNS/DNS record.
237    */
238   uint32_t record_type;
239
240 };
241
242
243 /**
244  * Handle to a currenty pending resolution.  On result (positive or
245  * negative) the #GNS_ResultProcessor is called.  
246  */
247 struct GNS_ResolverHandle
248 {
249
250   /**
251    * DLL 
252    */
253   struct GNS_ResolverHandle *next;
254
255   /**
256    * DLL 
257    */
258   struct GNS_ResolverHandle *prev;
259
260   /**
261    * The top-level GNS authoritative zone to query 
262    */
263   struct GNUNET_CRYPTO_EccPublicKey authority_zone;
264
265   /**
266    * called when resolution phase finishes 
267    */
268   GNS_ResultProcessor proc;
269   
270   /**
271    * closure passed to proc 
272    */
273   void* proc_cls;
274
275   /**
276    * Handle for DHT lookups. should be NULL if no lookups are in progress 
277    */
278   struct GNUNET_DHT_GetHandle *get_handle;
279
280   /**
281    * Handle to a VPN request, NULL if none is active.
282    */
283   struct GNUNET_VPN_RedirectionRequest *vpn_handle;
284
285   /**
286    * Socket for a DNS request, NULL if none is active.
287    */
288   struct GNUNET_DNSSTUB_RequestSocket *dns_request;
289
290   /**
291    * Handle for standard DNS resolution, NULL if none is active.
292    */
293   struct GNUNET_RESOLVER_RequestHandle *std_resolve;
294
295   /**
296    * Pending Namestore task
297    */
298   struct GNUNET_NAMESTORE_QueueEntry *namestore_qe;
299
300   /**
301    * Heap node associated with this lookup.  Used to limit number of
302    * concurrent requests.
303    */
304   struct GNUNET_CONTAINER_HeapNode *dht_heap_node;
305
306   /**
307    * DLL to store the authority chain 
308    */
309   struct AuthorityChain *ac_head;
310
311   /**
312    * DLL to store the authority chain 
313    */
314   struct AuthorityChain *ac_tail;
315
316   /**
317    * Private key of the shorten zone, NULL to not shorten.
318    */
319   struct GNUNET_CRYPTO_EccPrivateKey *shorten_key;
320
321   /**
322    * ID of a task associated with the resolution process.
323    */
324   GNUNET_SCHEDULER_TaskIdentifier task_id;
325
326   /**
327    * The name to resolve 
328    */
329   char *name;
330
331   /**
332    * DLL of results we got from DNS.
333    */
334   struct DnsResult *dns_result_head;
335
336   /**
337    * DLL of results we got from DNS.
338    */
339   struct DnsResult *dns_result_tail;
340
341   /**
342    * Current offset in 'name' where we are resolving.
343    */
344   size_t name_resolution_pos;
345
346   /**
347    * Use only cache 
348    */
349   int only_cached;
350
351   /**
352    * Desired type for the resolution.
353    */
354   int record_type;
355
356   /**
357    * We increment the loop limiter for each step in a recursive
358    * resolution.  If it passes our threshold (i.e. due to 
359    * self-recursion in the resolution, i.e CNAME fun), we stop.
360    */
361   unsigned int loop_limiter;
362
363 };
364
365
366 /**
367  * Handle for a PSEU lookup used to shorten names.
368  */
369 struct GetPseuAuthorityHandle
370 {
371   /**
372    * DLL
373    */
374   struct GetPseuAuthorityHandle *next;
375
376   /**
377    * DLL
378    */
379   struct GetPseuAuthorityHandle *prev;
380
381   /**
382    * Private key of the (shorten) zone to store the resulting
383    * pseudonym in.
384    */
385   struct GNUNET_CRYPTO_EccPrivateKey shorten_zone_key;
386
387   /**
388    * Original label (used if no PSEU record is found).
389    */
390   char label[GNUNET_DNSPARSER_MAX_LABEL_LENGTH + 1];
391
392   /**
393    * Label we are currently trying out (during #perform_pseu_lookup).
394    */
395   char *current_label;
396
397   /**
398    * The zone for which we are trying to find the PSEU record.
399    */
400   struct GNUNET_CRYPTO_EccPublicKey target_zone;
401
402   /**
403    * Handle for DHT lookups. Should be NULL if no lookups are in progress 
404    */
405   struct GNUNET_DHT_GetHandle *get_handle;
406
407   /**
408    * Handle to namestore request 
409    */
410   struct GNUNET_NAMESTORE_QueueEntry *namestore_task;
411
412   /**
413    * Task to abort DHT lookup operation.
414    */
415   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
416
417 };
418
419
420 /**
421  * Our handle to the namestore service
422  */
423 static struct GNUNET_NAMESTORE_Handle *namestore_handle;
424
425 /**
426  * Our handle to the vpn service
427  */
428 static struct GNUNET_VPN_Handle *vpn_handle;
429
430 /**
431  * Resolver handle to the dht
432  */
433 static struct GNUNET_DHT_Handle *dht_handle;
434
435 /**
436  * Handle to perform DNS lookups.
437  */
438 static struct GNUNET_DNSSTUB_Context *dns_handle;
439
440 /**
441  * Heap for limiting parallel DHT lookups
442  */
443 static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
444
445 /**
446  * Maximum amount of parallel queries to the DHT
447  */
448 static unsigned long long max_allowed_background_queries;
449
450 /**
451  * Head of PSEU/shorten operations list.
452  */
453 struct GetPseuAuthorityHandle *gph_head;
454
455 /**
456  * Tail of PSEU/shorten operations list.
457  */
458 struct GetPseuAuthorityHandle *gph_tail;
459
460 /**
461  * Head of resolver lookup list
462  */
463 static struct GNS_ResolverHandle *rlh_head;
464
465 /**
466  * Tail of resolver lookup list
467  */
468 static struct GNS_ResolverHandle *rlh_tail;
469
470 /**
471  * Global configuration.
472  */
473 static const struct GNUNET_CONFIGURATION_Handle *cfg;
474
475
476 /**
477  * Check if name is in srv format (_x._y.xxx)
478  *
479  * @param name
480  * @return GNUNET_YES if true
481  */
482 static int
483 is_srv (const char *name)
484 {
485   char *ndup;
486   int ret;
487
488   if (*name != '_')
489     return GNUNET_NO;
490   if (NULL == strstr (name, "._"))
491     return GNUNET_NO;
492   ret = GNUNET_YES;
493   ndup = GNUNET_strdup (name);
494   strtok (ndup, ".");
495   if (NULL == strtok (NULL, "."))
496     ret = GNUNET_NO;
497   if (NULL == strtok (NULL, "."))
498     ret = GNUNET_NO;
499   if (NULL != strtok (NULL, "."))
500     ret = GNUNET_NO;
501   GNUNET_free (ndup);
502   return ret;
503 }
504
505
506 /**
507  * Determine if this name is canonical (is a legal name in a zone, without delegation);
508  * note that we do not test that the name does not contain illegal characters, we only
509  * test for delegation.  Note that service records (i.e. _foo._srv) are canonical names
510  * even though they consist of multiple labels.
511  *
512  * Examples:
513  * a.b.gnu  = not canonical
514  * a         = canonical
515  * _foo._srv = canonical
516  * _f.bar    = not canonical
517  *
518  * @param name the name to test
519  * @return GNUNET_YES if canonical
520  */
521 static int
522 is_canonical (const char *name)
523 {
524   const char *pos;
525   const char *dot;
526
527   if (NULL == strchr (name, '.'))
528     return GNUNET_YES;
529   if ('_' != name[0])
530     return GNUNET_NO;
531   pos = &name[1];
532   while (NULL != (dot = strchr (pos, '.')))    
533     if ('_' != dot[1])
534       return GNUNET_NO;
535     else
536       pos = dot + 1;
537   return GNUNET_YES;
538 }
539
540
541 /* ******************** Shortening logic ************************ */
542
543
544 /**
545  * Cleanup a 'struct GetPseuAuthorityHandle', terminating all
546  * pending activities.
547  *
548  * @param gph handle to terminate
549  */
550 static void
551 free_get_pseu_authority_handle (struct GetPseuAuthorityHandle *gph)
552 {
553   if (NULL != gph->get_handle)
554   {
555     GNUNET_DHT_get_stop (gph->get_handle);
556     gph->get_handle = NULL;
557   }
558   if (NULL != gph->namestore_task)
559   {
560     GNUNET_NAMESTORE_cancel (gph->namestore_task);
561     gph->namestore_task = NULL;
562   }
563   if (GNUNET_SCHEDULER_NO_TASK != gph->timeout_task)
564   {
565     GNUNET_SCHEDULER_cancel (gph->timeout_task);
566     gph->timeout_task = GNUNET_SCHEDULER_NO_TASK;
567   }
568   GNUNET_CONTAINER_DLL_remove (gph_head, gph_tail, gph);
569   GNUNET_free_non_null (gph->current_label);
570   GNUNET_free (gph);
571 }
572
573
574 /**
575  * Continuation for pkey record creation (shorten)
576  *
577  * @param cls a GetPseuAuthorityHandle
578  * @param success unused
579  * @param emsg unused
580  */
581 static void
582 create_pkey_cont (void* cls, 
583                   int32_t success, 
584                   const char *emsg)
585 {
586   struct GetPseuAuthorityHandle* gph = cls;
587
588   gph->namestore_task = NULL;
589   free_get_pseu_authority_handle (gph);
590 }
591
592
593 /**
594  * Namestore calls this function if we have record for this name.
595  * (or with rd_count=0 to indicate no matches).
596  *
597  * @param cls the pending query
598  * @param rd_count the number of records with 'name'
599  * @param rd the record data
600  */
601 static void
602 process_pseu_lookup_ns (void *cls,
603                         unsigned int rd_count,
604                         const struct GNUNET_NAMESTORE_RecordData *rd);
605
606
607 /**
608  * We obtained a result for our query to the shorten zone from
609  * the namestore.  Try to decrypt.
610  *
611  * @param cls the handle to our shorten operation
612  * @param block resulting encrypted block
613  */
614 static void
615 process_pseu_block_ns (void *cls,
616                        const struct GNUNET_NAMESTORE_Block *block)
617 {
618   struct GetPseuAuthorityHandle *gph = cls;
619   struct GNUNET_CRYPTO_EccPublicKey pub;
620
621   gph->namestore_task = NULL;
622   if (NULL == block)
623   {
624     process_pseu_lookup_ns (gph, 0, NULL);
625     return;
626   }
627   GNUNET_CRYPTO_ecc_key_get_public (&gph->shorten_zone_key,
628                                     &pub);
629   if (GNUNET_OK != 
630       GNUNET_NAMESTORE_block_decrypt (block,
631                                       &pub,
632                                       gph->current_label,
633                                       &process_pseu_lookup_ns,
634                                       gph))
635   {
636     GNUNET_break (0);
637     free_get_pseu_authority_handle (gph);
638     return;
639   }
640 }
641
642
643 /**
644  * Lookup in the namestore for the shorten zone the given label.
645  *
646  * @param gph the handle to our shorten operation
647  * @param label the label to lookup
648  */
649 static void 
650 perform_pseu_lookup (struct GetPseuAuthorityHandle *gph,
651                      const char *label)
652
653   struct GNUNET_CRYPTO_EccPublicKey pub;
654   struct GNUNET_HashCode query;
655
656   GNUNET_CRYPTO_ecc_key_get_public (&gph->shorten_zone_key,
657                                     &pub);
658   GNUNET_free_non_null (gph->current_label);
659   gph->current_label = GNUNET_strdup (label);
660   GNUNET_NAMESTORE_query_from_public_key (&pub,
661                                           label,
662                                           &query);
663   gph->namestore_task = GNUNET_NAMESTORE_lookup_block (namestore_handle,
664                                                        &query,
665                                                        &process_pseu_block_ns,
666                                                        gph);
667 }
668
669
670 /**
671  * Namestore calls this function if we have record for this name.
672  * (or with rd_count=0 to indicate no matches).
673  *
674  * @param cls the pending query
675  * @param rd_count the number of records with 'name'
676  * @param rd the record data
677  */
678 static void
679 process_pseu_lookup_ns (void *cls,
680                         unsigned int rd_count,
681                         const struct GNUNET_NAMESTORE_RecordData *rd)
682 {
683   struct GetPseuAuthorityHandle *gph = cls;
684   struct GNUNET_NAMESTORE_RecordData new_pkey;
685
686   gph->namestore_task = NULL;
687   if (rd_count > 0)
688   {
689     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
690                "Name `%s' already taken, cannot shorten.\n", 
691                gph->current_label);
692     /* if this was not yet the original label, try one more
693        time, this time not using PSEU but the original label */
694     if (0 == strcmp (gph->current_label,
695                      gph->label))
696     {
697       free_get_pseu_authority_handle (gph);
698     }
699     else
700     {
701       perform_pseu_lookup (gph, gph->label);
702     }
703     return;
704   }
705   /* name is available */
706   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
707               "Shortening `%s' to `%s'\n", 
708               GNUNET_NAMESTORE_z2s (&gph->target_zone),
709               gph->current_label);
710   new_pkey.expiration_time = UINT64_MAX;
711   new_pkey.data_size = sizeof (struct GNUNET_CRYPTO_EccPublicKey);
712   new_pkey.data = &gph->target_zone;
713   new_pkey.record_type = GNUNET_NAMESTORE_TYPE_PKEY;
714   new_pkey.flags = GNUNET_NAMESTORE_RF_AUTHORITY
715                  | GNUNET_NAMESTORE_RF_PRIVATE
716                  | GNUNET_NAMESTORE_RF_PENDING;
717   gph->namestore_task 
718     = GNUNET_NAMESTORE_records_store (namestore_handle,
719                                       &gph->shorten_zone_key,
720                                       gph->current_label,
721                                       1, &new_pkey,
722                                       &create_pkey_cont, gph);
723 }
724
725
726 /**
727  * Process result of a DHT lookup for a PSEU record.
728  *
729  * @param gph the handle to our shorten operation
730  * @param pseu the pseu result or NULL
731  */
732 static void
733 process_pseu_result (struct GetPseuAuthorityHandle* gph, 
734                      const char *pseu)
735 {
736   if (NULL == pseu)
737   {
738     /* no PSEU found, try original label */
739     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
740                 "No PSEU found, trying original label `%s' instead.\n",
741                 gph->label);
742     perform_pseu_lookup (gph, gph->label);
743     return;
744   }  
745   /* check if 'pseu' is taken */
746   perform_pseu_lookup (gph, pseu);
747 }
748
749
750 /**
751  * Handle timeout for DHT request during shortening.
752  *
753  * @param cls the request handle as closure
754  * @param tc the task context
755  */
756 static void
757 handle_auth_discovery_timeout (void *cls,
758                                const struct GNUNET_SCHEDULER_TaskContext *tc)
759 {
760   struct GetPseuAuthorityHandle *gph = cls;
761
762   gph->timeout_task = GNUNET_SCHEDULER_NO_TASK;
763   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
764               "DHT lookup for PSEU query timed out.\n");
765   GNUNET_DHT_get_stop (gph->get_handle);
766   gph->get_handle = NULL;
767   process_pseu_result (gph, NULL);
768 }
769
770
771 /**
772  * Handle decrypted records from DHT result.
773  *
774  * @param cls closure with our 'struct GetPseuAuthorityHandle'
775  * @param rd_count number of entries in 'rd' array
776  * @param rd array of records with data to store
777  */
778 static void
779 process_auth_records (void *cls,
780                       unsigned int rd_count,
781                       const struct GNUNET_NAMESTORE_RecordData *rd)
782 {
783   struct GetPseuAuthorityHandle *gph = cls;
784   unsigned int i;
785
786   for (i=0; i < rd_count; i++)
787   {
788     if (GNUNET_NAMESTORE_TYPE_PSEU == rd[i].record_type)
789     {
790       /* found pseu */
791       process_pseu_result (gph, 
792                            (const char *) rd[i].data);
793       return;
794     }
795   }
796   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
797               "No PSEU record found in DHT reply.\n");
798   process_pseu_result (gph, NULL);
799 }
800
801
802 /**
803  * Function called when we find a PSEU entry in the DHT
804  *
805  * @param cls the request handle
806  * @param exp lifetime
807  * @param key the key the record was stored under
808  * @param get_path get path
809  * @param get_path_length get path length
810  * @param put_path put path
811  * @param put_path_length put path length
812  * @param type the block type
813  * @param size the size of the record
814  * @param data the record data
815  */
816 static void
817 process_auth_discovery_dht_result (void* cls,
818                                    struct GNUNET_TIME_Absolute exp,
819                                    const struct GNUNET_HashCode *key,
820                                    const struct GNUNET_PeerIdentity *get_path,
821                                    unsigned int get_path_length,
822                                    const struct GNUNET_PeerIdentity *put_path,
823                                    unsigned int put_path_length,
824                                    enum GNUNET_BLOCK_Type type,
825                                    size_t size,
826                                    const void *data)
827 {
828   struct GetPseuAuthorityHandle *gph = cls;
829   const struct GNUNET_NAMESTORE_Block *block;
830
831   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
832               "Got DHT result for PSEU request\n");
833   GNUNET_DHT_get_stop (gph->get_handle);
834   gph->get_handle = NULL;
835   GNUNET_SCHEDULER_cancel (gph->timeout_task);
836   gph->timeout_task = GNUNET_SCHEDULER_NO_TASK;
837
838   if (NULL == data)
839   {
840     /* is this allowed!? */
841     GNUNET_break (0);
842     process_pseu_result (gph, NULL);
843     return;
844   }
845   if (size < sizeof (struct GNUNET_NAMESTORE_Block))
846   {
847     /* how did this pass DHT block validation!? */
848     GNUNET_break (0);
849     process_pseu_result (gph, NULL);
850     return;   
851   }
852   block = data;
853   if (size !=
854       ntohs (block->purpose.size) + 
855       sizeof (struct GNUNET_CRYPTO_EccPublicKey) +
856       sizeof (struct GNUNET_CRYPTO_EccSignature))
857   {
858     /* how did this pass DHT block validation!? */
859     GNUNET_break (0);
860     process_pseu_result (gph, NULL);
861     return;   
862   }
863   if (GNUNET_OK !=
864       GNUNET_NAMESTORE_block_decrypt (block,
865                                       &gph->target_zone,
866                                       GNUNET_GNS_TLD_PLUS,
867                                       &process_auth_records,
868                                       gph))
869   {
870     /* other peer encrypted invalid block, complain */
871     GNUNET_break_op (0);
872     process_pseu_result (gph, NULL);
873     return;   
874   }
875 }
876
877
878 /**
879  * Callback called by namestore for a zone to name result.  We're
880  * trying to see if a short name for a given zone already exists.
881  *
882  * @param cls the closure
883  * @param zone_key the zone we queried
884  * @param name the name found or NULL
885  * @param rd_len number of records for the name
886  * @param rd the record data (PKEY) for the name
887  */
888 static void
889 process_zone_to_name_discover (void *cls,
890                                const struct GNUNET_CRYPTO_EccPrivateKey *zone_key,
891                                const char *name,
892                                unsigned int rd_len,
893                                const struct GNUNET_NAMESTORE_RecordData *rd)
894 {
895   struct GetPseuAuthorityHandle* gph = cls;
896   struct GNUNET_HashCode lookup_key;
897   
898   gph->namestore_task = NULL;
899   if (0 != rd_len)
900   {
901     /* we found a match in our own zone */
902     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
903                 "Shortening aborted, name `%s' already reserved for the zone\n",
904                 name);
905     free_get_pseu_authority_handle (gph);
906     return;
907   }
908   /* record does not yet exist, go into DHT to find PSEU record */
909   GNUNET_NAMESTORE_query_from_public_key (&gph->target_zone,
910                                           GNUNET_GNS_TLD_PLUS,                                    
911                                           &lookup_key);
912   gph->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
913                                                     &handle_auth_discovery_timeout, 
914                                                     gph);
915   gph->get_handle = GNUNET_DHT_get_start (dht_handle,
916                                           GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
917                                           &lookup_key,
918                                           DHT_GNS_REPLICATION_LEVEL,
919                                           GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
920                                           NULL, 0,
921                                           &process_auth_discovery_dht_result,
922                                           gph);
923 }
924
925
926 /**
927  * Start shortening algorithm, try to allocate a nice short
928  * canonical name for @a pub in @a shorten_zone, using
929  * @a original_label as one possible suggestion.
930  *
931  * @param original_label original label for the zone
932  * @param pub public key of the zone to shorten
933  * @param shorten_zone private key of the target zone for the new record
934  */
935 static void
936 start_shorten (const char *original_label,
937                const struct GNUNET_CRYPTO_EccPublicKey *pub,
938                const struct GNUNET_CRYPTO_EccPrivateKey *shorten_zone)
939 {
940   struct GetPseuAuthorityHandle *gph;
941   
942   if (strlen (original_label) > GNUNET_DNSPARSER_MAX_LABEL_LENGTH)
943   {
944     GNUNET_break (0);
945     return;
946   }
947   gph = GNUNET_new (struct GetPseuAuthorityHandle);
948   gph->shorten_zone_key = *shorten_zone;
949   gph->target_zone = *pub;
950   strcpy (gph->label, original_label);
951   GNUNET_CONTAINER_DLL_insert (gph_head, gph_tail, gph);
952   /* first, check if we *already* have a record for this zone */
953   gph->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
954                                                        shorten_zone,
955                                                        pub,
956                                                        &process_zone_to_name_discover,
957                                                        gph);
958 }
959
960
961 /* ************************** Resolution **************************** */
962
963 #if 0
964
965
966 /**
967  * VPN redirect result callback
968  *
969  * @param cls the resolver handle
970  * @param af the requested address family
971  * @param address in_addr(6) respectively
972  */
973 static void
974 process_record_result_vpn (void* cls, int af, const void *address)
975 {
976   struct ResolverHandle *rh = cls;
977   struct RecordLookupHandle *rlh = rh->proc_cls;
978   struct GNUNET_NAMESTORE_RecordData rd;
979
980   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
981              "GNS_PHASE_REC_VPN-%llu: Got answer from VPN to query!\n",
982              rh->id);
983   if (AF_INET == af)
984   {
985     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
986                "GNS_PHASE_REC-%llu: Answer is IPv4!\n",
987                rh->id);
988     if (GNUNET_DNSPARSER_TYPE_A != rlh->record_type)
989     {
990       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
991                  "GNS_PHASE_REC-%llu: Requested record is not IPv4!\n",
992                  rh->id);
993       rh->proc (rh->proc_cls, rh, 0, NULL);
994       return;
995     }
996     rd.record_type = GNUNET_DNSPARSER_TYPE_A;
997     rd.expiration_time = UINT64_MAX; /* FIXME: should probably pick something shorter... */
998     rd.data = address;
999     rd.data_size = sizeof (struct in_addr);
1000     rd.flags = 0;
1001     rh->proc (rh->proc_cls, rh, 1, &rd);
1002     return;
1003   }
1004   else if (AF_INET6 == af)
1005   {
1006     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1007                "GNS_PHASE_REC-%llu: Answer is IPv6!\n",
1008                rh->id);
1009     if (GNUNET_DNSPARSER_TYPE_AAAA != rlh->record_type)
1010     {
1011       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1012                  "GNS_PHASE_REC-%llu: Requested record is not IPv6!\n",
1013                  rh->id);
1014       rh->proc (rh->proc_cls, rh, 0, NULL);
1015       return;
1016     }
1017     rd.record_type = GNUNET_DNSPARSER_TYPE_AAAA;
1018     rd.expiration_time = UINT64_MAX; /* FIXME: should probably pick something shorter... */
1019     rd.data = address;
1020     rd.data_size = sizeof (struct in6_addr);
1021     rd.flags = 0;
1022     rh->proc (rh->proc_cls, rh, 1, &rd);
1023     return;
1024   }
1025
1026   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1027              "GNS_PHASE_REC-%llu: Got garbage from VPN!\n",
1028              rh->id);
1029   rh->proc (rh->proc_cls, rh, 0, NULL);
1030 }
1031
1032
1033
1034
1035
1036 /**
1037  * The final phase of resoution.
1038  * We found a VPN RR and want to request an IPv4/6 address
1039  *
1040  * @param rh the pending lookup handle
1041  * @param rd_count length of record data
1042  * @param rd record data containing VPN RR
1043  */
1044 static void
1045 resolve_record_vpn (struct ResolverHandle *rh,
1046                     unsigned int rd_count,
1047                     const struct GNUNET_NAMESTORE_RecordData *rd)
1048 {
1049   struct RecordLookupHandle *rlh = rh->proc_cls;
1050   struct GNUNET_HashCode serv_desc;
1051   struct GNUNET_TUN_GnsVpnRecord* vpn;
1052   int af;
1053   
1054   /* We cancel here as to not include the ns lookup in the timeout */
1055   if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
1056   {
1057     GNUNET_SCHEDULER_cancel(rh->timeout_task);
1058     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1059   }
1060   /* Start shortening */
1061   if ((NULL != rh->priv_key) &&
1062       (GNUNET_YES == is_canonical (rh->name)))
1063   {
1064     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1065              "GNS_PHASE_REC_VPN-%llu: Trying to shorten authority chain\n",
1066              rh->id);
1067     start_shorten (rh->authority_chain_head,
1068                    rh->priv_key);
1069   }
1070
1071   vpn = (struct GNUNET_TUN_GnsVpnRecord*)rd->data;
1072   GNUNET_CRYPTO_hash ((char*)&vpn[1],
1073                       strlen ((char*)&vpn[1]) + 1,
1074                       &serv_desc);
1075   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1076               "GNS_PHASE_REC_VPN-%llu: proto %hu peer %s!\n",
1077               rh->id,
1078               ntohs (vpn->proto),
1079               GNUNET_h2s (&vpn->peer));
1080
1081   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1082               "GNS_PHASE_REC_VPN-%llu: service %s -> %s!\n",
1083               rh->id,
1084               (char*)&vpn[1],
1085               GNUNET_h2s (&serv_desc));
1086   rh->proc = &handle_record_vpn;
1087   if (GNUNET_DNSPARSER_TYPE_A == rlh->record_type)
1088     af = AF_INET;
1089   else
1090     af = AF_INET6;
1091 #ifndef WINDOWS
1092   if (NULL == vpn_handle)
1093   {
1094     vpn_handle = GNUNET_VPN_connect (cfg);
1095     if (NULL == vpn_handle)
1096     {
1097       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1098                   "GNS_PHASE_INIT: Error connecting to VPN!\n");
1099       finish_lookup (rh, rh->proc_cls, 0, NULL);
1100       return;
1101     }
1102   }
1103
1104   rh->vpn_handle = GNUNET_VPN_redirect_to_peer (vpn_handle,
1105                                                 af, ntohs (vpn->proto),
1106                                                 (struct GNUNET_PeerIdentity *)&vpn->peer,
1107                                                 &serv_desc,
1108                                                 GNUNET_NO, //nac
1109                                                 GNUNET_TIME_UNIT_FOREVER_ABS, //FIXME
1110                                                 &process_record_result_vpn,
1111                                                 rh);
1112 #else
1113   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1114               "Error connecting to VPN (not available on W32 yet)\n");
1115   finish_lookup (rh, rh->proc_cls, 0, NULL);  
1116 #endif
1117 }
1118
1119
1120 //FIXME maybe define somewhere else?
1121 #define MAX_SOA_LENGTH sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)\
1122                         +(GNUNET_DNSPARSER_MAX_NAME_LENGTH*2)
1123 #define MAX_MX_LENGTH sizeof(uint16_t)+GNUNET_DNSPARSER_MAX_NAME_LENGTH
1124 #define MAX_SRV_LENGTH (sizeof(uint16_t)*3)+GNUNET_DNSPARSER_MAX_NAME_LENGTH
1125
1126
1127 /**
1128  * Exands a name ending in .+ with the zone of origin.
1129  * FIXME: funky api: 'dest' must be large enough to hold
1130  * the result; this is a bit yucky...
1131  *
1132  * @param dest destination buffer
1133  * @param src the .+ name
1134  * @param repl the string to replace the + with
1135  */
1136 static void
1137 expand_plus (char* dest, 
1138              const char* src, 
1139              const char* repl)
1140 {
1141   char* pos;
1142   size_t s_len = strlen (src) + 1;
1143
1144   //Eh? I guess this is at least strlen ('x.+') == 3 FIXME
1145   if (3 > s_len)
1146   {
1147     /* no postprocessing */
1148     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1149                "GNS_POSTPROCESS: %s too short\n", src);
1150     memcpy (dest, src, s_len);
1151     return;
1152   }
1153   if (0 == strcmp (src + s_len - 3, ".+"))
1154   {
1155     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1156                 "GNS_POSTPROCESS: Expanding .+ in %s\n", 
1157                 src);
1158     memset (dest, 0, s_len + strlen (repl) + strlen(GNUNET_GNS_TLD));
1159     strcpy (dest, src);
1160     pos = dest + s_len - 2;
1161     strcpy (pos, repl);
1162     pos += strlen (repl);
1163     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1164                 "GNS_POSTPROCESS: Expanded to %s\n", 
1165                 dest);
1166   }
1167   else
1168   {
1169     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1170                "GNS_POSTPROCESS: No postprocessing for %s\n", src);
1171     memcpy (dest, src, s_len);
1172   }
1173 }
1174
1175
1176 /**
1177  * finish lookup
1178  */
1179 static void
1180 finish_lookup (struct ResolverHandle *rh,
1181                struct RecordLookupHandle* rlh,
1182                unsigned int rd_count,
1183                const struct GNUNET_NAMESTORE_RecordData *rd)
1184 {
1185   unsigned int i;
1186   char new_rr_data[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
1187   char new_mx_data[MAX_MX_LENGTH];
1188   char new_soa_data[MAX_SOA_LENGTH];
1189   char new_srv_data[MAX_SRV_LENGTH];
1190   struct GNUNET_TUN_DnsSrvRecord *old_srv;
1191   struct GNUNET_TUN_DnsSrvRecord *new_srv;
1192   struct GNUNET_TUN_DnsSoaRecord *old_soa;
1193   struct GNUNET_TUN_DnsSoaRecord *new_soa;
1194   struct GNUNET_NAMESTORE_RecordData p_rd[rd_count];
1195   char* repl_string;
1196   char* pos;
1197   unsigned int offset;
1198
1199   if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
1200   {
1201     GNUNET_SCHEDULER_cancel(rh->timeout_task);
1202     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1203   }
1204
1205   GNUNET_CONTAINER_DLL_remove (rlh_head, rlh_tail, rh);
1206
1207   if (0 < rd_count)
1208     memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData));
1209
1210   for (i = 0; i < rd_count; i++)
1211   {
1212     
1213     if ((GNUNET_DNSPARSER_TYPE_NS != rd[i].record_type) &&
1214         (GNUNET_DNSPARSER_TYPE_PTR != rd[i].record_type) &&
1215         (GNUNET_DNSPARSER_TYPE_CNAME != rd[i].record_type) &&
1216         (GNUNET_DNSPARSER_TYPE_MX != rd[i].record_type) &&
1217         (GNUNET_DNSPARSER_TYPE_SOA != rd[i].record_type) &&
1218         (GNUNET_DNSPARSER_TYPE_SRV != rd[i].record_type))
1219     {
1220       p_rd[i].data = rd[i].data;
1221       continue;
1222     }
1223
1224     /**
1225      * for all those records we 'should'
1226      * also try to resolve the A/AAAA records (RFC1035)
1227      * This is a feature and not important
1228      */
1229     
1230     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1231                "GNS_POSTPROCESS: Postprocessing\n");
1232     if (0 == strcmp(rh->name, GNUNET_GNS_MASTERZONE_STR))
1233       repl_string = rlh->name;
1234     else
1235       repl_string = rlh->name+strlen(rh->name)+1;
1236
1237     offset = 0;
1238     if (GNUNET_DNSPARSER_TYPE_MX == rd[i].record_type)
1239     {
1240       memcpy (new_mx_data, (char*)rd[i].data, sizeof(uint16_t));
1241       offset = sizeof (uint16_t);
1242       pos = new_mx_data + offset;
1243       // FIXME: how do we know that 'pos' has enough space for the new name?
1244       expand_plus (pos, (char*)rd[i].data+sizeof(uint16_t),
1245                    repl_string);
1246       offset += strlen(new_mx_data+sizeof(uint16_t)) + 1;
1247       p_rd[i].data = new_mx_data;
1248       p_rd[i].data_size = offset;
1249     }
1250     else if (GNUNET_DNSPARSER_TYPE_SRV == rd[i].record_type)
1251     {
1252       /*
1253        * Prio, weight and port
1254        */
1255       new_srv = (struct GNUNET_TUN_DnsSrvRecord*)new_srv_data;
1256       old_srv = (struct GNUNET_TUN_DnsSrvRecord*)rd[i].data;
1257       new_srv->prio = old_srv->prio;
1258       new_srv->weight = old_srv->weight;
1259       new_srv->port = old_srv->port;
1260       // FIXME: how do we know that '&new_srv[1]' has enough space for the new name?
1261       expand_plus((char*)&new_srv[1], (char*)&old_srv[1],
1262                   repl_string);
1263       p_rd[i].data = new_srv_data;
1264       p_rd[i].data_size = sizeof (struct GNUNET_TUN_DnsSrvRecord) + strlen ((char*)&new_srv[1]) + 1;
1265     }
1266     else if (GNUNET_DNSPARSER_TYPE_SOA == rd[i].record_type)
1267     {
1268       /* expand mname and rname */
1269       old_soa = (struct GNUNET_TUN_DnsSoaRecord*)rd[i].data;
1270       new_soa = (struct GNUNET_TUN_DnsSoaRecord*)new_soa_data;
1271       memcpy (new_soa, old_soa, sizeof (struct GNUNET_TUN_DnsSoaRecord));
1272       // FIXME: how do we know that 'new_soa[1]' has enough space for the new name?
1273       expand_plus((char*)&new_soa[1], (char*)&old_soa[1], repl_string);
1274       offset = strlen ((char*)&new_soa[1]) + 1;
1275       // FIXME: how do we know that 'new_soa[1]' has enough space for the new name?
1276       expand_plus((char*)&new_soa[1] + offset,
1277                   (char*)&old_soa[1] + strlen ((char*)&old_soa[1]) + 1,
1278                   repl_string);
1279       p_rd[i].data_size = sizeof (struct GNUNET_TUN_DnsSoaRecord)
1280                           + offset
1281                           + strlen ((char*)&new_soa[1] + offset);
1282       p_rd[i].data = new_soa_data;
1283     }
1284     else
1285     {
1286       pos = new_rr_data;
1287       // FIXME: how do we know that 'rd[i].data' has enough space for the new name?
1288       expand_plus(pos, (char*)rd[i].data, repl_string);
1289       p_rd[i].data_size = strlen(new_rr_data)+1;
1290       p_rd[i].data = new_rr_data;
1291     }
1292     
1293   }
1294
1295   rlh->proc(rlh->proc_cls, rd_count, p_rd);
1296   GNUNET_free(rlh);
1297   free_resolver_handle (rh);
1298 }
1299
1300
1301 #endif
1302
1303 ///////////////////////////////////////////////////////////////////////////////////////////////////
1304 ///////////////////////////////////////////////////////////////////////////////////////////////////
1305 ///////////////////////////////////////////////////////////////////////////////////////////////////
1306 ///////////////////////////////////////////////////////////////////////////////////////////////////
1307 ///////////////////////////////////////////////////////////////////////////////////////////////////
1308
1309
1310 /**
1311  * Task scheduled to asynchronously fail a resolution.
1312  *
1313  * @param cls the 'struct GNS_ResolverHandle' of the resolution to fail
1314  * @param tc task context
1315  */
1316 static void
1317 fail_resolution (void *cls,
1318                  const struct GNUNET_SCHEDULER_TaskContext *tc)
1319 {
1320   struct GNS_ResolverHandle *rh = cls;
1321
1322   rh->task_id = GNUNET_SCHEDULER_NO_TASK;
1323   rh->proc (rh->proc_cls, 0, NULL);
1324   GNS_resolver_lookup_cancel (rh);
1325 }
1326
1327 #ifdef WINDOWS
1328 /* Don't have this on W32, here's a naive implementation */
1329 void *memrchr (const void *s, int c, size_t n)
1330 {
1331   size_t i;
1332   unsigned char *ucs = (unsigned char *) s;
1333   for (i = n - 1; i >= 0; i--)
1334     if (ucs[i] == c)
1335       return (void *) &ucs[i];
1336   return NULL;
1337 }
1338 #endif
1339
1340 /**
1341  * Get the next, rightmost label from the name that we are trying to resolve,
1342  * and update the resolution position accordingly.
1343  *
1344  * @param rh handle to the resolution operation to get the next label from
1345  * @return NULL if there are no more labels
1346  */
1347 static char *
1348 resolver_lookup_get_next_label (struct GNS_ResolverHandle *rh)
1349 {
1350   const char *rp;
1351   const char *dot;
1352   size_t len;
1353
1354   if (0 == rh->name_resolution_pos)
1355     return NULL;
1356   dot = memrchr (rh->name, (int) '.', rh->name_resolution_pos);
1357   if (NULL == dot)
1358   {
1359     /* done, this was the last one */
1360     len = rh->name_resolution_pos;
1361     rp = rh->name;
1362     rh->name_resolution_pos = 0; 
1363   }
1364   else
1365   {
1366     /* advance by one label */
1367     len = rh->name_resolution_pos - (dot - rh->name) - 1;
1368     rp = dot + 1;
1369     rh->name_resolution_pos = dot - rh->name;
1370   }  
1371   return GNUNET_strndup (rp, len);  
1372 }
1373
1374
1375 /**
1376  * Gives the cummulative result obtained to the callback and clean up the request.
1377  *
1378  * @param rh resolution process that has culminated in a result
1379  */
1380 static void
1381 transmit_lookup_dns_result (struct GNS_ResolverHandle *rh)
1382 {
1383   struct DnsResult *pos;
1384   unsigned int n;
1385   unsigned int i;
1386
1387   n = 0;
1388   for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
1389     n++;
1390   {
1391     struct GNUNET_NAMESTORE_RecordData rd[n];
1392
1393     i = 0;
1394     for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
1395     {
1396       rd[i].data = pos->data;
1397       rd[i].data_size = pos->data_size;
1398       rd[i].record_type = pos->record_type;
1399       if (0 == pos->expiration_time)
1400       {
1401         rd[i].flags = GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION;
1402         rd[i].expiration_time = 0;
1403       }
1404       else
1405       {
1406         rd[i].flags = GNUNET_NAMESTORE_RF_NONE;
1407         rd[i].expiration_time = pos->expiration_time;
1408       }
1409     }      
1410     rh->proc (rh->proc_cls,
1411               n,
1412               rd);
1413   }
1414   GNS_resolver_lookup_cancel (rh);
1415 }
1416
1417
1418 /**
1419  * Add a result from DNS to the records to be returned to the application.
1420  *
1421  * @param rh resolution request to extend with a result
1422  * @param expiration_time expiration time for the answer
1423  * @param record_type DNS record type of the answer
1424  * @param data_size number of bytes in @a data
1425  * @param data binary data to return in DNS record
1426  */
1427 static void
1428 add_dns_result (struct GNS_ResolverHandle *rh,
1429                 uint64_t expiration_time,
1430                 uint32_t record_type,
1431                 size_t data_size,
1432                 const void *data)
1433 {
1434   struct DnsResult *res;
1435
1436   res = GNUNET_malloc (sizeof (struct DnsResult) + data_size);
1437   res->expiration_time = expiration_time;
1438   res->data_size = data_size;
1439   res->record_type = record_type;
1440   res->data = &res[1];
1441   memcpy (&res[1], data, data_size);
1442   GNUNET_CONTAINER_DLL_insert (rh->dns_result_head,
1443                                rh->dns_result_tail,
1444                                res);
1445 }
1446
1447
1448 /**
1449  * We had to do a DNS lookup.  Convert the result (if any) and return
1450  * it.
1451  *
1452  * @param cls closure with the 'struct GNS_ResolverHandle'
1453  * @param addr one of the addresses of the host, NULL for the last address
1454  * @param addrlen length of the address
1455  */
1456 static void
1457 handle_dns_result (void *cls,
1458                    const struct sockaddr *addr,
1459                    socklen_t addrlen)
1460 {
1461   struct GNS_ResolverHandle *rh = cls;
1462   const struct sockaddr_in *sa4;
1463   const struct sockaddr_in6 *sa6;
1464
1465   rh->std_resolve = NULL;
1466   if (NULL == addr)
1467   {
1468     transmit_lookup_dns_result (rh);
1469     return;
1470   }
1471   switch (addr->sa_family)
1472   {
1473   case AF_INET:
1474     sa4 = (const struct sockaddr_in *) addr;
1475     add_dns_result (rh,
1476                     0 /* expiration time is unknown */,
1477                     GNUNET_DNSPARSER_TYPE_A,
1478                     sizeof (struct in_addr),
1479                     &sa4->sin_addr);
1480     break;
1481   case AF_INET6:
1482     sa6 = (const struct sockaddr_in6 *) addr;
1483     add_dns_result (rh,
1484                     0 /* expiration time is unknown */,
1485                     GNUNET_DNSPARSER_TYPE_AAAA,
1486                     sizeof (struct in6_addr),
1487                     &sa6->sin6_addr);
1488     break;
1489   default:
1490     GNUNET_break (0);
1491     break;
1492   }
1493 }
1494
1495
1496 /**
1497  * Task scheduled to continue with the resolution process.
1498  *
1499  * @param cls the 'struct GNS_ResolverHandle' of the resolution
1500  * @param tc task context
1501  */
1502 static void
1503 recursive_resolution (void *cls,
1504                       const struct GNUNET_SCHEDULER_TaskContext *tc);
1505
1506
1507 /**
1508  * Function called with the result of a DNS resolution.
1509  *
1510  * @param cls the request handle of the resolution that
1511  *        we were attempting to make
1512  * @param rs socket that received the response
1513  * @param dns dns response, never NULL
1514  * @param dns_len number of bytes in 'dns'
1515  */
1516 static void
1517 dns_result_parser (void *cls,
1518                    struct GNUNET_DNSSTUB_RequestSocket *rs,
1519                    const struct GNUNET_TUN_DnsHeader *dns,
1520                    size_t dns_len)
1521 {
1522   struct GNS_ResolverHandle *rh = cls;
1523   struct GNUNET_DNSPARSER_Packet *p;
1524
1525   rh->dns_request = NULL;
1526   GNUNET_SCHEDULER_cancel (rh->task_id);
1527   rh->task_id = GNUNET_SCHEDULER_NO_TASK;
1528   p = GNUNET_DNSPARSER_parse ((const char *) dns, 
1529                               dns_len);
1530   if (NULL == p)
1531   {
1532     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1533                 _("Failed to parse DNS response\n"));
1534     rh->proc (rh->proc_cls, 0, NULL);
1535     GNS_resolver_lookup_cancel (rh);
1536     return;
1537   }
1538   // FIXME: 
1539   // Check if the packet is the final answer, or
1540   // just pointing us to another NS or another name (CNAME), or another domain (DNAME);
1541   // then do the right thing (TM) -- possibly using "recursive_dns_resolution".
1542   GNUNET_break (0);
1543   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1544               _("NOT IMPLEMENTED\n"));
1545   rh->proc (rh->proc_cls, 0, NULL);
1546   GNS_resolver_lookup_cancel (rh);
1547
1548   
1549   GNUNET_DNSPARSER_free_packet (p);
1550 }
1551
1552
1553 /**
1554  * Perform recursive DNS resolution.  Asks the given DNS resolver to
1555  * resolve "rh->dns_name", possibly recursively proceeding following
1556  * NS delegations, CNAMES, etc., until 'rh->loop_limiter' bounds us or
1557  * we find the answer.
1558  *
1559  * @param rh resolution information
1560  */
1561 static void
1562 recursive_dns_resolution (struct GNS_ResolverHandle *rh)
1563 {
1564   struct AuthorityChain *ac;
1565   socklen_t sa_len;
1566   struct GNUNET_DNSPARSER_Query *query;
1567   struct GNUNET_DNSPARSER_Packet *p;
1568   char *dns_request;
1569   size_t dns_request_length;
1570
1571   ac = rh->ac_tail;
1572   GNUNET_assert (NULL != ac);
1573   GNUNET_assert (GNUNET_NO == ac->gns_authority);
1574   switch (((const struct sockaddr *) &ac->authority_info.dns_authority.dns_ip)->sa_family)
1575   {
1576   case AF_INET:
1577     sa_len = sizeof (struct sockaddr_in);
1578     break;
1579   case AF_INET6:
1580     sa_len = sizeof (struct sockaddr_in6);
1581     break;
1582   default:
1583     GNUNET_break (0);
1584     rh->proc (rh->proc_cls, 0, NULL);
1585     GNS_resolver_lookup_cancel (rh);
1586     return;
1587   }
1588   query = GNUNET_new (struct GNUNET_DNSPARSER_Query);
1589   query->name = GNUNET_strdup (ac->label);
1590   query->type = rh->record_type;
1591   query->class = GNUNET_TUN_DNS_CLASS_INTERNET;
1592   p = GNUNET_new (struct GNUNET_DNSPARSER_Packet);
1593   p->queries = query;
1594   p->num_queries = 1;
1595   p->id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1596                                                UINT16_MAX);
1597   p->flags.opcode = GNUNET_TUN_DNS_OPCODE_QUERY;
1598   p->flags.recursion_desired = 1;
1599   if (GNUNET_OK != 
1600       GNUNET_DNSPARSER_pack (p, 1024, &dns_request, &dns_request_length))
1601   {
1602     GNUNET_break (0);
1603     rh->proc (rh->proc_cls, 0, NULL);
1604     GNS_resolver_lookup_cancel (rh);
1605   }
1606   else
1607   {
1608     rh->dns_request = GNUNET_DNSSTUB_resolve (dns_handle,
1609                                               (const struct sockaddr *) &ac->authority_info.dns_authority.dns_ip,
1610                                               sa_len,
1611                                               dns_request,
1612                                               dns_request_length,
1613                                               &dns_result_parser,
1614                                               rh);
1615     rh->task_id = GNUNET_SCHEDULER_add_delayed (DNS_LOOKUP_TIMEOUT,
1616                                                 &fail_resolution,
1617                                                 rh);
1618   }
1619   GNUNET_free (dns_request);
1620   GNUNET_DNSPARSER_free_packet (p);
1621 }
1622
1623
1624 /**
1625  * We encountered a CNAME record during our resolution.
1626  * Merge it into our chain.
1627  *
1628  * @param rh resolution we are performing
1629  * @param cname value of the cname record we got for the current 
1630  *        authority chain tail
1631  */
1632 static void
1633 handle_gns_cname_result (struct GNS_ResolverHandle *rh,
1634                          const char *cname)
1635 {
1636   // FIXME: not implemented
1637   GNUNET_break (0);
1638   rh->proc (rh->proc_cls, 0, NULL);
1639   GNS_resolver_lookup_cancel (rh);
1640 }
1641
1642
1643 /**
1644  * Process a records that were decrypted from a block.
1645  *
1646  * @param cls closure with the 'struct GNS_ResolverHandle'
1647  * @param rd_count number of entries in @a rd array
1648  * @param rd array of records with data to store
1649  */
1650 static void
1651 handle_gns_resolution_result (void *cls,
1652                               unsigned int rd_count,
1653                               const struct GNUNET_NAMESTORE_RecordData *rd)
1654 {
1655   struct GNS_ResolverHandle *rh = cls;
1656   struct AuthorityChain *ac;
1657   unsigned int i;
1658   unsigned int j;
1659   struct sockaddr *sa;
1660   struct sockaddr_in v4;
1661   struct sockaddr_in6 v6;
1662   size_t sa_len;
1663   char *cname;
1664    
1665   if (0 == rh->name_resolution_pos)
1666   {
1667     /* top-level match, are we done yet? */
1668     if ( (rd_count > 0) &&
1669          (GNUNET_DNSPARSER_TYPE_CNAME == rd[0].record_type) &&
1670          (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type) )
1671     {
1672       cname = GNUNET_strndup (rd[0].data,
1673                               rd[0].data_size);
1674       handle_gns_cname_result (rh, 
1675                                cname);
1676       GNUNET_free (cname);
1677       return;     
1678     }
1679     /* FIXME: if A/AAAA was requested, but we got a VPN
1680        record, we should interact with GNUnet VPN here */
1681     
1682     /* yes, we are done, return result */
1683     rh->proc (rh->proc_cls, rd_count, rd);
1684     GNS_resolver_lookup_cancel (rh);
1685     return;         
1686   }
1687   /* need to recurse, check if we can */
1688   for (i=0;i<rd_count;i++)
1689   {
1690     switch (rd[i].record_type)
1691     {
1692     case GNUNET_NAMESTORE_TYPE_PKEY:
1693       /* delegation to another zone */
1694       if (sizeof (struct GNUNET_CRYPTO_EccPublicKey) !=
1695           rd[i].data_size)
1696       {
1697         GNUNET_break_op (0);
1698         rh->proc (rh->proc_cls, 0, NULL);
1699         GNS_resolver_lookup_cancel (rh);
1700         return;     
1701       }
1702       /* expand authority chain */
1703       ac = GNUNET_new (struct AuthorityChain);
1704       ac->rh = rh;
1705       ac->gns_authority = GNUNET_YES;
1706       memcpy (&ac->authority_info.gns_authority,
1707               rd[i].data,
1708               sizeof (struct GNUNET_CRYPTO_EccPublicKey));
1709       ac->label = resolver_lookup_get_next_label (rh);
1710       GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1711                                         rh->ac_tail,
1712                                         ac);
1713       /* recurse */
1714       rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1715                                               rh);
1716       break;
1717     case GNUNET_DNSPARSER_TYPE_NS:
1718       /* resolution continues within DNS */
1719       if (GNUNET_DNSPARSER_MAX_NAME_LENGTH < rd[i].data_size)
1720       {
1721         GNUNET_break_op (0);
1722         rh->proc (rh->proc_cls, 0, NULL);
1723         GNS_resolver_lookup_cancel (rh);
1724         return;     
1725       }
1726       /* find associated A/AAAA record */
1727       sa = NULL;
1728       for (j=0;j<rd_count;j++)
1729       {
1730         switch (rd[j].record_type)
1731         {
1732         case GNUNET_DNSPARSER_TYPE_A:
1733           if (sizeof (struct in_addr) != rd[i].data_size)
1734           {
1735             GNUNET_break_op (0);
1736             rh->proc (rh->proc_cls, 0, NULL);
1737             GNS_resolver_lookup_cancel (rh);
1738             return;     
1739           }
1740           /* FIXME: might want to check if we support IPv4 here,
1741              and otherwise skip this one and hope we find another */
1742           memset (&v4, 0, sizeof (v4));
1743           sa_len = sizeof (v4);
1744           v4.sin_family = AF_INET;
1745           v4.sin_port = htons (53);
1746 #if HAVE_SOCKADDR_IN_SIN_LEN
1747           v4.sin_len = (u_char) sa_len;
1748 #endif
1749           memcpy (&v4.sin_addr,
1750                   rd[j].data,
1751                   sizeof (struct in_addr));
1752           sa = (struct sockaddr *) &v4;
1753           break;
1754         case GNUNET_DNSPARSER_TYPE_AAAA:
1755           if (sizeof (struct in6_addr) != rd[i].data_size)
1756           {
1757             GNUNET_break_op (0);
1758             rh->proc (rh->proc_cls, 0, NULL);
1759             GNS_resolver_lookup_cancel (rh);
1760             return;     
1761           }
1762           /* FIXME: might want to check if we support IPv6 here,
1763              and otherwise skip this one and hope we find another */
1764           memset (&v6, 0, sizeof (v6));
1765           sa_len = sizeof (v6);
1766           v6.sin6_family = AF_INET6;
1767           v6.sin6_port = htons (53);
1768 #if HAVE_SOCKADDR_IN_SIN_LEN
1769           v6.sin6_len = (u_char) sa_len;
1770 #endif
1771           memcpy (&v6.sin6_addr,
1772                   rd[j].data,
1773                   sizeof (struct in6_addr));
1774           sa = (struct sockaddr *) &v6;
1775           break;
1776         }
1777         if (NULL != sa)
1778           break;
1779       }
1780       /* expand authority chain */
1781       ac = GNUNET_new (struct AuthorityChain);
1782       ac->rh = rh;
1783       strncpy (ac->authority_info.dns_authority.name,
1784                rd[i].data,
1785                rd[i].data_size);
1786       ac->authority_info.dns_authority.name[rd[i].data_size] = '\0';
1787       memcpy (&ac->authority_info.dns_authority.dns_ip,
1788               sa,
1789               sa_len);
1790       /* for DNS recursion, the label is the full DNS name,
1791          created from the remainder of the GNS name and the
1792          name in the NS record */
1793       GNUNET_asprintf (&ac->label,
1794                        "%.*s%s",
1795                        (int) rh->name_resolution_pos,
1796                        rh->name,
1797                        ac->authority_info.dns_authority.name);
1798       GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1799                                         rh->ac_tail,
1800                                         ac);
1801       if (strlen (ac->label) > GNUNET_DNSPARSER_MAX_NAME_LENGTH)
1802       {
1803         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1804                     _("GNS lookup resulted in DNS name that is too long (`%s')\n"),
1805                     ac->label);
1806         rh->proc (rh->proc_cls, 0, NULL);
1807         GNS_resolver_lookup_cancel (rh);
1808         return;
1809       }
1810       /* recurse */
1811       rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1812                                               rh);
1813       return;
1814     case GNUNET_DNSPARSER_TYPE_CNAME:
1815       cname = GNUNET_strndup (rd[i].data,
1816                               rd[i].data_size);
1817       handle_gns_cname_result (rh, 
1818                                cname);
1819       GNUNET_free (cname);
1820       return;
1821       /* FIXME: handle DNAME */
1822     default:
1823       /* skip */
1824       break;
1825     }
1826   }
1827   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1828               _("GNS lookup recursion failed (no delegation record found)\n"));
1829   rh->proc (rh->proc_cls, 0, NULL);
1830   GNS_resolver_lookup_cancel (rh);
1831 }
1832
1833
1834 /**
1835  * Function called once the namestore has completed the request for
1836  * caching a block.
1837  *
1838  * @param cls closure with the 'struct GNS_ResolverHandle'
1839  * @param success #GNUNET_OK on success
1840  * @param emsg error message
1841  */
1842 static void
1843 namestore_cache_continuation (void *cls,
1844                               int32_t success,
1845                               const char *emsg)
1846 {
1847   struct GNS_ResolverHandle *rh = cls;
1848
1849   rh->namestore_qe = NULL;
1850   if (NULL != emsg)
1851     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1852                 _("Failed to cache GNS resolution: %s\n"),
1853                 emsg);
1854 }
1855
1856
1857 /**
1858  * Iterator called on each result obtained for a DHT
1859  * operation that expects a reply
1860  *
1861  * @param cls closure with the 'struct GNS_ResolverHandle'
1862  * @param exp when will this value expire
1863  * @param key key of the result
1864  * @param get_path peers on reply path (or NULL if not recorded)
1865  *                 [0] = datastore's first neighbor, [length - 1] = local peer
1866  * @param get_path_length number of entries in get_path
1867  * @param put_path peers on the PUT path (or NULL if not recorded)
1868  *                 [0] = origin, [length - 1] = datastore
1869  * @param put_path_length number of entries in get_path
1870  * @param type type of the result
1871  * @param size number of bytes in data
1872  * @param data pointer to the result data
1873  */
1874 static void
1875 handle_dht_response (void *cls,
1876                      struct GNUNET_TIME_Absolute exp,
1877                      const struct GNUNET_HashCode * key,
1878                      const struct GNUNET_PeerIdentity *get_path,
1879                      unsigned int get_path_length,
1880                      const struct GNUNET_PeerIdentity *put_path, 
1881                      unsigned int put_path_length,
1882                      enum GNUNET_BLOCK_Type type,
1883                      size_t size, const void *data)
1884 {
1885   struct GNS_ResolverHandle *rh = cls;
1886   struct AuthorityChain *ac = rh->ac_tail;
1887   const struct GNUNET_NAMESTORE_Block *block;
1888   
1889   GNUNET_DHT_get_stop (rh->get_handle);
1890   rh->get_handle = NULL;
1891   GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
1892   rh->dht_heap_node = NULL;  
1893   if (size < sizeof (struct GNUNET_NAMESTORE_Block))
1894   {
1895     /* how did this pass DHT block validation!? */
1896     GNUNET_break (0);
1897     rh->proc (rh->proc_cls, 0, NULL);
1898     GNS_resolver_lookup_cancel (rh);
1899     return;   
1900   }
1901   block = data; 
1902   if (size !=
1903       ntohs (block->purpose.size) + 
1904       sizeof (struct GNUNET_CRYPTO_EccPublicKey) +
1905       sizeof (struct GNUNET_CRYPTO_EccSignature))
1906   {
1907     /* how did this pass DHT block validation!? */
1908     GNUNET_break (0);
1909     rh->proc (rh->proc_cls, 0, NULL);
1910     GNS_resolver_lookup_cancel (rh);
1911     return;   
1912   }
1913   if (GNUNET_OK !=
1914       GNUNET_NAMESTORE_block_decrypt (block,
1915                                       &ac->authority_info.gns_authority,
1916                                       ac->label,
1917                                       &handle_gns_resolution_result,
1918                                       rh))
1919   {
1920     GNUNET_break_op (0); /* block was ill-formed */
1921     rh->proc (rh->proc_cls, 0, NULL);
1922     GNS_resolver_lookup_cancel (rh);
1923     return;
1924   }
1925   /* Cache well-formed blocks */
1926   rh->namestore_qe = GNUNET_NAMESTORE_block_cache (namestore_handle,
1927                                                    block,
1928                                                    &namestore_cache_continuation,
1929                                                    rh);
1930 }
1931
1932
1933 /**
1934  * Process a record that was stored in the namestore.
1935  *
1936  * @param cls closure with the 'struct GNS_ResolverHandle'
1937  * @param block block that was stored in the namestore
1938  */
1939 static void 
1940 handle_namestore_block_response (void *cls,
1941                                  const struct GNUNET_NAMESTORE_Block *block)
1942 {
1943   struct GNS_ResolverHandle *rh = cls;
1944   struct GNS_ResolverHandle *rx;
1945   struct AuthorityChain *ac = rh->ac_tail;
1946   const char *label = ac->label;
1947   const struct GNUNET_CRYPTO_EccPublicKey *auth = &ac->authority_info.gns_authority;
1948   struct GNUNET_HashCode query;
1949
1950   GNUNET_NAMESTORE_query_from_public_key (auth,
1951                                           label,
1952                                           &query);
1953   rh->namestore_qe = NULL;
1954   if (NULL == block)
1955   {
1956     /* Namestore knows nothing; try DHT lookup */
1957     rh->get_handle = GNUNET_DHT_get_start (dht_handle,
1958                                            GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1959                                            &query,
1960                                            DHT_GNS_REPLICATION_LEVEL,
1961                                            GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
1962                                            NULL, 0,
1963                                            &handle_dht_response, rh);
1964     rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
1965                                                       rh,
1966                                                       GNUNET_TIME_absolute_get ().abs_value_us);
1967     if (GNUNET_CONTAINER_heap_get_size (dht_lookup_heap) > max_allowed_background_queries)
1968     {
1969       /* fail longest-standing DHT request */
1970       rx = GNUNET_CONTAINER_heap_peek (dht_lookup_heap);
1971       rx->proc (rx->proc_cls, 0, NULL);
1972       GNS_resolver_lookup_cancel (rx);
1973     }
1974     return;
1975   }
1976   if (GNUNET_OK !=
1977       GNUNET_NAMESTORE_block_decrypt (block,
1978                                       auth,
1979                                       label,
1980                                       &handle_gns_resolution_result,
1981                                       rh))
1982   {
1983     GNUNET_break_op (0); /* block was ill-formed */
1984     rh->proc (rh->proc_cls, 0, NULL);
1985     GNS_resolver_lookup_cancel (rh);
1986     return;
1987   }
1988 }
1989
1990
1991 /**
1992  * Lookup tail of our authority chain in the namestore.
1993  *
1994  * @param rh query we are processing
1995  */
1996 static void
1997 recursive_gns_resolution_namestore (struct GNS_ResolverHandle *rh)
1998 {
1999   struct AuthorityChain *ac = rh->ac_tail;
2000   struct GNUNET_HashCode query;
2001
2002   GNUNET_NAMESTORE_query_from_public_key (&ac->authority_info.gns_authority,
2003                                           ac->label,
2004                                           &query);
2005   rh->namestore_qe = GNUNET_NAMESTORE_lookup_block (namestore_handle,
2006                                                     &query,
2007                                                     &handle_namestore_block_response,
2008                                                     rh);
2009 }
2010
2011
2012 /**
2013  * Task scheduled to continue with the resolution process.
2014  *
2015  * @param cls the 'struct GNS_ResolverHandle' of the resolution
2016  * @param tc task context
2017  */
2018 static void
2019 recursive_resolution (void *cls,
2020                       const struct GNUNET_SCHEDULER_TaskContext *tc)
2021 {
2022   struct GNS_ResolverHandle *rh = cls;
2023
2024   rh->task_id = GNUNET_SCHEDULER_NO_TASK;
2025   if (MAX_RECURSION < rh->loop_limiter++)
2026   {
2027     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2028                 "Encountered unbounded recursion resolving `%s'\n",
2029                 rh->name);
2030     rh->proc (rh->proc_cls, 0, NULL);
2031     GNS_resolver_lookup_cancel (rh);
2032     return;
2033   }
2034   if (GNUNET_YES == rh->ac_tail->gns_authority)
2035     recursive_gns_resolution_namestore (rh);
2036   else
2037     recursive_dns_resolution (rh);
2038 }
2039
2040
2041 /**
2042  * Lookup of a record in a specific zone calls lookup result processor
2043  * on result.
2044  *
2045  * @param zone the zone to perform the lookup in
2046  * @param record_type the record type to look up
2047  * @param name the name to look up
2048  * @param shorten_key a private key for use with PSEU import (can be NULL)
2049  * @param only_cached GNUNET_NO to only check locally not DHT for performance
2050  * @param proc the processor to call on result
2051  * @param proc_cls the closure to pass to @a proc
2052  * @return handle to cancel operation
2053  */
2054 struct GNS_ResolverHandle *
2055 GNS_resolver_lookup (const struct GNUNET_CRYPTO_EccPublicKey *zone,
2056                      uint32_t record_type,
2057                      const char *name,
2058                      const struct GNUNET_CRYPTO_EccPrivateKey *shorten_key,
2059                      int only_cached,
2060                      GNS_ResultProcessor proc, void *proc_cls)
2061 {
2062   struct GNS_ResolverHandle *rh;
2063   struct AuthorityChain *ac;
2064   char *x;
2065   char *y;
2066   char *pkey;
2067
2068   rh = GNUNET_new (struct GNS_ResolverHandle);
2069   GNUNET_CONTAINER_DLL_insert (rlh_head,
2070                                rlh_tail,
2071                                rh);
2072   rh->authority_zone = *zone;
2073   rh->proc = proc;
2074   rh->proc_cls = proc_cls;
2075   rh->only_cached = only_cached;
2076   rh->record_type = record_type;
2077   rh->name = GNUNET_strdup (name);
2078   rh->name_resolution_pos = strlen (name);
2079   if (NULL != shorten_key)
2080   {
2081     rh->shorten_key = GNUNET_new (struct GNUNET_CRYPTO_EccPrivateKey);
2082     *rh->shorten_key = *shorten_key;
2083   }
2084
2085   if ( ( (GNUNET_YES == is_canonical (name)) &&
2086          (0 != strcmp (GNUNET_GNS_TLD, name)) ) ||
2087        ( (GNUNET_YES != is_gnu_tld (name)) &&
2088          (GNUNET_YES != is_zkey_tld (name)) ) )
2089   {
2090     /* use standard DNS lookup */
2091     int af;
2092
2093     switch (record_type)
2094     {
2095     case GNUNET_DNSPARSER_TYPE_A:
2096       af = AF_INET;
2097       break;
2098     case GNUNET_DNSPARSER_TYPE_AAAA:
2099       af = AF_INET6;
2100       break;
2101     default:
2102       af = AF_UNSPEC;
2103       break;
2104     }
2105     rh->std_resolve = GNUNET_RESOLVER_ip_get (name, 
2106                                               af,
2107                                               DNS_LOOKUP_TIMEOUT,
2108                                               &handle_dns_result,
2109                                               rh);
2110     return rh;
2111   }
2112   if (is_zkey_tld (name))
2113   {
2114     /* Name ends with ".zkey", try to replace authority zone with zkey
2115        authority */
2116     GNUNET_free (resolver_lookup_get_next_label (rh)); /* will return "zkey" */
2117     x = resolver_lookup_get_next_label (rh); /* will return 'x' coordinate */
2118     y = resolver_lookup_get_next_label (rh); /* will return 'y' coordinate */
2119     GNUNET_asprintf (&pkey,
2120                      "%s%s",
2121                      x, y);
2122     if ( (NULL == x) ||
2123          (NULL == y) ||
2124          (GNUNET_OK !=
2125           GNUNET_CRYPTO_ecc_public_key_from_string (pkey,
2126                                                     strlen (pkey),
2127                                                     &rh->authority_zone)) )
2128     {
2129       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2130                   _("Hostname `%s' is not well-formed, resolution fails\n"),
2131                   name);
2132       rh->task_id = GNUNET_SCHEDULER_add_now (&fail_resolution, rh);
2133     }
2134     GNUNET_free_non_null (x);
2135     GNUNET_free_non_null (y);
2136     GNUNET_free (pkey);
2137   }
2138   else
2139   {
2140     /* Name ends with ".gnu", eat ".gnu" and continue with resolution */
2141     GNUNET_free (resolver_lookup_get_next_label (rh));
2142   }
2143   ac = GNUNET_new (struct AuthorityChain);
2144   ac->rh = rh;
2145   ac->label = resolver_lookup_get_next_label (rh);
2146   if (NULL == ac->label)
2147     /* name was just "gnu", so we default to label '+' */
2148     ac->label = GNUNET_strdup (GNUNET_GNS_MASTERZONE_STR);
2149   ac->gns_authority = GNUNET_YES;
2150   ac->authority_info.gns_authority = rh->authority_zone;
2151   GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
2152                                     rh->ac_tail,
2153                                     ac);
2154   rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
2155                                           rh);
2156   return rh;
2157 }
2158
2159
2160 /**
2161  * Cancel active resolution (i.e. client disconnected).
2162  *
2163  * @param rh resolution to abort
2164  */
2165 void
2166 GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
2167 {
2168   struct DnsResult *dr;
2169   struct AuthorityChain *ac;
2170
2171   GNUNET_CONTAINER_DLL_remove (rlh_head,
2172                                rlh_tail,
2173                                rh);
2174   while (NULL != (ac = rh->ac_head))
2175   {
2176     GNUNET_CONTAINER_DLL_remove (rh->ac_head,
2177                                  rh->ac_tail,
2178                                  ac);
2179     GNUNET_free (ac->label);
2180     GNUNET_free (ac);
2181   }
2182   if (GNUNET_SCHEDULER_NO_TASK != rh->task_id)
2183   {
2184     GNUNET_SCHEDULER_cancel (rh->task_id);
2185     rh->task_id = GNUNET_SCHEDULER_NO_TASK;
2186   }
2187   if (NULL != rh->get_handle)
2188   {
2189     GNUNET_DHT_get_stop (rh->get_handle);
2190     rh->get_handle = NULL;
2191   }
2192   if (NULL != rh->dht_heap_node)
2193   {
2194     GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
2195     rh->dht_heap_node = NULL;
2196   }
2197   if (NULL != rh->dns_request)
2198   {
2199     GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
2200     rh->dns_request = NULL;
2201   }
2202   if (NULL != rh->namestore_qe)
2203   {
2204     GNUNET_NAMESTORE_cancel (rh->namestore_qe);
2205     rh->namestore_qe = NULL;
2206   }
2207   if (NULL != rh->std_resolve)
2208   {
2209     GNUNET_RESOLVER_request_cancel (rh->std_resolve);
2210     rh->std_resolve = NULL;
2211   }
2212   while (NULL != (dr = rh->dns_result_head))
2213   {
2214     GNUNET_CONTAINER_DLL_remove (rh->dns_result_head,
2215                                  rh->dns_result_tail,
2216                                  dr);
2217     GNUNET_free (dr);
2218   }
2219   GNUNET_free_non_null (rh->shorten_key);
2220   GNUNET_free (rh->name);
2221   GNUNET_free (rh);
2222 }
2223
2224
2225 /* ***************** Resolver initialization ********************* */
2226
2227
2228 /**
2229  * Initialize the resolver
2230  *
2231  * @param nh the namestore handle
2232  * @param dht the dht handle
2233  * @param c configuration handle
2234  * @param max_bg_queries maximum number of parallel background queries in dht
2235  */
2236 void
2237 GNS_resolver_init (struct GNUNET_NAMESTORE_Handle *nh,
2238                    struct GNUNET_DHT_Handle *dht,
2239                    const struct GNUNET_CONFIGURATION_Handle *c,
2240                    unsigned long long max_bg_queries)
2241 {
2242   char *dns_ip;
2243
2244   cfg = c;
2245   namestore_handle = nh;
2246   dht_handle = dht;
2247   dht_lookup_heap =
2248     GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
2249   max_allowed_background_queries = max_bg_queries;
2250   if (GNUNET_OK !=
2251       GNUNET_CONFIGURATION_get_value_string (c,
2252                                              "gns",
2253                                              "DNS_RESOLVER",
2254                                              &dns_ip))
2255   {
2256     /* user did not specify DNS resolver, use 8.8.8.8 */
2257     dns_ip = GNUNET_strdup ("8.8.8.8");
2258   }
2259   dns_handle = GNUNET_DNSSTUB_start (dns_ip);
2260   GNUNET_free (dns_ip);
2261 }
2262
2263
2264 /**
2265  * Shutdown resolver
2266  */
2267 void
2268 GNS_resolver_done ()
2269 {
2270   struct GNS_ResolverHandle *rh;
2271
2272   /* abort active resolutions */
2273   while (NULL != (rh = rlh_head))
2274   {
2275     rh->proc (rh->proc_cls, 0, NULL);
2276     GNS_resolver_lookup_cancel (rh);    
2277   }
2278   /* abort active shorten operations */
2279   while (NULL != gph_head)
2280     free_get_pseu_authority_handle (gph_head);
2281   GNUNET_CONTAINER_heap_destroy (dht_lookup_heap);
2282   dht_lookup_heap = NULL;
2283   GNUNET_DNSSTUB_stop (dns_handle);
2284   dns_handle = NULL;
2285 }
2286
2287
2288 /* *************** common helper functions (do not really belong here) *********** */
2289
2290 /**
2291  * Checks if "name" ends in ".tld"
2292  *
2293  * @param name the name to check
2294  * @param tld the TLD to check for
2295  * @return GNUNET_YES or GNUNET_NO
2296  */
2297 int
2298 is_tld (const char* name, const char* tld)
2299 {
2300   size_t offset = 0;
2301
2302   if (strlen (name) <= strlen (tld))
2303     return GNUNET_NO;
2304   offset = strlen (name) - strlen (tld);
2305   if (0 != strcmp (name + offset, tld))
2306     return GNUNET_NO;
2307   return GNUNET_YES;
2308 }
2309
2310
2311 /* end of gnunet-service-gns_resolver.c */