2 This file is part of GNUnet.
3 (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
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.
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.
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.
24 * @file gns/gnunet-service-gns_resolver.c
25 * @brief GNUnet GNS resolver logic
26 * @author Martin Schanzenbach
30 #include "gnunet_util_lib.h"
31 #include "gnunet_transport_service.h"
32 #include "gnunet_dns_service.h"
33 #include "gnunet_dht_service.h"
34 #include "gnunet_namestore_service.h"
35 #include "gnunet_dns_service.h"
36 #include "gnunet_dnsparser_lib.h"
37 #include "gnunet_gns_service.h"
38 #include "block_gns.h"
40 #include "gnunet-service-gns_resolver.h"
42 #define DHT_OPERATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)
43 #define DHT_LOOKUP_TIMEOUT DHT_OPERATION_TIMEOUT
44 #define DHT_GNS_REPLICATION_LEVEL 5
45 #define MAX_DNS_LABEL_LENGTH 63
49 * Our handle to the namestore service
51 static struct GNUNET_NAMESTORE_Handle *namestore_handle;
54 * Resolver handle to the dht
56 static struct GNUNET_DHT_Handle *dht_handle;
59 * Heap for parallel DHT lookups
61 static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
64 * Maximum amount of parallel queries in background
66 static unsigned long long max_allowed_background_queries;
71 static struct GNUNET_CRYPTO_ShortHashCode local_zone;
74 * Namestore calls this function if we have record for this name.
75 * (or with rd_count=0 to indicate no matches)
77 * @param cls the pending query
78 * @param key the key of the zone we did the lookup
79 * @param expiration expiration date of the namestore entry
80 * @param name the name for which we need an authority
81 * @param rd_count the number of records with 'name'
82 * @param rd the record data
83 * @param signature the signature of the authority for the record data
86 process_pseu_lookup_ns(void* cls,
87 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
88 struct GNUNET_TIME_Absolute expiration,
89 const char *name, unsigned int rd_count,
90 const struct GNUNET_NAMESTORE_RecordData *rd,
91 const struct GNUNET_CRYPTO_RsaSignature *signature)
93 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
94 struct GNUNET_NAMESTORE_RecordData new_pkey;
98 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
99 "GNS_AUTO_PSEU: Name %s already taken in NS!\n", name);
100 if (0 == strcmp(gph->name, name))
102 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
103 "GNS_AUTO_PSEU: Intelligent replacement not implemented\n",
109 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
110 "GNS_AUTO_PSEU: Trying delegated name %s\n", gph->name);
111 memcpy(gph->new_name, gph->name, strlen(gph->name)+1);
112 GNUNET_NAMESTORE_lookup_record(namestore_handle,
115 GNUNET_GNS_RECORD_PSEU,
116 &process_pseu_lookup_ns,
122 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
123 "GNS_AUTO_PSEU: Name %s not taken in NS! Adding\n", gph->new_name);
125 new_pkey.expiration = GNUNET_TIME_absolute_get_forever ();
126 new_pkey.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode);
127 new_pkey.data = &gph->new_zone;
128 new_pkey.record_type = GNUNET_GNS_RECORD_PKEY;
129 GNUNET_NAMESTORE_record_create (namestore_handle,
140 * process result of a dht pseu lookup
142 * @param gph the handle
143 * @param name the pseu result or NULL
146 process_pseu_result(struct GetPseuAuthorityHandle* gph, char* name)
150 memcpy(gph->new_name, gph->name, strlen(gph->name)+1);
154 memcpy(gph->new_name, name, strlen(name)+1);
157 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
158 "GNS_AUTO_PSEU: Checking %s for collision in NS\n", gph->new_name);
161 * Check for collision
163 GNUNET_NAMESTORE_lookup_record(namestore_handle,
166 GNUNET_GNS_RECORD_PSEU,
167 &process_pseu_lookup_ns,
172 * Handle timeout for dht request
174 * @param cls the request handle as closure
175 * @param tc the task context
178 handle_auth_discovery_timeout(void *cls,
179 const struct GNUNET_SCHEDULER_TaskContext *tc)
181 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
183 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
184 "GNS_GET_AUTH: dht lookup for query PSEU timed out.\n");
185 GNUNET_DHT_get_stop (gph->get_handle);
186 gph->get_handle = NULL;
187 process_pseu_result(gph, NULL);
191 * Function called when we find a PSEU entry in the DHT
193 * @param cls the request handle
194 * @param exp lifetime
195 * @param key the key the record was stored under
196 * @param get_path get path
197 * @param get_path_length get path length
198 * @param put_path put path
199 * @param put_path_length put path length
200 * @param type the block type
201 * @param size the size of the record
202 * @param data the record data
205 process_auth_discovery_dht_result(void* cls,
206 struct GNUNET_TIME_Absolute exp,
207 const GNUNET_HashCode * key,
208 const struct GNUNET_PeerIdentity *get_path,
209 unsigned int get_path_length,
210 const struct GNUNET_PeerIdentity *put_path,
211 unsigned int put_path_length,
212 enum GNUNET_BLOCK_Type type,
213 size_t size, const void *data)
215 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
216 struct GNSNameRecordBlock *nrb;
217 char* rd_data = (char*)data;
223 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
224 "GNS_GET_AUTH: got dht result (size=%d)\n", size);
228 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
229 "GNS_GET_AUTH: got dht result null!\n", size);
235 nrb = (struct GNSNameRecordBlock*)data;
237 /* stop lookup and timeout task */
238 GNUNET_DHT_get_stop (gph->get_handle);
239 gph->get_handle = NULL;
240 GNUNET_SCHEDULER_cancel(gph->timeout);
242 gph->get_handle = NULL;
244 nrb = (struct GNSNameRecordBlock*)data;
246 name = (char*)&nrb[1];
247 num_records = ntohl(nrb->rd_count);
249 struct GNUNET_NAMESTORE_RecordData rd[num_records];
251 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
252 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
254 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
259 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
260 "GNS_GET_AUTH: Error deserializing data!\n");
266 for (i=0; i<num_records; i++)
268 if ((strcmp(name, "+") == 0) &&
269 (rd[i].record_type == GNUNET_GNS_RECORD_PSEU))
272 process_pseu_result(gph, (char*)rd[i].data);
278 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_GET_AUTH: no pseu in dht!\n");
279 process_pseu_result(gph, NULL);
283 * Callback called by namestore for a zone to name
286 * @param cls the closure
287 * @param zone_key the zone we queried
288 * @param expire the expiration time of the name
289 * @param name the name found or NULL
290 * @param rd_len number of records for the name
291 * @param rd the record data (PKEY) for the name
292 * @param signature the signature for the record data
295 process_zone_to_name_discover(void *cls,
296 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
297 struct GNUNET_TIME_Absolute expire,
300 const struct GNUNET_NAMESTORE_RecordData *rd,
301 const struct GNUNET_CRYPTO_RsaSignature *signature)
303 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
305 /* we found a match in our own zone */
308 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
309 "GNS_AUTO_PSEU: name for zone in our root %d\n", strlen(name));
319 struct GNUNET_CRYPTO_ShortHashCode name_hash;
320 GNUNET_HashCode lookup_key;
321 struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
322 GNUNET_HashCode name_hash_double;
323 GNUNET_HashCode zone_hash_double;
325 GNUNET_CRYPTO_short_hash("+", strlen("+"), &name_hash);
326 GNUNET_CRYPTO_short_hash_double (&name_hash, &name_hash_double);
327 GNUNET_CRYPTO_short_hash_double (&gph->new_zone, &zone_hash_double);
328 GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
329 GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
331 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
332 "GNS_AUTO_PSEU: starting dht lookup for %s with key: %s\n",
333 "+", (char*)&lookup_key_string);
335 gph->timeout = GNUNET_SCHEDULER_add_delayed(DHT_LOOKUP_TIMEOUT,
336 &handle_auth_discovery_timeout, gph);
338 xquery = htonl(GNUNET_GNS_RECORD_PSEU);
340 GNUNET_assert(gph->get_handle == NULL);
341 gph->get_handle = GNUNET_DHT_get_start(dht_handle,
342 GNUNET_TIME_UNIT_FOREVER_REL,
343 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
345 DHT_GNS_REPLICATION_LEVEL,
349 &process_auth_discovery_dht_result,
357 * Callback for new authories
359 * @param name the name given by delegation
360 * @param zone the authority
361 * @param our_zone our local zone
362 * @param key the private key of our authority
364 static void process_discovered_authority(char* name,
365 struct GNUNET_CRYPTO_ShortHashCode zone,
366 struct GNUNET_CRYPTO_ShortHashCode our_zone,
367 struct GNUNET_CRYPTO_RsaPrivateKey *key)
369 struct GetPseuAuthorityHandle *gph;
372 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
373 "GNS_AUTO_PSEU: New authority %s discovered\n",
376 gph = GNUNET_malloc(sizeof(struct GetPseuAuthorityHandle));
377 namelen = strlen(name) + 1;
378 memcpy(gph->name, name, namelen);
380 gph->new_zone = zone;
381 gph->zone = our_zone;
384 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
387 &process_zone_to_name_discover,
393 * Initialize the resolver
395 * @param nh the namestore handle
396 * @param dh the dht handle
397 * @param lz the local zone's hash
398 * @param max_bg_queries maximum number of parallel background queries in dht
399 * @return GNUNET_OK on success
402 gns_resolver_init(struct GNUNET_NAMESTORE_Handle *nh,
403 struct GNUNET_DHT_Handle *dh,
404 struct GNUNET_CRYPTO_ShortHashCode lz,
405 unsigned long long max_bg_queries)
407 namestore_handle = nh;
411 GNUNET_CONTAINER_heap_create(GNUNET_CONTAINER_HEAP_ORDER_MIN);
412 max_allowed_background_queries = max_bg_queries;
414 if ((namestore_handle != NULL) && (dht_handle != NULL))
418 return GNUNET_SYSERR;
422 * Cleanup background lookups
424 * @param cls closure to iterator
425 * @param node heap nodes
426 * @param element the resolver handle
427 * @param cost heap cost
428 * @return always GNUNET_YES
431 cleanup_pending_background_queries(void* cls,
432 struct GNUNET_CONTAINER_HeapNode *node,
434 GNUNET_CONTAINER_HeapCostType cost)
436 struct ResolverHandle *rh = (struct ResolverHandle *)element;
437 ResolverCleanupContinuation cont = cls;
439 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
440 "GNS_CLEANUP: Terminating background lookup for %s\n",
442 GNUNET_DHT_get_stop(rh->get_handle);
443 rh->get_handle = NULL;
444 rh->proc(rh->proc_cls, rh, 0, NULL);
446 GNUNET_CONTAINER_heap_remove_node(node);
448 if (GNUNET_CONTAINER_heap_get_size(dht_lookup_heap) == 0)
460 gns_resolver_cleanup(ResolverCleanupContinuation cont)
462 unsigned int s = GNUNET_CONTAINER_heap_get_size(dht_lookup_heap);
463 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
464 "GNS_CLEANUP: %d pending background queries to terminate\n", s);
467 GNUNET_CONTAINER_heap_iterate (dht_lookup_heap,
468 &cleanup_pending_background_queries,
476 * Helper function to free resolver handle
478 * @param rh the handle to free
481 free_resolver_handle(struct ResolverHandle* rh)
483 struct AuthorityChain *ac;
484 struct AuthorityChain *ac_next;
489 ac = rh->authority_chain_head;
502 * Callback when record data is put into namestore
504 * @param cls the closure
505 * @param success GNUNET_OK on success
506 * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
509 on_namestore_record_put_result(void *cls,
513 if (GNUNET_NO == success)
515 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
516 "GNS_NS: records already in namestore\n");
519 else if (GNUNET_YES == success)
521 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
522 "GNS_NS: records successfully put in namestore\n");
526 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
527 "GNS_NS: Error putting records into namestore: %s\n", emsg);
531 handle_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
533 struct ResolverHandle *rh = cls;
535 if (rh->timeout_cont)
536 rh->timeout_cont(rh->timeout_cont_cls, tc);
540 * Processor for background lookups in the DHT
542 * @param cls closure (NULL)
543 * @param rd_count number of records found (not 0)
544 * @param rd record data
547 background_lookup_result_processor(void *cls,
549 const struct GNUNET_NAMESTORE_RecordData *rd)
551 //We could do sth verbose/more useful here but it doesn't make any difference
552 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
553 "GNS_BG: background dht lookup for finished.\n");
557 * Handle timeout for DHT requests
559 * @param cls the request handle as closure
560 * @param tc the task context
563 dht_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
565 struct ResolverHandle *rh = cls;
566 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
567 char new_name[MAX_DNS_NAME_LENGTH];
569 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
570 "GNS_PHASE_REC: dht lookup for query %s timed out.\n",
573 * Start resolution in bg
575 //strcpy(new_name, rh->name);
576 //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD));
577 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
578 rh->name, GNUNET_GNS_TLD);
580 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
581 "GNS_PHASE_REC: Starting background lookup for %s type %d\n",
582 new_name, rlh->record_type);
584 gns_resolver_lookup_record(rh->authority,
588 GNUNET_TIME_UNIT_FOREVER_REL,
589 &background_lookup_result_processor,
591 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
593 GNUNET_DHT_get_stop (rh->get_handle);
594 rh->get_handle = NULL;
595 rh->proc(rh->proc_cls, rh, 0, NULL);
600 * Function called when we get a result from the dht
601 * for our record query
603 * @param cls the request handle
604 * @param exp lifetime
605 * @param key the key the record was stored under
606 * @param get_path get path
607 * @param get_path_length get path length
608 * @param put_path put path
609 * @param put_path_length put path length
610 * @param type the block type
611 * @param size the size of the record
612 * @param data the record data
615 process_record_result_dht(void* cls,
616 struct GNUNET_TIME_Absolute exp,
617 const GNUNET_HashCode * key,
618 const struct GNUNET_PeerIdentity *get_path,
619 unsigned int get_path_length,
620 const struct GNUNET_PeerIdentity *put_path,
621 unsigned int put_path_length,
622 enum GNUNET_BLOCK_Type type,
623 size_t size, const void *data)
625 struct ResolverHandle *rh;
626 struct RecordLookupHandle *rlh;
627 struct GNSNameRecordBlock *nrb;
628 uint32_t num_records;
630 char* rd_data = (char*)data;
634 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
635 "GNS_PHASE_REC: got dht result (size=%d)\n", size);
640 //FIXME maybe check expiration here, check block type
642 rh = (struct ResolverHandle *)cls;
643 rlh = (struct RecordLookupHandle *) rh->proc_cls;
644 nrb = (struct GNSNameRecordBlock*)data;
646 /* stop lookup and timeout task */
647 GNUNET_DHT_get_stop (rh->get_handle);
648 rh->get_handle = NULL;
650 if (rh->dht_heap_node != NULL)
652 GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
653 rh->dht_heap_node = NULL;
656 if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
658 GNUNET_SCHEDULER_cancel(rh->timeout_task);
659 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
662 rh->get_handle = NULL;
663 name = (char*)&nrb[1];
664 num_records = ntohl(nrb->rd_count);
666 struct GNUNET_NAMESTORE_RecordData rd[num_records];
668 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
669 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
671 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
676 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
680 for (i=0; i<num_records; i++)
682 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
683 "GNS_PHASE_REC: Got name: %s (wanted %s)\n", name, rh->name);
684 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
685 "GNS_PHASE_REC: Got type: %d\n",
687 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
688 "GNS_PHASE_REC: Got data length: %d\n", rd[i].data_size);
689 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
690 "GNS_PHASE_REC: Got flag %d\n", rd[i].flags);
692 if ((strcmp(name, rh->name) == 0) &&
693 (rd[i].record_type == rlh->record_type))
701 * FIXME check pubkey against existing key in namestore?
702 * https://gnunet.org/bugs/view.php?id=2179
705 /* Save to namestore */
706 GNUNET_NAMESTORE_record_put (namestore_handle,
713 &on_namestore_record_put_result, //cont
718 rh->proc(rh->proc_cls, rh, num_records, rd);
720 rh->proc(rh->proc_cls, rh, 0, NULL);
727 * Start DHT lookup for a (name -> query->record_type) record in
728 * rh->authority's zone
730 * @param rh the pending gns query context
733 resolve_record_dht(struct ResolverHandle *rh)
736 struct GNUNET_CRYPTO_ShortHashCode name_hash;
737 GNUNET_HashCode lookup_key;
738 GNUNET_HashCode name_hash_double;
739 GNUNET_HashCode zone_hash_double;
740 struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
741 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
742 struct ResolverHandle *rh_heap_root;
744 GNUNET_CRYPTO_short_hash(rh->name, strlen(rh->name), &name_hash);
745 GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
746 GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
747 GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
748 GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
750 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
751 "GNS_PHASE_REC: starting dht lookup for %s with key: %s\n",
752 rh->name, (char*)&lookup_key_string);
754 //rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
755 rh->dht_heap_node = NULL;
757 if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
760 * Update timeout if necessary
762 if (rh->timeout_task == GNUNET_SCHEDULER_NO_TASK)
765 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
766 "GNS_PHASE_REC: Adjusting timeout\n");
768 * Set timeout for authority lookup phase to 1/2
770 rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
771 GNUNET_TIME_relative_divide(rh->timeout, 2),
772 &handle_lookup_timeout,
775 //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
776 // &dht_lookup_timeout,
778 rh->timeout_cont = &dht_lookup_timeout;
779 rh->timeout_cont_cls = rh;
783 if (max_allowed_background_queries <=
784 GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
786 rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
787 GNUNET_DHT_get_stop(rh_heap_root->get_handle);
788 rh_heap_root->get_handle = NULL;
789 rh_heap_root->dht_heap_node = NULL;
791 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
792 "GNS_PHASE_REC: Replacing oldest background query for %s\n",
794 rh_heap_root->proc(rh_heap_root->proc_cls,
799 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
801 GNUNET_TIME_absolute_get().abs_value);
804 xquery = htonl(rlh->record_type);
806 GNUNET_assert(rh->get_handle == NULL);
807 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
808 GNUNET_TIME_UNIT_FOREVER_REL,
809 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
811 DHT_GNS_REPLICATION_LEVEL,
815 &process_record_result_dht,
822 * Namestore calls this function if we have record for this name.
823 * (or with rd_count=0 to indicate no matches)
825 * @param cls the pending query
826 * @param key the key of the zone we did the lookup
827 * @param expiration expiration date of the namestore entry
828 * @param name the name for which we need an authority
829 * @param rd_count the number of records with 'name'
830 * @param rd the record data
831 * @param signature the signature of the authority for the record data
834 process_record_result_ns(void* cls,
835 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
836 struct GNUNET_TIME_Absolute expiration,
837 const char *name, unsigned int rd_count,
838 const struct GNUNET_NAMESTORE_RecordData *rd,
839 const struct GNUNET_CRYPTO_RsaSignature *signature)
841 struct ResolverHandle *rh;
842 struct RecordLookupHandle *rlh;
843 struct GNUNET_TIME_Relative remaining_time;
844 struct GNUNET_CRYPTO_ShortHashCode zone;
846 rh = (struct ResolverHandle *) cls;
847 rlh = (struct RecordLookupHandle *)rh->proc_cls;
848 GNUNET_CRYPTO_short_hash(key,
849 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
851 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
859 rh->status |= EXISTS;
862 if (remaining_time.rel_value == 0)
864 rh->status |= EXPIRED;
870 * Lookup terminated and no results
872 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
873 "GNS_PHASE_REC: Namestore lookup for %s terminated without results\n",
876 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
877 "GNS_PHASE_REC: Record %s unknown in namestore\n",
880 * Our zone and no result? Cannot resolve TT
882 rh->proc(rh->proc_cls, rh, 0, NULL);
889 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
890 "GNS_PHASE_REC: Processing additional result %s from namestore\n",
893 for (i=0; i<rd_count;i++)
896 if (rd[i].record_type != rlh->record_type)
899 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
902 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
903 "GNS_PHASE_REC: This record is expired. Skipping\n");
914 if (rh->answered == 0)
916 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
917 "GNS_PHASE_REC: No answers found. This is odd!\n");
918 rh->proc(rh->proc_cls, rh, 0, NULL);
922 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
923 "GNS_PHASE_REC: Found %d answer(s) to query in %d records!\n",
924 rh->answered, rd_count);
926 rh->proc(rh->proc_cls, rh, rd_count, rd);
932 * The final phase of resolution.
933 * rh->name is a name that is canonical and we do not have a delegation.
934 * Query namestore for this record
936 * @param rh the pending lookup
939 resolve_record_ns(struct ResolverHandle *rh)
941 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
943 /* We cancel here as to not include the ns lookup in the timeout */
944 if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
946 GNUNET_SCHEDULER_cancel(rh->timeout_task);
947 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
951 * Try to resolve this record in our namestore.
952 * The name to resolve is now in rh->authority_name
953 * since we tried to resolve it to an authority
956 GNUNET_NAMESTORE_lookup_record(namestore_handle,
960 &process_record_result_ns,
967 * Handle timeout for DHT requests
969 * @param cls the request handle as closure
970 * @param tc the task context
973 dht_authority_lookup_timeout(void *cls,
974 const struct GNUNET_SCHEDULER_TaskContext *tc)
976 struct ResolverHandle *rh = cls;
977 struct RecordLookupHandle *rlh = rh->proc_cls;
978 char new_name[MAX_DNS_NAME_LENGTH];
980 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
981 "GNS_PHASE_DELEGATE: dht lookup for query %s timed out.\n",
984 rh->status |= TIMED_OUT;
986 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
988 GNUNET_DHT_get_stop (rh->get_handle);
989 rh->get_handle = NULL;
991 if (strcmp(rh->name, "") == 0)
994 * promote authority back to name and try to resolve record
996 strcpy(rh->name, rh->authority_name);
997 rh->proc(rh->proc_cls, rh, 0, NULL);
1002 * Start resolution in bg
1004 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH,
1005 "%s.%s", rh->name, GNUNET_GNS_TLD);
1006 //strcpy(new_name, rh->name);
1007 //strcpy(new_name+strlen(new_name), ".");
1008 //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD));
1010 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1011 "GNS_PHASE_DELEGATE: Starting background query for %s type %d\n",
1012 new_name, rlh->record_type);
1014 gns_resolver_lookup_record(rh->authority,
1018 GNUNET_TIME_UNIT_FOREVER_REL,
1019 &background_lookup_result_processor,
1022 rh->proc(rh->proc_cls, rh, 0, NULL);
1026 static void resolve_delegation_dht(struct ResolverHandle *rh);
1029 static void resolve_delegation_ns(struct ResolverHandle *rh);
1032 * Function called when we get a result from the dht
1033 * for our query. Recursively tries to resolve authorities
1036 * @param cls the request handle
1037 * @param exp lifetime
1038 * @param key the key the record was stored under
1039 * @param get_path get path
1040 * @param get_path_length get path length
1041 * @param put_path put path
1042 * @param put_path_length put path length
1043 * @param type the block type
1044 * @param size the size of the record
1045 * @param data the record data
1048 process_delegation_result_dht(void* cls,
1049 struct GNUNET_TIME_Absolute exp,
1050 const GNUNET_HashCode * key,
1051 const struct GNUNET_PeerIdentity *get_path,
1052 unsigned int get_path_length,
1053 const struct GNUNET_PeerIdentity *put_path,
1054 unsigned int put_path_length,
1055 enum GNUNET_BLOCK_Type type,
1056 size_t size, const void *data)
1058 struct ResolverHandle *rh;
1059 struct GNSNameRecordBlock *nrb;
1060 uint32_t num_records;
1062 char* rd_data = (char*) data;
1065 struct GNUNET_CRYPTO_ShortHashCode zone, name_hash;
1066 GNUNET_HashCode zone_hash_double, name_hash_double;
1068 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE: Got DHT result\n");
1073 //FIXME check expiration?
1075 rh = (struct ResolverHandle *)cls;
1076 nrb = (struct GNSNameRecordBlock*)data;
1078 /* stop dht lookup and timeout task */
1079 GNUNET_DHT_get_stop (rh->get_handle);
1081 rh->get_handle = NULL;
1083 if (rh->dht_heap_node != NULL)
1085 GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
1086 rh->dht_heap_node = NULL;
1089 num_records = ntohl(nrb->rd_count);
1090 name = (char*)&nrb[1];
1092 struct GNUNET_NAMESTORE_RecordData rd[num_records];
1094 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
1095 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
1097 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
1102 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1103 "GNS_PHASE_DELEGATE: Error deserializing data!\n");
1107 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1108 "GNS_PHASE_DELEGATE: Got name: %s (wanted %s)\n",
1109 name, rh->authority_name);
1110 for (i=0; i<num_records; i++)
1113 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1114 "GNS_PHASE_DELEGATE: Got name: %s (wanted %s)\n",
1115 name, rh->authority_name);
1116 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1117 "GNS_PHASE_DELEGATE: Got type: %d (wanted %d)\n",
1118 rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
1119 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1120 "GNS_PHASE_DELEGATE: Got data length: %d\n",
1122 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1123 "GNS_PHASE_DELEGATE: Got flag %d\n", rd[i].flags);
1125 if ((strcmp(name, rh->authority_name) == 0) &&
1126 (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
1128 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1129 "GNS_PHASE_DELEGATE: Authority found in DHT\n");
1131 memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1132 struct AuthorityChain *auth =
1133 GNUNET_malloc(sizeof(struct AuthorityChain));
1134 auth->zone = rh->authority;
1135 memset(auth->name, 0, strlen(rh->authority_name)+1);
1136 strcpy(auth->name, rh->authority_name);
1137 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1138 rh->authority_chain_tail,
1141 /** try to import pkey if private key available */
1143 process_discovered_authority(name, auth->zone,
1144 rh->authority_chain_tail->zone,
1151 GNUNET_CRYPTO_short_hash(name, strlen(name), &name_hash);
1152 GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1153 GNUNET_CRYPTO_hash_xor(key, &name_hash_double, &zone_hash_double);
1154 GNUNET_CRYPTO_short_hash_from_truncation (&zone_hash_double, &zone);
1156 /* Save to namestore */
1157 if (0 != GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_tail->zone,
1160 GNUNET_NAMESTORE_record_put (namestore_handle,
1167 &on_namestore_record_put_result, //cont
1177 * FIXME in this case. should we ask namestore again?
1179 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1180 "GNS_PHASE_DELEGATE: Answer from DHT for %s to resolve: %s\n",
1181 rh->authority_name, rh->name);
1182 if (strcmp(rh->name, "") == 0)
1183 rh->proc(rh->proc_cls, rh, 0, NULL);
1185 resolve_delegation_ns(rh);
1190 * No pkey but name exists
1193 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1194 "GNS_PHASE_DELEGATE: Adding %s back to %s\n",
1195 rh->authority_name, rh->name);
1196 if (strcmp(rh->name, "") == 0)
1197 strcpy(rh->name, rh->authority_name);
1199 GNUNET_snprintf(rh->name, MAX_DNS_NAME_LENGTH, "%s.%s",
1200 rh->name, rh->authority_name); //FIXME ret
1202 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1203 "GNS_PHASE_DELEGATE: %s restored\n", rh->name);
1204 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1205 "GNS_PHASE_DELEGATE: DHT authority lookup found no match!\n");
1206 rh->proc(rh->proc_cls, rh, 0, NULL);
1209 #define MAX_SOA_LENGTH sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)\
1210 +(MAX_DNS_NAME_LENGTH*2)
1211 #define MAX_MX_LENGTH sizeof(uint16_t)+MAX_DNS_NAME_LENGTH
1215 expand_plus(char** dest, char* src, char* repl)
1218 unsigned int s_len = strlen(src)+1;
1220 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1221 "GNS_POSTPROCESS: Got %s to expand with %s\n", src, repl);
1225 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1226 "GNS_POSTPROCESS: %s to short\n", src);
1228 /* no postprocessing */
1229 memcpy(*dest, src, s_len+1);
1233 if (0 == strcmp(src+s_len-3, ".+"))
1235 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1236 "GNS_POSTPROCESS: Expanding .+ in %s\n", src);
1237 memset(*dest, 0, s_len+strlen(repl)+strlen(GNUNET_GNS_TLD));
1239 pos = *dest+s_len-2;
1241 pos += strlen(repl);
1242 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1243 "GNS_POSTPROCESS: Expanded to %s\n", *dest);
1247 memcpy(*dest, src, s_len+1);
1255 finish_lookup(struct ResolverHandle *rh,
1256 struct RecordLookupHandle* rlh,
1257 unsigned int rd_count,
1258 const struct GNUNET_NAMESTORE_RecordData *rd)
1261 char new_rr_data[MAX_DNS_NAME_LENGTH];
1262 char new_mx_data[MAX_MX_LENGTH];
1263 char new_soa_data[MAX_SOA_LENGTH];
1264 struct GNUNET_NAMESTORE_RecordData p_rd[rd_count];
1267 unsigned int offset;
1269 if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1270 GNUNET_SCHEDULER_cancel(rh->timeout_task);
1273 memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData));
1275 for (i = 0; i < rd_count; i++)
1278 if (rd[i].record_type != GNUNET_GNS_RECORD_TYPE_NS &&
1279 rd[i].record_type != GNUNET_GNS_RECORD_TYPE_CNAME &&
1280 rd[i].record_type != GNUNET_GNS_RECORD_MX &&
1281 rd[i].record_type != GNUNET_GNS_RECORD_TYPE_SOA)
1283 p_rd[i].data = rd[i].data;
1288 * for all those records we 'should'
1289 * also try to resolve the A/AAAA records (RFC1035)
1290 * This is a feature and not important
1293 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1294 "GNS_POSTPROCESS: Postprocessing\n");
1296 if (strcmp(rh->name, "+") == 0)
1297 repl_string = rlh->name;
1299 repl_string = rlh->name+strlen(rh->name)+1;
1302 if (rd[i].record_type == GNUNET_GNS_RECORD_MX)
1304 memcpy(new_mx_data, (char*)rd[i].data, sizeof(uint16_t));
1305 offset = sizeof(uint16_t);
1306 pos = new_mx_data+offset;
1307 expand_plus(&pos, (char*)rd[i].data+sizeof(uint16_t),
1309 offset += strlen(new_mx_data+sizeof(uint16_t))+1;
1310 p_rd[i].data = new_mx_data;
1311 p_rd[i].data_size = offset;
1313 else if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_SOA)
1315 /* expand mname and rname */
1317 expand_plus(&pos, (char*)rd[i].data, repl_string);
1318 offset = strlen(new_soa_data)+1;
1319 pos = new_soa_data+offset;
1320 expand_plus(&pos, (char*)rd[i].data+offset, repl_string);
1321 offset += strlen(new_soa_data+offset)+1;
1322 /* cpy the 4 numbers serial refresh retry and expire */
1323 memcpy(new_soa_data+offset, (char*)rd[i].data+offset, sizeof(uint32_t)*5);
1324 offset += sizeof(uint32_t)*5;
1325 p_rd[i].data_size = offset;
1326 p_rd[i].data = new_soa_data;
1331 expand_plus(&pos, (char*)rd[i].data, repl_string);
1332 p_rd[i].data_size = strlen(new_rr_data)+1;
1333 p_rd[i].data = new_rr_data;
1338 rlh->proc(rlh->proc_cls, rd_count, p_rd);
1344 * Process DHT lookup result for record.
1346 * @param cls the closure
1347 * @param rh resolver handle
1348 * @param rd_count number of results
1349 * @param rd record data
1352 handle_record_dht(void* cls, struct ResolverHandle *rh,
1353 unsigned int rd_count,
1354 const struct GNUNET_NAMESTORE_RecordData *rd)
1356 struct RecordLookupHandle* rlh;
1358 rlh = (struct RecordLookupHandle*)cls;
1361 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1362 "GNS_PHASE_REC: No records for %s found in DHT. Aborting\n",
1364 /* give up, cannot resolve */
1365 finish_lookup(rh, rlh, 0, NULL);
1366 free_resolver_handle(rh);
1370 /* results found yay */
1371 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1372 "GNS_PHASE_REC: Record resolved from DHT!");
1374 finish_lookup(rh, rlh, rd_count, rd);
1375 free_resolver_handle(rh);
1381 * Process namestore lookup result for record.
1383 * @param cls the closure
1384 * @param rh resolver handle
1385 * @param rd_count number of results
1386 * @param rd record data
1389 handle_record_ns(void* cls, struct ResolverHandle *rh,
1390 unsigned int rd_count,
1391 const struct GNUNET_NAMESTORE_RecordData *rd)
1393 struct RecordLookupHandle* rlh;
1394 rlh = (struct RecordLookupHandle*) cls;
1397 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1398 "GNS_PHASE_REC: NS returned no records. (status: %d)!\n",
1402 * There are 4 conditions that have to met for us to consult the DHT:
1403 * 1. The entry in the DHT is EXPIRED AND
1404 * 2. No entry in the NS existed AND
1405 * 3. The zone queried is not the local resolver's zone AND
1406 * 4. The name that was looked up is '+'
1407 * because if it was any other canonical name we either already queried
1408 * the DHT for the authority in the authority lookup phase (and thus
1409 * would already have an entry in the NS for the record)
1411 if (rh->status & (EXPIRED | !EXISTS) &&
1412 GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1414 (strcmp(rh->name, "+") == 0))
1416 rh->proc = &handle_record_dht;
1417 resolve_record_dht(rh);
1420 /* give up, cannot resolve */
1421 finish_lookup(rh, rlh, 0, NULL);
1422 free_resolver_handle(rh);
1426 /* results found yay */
1427 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1428 "GNS_PHASE_REC: Record resolved from namestore!");
1430 finish_lookup(rh, rlh, rd_count, rd);
1432 free_resolver_handle(rh);
1438 * Determine if this name is canonical.
1440 * a.b.gnunet = not canonical
1443 * @param name the name to test
1444 * @return 1 if canonical
1447 is_canonical(char* name)
1449 uint32_t len = strlen(name);
1452 for (i=0; i<len; i++)
1454 if (*(name+i) == '.')
1461 * Move one level up in the domain hierarchy and return the
1462 * passed top level domain.
1464 * @param name the domain
1465 * @param dest the destination where the tld will be put
1468 pop_tld(char* name, char* dest)
1472 if (is_canonical(name))
1479 for (len = strlen(name); len > 0; len--)
1481 if (*(name+len) == '.')
1491 strcpy(dest, (name+len+1));
1495 * Checks if name is in tld
1497 * @param name the name to check
1498 * @param tld the TLD to check for
1499 * @return GNUNET_YES or GNUNET_NO
1502 is_tld(const char* name, const char* tld)
1506 if (strlen(name) <= strlen(tld))
1511 offset = strlen(name)-strlen(tld);
1512 if (strcmp(name+offset, tld) != 0)
1514 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1515 "%s is not in .%s TLD\n", name, tld);
1522 * DHT resolution for delegation finished. Processing result.
1524 * @param cls the closure
1525 * @param rh resolver handle
1526 * @param rd_count number of results (always 0)
1527 * @param rd record data (always NULL)
1530 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
1531 unsigned int rd_count,
1532 const struct GNUNET_NAMESTORE_RecordData *rd)
1534 struct RecordLookupHandle* rlh;
1535 rlh = (struct RecordLookupHandle*) cls;
1538 if (strcmp(rh->name, "") == 0)
1540 if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1542 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1543 "GNS_PHASE_DELEGATE: Resolved queried PKEY via DHT.\n");
1544 finish_lookup(rh, rlh, rd_count, rd);
1545 free_resolver_handle(rh);
1548 /* We resolved full name for delegation. resolving record */
1549 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1550 "GNS_PHASE_DELEGATE: Resolved full name for delegation via DHT.\n");
1551 strcpy(rh->name, "+\0");
1552 rh->proc = &handle_record_ns;
1553 resolve_record_ns(rh);
1558 * we still have some left
1560 if (is_canonical(rh->name))
1562 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1563 "GNS_PHASE_DELEGATE: Resolving canonical record %s in ns\n",
1565 rh->proc = &handle_record_ns;
1566 resolve_record_ns(rh);
1569 /* give up, cannot resolve */
1570 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1571 "GNS_PHASE_DELEGATE: Cannot fully resolve delegation for %s via DHT!\n",
1573 finish_lookup(rh, rlh, 0, NULL);
1574 free_resolver_handle(rh);
1579 * Start DHT lookup for a name -> PKEY (compare NS) record in
1580 * rh->authority's zone
1582 * @param rh the pending gns query
1585 resolve_delegation_dht(struct ResolverHandle *rh)
1588 struct GNUNET_CRYPTO_ShortHashCode name_hash;
1589 GNUNET_HashCode name_hash_double;
1590 GNUNET_HashCode zone_hash_double;
1591 GNUNET_HashCode lookup_key;
1592 struct ResolverHandle *rh_heap_root;
1594 pop_tld(rh->name, rh->authority_name);
1595 GNUNET_CRYPTO_short_hash(rh->authority_name,
1596 strlen(rh->authority_name),
1598 GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1599 GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
1600 GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
1602 rh->dht_heap_node = NULL;
1604 if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
1606 //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1607 // &dht_authority_lookup_timeout,
1609 rh->timeout_cont = &dht_authority_lookup_timeout;
1610 rh->timeout_cont_cls = rh;
1614 if (max_allowed_background_queries <=
1615 GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
1617 /* terminate oldest lookup */
1618 rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
1619 GNUNET_DHT_get_stop(rh_heap_root->get_handle);
1620 rh_heap_root->dht_heap_node = NULL;
1622 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1623 "GNS_PHASE_DELEGATE: Replacing oldest background query for %s\n",
1624 rh_heap_root->authority_name);
1626 rh_heap_root->proc(rh_heap_root->proc_cls,
1631 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
1633 GNUNET_TIME_absolute_get().abs_value);
1636 xquery = htonl(GNUNET_GNS_RECORD_PKEY);
1638 GNUNET_assert(rh->get_handle == NULL);
1639 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
1640 GNUNET_TIME_UNIT_FOREVER_REL,
1641 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1643 DHT_GNS_REPLICATION_LEVEL,
1647 &process_delegation_result_dht,
1654 * Namestore resolution for delegation finished. Processing result.
1656 * @param cls the closure
1657 * @param rh resolver handle
1658 * @param rd_count number of results (always 0)
1659 * @param rd record data (always NULL)
1662 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
1663 unsigned int rd_count,
1664 const struct GNUNET_NAMESTORE_RecordData *rd)
1666 struct RecordLookupHandle* rlh;
1667 rlh = (struct RecordLookupHandle*) cls;
1669 if (strcmp(rh->name, "") == 0)
1671 if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1673 GNUNET_assert(rd_count == 1);
1674 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1675 "GNS_PHASE_DELEGATE: Resolved queried PKEY in NS.\n");
1676 finish_lookup(rh, rlh, rd_count, rd);
1677 free_resolver_handle(rh);
1680 /* We resolved full name for delegation. resolving record */
1681 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1682 "GNS_PHASE_DELEGATE: Resolved full name for delegation.\n");
1683 strcpy(rh->name, "+\0");
1684 rh->proc = &handle_record_ns;
1685 resolve_record_ns(rh);
1690 * we still have some left
1691 * check if authority in ns is fresh
1693 * or we are authority
1695 if ((rh->status & (EXISTS | !EXPIRED)) ||
1696 !GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1697 &rh->authority_chain_tail->zone))
1699 if (is_canonical(rh->name))
1701 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1702 "GNS_PHASE_DELEGATE: Resolving canonical record %s\n",
1704 rh->proc = &handle_record_ns;
1705 resolve_record_ns(rh);
1709 /* give up, cannot resolve */
1710 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1711 "GNS_PHASE_DELEGATE: Cannot fully resolve delegation for %s!\n",
1713 rlh->proc(rlh->proc_cls, 0, NULL);
1718 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1719 "GNS_PHASE_DELEGATE: Trying to resolve delegation for %s via DHT\n",
1721 rh->proc = &handle_delegation_dht;
1722 resolve_delegation_dht(rh);
1728 * This is a callback function that should give us only PKEY
1729 * records. Used to query the namestore for the authority (PKEY)
1730 * for 'name'. It will recursively try to resolve the
1731 * authority for a given name from the namestore.
1733 * @param cls the pending query
1734 * @param key the key of the zone we did the lookup
1735 * @param expiration expiration date of the record data set in the namestore
1736 * @param name the name for which we need an authority
1737 * @param rd_count the number of records with 'name'
1738 * @param rd the record data
1739 * @param signature the signature of the authority for the record data
1742 process_delegation_result_ns(void* cls,
1743 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1744 struct GNUNET_TIME_Absolute expiration,
1746 unsigned int rd_count,
1747 const struct GNUNET_NAMESTORE_RecordData *rd,
1748 const struct GNUNET_CRYPTO_RsaSignature *signature)
1750 struct ResolverHandle *rh;
1751 struct GNUNET_TIME_Relative remaining_time;
1752 struct GNUNET_CRYPTO_ShortHashCode zone;
1753 char new_name[MAX_DNS_NAME_LENGTH];
1755 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1756 "GNS_PHASE_DELEGATE: Got %d records from authority lookup\n",
1759 rh = (struct ResolverHandle *)cls;
1760 GNUNET_CRYPTO_short_hash(key,
1761 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1763 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1769 rh->status |= EXISTS;
1772 if (remaining_time.rel_value == 0)
1774 rh->status |= EXPIRED;
1778 * No authority found in namestore.
1783 * We did not find an authority in the namestore
1788 * Promote this authority back to a name maybe it is
1791 if (strcmp(rh->name, "") == 0)
1793 /* simply promote back */
1794 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1795 "GNS_PHASE_DELEGATE: Promoting %s back to name\n",
1796 rh->authority_name);
1797 strcpy(rh->name, rh->authority_name);
1801 /* add back to existing name */
1802 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1803 "GNS_PHASE_DELEGATE: Adding %s back to %s\n",
1804 rh->authority_name, rh->name);
1805 //memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
1806 strcpy(new_name, rh->name);
1807 strcpy(new_name+strlen(new_name), ".");
1808 strcpy(new_name+strlen(new_name), rh->authority_name);
1809 strcpy(rh->name, new_name);
1810 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1811 "GNS_PHASE_DELEGATE: %s restored\n", rh->name);
1813 rh->proc(rh->proc_cls, rh, 0, NULL);
1818 * We found an authority that may be able to help us
1819 * move on with query
1820 * Note only 1 pkey should have been returned.. anything else would be strange
1823 for (i=0; i<rd_count;i++)
1826 if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
1829 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
1832 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1833 "GNS_PHASE_DELEGATE: This pkey is expired.\n");
1834 if (remaining_time.rel_value == 0)
1836 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1837 "GNS_PHASE_DELEGATE: This dht entry is expired.\n");
1838 rh->authority_chain_head->fresh = 0;
1839 rh->proc(rh->proc_cls, rh, 0, NULL);
1847 * Resolve rest of query with new authority
1849 GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
1850 memcpy(&rh->authority, rd[i].data,
1851 sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1852 struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
1853 auth->zone = rh->authority;
1854 memset(auth->name, 0, strlen(rh->authority_name)+1);
1855 strcpy(auth->name, rh->authority_name);
1856 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1857 rh->authority_chain_tail,
1861 * We are done with PKEY resolution if name is empty
1862 * else resolve again with new authority
1864 if (strcmp(rh->name, "") == 0)
1865 rh->proc(rh->proc_cls, rh, rd_count, rd);
1867 resolve_delegation_ns(rh);
1874 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1875 "GNS_PHASE_DELEGATE: Authority lookup and but no PKEY... never get here\n");
1876 rh->proc(rh->proc_cls, rh, 0, NULL);
1881 * Resolve the delegation chain for the request in our namestore
1883 * @param rh the resolver handle
1886 resolve_delegation_ns(struct ResolverHandle *rh)
1888 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1889 "GNS_PHASE_DELEGATE: Resolving delegation for %s\n", rh->name);
1890 pop_tld(rh->name, rh->authority_name);
1891 GNUNET_NAMESTORE_lookup_record(namestore_handle,
1894 GNUNET_GNS_RECORD_PKEY,
1895 &process_delegation_result_ns,
1902 * Lookup of a record in a specific zone
1903 * calls lookup result processor on result
1905 * @param zone the root zone
1906 * @param record_type the record type to look up
1907 * @param name the name to look up
1908 * @param key a private key for use with PSEU import (can be NULL)
1909 * @param timeout timeout for resolution
1910 * @param proc the processor to call on result
1911 * @param cls the closure to pass to proc
1914 gns_resolver_lookup_record(struct GNUNET_CRYPTO_ShortHashCode zone,
1915 uint32_t record_type,
1917 struct GNUNET_CRYPTO_RsaPrivateKey *key,
1918 struct GNUNET_TIME_Relative timeout,
1919 RecordLookupProcessor proc,
1922 struct ResolverHandle *rh;
1923 struct RecordLookupHandle* rlh;
1924 char string_hash[MAX_DNS_LABEL_LENGTH];
1925 uint8_t* normalized_zkey;
1926 char nzkey[MAX_DNS_LABEL_LENGTH];
1929 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1930 "Starting resolution for %s (type=%d)!\n",
1934 if (is_canonical((char*)name) && (strcmp(GNUNET_GNS_TLD, name) != 0))
1936 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1937 "%s is canonical and not gnunet -> cannot resolve!\n", name);
1942 rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
1943 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1945 rh->authority = zone;
1948 rh->timeout = timeout;
1949 rh->get_handle = NULL;
1950 if (timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
1953 * Set timeout for authority lookup phase to 1/2
1955 rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
1956 GNUNET_TIME_relative_divide(timeout, 2),
1957 &handle_lookup_timeout,
1959 rh->timeout_cont = &dht_authority_lookup_timeout;
1960 rh->timeout_cont_cls = rh;
1964 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No timeout for query!\n");
1965 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1968 if (strcmp(GNUNET_GNS_TLD, name) == 0)
1971 * Only 'gnunet' given
1973 strcpy(rh->name, "\0");
1977 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1978 "Checking for TLD...\n");
1979 if (is_zkey_tld(name) == GNUNET_YES)
1981 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1984 * This is a zkey tld
1985 * build hash and use as initial authority
1988 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
1989 memcpy(rh->name, name,
1990 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
1991 pop_tld(rh->name, string_hash);
1993 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1994 "ZKEY is %s!\n", string_hash);
1996 normalized_zkey = u8_toupper ((uint8_t*)string_hash, strlen ((char *) string_hash),
1997 NULL, UNINORM_NFD, NULL, &normal_len);
1999 memcpy(nzkey, normalized_zkey, normal_len);
2000 nzkey[normal_len] = '\0';
2001 free(normalized_zkey);
2003 if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(nzkey,
2006 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2007 "Cannot convert ZKEY %s to hash!\n", string_hash);
2017 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2020 * Presumably GNUNET tld
2023 strlen(name)-strlen(GNUNET_GNS_TLD));
2024 memcpy(rh->name, name,
2025 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2030 * Initialize authority chain
2032 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2033 rh->authority_chain_head->prev = NULL;
2034 rh->authority_chain_head->next = NULL;
2035 rh->authority_chain_tail = rh->authority_chain_head;
2036 rh->authority_chain_head->zone = rh->authority;
2039 * Copy original query into lookup handle
2041 rlh->record_type = record_type;
2042 memset(rlh->name, 0, strlen(name) + 1);
2043 strcpy(rlh->name, name);
2045 rlh->proc_cls = cls;
2047 rh->proc = &handle_delegation_ns;
2048 resolve_delegation_ns(rh);
2051 /******** END Record Resolver ***********/
2055 * Callback calles by namestore for a zone to name
2058 * @param cls the closure
2059 * @param zone_key the zone we queried
2060 * @param expire the expiration time of the name
2061 * @param name the name found or NULL
2062 * @param rd_len number of records for the name
2063 * @param rd the record data (PKEY) for the name
2064 * @param signature the signature for the record data
2067 process_zone_to_name_shorten(void *cls,
2068 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
2069 struct GNUNET_TIME_Absolute expire,
2071 unsigned int rd_len,
2072 const struct GNUNET_NAMESTORE_RecordData *rd,
2073 const struct GNUNET_CRYPTO_RsaSignature *signature)
2075 struct ResolverHandle *rh = (struct ResolverHandle *)cls;
2076 struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
2077 struct AuthorityChain *next_authority;
2079 char result[MAX_DNS_NAME_LENGTH];
2080 char next_authority_name[MAX_DNS_LABEL_LENGTH];
2083 /* we found a match in our own zone */
2086 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2087 "result strlen %d\n", strlen(name));
2088 answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
2089 memset(result, 0, answer_len);
2090 if (strlen(rh->name) > 0)
2092 strcpy(result, rh->name);
2093 strcpy(result+strlen(rh->name), ".");
2096 strcpy(result+strlen(result), name);
2097 strcpy(result+strlen(result), ".");
2098 strcpy(result+strlen(result), GNUNET_GNS_TLD);
2100 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2101 "Sending shorten result %s\n", result);
2103 nsh->proc(nsh->proc_cls, result);
2105 free_resolver_handle(rh);
2107 else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2110 /* our zone, just append .gnunet */
2111 answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
2112 memset(result, 0, answer_len);
2113 strcpy(result, rh->name);
2114 strcpy(result+strlen(rh->name), ".");
2115 strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
2117 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2118 "Our zone: Sending name as shorten result %s\n", rh->name);
2120 nsh->proc(nsh->proc_cls, result);
2122 free_resolver_handle(rh);
2128 * continue with next authority
2130 next_authority = rh->authority_chain_head;
2131 // strlen(next_authority->name) + 2);
2132 memset(next_authority_name, 0, strlen(rh->name)+
2133 strlen(next_authority->name) + 2);
2134 strcpy(next_authority_name, rh->name);
2135 strcpy(next_authority_name+strlen(rh->name)+1, ".");
2136 strcpy(next_authority_name+strlen(rh->name)+2, next_authority->name);
2138 strcpy(rh->name, next_authority_name);
2139 GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
2140 rh->authority_chain_tail,
2143 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2144 &rh->authority_chain_tail->zone,
2145 &rh->authority_chain_head->zone,
2146 &process_zone_to_name_shorten,
2152 * DHT resolution for delegation finished. Processing result.
2154 * @param cls the closure
2155 * @param rh resolver handle
2156 * @param rd_count number of results (always 0)
2157 * @param rd record data (always NULL)
2160 handle_delegation_dht_bg_shorten(void* cls, struct ResolverHandle *rh,
2161 unsigned int rd_count,
2162 const struct GNUNET_NAMESTORE_RecordData *rd)
2165 /* We resolved full name for delegation. resolving record */
2166 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2167 "GNS_SHORTEN: Resolved up to %s for delegation via DHT in background.\n",
2169 free_resolver_handle(rh);
2173 * Process result from namestore delegation lookup
2174 * for shorten operation
2176 * @param cls the client shorten handle
2177 * @param rh the resolver handle
2178 * @param rd_count number of results (0)
2179 * @param rd data (NULL)
2182 handle_delegation_ns_shorten(void* cls,
2183 struct ResolverHandle *rh,
2185 const struct GNUNET_NAMESTORE_RecordData *rd)
2187 struct NameShortenHandle *nsh;
2188 char result[MAX_DNS_NAME_LENGTH];
2190 struct ResolverHandle *rh_bg;
2192 nsh = (struct NameShortenHandle *)cls;
2195 * At this point rh->name contains the part of the name
2196 * that we do not have a PKEY in our namestore to resolve.
2197 * The authority chain in the resolver handle is now
2198 * useful to backtrack if needed
2201 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2202 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2204 if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2208 * This is our zone append .gnunet unless name is empty
2209 * (it shouldn't be, usually FIXME what happens if we
2210 * shorten to our zone to a "" record??)
2213 answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
2214 memset(result, 0, answer_len);
2215 strcpy(result, rh->name);
2216 strcpy(result+strlen(rh->name), ".");
2217 strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
2219 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2220 "Our zone: Sending name as shorten result %s\n", rh->name);
2222 nsh->proc(nsh->proc_cls, result);
2224 free_resolver_handle(rh);
2229 * we have to this before zone to name for rh might
2233 if (!is_canonical(rh->name))
2235 rh_bg = GNUNET_malloc(sizeof(struct ResolverHandle));
2236 memcpy(rh_bg, rh, sizeof(struct ResolverHandle));
2239 /* backtrack authorities for names */
2240 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2241 &rh->authority_chain_tail->zone, //ours
2242 &rh->authority_chain_head->zone,
2243 &process_zone_to_name_shorten,
2252 * If authority resolution is incomplete we can do a background lookup
2253 * of the full name so that next time we can (likely) fully or at least
2254 * further shorten the name
2256 rh_bg->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2257 rh_bg->authority_chain_tail = rh_bg->authority_chain_head;
2258 rh_bg->authority_chain_head->zone = rh_bg->authority;
2260 rh_bg->proc = &handle_delegation_dht_bg_shorten;
2261 rh_bg->proc_cls = NULL;
2263 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2264 "GNS_SHORTEN: Starting background lookup for %s\n",
2267 resolve_delegation_dht(rh_bg);
2273 * Callback calles by namestore for a zone to name
2276 * @param cls the closure
2277 * @param zone_key the zone we queried
2278 * @param expire the expiration time of the name
2279 * @param name the name found or NULL
2280 * @param rd_len number of records for the name
2281 * @param rd the record data (PKEY) for the name
2282 * @param signature the signature for the record data
2285 process_zone_to_name_zkey(void *cls,
2286 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
2287 struct GNUNET_TIME_Absolute expire,
2289 unsigned int rd_len,
2290 const struct GNUNET_NAMESTORE_RecordData *rd,
2291 const struct GNUNET_CRYPTO_RsaSignature *signature)
2293 struct ResolverHandle *rh = cls;
2294 struct NameShortenHandle *nsh = rh->proc_cls;
2295 struct GNUNET_CRYPTO_ShortHashAsciiEncoded enc;
2296 char new_name[MAX_DNS_NAME_LENGTH];
2298 /* zkey not in our zone */
2302 * In this case we have not given this PKEY a name (yet)
2303 * It is either just not in our zone or not even cached
2304 * Since we do not know at this point we will not try to shorten
2305 * because PKEY import will happen if the user follows the zkey
2308 GNUNET_CRYPTO_short_hash_to_enc ((struct GNUNET_CRYPTO_ShortHashCode*)rd,
2310 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2311 "No name found for zkey %s returning verbatim!\n", enc);
2312 if (strcmp(rh->name, "") != 0)
2313 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s.%s",
2314 rh->name, enc, GNUNET_GNS_TLD_ZKEY);
2316 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
2317 enc, GNUNET_GNS_TLD_ZKEY);
2318 nsh->proc(nsh->proc_cls, new_name);
2320 free_resolver_handle(rh);
2324 if (strcmp(rh->name, "") != 0)
2325 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
2328 strcpy(new_name, name);
2330 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2331 "Continue shorten for %s!\n", new_name);
2333 strcpy(rh->name, new_name);
2335 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2336 rh->authority_chain_tail = rh->authority_chain_head;
2337 rh->authority_chain_head->zone = rh->authority;
2340 /* Start delegation resolution in our namestore */
2341 resolve_delegation_ns(rh);
2345 * Shorten api from resolver
2347 * @param zone the zone to use
2348 * @param name the name to shorten
2349 * @param key optional private key for background lookups and PSEU import
2350 * @param proc the processor to call with result
2351 * @param proc_cls closure to pass to proc
2354 gns_resolver_shorten_name(struct GNUNET_CRYPTO_ShortHashCode zone,
2356 struct GNUNET_CRYPTO_RsaPrivateKey *key,
2357 ShortenResultProcessor proc,
2360 struct ResolverHandle *rh;
2361 struct NameShortenHandle *nsh;
2362 char string_hash[MAX_DNS_LABEL_LENGTH];
2363 struct GNUNET_CRYPTO_ShortHashCode zkey;
2364 uint8_t* normalized_zkey;
2366 char nzkey[MAX_DNS_LABEL_LENGTH];
2369 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2370 "Starting shorten for %s!\n", name);
2372 if (is_canonical((char*)name))
2374 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2375 "%s is canonical. Returning verbatim\n", name);
2376 proc(proc_cls, name);
2380 nsh = GNUNET_malloc(sizeof (struct NameShortenHandle));
2383 nsh->proc_cls = proc_cls;
2385 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2386 rh->authority = zone;
2388 rh->proc = &handle_delegation_ns_shorten;
2391 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2392 "Checking for TLD...\n");
2393 if (is_zkey_tld(name) == GNUNET_YES)
2395 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2398 * This is a zkey tld
2399 * build hash and use as initial authority
2403 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
2404 memcpy(rh->name, name,
2405 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
2406 pop_tld(rh->name, string_hash);
2408 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2409 "ZKEY is %s!\n", string_hash);
2411 normalized_zkey = u8_toupper ((uint8_t*)string_hash, strlen ((char *) string_hash),
2412 NULL, UNINORM_NFD, NULL, &normal_len);
2414 memcpy(nzkey, normalized_zkey, normal_len);
2415 nzkey[normal_len] = '\0';
2416 free(normalized_zkey);
2418 if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(nzkey,
2421 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2422 "Cannot convert ZKEY %s to hash!\n", nzkey);
2425 proc(proc_cls, name);
2429 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2432 &process_zone_to_name_zkey,
2439 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2442 * Presumably GNUNET tld
2445 strlen(name)-strlen(GNUNET_GNS_TLD));
2446 memcpy(rh->name, name,
2447 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2450 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2451 rh->authority_chain_tail = rh->authority_chain_head;
2452 rh->authority_chain_head->zone = zone;
2455 /* Start delegation resolution in our namestore */
2456 resolve_delegation_ns(rh);
2459 /*********** END NAME SHORTEN ********************/
2463 * Process result from namestore delegation lookup
2464 * for get authority operation
2466 * @param cls the client get auth handle
2467 * @param rh the resolver handle
2468 * @param rd_count number of results (0)
2469 * @param rd data (NULL)
2472 handle_delegation_result_ns_get_auth(void* cls,
2473 struct ResolverHandle *rh,
2475 const struct GNUNET_NAMESTORE_RecordData *rd)
2477 struct GetNameAuthorityHandle* nah;
2478 char result[MAX_DNS_NAME_LENGTH];
2481 nah = (struct GetNameAuthorityHandle*) rh->proc_cls;
2484 * At this point rh->name contains the part of the name
2485 * that we do not have a PKEY in our namestore to resolve.
2486 * The authority chain in the resolver handle is now
2487 * useful to backtrack if needed
2490 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2491 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2493 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2494 "Building response!\n");
2495 if (is_canonical(rh->name))
2498 * We successfully resolved the authority in the ns
2499 * FIXME for our purposes this is fine
2500 * but maybe we want to have an api that also looks
2501 * into the dht (i.e. option in message)
2503 if (strlen(rh->name) > strlen(nah->name))
2505 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2506 "Record name longer than original lookup name... odd!\n");
2510 answer_len = strlen(nah->name) - strlen(rh->name)
2511 + strlen(GNUNET_GNS_TLD) + 1;
2512 memset(result, 0, answer_len);
2513 strcpy(result, nah->name + strlen(rh->name) + 1);
2515 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2516 "Got authority result %s\n", result);
2518 nah->proc(nah->proc_cls, result);
2520 free_resolver_handle(rh);
2524 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2525 "Unable to resolve authority for remaining %s!\n", rh->name);
2526 nah->proc(nah->proc_cls, "");
2528 free_resolver_handle(rh);
2536 * Tries to resolve the authority for name
2539 * @param zone the root zone to look up for
2540 * @param name the name to lookup up
2541 * @param proc the processor to call when finished
2542 * @param proc_cls the closure to pass to the processor
2545 gns_resolver_get_authority(struct GNUNET_CRYPTO_ShortHashCode zone,
2547 GetAuthorityResultProcessor proc,
2550 struct ResolverHandle *rh;
2551 struct GetNameAuthorityHandle *nah;
2553 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2554 "Starting authority resolution for %s!\n", name);
2556 nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
2557 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2558 rh->authority = zone;
2560 if (strcmp(GNUNET_GNS_TLD, name) == 0)
2562 strcpy(rh->name, "\0");
2567 strlen(name)-strlen(GNUNET_GNS_TLD));
2568 memcpy(rh->name, name,
2569 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2572 memset(nah->name, 0,
2574 strcpy(nah->name, name);
2576 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2577 rh->authority_chain_tail = rh->authority_chain_head;
2578 rh->authority_chain_head->zone = zone;
2579 rh->proc = &handle_delegation_result_ns_get_auth;
2580 rh->proc_cls = (void*)nah;
2583 nah->proc_cls = proc_cls;
2585 /* Start delegation resolution in our namestore */
2586 resolve_delegation_ns(rh);
2590 /******** END GET AUTHORITY *************/
2592 /* end of gnunet-service-gns_resolver.c */