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