bbeea86f40bf2f44153c142bf8796a69305ea401
[oweals/gnunet.git] / src / gns / gnunet-service-gns_resolver.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010, 2011 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  *
23  *
24  * @file gns/gnunet-service-gns_resolver.c
25  * @brief GNUnet GNS resolver logic
26  * @author Martin Schanzenbach
27  */
28 #include "platform.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_transport_service.h"
31 #include "gnunet_dns_service.h"
32 #include "gnunet_dht_service.h"
33 #include "gnunet_namestore_service.h"
34 #include "gnunet_vpn_service.h"
35 #include "gnunet_dns_service.h"
36 #include "gnunet_resolver_service.h"
37 #include "gnunet_dnsparser_lib.h"
38 #include "gnunet_gns_service.h"
39 #include "block_gns.h"
40 #include "gns.h"
41 #include "gnunet-service-gns_resolver.h"
42
43 #define DHT_LOOKUP_TIMEOUT DHT_OPERATION_TIMEOUT
44 #define DHT_GNS_REPLICATION_LEVEL 5
45 #define MAX_DNS_LABEL_LENGTH 63
46
47
48 /**
49  * Our handle to the namestore service
50  */
51 static struct GNUNET_NAMESTORE_Handle *namestore_handle;
52
53 /**
54  * Our handle to the vpn service
55  */
56 static struct GNUNET_VPN_Handle *vpn_handle;
57
58 /**
59  * Resolver handle to the dht
60  */
61 static struct GNUNET_DHT_Handle *dht_handle;
62
63 /**
64  * Heap for parallel DHT lookups
65  */
66 static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
67
68 /**
69  * Maximum amount of parallel queries in background
70  */
71 static unsigned long long max_allowed_background_queries;
72
73 /**
74  * Wheather or not to ignore pending records
75  */
76 static int ignore_pending_records;
77
78 /**
79  * Our local zone
80  */
81 static struct GNUNET_CRYPTO_ShortHashCode local_zone;
82
83 /**
84  * Background shortening handles
85  */
86 static struct GetPseuAuthorityHandle *gph_head;
87
88 /**
89  * Background shortening handles
90  */
91 static struct GetPseuAuthorityHandle *gph_tail;
92
93 /**
94  * a resolution identifier pool variable
95  * FIXME overflow?
96  * This is a non critical identifier useful for debugging
97  */
98 static unsigned long long rid = 0;
99
100 static int
101 is_srv (char* name)
102 {
103   char* ndup;
104   int ret = 1;
105
106   if (*name != '_')
107     return 0;
108   if (NULL == strstr (name, "._"))
109     return 0;
110
111   ndup = GNUNET_strdup (name);
112   strtok (ndup, ".");
113
114   if (NULL == strtok (NULL, "."))
115     ret = 0;
116
117   if (NULL == strtok (NULL, "."))
118     ret = 0;
119
120   if (NULL != strtok (NULL, "."))
121     ret = 0;
122
123   return ret;
124 }
125
126 /**
127  * Determine if this name is canonical.
128  * i.e.
129  * a.b.gnunet  = not canonical
130  * a           = canonical
131  *
132  * @param name the name to test
133  * @return 1 if canonical
134  */
135 static int
136 is_canonical(char* name)
137 {
138   char* ndup;
139   char* tok;
140
141   ndup = GNUNET_strdup (name);
142   tok = strtok (ndup, ".");
143
144   for (tok = strtok (NULL, "."); tok != NULL; tok = strtok (NULL, "."))
145   {
146     /*
147      * probably srv
148      */
149     if (*tok == '_')
150       continue;
151     GNUNET_free (ndup);
152     return 0;
153   }
154   GNUNET_free (ndup);
155   return 1;
156 }
157
158
159 /**
160  * Callback that shortens authorities
161  *
162  * @param gph the handle containing the name to shorten
163  */
164 static void
165 shorten_authority_chain (struct GetPseuAuthorityHandle *gph);
166
167
168 /**
169  * Namestore calls this function if we have record for this name.
170  * (or with rd_count=0 to indicate no matches)
171  *
172  * @param cls the pending query
173  * @param key the key of the zone we did the lookup
174  * @param expiration expiration date of the namestore entry
175  * @param name the name for which we need an authority
176  * @param rd_count the number of records with 'name'
177  * @param rd the record data
178  * @param signature the signature of the authority for the record data
179  */
180 static void
181 process_pseu_lookup_ns (void* cls,
182                       const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
183                       struct GNUNET_TIME_Absolute expiration,
184                       const char *name, unsigned int rd_count,
185                       const struct GNUNET_NAMESTORE_RecordData *rd,
186                       const struct GNUNET_CRYPTO_RsaSignature *signature)
187 {
188   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
189   struct GNUNET_NAMESTORE_RecordData new_pkey;
190   struct AuthorityChain *iter;
191
192   if (rd_count > 0)
193   {
194     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
195                "GNS_AUTO_PSEU: Name %s already taken in NS!\n", name);
196     if (0 == strcmp (gph->name, name))
197     {
198       if (gph->ahead->next != NULL)
199       {
200         if (GNUNET_CRYPTO_short_hash_cmp (&gph->ahead->next->zone,
201                                           &gph->our_zone))
202         {
203           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNS_GET_AUTH: trying next!\n");
204           iter = gph->ahead->next;
205           GNUNET_free (gph->ahead);
206           gph->ahead = iter;
207           shorten_authority_chain (gph);
208           return;
209         }
210       }
211
212       /* Clean up */
213       do
214       {
215         iter = gph->ahead->next;
216         GNUNET_free (gph->ahead);
217         gph->ahead = iter;
218       } while (iter != NULL);
219       GNUNET_CRYPTO_rsa_key_free (gph->key);
220       GNUNET_CONTAINER_DLL_remove (gph_head, gph_tail, gph);
221       GNUNET_free (gph);
222       return;
223     }
224
225     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
226                 "GNS_AUTO_PSEU: Trying delegated name %s\n", gph->name);
227     memcpy (gph->test_name, gph->name, strlen (gph->name)+1);
228     GNUNET_NAMESTORE_lookup_record (namestore_handle,
229                                     &gph->our_zone,
230                                     gph->test_name,
231                                     GNUNET_NAMESTORE_TYPE_ANY,
232                                     &process_pseu_lookup_ns,
233                                     gph);
234     return;
235   }
236
237   /* name is free */
238   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
239             "GNS_AUTO_PSEU: Name %s not taken in NS! Adding\n", gph->test_name);
240
241   new_pkey.expiration_time = UINT64_MAX;
242   new_pkey.data_size = sizeof (struct GNUNET_CRYPTO_ShortHashCode);
243   new_pkey.data = &gph->ahead->zone;
244   new_pkey.record_type = GNUNET_GNS_RECORD_PKEY;
245   new_pkey.flags = GNUNET_NAMESTORE_RF_AUTHORITY
246                  | GNUNET_NAMESTORE_RF_PRIVATE
247                  | GNUNET_NAMESTORE_RF_PENDING;
248   GNUNET_NAMESTORE_record_create (namestore_handle,
249                                   gph->key,
250                                   gph->test_name,
251                                   &new_pkey,
252                                   NULL, //cont
253                                   NULL); //cls
254   do
255   {
256     iter = gph->ahead->next;
257     GNUNET_free (gph->ahead);
258     gph->ahead = iter;
259   } while (iter != NULL);
260   GNUNET_CRYPTO_rsa_key_free (gph->key);
261   GNUNET_CONTAINER_DLL_remove (gph_head, gph_tail, gph);
262   GNUNET_free (gph);
263
264 }
265
266 /**
267  * process result of a dht pseu lookup
268  *
269  * @param gph the handle
270  * @param name the pseu result or NULL
271  */
272 static void
273 process_pseu_result (struct GetPseuAuthorityHandle* gph, char* name)
274 {
275   if (NULL == name)
276   {
277     memcpy (gph->test_name, gph->ahead->name, strlen (gph->ahead->name)+1);
278   }
279   else
280   {
281     memcpy (gph->test_name, name, strlen(name)+1);
282   }
283
284   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
285               "GNS_AUTO_PSEU: Checking %s for collision in NS\n",
286               gph->test_name);
287
288   /**
289    * Check for collision
290    */
291   GNUNET_NAMESTORE_lookup_record (namestore_handle,
292                                   &gph->our_zone,
293                                   gph->test_name,
294                                   GNUNET_NAMESTORE_TYPE_ANY,
295                                   &process_pseu_lookup_ns,
296                                   gph);
297 }
298
299 /**
300  * Handle timeout for dht request
301  *
302  * @param cls the request handle as closure
303  * @param tc the task context
304  */
305 static void
306 handle_auth_discovery_timeout(void *cls,
307                               const struct GNUNET_SCHEDULER_TaskContext *tc)
308 {
309   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
310   struct AuthorityChain *iter;
311
312   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
313               "GNS_GET_AUTH: dht lookup for query PSEU timed out.\n");
314   GNUNET_DHT_get_stop (gph->get_handle);
315   gph->get_handle = NULL;
316   
317   if (gph->ahead->next != NULL)
318   {
319     if (GNUNET_CRYPTO_short_hash_cmp (&gph->ahead->next->zone,
320                                       &gph->our_zone))
321     {
322       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNS_GET_AUTH: trying next!\n");
323       iter = gph->ahead->next;
324       GNUNET_free (gph->ahead);
325       gph->ahead = iter;
326       shorten_authority_chain (gph);
327       return;
328     }
329   }
330   
331   process_pseu_result (gph, NULL);
332 }
333
334 /**
335  * Function called when we find a PSEU entry in the DHT
336  *
337  * @param cls the request handle
338  * @param exp lifetime
339  * @param key the key the record was stored under
340  * @param get_path get path
341  * @param get_path_length get path length
342  * @param put_path put path
343  * @param put_path_length put path length
344  * @param type the block type
345  * @param size the size of the record
346  * @param data the record data
347  */
348 static void
349 process_auth_discovery_dht_result(void* cls,
350                                   struct GNUNET_TIME_Absolute exp,
351                                   const struct GNUNET_HashCode * key,
352                                   const struct GNUNET_PeerIdentity *get_path,
353                                   unsigned int get_path_length,
354                                   const struct GNUNET_PeerIdentity *put_path,
355                                   unsigned int put_path_length,
356                                   enum GNUNET_BLOCK_Type type,
357                                   size_t size, const void *data)
358 {
359   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
360   struct AuthorityChain *iter;
361   struct GNSNameRecordBlock *nrb;
362   char* rd_data = (char*)data;
363   char* name;
364   int num_records;
365   size_t rd_size;
366   int i;
367
368   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
369               "GNS_GET_AUTH: got dht result (size=%d)\n", size);
370
371   
372   /* stop lookup and timeout task */
373   GNUNET_DHT_get_stop (gph->get_handle);
374   gph->get_handle = NULL;
375   GNUNET_SCHEDULER_cancel (gph->timeout);
376   
377   if (data == NULL)
378   {
379     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
380                 "GNS_GET_AUTH: got dht result null!\n", size);
381     
382     do
383     {
384       iter = gph->ahead->next;
385       GNUNET_free (gph->ahead);
386       gph->ahead = iter;
387     } while (iter != NULL);
388     GNUNET_CRYPTO_rsa_key_free (gph->key);
389     GNUNET_CONTAINER_DLL_remove (gph_head, gph_tail, gph);
390     GNUNET_free (gph);
391     return;
392   }
393   
394   nrb = (struct GNSNameRecordBlock*)data;
395
396
397
398   nrb = (struct GNSNameRecordBlock*)data;
399   
400   name = (char*)&nrb[1];
401   num_records = ntohl (nrb->rd_count);
402   {
403     struct GNUNET_NAMESTORE_RecordData rd[num_records];
404
405     rd_data += strlen (name) + 1 + sizeof (struct GNSNameRecordBlock);
406     rd_size = size - strlen (name) - 1 - sizeof (struct GNSNameRecordBlock);
407
408     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
409                                                                rd_data,
410                                                                num_records,
411                                                                rd))
412     {
413       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
414                   "GNS_GET_AUTH: Error deserializing data!\n");
415     }
416     else
417     {
418       for (i=0; i < num_records; i++)
419       {
420         if ((strcmp (name, "+") == 0) &&
421             (rd[i].record_type == GNUNET_GNS_RECORD_PSEU))
422         {
423           /* found pseu */
424           process_pseu_result (gph, (char*)rd[i].data);
425           return;
426         }
427       }
428     }
429   }
430
431   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNS_GET_AUTH: no pseu in dht!\n");
432
433   if (gph->ahead->next != NULL)
434   {
435     if (GNUNET_CRYPTO_short_hash_cmp (&gph->ahead->next->zone,
436                                       &gph->our_zone))
437     {
438       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNS_GET_AUTH: trying next!\n");
439       iter = gph->ahead->next;
440       GNUNET_free (gph->ahead);
441       gph->ahead = iter;
442       shorten_authority_chain (gph);
443       return;
444     }
445   }
446   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
447               "GNS_GET_AUTH: finished shorten, no results!\n");
448   process_pseu_result (gph, NULL);
449 }
450
451 /**
452  * Process PSEU discovery for shorten via namestore
453  *
454  * @param cls the GetPseuAuthorityHandle
455  * @param key the public key
456  * @param expiration recorddata expiration
457  * @param name the looked up name
458  * @param rd_count number of records in set
459  * @param rd record data
460  * @param signature the signature
461  */
462 static void
463 process_auth_discovery_ns_result(void* cls,
464                       const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
465                       struct GNUNET_TIME_Absolute expiration,
466                       const char *name,
467                       unsigned int rd_count,
468                       const struct GNUNET_NAMESTORE_RecordData *rd,
469                       const struct GNUNET_CRYPTO_RsaSignature *signature)
470 {
471   uint32_t xquery;
472   struct GNUNET_CRYPTO_ShortHashCode name_hash;
473   struct GNUNET_HashCode lookup_key;
474   struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
475   struct GNUNET_HashCode name_hash_double;
476   struct GNUNET_HashCode zone_hash_double;
477   int i;
478   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
479   struct AuthorityChain *iter;
480   
481   /* no pseu found */
482   if (rd_count == 0)
483   {
484     /**
485      * check dht
486      */
487     GNUNET_CRYPTO_short_hash ("+", strlen ("+"), &name_hash);
488     GNUNET_CRYPTO_short_hash_double (&name_hash, &name_hash_double);
489     GNUNET_CRYPTO_short_hash_double (&gph->ahead->zone, &zone_hash_double);
490     GNUNET_CRYPTO_hash_xor (&name_hash_double, &zone_hash_double, &lookup_key);
491     GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
492
493     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
494                "GNS_AUTO_PSEU: starting dht lookup for %s with key: %s\n",
495                "+", (char*)&lookup_key_string);
496
497     gph->timeout = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
498                                          &handle_auth_discovery_timeout, gph);
499
500     xquery = htonl (GNUNET_GNS_RECORD_PSEU);
501     
502     GNUNET_assert (gph->get_handle == NULL);
503
504     gph->get_handle = GNUNET_DHT_get_start(dht_handle,
505                                            GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
506                                            &lookup_key,
507                                            DHT_GNS_REPLICATION_LEVEL,
508                                            GNUNET_DHT_RO_NONE,
509                                            &xquery,
510                                            sizeof(xquery),
511                                            &process_auth_discovery_dht_result,
512                                            gph);
513     return;
514   }
515
516   for (i=0; i < rd_count; i++)
517   {
518     if ((strcmp (name, "+") == 0) &&
519         (rd[i].record_type == GNUNET_GNS_RECORD_PSEU))
520     {
521       /* found pseu */
522       process_pseu_result (gph, (char*)rd[i].data);
523       return;
524     }
525   }
526
527   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNS_GET_AUTH: no pseu in namestore!\n");
528   
529   if (gph->ahead->next != NULL)
530   {
531     if (GNUNET_CRYPTO_short_hash_cmp (&gph->ahead->next->zone,
532                                       &gph->our_zone))
533     {
534       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNS_GET_AUTH: trying next!\n");
535       iter = gph->ahead->next;
536       GNUNET_free (gph->ahead);
537       gph->ahead = iter;
538       shorten_authority_chain (gph);
539       return;
540     }
541   }
542   
543   process_pseu_result (gph, NULL);
544 }
545
546 /**
547  * Callback called by namestore for a zone to name
548  * result
549  *
550  * @param cls the closure
551  * @param zone_key the zone we queried
552  * @param expire the expiration time of the name
553  * @param name the name found or NULL
554  * @param rd_len number of records for the name
555  * @param rd the record data (PKEY) for the name
556  * @param signature the signature for the record data
557  */
558 static void
559 process_zone_to_name_discover (void *cls,
560                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
561                  struct GNUNET_TIME_Absolute expire,
562                  const char *name,
563                  unsigned int rd_len,
564                  const struct GNUNET_NAMESTORE_RecordData *rd,
565                  const struct GNUNET_CRYPTO_RsaSignature *signature)
566 {
567   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
568   struct AuthorityChain *iter;
569
570   /* we found a match in our own zone */
571   if (rd_len != 0)
572   {
573     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
574                "GNS_AUTO_PSEU: name for zone in our root %s\n", name);
575
576     iter = gph->ahead;
577     do
578     {
579       iter = gph->ahead->next;
580       GNUNET_free (gph->ahead);
581       gph->ahead = iter;
582     } while (iter != NULL);
583     GNUNET_CRYPTO_rsa_key_free (gph->key);
584     GNUNET_CONTAINER_DLL_remove (gph_head, gph_tail, gph);
585     GNUNET_free (gph);
586   }
587   else
588   {
589
590     GNUNET_NAMESTORE_lookup_record (namestore_handle,
591                                     &gph->ahead->zone,
592                                     "+",
593                                     GNUNET_GNS_RECORD_PSEU,
594                                     &process_auth_discovery_ns_result,
595                                     gph);
596   }
597
598 }
599
600
601 /**
602  * Callback that shortens authorities
603  *
604  * @param gph the handle to the shorten request
605  */
606 static void
607 shorten_authority_chain (struct GetPseuAuthorityHandle *gph)
608 {
609
610   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
611               "GNS_AUTO_PSEU: New authority %s discovered\n",
612               gph->ahead->name);
613
614   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
615                                  &gph->our_zone,
616                                  &gph->ahead->zone,
617                                  &process_zone_to_name_discover,
618                                  gph);
619
620 }
621
622 static void
623 start_shorten (struct AuthorityChain *atail,
624                struct GNUNET_CRYPTO_RsaPrivateKey *key)
625 {
626   struct AuthorityChain *new_head = NULL;
627   struct AuthorityChain *new_tail = NULL;
628   struct AuthorityChain *iter;
629   struct AuthorityChain *acopy;
630   struct GetPseuAuthorityHandle *gph;
631   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
632   struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *pb_key;
633
634   /* First copy the authority chain in reverse order */
635   for (iter = atail; iter != NULL; iter = iter->prev)
636   {
637     acopy = GNUNET_malloc (sizeof (struct AuthorityChain));
638     memcpy (acopy, iter, sizeof (struct AuthorityChain));
639     acopy->next = NULL;
640     acopy->prev = NULL;
641     GNUNET_CONTAINER_DLL_insert (new_head, new_tail, acopy);
642   }
643
644   gph = GNUNET_malloc (sizeof (struct GetPseuAuthorityHandle));
645
646   GNUNET_CRYPTO_rsa_key_get_public (key, &pkey);
647   pb_key = GNUNET_CRYPTO_rsa_encode_key (key);
648   gph->key = GNUNET_CRYPTO_rsa_decode_key ((char*)pb_key, ntohs (pb_key->len));
649   //gph->key = key;//GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPrivateKey));
650   //memcpy (gph->key, key, sizeof (struct GNUNET_CRYPTO_RsaPrivateKey));
651   
652   GNUNET_CRYPTO_short_hash (&pkey,
653                         sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
654                         &gph->our_zone);
655   gph->ahead = new_head;
656
657   GNUNET_CONTAINER_DLL_insert (gph_head, gph_tail, gph);
658
659   shorten_authority_chain (gph);
660 }
661
662 /**
663  * Initialize the resolver
664  *
665  * @param nh the namestore handle
666  * @param dh the dht handle
667  * @param lz the local zone's hash
668  * @param cfg configuration handle
669  * @param max_bg_queries maximum number of parallel background queries in dht
670  * @param ignore_pending ignore records that still require user confirmation
671  *        on lookup
672  * @return GNUNET_OK on success
673  */
674 int
675 gns_resolver_init(struct GNUNET_NAMESTORE_Handle *nh,
676                   struct GNUNET_DHT_Handle *dh,
677                   struct GNUNET_CRYPTO_ShortHashCode lz,
678                   const struct GNUNET_CONFIGURATION_Handle *cfg,
679                   unsigned long long max_bg_queries,
680                   int ignore_pending)
681 {
682   namestore_handle = nh;
683   dht_handle = dh;
684   local_zone = lz;
685   dht_lookup_heap =
686     GNUNET_CONTAINER_heap_create(GNUNET_CONTAINER_HEAP_ORDER_MIN);
687   max_allowed_background_queries = max_bg_queries;
688   ignore_pending_records = ignore_pending;
689
690   gph_head = NULL;
691   gph_tail = NULL;
692
693   GNUNET_RESOLVER_connect (cfg);
694   
695   if (NULL == vpn_handle)
696   {
697     vpn_handle = GNUNET_VPN_connect (cfg);
698     if (NULL == vpn_handle)
699     {
700       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
701                   "GNS_PHASE_INIT: Error connecting to VPN!\n");
702
703       return GNUNET_SYSERR;
704     }
705   }
706
707   if ((namestore_handle != NULL) && (dht_handle != NULL))
708   {
709     return GNUNET_OK;
710   }
711
712   return GNUNET_SYSERR;
713 }
714
715 /**
716  * Cleanup background lookups
717  *
718  * @param cls closure to iterator
719  * @param node heap nodes
720  * @param element the resolver handle
721  * @param cost heap cost
722  * @return always GNUNET_YES
723  */
724 static int
725 cleanup_pending_background_queries(void* cls,
726                                    struct GNUNET_CONTAINER_HeapNode *node,
727                                    void *element,
728                                    GNUNET_CONTAINER_HeapCostType cost)
729 {
730   struct ResolverHandle *rh = (struct ResolverHandle *)element;
731   ResolverCleanupContinuation cont = cls;
732
733   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
734              "GNS_CLEANUP-%llu: Terminating background lookup for %s\n",
735              rh->id, rh->name);
736   GNUNET_DHT_get_stop(rh->get_handle);
737   rh->get_handle = NULL;
738   rh->proc(rh->proc_cls, rh, 0, NULL);
739
740   GNUNET_CONTAINER_heap_remove_node(node);
741
742   if (GNUNET_CONTAINER_heap_get_size(dht_lookup_heap) == 0)
743     cont();
744
745
746   return GNUNET_YES;
747 }
748
749
750 /**
751  * Shutdown resolver
752  */
753 void
754 gns_resolver_cleanup(ResolverCleanupContinuation cont)
755 {
756   unsigned int s = GNUNET_CONTAINER_heap_get_size(dht_lookup_heap);
757   struct GetPseuAuthorityHandle *tmp;
758   struct AuthorityChain *iter;
759
760   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
761              "GNS_CLEANUP: %d pending background queries to terminate\n", s);
762   
763   tmp = gph_head;
764   for (tmp = gph_head; tmp != NULL; tmp = gph_head)
765   {
766     if (tmp->get_handle != NULL)
767       GNUNET_DHT_get_stop (tmp->get_handle);
768     tmp->get_handle = NULL;
769     if (tmp->timeout != GNUNET_SCHEDULER_NO_TASK)
770       GNUNET_SCHEDULER_cancel (tmp->timeout);
771     tmp->timeout = GNUNET_SCHEDULER_NO_TASK;
772     
773     iter = tmp->ahead;
774     do
775     {
776       iter = tmp->ahead->next;
777       GNUNET_free (tmp->ahead);
778       tmp->ahead = iter;
779     } while (iter != NULL);
780     
781     GNUNET_CRYPTO_rsa_key_free (tmp->key);
782     GNUNET_CONTAINER_DLL_remove (gph_head, gph_tail, tmp);
783     GNUNET_free (tmp);
784   }
785   
786   
787   if (0 != s)
788     GNUNET_CONTAINER_heap_iterate (dht_lookup_heap,
789                                    &cleanup_pending_background_queries,
790                                    cont);
791   else
792     cont();
793 }
794
795
796 /**
797  * Helper function to free resolver handle
798  *
799  * @param rh the handle to free
800  */
801 static void
802 free_resolver_handle(struct ResolverHandle* rh)
803 {
804   struct AuthorityChain *ac;
805   struct AuthorityChain *ac_next;
806
807   if (NULL == rh)
808     return;
809
810   ac = rh->authority_chain_head;
811
812   while (NULL != ac)
813   {
814     ac_next = ac->next;
815     GNUNET_free(ac);
816     ac = ac_next;
817   }
818
819   if (NULL != rh->dns_raw_packet)
820     GNUNET_free (rh->dns_raw_packet);
821
822   GNUNET_free(rh);
823 }
824
825
826 /**
827  * Callback when record data is put into namestore
828  *
829  * @param cls the closure
830  * @param success GNUNET_OK on success
831  * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
832  */
833 void
834 on_namestore_record_put_result(void *cls,
835                                int32_t success,
836                                const char *emsg)
837 {
838   if (GNUNET_NO == success)
839   {
840     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
841                "GNS_NS: records already in namestore\n");
842     return;
843   }
844   else if (GNUNET_YES == success)
845   {
846     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
847                "GNS_NS: records successfully put in namestore\n");
848     return;
849   }
850
851   GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
852              "GNS_NS: Error putting records into namestore: %s\n", emsg);
853 }
854
855 static void
856 handle_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
857 {
858   struct ResolverHandle *rh = cls;
859
860   if (rh->timeout_cont)
861     rh->timeout_cont(rh->timeout_cont_cls, tc);
862 }
863
864 /**
865  * Processor for background lookups in the DHT
866  *
867  * @param cls closure (NULL)
868  * @param rd_count number of records found (not 0)
869  * @param rd record data
870  */
871 static void
872 background_lookup_result_processor(void *cls,
873                                    uint32_t rd_count,
874                                    const struct GNUNET_NAMESTORE_RecordData *rd)
875 {
876   //We could do sth verbose/more useful here but it doesn't make any difference
877   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
878              "GNS_BG: background dht lookup finished. (%d results)\n",
879              rd_count);
880 }
881
882 /**
883  * Handle timeout for DHT requests
884  *
885  * @param cls the request handle as closure
886  * @param tc the task context
887  */
888 static void
889 dht_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
890 {
891   struct ResolverHandle *rh = cls;
892   struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
893   char new_name[MAX_DNS_NAME_LENGTH];
894
895   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
896              "GNS_PHASE_REC-%d: dht lookup for query %s (%ds)timed out.\n",
897              rh->id, rh->name, rh->timeout.rel_value);
898   /**
899    * Start resolution in bg
900    */
901   //strcpy(new_name, rh->name);
902   //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD));
903   GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
904                   rh->name, GNUNET_GNS_TLD);
905
906   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
907              "GNS_PHASE_REC-%d: Starting background lookup for %s type %d\n",
908              rh->id, new_name, rlh->record_type);
909
910   gns_resolver_lookup_record(rh->authority,
911                              rh->private_local_zone,
912                              rlh->record_type,
913                              new_name,
914                              rh->priv_key,
915                              GNUNET_TIME_UNIT_FOREVER_REL,
916                              GNUNET_NO,
917                              &background_lookup_result_processor,
918                              NULL);
919   rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
920
921   GNUNET_DHT_get_stop (rh->get_handle);
922   rh->get_handle = NULL;
923   rh->proc(rh->proc_cls, rh, 0, NULL);
924 }
925
926
927 /**
928  * Function called when we get a result from the dht
929  * for our record query
930  *
931  * @param cls the request handle
932  * @param exp lifetime
933  * @param key the key the record was stored under
934  * @param get_path get path
935  * @param get_path_length get path length
936  * @param put_path put path
937  * @param put_path_length put path length
938  * @param type the block type
939  * @param size the size of the record
940  * @param data the record data
941  */
942 static void
943 process_record_result_dht(void* cls,
944                           struct GNUNET_TIME_Absolute exp,
945                           const struct GNUNET_HashCode * key,
946                           const struct GNUNET_PeerIdentity *get_path,
947                           unsigned int get_path_length,
948                           const struct GNUNET_PeerIdentity *put_path,
949                           unsigned int put_path_length,
950                           enum GNUNET_BLOCK_Type type,
951                           size_t size, const void *data)
952 {
953   struct ResolverHandle *rh;
954   struct RecordLookupHandle *rlh;
955   struct GNSNameRecordBlock *nrb;
956   uint32_t num_records;
957   char* name = NULL;
958   char* rd_data = (char*)data;
959   int i;
960   int rd_size;
961
962   rh = (struct ResolverHandle *)cls;
963   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
964              "GNS_PHASE_REC-%d: got dht result (size=%d)\n", rh->id, size);
965
966   //FIXME maybe check expiration here, check block type
967
968
969   rlh = (struct RecordLookupHandle *) rh->proc_cls;
970   nrb = (struct GNSNameRecordBlock*)data;
971
972   /* stop lookup and timeout task */
973   GNUNET_DHT_get_stop (rh->get_handle);
974   rh->get_handle = NULL;
975
976   if (rh->dht_heap_node != NULL)
977   {
978     GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
979     rh->dht_heap_node = NULL;
980   }
981
982   if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
983   {
984     GNUNET_SCHEDULER_cancel(rh->timeout_task);
985     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
986   }
987
988   rh->get_handle = NULL;
989   name = (char*)&nrb[1];
990   num_records = ntohl(nrb->rd_count);
991   {
992     struct GNUNET_NAMESTORE_RecordData rd[num_records];
993
994     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
995     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
996
997     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
998                                                                rd_data,
999                                                                num_records,
1000                                                                rd))
1001     {
1002       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1003                  "GNS_PHASE_REC-%d: Error deserializing data!\n", rh->id);
1004       return;
1005     }
1006
1007     for (i=0; i<num_records; i++)
1008     {
1009       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1010                  "GNS_PHASE_REC-%d: Got name: %s (wanted %s)\n",
1011                  rh->id, name, rh->name);
1012       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1013                  "GNS_PHASE_REC-%d: Got type: %d (wanted %d)\n",
1014                  rh->id, rd[i].record_type, rlh->record_type);
1015       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1016                  "GNS_PHASE_REC-%d: Got data length: %d\n",
1017                  rh->id, rd[i].data_size);
1018       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1019                  "GNS_PHASE_REC-%d: Got flag %d\n",
1020                  rh->id, rd[i].flags);
1021
1022       if ((strcmp(name, rh->name) == 0) &&
1023           (rd[i].record_type == rlh->record_type))
1024       {
1025         rh->answered++;
1026       }
1027
1028     }
1029
1030     /**
1031      * FIXME check pubkey against existing key in namestore?
1032      * https://gnunet.org/bugs/view.php?id=2179
1033      */
1034
1035     /* Save to namestore */
1036     GNUNET_NAMESTORE_record_put (namestore_handle,
1037                                  &nrb->public_key,
1038                                  name,
1039                                  exp,
1040                                  num_records,
1041                                  rd,
1042                                  &nrb->signature,
1043                                  &on_namestore_record_put_result, //cont
1044                                  NULL); //cls
1045
1046
1047     if (rh->answered)
1048       rh->proc(rh->proc_cls, rh, num_records, rd);
1049     else
1050       rh->proc(rh->proc_cls, rh, 0, NULL);
1051   }
1052
1053 }
1054
1055
1056 /**
1057  * Start DHT lookup for a (name -> query->record_type) record in
1058  * rh->authority's zone
1059  *
1060  * @param rh the pending gns query context
1061  */
1062 static void
1063 resolve_record_dht (struct ResolverHandle *rh)
1064 {
1065   uint32_t xquery;
1066   struct GNUNET_CRYPTO_ShortHashCode name_hash;
1067   struct GNUNET_HashCode lookup_key;
1068   struct GNUNET_HashCode name_hash_double;
1069   struct GNUNET_HashCode zone_hash_double;
1070   struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
1071   struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
1072   struct ResolverHandle *rh_heap_root;
1073
1074   GNUNET_CRYPTO_short_hash(rh->name, strlen(rh->name), &name_hash);
1075   GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1076   GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
1077   GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
1078   GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
1079
1080   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1081              "GNS_PHASE_REC-%d: starting dht lookup for %s with key: %s\n",
1082              rh->id, rh->name, (char*)&lookup_key_string);
1083
1084   //rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1085   rh->dht_heap_node = NULL;
1086
1087   if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
1088   {
1089     /**
1090      * Update timeout if necessary
1091      */
1092     if (rh->timeout_task == GNUNET_SCHEDULER_NO_TASK)
1093     {
1094
1095       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1096                  "GNS_PHASE_REC-%d: Adjusting timeout\n", rh->id);
1097       /*
1098        * Set timeout for authority lookup phase to 1/2
1099        */
1100       rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
1101                                                       GNUNET_TIME_relative_divide(rh->timeout, 2),
1102                                                       &handle_lookup_timeout,
1103                                                       rh);
1104     }
1105     //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1106     //                                                   &dht_lookup_timeout,
1107     //                                                   rh);
1108     rh->timeout_cont = &dht_lookup_timeout;
1109     rh->timeout_cont_cls = rh;
1110   }
1111   else 
1112   {
1113     if (max_allowed_background_queries <=
1114         GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
1115     {
1116       rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
1117       GNUNET_DHT_get_stop(rh_heap_root->get_handle);
1118       rh_heap_root->get_handle = NULL;
1119       rh_heap_root->dht_heap_node = NULL;
1120
1121       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1122                  "GNS_PHASE_REC-%d: Replacing oldest background query for %s\n",
1123                  rh->id, rh_heap_root->name);
1124       rh_heap_root->proc(rh_heap_root->proc_cls,
1125                          rh_heap_root,
1126                          0,
1127                          NULL);
1128     }
1129     rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
1130                                                       rh,
1131                                                       GNUNET_TIME_absolute_get().abs_value);
1132   }
1133
1134   xquery = htonl(rlh->record_type);
1135
1136   GNUNET_assert(rh->get_handle == NULL);
1137   rh->get_handle = GNUNET_DHT_get_start(dht_handle, 
1138                                         GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1139                                         &lookup_key,
1140                                         DHT_GNS_REPLICATION_LEVEL,
1141                                         GNUNET_DHT_RO_NONE,
1142                                         &xquery, 
1143                                         sizeof(xquery),
1144                                         &process_record_result_dht,
1145                                         rh);
1146
1147 }
1148
1149
1150 /**
1151  * Namestore calls this function if we have record for this name.
1152  * (or with rd_count=0 to indicate no matches)
1153  *
1154  * @param cls the pending query
1155  * @param key the key of the zone we did the lookup
1156  * @param expiration expiration date of the namestore entry
1157  * @param name the name for which we need an authority
1158  * @param rd_count the number of records with 'name'
1159  * @param rd the record data
1160  * @param signature the signature of the authority for the record data
1161  */
1162 static void
1163 process_record_result_ns (void* cls,
1164                           const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1165                           struct GNUNET_TIME_Absolute expiration,
1166                           const char *name, unsigned int rd_count,
1167                           const struct GNUNET_NAMESTORE_RecordData *rd,
1168                           const struct GNUNET_CRYPTO_RsaSignature *signature)
1169 {
1170   struct ResolverHandle *rh;
1171   struct RecordLookupHandle *rlh;
1172   struct GNUNET_TIME_Relative remaining_time;
1173   struct GNUNET_CRYPTO_ShortHashCode zone;
1174   struct GNUNET_TIME_Absolute et;
1175   unsigned int i;
1176
1177   rh = (struct ResolverHandle *) cls;
1178   rlh = (struct RecordLookupHandle *)rh->proc_cls;
1179   GNUNET_CRYPTO_short_hash(key,
1180                            sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1181                            &zone);
1182   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1183
1184
1185
1186   rh->status = 0;
1187
1188   if (name != NULL)
1189   {
1190     rh->status |= RSL_RECORD_EXISTS;
1191
1192     if (remaining_time.rel_value == 0)
1193     {
1194       rh->status |= RSL_RECORD_EXPIRED;
1195     }
1196   }
1197
1198   if (rd_count == 0)
1199   {
1200     /**
1201      * Lookup terminated and no results
1202      */
1203     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1204                "GNS_PHASE_REC-%d: Namestore lookup for %s terminated without results\n",
1205                rh->id, name);
1206
1207     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1208                "GNS_PHASE_REC-%d: Record %s unknown in namestore\n",
1209                rh->id, rh->name);
1210     /**
1211      * Our zone and no result? Cannot resolve TT
1212      */
1213     rh->proc(rh->proc_cls, rh, 0, NULL);
1214     return;
1215
1216   }
1217   else
1218   {
1219     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1220                "GNS_PHASE_REC-%d: Processing additional result %s from namestore\n",
1221                rh->id, name);
1222     for (i=0; i<rd_count;i++)
1223     {
1224       if (rd[i].record_type != rlh->record_type)
1225         continue;
1226
1227       if (ignore_pending_records &&
1228           (rd[i].flags & GNUNET_NAMESTORE_RF_PENDING))
1229       {
1230         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1231                    "GNS_PHASE_REC-%d: Record %s is awaiting user confirmation. Skipping\n",
1232                    rh->id, name);
1233         continue;
1234       }
1235
1236       GNUNET_break (0 == (rd[i].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION));
1237       et.abs_value = rd[i].expiration_time;
1238       if ((GNUNET_TIME_absolute_get_remaining (et)).rel_value
1239           == 0)
1240       {
1241         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1242                    "GNS_PHASE_REC-%d: This record is expired. Skipping\n",
1243                    rh->id);
1244         continue;
1245       }
1246       rh->answered++;
1247     }
1248
1249     /**
1250      * no answers found
1251      */
1252     if (rh->answered == 0)
1253     {
1254       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
1255                  "GNS_PHASE_REC-%d: No answers found. This is odd!\n", rh->id);
1256       rh->proc(rh->proc_cls, rh, 0, NULL);
1257       return;
1258     }
1259
1260     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1261                "GNS_PHASE_REC-%d: Found %d answer(s) to query in %d records!\n",
1262                rh->id, rh->answered, rd_count);
1263
1264     rh->proc(rh->proc_cls, rh, rd_count, rd);
1265   }
1266 }
1267
1268
1269 /**
1270  * VPN redirect result callback
1271  *
1272  * @param cls the resolver handle
1273  * @param af the requested address family
1274  * @param address in_addr(6) respectively
1275  */
1276 static void
1277 process_record_result_vpn (void* cls, int af, const void *address)
1278 {
1279   struct ResolverHandle *rh = cls;
1280   struct RecordLookupHandle *rlh;
1281   struct GNUNET_NAMESTORE_RecordData rd;
1282
1283   rlh = (struct RecordLookupHandle *)rh->proc_cls;
1284
1285   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1286              "GNS_PHASE_REC_VPN-%d: Got answer from VPN to query!\n",
1287              rh->id);
1288   if (af == AF_INET)
1289   {
1290     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1291                "GNS_PHASE_REC-%d: Answer is IPv4!\n",
1292                rh->id);
1293     if (rlh->record_type != GNUNET_GNS_RECORD_TYPE_A)
1294     {
1295       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1296                  "GNS_PHASE_REC-%d: Requested record is not IPv4!\n",
1297                  rh->id);
1298       rh->proc (rh->proc_cls, rh, 0, NULL);
1299       return;
1300     }
1301     rd.record_type = GNUNET_GNS_RECORD_TYPE_A;
1302     rd.expiration_time = UINT64_MAX; /* FIXME: should probably pick something shorter... */
1303     rd.data = address;
1304     rd.data_size = sizeof (struct in_addr);
1305     rd.flags = 0;
1306     rh->proc (rh->proc_cls, rh, 1, &rd);
1307     return;
1308   }
1309   else if (af == AF_INET6)
1310   {
1311     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1312                "GNS_PHASE_REC-%d: Answer is IPv6!\n",
1313                rh->id);
1314     if (rlh->record_type != GNUNET_GNS_RECORD_AAAA)
1315     {
1316       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1317                  "GNS_PHASE_REC-%d: Requested record is not IPv6!\n",
1318                  rh->id);
1319       rh->proc (rh->proc_cls, rh, 0, NULL);
1320       return;
1321     }
1322     rd.record_type = GNUNET_GNS_RECORD_AAAA;
1323     rd.expiration_time = UINT64_MAX; /* FIXME: should probably pick something shorter... */
1324     rd.data = address;
1325     rd.data_size = sizeof (struct in6_addr);
1326     rd.flags = 0;
1327     rh->proc (rh->proc_cls, rh, 1, &rd);
1328     return;
1329   }
1330
1331   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1332              "GNS_PHASE_REC-%d: Got garbage from VPN!\n",
1333              rh->id);
1334   rh->proc (rh->proc_cls, rh, 0, NULL);
1335 }
1336
1337
1338 /**
1339  * finish lookup
1340  *
1341  * @param rh resolver handle
1342  * @param rlh record lookup handle
1343  * @param rd_count number of results
1344  * @param rd results
1345  */
1346 static void
1347 finish_lookup(struct ResolverHandle *rh,
1348               struct RecordLookupHandle* rlh,
1349               unsigned int rd_count,
1350               const struct GNUNET_NAMESTORE_RecordData *rd);
1351
1352 /**
1353  * Process VPN lookup result for record
1354  *
1355  * @param cls the record lookup handle
1356  * @param rh resolver handle
1357  * @param rd_count number of results (1)
1358  * @param rd record data containing the result
1359  */
1360 static void
1361 handle_record_vpn (void* cls, struct ResolverHandle *rh,
1362                    unsigned int rd_count,
1363                    const struct GNUNET_NAMESTORE_RecordData *rd)
1364 {
1365   struct RecordLookupHandle* rlh = (struct RecordLookupHandle*) cls;
1366   
1367   if (rd_count == 0)
1368   {
1369     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1370                "GNS_PHASE_REC_VPN-%d: VPN returned no records. (status: %d)!\n",
1371                rh->id,
1372                rh->status);
1373     /* give up, cannot resolve */
1374     finish_lookup(rh, rlh, 0, NULL);
1375     free_resolver_handle(rh);
1376     return;
1377   }
1378
1379   /* results found yay */
1380   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1381              "GNS_PHASE_REC_VPN-%d: Record resolved from VPN!", rh->id);
1382
1383   finish_lookup(rh, rlh, rd_count, rd);
1384
1385   free_resolver_handle(rh);
1386 }
1387
1388
1389 /**
1390  * Sends a UDP dns query to a nameserver specified in the rh
1391  * 
1392  * @param rh the resolver handle
1393  */
1394 static void
1395 send_dns_packet (struct ResolverHandle *rh);
1396
1397
1398 static void
1399 handle_dns_resolver (void *cls,
1400                      const struct sockaddr *addr,
1401                      socklen_t addrlen)
1402 {
1403   struct ResolverHandle *rh = cls;
1404   struct RecordLookupHandle *rlh = rh->proc_cls;
1405   struct GNUNET_NAMESTORE_RecordData rd;
1406   struct sockaddr_in *sai;
1407   struct sockaddr_in6 *sai6;
1408
1409   if (NULL == addr)
1410   {
1411     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1412                 "No address found in DNS!\n");
1413     finish_lookup (rh, rlh, 0, NULL);
1414     free_resolver_handle (rh);
1415     return;
1416   }
1417   
1418   if (addrlen == sizeof (struct sockaddr_in))
1419   {
1420     sai = (struct sockaddr_in*) addr;
1421     rd.record_type = GNUNET_GNS_RECORD_TYPE_A;
1422     rd.data_size = sizeof (struct in_addr);
1423     rd.data = &sai->sin_addr;
1424   }
1425   else
1426   {
1427     sai6 = (struct sockaddr_in6*) addr;
1428     rd.record_type = GNUNET_GNS_RECORD_AAAA;
1429     rd.data_size = sizeof (struct in6_addr);
1430     rd.data = &sai6->sin6_addr;
1431   }
1432   
1433   rd.expiration_time = UINT64_MAX; /* FIXME: should probably pick something shorter */
1434   rd.flags = 0;
1435
1436   finish_lookup (rh, rlh, 1, &rd);
1437   GNUNET_RESOLVER_request_cancel (rh->dns_resolver_handle);
1438   free_resolver_handle (rh);
1439 }
1440
1441 /**
1442  * Resolve DNS name via local stub resolver
1443  *
1444  * @param rh the resolver handle
1445  */
1446 static void
1447 resolve_dns_name (struct ResolverHandle *rh)
1448 {
1449   struct RecordLookupHandle *rlh = rh->proc_cls;
1450   int af;
1451
1452   if ((rlh->record_type != GNUNET_GNS_RECORD_TYPE_A) &&
1453       (rlh->record_type != GNUNET_GNS_RECORD_AAAA))
1454   {
1455     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1456                 "Can only resolve A/AAAA via stub... abort\n");
1457     finish_lookup (rh, rlh, 0, NULL);
1458     free_resolver_handle (rh);
1459     return;
1460   }
1461
1462   if (rlh->record_type == GNUNET_GNS_RECORD_TYPE_A)
1463     af = AF_INET;
1464   else
1465     af = AF_INET6;
1466
1467   //GNUNET_RESOLVER_connect (cfg); FIXME into init
1468
1469   rh->dns_resolver_handle = GNUNET_RESOLVER_ip_get (rh->dns_name,
1470                                                     af,
1471                                                     rh->timeout,
1472                                                     &handle_dns_resolver,
1473                                                     rh);
1474 }
1475
1476
1477 /**
1478  * Read DNS udp packet from socket
1479  *
1480  * @param cls the resolver handle
1481  * @param tc task context
1482  */
1483 static void
1484 read_dns_response (void *cls,
1485                    const struct GNUNET_SCHEDULER_TaskContext *tc)
1486 {
1487   struct ResolverHandle *rh = cls;
1488   struct RecordLookupHandle *rlh = rh->proc_cls;
1489   char buf[UINT16_MAX];
1490   ssize_t r;
1491   struct sockaddr_in addr;
1492   socklen_t addrlen;
1493   struct GNUNET_DNSPARSER_Packet *packet;
1494   struct GNUNET_NAMESTORE_RecordData rd;
1495   int found_delegation = GNUNET_NO;
1496   int found_cname = GNUNET_NO;
1497   char* delegation_name = NULL;
1498   int zone_offset = 0;
1499   int i;
1500
1501   rh->dns_read_task = GNUNET_SCHEDULER_NO_TASK;
1502   if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
1503   {
1504     /* timeout or shutdown */
1505     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1506                 "Terminating DNS query\n");
1507     finish_lookup (rh, rlh, 0, NULL);
1508     GNUNET_NETWORK_socket_close (rh->dns_sock);
1509     free_resolver_handle (rh);
1510     return;
1511   }
1512
1513   addrlen = sizeof (addr);
1514   r = GNUNET_NETWORK_socket_recvfrom (rh->dns_sock,
1515                                       buf, sizeof (buf),
1516                                       (struct sockaddr*) &addr,
1517                                       &addrlen);
1518
1519   if (-1 == r)
1520   {
1521     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom");
1522     finish_lookup (rh, rlh, 0, NULL);
1523     GNUNET_NETWORK_socket_close (rh->dns_sock);
1524     free_resolver_handle (rh);
1525     return;
1526   }
1527
1528   packet = GNUNET_DNSPARSER_parse (buf, r);
1529   
1530   if (NULL == packet)
1531   {
1532     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1533                 "Failed to parse DNS reply!\n");
1534     finish_lookup (rh, rlh, 0, NULL);
1535     GNUNET_NETWORK_socket_close (rh->dns_sock);
1536     free_resolver_handle (rh);
1537     return;
1538   }
1539
1540   for (i = 0; i < packet->num_answers; i++)
1541   {
1542     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1543                "Got record type %d (want %d)\n",
1544                packet->answers[i].type,
1545                rlh->record_type);
1546     /* http://tools.ietf.org/html/rfc1034#section-3.6.2 */
1547     if (packet->answers[i].type == GNUNET_GNS_RECORD_TYPE_CNAME)
1548     {
1549       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1550                   "CNAME... restarting query with %s\n",
1551                   packet->answers[i].data.hostname
1552                  );
1553       strcpy (rh->dns_name, packet->answers[i].data.hostname);
1554       found_cname = GNUNET_YES;
1555       //send_dns_packet (rh);
1556       //GNUNET_DNSPARSER_free_packet (packet);
1557       continue;
1558     }
1559     
1560     if ((packet->answers[i].type == rlh->record_type) &&
1561         (0 == strcmp (packet->answers[i].name, rh->dns_name)))
1562     {
1563       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1564                   "Found record!\n");
1565       rd.data = packet->answers[i].data.raw.data;
1566       rd.data_size = packet->answers[i].data.raw.data_len;
1567       rd.record_type = packet->answers[i].type;
1568       rd.flags = 0;
1569       rd.expiration_time = packet->answers[i].expiration_time.abs_value;
1570       finish_lookup (rh, rlh, 1, &rd);
1571       GNUNET_NETWORK_socket_close (rh->dns_sock);
1572       GNUNET_DNSPARSER_free_packet (packet);
1573       free_resolver_handle (rh);
1574       return;
1575     }
1576   }
1577
1578   if (GNUNET_YES == found_cname)
1579   {
1580     zone_offset = strlen (rh->dns_name) - strlen (rh->dns_zone) - 1;
1581     
1582     if (0 > zone_offset)
1583       zone_offset = 0;
1584
1585     /* restart query with CNAME */
1586     if (0 == strcmp (rh->dns_name+zone_offset, rh->dns_zone))
1587     {
1588       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1589                   "Asking same server for %s\n", rh->dns_name);
1590       send_dns_packet (rh);
1591     }
1592     else
1593     {
1594       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1595                   "Trying system resolver for %s\n", rh->dns_name);
1596       resolve_dns_name (rh);
1597     }
1598
1599     GNUNET_DNSPARSER_free_packet (packet);
1600     return;
1601   }
1602
1603   for (i = 0; i < packet->num_authority_records; i++)
1604   {
1605     
1606     if (packet->authority_records[i].type == GNUNET_GNS_RECORD_TYPE_NS)
1607     {
1608       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1609                   "Found NS delegation!\n");
1610       found_delegation = GNUNET_YES;
1611       delegation_name = packet->authority_records[i].data.hostname;
1612       break;
1613     }
1614   }
1615
1616   for (i = 0; i < packet->num_additional_records; i++)
1617   {
1618     if (found_delegation == GNUNET_NO)
1619       break;
1620
1621     if ((packet->additional_records[i].type == GNUNET_GNS_RECORD_TYPE_A) &&
1622         (0 == strcmp (packet->additional_records[i].name, delegation_name)))
1623     {
1624       GNUNET_assert (sizeof (struct in_addr) ==
1625                      packet->authority_records[i].data.raw.data_len);
1626       
1627       rh->dns_addr.sin_addr =
1628         *((struct in_addr*)packet->authority_records[i].data.raw.data);
1629       send_dns_packet (rh);
1630       GNUNET_DNSPARSER_free_packet (packet);
1631       return;
1632     }
1633   }
1634
1635   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1636               "Nothing useful in DNS reply!\n");
1637   finish_lookup (rh, rlh, 0, NULL);
1638   GNUNET_NETWORK_socket_close (rh->dns_sock);
1639   free_resolver_handle (rh);
1640   GNUNET_DNSPARSER_free_packet (packet);
1641   return;
1642 }
1643
1644 /**
1645  * Sends a UDP dns query to a nameserver specified in the rh
1646  * 
1647  * @param rh the request handle
1648  */
1649 static void
1650 send_dns_packet (struct ResolverHandle *rh)
1651 {
1652   struct GNUNET_NETWORK_FDSet *rset = GNUNET_NETWORK_fdset_create ();
1653   GNUNET_NETWORK_fdset_set (rset, rh->dns_sock);
1654   
1655   GNUNET_NETWORK_socket_sendto (rh->dns_sock,
1656                                 rh->dns_raw_packet,
1657                                 rh->dns_raw_packet_size,
1658                                 (struct sockaddr*)&rh->dns_addr,
1659                                 sizeof (struct sockaddr_in));
1660
1661   rh->dns_read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1662                                                     rh->timeout, //FIXME less?
1663                                                     rset,
1664                                                     NULL,
1665                                                     &read_dns_response,
1666                                                     rh);
1667
1668   GNUNET_NETWORK_fdset_destroy (rset);
1669
1670 }
1671
1672 /**
1673  * The final phase of resoution.
1674  * We found a NS RR and want to resolve via DNS
1675  *
1676  * @param rh the pending lookup handle
1677  * @param rd_count length of record data
1678  * @param rd record data containing VPN RR
1679  */
1680 static void
1681 resolve_record_dns (struct ResolverHandle *rh,
1682                     int rd_count,
1683                     const struct GNUNET_NAMESTORE_RecordData *rd)
1684 {
1685   struct GNUNET_DNSPARSER_Query query;
1686   struct GNUNET_DNSPARSER_Packet packet;
1687   struct GNUNET_DNSPARSER_Flags flags;
1688   struct in_addr dnsip;
1689   struct sockaddr_in addr;
1690   struct sockaddr *sa;
1691   int i;
1692   struct RecordLookupHandle *rlh = rh->proc_cls;
1693
1694   memset (&packet, 0, sizeof (struct GNUNET_DNSPARSER_Packet));
1695   
1696   /* We cancel here as to not include the ns lookup in the timeout */
1697   if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1698   {
1699     GNUNET_SCHEDULER_cancel(rh->timeout_task);
1700     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1701   }
1702   /* Start shortening */
1703   if ((rh->priv_key != NULL) && is_canonical (rh->name))
1704   {
1705     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1706              "GNS_PHASE_REC_DNS-%llu: Trying to shorten authority chain\n",
1707              rh->id);
1708     start_shorten (rh->authority_chain_tail,
1709                    rh->priv_key);
1710   }
1711
1712   for (i = 0; i < rd_count; i++)
1713   {
1714     /* Synthesize dns name */
1715     if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_NS)
1716     {
1717       strcpy (rh->dns_zone, (char*)rd[i].data);
1718       if (0 == strcmp (rh->name, ""))
1719         strcpy (rh->dns_name, (char*)rd[i].data);
1720       else
1721         sprintf (rh->dns_name, "%s.%s", rh->name, (char*)rd[i].data);
1722     }
1723     /* The glue */
1724     if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_A)
1725       dnsip = *((struct in_addr*)rd[i].data);
1726   }
1727   
1728   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1729               "GNS_PHASE_REC_DNS-%llu: Looking up %s from %s\n",
1730               rh->id,
1731               rh->dns_name,
1732               inet_ntoa (dnsip));
1733   rh->dns_sock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0);
1734   if (rh->dns_sock == NULL)
1735   {
1736     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1737                 "GNS_PHASE_REC_DNS-%llu: Error creating udp socket for dns!\n",
1738                 rh->id);
1739     finish_lookup (rh, rlh, 0, NULL);
1740     free_resolver_handle (rh);
1741     return;
1742   }
1743
1744   memset (&addr, 0, sizeof (struct sockaddr_in));
1745   sa = (struct sockaddr *) &addr;
1746   sa->sa_family = AF_INET;
1747   if (GNUNET_OK != GNUNET_NETWORK_socket_bind (rh->dns_sock,
1748                                                sa,
1749                                                sizeof (struct sockaddr_in)))
1750   {
1751     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1752                 "GNS_PHASE_REC_DNS-%llu: Error binding udp socket for dns!\n",
1753                 rh->id);
1754     GNUNET_NETWORK_socket_close (rh->dns_sock);
1755     finish_lookup (rh, rlh, 0, NULL);
1756     free_resolver_handle (rh);
1757     return;
1758   }
1759   
1760   /*TODO create dnsparser query, serialize, sendto, handle reply*/
1761   query.name = rh->dns_name;
1762   query.type = rlh->record_type;
1763   query.class = GNUNET_DNSPARSER_CLASS_INTERNET;
1764   memset (&flags, 0, sizeof (flags));
1765   flags.recursion_desired = 1;
1766   flags.checking_disabled = 1;
1767   packet.queries = &query;
1768   packet.answers = NULL;
1769   packet.authority_records = NULL;
1770   packet.num_queries = 1;
1771   packet.num_answers = 0;
1772   packet.num_authority_records = 0;
1773   packet.num_additional_records = 0;
1774   packet.flags = flags;
1775   packet.id = rh->id;
1776   if (GNUNET_OK != GNUNET_DNSPARSER_pack (&packet,
1777                                           UINT16_MAX,
1778                                           &rh->dns_raw_packet,
1779                                           &rh->dns_raw_packet_size))
1780   {
1781     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1782                 "GNS_PHASE_REC_DNS-%llu: Creating raw dns packet!\n",
1783                 rh->id);
1784     GNUNET_NETWORK_socket_close (rh->dns_sock);
1785     finish_lookup (rh, rlh, 0, NULL);
1786     free_resolver_handle (rh);
1787     return;
1788   }
1789
1790   rh->dns_addr.sin_family = AF_INET;
1791   rh->dns_addr.sin_port = htons (53); //domain
1792   rh->dns_addr.sin_addr = dnsip;
1793 #if HAVE_SOCKADDR_IN_SIN_LEN
1794   rh->dns_addr.sin_len = (u_char) sizeof (struct sockaddr_in);
1795 #endif
1796
1797   send_dns_packet (rh);
1798 }
1799
1800
1801 /**
1802  * The final phase of resoution.
1803  * We found a VPN RR and want to request an IPv4/6 address
1804  *
1805  * @param rh the pending lookup handle
1806  * @param rd_count length of record data
1807  * @param rd record data containing VPN RR
1808  */
1809 static void
1810 resolve_record_vpn (struct ResolverHandle *rh,
1811                     int rd_count,
1812                     const struct GNUNET_NAMESTORE_RecordData *rd)
1813 {
1814   int af;
1815   int proto;
1816   struct GNUNET_HashCode peer_id;
1817   struct GNUNET_CRYPTO_HashAsciiEncoded s_pid;
1818   struct GNUNET_HashCode serv_desc;
1819   struct GNUNET_CRYPTO_HashAsciiEncoded s_sd;
1820   char* pos;
1821   size_t len = (sizeof (uint32_t) * 2) + (sizeof (struct GNUNET_HashCode) * 2);
1822   
1823   /* We cancel here as to not include the ns lookup in the timeout */
1824   if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1825   {
1826     GNUNET_SCHEDULER_cancel(rh->timeout_task);
1827     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1828   }
1829   /* Start shortening */
1830   if ((rh->priv_key != NULL) && is_canonical (rh->name))
1831   {
1832     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1833              "GNS_PHASE_REC_VPN-%llu: Trying to shorten authority chain\n",
1834              rh->id);
1835     start_shorten (rh->authority_chain_tail,
1836                    rh->priv_key);
1837   }
1838
1839   /* Extracting VPN information FIXME rd parsing with NS API?*/
1840   if (len != rd->data_size)
1841   {
1842     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1843                 "GNS_PHASE_REC_VPN-%llu: Error parsing VPN RR!\n",
1844                 rh->id);
1845     finish_lookup (rh, rh->proc_cls, 0, NULL);
1846     free_resolver_handle (rh);
1847     return;
1848   }
1849
1850   pos = (char*)rd;
1851   memcpy (&af, pos, sizeof (uint32_t));
1852   pos += sizeof (uint32_t);
1853   memcpy (&proto, pos, sizeof (uint32_t));
1854   pos += sizeof (uint32_t);
1855   memcpy (&s_pid, pos, sizeof (struct GNUNET_HashCode));
1856   pos += sizeof (struct GNUNET_HashCode);
1857   memcpy (&s_sd, pos, sizeof (struct GNUNET_HashCode));
1858
1859
1860   if ((GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char*)&s_pid, &peer_id)) ||
1861       (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char*)&s_sd, &serv_desc)))
1862   {
1863     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1864                 "GNS_PHASE_REC_VPN-%llu: Error parsing VPN RR hashes!\n",
1865                 rh->id);
1866     finish_lookup (rh, rh->proc_cls, 0, NULL);
1867     free_resolver_handle (rh);
1868     return;
1869   }
1870
1871   rh->proc = &handle_record_vpn;
1872
1873   if (NULL == vpn_handle)
1874   {
1875     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1876                 "GNS_PHASE_REC_VPN-%llu: VPN not connected!\n",
1877                 rh->id);
1878     finish_lookup (rh, rh->proc_cls, 0, NULL);
1879     free_resolver_handle (rh);
1880     return;
1881   }
1882   
1883   //FIXME timeout??
1884   rh->vpn_handle = GNUNET_VPN_redirect_to_peer (vpn_handle,
1885                                           af, proto,
1886                                           (struct GNUNET_PeerIdentity*)&peer_id,
1887                                           &serv_desc,
1888                                           GNUNET_NO, //nac
1889                                           GNUNET_TIME_UNIT_FOREVER_ABS, //FIXME
1890                                           &process_record_result_vpn,
1891                                           rh);
1892
1893 }
1894
1895 /**
1896  * The final phase of resolution.
1897  * rh->name is a name that is canonical and we do not have a delegation.
1898  * Query namestore for this record
1899  *
1900  * @param rh the pending lookup handle
1901  */
1902 static void
1903 resolve_record_ns(struct ResolverHandle *rh)
1904 {
1905   struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
1906   
1907   /* We cancel here as to not include the ns lookup in the timeout */
1908   if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1909   {
1910     GNUNET_SCHEDULER_cancel(rh->timeout_task);
1911     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1912   }
1913   /* Start shortening */
1914   if ((rh->priv_key != NULL) && is_canonical (rh->name))
1915   {
1916     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1917              "GNS_PHASE_REC-%llu: Trying to shorten authority chain\n",
1918              rh->id);
1919     start_shorten (rh->authority_chain_tail,
1920                    rh->priv_key);
1921   }
1922   
1923   /**
1924    * Try to resolve this record in our namestore.
1925    * The name to resolve is now in rh->authority_name
1926    * since we tried to resolve it to an authority
1927    * and failed.
1928    **/
1929   GNUNET_NAMESTORE_lookup_record(namestore_handle,
1930                                  &rh->authority,
1931                                  rh->name,
1932                                  rlh->record_type,
1933                                  &process_record_result_ns,
1934                                  rh);
1935 }
1936
1937
1938
1939 /**
1940  * Handle timeout for DHT requests
1941  *
1942  * @param cls the request handle as closure
1943  * @param tc the task context
1944  */
1945 static void
1946 dht_authority_lookup_timeout(void *cls,
1947                              const struct GNUNET_SCHEDULER_TaskContext *tc)
1948 {
1949   struct ResolverHandle *rh = cls;
1950   struct RecordLookupHandle *rlh = rh->proc_cls;
1951   char new_name[MAX_DNS_NAME_LENGTH];
1952
1953   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1954          "GNS_PHASE_DELEGATE_DHT-%llu: dht lookup for query %s (%ds)timed out.\n",
1955          rh->id, rh->authority_name, rh->timeout.rel_value);
1956
1957   rh->status |= RSL_TIMED_OUT;
1958
1959   rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1960   
1961   GNUNET_DHT_get_stop (rh->get_handle);
1962   rh->get_handle = NULL;
1963   
1964   if (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)
1965   {
1966     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1967                "GNS_PHASE_DELEGATE_DHT-%llu: Got shutdown\n",
1968                rh->id);
1969     rh->proc(rh->proc_cls, rh, 0, NULL);
1970     return;
1971   }
1972
1973   if (strcmp(rh->name, "") == 0)
1974   {
1975     /*
1976      * promote authority back to name and try to resolve record
1977      */
1978     strcpy(rh->name, rh->authority_name);
1979     rh->proc(rh->proc_cls, rh, 0, NULL);
1980     return;
1981   }
1982   
1983   /**
1984    * Start resolution in bg
1985    */
1986   GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH,
1987                   "%s.%s.%s", rh->name, rh->authority_name, GNUNET_GNS_TLD);
1988   //strcpy(new_name, rh->name);
1989   //strcpy(new_name+strlen(new_name), ".");
1990   //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD));
1991   
1992   strcpy(rh->name, new_name);
1993
1994   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1995         "GNS_PHASE_DELEGATE_DHT-%llu: Starting background query for %s type %d\n",
1996         rh->id, rh->name, rlh->record_type);
1997
1998   gns_resolver_lookup_record(rh->authority,
1999                              rh->private_local_zone,
2000                              rlh->record_type,
2001                              new_name,
2002                              rh->priv_key,
2003                              GNUNET_TIME_UNIT_FOREVER_REL,
2004                              GNUNET_NO,
2005                              &background_lookup_result_processor,
2006                              NULL);
2007
2008   rh->proc(rh->proc_cls, rh, 0, NULL);
2009 }
2010
2011 /* Prototype */
2012 static void resolve_delegation_dht(struct ResolverHandle *rh);
2013
2014 /* Prototype */
2015 static void resolve_delegation_ns(struct ResolverHandle *rh);
2016
2017
2018 /**
2019  * Namestore resolution for delegation finished. Processing result.
2020  *
2021  * @param cls the closure
2022  * @param rh resolver handle
2023  * @param rd_count number of results (always 0)
2024  * @param rd record data (always NULL)
2025  */
2026 static void
2027 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
2028                           unsigned int rd_count,
2029                           const struct GNUNET_NAMESTORE_RecordData *rd);
2030
2031
2032 /**
2033  * This is a callback function that checks for key revocation
2034  *
2035  * @param cls the pending query
2036  * @param key the key of the zone we did the lookup
2037  * @param expiration expiration date of the record data set in the namestore
2038  * @param name the name for which we need an authority
2039  * @param rd_count the number of records with 'name'
2040  * @param rd the record data
2041  * @param signature the signature of the authority for the record data
2042  */
2043 static void
2044 process_pkey_revocation_result_ns (void *cls,
2045                     const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
2046                     struct GNUNET_TIME_Absolute expiration,
2047                     const char *name,
2048                     unsigned int rd_count,
2049                     const struct GNUNET_NAMESTORE_RecordData *rd,
2050                     const struct GNUNET_CRYPTO_RsaSignature *signature)
2051 {
2052   struct ResolverHandle *rh = cls;
2053   struct GNUNET_TIME_Relative remaining_time;
2054   int i;
2055   
2056   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
2057   
2058   for (i = 0; i < rd_count; i++)
2059   {
2060     if (rd[i].record_type == GNUNET_GNS_RECORD_REV)
2061     {
2062       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2063                  "GNS_PHASE_DELEGATE_REV-%llu: Zone has been revoked.\n",
2064                  rh->id);
2065       rh->status |= RSL_PKEY_REVOKED;
2066       rh->proc (rh->proc_cls, rh, 0, NULL);
2067       return;
2068     }
2069   }
2070   
2071   if ((name == NULL) ||
2072       (remaining_time.rel_value == 0))
2073   {
2074     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2075           "GNS_PHASE_DELEGATE_REV-%llu: + Records don't exist or are expired.\n",
2076           rh->id, name);
2077
2078     if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
2079     {
2080       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2081         "GNS_PHASE_DELEGATE_REV-%d: Starting background lookup for %s type %d\n",
2082         rh->id, "+.gnunet", GNUNET_GNS_RECORD_REV);
2083
2084       gns_resolver_lookup_record(rh->authority,
2085                                  rh->private_local_zone,
2086                                  GNUNET_GNS_RECORD_REV,
2087                                  GNUNET_GNS_TLD,
2088                                  rh->priv_key,
2089                                  GNUNET_TIME_UNIT_FOREVER_REL,
2090                                  GNUNET_NO,
2091                                  &background_lookup_result_processor,
2092                                  NULL);
2093     }
2094   }
2095  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2096              "GNS_PHASE_DELEGATE_REV-%llu: Revocation checkpassed\n",
2097              rh->id);
2098   /**
2099    * We are done with PKEY resolution if name is empty
2100    * else resolve again with new authority
2101    */
2102   if (strcmp (rh->name, "") == 0)
2103     rh->proc (rh->proc_cls, rh, 0, NULL);
2104   else
2105     resolve_delegation_ns (rh);
2106   return;
2107 }
2108
2109
2110 /**
2111  * Function called when we get a result from the dht
2112  * for our query. Recursively tries to resolve authorities
2113  * for name in DHT.
2114  *
2115  * @param cls the request handle
2116  * @param exp lifetime
2117  * @param key the key the record was stored under
2118  * @param get_path get path
2119  * @param get_path_length get path length
2120  * @param put_path put path
2121  * @param put_path_length put path length
2122  * @param type the block type
2123  * @param size the size of the record
2124  * @param data the record data
2125  */
2126 static void
2127 process_delegation_result_dht(void* cls,
2128                  struct GNUNET_TIME_Absolute exp,
2129                  const struct GNUNET_HashCode * key,
2130                  const struct GNUNET_PeerIdentity *get_path,
2131                  unsigned int get_path_length,
2132                  const struct GNUNET_PeerIdentity *put_path,
2133                  unsigned int put_path_length,
2134                  enum GNUNET_BLOCK_Type type,
2135                  size_t size, const void *data)
2136 {
2137   struct ResolverHandle *rh;
2138   struct GNSNameRecordBlock *nrb;
2139   uint32_t num_records;
2140   char* name = NULL;
2141   char* rd_data = (char*) data;
2142   int i;
2143   int rd_size;
2144   struct GNUNET_CRYPTO_ShortHashCode zone, name_hash;
2145   struct GNUNET_HashCode zone_hash_double, name_hash_double;
2146
2147   rh = (struct ResolverHandle *)cls;
2148   
2149   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2150              "GNS_PHASE_DELEGATE_DHT-%llu: Got DHT result\n", rh->id);
2151
2152   if (data == NULL)
2153     return;
2154   
2155   nrb = (struct GNSNameRecordBlock*)data;
2156   
2157   /* stop dht lookup and timeout task */
2158   GNUNET_DHT_get_stop (rh->get_handle);
2159
2160   rh->get_handle = NULL;
2161
2162   if (rh->dht_heap_node != NULL)
2163   {
2164     GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
2165     rh->dht_heap_node = NULL;
2166   }
2167
2168   num_records = ntohl(nrb->rd_count);
2169   name = (char*)&nrb[1];
2170   {
2171     struct GNUNET_NAMESTORE_RecordData rd[num_records];
2172     
2173     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
2174     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
2175   
2176     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
2177                                                                rd_data,
2178                                                                num_records,
2179                                                                rd))
2180     {
2181       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
2182                  "GNS_PHASE_DELEGATE_DHT-%llu: Error deserializing data!\n",
2183                  rh->id);
2184       return;
2185     }
2186
2187     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2188                "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n",
2189                rh->id, name, rh->authority_name);
2190     for (i=0; i<num_records; i++)
2191     {
2192     
2193       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2194                 "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n",
2195                 rh->id, name, rh->authority_name);
2196       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2197                  "GNS_PHASE_DELEGATE_DHT-%llu: Got type: %d (wanted %d)\n",
2198                  rh->id, rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
2199       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2200                  "GNS_PHASE_DELEGATE_DHT-%llu: Got data length: %d\n",
2201                  rh->id, rd[i].data_size);
2202       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2203                  "GNS_PHASE_DELEGATE_DHT-%llu: Got flag %d\n",
2204                  rh->id, rd[i].flags);
2205       
2206       if ((rd[i].record_type == GNUNET_GNS_RECORD_VPN) ||
2207           (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_NS) ||
2208           (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_CNAME))
2209       {
2210         /**
2211          * This is a VPN,NS,CNAME entry. Let namestore handle this after caching
2212          */
2213         if (strcmp(rh->name, "") == 0)
2214           strcpy(rh->name, rh->authority_name);
2215         else
2216           GNUNET_snprintf(rh->name, MAX_DNS_NAME_LENGTH, "%s.%s",
2217                  rh->name, rh->authority_name); //FIXME ret
2218         rh->answered = 1;
2219         break;
2220       }
2221
2222       if ((strcmp(name, rh->authority_name) == 0) &&
2223           (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
2224       {
2225         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2226                    "GNS_PHASE_DELEGATE_DHT-%llu: Authority found in DHT\n",
2227                    rh->id);
2228         rh->answered = 1;
2229         memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
2230         struct AuthorityChain *auth =
2231           GNUNET_malloc(sizeof(struct AuthorityChain));
2232         auth->zone = rh->authority;
2233         memset(auth->name, 0, strlen(rh->authority_name)+1);
2234         strcpy(auth->name, rh->authority_name);
2235         GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
2236                                      rh->authority_chain_tail,
2237                                      auth);
2238
2239         /** try to import pkey if private key available */
2240         //if (rh->priv_key && is_canonical (rh->name))
2241         //  process_discovered_authority(name, auth->zone,
2242         //                               rh->authority_chain_tail->zone,
2243         //                               rh->priv_key);
2244       }
2245
2246     }
2247
2248
2249     GNUNET_CRYPTO_short_hash(name, strlen(name), &name_hash);
2250     GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
2251     GNUNET_CRYPTO_hash_xor(key, &name_hash_double, &zone_hash_double);
2252     GNUNET_CRYPTO_short_hash_from_truncation (&zone_hash_double, &zone);
2253
2254     /* Save to namestore */
2255     if (0 != GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_tail->zone,
2256                                           &zone))
2257     {
2258       GNUNET_NAMESTORE_record_put (namestore_handle,
2259                                  &nrb->public_key,
2260                                  name,
2261                                  exp,
2262                                  num_records,
2263                                  rd,
2264                                  &nrb->signature,
2265                                  &on_namestore_record_put_result, //cont
2266                                  NULL); //cls
2267     }
2268   }
2269   
2270   if (rh->answered)
2271   {
2272     rh->answered = 0;
2273     /**
2274      * delegate
2275      * FIXME in this case. should we ask namestore again?
2276      */
2277     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2278       "GNS_PHASE_DELEGATE_DHT-%llu: Answer from DHT for %s. Yet to resolve: %s\n",
2279       rh->id, rh->authority_name, rh->name);
2280
2281     if (strcmp(rh->name, "") == 0)
2282     {
2283       /* Start shortening */
2284       if ((rh->priv_key != NULL) && is_canonical (rh->name))
2285       {
2286         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2287              "GNS_PHASE_DELEGATE_DHT-%llu: Trying to shorten authority chain\n",
2288              rh->id);
2289         start_shorten (rh->authority_chain_tail,
2290                        rh->priv_key);
2291       }
2292     }
2293     else
2294       rh->proc = &handle_delegation_ns;
2295
2296     /* Check for key revocation and delegate */
2297     GNUNET_NAMESTORE_lookup_record (namestore_handle,
2298                                     &rh->authority,
2299                                     "+",
2300                                     GNUNET_GNS_RECORD_REV,
2301                                     &process_pkey_revocation_result_ns,
2302                                     rh);   
2303     
2304     /*if (strcmp(rh->name, "") == 0)
2305     {
2306       if ((rh->priv_key != NULL) && is_canonical (rh->name))
2307       {
2308         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2309              "GNS_PHASE_DELEGATE_DHT-%llu: Trying to shorten authority chain\n",
2310              rh->id);
2311         start_shorten (rh->authority_chain_tail,
2312                        rh->priv_key);
2313       }
2314       
2315       rh->proc(rh->proc_cls, rh, 0, NULL);
2316     }
2317     else
2318     {
2319       rh->proc = &handle_delegation_ns;
2320       resolve_delegation_ns (rh);
2321     }
2322     */
2323     return;
2324   }
2325   
2326   /**
2327    * No pkey but name exists
2328    * promote back
2329    */
2330   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2331              "GNS_PHASE_DELEGATE_DHT-%llu: Adding %s back to %s\n",
2332              rh->id, rh->authority_name, rh->name);
2333   if (strcmp(rh->name, "") == 0)
2334     strcpy(rh->name, rh->authority_name);
2335   else
2336     GNUNET_snprintf(rh->name, MAX_DNS_NAME_LENGTH, "%s.%s",
2337                   rh->name, rh->authority_name); //FIXME ret
2338   
2339   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2340              "GNS_PHASE_DELEGATE_DHT-%llu: %s restored\n", rh->id, rh->name);
2341   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2342            "GNS_PHASE_DELEGATE_DHT-%llu: DHT authority lookup found no match!\n",
2343            rh->id);
2344   rh->proc(rh->proc_cls, rh, 0, NULL);
2345 }
2346
2347 #define MAX_SOA_LENGTH sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)\
2348                         +(MAX_DNS_NAME_LENGTH*2)
2349 #define MAX_MX_LENGTH sizeof(uint16_t)+MAX_DNS_NAME_LENGTH
2350 #define MAX_SRV_LENGTH (sizeof(uint16_t)*3)+MAX_DNS_NAME_LENGTH
2351
2352
2353 static void
2354 expand_plus(char** dest, char* src, char* repl)
2355 {
2356   char* pos;
2357   unsigned int s_len = strlen(src)+1;
2358
2359   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2360              "GNS_POSTPROCESS: Got %s to expand with %s\n", src, repl);
2361
2362   if (s_len < 3)
2363   {
2364     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2365                "GNS_POSTPROCESS: %s to short\n", src);
2366
2367     /* no postprocessing */
2368     memcpy(*dest, src, s_len+1);
2369     return;
2370   }
2371   
2372   if (0 == strcmp(src+s_len-3, ".+"))
2373   {
2374     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2375                "GNS_POSTPROCESS: Expanding .+ in %s\n", src);
2376     memset(*dest, 0, s_len+strlen(repl)+strlen(GNUNET_GNS_TLD));
2377     strcpy(*dest, src);
2378     pos = *dest+s_len-2;
2379     strcpy(pos, repl);
2380     pos += strlen(repl);
2381     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2382                "GNS_POSTPROCESS: Expanded to %s\n", *dest);
2383   }
2384   else
2385   {
2386     memcpy(*dest, src, s_len+1);
2387   }
2388 }
2389
2390 /**
2391  * finish lookup
2392  */
2393 static void
2394 finish_lookup(struct ResolverHandle *rh,
2395               struct RecordLookupHandle* rlh,
2396               unsigned int rd_count,
2397               const struct GNUNET_NAMESTORE_RecordData *rd)
2398 {
2399   int i;
2400   char new_rr_data[MAX_DNS_NAME_LENGTH];
2401   char new_mx_data[MAX_MX_LENGTH];
2402   char new_soa_data[MAX_SOA_LENGTH];
2403   char new_srv_data[MAX_SRV_LENGTH];
2404   struct GNUNET_NAMESTORE_RecordData p_rd[rd_count];
2405   char* repl_string;
2406   char* pos;
2407   unsigned int offset;
2408
2409   if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
2410   {
2411     GNUNET_SCHEDULER_cancel(rh->timeout_task);
2412     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2413   }
2414
2415   if (rd_count > 0)
2416     memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData));
2417
2418   for (i = 0; i < rd_count; i++)
2419   {
2420     
2421     if (rd[i].record_type != GNUNET_GNS_RECORD_TYPE_NS &&
2422         rd[i].record_type != GNUNET_GNS_RECORD_TYPE_CNAME &&
2423         rd[i].record_type != GNUNET_GNS_RECORD_MX &&
2424         rd[i].record_type != GNUNET_GNS_RECORD_TYPE_SOA &&
2425         rd[i].record_type != GNUNET_GNS_RECORD_TYPE_SRV)
2426     {
2427       p_rd[i].data = rd[i].data;
2428       continue;
2429     }
2430
2431     /**
2432      * for all those records we 'should'
2433      * also try to resolve the A/AAAA records (RFC1035)
2434      * This is a feature and not important
2435      */
2436     
2437     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2438                "GNS_POSTPROCESS: Postprocessing\n");
2439
2440     if (strcmp(rh->name, "+") == 0)
2441       repl_string = rlh->name;
2442     else
2443       repl_string = rlh->name+strlen(rh->name)+1;
2444
2445     offset = 0;
2446     if (rd[i].record_type == GNUNET_GNS_RECORD_MX)
2447     {
2448       memcpy (new_mx_data, (char*)rd[i].data, sizeof(uint16_t));
2449       offset = sizeof(uint16_t);
2450       pos = new_mx_data+offset;
2451       expand_plus(&pos, (char*)rd[i].data+sizeof(uint16_t),
2452                   repl_string);
2453       offset += strlen(new_mx_data+sizeof(uint16_t))+1;
2454       p_rd[i].data = new_mx_data;
2455       p_rd[i].data_size = offset;
2456     }
2457     else if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_SRV)
2458     {
2459       /*
2460        * Prio, weight and port
2461        */
2462       memcpy (new_srv_data, (char*)rd[i].data, sizeof (uint16_t) * 3);
2463       offset = sizeof (uint16_t) * 3;
2464       pos = new_srv_data+offset;
2465       expand_plus(&pos, (char*)rd[i].data+(sizeof(uint16_t)*3),
2466                   repl_string);
2467       offset += strlen(new_srv_data+(sizeof(uint16_t)*3))+1;
2468       p_rd[i].data = new_srv_data;
2469       p_rd[i].data_size = offset;
2470     }
2471     else if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_SOA)
2472     {
2473       /* expand mname and rname */
2474       pos = new_soa_data;
2475       expand_plus(&pos, (char*)rd[i].data, repl_string);
2476       offset = strlen(new_soa_data)+1;
2477       pos = new_soa_data+offset;
2478       expand_plus(&pos, (char*)rd[i].data+offset, repl_string);
2479       offset += strlen(new_soa_data+offset)+1;
2480       /* cpy the 4 numbers serial refresh retry and expire */
2481       memcpy(new_soa_data+offset, (char*)rd[i].data+offset, sizeof(uint32_t)*5);
2482       offset += sizeof(uint32_t)*5;
2483       p_rd[i].data_size = offset;
2484       p_rd[i].data = new_soa_data;
2485     }
2486     else
2487     {
2488       pos = new_rr_data;
2489       expand_plus(&pos, (char*)rd[i].data, repl_string);
2490       p_rd[i].data_size = strlen(new_rr_data)+1;
2491       p_rd[i].data = new_rr_data;
2492     }
2493     
2494   }
2495
2496   rlh->proc(rlh->proc_cls, rd_count, p_rd);
2497   GNUNET_free(rlh);
2498   
2499 }
2500
2501 /**
2502  * Process DHT lookup result for record.
2503  *
2504  * @param cls the closure
2505  * @param rh resolver handle
2506  * @param rd_count number of results
2507  * @param rd record data
2508  */
2509 static void
2510 handle_record_dht(void* cls, struct ResolverHandle *rh,
2511                        unsigned int rd_count,
2512                        const struct GNUNET_NAMESTORE_RecordData *rd)
2513 {
2514   struct RecordLookupHandle* rlh;
2515
2516   rlh = (struct RecordLookupHandle*)cls;
2517   if (rd_count == 0)
2518   {
2519     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2520                "GNS_PHASE_REC-%d: No records for %s found in DHT. Aborting\n",
2521                rh->id, rh->name);
2522     /* give up, cannot resolve */
2523     finish_lookup(rh, rlh, 0, NULL);
2524     free_resolver_handle(rh);
2525     return;
2526   }
2527
2528   /* results found yay */
2529   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2530              "GNS_PHASE_REC-%d: Record resolved from DHT!", rh->id);
2531
2532   finish_lookup(rh, rlh, rd_count, rd);
2533   free_resolver_handle(rh);
2534
2535 }
2536
2537
2538
2539
2540 /**
2541  * Process namestore lookup result for record.
2542  *
2543  * @param cls the closure
2544  * @param rh resolver handle
2545  * @param rd_count number of results
2546  * @param rd record data
2547  */
2548 static void
2549 handle_record_ns (void* cls, struct ResolverHandle *rh,
2550                   unsigned int rd_count,
2551                   const struct GNUNET_NAMESTORE_RecordData *rd)
2552 {
2553   struct RecordLookupHandle* rlh;
2554   rlh = (struct RecordLookupHandle*) cls;
2555   int check_dht = GNUNET_YES;
2556
2557   if (rd_count == 0)
2558   {
2559     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2560                "GNS_PHASE_REC-%d: NS returned no records. (status: %d)!\n",
2561                rh->id,
2562                rh->status);
2563     
2564     /**
2565      * There are 5 conditions that have to met for us to consult the DHT:
2566      * 1. The entry in the DHT is RSL_RECORD_EXPIRED OR
2567      * 2. No entry in the NS existed AND
2568      * 3. The zone queried is not the local resolver's zone AND
2569      * 4. The name that was looked up is '+'
2570      *    because if it was any other canonical name we either already queried
2571      *    the DHT for the authority in the authority lookup phase (and thus
2572      *    would already have an entry in the NS for the record)
2573      * 5. We are not in cache only mode
2574      */
2575     if (((rh->status & RSL_RECORD_EXPIRED) != 0) &&
2576         ((rh->status & RSL_RECORD_EXISTS) == 0) )
2577       check_dht = GNUNET_NO;
2578     
2579     if (0 != GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2580                                           &rh->private_local_zone))
2581       check_dht = GNUNET_NO;
2582     
2583     if ((strcmp (rh->name, "+") != 0) && (is_srv (rh->name) != 0))
2584         check_dht = GNUNET_NO;
2585
2586
2587     if (rh->only_cached == GNUNET_YES)
2588       check_dht = GNUNET_NO;
2589     
2590     if (GNUNET_YES == check_dht)
2591     {
2592       rh->proc = &handle_record_dht;
2593       resolve_record_dht(rh);
2594       return;
2595     }
2596     /* give up, cannot resolve */
2597     finish_lookup(rh, rlh, 0, NULL);
2598     free_resolver_handle(rh);
2599     return;
2600   }
2601
2602   /* results found yay */
2603   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2604              "GNS_PHASE_REC-%d: Record resolved from namestore!", rh->id);
2605
2606   finish_lookup(rh, rlh, rd_count, rd);
2607
2608   free_resolver_handle(rh);
2609
2610 }
2611
2612
2613 /**
2614  * Move one level up in the domain hierarchy and return the
2615  * passed top level domain.
2616  *
2617  * @param name the domain
2618  * @param dest the destination where the tld will be put
2619  */
2620 void
2621 pop_tld(char* name, char* dest)
2622 {
2623   uint32_t len;
2624
2625   if (is_canonical (name))
2626   {
2627     strcpy(dest, name);
2628     strcpy(name, "");
2629     return;
2630   }
2631
2632   for (len = strlen(name); len > 0; len--)
2633   {
2634     if (*(name+len) == '.')
2635       break;
2636   }
2637   
2638   //Was canonical?
2639   if (len == 0)
2640     return;
2641
2642   name[len] = '\0';
2643
2644   strcpy(dest, (name+len+1));
2645 }
2646
2647 /**
2648  * Checks if name is in tld
2649  *
2650  * @param name the name to check
2651  * @param tld the TLD to check for
2652  * @return GNUNET_YES or GNUNET_NO
2653  */
2654 int
2655 is_tld(const char* name, const char* tld)
2656 {
2657   int offset = 0;
2658
2659   if (strlen(name) <= strlen(tld))
2660   {
2661     return GNUNET_NO;
2662   }
2663   
2664   offset = strlen(name)-strlen(tld);
2665   if (strcmp(name+offset, tld) != 0)
2666   {
2667     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2668                "%s is not in .%s TLD\n", name, tld);
2669     return GNUNET_NO;
2670   }
2671   return GNUNET_YES;
2672 }
2673
2674 /**
2675  * DHT resolution for delegation finished. Processing result.
2676  *
2677  * @param cls the closure
2678  * @param rh resolver handle
2679  * @param rd_count number of results (always 0)
2680  * @param rd record data (always NULL)
2681  */
2682 static void
2683 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
2684                           unsigned int rd_count,
2685                           const struct GNUNET_NAMESTORE_RecordData *rd)
2686 {
2687   struct RecordLookupHandle* rlh;
2688   rlh = (struct RecordLookupHandle*) cls;
2689   
2690
2691   if (strcmp(rh->name, "") == 0)
2692   {
2693     if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
2694     {
2695       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2696                  "GNS_PHASE_DELEGATE_DHT-%llu: Resolved queried PKEY via DHT.\n",
2697                  rh->id);
2698       finish_lookup(rh, rlh, rd_count, rd);
2699       free_resolver_handle(rh);
2700       return;
2701     }
2702     /* We resolved full name for delegation. resolving record */
2703     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2704      "GNS_PHASE_DELEGATE_DHT-%llu: Resolved full name for delegation via DHT.\n",
2705      rh->id);
2706     strcpy(rh->name, "+\0");
2707     rh->proc = &handle_record_ns;
2708     resolve_record_ns(rh);
2709     return;
2710   }
2711
2712   /**
2713    * we still have some left
2714    **/
2715   if (is_canonical(rh->name))
2716   {
2717     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2718              "GNS_PHASE_DELEGATE_DHT-%llu: Resolving canonical record %s in ns\n",
2719              rh->id,
2720              rh->name);
2721     rh->proc = &handle_record_ns;
2722     resolve_record_ns(rh);
2723     return;
2724   }
2725   /* give up, cannot resolve */
2726   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2727  "GNS_PHASE_DELEGATE_DHT-%llu: Cannot fully resolve delegation for %s via DHT!\n",
2728  rh->id, rh->name);
2729   finish_lookup(rh, rlh, 0, NULL);
2730   free_resolver_handle(rh);
2731 }
2732
2733
2734 /**
2735  * Start DHT lookup for a name -> PKEY (compare NS) record in
2736  * rh->authority's zone
2737  *
2738  * @param rh the pending gns query
2739  */
2740 static void
2741 resolve_delegation_dht(struct ResolverHandle *rh)
2742 {
2743   uint32_t xquery;
2744   struct GNUNET_CRYPTO_ShortHashCode name_hash;
2745   struct GNUNET_HashCode name_hash_double;
2746   struct GNUNET_HashCode zone_hash_double;
2747   struct GNUNET_HashCode lookup_key;
2748   struct ResolverHandle *rh_heap_root;
2749   
2750   pop_tld(rh->name, rh->authority_name); 
2751   GNUNET_CRYPTO_short_hash(rh->authority_name,
2752                      strlen(rh->authority_name),
2753                      &name_hash);
2754   GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
2755   GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
2756   GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
2757   
2758   rh->dht_heap_node = NULL;
2759
2760   if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
2761   {
2762     //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
2763     //                                          &dht_authority_lookup_timeout,
2764     //                                                   rh);
2765     rh->timeout_cont = &dht_authority_lookup_timeout;
2766     rh->timeout_cont_cls = rh;
2767   }
2768   else 
2769   {
2770     if (max_allowed_background_queries <=
2771         GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
2772     {
2773       /* terminate oldest lookup */
2774       rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
2775       GNUNET_DHT_get_stop(rh_heap_root->get_handle);
2776       rh_heap_root->dht_heap_node = NULL;
2777       
2778       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2779         "GNS_PHASE_DELEGATE_DHT-%llu: Replacing oldest background query for %s\n",
2780         rh->id, rh_heap_root->authority_name);
2781       
2782       rh_heap_root->proc(rh_heap_root->proc_cls,
2783                          rh_heap_root,
2784                          0,
2785                          NULL);
2786     }
2787     rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
2788                                          rh,
2789                                          GNUNET_TIME_absolute_get().abs_value);
2790   }
2791   
2792   xquery = htonl(GNUNET_GNS_RECORD_PKEY);
2793   
2794   GNUNET_assert(rh->get_handle == NULL);
2795   rh->get_handle = GNUNET_DHT_get_start(dht_handle,
2796                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
2797                        &lookup_key,
2798                        DHT_GNS_REPLICATION_LEVEL,
2799                        GNUNET_DHT_RO_NONE,
2800                        &xquery,
2801                        sizeof(xquery),
2802                        &process_delegation_result_dht,
2803                        rh);
2804
2805 }
2806
2807
2808 /**
2809  * Namestore resolution for delegation finished. Processing result.
2810  *
2811  * @param cls the closure
2812  * @param rh resolver handle
2813  * @param rd_count number of results (always 0)
2814  * @param rd record data (always NULL)
2815  */
2816 static void
2817 handle_delegation_ns (void* cls, struct ResolverHandle *rh,
2818                       unsigned int rd_count,
2819                       const struct GNUNET_NAMESTORE_RecordData *rd)
2820 {
2821   struct RecordLookupHandle* rlh;
2822   rlh = (struct RecordLookupHandle*) cls;
2823   int check_dht = GNUNET_YES;
2824   int s_len = 0;
2825
2826   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2827              "GNS_PHASE_DELEGATE_NS-%llu: Resolution status: %d.\n",
2828              rh->id, rh->status);
2829
2830   if (rh->status & RSL_PKEY_REVOKED)
2831   {
2832     finish_lookup (rh, rlh, 0, NULL);
2833     free_resolver_handle (rh);
2834     return;
2835   }
2836   
2837   if (strcmp(rh->name, "") == 0)
2838   {
2839     
2840     /* We resolved full name for delegation. resolving record */
2841     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2842               "GNS_PHASE_DELEGATE_NS-%llu: Resolved full name for delegation.\n",
2843               rh->id);
2844     if (rh->status & RSL_CNAME_FOUND)
2845     {
2846       if (rlh->record_type == GNUNET_GNS_RECORD_TYPE_CNAME)
2847       {
2848         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2849                   "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried CNAME in NS.\n",
2850                   rh->id);
2851         strcpy (rh->name, rh->authority_name);
2852         finish_lookup (rh, rlh, rd_count, rd);
2853         free_resolver_handle (rh);
2854         return;
2855       }
2856       
2857       /* A .+ CNAME  */
2858       if (is_tld ((char*)rd->data, GNUNET_GNS_TLD_PLUS))
2859       {
2860         s_len = strlen (rd->data) - 2;
2861         memcpy (rh->name, rd->data, s_len);
2862         rh->name[s_len] = '\0';
2863         resolve_delegation_ns (rh);
2864         return;
2865       }
2866       else if (is_tld ((char*)rd->data, GNUNET_GNS_TLD_ZKEY))
2867       {
2868         gns_resolver_lookup_record (rh->authority,
2869                                     rh->private_local_zone,
2870                                     rlh->record_type,
2871                                     (char*)rd->data,
2872                                     rh->priv_key,
2873                                     rh->timeout,
2874                                     rh->only_cached,
2875                                     rlh->proc,
2876                                     rlh->proc_cls);
2877         GNUNET_free (rlh);
2878         free_resolver_handle (rh);
2879         return;
2880       }
2881       else
2882       {
2883         //Try DNS resolver
2884         strcpy (rh->dns_name, (char*)rd->data);
2885         resolve_dns_name (rh);
2886         return;
2887       }
2888
2889     }
2890     else if (rh->status & RSL_DELEGATE_VPN)
2891     {
2892       if (rlh->record_type == GNUNET_GNS_RECORD_VPN)
2893       {
2894         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2895                  "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried VPNRR in NS.\n",
2896                  rh->id);
2897         finish_lookup(rh, rlh, rd_count, rd);
2898         free_resolver_handle(rh);
2899         return;
2900       }
2901       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2902              "GNS_PHASE_DELEGATE_NS-%llu: VPN delegation starting.\n",
2903              rh->id);
2904       GNUNET_assert (NULL != rd);
2905       rh->proc = &handle_record_vpn;
2906       resolve_record_vpn (rh, rd_count, rd);
2907       return;
2908     }
2909     else if (rh->status & RSL_DELEGATE_NS)
2910     {
2911       if (rlh->record_type == GNUNET_GNS_RECORD_TYPE_NS)
2912       {
2913         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2914                    "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried NSRR in NS.\n",
2915                    rh->id);
2916         finish_lookup(rh, rlh, rd_count, rd);
2917         free_resolver_handle(rh);
2918         return;
2919       }
2920       
2921       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2922                  "GNS_PHASE_DELEGATE_NS-%llu: NS delegation starting.\n",
2923                  rh->id);
2924       GNUNET_assert (NULL != rd);
2925       rh->proc = &handle_record_ns;
2926       resolve_record_dns (rh, rd_count, rd);
2927       return;
2928     }
2929     else if (rh->status & RSL_DELEGATE_PKEY)
2930     {
2931       if (rh->status & RSL_PKEY_REVOKED)
2932       {
2933         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2934                    "GNS_PHASE_DELEGATE_NS-%llu: Resolved PKEY is revoked.\n",
2935                    rh->id);
2936         finish_lookup (rh, rlh, 0, NULL);
2937         free_resolver_handle (rh);
2938         return;
2939       }
2940       else if (rlh->record_type == GNUNET_GNS_RECORD_PKEY)
2941       {
2942         GNUNET_assert(rd_count == 1);
2943         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2944                    "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried PKEY in NS.\n",
2945                    rh->id);
2946         finish_lookup(rh, rlh, rd_count, rd);
2947         free_resolver_handle(rh);
2948         return;
2949       }
2950     }
2951     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2952                "GNS_PHASE_DELEGATE_NS-%llu: Resolving record +\n",
2953                rh->id);
2954     strcpy(rh->name, "+\0");
2955     rh->proc = &handle_record_ns;
2956     resolve_record_ns(rh);
2957     return;
2958   }
2959   
2960   if (rh->status & RSL_DELEGATE_NS)
2961   {
2962     if (rlh->record_type == GNUNET_GNS_RECORD_TYPE_NS)
2963     {
2964       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2965                  "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried NSRR in NS.\n",
2966                  rh->id);
2967       finish_lookup(rh, rlh, rd_count, rd);
2968       free_resolver_handle(rh);
2969       return;
2970     }
2971     
2972     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2973                "GNS_PHASE_DELEGATE_NS-%llu: NS delegation starting.\n",
2974                rh->id);
2975     GNUNET_assert (NULL != rd);
2976     rh->proc = &handle_record_ns;
2977     resolve_record_dns (rh, rd_count, rd);
2978     return;
2979   }
2980   
2981   /**
2982    * we still have some left
2983    * check if authority in ns is fresh
2984    * and exists
2985    * or we are authority
2986    **/
2987
2988   if ((rh->status & RSL_RECORD_EXISTS) &&
2989        !(rh->status & RSL_RECORD_EXPIRED))
2990     check_dht = GNUNET_NO;
2991
2992   if (0 == GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2993                                         &rh->private_local_zone))
2994     check_dht = GNUNET_NO;
2995
2996   if (rh->only_cached == GNUNET_YES)
2997     check_dht = GNUNET_NO;
2998
2999   if (check_dht == GNUNET_NO)
3000   {
3001     if (is_canonical(rh->name))
3002     {
3003       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3004                  "GNS_PHASE_DELEGATE_NS-%llu: Resolving canonical record %s\n",
3005                  rh->id,
3006                  rh->name);
3007       rh->proc = &handle_record_ns;
3008       resolve_record_ns(rh);
3009     }
3010     else
3011     {
3012       /* give up, cannot resolve */
3013       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3014           "GNS_PHASE_DELEGATE_NS-%llu: Cannot fully resolve delegation for %s!\n",
3015           rh->id,
3016           rh->name);
3017       finish_lookup(rh, rlh, rd_count, rd);
3018       //rlh->proc(rlh->proc_cls, 0, NULL);
3019     }
3020     return;
3021   }
3022
3023   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3024       "GNS_PHASE_DELEGATE_NS-%llu: Trying to resolve delegation for %s via DHT\n",
3025       rh->id, rh->name);
3026   rh->proc = &handle_delegation_dht;
3027   resolve_delegation_dht(rh);
3028 }
3029
3030
3031 /**
3032  * This is a callback function that should give us only PKEY
3033  * records. Used to query the namestore for the authority (PKEY)
3034  * for 'name'. It will recursively try to resolve the
3035  * authority for a given name from the namestore.
3036  *
3037  * @param cls the pending query
3038  * @param key the key of the zone we did the lookup
3039  * @param expiration expiration date of the record data set in the namestore
3040  * @param name the name for which we need an authority
3041  * @param rd_count the number of records with 'name'
3042  * @param rd the record data
3043  * @param signature the signature of the authority for the record data
3044  */
3045 static void
3046 process_delegation_result_ns (void* cls,
3047                    const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
3048                    struct GNUNET_TIME_Absolute expiration,
3049                    const char *name,
3050                    unsigned int rd_count,
3051                    const struct GNUNET_NAMESTORE_RecordData *rd,
3052                    const struct GNUNET_CRYPTO_RsaSignature *signature)
3053 {
3054   struct ResolverHandle *rh;
3055   struct GNUNET_TIME_Relative remaining_time;
3056   struct GNUNET_CRYPTO_ShortHashCode zone;
3057   char new_name[MAX_DNS_NAME_LENGTH];
3058   unsigned int i;
3059   struct GNUNET_TIME_Absolute et;
3060  
3061   rh = (struct ResolverHandle *)cls; 
3062   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3063           "GNS_PHASE_DELEGATE_NS-%llu: Got %d records from authority lookup\n",
3064           rh->id, rd_count);
3065
3066   GNUNET_CRYPTO_short_hash (key,
3067                       sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3068                       &zone);
3069   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
3070   
3071   rh->status = 0;
3072   
3073   if (name != NULL)
3074   {
3075     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3076                 "GNS_PHASE_DELEGATE_NS-%llu: Records with name %s exist.\n",
3077                 rh->id, name);
3078     rh->status |= RSL_RECORD_EXISTS;
3079   
3080     if (remaining_time.rel_value == 0)
3081     {
3082       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3083                   "GNS_PHASE_DELEGATE_NS-%llu: Record set %s expired.\n",
3084                   rh->id, name);
3085       rh->status |= RSL_RECORD_EXPIRED;
3086     }
3087   }
3088   
3089   /**
3090    * No authority found in namestore.
3091    */
3092   if (rd_count == 0)
3093   {
3094     /**
3095      * We did not find an authority in the namestore
3096      */
3097     
3098     /**
3099      * No PKEY in zone.
3100      * Promote this authority back to a name maybe it is
3101      * our record.
3102      */
3103     if (strcmp (rh->name, "") == 0)
3104     {
3105       /* simply promote back */
3106       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3107                   "GNS_PHASE_DELEGATE_NS-%llu: Promoting %s back to name\n",
3108                   rh->id, rh->authority_name);
3109       strcpy (rh->name, rh->authority_name);
3110     }
3111     else
3112     {
3113       /* add back to existing name */
3114       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3115                   "GNS_PHASE_DELEGATE_NS-%llu: Adding %s back to %s\n",
3116                   rh->id, rh->authority_name, rh->name);
3117       GNUNET_snprintf (new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
3118                        rh->name, rh->authority_name);
3119       strcpy (rh->name, new_name);
3120       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3121                   "GNS_PHASE_DELEGATE_NS-%llu: %s restored\n",
3122                   rh->id, rh->name);
3123     }
3124
3125     rh->proc (rh->proc_cls, rh, 0, NULL);
3126     return;
3127   }
3128
3129   /**
3130    * We found an authority that may be able to help us
3131    * move on with query
3132    * Note only 1 pkey should have been returned.. anything else would be strange
3133    */
3134   for (i=0; i < rd_count;i++)
3135   {
3136     
3137     /**
3138      * A CNAME. Like regular DNS this means the is no other record for this
3139      * name.
3140      */
3141     if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_CNAME)
3142     {
3143       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3144                  "GNS_PHASE_DELEGATE_NS-%llu: CNAME found.\n",
3145                  rh->id);
3146
3147       rh->status |= RSL_CNAME_FOUND;
3148       rh->proc (rh->proc_cls, rh, rd_count, rd);
3149       return;
3150     }
3151
3152     /**
3153      * Redirect via VPN
3154      */
3155     if (rd[i].record_type == GNUNET_GNS_RECORD_VPN)
3156     {
3157       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3158                  "GNS_PHASE_DELEGATE_NS-%llu: VPN found.\n",
3159                  rh->id);
3160       rh->status |= RSL_DELEGATE_VPN;
3161       rh->proc (rh->proc_cls, rh, rd_count, rd);
3162       return;
3163     }
3164
3165     /**
3166      * Redirect via NS
3167      * FIXME make optional
3168      */
3169     if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_NS)
3170     {
3171       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3172                  "GNS_PHASE_DELEGATE_NS-%llu: NS found.\n",
3173                  rh->id);
3174       rh->status |= RSL_DELEGATE_NS;
3175       rh->proc (rh->proc_cls, rh, rd_count, rd);
3176       return;
3177     }
3178   
3179     if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
3180       continue;
3181
3182     rh->status |= RSL_DELEGATE_PKEY;
3183
3184     if ((ignore_pending_records != 0) &&
3185         (rd[i].flags & GNUNET_NAMESTORE_RF_PENDING))
3186     {
3187       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3188      "GNS_PHASE_DELEGATE_NS-%llu: PKEY for %s is pending user confirmation.\n",
3189         rh->id,
3190         name);
3191       continue;
3192     }
3193     
3194     GNUNET_break (0 == (rd[i].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION));
3195     et.abs_value = rd[i].expiration_time;
3196     if ((GNUNET_TIME_absolute_get_remaining (et)).rel_value
3197          == 0)
3198     {
3199       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3200                   "GNS_PHASE_DELEGATE_NS-%llu: This pkey is expired.\n",
3201                   rh->id);
3202       if (remaining_time.rel_value == 0)
3203       {
3204         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3205                     "GNS_PHASE_DELEGATE_NS-%llu: This dht entry is expired.\n",
3206                     rh->id);
3207         rh->authority_chain_head->fresh = 0;
3208         rh->proc (rh->proc_cls, rh, 0, NULL);
3209         return;
3210       }
3211
3212       continue;
3213     }
3214
3215     /**
3216      * Resolve rest of query with new authority
3217      */
3218     GNUNET_assert (rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
3219     memcpy (&rh->authority, rd[i].data,
3220             sizeof (struct GNUNET_CRYPTO_ShortHashCode));
3221     struct AuthorityChain *auth = GNUNET_malloc(sizeof (struct AuthorityChain));
3222     auth->zone = rh->authority;
3223     memset (auth->name, 0, strlen (rh->authority_name)+1);
3224     strcpy (auth->name, rh->authority_name);
3225     GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
3226                                  rh->authority_chain_tail,
3227                                  auth);
3228     
3229     /* Check for key revocation and delegate */
3230     GNUNET_NAMESTORE_lookup_record (namestore_handle,
3231                                     &rh->authority,
3232                                     "+",
3233                                     GNUNET_GNS_RECORD_REV,
3234                                     &process_pkey_revocation_result_ns,
3235                                     rh);
3236     return;
3237   
3238   }
3239   
3240   /**
3241    * no answers found
3242    */
3243   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3244     "GNS_PHASE_DELEGATE_NS-%llu: Authority lookup and no PKEY...\n", rh->id);
3245   /**
3246    * If we have found some records for the LAST label
3247    * we return the results. Else null.
3248    */
3249   if (strcmp(rh->name, "") == 0)
3250   {
3251     /* Start shortening */
3252     if ((rh->priv_key != NULL) && is_canonical (rh->name))
3253     {
3254       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3255               "GNS_PHASE_DELEGATE_NS-%llu: Trying to shorten authority chain\n",
3256               rh->id);
3257       start_shorten (rh->authority_chain_tail,
3258                     rh->priv_key);
3259     }
3260     /* simply promote back */
3261     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3262                "GNS_PHASE_DELEGATE_NS-%llu: Promoting %s back to name\n",
3263                rh->id, rh->authority_name);
3264     strcpy(rh->name, rh->authority_name);
3265     rh->proc(rh->proc_cls, rh, rd_count, rd);
3266   }
3267   else
3268   {
3269     rh->proc(rh->proc_cls, rh, 0, NULL);
3270   }
3271 }
3272
3273
3274 /**
3275  * Resolve the delegation chain for the request in our namestore
3276  *
3277  * @param rh the resolver handle
3278  */
3279 static void
3280 resolve_delegation_ns (struct ResolverHandle *rh)
3281 {
3282   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3283              "GNS_PHASE_DELEGATE_NS-%llu: Resolving delegation for %s\n",
3284              rh->id, rh->name);
3285   pop_tld(rh->name, rh->authority_name);
3286   GNUNET_NAMESTORE_lookup_record(namestore_handle,
3287                                  &rh->authority,
3288                                  rh->authority_name,
3289                                  GNUNET_GNS_RECORD_ANY,
3290                                  &process_delegation_result_ns,
3291                                  rh);
3292
3293 }
3294
3295
3296 /**
3297  * Lookup of a record in a specific zone
3298  * calls lookup result processor on result
3299  *
3300  * @param zone the root zone
3301  * @param pzone the private local zone
3302  * @param record_type the record type to look up
3303  * @param name the name to look up
3304  * @param key a private key for use with PSEU import (can be NULL)
3305  * @param timeout timeout for resolution
3306  * @param only_cached GNUNET_NO to only check locally not DHT for performance
3307  * @param proc the processor to call on result
3308  * @param cls the closure to pass to proc
3309  */
3310 void
3311 gns_resolver_lookup_record (struct GNUNET_CRYPTO_ShortHashCode zone,
3312                             struct GNUNET_CRYPTO_ShortHashCode pzone,
3313                             uint32_t record_type,
3314                             const char* name,
3315                             struct GNUNET_CRYPTO_RsaPrivateKey *key,
3316                             struct GNUNET_TIME_Relative timeout,
3317                             int only_cached,
3318                             RecordLookupProcessor proc,
3319                             void* cls)
3320 {
3321   struct ResolverHandle *rh;
3322   struct RecordLookupHandle* rlh;
3323   char string_hash[MAX_DNS_LABEL_LENGTH];
3324   char nzkey[MAX_DNS_LABEL_LENGTH];
3325   char* nzkey_ptr = nzkey;
3326
3327   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3328               "Starting resolution for %s (type=%d)!\n",
3329               name, record_type);
3330
3331   
3332   if (is_canonical((char*)name) && (strcmp(GNUNET_GNS_TLD, name) != 0))
3333   {
3334     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3335                 "%s is canonical and not gnunet -> cannot resolve!\n", name);
3336     proc(cls, 0, NULL);
3337     return;
3338   }
3339   
3340   rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
3341   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
3342
3343   rh->authority = zone;
3344   rh->id = rid++;
3345   rh->proc_cls = rlh;
3346   rh->priv_key = key;
3347   rh->timeout = timeout;
3348   rh->get_handle = NULL;
3349   rh->private_local_zone = pzone;
3350   rh->only_cached = only_cached;
3351   
3352   if (NULL == key)
3353   {
3354     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3355                 "No shorten key for resolution\n");
3356   }
3357
3358   if (timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
3359   {
3360     /*
3361      * Set timeout for authority lookup phase to 1/2
3362      */
3363     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3364                 "Timeout for lookup set to %ds\n", rh->timeout.rel_value);
3365     rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
3366                                 GNUNET_TIME_relative_divide(timeout, 2),
3367                                                 &handle_lookup_timeout,
3368                                                 rh);
3369     rh->timeout_cont = &dht_authority_lookup_timeout;
3370     rh->timeout_cont_cls = rh;
3371   }
3372   else
3373   {
3374     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No timeout for query!\n");
3375     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3376   }
3377   
3378   if (strcmp(GNUNET_GNS_TLD, name) == 0)
3379   {
3380     /**
3381      * Only 'gnunet' given
3382      */
3383     strcpy(rh->name, "\0");
3384   }
3385   else
3386   {
3387     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3388                 "Checking for TLD...\n");
3389     if (is_zkey_tld(name) == GNUNET_YES)
3390     {
3391       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3392                   "TLD is zkey\n");
3393       /**
3394        * This is a zkey tld
3395        * build hash and use as initial authority
3396        */
3397       memset(rh->name, 0,
3398              strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
3399       memcpy(rh->name, name,
3400              strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
3401       pop_tld(rh->name, string_hash);
3402
3403       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3404                   "ZKEY is %s!\n", string_hash);
3405       
3406       GNUNET_STRINGS_utf8_toupper(string_hash, &nzkey_ptr);
3407
3408       if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(nzkey,
3409                                                       &rh->authority))
3410       {
3411         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3412                     "Cannot convert ZKEY %s to hash!\n", string_hash);
3413         GNUNET_free(rh);
3414         GNUNET_free(rlh);
3415         proc(cls, 0, NULL);
3416         return;
3417       }
3418
3419     }
3420     else
3421     {
3422       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3423                   "TLD is gnunet\n");
3424       /**
3425        * Presumably GNUNET tld
3426        */
3427       memset(rh->name, 0,
3428              strlen(name)-strlen(GNUNET_GNS_TLD));
3429       memcpy(rh->name, name,
3430              strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
3431     }
3432   }
3433   
3434   /**
3435    * Initialize authority chain
3436    */
3437   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
3438   rh->authority_chain_head->prev = NULL;
3439   rh->authority_chain_head->next = NULL;
3440   rh->authority_chain_tail = rh->authority_chain_head;
3441   rh->authority_chain_head->zone = rh->authority;
3442   
3443   /**
3444    * Copy original query into lookup handle
3445    */
3446   rlh->record_type = record_type;
3447   memset(rlh->name, 0, strlen(name) + 1);
3448   strcpy(rlh->name, name);
3449   rlh->proc = proc;
3450   rlh->proc_cls = cls;
3451
3452   rh->proc = &handle_delegation_ns;
3453   resolve_delegation_ns(rh);
3454 }
3455
3456 /******** END Record Resolver ***********/
3457
3458 /**
3459  * Callback calles by namestore for a zone to name
3460  * result
3461  *
3462  * @param cls the closure
3463  * @param zone_key the zone we queried
3464  * @param expire the expiration time of the name
3465  * @param name the name found or NULL
3466  * @param rd_len number of records for the name
3467  * @param rd the record data (PKEY) for the name
3468  * @param signature the signature for the record data
3469  */
3470 static void
3471 process_zone_to_name_shorten_root (void *cls,
3472                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
3473                  struct GNUNET_TIME_Absolute expire,
3474                  const char *name,
3475                  unsigned int rd_len,
3476                  const struct GNUNET_NAMESTORE_RecordData *rd,
3477                  const struct GNUNET_CRYPTO_RsaSignature *signature);
3478
3479
3480 /**
3481  * Callback called by namestore for a zone to name
3482  * result
3483  *
3484  * @param cls the closure
3485  * @param zone_key the zone we queried
3486  * @param expire the expiration time of the name
3487  * @param name the name found or NULL
3488  * @param rd_len number of records for the name
3489  * @param rd the record data (PKEY) for the name
3490  * @param signature the signature for the record data
3491  */
3492 static void
3493 process_zone_to_name_shorten_shorten (void *cls,
3494                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
3495                  struct GNUNET_TIME_Absolute expire,
3496                  const char *name,
3497                  unsigned int rd_len,
3498                  const struct GNUNET_NAMESTORE_RecordData *rd,
3499                  const struct GNUNET_CRYPTO_RsaSignature *signature)
3500 {
3501   struct ResolverHandle *rh = (struct ResolverHandle *)cls;
3502   struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
3503   struct AuthorityChain *next_authority;
3504
3505   char result[MAX_DNS_NAME_LENGTH];
3506   char tmp_name[MAX_DNS_NAME_LENGTH];
3507   size_t answer_len;
3508   
3509   /* we found a match in our own root zone */
3510   if (rd_len != 0)
3511   {
3512     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3513                "result strlen %d\n", strlen(name));
3514     answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
3515     memset(result, 0, answer_len);
3516
3517     if (strlen(rh->name) > 0)
3518     {
3519       sprintf (result, "%s.%s.%s.%s.%s",
3520                rh->name, name,
3521                nsh->shorten_zone_name, nsh->private_zone_name,
3522                GNUNET_GNS_TLD);
3523     }
3524     else
3525     {
3526       sprintf (result, "%s.%s.%s.%s", name,
3527                nsh->shorten_zone_name, nsh->private_zone_name,
3528                GNUNET_GNS_TLD);
3529     }
3530     
3531     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3532                "Found shorten result %s\n", result);
3533     if (strlen (nsh->result) > strlen (result))
3534       strcpy (nsh->result, result);
3535   }
3536   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3537                                         nsh->shorten_zone) == 0)
3538   {
3539     /**
3540      * This is our zone append .gnunet unless name is empty
3541      * (it shouldn't be, usually FIXME what happens if we
3542      * shorten to our zone to a "" record??)
3543      */
3544     
3545     sprintf (result, "%s.%s.%s.%s",
3546              rh->name,
3547              nsh->shorten_zone_name, nsh->private_zone_name,
3548              GNUNET_GNS_TLD);
3549     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3550                "Our zone: Found %s as shorten result\n", result);
3551     
3552     if (strlen (nsh->result) > strlen (result))
3553       strcpy (nsh->result, result);
3554     //nsh->proc(nsh->proc_cls, result);
3555     //GNUNET_free(nsh);
3556     //free_resolver_handle(rh);
3557     //return;
3558   }
3559   
3560   
3561   /**
3562    * No PSEU found.
3563    * continue with next authority if exists
3564    */
3565   if ((rh->authority_chain_head->next == NULL))
3566   {
3567     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3568                 "Sending %s as shorten result\n", nsh->result);
3569     nsh->proc(nsh->proc_cls, nsh->result);
3570     GNUNET_free (nsh);
3571     free_resolver_handle (rh);
3572     return;
3573   }
3574   next_authority = rh->authority_chain_head;
3575   
3576   GNUNET_snprintf(tmp_name, MAX_DNS_NAME_LENGTH,
3577                   "%s.%s", rh->name, next_authority->name);
3578   
3579   strcpy(rh->name, tmp_name);
3580   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3581              "No PSEU found for authority %s. Promoting back: %s\n",
3582              next_authority->name, rh->name);
3583   
3584   GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
3585                             rh->authority_chain_tail,
3586                             next_authority);
3587
3588   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3589                                  &rh->authority_chain_tail->zone,
3590                                  &rh->authority_chain_head->zone,
3591                                  &process_zone_to_name_shorten_root,
3592                                  rh);
3593 }
3594
3595 /**
3596  * Callback calles by namestore for a zone to name
3597  * result
3598  *
3599  * @param cls the closure
3600  * @param zone_key the zone we queried
3601  * @param expire the expiration time of the name
3602  * @param name the name found or NULL
3603  * @param rd_len number of records for the name
3604  * @param rd the record data (PKEY) for the name
3605  * @param signature the signature for the record data
3606  */
3607 static void
3608 process_zone_to_name_shorten_private (void *cls,
3609                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
3610                  struct GNUNET_TIME_Absolute expire,
3611                  const char *name,
3612                  unsigned int rd_len,
3613                  const struct GNUNET_NAMESTORE_RecordData *rd,
3614                  const struct GNUNET_CRYPTO_RsaSignature *signature)
3615 {
3616   struct ResolverHandle *rh = (struct ResolverHandle *)cls;
3617   struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
3618   struct AuthorityChain *next_authority;
3619
3620   char result[MAX_DNS_NAME_LENGTH];
3621   char tmp_name[MAX_DNS_NAME_LENGTH];
3622   size_t answer_len;
3623   
3624   /* we found a match in our own root zone */
3625   if (rd_len != 0)
3626   {
3627     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3628                "result strlen %d\n", strlen(name));
3629     answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
3630     memset(result, 0, answer_len);
3631
3632     if (strlen(rh->name) > 0)
3633     {
3634       sprintf (result, "%s.%s.%s", rh->name, name, GNUNET_GNS_TLD);
3635     }
3636     else
3637     {
3638       sprintf (result, "%s.%s", name, GNUNET_GNS_TLD);
3639     }
3640     
3641     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3642                "Found shorten result %s\n", result);
3643     if (strlen (nsh->result) > strlen (result))
3644       strcpy (nsh->result, result);
3645   }
3646   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3647                                         nsh->private_zone) == 0)
3648   {
3649     /**
3650      * This is our zone append .gnunet unless name is empty
3651      * (it shouldn't be, usually FIXME what happens if we
3652      * shorten to our zone to a "" record??)
3653      */
3654     
3655     sprintf (result, "%s.%s.%s",
3656              rh->name, nsh->private_zone_name, GNUNET_GNS_TLD);
3657     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3658                "Our private zone: Found %s as shorten result %s\n", result);
3659     if (strlen (nsh->result) > strlen (result))
3660       strcpy (nsh->result, result);
3661   }
3662   
3663   if (nsh->shorten_zone != NULL)
3664   {
3665     /* backtrack authorities for names in priv zone */
3666     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3667                                    nsh->shorten_zone,
3668                                    &rh->authority_chain_head->zone,
3669                                    &process_zone_to_name_shorten_shorten,
3670                                    rh);
3671   }
3672   else
3673   {
3674     /**
3675      * No PSEU found.
3676      * continue with next authority if exists
3677      */
3678     if ((rh->authority_chain_head->next == NULL))
3679     {
3680       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3681                  "Sending %s as shorten result\n", nsh->result);
3682       nsh->proc(nsh->proc_cls, nsh->result);
3683       GNUNET_free(nsh);
3684       free_resolver_handle(rh);
3685       return;
3686     }
3687     next_authority = rh->authority_chain_head;
3688     
3689     GNUNET_snprintf(tmp_name, MAX_DNS_NAME_LENGTH,
3690                     "%s.%s", rh->name, next_authority->name);
3691     
3692     strcpy(rh->name, tmp_name);
3693     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3694                "No PSEU found for authority %s. Promoting back: %s\n",
3695                next_authority->name, rh->name);
3696     
3697     GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
3698                               rh->authority_chain_tail,
3699                               next_authority);
3700
3701     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3702                                    &rh->authority_chain_tail->zone,
3703                                    &rh->authority_chain_head->zone,
3704                                    &process_zone_to_name_shorten_root,
3705                                    rh);
3706   }
3707 }
3708
3709 /**
3710  * Callback calles by namestore for a zone to name
3711  * result
3712  *
3713  * @param cls the closure
3714  * @param zone_key the zone we queried
3715  * @param expire the expiration time of the name
3716  * @param name the name found or NULL
3717  * @param rd_len number of records for the name
3718  * @param rd the record data (PKEY) for the name
3719  * @param signature the signature for the record data
3720  */
3721 static void
3722 process_zone_to_name_shorten_root (void *cls,
3723                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
3724                  struct GNUNET_TIME_Absolute expire,
3725                  const char *name,
3726                  unsigned int rd_len,
3727                  const struct GNUNET_NAMESTORE_RecordData *rd,
3728                  const struct GNUNET_CRYPTO_RsaSignature *signature)
3729 {
3730   struct ResolverHandle *rh = (struct ResolverHandle *)cls;
3731   struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
3732   struct AuthorityChain *next_authority;
3733
3734   char result[MAX_DNS_NAME_LENGTH];
3735   char tmp_name[MAX_DNS_NAME_LENGTH];
3736   size_t answer_len;
3737   
3738   /* we found a match in our own root zone */
3739   if (rd_len != 0)
3740   {
3741     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3742                "result strlen %d\n", strlen(name));
3743     answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
3744     memset(result, 0, answer_len);
3745
3746     if (strlen(rh->name) > 0)
3747     {
3748       sprintf (result, "%s.%s.%s", rh->name, name, GNUNET_GNS_TLD);
3749     }
3750     else
3751     {
3752       sprintf (result, "%s.%s", name, GNUNET_GNS_TLD);
3753     }
3754     
3755     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3756                "Found shorten result %s\n", result);
3757     if (strlen (nsh->result) > strlen (result))
3758       strcpy (nsh->result, result);
3759   }
3760   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3761                                         nsh->root_zone) == 0)
3762   {
3763     /**
3764      * This is our zone append .gnunet unless name is empty
3765      * (it shouldn't be, usually FIXME what happens if we
3766      * shorten to our zone to a "" record??)
3767      */
3768     
3769     sprintf (result, "%s.%s", rh->name, GNUNET_GNS_TLD);
3770     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3771                "Our zone: Found %s as shorten result\n", result);
3772     if (strlen (nsh->result) > strlen (result))
3773       strcpy (nsh->result, result);
3774   }
3775   
3776   if (nsh->private_zone != NULL)
3777   {
3778     /* backtrack authorities for names in priv zone */
3779     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3780                                    nsh->private_zone,
3781                                    &rh->authority_chain_head->zone,
3782                                    &process_zone_to_name_shorten_private,
3783                                    rh);
3784   }
3785   else
3786   {
3787     /**
3788      * No PSEU found.
3789      * continue with next authority if exists
3790      */
3791     if ((rh->authority_chain_head->next == NULL))
3792     {
3793       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3794                  "Sending %s as shorten result\n", nsh->result);
3795       nsh->proc(nsh->proc_cls, nsh->result);
3796       GNUNET_free(nsh);
3797       free_resolver_handle(rh);
3798       return;
3799     }
3800     next_authority = rh->authority_chain_head;
3801     
3802     GNUNET_snprintf(tmp_name, MAX_DNS_NAME_LENGTH,
3803                     "%s.%s", rh->name, next_authority->name);
3804     
3805     strcpy(rh->name, tmp_name);
3806     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3807                "No PSEU found for authority %s. Promoting back: %s\n",
3808                next_authority->name, rh->name);
3809     
3810     GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
3811                               rh->authority_chain_tail,
3812                               next_authority);
3813
3814     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3815                                    &rh->authority_chain_tail->zone,
3816                                    &rh->authority_chain_head->zone,
3817                                    &process_zone_to_name_shorten_root,
3818                                    rh);
3819   }
3820 }
3821
3822
3823 /**
3824  * Process result from namestore delegation lookup
3825  * for shorten operation
3826  *
3827  * @param cls the client shorten handle
3828  * @param rh the resolver handle
3829  * @param rd_count number of results (0)
3830  * @param rd data (NULL)
3831  */
3832 void
3833 handle_delegation_ns_shorten (void* cls,
3834                       struct ResolverHandle *rh,
3835                       uint32_t rd_count,
3836                       const struct GNUNET_NAMESTORE_RecordData *rd)
3837 {
3838   struct NameShortenHandle *nsh;
3839   char result[MAX_DNS_NAME_LENGTH];
3840
3841   nsh = (struct NameShortenHandle *)cls;
3842   
3843   /**
3844    * At this point rh->name contains the part of the name
3845    * that we do not have a PKEY in our namestore to resolve.
3846    * The authority chain in the resolver handle is now
3847    * useful to backtrack if needed
3848    */
3849   
3850   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3851              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
3852   memset(result, 0, sizeof (result));
3853
3854   if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3855                                    nsh->root_zone) == 0)
3856   {
3857     /**
3858      * This is our zone append .gnunet unless name is empty
3859      * (it shouldn't be, usually FIXME what happens if we
3860      * shorten to our zone to a "" record??)
3861      */
3862     
3863     sprintf (result, "%s.%s", rh->name, GNUNET_GNS_TLD);
3864     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3865                "Our zone: Found %s as shorten result\n", result);
3866     
3867     if (strlen (nsh->result) > strlen (result))
3868       strcpy (nsh->result, result);
3869
3870   }
3871   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3872                                         nsh->private_zone) == 0)
3873   {
3874     /**
3875      * This is our zone append .gnunet unless name is empty
3876      * (it shouldn't be, usually FIXME what happens if we
3877      * shorten to our zone to a "" record??)
3878      */
3879     
3880     sprintf (result, "%s.%s.%s",
3881              rh->name, nsh->private_zone_name, GNUNET_GNS_TLD);
3882     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3883                "Our zone: Found %s as shorten result %s\n", result);
3884     
3885     if (strlen (nsh->result) > strlen (result))
3886       strcpy (nsh->result, result);
3887   }
3888   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3889                                         nsh->shorten_zone) == 0)
3890   {
3891     /**
3892      * This is our zone append .gnunet unless name is empty
3893      * (it shouldn't be, usually FIXME what happens if we
3894      * shorten to our zone to a "" record??)
3895      */
3896     
3897     sprintf (result, "%s.%s.%s",
3898              rh->name, nsh->private_zone_name, GNUNET_GNS_TLD);
3899     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3900                "Our zone: Found %s as shorten result\n", result);
3901     
3902     if (strlen (nsh->result) > strlen (result))
3903       strcpy (nsh->result, result);
3904   }
3905   
3906   
3907   /* backtrack authorities for names */
3908   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3909                                  nsh->root_zone,
3910                                  &rh->authority_chain_head->zone,
3911                                  &process_zone_to_name_shorten_root,
3912                                  rh);
3913   
3914 }
3915
3916
3917 /**
3918  * Callback calles by namestore for a zone to name
3919  * result
3920  *
3921  * @param cls the closure
3922  * @param zone_key the zone we queried
3923  * @param expire the expiration time of the name
3924  * @param name the name found or NULL
3925  * @param rd_len number of records for the name
3926  * @param rd the record data (PKEY) for the name
3927  * @param signature the signature for the record data
3928  */
3929 static void
3930 process_zone_to_name_zkey(void *cls,
3931                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
3932                  struct GNUNET_TIME_Absolute expire,
3933                  const char *name,
3934                  unsigned int rd_len,
3935                  const struct GNUNET_NAMESTORE_RecordData *rd,
3936                  const struct GNUNET_CRYPTO_RsaSignature *signature)
3937 {
3938   struct ResolverHandle *rh = cls;
3939   struct NameShortenHandle *nsh = rh->proc_cls;
3940   struct GNUNET_CRYPTO_ShortHashAsciiEncoded enc;
3941   char new_name[MAX_DNS_NAME_LENGTH];
3942
3943   /* zkey not in our zone */
3944   if (name == NULL)
3945   {
3946     /**
3947      * In this case we have not given this PKEY a name (yet)
3948      * It is either just not in our zone or not even cached
3949      * Since we do not know at this point we will not try to shorten
3950      * because PKEY import will happen if the user follows the zkey
3951      * link.
3952      */
3953     GNUNET_CRYPTO_short_hash_to_enc ((struct GNUNET_CRYPTO_ShortHashCode*)rd,
3954                                      &enc);
3955     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3956                "No name found for zkey %s returning verbatim!\n", enc);
3957     if (strcmp(rh->name, "") != 0)
3958       GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s.%s",
3959                       rh->name, enc, GNUNET_GNS_TLD_ZKEY);
3960     else
3961       GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
3962                       enc, GNUNET_GNS_TLD_ZKEY);
3963
3964     strcpy (nsh->result, new_name);
3965
3966     nsh->proc(nsh->proc_cls, new_name);
3967     GNUNET_free(nsh);
3968     free_resolver_handle(rh);
3969     return;
3970   }
3971   
3972   if (strcmp(rh->name, "") != 0)
3973     GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
3974                     rh->name, name);
3975   else
3976     strcpy(new_name, name);
3977
3978   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3979              "Continue shorten for %s!\n", new_name);
3980
3981   strcpy(rh->name, new_name);
3982   
3983   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
3984   rh->authority_chain_tail = rh->authority_chain_head;
3985   rh->authority_chain_head->zone = rh->authority;
3986   
3987   
3988   /* Start delegation resolution in our namestore */
3989   resolve_delegation_ns(rh);
3990 }
3991
3992
3993 /**
3994  * Shorten api from resolver
3995  *
3996  * @param zone the root zone to use
3997  * @param pzone the private zone to use
3998  * @param szone the shorten zone to use
3999  * @param name the name to shorten
4000  * @param private_zone_name name of the private zone
4001  * @param shorten_zone_name name of the shorten zone
4002  * @param proc the processor to call with result
4003  * @param proc_cls closure to pass to proc
4004  */
4005 void
4006 gns_resolver_shorten_name (struct GNUNET_CRYPTO_ShortHashCode *zone,
4007                            struct GNUNET_CRYPTO_ShortHashCode *pzone,
4008                            struct GNUNET_CRYPTO_ShortHashCode *szone,
4009                            const char* name,
4010                            const char* private_zone_name,
4011                            const char* shorten_zone_name,
4012                            ShortenResultProcessor proc,
4013                            void* proc_cls)
4014 {
4015   struct ResolverHandle *rh;
4016   struct NameShortenHandle *nsh;
4017   char string_hash[MAX_DNS_LABEL_LENGTH];
4018   struct GNUNET_CRYPTO_ShortHashCode zkey;
4019   char nzkey[MAX_DNS_LABEL_LENGTH];
4020   char* nzkey_ptr = nzkey;
4021
4022
4023   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4024               "Starting shorten for %s!\n", name);
4025   
4026   if (is_canonical ((char*)name))
4027   {
4028     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4029                 "%s is canonical. Returning verbatim\n", name);
4030     proc (proc_cls, name);
4031     return;
4032   }
4033
4034   nsh = GNUNET_malloc (sizeof (struct NameShortenHandle));
4035
4036   nsh->proc = proc;
4037   nsh->proc_cls = proc_cls;
4038   nsh->root_zone = zone;
4039   nsh->private_zone = pzone;
4040   nsh->shorten_zone = szone;
4041   strcpy (nsh->private_zone_name, private_zone_name);
4042   strcpy (nsh->shorten_zone_name, shorten_zone_name);
4043   strcpy (nsh->result, name);
4044   
4045   rh = GNUNET_malloc (sizeof (struct ResolverHandle));
4046   rh->authority = *zone;
4047   rh->id = rid++;
4048   rh->priv_key = NULL;
4049   rh->proc = &handle_delegation_ns_shorten;
4050   rh->proc_cls = nsh;
4051   rh->id = rid++;
4052   rh->private_local_zone = *zone;
4053   
4054   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4055                 "Checking for TLD...\n");
4056   if (is_zkey_tld (name) == GNUNET_YES)
4057   {
4058     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4059                 "TLD is zkey\n");
4060     /**
4061      * This is a zkey tld
4062      * build hash and use as initial authority
4063      * FIXME sscanf
4064      */
4065     memset (rh->name, 0,
4066             strlen (name)-strlen (GNUNET_GNS_TLD_ZKEY));
4067     memcpy (rh->name, name,
4068             strlen(name)-strlen (GNUNET_GNS_TLD_ZKEY) - 1);
4069     pop_tld (rh->name, string_hash);
4070
4071     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4072                 "ZKEY is %s!\n", string_hash);
4073     
4074     GNUNET_STRINGS_utf8_toupper (string_hash, &nzkey_ptr);
4075
4076     if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string (nzkey,
4077                                                            &zkey))
4078     {
4079       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4080                   "Cannot convert ZKEY %s to hash!\n", nzkey);
4081       GNUNET_free (rh);
4082       GNUNET_free (nsh);
4083       proc (proc_cls, name);
4084       return;
4085     }
4086
4087     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
4088                                    zone, //ours
4089                                    &zkey,
4090                                    &process_zone_to_name_zkey,
4091                                    rh);
4092     return;
4093
4094   }
4095   else
4096   {
4097     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4098                 "TLD is gnunet\n");
4099     /**
4100      * Presumably GNUNET tld
4101      */
4102     memset (rh->name, 0,
4103             strlen (name)-strlen (GNUNET_GNS_TLD));
4104     memcpy (rh->name, name,
4105             strlen (name)-strlen (GNUNET_GNS_TLD) - 1);
4106   }
4107
4108   rh->authority_chain_head = GNUNET_malloc (sizeof (struct AuthorityChain));
4109   rh->authority_chain_tail = rh->authority_chain_head;
4110   rh->authority_chain_head->zone = *zone;
4111   
4112   
4113   /* Start delegation resolution in our namestore */
4114   resolve_delegation_ns (rh);
4115 }
4116
4117 /*********** END NAME SHORTEN ********************/
4118
4119
4120 /**
4121  * Process result from namestore delegation lookup
4122  * for get authority operation
4123  *
4124  * @param cls the client get auth handle
4125  * @param rh the resolver handle
4126  * @param rd_count number of results (0)
4127  * @param rd data (NULL)
4128  */
4129 void
4130 handle_delegation_result_ns_get_auth(void* cls,
4131                       struct ResolverHandle *rh,
4132                       uint32_t rd_count,
4133                       const struct GNUNET_NAMESTORE_RecordData *rd)
4134 {
4135   struct GetNameAuthorityHandle* nah;
4136   char result[MAX_DNS_NAME_LENGTH];
4137   size_t answer_len;
4138
4139   nah = (struct GetNameAuthorityHandle*) rh->proc_cls;
4140   
4141   /**
4142    * At this point rh->name contains the part of the name
4143    * that we do not have a PKEY in our namestore to resolve.
4144    * The authority chain in the resolver handle is now
4145    * useful to backtrack if needed
4146    */
4147   
4148   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4149              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
4150
4151   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4152              "Building response!\n");
4153   if (is_canonical(rh->name))
4154   {
4155     /**
4156      * We successfully resolved the authority in the ns
4157      * FIXME for our purposes this is fine
4158      * but maybe we want to have an api that also looks
4159      * into the dht (i.e. option in message)
4160      **/
4161     if (strlen(rh->name) > strlen(nah->name))
4162     {
4163       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4164                  "Record name longer than original lookup name... odd!\n");
4165       //FIXME to sth here
4166     }
4167
4168     answer_len = strlen(nah->name) - strlen(rh->name)
4169       + strlen(GNUNET_GNS_TLD) + 1;
4170     memset(result, 0, answer_len);
4171     strcpy(result, nah->name + strlen(rh->name) + 1);
4172
4173     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4174                "Got authority result %s\n", result);
4175     
4176     nah->proc(nah->proc_cls, result);
4177     GNUNET_free(nah);
4178     free_resolver_handle(rh);
4179   }
4180   else
4181   {
4182     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4183                "Unable to resolve authority for remaining %s!\n", rh->name);
4184     nah->proc(nah->proc_cls, "");
4185     GNUNET_free(nah);
4186     free_resolver_handle(rh);
4187   }
4188
4189
4190 }
4191
4192
4193 /**
4194  * Tries to resolve the authority for name
4195  * in our namestore
4196  *
4197  * @param zone the root zone to look up for
4198  * @param pzone the private local zone
4199  * @param name the name to lookup up
4200  * @param proc the processor to call when finished
4201  * @param proc_cls the closure to pass to the processor
4202  */
4203 void
4204 gns_resolver_get_authority(struct GNUNET_CRYPTO_ShortHashCode zone,
4205                            struct GNUNET_CRYPTO_ShortHashCode pzone,
4206                            const char* name,
4207                            GetAuthorityResultProcessor proc,
4208                            void* proc_cls)
4209 {
4210   struct ResolverHandle *rh;
4211   struct GetNameAuthorityHandle *nah;
4212
4213   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4214               "Starting authority resolution for %s!\n", name);
4215
4216   nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
4217   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
4218   rh->authority = zone;
4219   rh->id = rid++;
4220   rh->private_local_zone = pzone;
4221   
4222   if (strcmp(GNUNET_GNS_TLD, name) == 0)
4223   {
4224     strcpy(rh->name, "\0");
4225   }
4226   else
4227   {
4228     memset(rh->name, 0,
4229            strlen(name)-strlen(GNUNET_GNS_TLD));
4230     memcpy(rh->name, name,
4231            strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
4232   }
4233
4234   memset(nah->name, 0,
4235          strlen(name)+1);
4236   strcpy(nah->name, name);
4237   
4238   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
4239   rh->authority_chain_tail = rh->authority_chain_head;
4240   rh->authority_chain_head->zone = zone;
4241   rh->proc = &handle_delegation_result_ns_get_auth;
4242   rh->proc_cls = (void*)nah;
4243
4244   nah->proc = proc;
4245   nah->proc_cls = proc_cls;
4246
4247   /* Start delegation resolution in our namestore */
4248   resolve_delegation_ns(rh);
4249
4250 }
4251
4252 /******** END GET AUTHORITY *************/
4253
4254 /* end of gnunet-service-gns_resolver.c */