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
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_dns_service.h"
35 #include "gnunet_dnsparser_lib.h"
36 #include "gnunet_gns_service.h"
37 #include "block_gns.h"
39 #include "gnunet-service-gns_resolver.h"
41 #define DHT_LOOKUP_TIMEOUT DHT_OPERATION_TIMEOUT
42 #define DHT_GNS_REPLICATION_LEVEL 5
43 #define MAX_DNS_LABEL_LENGTH 63
47 * Our handle to the namestore service
49 static struct GNUNET_NAMESTORE_Handle *namestore_handle;
52 * Resolver handle to the dht
54 static struct GNUNET_DHT_Handle *dht_handle;
57 * Heap for parallel DHT lookups
59 static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
62 * Maximum amount of parallel queries in background
64 static unsigned long long max_allowed_background_queries;
67 * Wheather or not to ignore pending records
69 static int ignore_pending_records;
74 static struct GNUNET_CRYPTO_ShortHashCode local_zone;
77 * a resolution identifier pool variable
79 * This is a non critical identifier useful for debugging
81 static unsigned long long rid = 0;
85 * Determine if this name is canonical.
87 * a.b.gnunet = not canonical
90 * @param name the name to test
91 * @return 1 if canonical
94 is_canonical(char* name)
96 uint32_t len = strlen(name);
101 if (*(name+i) == '.')
109 * Namestore calls this function if we have record for this name.
110 * (or with rd_count=0 to indicate no matches)
112 * @param cls the pending query
113 * @param key the key of the zone we did the lookup
114 * @param expiration expiration date of the namestore entry
115 * @param name the name for which we need an authority
116 * @param rd_count the number of records with 'name'
117 * @param rd the record data
118 * @param signature the signature of the authority for the record data
121 process_pseu_lookup_ns(void* cls,
122 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
123 struct GNUNET_TIME_Absolute expiration,
124 const char *name, unsigned int rd_count,
125 const struct GNUNET_NAMESTORE_RecordData *rd,
126 const struct GNUNET_CRYPTO_RsaSignature *signature)
128 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
129 struct GNUNET_NAMESTORE_RecordData new_pkey;
133 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
134 "GNS_AUTO_PSEU: Name %s already taken in NS!\n", name);
135 if (0 == strcmp(gph->name, name))
137 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
138 "GNS_AUTO_PSEU: Intelligent replacement not implemented\n",
144 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
145 "GNS_AUTO_PSEU: Trying delegated name %s\n", gph->name);
146 memcpy(gph->new_name, gph->name, strlen(gph->name)+1);
147 GNUNET_NAMESTORE_lookup_record(namestore_handle,
150 GNUNET_NAMESTORE_TYPE_ANY,
151 &process_pseu_lookup_ns,
157 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
158 "GNS_AUTO_PSEU: Name %s not taken in NS! Adding\n", gph->new_name);
160 new_pkey.expiration = GNUNET_TIME_UNIT_FOREVER_ABS;
161 new_pkey.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode);
162 new_pkey.data = &gph->new_zone;
163 new_pkey.record_type = GNUNET_GNS_RECORD_PKEY;
164 new_pkey.flags = GNUNET_NAMESTORE_RF_AUTHORITY
165 | GNUNET_NAMESTORE_RF_PRIVATE
166 | GNUNET_NAMESTORE_RF_PENDING;
167 GNUNET_NAMESTORE_record_create (namestore_handle,
178 * process result of a dht pseu lookup
180 * @param gph the handle
181 * @param name the pseu result or NULL
184 process_pseu_result(struct GetPseuAuthorityHandle* gph, char* name)
188 memcpy(gph->new_name, gph->name, strlen(gph->name)+1);
192 memcpy(gph->new_name, name, strlen(name)+1);
195 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
196 "GNS_AUTO_PSEU: Checking %s for collision in NS\n", gph->new_name);
199 * Check for collision
201 GNUNET_NAMESTORE_lookup_record(namestore_handle,
204 GNUNET_NAMESTORE_TYPE_ANY,
205 &process_pseu_lookup_ns,
210 * Handle timeout for dht request
212 * @param cls the request handle as closure
213 * @param tc the task context
216 handle_auth_discovery_timeout(void *cls,
217 const struct GNUNET_SCHEDULER_TaskContext *tc)
219 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
221 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
222 "GNS_GET_AUTH: dht lookup for query PSEU timed out.\n");
223 GNUNET_DHT_get_stop (gph->get_handle);
224 gph->get_handle = NULL;
225 process_pseu_result(gph, NULL);
229 * Function called when we find a PSEU entry in the DHT
231 * @param cls the request handle
232 * @param exp lifetime
233 * @param key the key the record was stored under
234 * @param get_path get path
235 * @param get_path_length get path length
236 * @param put_path put path
237 * @param put_path_length put path length
238 * @param type the block type
239 * @param size the size of the record
240 * @param data the record data
243 process_auth_discovery_dht_result(void* cls,
244 struct GNUNET_TIME_Absolute exp,
245 const struct GNUNET_HashCode * key,
246 const struct GNUNET_PeerIdentity *get_path,
247 unsigned int get_path_length,
248 const struct GNUNET_PeerIdentity *put_path,
249 unsigned int put_path_length,
250 enum GNUNET_BLOCK_Type type,
251 size_t size, const void *data)
253 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
254 struct GNSNameRecordBlock *nrb;
255 char* rd_data = (char*)data;
261 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
262 "GNS_GET_AUTH: got dht result (size=%d)\n", size);
266 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
267 "GNS_GET_AUTH: got dht result null!\n", size);
273 nrb = (struct GNSNameRecordBlock*)data;
275 /* stop lookup and timeout task */
276 GNUNET_DHT_get_stop (gph->get_handle);
277 gph->get_handle = NULL;
278 GNUNET_SCHEDULER_cancel(gph->timeout);
280 gph->get_handle = NULL;
282 nrb = (struct GNSNameRecordBlock*)data;
284 name = (char*)&nrb[1];
285 num_records = ntohl(nrb->rd_count);
287 struct GNUNET_NAMESTORE_RecordData rd[num_records];
289 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
290 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
292 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
297 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
298 "GNS_GET_AUTH: Error deserializing data!\n");
304 for (i=0; i<num_records; i++)
306 if ((strcmp(name, "+") == 0) &&
307 (rd[i].record_type == GNUNET_GNS_RECORD_PSEU))
310 process_pseu_result(gph, (char*)rd[i].data);
316 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_GET_AUTH: no pseu in dht!\n");
317 process_pseu_result(gph, NULL);
321 process_auth_discovery_ns_result(void* cls,
322 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
323 struct GNUNET_TIME_Absolute expiration,
324 const char *name, unsigned int rd_count,
325 const struct GNUNET_NAMESTORE_RecordData *rd,
326 const struct GNUNET_CRYPTO_RsaSignature *signature)
329 struct GNUNET_CRYPTO_ShortHashCode name_hash;
330 struct GNUNET_HashCode lookup_key;
331 struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
332 struct GNUNET_HashCode name_hash_double;
333 struct GNUNET_HashCode zone_hash_double;
335 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
343 GNUNET_CRYPTO_short_hash("+", strlen("+"), &name_hash);
344 GNUNET_CRYPTO_short_hash_double (&name_hash, &name_hash_double);
345 GNUNET_CRYPTO_short_hash_double (&gph->new_zone, &zone_hash_double);
346 GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
347 GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
349 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
350 "GNS_AUTO_PSEU: starting dht lookup for %s with key: %s\n",
351 "+", (char*)&lookup_key_string);
353 gph->timeout = GNUNET_SCHEDULER_add_delayed(DHT_LOOKUP_TIMEOUT,
354 &handle_auth_discovery_timeout, gph);
356 xquery = htonl(GNUNET_GNS_RECORD_PSEU);
358 GNUNET_assert(gph->get_handle == NULL);
359 gph->get_handle = GNUNET_DHT_get_start(dht_handle,
360 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
362 DHT_GNS_REPLICATION_LEVEL,
366 &process_auth_discovery_dht_result,
370 for (i=0; i<rd_count; i++)
372 if ((strcmp(name, "+") == 0) &&
373 (rd[i].record_type == GNUNET_GNS_RECORD_PSEU))
376 process_pseu_result(gph, (char*)rd[i].data);
383 * Callback called by namestore for a zone to name
386 * @param cls the closure
387 * @param zone_key the zone we queried
388 * @param expire the expiration time of the name
389 * @param name the name found or NULL
390 * @param rd_len number of records for the name
391 * @param rd the record data (PKEY) for the name
392 * @param signature the signature for the record data
395 process_zone_to_name_discover(void *cls,
396 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
397 struct GNUNET_TIME_Absolute expire,
400 const struct GNUNET_NAMESTORE_RecordData *rd,
401 const struct GNUNET_CRYPTO_RsaSignature *signature)
403 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
405 /* we found a match in our own zone */
408 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
409 "GNS_AUTO_PSEU: name for zone in our root %s\n", name);
415 GNUNET_NAMESTORE_lookup_record(namestore_handle,
418 GNUNET_GNS_RECORD_PSEU,
419 &process_auth_discovery_ns_result,
428 * Callback for new authories
430 * @param name the name given by delegation
431 * @param zone the authority
432 * @param our_zone our local zone
433 * @param key the private key of our authority
435 static void process_discovered_authority(char* name,
436 struct GNUNET_CRYPTO_ShortHashCode zone,
437 struct GNUNET_CRYPTO_ShortHashCode our_zone,
438 struct GNUNET_CRYPTO_RsaPrivateKey *key)
440 struct GetPseuAuthorityHandle *gph;
443 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
444 "GNS_AUTO_PSEU: New authority %s discovered\n",
447 gph = GNUNET_malloc(sizeof(struct GetPseuAuthorityHandle));
448 namelen = strlen(name) + 1;
449 memcpy(gph->name, name, namelen);
451 gph->new_zone = zone;
452 gph->zone = our_zone;
455 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
458 &process_zone_to_name_discover,
464 * Initialize the resolver
466 * @param nh the namestore handle
467 * @param dh the dht handle
468 * @param lz the local zone's hash
469 * @param max_bg_queries maximum number of parallel background queries in dht
470 * @param ignore_pending ignore records that still require user confirmation
472 * @return GNUNET_OK on success
475 gns_resolver_init(struct GNUNET_NAMESTORE_Handle *nh,
476 struct GNUNET_DHT_Handle *dh,
477 struct GNUNET_CRYPTO_ShortHashCode lz,
478 unsigned long long max_bg_queries,
481 namestore_handle = nh;
485 GNUNET_CONTAINER_heap_create(GNUNET_CONTAINER_HEAP_ORDER_MIN);
486 max_allowed_background_queries = max_bg_queries;
487 ignore_pending_records = ignore_pending;
489 if ((namestore_handle != NULL) && (dht_handle != NULL))
493 return GNUNET_SYSERR;
497 * Cleanup background lookups
499 * @param cls closure to iterator
500 * @param node heap nodes
501 * @param element the resolver handle
502 * @param cost heap cost
503 * @return always GNUNET_YES
506 cleanup_pending_background_queries(void* cls,
507 struct GNUNET_CONTAINER_HeapNode *node,
509 GNUNET_CONTAINER_HeapCostType cost)
511 struct ResolverHandle *rh = (struct ResolverHandle *)element;
512 ResolverCleanupContinuation cont = cls;
514 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
515 "GNS_CLEANUP-%llu: Terminating background lookup for %s\n",
517 GNUNET_DHT_get_stop(rh->get_handle);
518 rh->get_handle = NULL;
519 rh->proc(rh->proc_cls, rh, 0, NULL);
521 GNUNET_CONTAINER_heap_remove_node(node);
523 if (GNUNET_CONTAINER_heap_get_size(dht_lookup_heap) == 0)
535 gns_resolver_cleanup(ResolverCleanupContinuation cont)
537 unsigned int s = GNUNET_CONTAINER_heap_get_size(dht_lookup_heap);
538 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
539 "GNS_CLEANUP: %d pending background queries to terminate\n", s);
542 GNUNET_CONTAINER_heap_iterate (dht_lookup_heap,
543 &cleanup_pending_background_queries,
551 * Helper function to free resolver handle
553 * @param rh the handle to free
556 free_resolver_handle(struct ResolverHandle* rh)
558 struct AuthorityChain *ac;
559 struct AuthorityChain *ac_next;
564 ac = rh->authority_chain_head;
577 * Callback when record data is put into namestore
579 * @param cls the closure
580 * @param success GNUNET_OK on success
581 * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
584 on_namestore_record_put_result(void *cls,
588 if (GNUNET_NO == success)
590 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
591 "GNS_NS: records already in namestore\n");
594 else if (GNUNET_YES == success)
596 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
597 "GNS_NS: records successfully put in namestore\n");
601 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
602 "GNS_NS: Error putting records into namestore: %s\n", emsg);
606 handle_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
608 struct ResolverHandle *rh = cls;
610 if (rh->timeout_cont)
611 rh->timeout_cont(rh->timeout_cont_cls, tc);
615 * Processor for background lookups in the DHT
617 * @param cls closure (NULL)
618 * @param rd_count number of records found (not 0)
619 * @param rd record data
622 background_lookup_result_processor(void *cls,
624 const struct GNUNET_NAMESTORE_RecordData *rd)
626 //We could do sth verbose/more useful here but it doesn't make any difference
627 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
628 "GNS_BG: background dht lookup for finished. (%d results)\n",
633 * Handle timeout for DHT requests
635 * @param cls the request handle as closure
636 * @param tc the task context
639 dht_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
641 struct ResolverHandle *rh = cls;
642 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
643 char new_name[MAX_DNS_NAME_LENGTH];
645 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
646 "GNS_PHASE_REC-%d: dht lookup for query %s (%ds)timed out.\n",
647 rh->id, rh->name, rh->timeout.rel_value);
649 * Start resolution in bg
651 //strcpy(new_name, rh->name);
652 //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD));
653 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
654 rh->name, GNUNET_GNS_TLD);
656 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
657 "GNS_PHASE_REC-%d: Starting background lookup for %s type %d\n",
658 rh->id, new_name, rlh->record_type);
660 gns_resolver_lookup_record(rh->authority,
661 rh->private_local_zone,
665 GNUNET_TIME_UNIT_FOREVER_REL,
667 &background_lookup_result_processor,
669 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
671 GNUNET_DHT_get_stop (rh->get_handle);
672 rh->get_handle = NULL;
673 rh->proc(rh->proc_cls, rh, 0, NULL);
678 * Function called when we get a result from the dht
679 * for our record query
681 * @param cls the request handle
682 * @param exp lifetime
683 * @param key the key the record was stored under
684 * @param get_path get path
685 * @param get_path_length get path length
686 * @param put_path put path
687 * @param put_path_length put path length
688 * @param type the block type
689 * @param size the size of the record
690 * @param data the record data
693 process_record_result_dht(void* cls,
694 struct GNUNET_TIME_Absolute exp,
695 const struct GNUNET_HashCode * key,
696 const struct GNUNET_PeerIdentity *get_path,
697 unsigned int get_path_length,
698 const struct GNUNET_PeerIdentity *put_path,
699 unsigned int put_path_length,
700 enum GNUNET_BLOCK_Type type,
701 size_t size, const void *data)
703 struct ResolverHandle *rh;
704 struct RecordLookupHandle *rlh;
705 struct GNSNameRecordBlock *nrb;
706 uint32_t num_records;
708 char* rd_data = (char*)data;
712 rh = (struct ResolverHandle *)cls;
713 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
714 "GNS_PHASE_REC-%d: got dht result (size=%d)\n", rh->id, size);
719 //FIXME maybe check expiration here, check block type
722 rlh = (struct RecordLookupHandle *) rh->proc_cls;
723 nrb = (struct GNSNameRecordBlock*)data;
725 /* stop lookup and timeout task */
726 GNUNET_DHT_get_stop (rh->get_handle);
727 rh->get_handle = NULL;
729 if (rh->dht_heap_node != NULL)
731 GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
732 rh->dht_heap_node = NULL;
735 if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
737 GNUNET_SCHEDULER_cancel(rh->timeout_task);
738 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
741 rh->get_handle = NULL;
742 name = (char*)&nrb[1];
743 num_records = ntohl(nrb->rd_count);
745 struct GNUNET_NAMESTORE_RecordData rd[num_records];
747 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
748 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
750 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
755 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
756 "GNS_PHASE_REC-%d: Error deserializing data!\n", rh->id);
760 for (i=0; i<num_records; i++)
762 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
763 "GNS_PHASE_REC-%d: Got name: %s (wanted %s)\n",
764 rh->id, name, rh->name);
765 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
766 "GNS_PHASE_REC-%d: Got type: %d\n",
767 rh->id, rd[i].record_type);
768 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
769 "GNS_PHASE_REC-%d: Got data length: %d\n",
770 rh->id, rd[i].data_size);
771 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
772 "GNS_PHASE_REC-%d: Got flag %d\n",
773 rh->id, rd[i].flags);
775 if ((strcmp(name, rh->name) == 0) &&
776 (rd[i].record_type == rlh->record_type))
784 * FIXME check pubkey against existing key in namestore?
785 * https://gnunet.org/bugs/view.php?id=2179
788 /* Save to namestore */
789 GNUNET_NAMESTORE_record_put (namestore_handle,
796 &on_namestore_record_put_result, //cont
801 rh->proc(rh->proc_cls, rh, num_records, rd);
803 rh->proc(rh->proc_cls, rh, 0, NULL);
810 * Start DHT lookup for a (name -> query->record_type) record in
811 * rh->authority's zone
813 * @param rh the pending gns query context
816 resolve_record_dht(struct ResolverHandle *rh)
819 struct GNUNET_CRYPTO_ShortHashCode name_hash;
820 struct GNUNET_HashCode lookup_key;
821 struct GNUNET_HashCode name_hash_double;
822 struct GNUNET_HashCode zone_hash_double;
823 struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
824 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
825 struct ResolverHandle *rh_heap_root;
827 GNUNET_CRYPTO_short_hash(rh->name, strlen(rh->name), &name_hash);
828 GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
829 GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
830 GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
831 GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
833 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
834 "GNS_PHASE_REC-%d: starting dht lookup for %s with key: %s\n",
835 rh->id, rh->name, (char*)&lookup_key_string);
837 //rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
838 rh->dht_heap_node = NULL;
840 if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
843 * Update timeout if necessary
845 if (rh->timeout_task == GNUNET_SCHEDULER_NO_TASK)
848 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
849 "GNS_PHASE_REC-%d: Adjusting timeout\n", rh->id);
851 * Set timeout for authority lookup phase to 1/2
853 rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
854 GNUNET_TIME_relative_divide(rh->timeout, 2),
855 &handle_lookup_timeout,
858 //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
859 // &dht_lookup_timeout,
861 rh->timeout_cont = &dht_lookup_timeout;
862 rh->timeout_cont_cls = rh;
866 if (max_allowed_background_queries <=
867 GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
869 rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
870 GNUNET_DHT_get_stop(rh_heap_root->get_handle);
871 rh_heap_root->get_handle = NULL;
872 rh_heap_root->dht_heap_node = NULL;
874 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
875 "GNS_PHASE_REC-%d: Replacing oldest background query for %s\n",
876 rh->id, rh_heap_root->name);
877 rh_heap_root->proc(rh_heap_root->proc_cls,
882 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
884 GNUNET_TIME_absolute_get().abs_value);
887 xquery = htonl(rlh->record_type);
889 GNUNET_assert(rh->get_handle == NULL);
890 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
891 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
893 DHT_GNS_REPLICATION_LEVEL,
897 &process_record_result_dht,
904 * Namestore calls this function if we have record for this name.
905 * (or with rd_count=0 to indicate no matches)
907 * @param cls the pending query
908 * @param key the key of the zone we did the lookup
909 * @param expiration expiration date of the namestore entry
910 * @param name the name for which we need an authority
911 * @param rd_count the number of records with 'name'
912 * @param rd the record data
913 * @param signature the signature of the authority for the record data
916 process_record_result_ns(void* cls,
917 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
918 struct GNUNET_TIME_Absolute expiration,
919 const char *name, unsigned int rd_count,
920 const struct GNUNET_NAMESTORE_RecordData *rd,
921 const struct GNUNET_CRYPTO_RsaSignature *signature)
923 struct ResolverHandle *rh;
924 struct RecordLookupHandle *rlh;
925 struct GNUNET_TIME_Relative remaining_time;
926 struct GNUNET_CRYPTO_ShortHashCode zone;
928 rh = (struct ResolverHandle *) cls;
929 rlh = (struct RecordLookupHandle *)rh->proc_cls;
930 GNUNET_CRYPTO_short_hash(key,
931 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
933 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
941 rh->status |= RSL_RECORD_EXISTS;
944 if (remaining_time.rel_value == 0)
946 rh->status |= RSL_RECORD_EXPIRED;
952 * Lookup terminated and no results
954 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
955 "GNS_PHASE_REC-%d: Namestore lookup for %s terminated without results\n",
958 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
959 "GNS_PHASE_REC-%d: Record %s unknown in namestore\n",
962 * Our zone and no result? Cannot resolve TT
964 rh->proc(rh->proc_cls, rh, 0, NULL);
971 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
972 "GNS_PHASE_REC-%d: Processing additional result %s from namestore\n",
975 for (i=0; i<rd_count;i++)
978 if (rd[i].record_type != rlh->record_type)
981 if (ignore_pending_records &&
982 (rd[i].flags & GNUNET_NAMESTORE_RF_PENDING))
984 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
985 "GNS_PHASE_REC-%d: Record %s is awaiting user confirmation. Skipping\n",
990 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
993 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
994 "GNS_PHASE_REC-%d: This record is expired. Skipping\n",
1006 if (rh->answered == 0)
1008 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1009 "GNS_PHASE_REC-%d: No answers found. This is odd!\n", rh->id);
1010 rh->proc(rh->proc_cls, rh, 0, NULL);
1014 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1015 "GNS_PHASE_REC-%d: Found %d answer(s) to query in %d records!\n",
1016 rh->id, rh->answered, rd_count);
1018 rh->proc(rh->proc_cls, rh, rd_count, rd);
1024 * The final phase of resolution.
1025 * rh->name is a name that is canonical and we do not have a delegation.
1026 * Query namestore for this record
1028 * @param rh the pending lookup
1031 resolve_record_ns(struct ResolverHandle *rh)
1033 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
1035 /* We cancel here as to not include the ns lookup in the timeout */
1036 if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1038 GNUNET_SCHEDULER_cancel(rh->timeout_task);
1039 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1043 * Try to resolve this record in our namestore.
1044 * The name to resolve is now in rh->authority_name
1045 * since we tried to resolve it to an authority
1048 GNUNET_NAMESTORE_lookup_record(namestore_handle,
1052 &process_record_result_ns,
1059 * Handle timeout for DHT requests
1061 * @param cls the request handle as closure
1062 * @param tc the task context
1065 dht_authority_lookup_timeout(void *cls,
1066 const struct GNUNET_SCHEDULER_TaskContext *tc)
1068 struct ResolverHandle *rh = cls;
1069 struct RecordLookupHandle *rlh = rh->proc_cls;
1070 char new_name[MAX_DNS_NAME_LENGTH];
1072 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1073 "GNS_PHASE_DELEGATE_DHT-%llu: dht lookup for query %s (%ds)timed out.\n",
1074 rh->id, rh->authority_name, rh->timeout.rel_value);
1076 rh->status |= RSL_TIMED_OUT;
1078 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1080 GNUNET_DHT_get_stop (rh->get_handle);
1081 rh->get_handle = NULL;
1083 if (strcmp(rh->name, "") == 0)
1086 * promote authority back to name and try to resolve record
1088 strcpy(rh->name, rh->authority_name);
1089 rh->proc(rh->proc_cls, rh, 0, NULL);
1094 * Start resolution in bg
1096 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH,
1097 "%s.%s.%s", rh->name, rh->authority_name, GNUNET_GNS_TLD);
1098 //strcpy(new_name, rh->name);
1099 //strcpy(new_name+strlen(new_name), ".");
1100 //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD));
1102 strcpy(rh->name, new_name);
1104 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1105 "GNS_PHASE_DELEGATE_DHT-%llu: Starting background query for %s type %d\n",
1106 rh->id, rh->name, rlh->record_type);
1108 gns_resolver_lookup_record(rh->authority,
1109 rh->private_local_zone,
1113 GNUNET_TIME_UNIT_FOREVER_REL,
1115 &background_lookup_result_processor,
1118 rh->proc(rh->proc_cls, rh, 0, NULL);
1122 static void resolve_delegation_dht(struct ResolverHandle *rh);
1125 static void resolve_delegation_ns(struct ResolverHandle *rh);
1129 * Namestore resolution for delegation finished. Processing result.
1131 * @param cls the closure
1132 * @param rh resolver handle
1133 * @param rd_count number of results (always 0)
1134 * @param rd record data (always NULL)
1137 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
1138 unsigned int rd_count,
1139 const struct GNUNET_NAMESTORE_RecordData *rd);
1143 * Function called when we get a result from the dht
1144 * for our query. Recursively tries to resolve authorities
1147 * @param cls the request handle
1148 * @param exp lifetime
1149 * @param key the key the record was stored under
1150 * @param get_path get path
1151 * @param get_path_length get path length
1152 * @param put_path put path
1153 * @param put_path_length put path length
1154 * @param type the block type
1155 * @param size the size of the record
1156 * @param data the record data
1159 process_delegation_result_dht(void* cls,
1160 struct GNUNET_TIME_Absolute exp,
1161 const struct GNUNET_HashCode * key,
1162 const struct GNUNET_PeerIdentity *get_path,
1163 unsigned int get_path_length,
1164 const struct GNUNET_PeerIdentity *put_path,
1165 unsigned int put_path_length,
1166 enum GNUNET_BLOCK_Type type,
1167 size_t size, const void *data)
1169 struct ResolverHandle *rh;
1170 struct GNSNameRecordBlock *nrb;
1171 uint32_t num_records;
1173 char* rd_data = (char*) data;
1176 struct GNUNET_CRYPTO_ShortHashCode zone, name_hash;
1177 struct GNUNET_HashCode zone_hash_double, name_hash_double;
1179 rh = (struct ResolverHandle *)cls;
1181 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1182 "GNS_PHASE_DELEGATE_DHT-%llu: Got DHT result\n", rh->id);
1187 nrb = (struct GNSNameRecordBlock*)data;
1189 /* stop dht lookup and timeout task */
1190 GNUNET_DHT_get_stop (rh->get_handle);
1192 rh->get_handle = NULL;
1194 if (rh->dht_heap_node != NULL)
1196 GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
1197 rh->dht_heap_node = NULL;
1200 num_records = ntohl(nrb->rd_count);
1201 name = (char*)&nrb[1];
1203 struct GNUNET_NAMESTORE_RecordData rd[num_records];
1205 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
1206 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
1208 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
1213 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1214 "GNS_PHASE_DELEGATE_DHT-%llu: Error deserializing data!\n",
1219 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1220 "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n",
1221 rh->id, name, rh->authority_name);
1222 for (i=0; i<num_records; i++)
1225 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1226 "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n",
1227 rh->id, name, rh->authority_name);
1228 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1229 "GNS_PHASE_DELEGATE_DHT-%llu: Got type: %d (wanted %d)\n",
1230 rh->id, rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
1231 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1232 "GNS_PHASE_DELEGATE_DHT-%llu: Got data length: %d\n",
1233 rh->id, rd[i].data_size);
1234 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1235 "GNS_PHASE_DELEGATE_DHT-%llu: Got flag %d\n",
1236 rh->id, rd[i].flags);
1238 if ((strcmp(name, rh->authority_name) == 0) &&
1239 (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
1241 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1242 "GNS_PHASE_DELEGATE_DHT-%llu: Authority found in DHT\n",
1245 memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1246 struct AuthorityChain *auth =
1247 GNUNET_malloc(sizeof(struct AuthorityChain));
1248 auth->zone = rh->authority;
1249 memset(auth->name, 0, strlen(rh->authority_name)+1);
1250 strcpy(auth->name, rh->authority_name);
1251 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1252 rh->authority_chain_tail,
1255 /** try to import pkey if private key available */
1256 if (rh->priv_key && is_canonical (rh->name))
1257 process_discovered_authority(name, auth->zone,
1258 rh->authority_chain_tail->zone,
1265 GNUNET_CRYPTO_short_hash(name, strlen(name), &name_hash);
1266 GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1267 GNUNET_CRYPTO_hash_xor(key, &name_hash_double, &zone_hash_double);
1268 GNUNET_CRYPTO_short_hash_from_truncation (&zone_hash_double, &zone);
1270 /* Save to namestore */
1271 if (0 != GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_tail->zone,
1274 GNUNET_NAMESTORE_record_put (namestore_handle,
1281 &on_namestore_record_put_result, //cont
1291 * FIXME in this case. should we ask namestore again?
1293 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1294 "GNS_PHASE_DELEGATE_DHT-%llu: Answer from DHT for %s. Yet to resolve: %s\n",
1295 rh->id, rh->authority_name, rh->name);
1296 if (strcmp(rh->name, "") == 0)
1298 rh->proc(rh->proc_cls, rh, 0, NULL);
1302 rh->proc = &handle_delegation_ns;
1303 resolve_delegation_ns(rh);
1309 * No pkey but name exists
1312 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1313 "GNS_PHASE_DELEGATE_DHT-%llu: Adding %s back to %s\n",
1314 rh->id, rh->authority_name, rh->name);
1315 if (strcmp(rh->name, "") == 0)
1316 strcpy(rh->name, rh->authority_name);
1318 GNUNET_snprintf(rh->name, MAX_DNS_NAME_LENGTH, "%s.%s",
1319 rh->name, rh->authority_name); //FIXME ret
1321 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1322 "GNS_PHASE_DELEGATE_DHT-%llu: %s restored\n", rh->id, rh->name);
1323 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1324 "GNS_PHASE_DELEGATE_DHT-%llu: DHT authority lookup found no match!\n",
1326 rh->proc(rh->proc_cls, rh, 0, NULL);
1329 #define MAX_SOA_LENGTH sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)\
1330 +(MAX_DNS_NAME_LENGTH*2)
1331 #define MAX_MX_LENGTH sizeof(uint16_t)+MAX_DNS_NAME_LENGTH
1335 expand_plus(char** dest, char* src, char* repl)
1338 unsigned int s_len = strlen(src)+1;
1340 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1341 "GNS_POSTPROCESS: Got %s to expand with %s\n", src, repl);
1345 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1346 "GNS_POSTPROCESS: %s to short\n", src);
1348 /* no postprocessing */
1349 memcpy(*dest, src, s_len+1);
1353 if (0 == strcmp(src+s_len-3, ".+"))
1355 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1356 "GNS_POSTPROCESS: Expanding .+ in %s\n", src);
1357 memset(*dest, 0, s_len+strlen(repl)+strlen(GNUNET_GNS_TLD));
1359 pos = *dest+s_len-2;
1361 pos += strlen(repl);
1362 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1363 "GNS_POSTPROCESS: Expanded to %s\n", *dest);
1367 memcpy(*dest, src, s_len+1);
1375 finish_lookup(struct ResolverHandle *rh,
1376 struct RecordLookupHandle* rlh,
1377 unsigned int rd_count,
1378 const struct GNUNET_NAMESTORE_RecordData *rd)
1381 char new_rr_data[MAX_DNS_NAME_LENGTH];
1382 char new_mx_data[MAX_MX_LENGTH];
1383 char new_soa_data[MAX_SOA_LENGTH];
1384 struct GNUNET_NAMESTORE_RecordData p_rd[rd_count];
1387 unsigned int offset;
1389 if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1391 GNUNET_SCHEDULER_cancel(rh->timeout_task);
1392 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1396 memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData));
1398 for (i = 0; i < rd_count; i++)
1401 if (rd[i].record_type != GNUNET_GNS_RECORD_TYPE_NS &&
1402 rd[i].record_type != GNUNET_GNS_RECORD_TYPE_CNAME &&
1403 rd[i].record_type != GNUNET_GNS_RECORD_MX &&
1404 rd[i].record_type != GNUNET_GNS_RECORD_TYPE_SOA)
1406 p_rd[i].data = rd[i].data;
1411 * for all those records we 'should'
1412 * also try to resolve the A/AAAA records (RFC1035)
1413 * This is a feature and not important
1416 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1417 "GNS_POSTPROCESS: Postprocessing\n");
1419 if (strcmp(rh->name, "+") == 0)
1420 repl_string = rlh->name;
1422 repl_string = rlh->name+strlen(rh->name)+1;
1425 if (rd[i].record_type == GNUNET_GNS_RECORD_MX)
1427 memcpy(new_mx_data, (char*)rd[i].data, sizeof(uint16_t));
1428 offset = sizeof(uint16_t);
1429 pos = new_mx_data+offset;
1430 expand_plus(&pos, (char*)rd[i].data+sizeof(uint16_t),
1432 offset += strlen(new_mx_data+sizeof(uint16_t))+1;
1433 p_rd[i].data = new_mx_data;
1434 p_rd[i].data_size = offset;
1436 else if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_SOA)
1438 /* expand mname and rname */
1440 expand_plus(&pos, (char*)rd[i].data, repl_string);
1441 offset = strlen(new_soa_data)+1;
1442 pos = new_soa_data+offset;
1443 expand_plus(&pos, (char*)rd[i].data+offset, repl_string);
1444 offset += strlen(new_soa_data+offset)+1;
1445 /* cpy the 4 numbers serial refresh retry and expire */
1446 memcpy(new_soa_data+offset, (char*)rd[i].data+offset, sizeof(uint32_t)*5);
1447 offset += sizeof(uint32_t)*5;
1448 p_rd[i].data_size = offset;
1449 p_rd[i].data = new_soa_data;
1454 expand_plus(&pos, (char*)rd[i].data, repl_string);
1455 p_rd[i].data_size = strlen(new_rr_data)+1;
1456 p_rd[i].data = new_rr_data;
1461 rlh->proc(rlh->proc_cls, rd_count, p_rd);
1467 * Process DHT lookup result for record.
1469 * @param cls the closure
1470 * @param rh resolver handle
1471 * @param rd_count number of results
1472 * @param rd record data
1475 handle_record_dht(void* cls, struct ResolverHandle *rh,
1476 unsigned int rd_count,
1477 const struct GNUNET_NAMESTORE_RecordData *rd)
1479 struct RecordLookupHandle* rlh;
1481 rlh = (struct RecordLookupHandle*)cls;
1484 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1485 "GNS_PHASE_REC-%d: No records for %s found in DHT. Aborting\n",
1487 /* give up, cannot resolve */
1488 finish_lookup(rh, rlh, 0, NULL);
1489 free_resolver_handle(rh);
1493 /* results found yay */
1494 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1495 "GNS_PHASE_REC-%d: Record resolved from DHT!", rh->id);
1497 finish_lookup(rh, rlh, rd_count, rd);
1498 free_resolver_handle(rh);
1504 * Process namestore lookup result for record.
1506 * @param cls the closure
1507 * @param rh resolver handle
1508 * @param rd_count number of results
1509 * @param rd record data
1512 handle_record_ns(void* cls, struct ResolverHandle *rh,
1513 unsigned int rd_count,
1514 const struct GNUNET_NAMESTORE_RecordData *rd)
1516 struct RecordLookupHandle* rlh;
1517 rlh = (struct RecordLookupHandle*) cls;
1520 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1521 "GNS_PHASE_REC-%d: NS returned no records. (status: %d)!\n",
1526 * There are 5 conditions that have to met for us to consult the DHT:
1527 * 1. The entry in the DHT is RSL_RECORD_EXPIRED AND
1528 * 2. No entry in the NS existed AND
1529 * 3. The zone queried is not the local resolver's zone AND
1530 * 4. The name that was looked up is '+'
1531 * because if it was any other canonical name we either already queried
1532 * the DHT for the authority in the authority lookup phase (and thus
1533 * would already have an entry in the NS for the record)
1534 * 5. We are not in cache only mode
1536 if (rh->status & (RSL_RECORD_EXPIRED | !RSL_RECORD_EXISTS) &&
1537 GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1538 &rh->private_local_zone) &&
1539 (strcmp(rh->name, "+") == 0) &&
1540 (rh->only_cached == GNUNET_NO))
1542 rh->proc = &handle_record_dht;
1543 resolve_record_dht(rh);
1546 /* give up, cannot resolve */
1547 finish_lookup(rh, rlh, 0, NULL);
1548 free_resolver_handle(rh);
1552 /* results found yay */
1553 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1554 "GNS_PHASE_REC-%d: Record resolved from namestore!", rh->id);
1556 finish_lookup(rh, rlh, rd_count, rd);
1558 free_resolver_handle(rh);
1564 * Move one level up in the domain hierarchy and return the
1565 * passed top level domain.
1567 * @param name the domain
1568 * @param dest the destination where the tld will be put
1571 pop_tld(char* name, char* dest)
1575 if (is_canonical(name))
1582 for (len = strlen(name); len > 0; len--)
1584 if (*(name+len) == '.')
1594 strcpy(dest, (name+len+1));
1598 * Checks if name is in tld
1600 * @param name the name to check
1601 * @param tld the TLD to check for
1602 * @return GNUNET_YES or GNUNET_NO
1605 is_tld(const char* name, const char* tld)
1609 if (strlen(name) <= strlen(tld))
1614 offset = strlen(name)-strlen(tld);
1615 if (strcmp(name+offset, tld) != 0)
1617 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1618 "%s is not in .%s TLD\n", name, tld);
1625 * DHT resolution for delegation finished. Processing result.
1627 * @param cls the closure
1628 * @param rh resolver handle
1629 * @param rd_count number of results (always 0)
1630 * @param rd record data (always NULL)
1633 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
1634 unsigned int rd_count,
1635 const struct GNUNET_NAMESTORE_RecordData *rd)
1637 struct RecordLookupHandle* rlh;
1638 rlh = (struct RecordLookupHandle*) cls;
1641 if (strcmp(rh->name, "") == 0)
1643 if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1645 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1646 "GNS_PHASE_DELEGATE_DHT-%llu: Resolved queried PKEY via DHT.\n",
1648 finish_lookup(rh, rlh, rd_count, rd);
1649 free_resolver_handle(rh);
1652 /* We resolved full name for delegation. resolving record */
1653 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1654 "GNS_PHASE_DELEGATE_DHT-%llu: Resolved full name for delegation via DHT.\n",
1656 strcpy(rh->name, "+\0");
1657 rh->proc = &handle_record_ns;
1658 resolve_record_ns(rh);
1663 * we still have some left
1665 if (is_canonical(rh->name))
1667 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1668 "GNS_PHASE_DELEGATE_DHT-%llu: Resolving canonical record %s in ns\n",
1671 rh->proc = &handle_record_ns;
1672 resolve_record_ns(rh);
1675 /* give up, cannot resolve */
1676 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1677 "GNS_PHASE_DELEGATE_DHT-%llu: Cannot fully resolve delegation for %s via DHT!\n",
1679 finish_lookup(rh, rlh, 0, NULL);
1680 free_resolver_handle(rh);
1685 * Start DHT lookup for a name -> PKEY (compare NS) record in
1686 * rh->authority's zone
1688 * @param rh the pending gns query
1691 resolve_delegation_dht(struct ResolverHandle *rh)
1694 struct GNUNET_CRYPTO_ShortHashCode name_hash;
1695 struct GNUNET_HashCode name_hash_double;
1696 struct GNUNET_HashCode zone_hash_double;
1697 struct GNUNET_HashCode lookup_key;
1698 struct ResolverHandle *rh_heap_root;
1700 pop_tld(rh->name, rh->authority_name);
1701 GNUNET_CRYPTO_short_hash(rh->authority_name,
1702 strlen(rh->authority_name),
1704 GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1705 GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
1706 GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
1708 rh->dht_heap_node = NULL;
1710 if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
1712 //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1713 // &dht_authority_lookup_timeout,
1715 rh->timeout_cont = &dht_authority_lookup_timeout;
1716 rh->timeout_cont_cls = rh;
1720 if (max_allowed_background_queries <=
1721 GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
1723 /* terminate oldest lookup */
1724 rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
1725 GNUNET_DHT_get_stop(rh_heap_root->get_handle);
1726 rh_heap_root->dht_heap_node = NULL;
1728 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1729 "GNS_PHASE_DELEGATE_DHT-%llu: Replacing oldest background query for %s\n",
1730 rh->id, rh_heap_root->authority_name);
1732 rh_heap_root->proc(rh_heap_root->proc_cls,
1737 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
1739 GNUNET_TIME_absolute_get().abs_value);
1742 xquery = htonl(GNUNET_GNS_RECORD_PKEY);
1744 GNUNET_assert(rh->get_handle == NULL);
1745 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
1746 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1748 DHT_GNS_REPLICATION_LEVEL,
1752 &process_delegation_result_dht,
1759 * Namestore resolution for delegation finished. Processing result.
1761 * @param cls the closure
1762 * @param rh resolver handle
1763 * @param rd_count number of results (always 0)
1764 * @param rd record data (always NULL)
1767 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
1768 unsigned int rd_count,
1769 const struct GNUNET_NAMESTORE_RecordData *rd)
1771 struct RecordLookupHandle* rlh;
1772 rlh = (struct RecordLookupHandle*) cls;
1774 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1775 "GNS_PHASE_DELEGATE_NS-%llu: Resolution status: %d.\n",
1776 rh->id, rh->status);
1778 if (strcmp(rh->name, "") == 0)
1780 if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1782 GNUNET_assert(rd_count == 1);
1783 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1784 "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried PKEY in NS.\n",
1786 finish_lookup(rh, rlh, rd_count, rd);
1787 free_resolver_handle(rh);
1790 /* We resolved full name for delegation. resolving record */
1791 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1792 "GNS_PHASE_DELEGATE_NS-%llu: Resolved full name for delegation.\n",
1794 strcpy(rh->name, "+\0");
1795 rh->proc = &handle_record_ns;
1796 resolve_record_ns(rh);
1801 * we still have some left
1802 * check if authority in ns is fresh
1804 * or we are authority
1806 if (((rh->status & RSL_RECORD_EXISTS) && (!(rh->status & RSL_RECORD_EXPIRED)))
1807 || !GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1808 &rh->private_local_zone))
1810 if (is_canonical(rh->name))
1812 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1813 "GNS_PHASE_DELEGATE_NS-%llu: Resolving canonical record %s\n",
1816 rh->proc = &handle_record_ns;
1817 resolve_record_ns(rh);
1821 /* give up, cannot resolve */
1822 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1823 "GNS_PHASE_DELEGATE_NS-%llu: Cannot fully resolve delegation for %s!\n",
1826 finish_lookup(rh, rlh, rd_count, rd);
1827 //rlh->proc(rlh->proc_cls, 0, NULL);
1832 if (rh->only_cached == GNUNET_YES)
1834 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1835 "GNS_PHASE_DELEGATE_NS-%llu: Only cache resolution, no result\n",
1837 finish_lookup(rh, rlh, rd_count, rd);
1841 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1842 "GNS_PHASE_DELEGATE_NS-%llu: Trying to resolve delegation for %s via DHT\n",
1844 rh->proc = &handle_delegation_dht;
1845 resolve_delegation_dht(rh);
1851 * This is a callback function that should give us only PKEY
1852 * records. Used to query the namestore for the authority (PKEY)
1853 * for 'name'. It will recursively try to resolve the
1854 * authority for a given name from the namestore.
1856 * @param cls the pending query
1857 * @param key the key of the zone we did the lookup
1858 * @param expiration expiration date of the record data set in the namestore
1859 * @param name the name for which we need an authority
1860 * @param rd_count the number of records with 'name'
1861 * @param rd the record data
1862 * @param signature the signature of the authority for the record data
1865 process_delegation_result_ns(void* cls,
1866 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1867 struct GNUNET_TIME_Absolute expiration,
1869 unsigned int rd_count,
1870 const struct GNUNET_NAMESTORE_RecordData *rd,
1871 const struct GNUNET_CRYPTO_RsaSignature *signature)
1873 struct ResolverHandle *rh;
1874 struct GNUNET_TIME_Relative remaining_time;
1875 struct GNUNET_CRYPTO_ShortHashCode zone;
1876 char new_name[MAX_DNS_NAME_LENGTH];
1878 rh = (struct ResolverHandle *)cls;
1879 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1880 "GNS_PHASE_DELEGATE_NS-%llu: Got %d records from authority lookup\n",
1883 GNUNET_CRYPTO_short_hash(key,
1884 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1886 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1892 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1893 "GNS_PHASE_DELEGATE_NS-%llu: Records with name %s exist.\n",
1895 rh->status |= RSL_RECORD_EXISTS;
1898 if (remaining_time.rel_value == 0)
1900 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1901 "GNS_PHASE_DELEGATE_NS-%llu: Record set %s expired.\n",
1903 rh->status |= RSL_RECORD_EXPIRED;
1907 * No authority found in namestore.
1912 * We did not find an authority in the namestore
1917 * Promote this authority back to a name maybe it is
1920 if (strcmp(rh->name, "") == 0)
1922 /* simply promote back */
1923 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1924 "GNS_PHASE_DELEGATE_NS-%llu: Promoting %s back to name\n",
1925 rh->id, rh->authority_name);
1926 strcpy(rh->name, rh->authority_name);
1930 /* add back to existing name */
1931 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1932 "GNS_PHASE_DELEGATE_NS-%llu: Adding %s back to %s\n",
1933 rh->id, rh->authority_name, rh->name);
1934 //memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
1935 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
1936 rh->name, rh->authority_name);
1937 //strcpy(new_name, rh->name);
1938 //strcpy(new_name+strlen(new_name), ".");
1939 //strcpy(new_name+strlen(new_name), rh->authority_name);
1940 strcpy(rh->name, new_name);
1941 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1942 "GNS_PHASE_DELEGATE_NS-%llu: %s restored\n", rh->id, rh->name);
1944 rh->proc(rh->proc_cls, rh, 0, NULL);
1949 * We found an authority that may be able to help us
1950 * move on with query
1951 * Note only 1 pkey should have been returned.. anything else would be strange
1954 for (i=0; i<rd_count;i++)
1957 if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
1960 if (ignore_pending_records &&
1961 (rd[i].flags & GNUNET_NAMESTORE_RF_PENDING))
1963 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1964 "GNS_PHASE_DELEGATE_NS-%llu: PKEY for %s is pending user confirmation.\n",
1970 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
1973 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1974 "GNS_PHASE_DELEGATE_NS-%llu: This pkey is expired.\n",
1976 if (remaining_time.rel_value == 0)
1978 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1979 "GNS_PHASE_DELEGATE_NS-%llu: This dht entry is expired.\n",
1981 rh->authority_chain_head->fresh = 0;
1982 rh->proc(rh->proc_cls, rh, 0, NULL);
1990 * Resolve rest of query with new authority
1992 GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
1993 memcpy(&rh->authority, rd[i].data,
1994 sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1995 struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
1996 auth->zone = rh->authority;
1997 memset(auth->name, 0, strlen(rh->authority_name)+1);
1998 strcpy(auth->name, rh->authority_name);
1999 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
2000 rh->authority_chain_tail,
2003 /** try to import pkey if private key available
2004 * TODO: Only import last one?
2006 if (rh->priv_key && (name != NULL) && is_canonical (rh->name))
2007 process_discovered_authority((char*)name, auth->zone,
2008 rh->authority_chain_tail->zone,
2011 * We are done with PKEY resolution if name is empty
2012 * else resolve again with new authority
2014 if (strcmp(rh->name, "") == 0)
2015 rh->proc(rh->proc_cls, rh, rd_count, rd);
2017 resolve_delegation_ns(rh);
2024 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2025 "GNS_PHASE_DELEGATE_NS-%llu: Authority lookup and no PKEY...\n", rh->id);
2027 * If we have found some records for the LAST label
2028 * we return the results. Else null.
2030 if (strcmp(rh->name, "") == 0)
2032 /* simply promote back */
2033 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2034 "GNS_PHASE_DELEGATE_NS-%llu: Promoting %s back to name\n",
2035 rh->id, rh->authority_name);
2036 strcpy(rh->name, rh->authority_name);
2037 rh->proc(rh->proc_cls, rh, rd_count, rd);
2041 rh->proc(rh->proc_cls, rh, 0, NULL);
2047 * Resolve the delegation chain for the request in our namestore
2049 * @param rh the resolver handle
2052 resolve_delegation_ns(struct ResolverHandle *rh)
2054 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2055 "GNS_PHASE_DELEGATE_NS-%llu: Resolving delegation for %s\n",
2057 pop_tld(rh->name, rh->authority_name);
2058 GNUNET_NAMESTORE_lookup_record(namestore_handle,
2061 GNUNET_GNS_RECORD_ANY,
2062 &process_delegation_result_ns,
2069 * Lookup of a record in a specific zone
2070 * calls lookup result processor on result
2072 * @param zone the root zone
2073 * @param pzone the private local zone
2074 * @param record_type the record type to look up
2075 * @param name the name to look up
2076 * @param key a private key for use with PSEU import (can be NULL)
2077 * @param timeout timeout for resolution
2078 * @param only_cached GNUNET_NO to only check locally not DHT for performance
2079 * @param proc the processor to call on result
2080 * @param cls the closure to pass to proc
2083 gns_resolver_lookup_record(struct GNUNET_CRYPTO_ShortHashCode zone,
2084 struct GNUNET_CRYPTO_ShortHashCode pzone,
2085 uint32_t record_type,
2087 struct GNUNET_CRYPTO_RsaPrivateKey *key,
2088 struct GNUNET_TIME_Relative timeout,
2090 RecordLookupProcessor proc,
2093 struct ResolverHandle *rh;
2094 struct RecordLookupHandle* rlh;
2095 char string_hash[MAX_DNS_LABEL_LENGTH];
2096 char nzkey[MAX_DNS_LABEL_LENGTH];
2097 char* nzkey_ptr = nzkey;
2099 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2100 "Starting resolution for %s (type=%d)!\n",
2104 if (is_canonical((char*)name) && (strcmp(GNUNET_GNS_TLD, name) != 0))
2106 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2107 "%s is canonical and not gnunet -> cannot resolve!\n", name);
2112 rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
2113 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2115 rh->authority = zone;
2119 rh->timeout = timeout;
2120 rh->get_handle = NULL;
2121 rh->private_local_zone = pzone;
2122 rh->only_cached = only_cached;
2124 if (timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
2127 * Set timeout for authority lookup phase to 1/2
2129 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2130 "Timeout for lookup set to %ds\n", rh->timeout.rel_value);
2131 rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
2132 GNUNET_TIME_relative_divide(timeout, 2),
2133 &handle_lookup_timeout,
2135 rh->timeout_cont = &dht_authority_lookup_timeout;
2136 rh->timeout_cont_cls = rh;
2140 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No timeout for query!\n");
2141 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2144 if (strcmp(GNUNET_GNS_TLD, name) == 0)
2147 * Only 'gnunet' given
2149 strcpy(rh->name, "\0");
2153 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2154 "Checking for TLD...\n");
2155 if (is_zkey_tld(name) == GNUNET_YES)
2157 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2160 * This is a zkey tld
2161 * build hash and use as initial authority
2164 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
2165 memcpy(rh->name, name,
2166 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
2167 pop_tld(rh->name, string_hash);
2169 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2170 "ZKEY is %s!\n", string_hash);
2172 GNUNET_STRINGS_utf8_toupper(string_hash, &nzkey_ptr);
2174 if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(nzkey,
2177 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2178 "Cannot convert ZKEY %s to hash!\n", string_hash);
2188 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2191 * Presumably GNUNET tld
2194 strlen(name)-strlen(GNUNET_GNS_TLD));
2195 memcpy(rh->name, name,
2196 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2201 * Initialize authority chain
2203 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2204 rh->authority_chain_head->prev = NULL;
2205 rh->authority_chain_head->next = NULL;
2206 rh->authority_chain_tail = rh->authority_chain_head;
2207 rh->authority_chain_head->zone = rh->authority;
2210 * Copy original query into lookup handle
2212 rlh->record_type = record_type;
2213 memset(rlh->name, 0, strlen(name) + 1);
2214 strcpy(rlh->name, name);
2216 rlh->proc_cls = cls;
2218 rh->proc = &handle_delegation_ns;
2219 resolve_delegation_ns(rh);
2222 /******** END Record Resolver ***********/
2226 * Callback calles by namestore for a zone to name
2229 * @param cls the closure
2230 * @param zone_key the zone we queried
2231 * @param expire the expiration time of the name
2232 * @param name the name found or NULL
2233 * @param rd_len number of records for the name
2234 * @param rd the record data (PKEY) for the name
2235 * @param signature the signature for the record data
2238 process_zone_to_name_shorten(void *cls,
2239 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
2240 struct GNUNET_TIME_Absolute expire,
2242 unsigned int rd_len,
2243 const struct GNUNET_NAMESTORE_RecordData *rd,
2244 const struct GNUNET_CRYPTO_RsaSignature *signature)
2246 struct ResolverHandle *rh = (struct ResolverHandle *)cls;
2247 struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
2248 struct AuthorityChain *next_authority;
2250 char result[MAX_DNS_NAME_LENGTH];
2251 char tmp_name[MAX_DNS_NAME_LENGTH];
2254 /* we found a match in our own zone */
2257 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2258 "result strlen %d\n", strlen(name));
2259 answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
2260 memset(result, 0, answer_len);
2261 if (strlen(rh->name) > 0)
2263 strcpy(result, rh->name);
2264 strcpy(result+strlen(rh->name), ".");
2267 strcpy(result+strlen(result), name);
2268 strcpy(result+strlen(result), ".");
2269 strcpy(result+strlen(result), GNUNET_GNS_TLD);
2271 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2272 "Sending shorten result %s\n", result);
2274 nsh->proc(nsh->proc_cls, result);
2276 free_resolver_handle(rh);
2278 else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2279 &rh->private_local_zone) == 0)
2281 /* our zone, just append .gnunet */
2282 answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
2283 memset(result, 0, answer_len);
2284 strcpy(result, rh->name);
2285 strcpy(result+strlen(rh->name), ".");
2286 strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
2288 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2289 "Our zone: Sending name as shorten result %s\n", rh->name);
2291 nsh->proc(nsh->proc_cls, result);
2293 free_resolver_handle(rh);
2299 * continue with next authority
2301 next_authority = rh->authority_chain_head;
2303 GNUNET_snprintf(tmp_name, MAX_DNS_NAME_LENGTH,
2304 "%s.%s", rh->name, next_authority->name);
2306 strcpy(rh->name, tmp_name);
2307 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2308 "No PSEU found for authority %s. Promoting back: %s\n",
2309 next_authority->name, rh->name);
2311 GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
2312 rh->authority_chain_tail,
2315 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2316 &rh->authority_chain_tail->zone,
2317 &rh->authority_chain_head->zone,
2318 &process_zone_to_name_shorten,
2324 * DHT resolution for delegation. Processing result.
2326 * @param cls the closure
2327 * @param rh resolver handle
2328 * @param rd_count number of results
2329 * @param rd record data
2332 handle_delegation_dht_bg_shorten(void* cls, struct ResolverHandle *rh,
2333 unsigned int rd_count,
2334 const struct GNUNET_NAMESTORE_RecordData *rd)
2337 /* We resolved full name for delegation. resolving record */
2338 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2339 "GNS_SHORTEN: Resolved up to %s for delegation via DHT in background.\n",
2341 free_resolver_handle(rh);
2345 * Process result from namestore delegation lookup
2346 * for shorten operation
2348 * @param cls the client shorten handle
2349 * @param rh the resolver handle
2350 * @param rd_count number of results (0)
2351 * @param rd data (NULL)
2354 handle_delegation_ns_shorten(void* cls,
2355 struct ResolverHandle *rh,
2357 const struct GNUNET_NAMESTORE_RecordData *rd)
2359 struct NameShortenHandle *nsh;
2360 char result[MAX_DNS_NAME_LENGTH];
2362 struct ResolverHandle *rh_bg;
2364 nsh = (struct NameShortenHandle *)cls;
2367 * At this point rh->name contains the part of the name
2368 * that we do not have a PKEY in our namestore to resolve.
2369 * The authority chain in the resolver handle is now
2370 * useful to backtrack if needed
2373 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2374 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2376 if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2377 &rh->private_local_zone) == 0)
2380 * This is our zone append .gnunet unless name is empty
2381 * (it shouldn't be, usually FIXME what happens if we
2382 * shorten to our zone to a "" record??)
2385 answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
2386 memset(result, 0, answer_len);
2387 strcpy(result, rh->name);
2388 strcpy(result+strlen(rh->name), ".");
2389 strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
2391 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2392 "Our zone: Sending name as shorten result %s\n", rh->name);
2394 nsh->proc(nsh->proc_cls, result);
2396 free_resolver_handle(rh);
2401 * we have to this before zone to name for rh might
2405 if (!is_canonical(rh->name))
2407 rh_bg = GNUNET_malloc(sizeof(struct ResolverHandle));
2408 memcpy(rh_bg, rh, sizeof(struct ResolverHandle));
2412 /* backtrack authorities for names */
2413 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2414 &rh->authority_chain_tail->zone, //ours
2415 &rh->authority_chain_head->zone,
2416 &process_zone_to_name_shorten,
2425 * If authority resolution is incomplete we can do a background lookup
2426 * of the full name so that next time we can (likely) fully or at least
2427 * further shorten the name
2429 rh_bg->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2430 rh_bg->authority_chain_tail = rh_bg->authority_chain_head;
2431 rh_bg->authority_chain_head->zone = rh_bg->authority;
2433 rh_bg->proc = &handle_delegation_dht_bg_shorten;
2434 rh_bg->proc_cls = NULL;
2435 rh_bg->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
2437 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2438 "GNS_SHORTEN: Starting background lookup for %s\n",
2441 resolve_delegation_dht(rh_bg);
2447 * Callback calles by namestore for a zone to name
2450 * @param cls the closure
2451 * @param zone_key the zone we queried
2452 * @param expire the expiration time of the name
2453 * @param name the name found or NULL
2454 * @param rd_len number of records for the name
2455 * @param rd the record data (PKEY) for the name
2456 * @param signature the signature for the record data
2459 process_zone_to_name_zkey(void *cls,
2460 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
2461 struct GNUNET_TIME_Absolute expire,
2463 unsigned int rd_len,
2464 const struct GNUNET_NAMESTORE_RecordData *rd,
2465 const struct GNUNET_CRYPTO_RsaSignature *signature)
2467 struct ResolverHandle *rh = cls;
2468 struct NameShortenHandle *nsh = rh->proc_cls;
2469 struct GNUNET_CRYPTO_ShortHashAsciiEncoded enc;
2470 char new_name[MAX_DNS_NAME_LENGTH];
2472 /* zkey not in our zone */
2476 * In this case we have not given this PKEY a name (yet)
2477 * It is either just not in our zone or not even cached
2478 * Since we do not know at this point we will not try to shorten
2479 * because PKEY import will happen if the user follows the zkey
2482 GNUNET_CRYPTO_short_hash_to_enc ((struct GNUNET_CRYPTO_ShortHashCode*)rd,
2484 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2485 "No name found for zkey %s returning verbatim!\n", enc);
2486 if (strcmp(rh->name, "") != 0)
2487 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s.%s",
2488 rh->name, enc, GNUNET_GNS_TLD_ZKEY);
2490 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
2491 enc, GNUNET_GNS_TLD_ZKEY);
2492 nsh->proc(nsh->proc_cls, new_name);
2494 free_resolver_handle(rh);
2498 if (strcmp(rh->name, "") != 0)
2499 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
2502 strcpy(new_name, name);
2504 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2505 "Continue shorten for %s!\n", new_name);
2507 strcpy(rh->name, new_name);
2509 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2510 rh->authority_chain_tail = rh->authority_chain_head;
2511 rh->authority_chain_head->zone = rh->authority;
2514 /* Start delegation resolution in our namestore */
2515 resolve_delegation_ns(rh);
2520 * Shorten api from resolver
2522 * @param zone the zone to use
2523 * @param pzone the private local zone
2524 * @param name the name to shorten
2525 * @param key optional private key for background lookups and PSEU import
2526 * @param proc the processor to call with result
2527 * @param proc_cls closure to pass to proc
2530 gns_resolver_shorten_name(struct GNUNET_CRYPTO_ShortHashCode zone,
2531 struct GNUNET_CRYPTO_ShortHashCode pzone,
2533 struct GNUNET_CRYPTO_RsaPrivateKey *key,
2534 ShortenResultProcessor proc,
2537 struct ResolverHandle *rh;
2538 struct NameShortenHandle *nsh;
2539 char string_hash[MAX_DNS_LABEL_LENGTH];
2540 struct GNUNET_CRYPTO_ShortHashCode zkey;
2541 char nzkey[MAX_DNS_LABEL_LENGTH];
2542 char* nzkey_ptr = nzkey;
2545 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2546 "Starting shorten for %s!\n", name);
2548 if (is_canonical((char*)name))
2550 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2551 "%s is canonical. Returning verbatim\n", name);
2552 proc(proc_cls, name);
2556 nsh = GNUNET_malloc(sizeof (struct NameShortenHandle));
2559 nsh->proc_cls = proc_cls;
2561 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2562 rh->authority = zone;
2565 rh->proc = &handle_delegation_ns_shorten;
2568 rh->private_local_zone = pzone;
2570 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2571 "Checking for TLD...\n");
2572 if (is_zkey_tld(name) == GNUNET_YES)
2574 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2577 * This is a zkey tld
2578 * build hash and use as initial authority
2582 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
2583 memcpy(rh->name, name,
2584 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
2585 pop_tld(rh->name, string_hash);
2587 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2588 "ZKEY is %s!\n", string_hash);
2590 GNUNET_STRINGS_utf8_toupper(string_hash, &nzkey_ptr);
2592 if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(nzkey,
2595 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2596 "Cannot convert ZKEY %s to hash!\n", nzkey);
2599 proc(proc_cls, name);
2603 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2606 &process_zone_to_name_zkey,
2613 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2616 * Presumably GNUNET tld
2619 strlen(name)-strlen(GNUNET_GNS_TLD));
2620 memcpy(rh->name, name,
2621 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2624 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2625 rh->authority_chain_tail = rh->authority_chain_head;
2626 rh->authority_chain_head->zone = zone;
2629 /* Start delegation resolution in our namestore */
2630 resolve_delegation_ns(rh);
2633 /*********** END NAME SHORTEN ********************/
2637 * Process result from namestore delegation lookup
2638 * for get authority operation
2640 * @param cls the client get auth handle
2641 * @param rh the resolver handle
2642 * @param rd_count number of results (0)
2643 * @param rd data (NULL)
2646 handle_delegation_result_ns_get_auth(void* cls,
2647 struct ResolverHandle *rh,
2649 const struct GNUNET_NAMESTORE_RecordData *rd)
2651 struct GetNameAuthorityHandle* nah;
2652 char result[MAX_DNS_NAME_LENGTH];
2655 nah = (struct GetNameAuthorityHandle*) rh->proc_cls;
2658 * At this point rh->name contains the part of the name
2659 * that we do not have a PKEY in our namestore to resolve.
2660 * The authority chain in the resolver handle is now
2661 * useful to backtrack if needed
2664 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2665 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2667 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2668 "Building response!\n");
2669 if (is_canonical(rh->name))
2672 * We successfully resolved the authority in the ns
2673 * FIXME for our purposes this is fine
2674 * but maybe we want to have an api that also looks
2675 * into the dht (i.e. option in message)
2677 if (strlen(rh->name) > strlen(nah->name))
2679 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2680 "Record name longer than original lookup name... odd!\n");
2684 answer_len = strlen(nah->name) - strlen(rh->name)
2685 + strlen(GNUNET_GNS_TLD) + 1;
2686 memset(result, 0, answer_len);
2687 strcpy(result, nah->name + strlen(rh->name) + 1);
2689 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2690 "Got authority result %s\n", result);
2692 nah->proc(nah->proc_cls, result);
2694 free_resolver_handle(rh);
2698 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2699 "Unable to resolve authority for remaining %s!\n", rh->name);
2700 nah->proc(nah->proc_cls, "");
2702 free_resolver_handle(rh);
2710 * Tries to resolve the authority for name
2713 * @param zone the root zone to look up for
2714 * @param pzone the private local zone
2715 * @param name the name to lookup up
2716 * @param proc the processor to call when finished
2717 * @param proc_cls the closure to pass to the processor
2720 gns_resolver_get_authority(struct GNUNET_CRYPTO_ShortHashCode zone,
2721 struct GNUNET_CRYPTO_ShortHashCode pzone,
2723 GetAuthorityResultProcessor proc,
2726 struct ResolverHandle *rh;
2727 struct GetNameAuthorityHandle *nah;
2729 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2730 "Starting authority resolution for %s!\n", name);
2732 nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
2733 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2734 rh->authority = zone;
2736 rh->private_local_zone = pzone;
2738 if (strcmp(GNUNET_GNS_TLD, name) == 0)
2740 strcpy(rh->name, "\0");
2745 strlen(name)-strlen(GNUNET_GNS_TLD));
2746 memcpy(rh->name, name,
2747 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2750 memset(nah->name, 0,
2752 strcpy(nah->name, name);
2754 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2755 rh->authority_chain_tail = rh->authority_chain_head;
2756 rh->authority_chain_head->zone = zone;
2757 rh->proc = &handle_delegation_result_ns_get_auth;
2758 rh->proc_cls = (void*)nah;
2761 nah->proc_cls = proc_cls;
2763 /* Start delegation resolution in our namestore */
2764 resolve_delegation_ns(rh);
2768 /******** END GET AUTHORITY *************/
2770 /* end of gnunet-service-gns_resolver.c */