6d77997e71999311e2c7adff54d81cfd83482a18
[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
1328 /**
1329  * Get the next, rightmost label from the name that we are trying to resolve,
1330  * and update the resolution position accordingly.
1331  *
1332  * @param rh handle to the resolution operation to get the next label from
1333  * @return NULL if there are no more labels
1334  */
1335 static char *
1336 resolver_lookup_get_next_label (struct GNS_ResolverHandle *rh)
1337 {
1338   const char *rp;
1339   const char *dot;
1340   size_t len;
1341
1342   if (0 == rh->name_resolution_pos)
1343     return NULL;
1344   dot = memrchr (rh->name, (int) '.', rh->name_resolution_pos);
1345   if (NULL == dot)
1346   {
1347     /* done, this was the last one */
1348     len = rh->name_resolution_pos;
1349     rp = rh->name;
1350     rh->name_resolution_pos = 0; 
1351   }
1352   else
1353   {
1354     /* advance by one label */
1355     len = rh->name_resolution_pos - (dot - rh->name) - 1;
1356     rp = dot + 1;
1357     rh->name_resolution_pos = dot - rh->name;
1358   }  
1359   return GNUNET_strndup (rp, len);  
1360 }
1361
1362
1363 /**
1364  * Gives the cummulative result obtained to the callback and clean up the request.
1365  *
1366  * @param rh resolution process that has culminated in a result
1367  */
1368 static void
1369 transmit_lookup_dns_result (struct GNS_ResolverHandle *rh)
1370 {
1371   struct DnsResult *pos;
1372   unsigned int n;
1373   unsigned int i;
1374
1375   n = 0;
1376   for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
1377     n++;
1378   {
1379     struct GNUNET_NAMESTORE_RecordData rd[n];
1380
1381     i = 0;
1382     for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
1383     {
1384       rd[i].data = pos->data;
1385       rd[i].data_size = pos->data_size;
1386       rd[i].record_type = pos->record_type;
1387       if (0 == pos->expiration_time)
1388       {
1389         rd[i].flags = GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION;
1390         rd[i].expiration_time = 0;
1391       }
1392       else
1393       {
1394         rd[i].flags = GNUNET_NAMESTORE_RF_NONE;
1395         rd[i].expiration_time = pos->expiration_time;
1396       }
1397     }      
1398     rh->proc (rh->proc_cls,
1399               n,
1400               rd);
1401   }
1402   GNS_resolver_lookup_cancel (rh);
1403 }
1404
1405
1406 /**
1407  * Add a result from DNS to the records to be returned to the application.
1408  *
1409  * @param rh resolution request to extend with a result
1410  * @param expiration_time expiration time for the answer
1411  * @param record_type DNS record type of the answer
1412  * @param data_size number of bytes in @a data
1413  * @param data binary data to return in DNS record
1414  */
1415 static void
1416 add_dns_result (struct GNS_ResolverHandle *rh,
1417                 uint64_t expiration_time,
1418                 uint32_t record_type,
1419                 size_t data_size,
1420                 const void *data)
1421 {
1422   struct DnsResult *res;
1423
1424   res = GNUNET_malloc (sizeof (struct DnsResult) + data_size);
1425   res->expiration_time = expiration_time;
1426   res->data_size = data_size;
1427   res->record_type = record_type;
1428   res->data = &res[1];
1429   memcpy (&res[1], data, data_size);
1430   GNUNET_CONTAINER_DLL_insert (rh->dns_result_head,
1431                                rh->dns_result_tail,
1432                                res);
1433 }
1434
1435
1436 /**
1437  * We had to do a DNS lookup.  Convert the result (if any) and return
1438  * it.
1439  *
1440  * @param cls closure with the 'struct GNS_ResolverHandle'
1441  * @param addr one of the addresses of the host, NULL for the last address
1442  * @param addrlen length of the address
1443  */
1444 static void
1445 handle_dns_result (void *cls,
1446                    const struct sockaddr *addr,
1447                    socklen_t addrlen)
1448 {
1449   struct GNS_ResolverHandle *rh = cls;
1450   const struct sockaddr_in *sa4;
1451   const struct sockaddr_in6 *sa6;
1452
1453   rh->std_resolve = NULL;
1454   if (NULL == addr)
1455   {
1456     transmit_lookup_dns_result (rh);
1457     return;
1458   }
1459   switch (addr->sa_family)
1460   {
1461   case AF_INET:
1462     sa4 = (const struct sockaddr_in *) addr;
1463     add_dns_result (rh,
1464                     0 /* expiration time is unknown */,
1465                     GNUNET_DNSPARSER_TYPE_A,
1466                     sizeof (struct in_addr),
1467                     &sa4->sin_addr);
1468     break;
1469   case AF_INET6:
1470     sa6 = (const struct sockaddr_in6 *) addr;
1471     add_dns_result (rh,
1472                     0 /* expiration time is unknown */,
1473                     GNUNET_DNSPARSER_TYPE_AAAA,
1474                     sizeof (struct in6_addr),
1475                     &sa6->sin6_addr);
1476     break;
1477   default:
1478     GNUNET_break (0);
1479     break;
1480   }
1481 }
1482
1483
1484 /**
1485  * Task scheduled to continue with the resolution process.
1486  *
1487  * @param cls the 'struct GNS_ResolverHandle' of the resolution
1488  * @param tc task context
1489  */
1490 static void
1491 recursive_resolution (void *cls,
1492                       const struct GNUNET_SCHEDULER_TaskContext *tc);
1493
1494
1495 /**
1496  * Function called with the result of a DNS resolution.
1497  *
1498  * @param cls the request handle of the resolution that
1499  *        we were attempting to make
1500  * @param rs socket that received the response
1501  * @param dns dns response, never NULL
1502  * @param dns_len number of bytes in 'dns'
1503  */
1504 static void
1505 dns_result_parser (void *cls,
1506                    struct GNUNET_DNSSTUB_RequestSocket *rs,
1507                    const struct GNUNET_TUN_DnsHeader *dns,
1508                    size_t dns_len)
1509 {
1510   struct GNS_ResolverHandle *rh = cls;
1511   struct GNUNET_DNSPARSER_Packet *p;
1512
1513   rh->dns_request = NULL;
1514   GNUNET_SCHEDULER_cancel (rh->task_id);
1515   rh->task_id = GNUNET_SCHEDULER_NO_TASK;
1516   p = GNUNET_DNSPARSER_parse ((const char *) dns, 
1517                               dns_len);
1518   if (NULL == p)
1519   {
1520     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1521                 _("Failed to parse DNS response\n"));
1522     rh->proc (rh->proc_cls, 0, NULL);
1523     GNS_resolver_lookup_cancel (rh);
1524     return;
1525   }
1526   // FIXME: 
1527   // Check if the packet is the final answer, or
1528   // just pointing us to another NS or another name (CNAME), or another domain (DNAME);
1529   // then do the right thing (TM) -- possibly using "recursive_dns_resolution".
1530   GNUNET_break (0);
1531   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1532               _("NOT IMPLEMENTED\n"));
1533   rh->proc (rh->proc_cls, 0, NULL);
1534   GNS_resolver_lookup_cancel (rh);
1535
1536   
1537   GNUNET_DNSPARSER_free_packet (p);
1538 }
1539
1540
1541 /**
1542  * Perform recursive DNS resolution.  Asks the given DNS resolver to
1543  * resolve "rh->dns_name", possibly recursively proceeding following
1544  * NS delegations, CNAMES, etc., until 'rh->loop_limiter' bounds us or
1545  * we find the answer.
1546  *
1547  * @param rh resolution information
1548  */
1549 static void
1550 recursive_dns_resolution (struct GNS_ResolverHandle *rh)
1551 {
1552   struct AuthorityChain *ac;
1553   socklen_t sa_len;
1554   struct GNUNET_DNSPARSER_Query *query;
1555   struct GNUNET_DNSPARSER_Packet *p;
1556   char *dns_request;
1557   size_t dns_request_length;
1558
1559   ac = rh->ac_tail;
1560   GNUNET_assert (NULL != ac);
1561   GNUNET_assert (GNUNET_NO == ac->gns_authority);
1562   switch (((const struct sockaddr *) &ac->authority_info.dns_authority.dns_ip)->sa_family)
1563   {
1564   case AF_INET:
1565     sa_len = sizeof (struct sockaddr_in);
1566     break;
1567   case AF_INET6:
1568     sa_len = sizeof (struct sockaddr_in6);
1569     break;
1570   default:
1571     GNUNET_break (0);
1572     rh->proc (rh->proc_cls, 0, NULL);
1573     GNS_resolver_lookup_cancel (rh);
1574     return;
1575   }
1576   query = GNUNET_new (struct GNUNET_DNSPARSER_Query);
1577   query->name = GNUNET_strdup (ac->label);
1578   query->type = rh->record_type;
1579   query->class = GNUNET_TUN_DNS_CLASS_INTERNET;
1580   p = GNUNET_new (struct GNUNET_DNSPARSER_Packet);
1581   p->queries = query;
1582   p->num_queries = 1;
1583   p->id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1584                                                UINT16_MAX);
1585   p->flags.opcode = GNUNET_TUN_DNS_OPCODE_QUERY;
1586   p->flags.recursion_desired = 1;
1587   if (GNUNET_OK != 
1588       GNUNET_DNSPARSER_pack (p, 1024, &dns_request, &dns_request_length))
1589   {
1590     GNUNET_break (0);
1591     rh->proc (rh->proc_cls, 0, NULL);
1592     GNS_resolver_lookup_cancel (rh);
1593   }
1594   else
1595   {
1596     rh->dns_request = GNUNET_DNSSTUB_resolve (dns_handle,
1597                                               (const struct sockaddr *) &ac->authority_info.dns_authority.dns_ip,
1598                                               sa_len,
1599                                               dns_request,
1600                                               dns_request_length,
1601                                               &dns_result_parser,
1602                                               rh);
1603     rh->task_id = GNUNET_SCHEDULER_add_delayed (DNS_LOOKUP_TIMEOUT,
1604                                                 &fail_resolution,
1605                                                 rh);
1606   }
1607   GNUNET_free (dns_request);
1608   GNUNET_DNSPARSER_free_packet (p);
1609 }
1610
1611
1612 /**
1613  * We encountered a CNAME record during our resolution.
1614  * Merge it into our chain.
1615  *
1616  * @param rh resolution we are performing
1617  * @param cname value of the cname record we got for the current 
1618  *        authority chain tail
1619  */
1620 static void
1621 handle_gns_cname_result (struct GNS_ResolverHandle *rh,
1622                          const char *cname)
1623 {
1624   // FIXME: not implemented
1625   GNUNET_break (0);
1626   rh->proc (rh->proc_cls, 0, NULL);
1627   GNS_resolver_lookup_cancel (rh);
1628 }
1629
1630
1631 /**
1632  * Process a records that were decrypted from a block.
1633  *
1634  * @param cls closure with the 'struct GNS_ResolverHandle'
1635  * @param rd_count number of entries in @a rd array
1636  * @param rd array of records with data to store
1637  */
1638 static void
1639 handle_gns_resolution_result (void *cls,
1640                               unsigned int rd_count,
1641                               const struct GNUNET_NAMESTORE_RecordData *rd)
1642 {
1643   struct GNS_ResolverHandle *rh = cls;
1644   struct AuthorityChain *ac;
1645   unsigned int i;
1646   unsigned int j;
1647   struct sockaddr *sa;
1648   struct sockaddr_in v4;
1649   struct sockaddr_in6 v6;
1650   size_t sa_len;
1651   char *cname;
1652    
1653   if (0 == rh->name_resolution_pos)
1654   {
1655     /* top-level match, are we done yet? */
1656     if ( (rd_count > 0) &&
1657          (GNUNET_DNSPARSER_TYPE_CNAME == rd[0].record_type) &&
1658          (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type) )
1659     {
1660       cname = GNUNET_strndup (rd[0].data,
1661                               rd[0].data_size);
1662       handle_gns_cname_result (rh, 
1663                                cname);
1664       GNUNET_free (cname);
1665       return;     
1666     }
1667     /* FIXME: if A/AAAA was requested, but we got a VPN
1668        record, we should interact with GNUnet VPN here */
1669     
1670     /* yes, we are done, return result */
1671     rh->proc (rh->proc_cls, rd_count, rd);
1672     GNS_resolver_lookup_cancel (rh);
1673     return;         
1674   }
1675   /* need to recurse, check if we can */
1676   for (i=0;i<rd_count;i++)
1677   {
1678     switch (rd[i].record_type)
1679     {
1680     case GNUNET_NAMESTORE_TYPE_PKEY:
1681       /* delegation to another zone */
1682       if (sizeof (struct GNUNET_CRYPTO_EccPublicKey) !=
1683           rd[i].data_size)
1684       {
1685         GNUNET_break_op (0);
1686         rh->proc (rh->proc_cls, 0, NULL);
1687         GNS_resolver_lookup_cancel (rh);
1688         return;     
1689       }
1690       /* expand authority chain */
1691       ac = GNUNET_new (struct AuthorityChain);
1692       ac->rh = rh;
1693       ac->gns_authority = GNUNET_YES;
1694       memcpy (&ac->authority_info.gns_authority,
1695               rd[i].data,
1696               sizeof (struct GNUNET_CRYPTO_EccPublicKey));
1697       ac->label = resolver_lookup_get_next_label (rh);
1698       GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1699                                         rh->ac_tail,
1700                                         ac);
1701       /* recurse */
1702       rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1703                                               rh);
1704       break;
1705     case GNUNET_DNSPARSER_TYPE_NS:
1706       /* resolution continues within DNS */
1707       if (GNUNET_DNSPARSER_MAX_NAME_LENGTH < rd[i].data_size)
1708       {
1709         GNUNET_break_op (0);
1710         rh->proc (rh->proc_cls, 0, NULL);
1711         GNS_resolver_lookup_cancel (rh);
1712         return;     
1713       }
1714       /* find associated A/AAAA record */
1715       sa = NULL;
1716       for (j=0;j<rd_count;j++)
1717       {
1718         switch (rd[j].record_type)
1719         {
1720         case GNUNET_DNSPARSER_TYPE_A:
1721           if (sizeof (struct in_addr) != rd[i].data_size)
1722           {
1723             GNUNET_break_op (0);
1724             rh->proc (rh->proc_cls, 0, NULL);
1725             GNS_resolver_lookup_cancel (rh);
1726             return;     
1727           }
1728           /* FIXME: might want to check if we support IPv4 here,
1729              and otherwise skip this one and hope we find another */
1730           memset (&v4, 0, sizeof (v4));
1731           sa_len = sizeof (v4);
1732           v4.sin_family = AF_INET;
1733           v4.sin_port = htons (53);
1734 #if HAVE_SOCKADDR_IN_SIN_LEN
1735           v4.sin_len = (u_char) sa_len;
1736 #endif
1737           memcpy (&v4.sin_addr,
1738                   rd[j].data,
1739                   sizeof (struct in_addr));
1740           sa = (struct sockaddr *) &v4;
1741           break;
1742         case GNUNET_DNSPARSER_TYPE_AAAA:
1743           if (sizeof (struct in6_addr) != rd[i].data_size)
1744           {
1745             GNUNET_break_op (0);
1746             rh->proc (rh->proc_cls, 0, NULL);
1747             GNS_resolver_lookup_cancel (rh);
1748             return;     
1749           }
1750           /* FIXME: might want to check if we support IPv6 here,
1751              and otherwise skip this one and hope we find another */
1752           memset (&v6, 0, sizeof (v6));
1753           sa_len = sizeof (v6);
1754           v6.sin6_family = AF_INET6;
1755           v6.sin6_port = htons (53);
1756 #if HAVE_SOCKADDR_IN_SIN_LEN
1757           v6.sin6_len = (u_char) sa_len;
1758 #endif
1759           memcpy (&v6.sin6_addr,
1760                   rd[j].data,
1761                   sizeof (struct in6_addr));
1762           sa = (struct sockaddr *) &v6;
1763           break;
1764         }
1765         if (NULL != sa)
1766           break;
1767       }
1768       /* expand authority chain */
1769       ac = GNUNET_new (struct AuthorityChain);
1770       ac->rh = rh;
1771       strncpy (ac->authority_info.dns_authority.name,
1772                rd[i].data,
1773                rd[i].data_size);
1774       ac->authority_info.dns_authority.name[rd[i].data_size] = '\0';
1775       memcpy (&ac->authority_info.dns_authority.dns_ip,
1776               sa,
1777               sa_len);
1778       /* for DNS recursion, the label is the full DNS name,
1779          created from the remainder of the GNS name and the
1780          name in the NS record */
1781       GNUNET_asprintf (&ac->label,
1782                        "%.*s%s",
1783                        (int) rh->name_resolution_pos,
1784                        rh->name,
1785                        ac->authority_info.dns_authority.name);
1786       GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1787                                         rh->ac_tail,
1788                                         ac);
1789       if (strlen (ac->label) > GNUNET_DNSPARSER_MAX_NAME_LENGTH)
1790       {
1791         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1792                     _("GNS lookup resulted in DNS name that is too long (`%s')\n"),
1793                     ac->label);
1794         rh->proc (rh->proc_cls, 0, NULL);
1795         GNS_resolver_lookup_cancel (rh);
1796         return;
1797       }
1798       /* recurse */
1799       rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1800                                               rh);
1801       return;
1802     case GNUNET_DNSPARSER_TYPE_CNAME:
1803       cname = GNUNET_strndup (rd[i].data,
1804                               rd[i].data_size);
1805       handle_gns_cname_result (rh, 
1806                                cname);
1807       GNUNET_free (cname);
1808       return;
1809       /* FIXME: handle DNAME */
1810     default:
1811       /* skip */
1812       break;
1813     }
1814   }
1815   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1816               _("GNS lookup recursion failed (no delegation record found)\n"));
1817   rh->proc (rh->proc_cls, 0, NULL);
1818   GNS_resolver_lookup_cancel (rh);
1819 }
1820
1821
1822 /**
1823  * Function called once the namestore has completed the request for
1824  * caching a block.
1825  *
1826  * @param cls closure with the 'struct GNS_ResolverHandle'
1827  * @param success #GNUNET_OK on success
1828  * @param emsg error message
1829  */
1830 static void
1831 namestore_cache_continuation (void *cls,
1832                               int32_t success,
1833                               const char *emsg)
1834 {
1835   struct GNS_ResolverHandle *rh = cls;
1836
1837   rh->namestore_qe = NULL;
1838   if (NULL != emsg)
1839     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1840                 _("Failed to cache GNS resolution: %s\n"),
1841                 emsg);
1842 }
1843
1844
1845 /**
1846  * Iterator called on each result obtained for a DHT
1847  * operation that expects a reply
1848  *
1849  * @param cls closure with the 'struct GNS_ResolverHandle'
1850  * @param exp when will this value expire
1851  * @param key key of the result
1852  * @param get_path peers on reply path (or NULL if not recorded)
1853  *                 [0] = datastore's first neighbor, [length - 1] = local peer
1854  * @param get_path_length number of entries in get_path
1855  * @param put_path peers on the PUT path (or NULL if not recorded)
1856  *                 [0] = origin, [length - 1] = datastore
1857  * @param put_path_length number of entries in get_path
1858  * @param type type of the result
1859  * @param size number of bytes in data
1860  * @param data pointer to the result data
1861  */
1862 static void
1863 handle_dht_response (void *cls,
1864                      struct GNUNET_TIME_Absolute exp,
1865                      const struct GNUNET_HashCode * key,
1866                      const struct GNUNET_PeerIdentity *get_path,
1867                      unsigned int get_path_length,
1868                      const struct GNUNET_PeerIdentity *put_path, 
1869                      unsigned int put_path_length,
1870                      enum GNUNET_BLOCK_Type type,
1871                      size_t size, const void *data)
1872 {
1873   struct GNS_ResolverHandle *rh = cls;
1874   struct AuthorityChain *ac = rh->ac_tail;
1875   const struct GNUNET_NAMESTORE_Block *block;
1876   
1877   GNUNET_DHT_get_stop (rh->get_handle);
1878   rh->get_handle = NULL;
1879   GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
1880   rh->dht_heap_node = NULL;  
1881   if (size < sizeof (struct GNUNET_NAMESTORE_Block))
1882   {
1883     /* how did this pass DHT block validation!? */
1884     GNUNET_break (0);
1885     rh->proc (rh->proc_cls, 0, NULL);
1886     GNS_resolver_lookup_cancel (rh);
1887     return;   
1888   }
1889   block = data; 
1890   if (size !=
1891       ntohs (block->purpose.size) + 
1892       sizeof (struct GNUNET_CRYPTO_EccPublicKey) +
1893       sizeof (struct GNUNET_CRYPTO_EccSignature))
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   if (GNUNET_OK !=
1902       GNUNET_NAMESTORE_block_decrypt (block,
1903                                       &ac->authority_info.gns_authority,
1904                                       ac->label,
1905                                       &handle_gns_resolution_result,
1906                                       rh))
1907   {
1908     GNUNET_break_op (0); /* block was ill-formed */
1909     rh->proc (rh->proc_cls, 0, NULL);
1910     GNS_resolver_lookup_cancel (rh);
1911     return;
1912   }
1913   /* Cache well-formed blocks */
1914   rh->namestore_qe = GNUNET_NAMESTORE_block_cache (namestore_handle,
1915                                                    block,
1916                                                    &namestore_cache_continuation,
1917                                                    rh);
1918 }
1919
1920
1921 /**
1922  * Process a record that was stored in the namestore.
1923  *
1924  * @param cls closure with the 'struct GNS_ResolverHandle'
1925  * @param block block that was stored in the namestore
1926  */
1927 static void 
1928 handle_namestore_block_response (void *cls,
1929                                  const struct GNUNET_NAMESTORE_Block *block)
1930 {
1931   struct GNS_ResolverHandle *rh = cls;
1932   struct GNS_ResolverHandle *rx;
1933   struct AuthorityChain *ac = rh->ac_tail;
1934   const char *label = ac->label;
1935   const struct GNUNET_CRYPTO_EccPublicKey *auth = &ac->authority_info.gns_authority;
1936   struct GNUNET_HashCode query;
1937
1938   GNUNET_NAMESTORE_query_from_public_key (auth,
1939                                           label,
1940                                           &query);
1941   rh->namestore_qe = NULL;
1942   if (NULL == block)
1943   {
1944     /* Namestore knows nothing; try DHT lookup */
1945     rh->get_handle = GNUNET_DHT_get_start (dht_handle,
1946                                            GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1947                                            &query,
1948                                            DHT_GNS_REPLICATION_LEVEL,
1949                                            GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
1950                                            NULL, 0,
1951                                            &handle_dht_response, rh);
1952     rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
1953                                                       rh,
1954                                                       GNUNET_TIME_absolute_get ().abs_value_us);
1955     if (GNUNET_CONTAINER_heap_get_size (dht_lookup_heap) > max_allowed_background_queries)
1956     {
1957       /* fail longest-standing DHT request */
1958       rx = GNUNET_CONTAINER_heap_peek (dht_lookup_heap);
1959       rx->proc (rx->proc_cls, 0, NULL);
1960       GNS_resolver_lookup_cancel (rx);
1961     }
1962     return;
1963   }
1964   if (GNUNET_OK !=
1965       GNUNET_NAMESTORE_block_decrypt (block,
1966                                       auth,
1967                                       label,
1968                                       &handle_gns_resolution_result,
1969                                       rh))
1970   {
1971     GNUNET_break_op (0); /* block was ill-formed */
1972     rh->proc (rh->proc_cls, 0, NULL);
1973     GNS_resolver_lookup_cancel (rh);
1974     return;
1975   }
1976 }
1977
1978
1979 /**
1980  * Lookup tail of our authority chain in the namestore.
1981  *
1982  * @param rh query we are processing
1983  */
1984 static void
1985 recursive_gns_resolution_namestore (struct GNS_ResolverHandle *rh)
1986 {
1987   struct AuthorityChain *ac = rh->ac_tail;
1988   struct GNUNET_HashCode query;
1989
1990   GNUNET_NAMESTORE_query_from_public_key (&ac->authority_info.gns_authority,
1991                                           ac->label,
1992                                           &query);
1993   rh->namestore_qe = GNUNET_NAMESTORE_lookup_block (namestore_handle,
1994                                                     &query,
1995                                                     &handle_namestore_block_response,
1996                                                     rh);
1997 }
1998
1999
2000 /**
2001  * Task scheduled to continue with the resolution process.
2002  *
2003  * @param cls the 'struct GNS_ResolverHandle' of the resolution
2004  * @param tc task context
2005  */
2006 static void
2007 recursive_resolution (void *cls,
2008                       const struct GNUNET_SCHEDULER_TaskContext *tc)
2009 {
2010   struct GNS_ResolverHandle *rh = cls;
2011
2012   rh->task_id = GNUNET_SCHEDULER_NO_TASK;
2013   if (MAX_RECURSION < rh->loop_limiter++)
2014   {
2015     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2016                 "Encountered unbounded recursion resolving `%s'\n",
2017                 rh->name);
2018     rh->proc (rh->proc_cls, 0, NULL);
2019     GNS_resolver_lookup_cancel (rh);
2020     return;
2021   }
2022   if (GNUNET_YES == rh->ac_tail->gns_authority)
2023     recursive_gns_resolution_namestore (rh);
2024   else
2025     recursive_dns_resolution (rh);
2026 }
2027
2028
2029 /**
2030  * Lookup of a record in a specific zone calls lookup result processor
2031  * on result.
2032  *
2033  * @param zone the zone to perform the lookup in
2034  * @param record_type the record type to look up
2035  * @param name the name to look up
2036  * @param shorten_key a private key for use with PSEU import (can be NULL)
2037  * @param only_cached GNUNET_NO to only check locally not DHT for performance
2038  * @param proc the processor to call on result
2039  * @param proc_cls the closure to pass to @a proc
2040  * @return handle to cancel operation
2041  */
2042 struct GNS_ResolverHandle *
2043 GNS_resolver_lookup (const struct GNUNET_CRYPTO_EccPublicKey *zone,
2044                      uint32_t record_type,
2045                      const char *name,
2046                      const struct GNUNET_CRYPTO_EccPrivateKey *shorten_key,
2047                      int only_cached,
2048                      GNS_ResultProcessor proc, void *proc_cls)
2049 {
2050   struct GNS_ResolverHandle *rh;
2051   struct AuthorityChain *ac;
2052   char *x;
2053   char *y;
2054   char *pkey;
2055
2056   rh = GNUNET_new (struct GNS_ResolverHandle);
2057   GNUNET_CONTAINER_DLL_insert (rlh_head,
2058                                rlh_tail,
2059                                rh);
2060   rh->authority_zone = *zone;
2061   rh->proc = proc;
2062   rh->proc_cls = proc_cls;
2063   rh->only_cached = only_cached;
2064   rh->record_type = record_type;
2065   rh->name = GNUNET_strdup (name);
2066   rh->name_resolution_pos = strlen (name);
2067   if (NULL != shorten_key)
2068   {
2069     rh->shorten_key = GNUNET_new (struct GNUNET_CRYPTO_EccPrivateKey);
2070     *rh->shorten_key = *shorten_key;
2071   }
2072
2073   if ( ( (GNUNET_YES == is_canonical (name)) &&
2074          (0 != strcmp (GNUNET_GNS_TLD, name)) ) ||
2075        ( (GNUNET_YES != is_gnu_tld (name)) &&
2076          (GNUNET_YES != is_zkey_tld (name)) ) )
2077   {
2078     /* use standard DNS lookup */
2079     int af;
2080
2081     switch (record_type)
2082     {
2083     case GNUNET_DNSPARSER_TYPE_A:
2084       af = AF_INET;
2085       break;
2086     case GNUNET_DNSPARSER_TYPE_AAAA:
2087       af = AF_INET6;
2088       break;
2089     default:
2090       af = AF_UNSPEC;
2091       break;
2092     }
2093     rh->std_resolve = GNUNET_RESOLVER_ip_get (name, 
2094                                               af,
2095                                               DNS_LOOKUP_TIMEOUT,
2096                                               &handle_dns_result,
2097                                               rh);
2098     return rh;
2099   }
2100   if (is_zkey_tld (name))
2101   {
2102     /* Name ends with ".zkey", try to replace authority zone with zkey
2103        authority */
2104     GNUNET_free (resolver_lookup_get_next_label (rh)); /* will return "zkey" */
2105     x = resolver_lookup_get_next_label (rh); /* will return 'x' coordinate */
2106     y = resolver_lookup_get_next_label (rh); /* will return 'y' coordinate */
2107     GNUNET_asprintf (&pkey,
2108                      "%s%s",
2109                      x, y);
2110     if ( (NULL == x) ||
2111          (NULL == y) ||
2112          (GNUNET_OK !=
2113           GNUNET_CRYPTO_ecc_public_key_from_string (pkey,
2114                                                     strlen (pkey),
2115                                                     &rh->authority_zone)) )
2116     {
2117       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2118                   _("Hostname `%s' is not well-formed, resolution fails\n"),
2119                   name);
2120       rh->task_id = GNUNET_SCHEDULER_add_now (&fail_resolution, rh);
2121     }
2122     GNUNET_free_non_null (x);
2123     GNUNET_free_non_null (y);
2124     GNUNET_free (pkey);
2125   }
2126   else
2127   {
2128     /* Name ends with ".gnu", eat ".gnu" and continue with resolution */
2129     GNUNET_free (resolver_lookup_get_next_label (rh));
2130   }
2131   ac = GNUNET_new (struct AuthorityChain);
2132   ac->rh = rh;
2133   ac->label = resolver_lookup_get_next_label (rh);
2134   if (NULL == ac->label)
2135     /* name was just "gnu", so we default to label '+' */
2136     ac->label = GNUNET_strdup (GNUNET_GNS_MASTERZONE_STR);
2137   ac->gns_authority = GNUNET_YES;
2138   ac->authority_info.gns_authority = rh->authority_zone;
2139   GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
2140                                     rh->ac_tail,
2141                                     ac);
2142   rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
2143                                           rh);
2144   return rh;
2145 }
2146
2147
2148 /**
2149  * Cancel active resolution (i.e. client disconnected).
2150  *
2151  * @param rh resolution to abort
2152  */
2153 void
2154 GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
2155 {
2156   struct DnsResult *dr;
2157   struct AuthorityChain *ac;
2158
2159   GNUNET_CONTAINER_DLL_remove (rlh_head,
2160                                rlh_tail,
2161                                rh);
2162   while (NULL != (ac = rh->ac_head))
2163   {
2164     GNUNET_CONTAINER_DLL_remove (rh->ac_head,
2165                                  rh->ac_tail,
2166                                  ac);
2167     GNUNET_free (ac->label);
2168     GNUNET_free (ac);
2169   }
2170   if (GNUNET_SCHEDULER_NO_TASK != rh->task_id)
2171   {
2172     GNUNET_SCHEDULER_cancel (rh->task_id);
2173     rh->task_id = GNUNET_SCHEDULER_NO_TASK;
2174   }
2175   if (NULL != rh->get_handle)
2176   {
2177     GNUNET_DHT_get_stop (rh->get_handle);
2178     rh->get_handle = NULL;
2179   }
2180   if (NULL != rh->dht_heap_node)
2181   {
2182     GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
2183     rh->dht_heap_node = NULL;
2184   }
2185   if (NULL != rh->dns_request)
2186   {
2187     GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
2188     rh->dns_request = NULL;
2189   }
2190   if (NULL != rh->namestore_qe)
2191   {
2192     GNUNET_NAMESTORE_cancel (rh->namestore_qe);
2193     rh->namestore_qe = NULL;
2194   }
2195   if (NULL != rh->std_resolve)
2196   {
2197     GNUNET_RESOLVER_request_cancel (rh->std_resolve);
2198     rh->std_resolve = NULL;
2199   }
2200   while (NULL != (dr = rh->dns_result_head))
2201   {
2202     GNUNET_CONTAINER_DLL_remove (rh->dns_result_head,
2203                                  rh->dns_result_tail,
2204                                  dr);
2205     GNUNET_free (dr);
2206   }
2207   GNUNET_free_non_null (rh->shorten_key);
2208   GNUNET_free (rh->name);
2209   GNUNET_free (rh);
2210 }
2211
2212
2213 /* ***************** Resolver initialization ********************* */
2214
2215
2216 /**
2217  * Initialize the resolver
2218  *
2219  * @param nh the namestore handle
2220  * @param dht the dht handle
2221  * @param c configuration handle
2222  * @param max_bg_queries maximum number of parallel background queries in dht
2223  */
2224 void
2225 GNS_resolver_init (struct GNUNET_NAMESTORE_Handle *nh,
2226                    struct GNUNET_DHT_Handle *dht,
2227                    const struct GNUNET_CONFIGURATION_Handle *c,
2228                    unsigned long long max_bg_queries)
2229 {
2230   char *dns_ip;
2231
2232   cfg = c;
2233   namestore_handle = nh;
2234   dht_handle = dht;
2235   dht_lookup_heap =
2236     GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
2237   max_allowed_background_queries = max_bg_queries;
2238   if (GNUNET_OK !=
2239       GNUNET_CONFIGURATION_get_value_string (c,
2240                                              "gns",
2241                                              "DNS_RESOLVER",
2242                                              &dns_ip))
2243   {
2244     /* user did not specify DNS resolver, use 8.8.8.8 */
2245     dns_ip = GNUNET_strdup ("8.8.8.8");
2246   }
2247   dns_handle = GNUNET_DNSSTUB_start (dns_ip);
2248   GNUNET_free (dns_ip);
2249 }
2250
2251
2252 /**
2253  * Shutdown resolver
2254  */
2255 void
2256 GNS_resolver_done ()
2257 {
2258   struct GNS_ResolverHandle *rh;
2259
2260   /* abort active resolutions */
2261   while (NULL != (rh = rlh_head))
2262   {
2263     rh->proc (rh->proc_cls, 0, NULL);
2264     GNS_resolver_lookup_cancel (rh);    
2265   }
2266   /* abort active shorten operations */
2267   while (NULL != gph_head)
2268     free_get_pseu_authority_handle (gph_head);
2269   GNUNET_CONTAINER_heap_destroy (dht_lookup_heap);
2270   dht_lookup_heap = NULL;
2271   GNUNET_DNSSTUB_stop (dns_handle);
2272   dns_handle = NULL;
2273 }
2274
2275
2276 /* *************** common helper functions (do not really belong here) *********** */
2277
2278 /**
2279  * Checks if "name" ends in ".tld"
2280  *
2281  * @param name the name to check
2282  * @param tld the TLD to check for
2283  * @return GNUNET_YES or GNUNET_NO
2284  */
2285 int
2286 is_tld (const char* name, const char* tld)
2287 {
2288   size_t offset = 0;
2289
2290   if (strlen (name) <= strlen (tld))
2291     return GNUNET_NO;
2292   offset = strlen (name) - strlen (tld);
2293   if (0 != strcmp (name + offset, tld))
2294     return GNUNET_NO;
2295   return GNUNET_YES;
2296 }
2297
2298
2299 /* end of gnunet-service-gns_resolver.c */