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_OPERATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)
42 #define DHT_LOOKUP_TIMEOUT DHT_OPERATION_TIMEOUT
43 #define DHT_GNS_REPLICATION_LEVEL 5
44 #define MAX_DNS_LABEL_LENGTH 63
48 * Our handle to the namestore service
50 static struct GNUNET_NAMESTORE_Handle *namestore_handle;
53 * Resolver handle to the dht
55 static struct GNUNET_DHT_Handle *dht_handle;
58 * Heap for parallel DHT lookups
60 static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
63 * Maximum amount of parallel queries in background
65 static unsigned long long max_allowed_background_queries;
70 static struct GNUNET_CRYPTO_ShortHashCode local_zone;
73 * Namestore calls this function if we have record for this name.
74 * (or with rd_count=0 to indicate no matches)
76 * @param cls the pending query
77 * @param key the key of the zone we did the lookup
78 * @param expiration expiration date of the namestore entry
79 * @param name the name for which we need an authority
80 * @param rd_count the number of records with 'name'
81 * @param rd the record data
82 * @param signature the signature of the authority for the record data
85 process_pseu_lookup_ns(void* cls,
86 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
87 struct GNUNET_TIME_Absolute expiration,
88 const char *name, unsigned int rd_count,
89 const struct GNUNET_NAMESTORE_RecordData *rd,
90 const struct GNUNET_CRYPTO_RsaSignature *signature)
92 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
93 struct GNUNET_NAMESTORE_RecordData new_pkey;
97 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
98 "GNS_AUTO_PSEU: Name %s already taken in NS!\n", name);
99 if (0 == strcmp(gph->name, name))
101 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
102 "GNS_AUTO_PSEU: Intelligent replacement not implemented\n",
108 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
109 "GNS_AUTO_PSEU: Trying delegated name %s\n", gph->name);
110 memcpy(gph->new_name, gph->name, strlen(gph->name)+1);
111 GNUNET_NAMESTORE_lookup_record(namestore_handle,
114 GNUNET_GNS_RECORD_PSEU,
115 &process_pseu_lookup_ns,
121 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
122 "GNS_AUTO_PSEU: Name %s not taken in NS! Adding\n", gph->new_name);
124 new_pkey.expiration = GNUNET_TIME_absolute_get_forever ();
125 new_pkey.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode);
126 new_pkey.data = &gph->new_zone;
127 new_pkey.record_type = GNUNET_GNS_RECORD_PKEY;
128 GNUNET_NAMESTORE_record_create (namestore_handle,
139 * process result of a dht pseu lookup
141 * @param gph the handle
142 * @param name the pseu result or NULL
145 process_pseu_result(struct GetPseuAuthorityHandle* gph, char* name)
149 memcpy(gph->new_name, gph->name, strlen(gph->name)+1);
153 memcpy(gph->new_name, name, strlen(name)+1);
156 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
157 "GNS_AUTO_PSEU: Checking %s for collision in NS\n", gph->new_name);
160 * Check for collision
162 GNUNET_NAMESTORE_lookup_record(namestore_handle,
165 GNUNET_GNS_RECORD_PSEU,
166 &process_pseu_lookup_ns,
171 * Handle timeout for dht request
173 * @param cls the request handle as closure
174 * @param tc the task context
177 handle_auth_discovery_timeout(void *cls,
178 const struct GNUNET_SCHEDULER_TaskContext *tc)
180 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
182 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
183 "GNS_GET_AUTH: dht lookup for query PSEU timed out.\n");
184 GNUNET_DHT_get_stop (gph->get_handle);
185 gph->get_handle = NULL;
186 process_pseu_result(gph, NULL);
190 * Function called when we find a PSEU entry in the DHT
192 * @param cls the request handle
193 * @param exp lifetime
194 * @param key the key the record was stored under
195 * @param get_path get path
196 * @param get_path_length get path length
197 * @param put_path put path
198 * @param put_path_length put path length
199 * @param type the block type
200 * @param size the size of the record
201 * @param data the record data
204 process_auth_discovery_dht_result(void* cls,
205 struct GNUNET_TIME_Absolute exp,
206 const GNUNET_HashCode * key,
207 const struct GNUNET_PeerIdentity *get_path,
208 unsigned int get_path_length,
209 const struct GNUNET_PeerIdentity *put_path,
210 unsigned int put_path_length,
211 enum GNUNET_BLOCK_Type type,
212 size_t size, const void *data)
214 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
215 struct GNSNameRecordBlock *nrb;
216 char* rd_data = (char*)data;
222 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
223 "GNS_GET_AUTH: got dht result (size=%d)\n", size);
227 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
228 "GNS_GET_AUTH: got dht result null!\n", size);
234 nrb = (struct GNSNameRecordBlock*)data;
236 /* stop lookup and timeout task */
237 GNUNET_DHT_get_stop (gph->get_handle);
238 gph->get_handle = NULL;
239 GNUNET_SCHEDULER_cancel(gph->timeout);
241 gph->get_handle = NULL;
243 nrb = (struct GNSNameRecordBlock*)data;
245 name = (char*)&nrb[1];
246 num_records = ntohl(nrb->rd_count);
248 struct GNUNET_NAMESTORE_RecordData rd[num_records];
250 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
251 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
253 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
258 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
259 "GNS_GET_AUTH: Error deserializing data!\n");
265 for (i=0; i<num_records; i++)
267 if ((strcmp(name, "+") == 0) &&
268 (rd[i].record_type == GNUNET_GNS_RECORD_PSEU))
271 process_pseu_result(gph, (char*)rd[i].data);
277 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_GET_AUTH: no pseu in dht!\n");
278 process_pseu_result(gph, NULL);
282 * Callback called by namestore for a zone to name
285 * @param cls the closure
286 * @param zone_key the zone we queried
287 * @param expire the expiration time of the name
288 * @param name the name found or NULL
289 * @param rd_len number of records for the name
290 * @param rd the record data (PKEY) for the name
291 * @param signature the signature for the record data
294 process_zone_to_name_discover(void *cls,
295 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
296 struct GNUNET_TIME_Absolute expire,
299 const struct GNUNET_NAMESTORE_RecordData *rd,
300 const struct GNUNET_CRYPTO_RsaSignature *signature)
302 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
304 /* we found a match in our own zone */
307 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
308 "GNS_AUTO_PSEU: name for zone in our root %d\n", strlen(name));
318 struct GNUNET_CRYPTO_ShortHashCode name_hash;
319 GNUNET_HashCode lookup_key;
320 struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
321 GNUNET_HashCode name_hash_double;
322 GNUNET_HashCode zone_hash_double;
324 GNUNET_CRYPTO_short_hash("+", strlen("+"), &name_hash);
325 GNUNET_CRYPTO_short_hash_double (&name_hash, &name_hash_double);
326 GNUNET_CRYPTO_short_hash_double (&gph->new_zone, &zone_hash_double);
327 GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
328 GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
330 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
331 "GNS_AUTO_PSEU: starting dht lookup for %s with key: %s\n",
332 "+", (char*)&lookup_key_string);
334 gph->timeout = GNUNET_SCHEDULER_add_delayed(DHT_LOOKUP_TIMEOUT,
335 &handle_auth_discovery_timeout, gph);
337 xquery = htonl(GNUNET_GNS_RECORD_PSEU);
339 GNUNET_assert(gph->get_handle == NULL);
340 gph->get_handle = GNUNET_DHT_get_start(dht_handle,
341 GNUNET_TIME_UNIT_FOREVER_REL,
342 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
344 DHT_GNS_REPLICATION_LEVEL,
348 &process_auth_discovery_dht_result,
356 * Callback for new authories
358 * @param name the name given by delegation
359 * @param zone the authority
360 * @param our_zone our local zone
361 * @param the private key of our authority
363 static void process_discovered_authority(char* name,
364 struct GNUNET_CRYPTO_ShortHashCode zone,
365 struct GNUNET_CRYPTO_ShortHashCode our_zone,
366 struct GNUNET_CRYPTO_RsaPrivateKey *key)
368 struct GetPseuAuthorityHandle *gph;
371 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
372 "GNS_AUTO_PSEU: New authority %s discovered\n",
375 gph = GNUNET_malloc(sizeof(struct GetPseuAuthorityHandle));
376 namelen = strlen(name) + 1;
377 memcpy(gph->name, name, namelen);
379 gph->new_zone = zone;
380 gph->zone = our_zone;
383 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
386 &process_zone_to_name_discover,
392 * Initialize the resolver
394 * @param nh the namestore handle
395 * @param dh the dht handle
396 * @param lz the local zone's hash
397 * @return GNUNET_OK on success
400 gns_resolver_init(struct GNUNET_NAMESTORE_Handle *nh,
401 struct GNUNET_DHT_Handle *dh,
402 struct GNUNET_CRYPTO_ShortHashCode lz,
403 unsigned long long max_bg_queries)
405 namestore_handle = nh;
409 GNUNET_CONTAINER_heap_create(GNUNET_CONTAINER_HEAP_ORDER_MIN);
410 max_allowed_background_queries = max_bg_queries;
412 if ((namestore_handle != NULL) && (dht_handle != NULL))
416 return GNUNET_SYSERR;
420 * Cleanup background lookups
422 * @param cls closure to iterator
423 * @param node heap nodes
424 * @param element the resolver handle
425 * @param cost heap cost
426 * @return always GNUNET_YES
429 cleanup_pending_background_queries(void* cls,
430 struct GNUNET_CONTAINER_HeapNode *node,
432 GNUNET_CONTAINER_HeapCostType cost)
434 struct ResolverHandle *rh = (struct ResolverHandle *)element;
435 ResolverCleanupContinuation cont = cls;
437 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
438 "GNS_CLEANUP: Terminating background lookup for %s\n",
440 GNUNET_DHT_get_stop(rh->get_handle);
441 rh->get_handle = NULL;
442 rh->proc(rh->proc_cls, rh, 0, NULL);
444 GNUNET_CONTAINER_heap_remove_node(node);
446 if (GNUNET_CONTAINER_heap_get_size(dht_lookup_heap) == 0)
458 gns_resolver_cleanup(ResolverCleanupContinuation cont)
460 unsigned int s = GNUNET_CONTAINER_heap_get_size(dht_lookup_heap);
461 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
462 "GNS_CLEANUP: %d pending background queries to terminate\n", s);
465 GNUNET_CONTAINER_heap_iterate (dht_lookup_heap,
466 &cleanup_pending_background_queries,
474 * Helper function to free resolver handle
476 * @param rh the handle to free
479 free_resolver_handle(struct ResolverHandle* rh)
481 struct AuthorityChain *ac;
482 struct AuthorityChain *ac_next;
487 ac = rh->authority_chain_head;
500 * Callback when record data is put into namestore
502 * @param cls the closure
503 * @param success GNUNET_OK on success
504 * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
507 on_namestore_record_put_result(void *cls,
511 if (GNUNET_NO == success)
513 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
514 "GNS_NS: records already in namestore\n");
517 else if (GNUNET_YES == success)
519 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
520 "GNS_NS: records successfully put in namestore\n");
524 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
525 "GNS_NS: Error putting records into namestore: %s\n", emsg);
529 handle_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
531 struct ResolverHandle *rh = cls;
533 if (rh->timeout_cont)
534 rh->timeout_cont(rh->timeout_cont_cls, tc);
538 * Processor for background lookups in the DHT
540 * @param cls closure (NULL)
541 * @param rd_count number of records found (not 0)
542 * @param rd record data
545 background_lookup_result_processor(void *cls,
547 const struct GNUNET_NAMESTORE_RecordData *rd)
549 //We could do sth verbose/more useful here but it doesn't make any difference
550 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
551 "GNS_BG: background dht lookup for finished.\n");
555 * Handle timeout for DHT requests
557 * @param cls the request handle as closure
558 * @param tc the task context
561 dht_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
563 struct ResolverHandle *rh = cls;
564 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
565 char new_name[MAX_DNS_NAME_LENGTH];
567 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
568 "GNS_PHASE_REC: dht lookup for query %s timed out.\n",
571 * Start resolution in bg
573 //strcpy(new_name, rh->name);
574 //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD));
575 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
576 rh->name, GNUNET_GNS_TLD);
578 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
579 "GNS_PHASE_REC: Starting background lookup for %s type %d\n",
580 new_name, rlh->record_type);
582 gns_resolver_lookup_record(rh->authority,
586 GNUNET_TIME_UNIT_FOREVER_REL,
587 &background_lookup_result_processor,
589 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
591 GNUNET_DHT_get_stop (rh->get_handle);
592 rh->get_handle = NULL;
593 rh->proc(rh->proc_cls, rh, 0, NULL);
598 * Function called when we get a result from the dht
599 * for our record query
601 * @param cls the request handle
602 * @param exp lifetime
603 * @param key the key the record was stored under
604 * @param get_path get path
605 * @param get_path_length get path length
606 * @param put_path put path
607 * @param put_path_length put path length
608 * @param type the block type
609 * @param size the size of the record
610 * @param data the record data
613 process_record_result_dht(void* cls,
614 struct GNUNET_TIME_Absolute exp,
615 const GNUNET_HashCode * key,
616 const struct GNUNET_PeerIdentity *get_path,
617 unsigned int get_path_length,
618 const struct GNUNET_PeerIdentity *put_path,
619 unsigned int put_path_length,
620 enum GNUNET_BLOCK_Type type,
621 size_t size, const void *data)
623 struct ResolverHandle *rh;
624 struct RecordLookupHandle *rlh;
625 struct GNSNameRecordBlock *nrb;
626 uint32_t num_records;
628 char* rd_data = (char*)data;
632 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
633 "GNS_PHASE_REC: got dht result (size=%d)\n", size);
638 //FIXME maybe check expiration here, check block type
640 rh = (struct ResolverHandle *)cls;
641 rlh = (struct RecordLookupHandle *) rh->proc_cls;
642 nrb = (struct GNSNameRecordBlock*)data;
644 /* stop lookup and timeout task */
645 GNUNET_DHT_get_stop (rh->get_handle);
646 rh->get_handle = NULL;
648 if (rh->dht_heap_node != NULL)
650 GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
651 rh->dht_heap_node = NULL;
654 if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
656 GNUNET_SCHEDULER_cancel(rh->timeout_task);
657 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
660 rh->get_handle = NULL;
661 name = (char*)&nrb[1];
662 num_records = ntohl(nrb->rd_count);
664 struct GNUNET_NAMESTORE_RecordData rd[num_records];
666 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
667 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
669 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
674 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
678 for (i=0; i<num_records; i++)
680 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
681 "GNS_PHASE_REC: Got name: %s (wanted %s)\n", name, rh->name);
682 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
683 "GNS_PHASE_REC: Got type: %d\n",
685 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
686 "GNS_PHASE_REC: Got data length: %d\n", rd[i].data_size);
687 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
688 "GNS_PHASE_REC: Got flag %d\n", rd[i].flags);
690 if ((strcmp(name, rh->name) == 0) &&
691 (rd[i].record_type == rlh->record_type))
699 * FIXME check pubkey against existing key in namestore?
700 * https://gnunet.org/bugs/view.php?id=2179
703 /* Save to namestore */
704 GNUNET_NAMESTORE_record_put (namestore_handle,
711 &on_namestore_record_put_result, //cont
716 rh->proc(rh->proc_cls, rh, num_records, rd);
718 rh->proc(rh->proc_cls, rh, 0, NULL);
725 * Start DHT lookup for a (name -> query->record_type) record in
726 * rh->authority's zone
728 * @param rh the pending gns query context
731 resolve_record_dht(struct ResolverHandle *rh)
734 struct GNUNET_CRYPTO_ShortHashCode name_hash;
735 GNUNET_HashCode lookup_key;
736 GNUNET_HashCode name_hash_double;
737 GNUNET_HashCode zone_hash_double;
738 struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
739 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
740 struct ResolverHandle *rh_heap_root;
742 GNUNET_CRYPTO_short_hash(rh->name, strlen(rh->name), &name_hash);
743 GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
744 GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
745 GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
746 GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
748 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
749 "GNS_PHASE_REC: starting dht lookup for %s with key: %s\n",
750 rh->name, (char*)&lookup_key_string);
752 //rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
753 rh->dht_heap_node = NULL;
755 if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
758 * Update timeout if necessary
760 if (rh->timeout_task == GNUNET_SCHEDULER_NO_TASK)
763 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
764 "GNS_PHASE_REC: Adjusting timeout\n");
766 * Set timeout for authority lookup phase to 1/2
768 rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
769 GNUNET_TIME_relative_divide(rh->timeout, 2),
770 &handle_lookup_timeout,
773 //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
774 // &dht_lookup_timeout,
776 rh->timeout_cont = &dht_lookup_timeout;
777 rh->timeout_cont_cls = rh;
781 if (max_allowed_background_queries <=
782 GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
784 rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
785 GNUNET_DHT_get_stop(rh_heap_root->get_handle);
786 rh_heap_root->get_handle = NULL;
787 rh_heap_root->dht_heap_node = NULL;
789 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
790 "GNS_PHASE_REC: Replacing oldest background query for %s\n",
792 rh_heap_root->proc(rh_heap_root->proc_cls,
797 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
799 GNUNET_TIME_absolute_get().abs_value);
802 xquery = htonl(rlh->record_type);
804 GNUNET_assert(rh->get_handle == NULL);
805 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
806 GNUNET_TIME_UNIT_FOREVER_REL,
807 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
809 DHT_GNS_REPLICATION_LEVEL,
813 &process_record_result_dht,
820 * Namestore calls this function if we have record for this name.
821 * (or with rd_count=0 to indicate no matches)
823 * @param cls the pending query
824 * @param key the key of the zone we did the lookup
825 * @param expiration expiration date of the namestore entry
826 * @param name the name for which we need an authority
827 * @param rd_count the number of records with 'name'
828 * @param rd the record data
829 * @param signature the signature of the authority for the record data
832 process_record_result_ns(void* cls,
833 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
834 struct GNUNET_TIME_Absolute expiration,
835 const char *name, unsigned int rd_count,
836 const struct GNUNET_NAMESTORE_RecordData *rd,
837 const struct GNUNET_CRYPTO_RsaSignature *signature)
839 struct ResolverHandle *rh;
840 struct RecordLookupHandle *rlh;
841 struct GNUNET_TIME_Relative remaining_time;
842 struct GNUNET_CRYPTO_ShortHashCode zone;
844 rh = (struct ResolverHandle *) cls;
845 rlh = (struct RecordLookupHandle *)rh->proc_cls;
846 GNUNET_CRYPTO_short_hash(key,
847 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
849 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
857 rh->status |= EXISTS;
860 if (remaining_time.rel_value == 0)
862 rh->status |= EXPIRED;
868 * Lookup terminated and no results
870 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
871 "GNS_PHASE_REC: Namestore lookup for %s terminated without results\n",
874 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
875 "GNS_PHASE_REC: Record %s unknown in namestore\n",
878 * Our zone and no result? Cannot resolve TT
880 rh->proc(rh->proc_cls, rh, 0, NULL);
887 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
888 "GNS_PHASE_REC: Processing additional result %s from namestore\n",
891 for (i=0; i<rd_count;i++)
894 if (rd[i].record_type != rlh->record_type)
897 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
900 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
901 "GNS_PHASE_REC: This record is expired. Skipping\n");
912 if (rh->answered == 0)
914 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
915 "GNS_PHASE_REC: No answers found. This is odd!\n");
916 rh->proc(rh->proc_cls, rh, 0, NULL);
920 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
921 "GNS_PHASE_REC: Found %d answer(s) to query in %d records!\n",
922 rh->answered, rd_count);
924 rh->proc(rh->proc_cls, rh, rd_count, rd);
930 * The final phase of resolution.
931 * rh->name is a name that is canonical and we do not have a delegation.
932 * Query namestore for this record
934 * @param rh the pending lookup
937 resolve_record_ns(struct ResolverHandle *rh)
939 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
941 /* We cancel here as to not include the ns lookup in the timeout */
942 if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
944 GNUNET_SCHEDULER_cancel(rh->timeout_task);
945 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
949 * Try to resolve this record in our namestore.
950 * The name to resolve is now in rh->authority_name
951 * since we tried to resolve it to an authority
954 GNUNET_NAMESTORE_lookup_record(namestore_handle,
958 &process_record_result_ns,
965 * Handle timeout for DHT requests
967 * @param cls the request handle as closure
968 * @param tc the task context
971 dht_authority_lookup_timeout(void *cls,
972 const struct GNUNET_SCHEDULER_TaskContext *tc)
974 struct ResolverHandle *rh = cls;
975 struct RecordLookupHandle *rlh = rh->proc_cls;
976 char new_name[MAX_DNS_NAME_LENGTH];
978 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
979 "GNS_PHASE_DELEGATE: dht lookup for query %s timed out.\n",
982 rh->status |= TIMED_OUT;
984 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
986 GNUNET_DHT_get_stop (rh->get_handle);
987 rh->get_handle = NULL;
989 if (strcmp(rh->name, "") == 0)
992 * promote authority back to name and try to resolve record
994 strcpy(rh->name, rh->authority_name);
995 rh->proc(rh->proc_cls, rh, 0, NULL);
1000 * Start resolution in bg
1002 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH,
1003 "%s.%s", rh->name, GNUNET_GNS_TLD);
1004 //strcpy(new_name, rh->name);
1005 //strcpy(new_name+strlen(new_name), ".");
1006 //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD));
1008 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1009 "GNS_PHASE_DELEGATE: Starting background query for %s type %d\n",
1010 new_name, rlh->record_type);
1012 gns_resolver_lookup_record(rh->authority,
1016 GNUNET_TIME_UNIT_FOREVER_REL,
1017 &background_lookup_result_processor,
1020 rh->proc(rh->proc_cls, rh, 0, NULL);
1024 static void resolve_delegation_dht(struct ResolverHandle *rh);
1027 static void resolve_delegation_ns(struct ResolverHandle *rh);
1030 * Function called when we get a result from the dht
1031 * for our query. Recursively tries to resolve authorities
1034 * @param cls the request handle
1035 * @param exp lifetime
1036 * @param key the key the record was stored under
1037 * @param get_path get path
1038 * @param get_path_length get path length
1039 * @param put_path put path
1040 * @param put_path_length put path length
1041 * @param type the block type
1042 * @param size the size of the record
1043 * @param data the record data
1046 process_delegation_result_dht(void* cls,
1047 struct GNUNET_TIME_Absolute exp,
1048 const GNUNET_HashCode * key,
1049 const struct GNUNET_PeerIdentity *get_path,
1050 unsigned int get_path_length,
1051 const struct GNUNET_PeerIdentity *put_path,
1052 unsigned int put_path_length,
1053 enum GNUNET_BLOCK_Type type,
1054 size_t size, const void *data)
1056 struct ResolverHandle *rh;
1057 struct GNSNameRecordBlock *nrb;
1058 uint32_t num_records;
1060 char* rd_data = (char*) data;
1063 struct GNUNET_CRYPTO_ShortHashCode zone, name_hash;
1064 GNUNET_HashCode zone_hash_double, name_hash_double;
1066 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE: Got DHT result\n");
1071 //FIXME check expiration?
1073 rh = (struct ResolverHandle *)cls;
1074 nrb = (struct GNSNameRecordBlock*)data;
1076 /* stop dht lookup and timeout task */
1077 GNUNET_DHT_get_stop (rh->get_handle);
1079 rh->get_handle = NULL;
1081 if (rh->dht_heap_node != NULL)
1083 GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
1084 rh->dht_heap_node = NULL;
1087 num_records = ntohl(nrb->rd_count);
1088 name = (char*)&nrb[1];
1090 struct GNUNET_NAMESTORE_RecordData rd[num_records];
1092 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
1093 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
1095 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
1100 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1101 "GNS_PHASE_DELEGATE: Error deserializing data!\n");
1105 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1106 "GNS_PHASE_DELEGATE: Got name: %s (wanted %s)\n",
1107 name, rh->authority_name);
1108 for (i=0; i<num_records; i++)
1111 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1112 "GNS_PHASE_DELEGATE: Got name: %s (wanted %s)\n",
1113 name, rh->authority_name);
1114 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1115 "GNS_PHASE_DELEGATE: Got type: %d (wanted %d)\n",
1116 rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
1117 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1118 "GNS_PHASE_DELEGATE: Got data length: %d\n",
1120 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1121 "GNS_PHASE_DELEGATE: Got flag %d\n", rd[i].flags);
1123 if ((strcmp(name, rh->authority_name) == 0) &&
1124 (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
1126 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1127 "GNS_PHASE_DELEGATE: Authority found in DHT\n");
1129 memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1130 struct AuthorityChain *auth =
1131 GNUNET_malloc(sizeof(struct AuthorityChain));
1132 auth->zone = rh->authority;
1133 memset(auth->name, 0, strlen(rh->authority_name)+1);
1134 strcpy(auth->name, rh->authority_name);
1135 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1136 rh->authority_chain_tail,
1139 /** try to import pkey if private key available */
1141 process_discovered_authority(name, auth->zone,
1142 rh->authority_chain_tail->zone,
1149 GNUNET_CRYPTO_short_hash(name, strlen(name), &name_hash);
1150 GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1151 GNUNET_CRYPTO_hash_xor(key, &name_hash_double, &zone_hash_double);
1152 GNUNET_CRYPTO_short_hash_from_truncation (&zone_hash_double, &zone);
1154 /* Save to namestore */
1155 if (0 != GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_tail->zone,
1158 GNUNET_NAMESTORE_record_put (namestore_handle,
1165 &on_namestore_record_put_result, //cont
1175 * FIXME in this case. should we ask namestore again?
1177 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1178 "GNS_PHASE_DELEGATE: Answer from DHT for %s to resolve: %s\n",
1179 rh->authority_name, rh->name);
1180 if (strcmp(rh->name, "") == 0)
1181 rh->proc(rh->proc_cls, rh, 0, NULL);
1183 resolve_delegation_ns(rh);
1188 * No pkey but name exists
1191 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1192 "GNS_PHASE_DELEGATE: Adding %s back to %s\n",
1193 rh->authority_name, rh->name);
1194 if (strcmp(rh->name, "") == 0)
1195 strcpy(rh->name, rh->authority_name);
1197 GNUNET_snprintf(rh->name, MAX_DNS_NAME_LENGTH, "%s.%s",
1198 rh->name, rh->authority_name); //FIXME ret
1200 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1201 "GNS_PHASE_DELEGATE: %s restored\n", rh->name);
1202 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1203 "GNS_PHASE_DELEGATE: DHT authority lookup found no match!\n");
1204 rh->proc(rh->proc_cls, rh, 0, NULL);
1207 #define MAX_SOA_LENGTH sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)\
1208 +(MAX_DNS_NAME_LENGTH*2)
1209 #define MAX_MX_LENGTH sizeof(uint16_t)+MAX_DNS_NAME_LENGTH
1213 expand_plus(char** dest, char* src, char* repl)
1216 unsigned int s_len = strlen(src)+1;
1218 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1219 "GNS_POSTPROCESS: Got %s to expand with %s\n", src, repl);
1223 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1224 "GNS_POSTPROCESS: %s to short\n", src);
1226 /* no postprocessing */
1227 memcpy(*dest, src, s_len+1);
1231 if (0 == strcmp(src+s_len-3, ".+"))
1233 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1234 "GNS_POSTPROCESS: Expanding .+ in %s\n", src);
1235 memset(*dest, 0, s_len+strlen(repl)+strlen(GNUNET_GNS_TLD));
1237 pos = *dest+s_len-2;
1239 pos += strlen(repl);
1240 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1241 "GNS_POSTPROCESS: Expanded to %s\n", *dest);
1245 memcpy(*dest, src, s_len+1);
1253 finish_lookup(struct ResolverHandle *rh,
1254 struct RecordLookupHandle* rlh,
1255 unsigned int rd_count,
1256 const struct GNUNET_NAMESTORE_RecordData *rd)
1259 char new_rr_data[MAX_DNS_NAME_LENGTH];
1260 char new_mx_data[MAX_MX_LENGTH];
1261 char new_soa_data[MAX_SOA_LENGTH];
1262 struct GNUNET_NAMESTORE_RecordData p_rd[rd_count];
1265 unsigned int offset;
1267 if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1268 GNUNET_SCHEDULER_cancel(rh->timeout_task);
1271 memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData));
1273 for (i = 0; i < rd_count; i++)
1276 if (rd[i].record_type != GNUNET_GNS_RECORD_TYPE_NS &&
1277 rd[i].record_type != GNUNET_GNS_RECORD_TYPE_CNAME &&
1278 rd[i].record_type != GNUNET_GNS_RECORD_MX &&
1279 rd[i].record_type != GNUNET_GNS_RECORD_TYPE_SOA)
1281 p_rd[i].data = rd[i].data;
1286 * for all those records we 'should'
1287 * also try to resolve the A/AAAA records (RFC1035)
1288 * This is a feature and not important
1291 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1292 "GNS_POSTPROCESS: Postprocessing\n");
1294 if (strcmp(rh->name, "+") == 0)
1295 repl_string = rlh->name;
1297 repl_string = rlh->name+strlen(rh->name)+1;
1300 if (rd[i].record_type == GNUNET_GNS_RECORD_MX)
1302 memcpy(new_mx_data, (char*)rd[i].data, sizeof(uint16_t));
1303 offset = sizeof(uint16_t);
1304 pos = new_mx_data+offset;
1305 expand_plus(&pos, (char*)rd[i].data+sizeof(uint16_t),
1307 offset += strlen(new_mx_data+sizeof(uint16_t))+1;
1308 p_rd[i].data = new_mx_data;
1309 p_rd[i].data_size = offset;
1311 else if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_SOA)
1313 /* expand mname and rname */
1315 expand_plus(&pos, (char*)rd[i].data, repl_string);
1316 offset = strlen(new_soa_data)+1;
1317 pos = new_soa_data+offset;
1318 expand_plus(&pos, (char*)rd[i].data+offset, repl_string);
1319 offset += strlen(new_soa_data+offset)+1;
1320 /* cpy the 4 numbers serial refresh retry and expire */
1321 memcpy(new_soa_data+offset, (char*)rd[i].data+offset, sizeof(uint32_t)*5);
1322 offset += sizeof(uint32_t)*5;
1323 p_rd[i].data_size = offset;
1324 p_rd[i].data = new_soa_data;
1329 expand_plus(&pos, (char*)rd[i].data, repl_string);
1330 p_rd[i].data_size = strlen(new_rr_data)+1;
1331 p_rd[i].data = new_rr_data;
1336 rlh->proc(rlh->proc_cls, rd_count, p_rd);
1342 * Process DHT lookup result for record.
1344 * @param cls the closure
1345 * @param rh resolver handle
1346 * @param rd_count number of results
1347 * @param rd record data
1350 handle_record_dht(void* cls, struct ResolverHandle *rh,
1351 unsigned int rd_count,
1352 const struct GNUNET_NAMESTORE_RecordData *rd)
1354 struct RecordLookupHandle* rlh;
1356 rlh = (struct RecordLookupHandle*)cls;
1359 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1360 "GNS_PHASE_REC: No records for %s found in DHT. Aborting\n",
1362 /* give up, cannot resolve */
1363 finish_lookup(rh, rlh, 0, NULL);
1364 free_resolver_handle(rh);
1368 /* results found yay */
1369 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1370 "GNS_PHASE_REC: Record resolved from DHT!");
1372 finish_lookup(rh, rlh, rd_count, rd);
1373 free_resolver_handle(rh);
1379 * Process namestore lookup result for record.
1381 * @param cls the closure
1382 * @param rh resolver handle
1383 * @param rd_count number of results
1384 * @param rd record data
1387 handle_record_ns(void* cls, struct ResolverHandle *rh,
1388 unsigned int rd_count,
1389 const struct GNUNET_NAMESTORE_RecordData *rd)
1391 struct RecordLookupHandle* rlh;
1392 rlh = (struct RecordLookupHandle*) cls;
1395 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1396 "GNS_PHASE_REC: Resolution status: %d!\n", rh->status);
1398 /* ns entry expired and not ours. try dht */
1399 if (rh->status & (EXPIRED | !EXISTS) &&
1400 GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1403 rh->proc = &handle_record_dht;
1404 resolve_record_dht(rh);
1407 /* give up, cannot resolve */
1408 finish_lookup(rh, rlh, 0, NULL);
1409 free_resolver_handle(rh);
1413 /* results found yay */
1414 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1415 "GNS_PHASE_REC: Record resolved from namestore!");
1417 finish_lookup(rh, rlh, rd_count, rd);
1419 free_resolver_handle(rh);
1425 * Determine if this name is canonical.
1427 * a.b.gnunet = not canonical
1430 * @param name the name to test
1431 * @return 1 if canonical
1434 is_canonical(char* name)
1436 uint32_t len = strlen(name);
1439 for (i=0; i<len; i++)
1441 if (*(name+i) == '.')
1448 * Move one level up in the domain hierarchy and return the
1449 * passed top level domain.
1451 * @param name the domain
1452 * @param dest the destination where the tld will be put
1455 pop_tld(char* name, char* dest)
1459 if (is_canonical(name))
1466 for (len = strlen(name); len > 0; len--)
1468 if (*(name+len) == '.')
1478 strcpy(dest, (name+len+1));
1482 * Checks if name is in tld
1484 * @param name the name to check
1485 * @param tld the TLD to check for
1486 * @return GNUNET_YES or GNUNET_NO
1489 is_tld(const char* name, const char* tld)
1493 if (strlen(name) <= strlen(tld))
1498 offset = strlen(name)-strlen(tld);
1499 if (strcmp(name+offset, tld) != 0)
1501 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1502 "%s is not in .%s TLD\n", name, tld);
1509 * DHT resolution for delegation finished. Processing result.
1511 * @param cls the closure
1512 * @param rh resolver handle
1513 * @param rd_count number of results (always 0)
1514 * @param rd record data (always NULL)
1517 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
1518 unsigned int rd_count,
1519 const struct GNUNET_NAMESTORE_RecordData *rd)
1521 struct RecordLookupHandle* rlh;
1522 rlh = (struct RecordLookupHandle*) cls;
1525 if (strcmp(rh->name, "") == 0)
1527 if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1529 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1530 "GNS_PHASE_DELEGATE: Resolved queried PKEY via DHT.\n");
1531 finish_lookup(rh, rlh, rd_count, rd);
1532 free_resolver_handle(rh);
1535 /* We resolved full name for delegation. resolving record */
1536 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1537 "GNS_PHASE_DELEGATE: Resolved full name for delegation via DHT.\n");
1538 strcpy(rh->name, "+\0");
1539 rh->proc = &handle_record_ns;
1540 resolve_record_ns(rh);
1545 * we still have some left
1547 if (is_canonical(rh->name))
1549 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1550 "GNS_PHASE_DELEGATE: Resolving canonical record %s in ns\n",
1552 rh->proc = &handle_record_ns;
1553 resolve_record_ns(rh);
1556 /* give up, cannot resolve */
1557 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1558 "GNS_PHASE_DELEGATE: Cannot fully resolve delegation for %s via DHT!\n",
1560 finish_lookup(rh, rlh, 0, NULL);
1561 free_resolver_handle(rh);
1566 * Start DHT lookup for a name -> PKEY (compare NS) record in
1567 * rh->authority's zone
1569 * @param rh the pending gns query
1572 resolve_delegation_dht(struct ResolverHandle *rh)
1575 struct GNUNET_CRYPTO_ShortHashCode name_hash;
1576 GNUNET_HashCode name_hash_double;
1577 GNUNET_HashCode zone_hash_double;
1578 GNUNET_HashCode lookup_key;
1579 struct ResolverHandle *rh_heap_root;
1581 pop_tld(rh->name, rh->authority_name);
1582 GNUNET_CRYPTO_short_hash(rh->authority_name,
1583 strlen(rh->authority_name),
1585 GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1586 GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
1587 GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
1589 rh->dht_heap_node = NULL;
1591 if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
1593 //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1594 // &dht_authority_lookup_timeout,
1596 rh->timeout_cont = &dht_authority_lookup_timeout;
1597 rh->timeout_cont_cls = rh;
1601 if (max_allowed_background_queries <=
1602 GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
1604 /* terminate oldest lookup */
1605 rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
1606 GNUNET_DHT_get_stop(rh_heap_root->get_handle);
1607 rh_heap_root->dht_heap_node = NULL;
1609 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1610 "GNS_PHASE_DELEGATE: Replacing oldest background query for %s\n",
1611 rh_heap_root->authority_name);
1613 rh_heap_root->proc(rh_heap_root->proc_cls,
1618 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
1620 GNUNET_TIME_absolute_get().abs_value);
1623 xquery = htonl(GNUNET_GNS_RECORD_PKEY);
1625 GNUNET_assert(rh->get_handle == NULL);
1626 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
1627 GNUNET_TIME_UNIT_FOREVER_REL,
1628 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1630 DHT_GNS_REPLICATION_LEVEL,
1634 &process_delegation_result_dht,
1641 * Namestore resolution for delegation finished. Processing result.
1643 * @param cls the closure
1644 * @param rh resolver handle
1645 * @param rd_count number of results (always 0)
1646 * @param rd record data (always NULL)
1649 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
1650 unsigned int rd_count,
1651 const struct GNUNET_NAMESTORE_RecordData *rd)
1653 struct RecordLookupHandle* rlh;
1654 rlh = (struct RecordLookupHandle*) cls;
1656 if (strcmp(rh->name, "") == 0)
1658 if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1660 GNUNET_assert(rd_count == 1);
1661 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1662 "GNS_PHASE_DELEGATE: Resolved queried PKEY in NS.\n");
1663 finish_lookup(rh, rlh, rd_count, rd);
1664 free_resolver_handle(rh);
1667 /* We resolved full name for delegation. resolving record */
1668 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1669 "GNS_PHASE_DELEGATE: Resolved full name for delegation.\n");
1670 strcpy(rh->name, "+\0");
1671 rh->proc = &handle_record_ns;
1672 resolve_record_ns(rh);
1677 * we still have some left
1678 * check if authority in ns is fresh
1680 * or we are authority
1682 if ((rh->status & (EXISTS | !EXPIRED)) ||
1683 !GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1684 &rh->authority_chain_tail->zone))
1686 if (is_canonical(rh->name))
1688 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1689 "GNS_PHASE_DELEGATE: Resolving canonical record %s\n",
1691 rh->proc = &handle_record_ns;
1692 resolve_record_ns(rh);
1696 /* give up, cannot resolve */
1697 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1698 "GNS_PHASE_DELEGATE: Cannot fully resolve delegation for %s!\n",
1700 rlh->proc(rlh->proc_cls, 0, NULL);
1705 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1706 "GNS_PHASE_DELEGATE: Trying to resolve delegation for %s via DHT\n",
1708 rh->proc = &handle_delegation_dht;
1709 resolve_delegation_dht(rh);
1715 * This is a callback function that should give us only PKEY
1716 * records. Used to query the namestore for the authority (PKEY)
1717 * for 'name'. It will recursively try to resolve the
1718 * authority for a given name from the namestore.
1720 * @param cls the pending query
1721 * @param key the key of the zone we did the lookup
1722 * @param expiration expiration date of the record data set in the namestore
1723 * @param name the name for which we need an authority
1724 * @param rd_count the number of records with 'name'
1725 * @param rd the record data
1726 * @param signature the signature of the authority for the record data
1729 process_delegation_result_ns(void* cls,
1730 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1731 struct GNUNET_TIME_Absolute expiration,
1733 unsigned int rd_count,
1734 const struct GNUNET_NAMESTORE_RecordData *rd,
1735 const struct GNUNET_CRYPTO_RsaSignature *signature)
1737 struct ResolverHandle *rh;
1738 struct GNUNET_TIME_Relative remaining_time;
1739 struct GNUNET_CRYPTO_ShortHashCode zone;
1740 char new_name[MAX_DNS_NAME_LENGTH];
1742 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1743 "GNS_PHASE_DELEGATE: Got %d records from authority lookup\n",
1746 rh = (struct ResolverHandle *)cls;
1747 GNUNET_CRYPTO_short_hash(key,
1748 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1750 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1756 rh->status |= EXISTS;
1759 if (remaining_time.rel_value == 0)
1761 rh->status |= EXPIRED;
1765 * No authority found in namestore.
1770 * We did not find an authority in the namestore
1775 * Promote this authority back to a name maybe it is
1778 if (strcmp(rh->name, "") == 0)
1780 /* simply promote back */
1781 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1782 "GNS_PHASE_DELEGATE: Promoting %s back to name\n",
1783 rh->authority_name);
1784 strcpy(rh->name, rh->authority_name);
1788 /* add back to existing name */
1789 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1790 "GNS_PHASE_DELEGATE: Adding %s back to %s\n",
1791 rh->authority_name, rh->name);
1792 //memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
1793 strcpy(new_name, rh->name);
1794 strcpy(new_name+strlen(new_name), ".");
1795 strcpy(new_name+strlen(new_name), rh->authority_name);
1796 strcpy(rh->name, new_name);
1797 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1798 "GNS_PHASE_DELEGATE: %s restored\n", rh->name);
1800 rh->proc(rh->proc_cls, rh, 0, NULL);
1805 * We found an authority that may be able to help us
1806 * move on with query
1807 * Note only 1 pkey should have been returned.. anything else would be strange
1810 for (i=0; i<rd_count;i++)
1813 if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
1816 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
1819 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1820 "GNS_PHASE_DELEGATE: This pkey is expired.\n");
1821 if (remaining_time.rel_value == 0)
1823 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1824 "GNS_PHASE_DELEGATE: This dht entry is expired.\n");
1825 rh->authority_chain_head->fresh = 0;
1826 rh->proc(rh->proc_cls, rh, 0, NULL);
1834 * Resolve rest of query with new authority
1836 GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
1837 memcpy(&rh->authority, rd[i].data,
1838 sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1839 struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
1840 auth->zone = rh->authority;
1841 memset(auth->name, 0, strlen(rh->authority_name)+1);
1842 strcpy(auth->name, rh->authority_name);
1843 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1844 rh->authority_chain_tail,
1848 * We are done with PKEY resolution if name is empty
1849 * else resolve again with new authority
1851 if (strcmp(rh->name, "") == 0)
1852 rh->proc(rh->proc_cls, rh, rd_count, rd);
1854 resolve_delegation_ns(rh);
1861 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1862 "GNS_PHASE_DELEGATE: Authority lookup and but no PKEY... never get here\n");
1863 rh->proc(rh->proc_cls, rh, 0, NULL);
1868 * Resolve the delegation chain for the request in our namestore
1870 * @param rh the resolver handle
1873 resolve_delegation_ns(struct ResolverHandle *rh)
1875 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1876 "GNS_PHASE_DELEGATE: Resolving delegation for %s\n", rh->name);
1877 pop_tld(rh->name, rh->authority_name);
1878 GNUNET_NAMESTORE_lookup_record(namestore_handle,
1881 GNUNET_GNS_RECORD_PKEY,
1882 &process_delegation_result_ns,
1889 * Lookup of a record in a specific zone
1890 * calls lookup result processor on result
1892 * @param zone the root zone
1893 * @param record_type the record type to look up
1894 * @param name the name to look up
1895 * @param key a private key for use with PSEU import (can be NULL)
1896 * @param timeout timeout for resolution
1897 * @param proc the processor to call on result
1898 * @param cls the closure to pass to proc
1901 gns_resolver_lookup_record(struct GNUNET_CRYPTO_ShortHashCode zone,
1902 uint32_t record_type,
1904 struct GNUNET_CRYPTO_RsaPrivateKey *key,
1905 struct GNUNET_TIME_Relative timeout,
1906 RecordLookupProcessor proc,
1909 struct ResolverHandle *rh;
1910 struct RecordLookupHandle* rlh;
1911 char string_hash[MAX_DNS_LABEL_LENGTH];
1913 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1914 "Starting resolution for %s (type=%d)!\n",
1918 if (is_canonical((char*)name) && (strcmp(GNUNET_GNS_TLD, name) != 0))
1920 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1921 "%s is canonical and not gnunet -> cannot resolve!\n", name);
1926 rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
1927 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1929 rh->authority = zone;
1932 rh->timeout = timeout;
1933 rh->get_handle = NULL;
1934 if (timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
1937 * Set timeout for authority lookup phase to 1/2
1939 rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
1940 GNUNET_TIME_relative_divide(timeout, 2),
1941 &handle_lookup_timeout,
1943 rh->timeout_cont = &dht_authority_lookup_timeout;
1944 rh->timeout_cont_cls = rh;
1948 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No timeout for query!\n");
1949 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1952 if (strcmp(GNUNET_GNS_TLD, name) == 0)
1955 * Only 'gnunet' given
1957 strcpy(rh->name, "\0");
1961 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1962 "Checking for TLD...\n");
1963 if (is_zkey_tld(name) == GNUNET_YES)
1965 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1968 * This is a zkey tld
1969 * build hash and use as initial authority
1972 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
1973 memcpy(rh->name, name,
1974 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
1975 pop_tld(rh->name, string_hash);
1977 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1978 "ZKEY is %s!\n", string_hash);
1980 if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(string_hash,
1983 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1984 "Cannot convert ZKEY %s to hash!\n", string_hash);
1994 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1997 * Presumably GNUNET tld
2000 strlen(name)-strlen(GNUNET_GNS_TLD));
2001 memcpy(rh->name, name,
2002 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2007 * Initialize authority chain
2009 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2010 rh->authority_chain_head->prev = NULL;
2011 rh->authority_chain_head->next = NULL;
2012 rh->authority_chain_tail = rh->authority_chain_head;
2013 rh->authority_chain_head->zone = rh->authority;
2016 * Copy original query into lookup handle
2018 rlh->record_type = record_type;
2019 memset(rlh->name, 0, strlen(name) + 1);
2020 strcpy(rlh->name, name);
2022 rlh->proc_cls = cls;
2024 rh->proc = &handle_delegation_ns;
2025 resolve_delegation_ns(rh);
2028 /******** END Record Resolver ***********/
2032 * Callback calles by namestore for a zone to name
2035 * @param cls the closure
2036 * @param zone_key the zone we queried
2037 * @param expire the expiration time of the name
2038 * @param name the name found or NULL
2039 * @param rd_len number of records for the name
2040 * @param rd the record data (PKEY) for the name
2041 * @param signature the signature for the record data
2044 process_zone_to_name_shorten(void *cls,
2045 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
2046 struct GNUNET_TIME_Absolute expire,
2048 unsigned int rd_len,
2049 const struct GNUNET_NAMESTORE_RecordData *rd,
2050 const struct GNUNET_CRYPTO_RsaSignature *signature)
2052 struct ResolverHandle *rh = (struct ResolverHandle *)cls;
2053 struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
2054 struct AuthorityChain *next_authority;
2056 char result[MAX_DNS_NAME_LENGTH];
2057 char next_authority_name[MAX_DNS_LABEL_LENGTH];
2060 /* we found a match in our own zone */
2063 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2064 "result strlen %d\n", strlen(name));
2065 answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
2066 memset(result, 0, answer_len);
2067 if (strlen(rh->name) > 0)
2069 strcpy(result, rh->name);
2070 strcpy(result+strlen(rh->name), ".");
2073 strcpy(result+strlen(result), name);
2074 strcpy(result+strlen(result), ".");
2075 strcpy(result+strlen(result), GNUNET_GNS_TLD);
2077 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2078 "Sending shorten result %s\n", result);
2080 nsh->proc(nsh->proc_cls, result);
2082 free_resolver_handle(rh);
2084 else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2087 /* our zone, just append .gnunet */
2088 answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
2089 memset(result, 0, answer_len);
2090 strcpy(result, rh->name);
2091 strcpy(result+strlen(rh->name), ".");
2092 strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
2094 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2095 "Our zone: Sending name as shorten result %s\n", rh->name);
2097 nsh->proc(nsh->proc_cls, result);
2099 free_resolver_handle(rh);
2105 * continue with next authority
2107 next_authority = rh->authority_chain_head;
2108 // strlen(next_authority->name) + 2);
2109 memset(next_authority_name, 0, strlen(rh->name)+
2110 strlen(next_authority->name) + 2);
2111 strcpy(next_authority_name, rh->name);
2112 strcpy(next_authority_name+strlen(rh->name)+1, ".");
2113 strcpy(next_authority_name+strlen(rh->name)+2, next_authority->name);
2115 strcpy(rh->name, next_authority_name);
2116 GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
2117 rh->authority_chain_tail,
2120 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2121 &rh->authority_chain_tail->zone,
2122 &rh->authority_chain_head->zone,
2123 &process_zone_to_name_shorten,
2130 * Process result from namestore delegation lookup
2131 * for shorten operation
2133 * @param cls the client shorten handle
2134 * @param rh the resolver handle
2135 * @param rd_count number of results (0)
2136 * @param rd data (NULL)
2139 handle_delegation_ns_shorten(void* cls,
2140 struct ResolverHandle *rh,
2142 const struct GNUNET_NAMESTORE_RecordData *rd)
2144 struct NameShortenHandle *nsh;
2145 char result[MAX_DNS_NAME_LENGTH];
2148 nsh = (struct NameShortenHandle *)cls;
2151 * At this point rh->name contains the part of the name
2152 * that we do not have a PKEY in our namestore to resolve.
2153 * The authority chain in the resolver handle is now
2154 * useful to backtrack if needed
2157 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2158 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2160 if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2164 * This is our zone append .gnunet unless name is empty
2165 * (it shouldn't be, usually FIXME what happens if we
2166 * shorten to our zone to a "" record??)
2169 answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
2170 memset(result, 0, answer_len);
2171 strcpy(result, rh->name);
2172 strcpy(result+strlen(rh->name), ".");
2173 strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
2175 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2176 "Our zone: Sending name as shorten result %s\n", rh->name);
2178 nsh->proc(nsh->proc_cls, result);
2180 free_resolver_handle(rh);
2184 /* backtrack authorities for names */
2185 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2186 &rh->authority_chain_tail->zone, //ours
2187 &rh->authority_chain_head->zone,
2188 &process_zone_to_name_shorten,
2194 * Shorten api from resolver
2196 * @param zone the zone to use
2197 * @param name the name to shorten
2198 * @param proc the processor to call with result
2199 * @param cls closure to pass to proc
2202 gns_resolver_shorten_name(struct GNUNET_CRYPTO_ShortHashCode zone,
2204 ShortenResultProcessor proc,
2207 struct ResolverHandle *rh;
2208 struct NameShortenHandle *nsh;
2209 char string_hash[MAX_DNS_NAME_LENGTH]; //FIXME LABEL length when shorthash
2211 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2212 "Starting shorten for %s!\n", name);
2214 if (is_canonical((char*)name))
2216 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2217 "%s is canonical. Returning verbatim\n", name);
2222 nsh = GNUNET_malloc(sizeof (struct NameShortenHandle));
2226 nsh->proc_cls = cls;
2228 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2229 rh->authority = zone;
2231 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2232 "Checking for TLD...\n");
2233 if (is_zkey_tld(name) == GNUNET_YES)
2235 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2238 * This is a zkey tld
2239 * build hash and use as initial authority
2242 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
2243 memcpy(rh->name, name,
2244 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
2245 pop_tld(rh->name, string_hash);
2247 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2248 "ZKEY is %s!\n", string_hash);
2250 if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(string_hash,
2253 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2254 "Cannot convert ZKEY %s to hash!\n", string_hash);
2264 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2267 * Presumably GNUNET tld
2270 strlen(name)-strlen(GNUNET_GNS_TLD));
2271 memcpy(rh->name, name,
2272 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2275 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2276 rh->authority_chain_tail = rh->authority_chain_head;
2277 rh->authority_chain_head->zone = zone;
2278 rh->proc = &handle_delegation_ns_shorten;
2281 /* Start delegation resolution in our namestore */
2282 resolve_delegation_ns(rh);
2285 /*********** END NAME SHORTEN ********************/
2289 * Process result from namestore delegation lookup
2290 * for get authority operation
2292 * @param cls the client get auth handle
2293 * @param rh the resolver handle
2294 * @param rd_count number of results (0)
2295 * @param rd data (NULL)
2298 handle_delegation_result_ns_get_auth(void* cls,
2299 struct ResolverHandle *rh,
2301 const struct GNUNET_NAMESTORE_RecordData *rd)
2303 struct GetNameAuthorityHandle* nah;
2304 char result[MAX_DNS_NAME_LENGTH];
2307 nah = (struct GetNameAuthorityHandle*) rh->proc_cls;
2310 * At this point rh->name contains the part of the name
2311 * that we do not have a PKEY in our namestore to resolve.
2312 * The authority chain in the resolver handle is now
2313 * useful to backtrack if needed
2316 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2317 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2319 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2320 "Building response!\n");
2321 if (is_canonical(rh->name))
2324 * We successfully resolved the authority in the ns
2325 * FIXME for our purposes this is fine
2326 * but maybe we want to have an api that also looks
2327 * into the dht (i.e. option in message)
2329 if (strlen(rh->name) > strlen(nah->name))
2331 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2332 "Record name longer than original lookup name... odd!\n");
2336 answer_len = strlen(nah->name) - strlen(rh->name)
2337 + strlen(GNUNET_GNS_TLD) + 1;
2338 memset(result, 0, answer_len);
2339 strcpy(result, nah->name + strlen(rh->name) + 1);
2341 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2342 "Got authority result %s\n", result);
2344 nah->proc(nah->proc_cls, result);
2346 free_resolver_handle(rh);
2350 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2351 "Unable to resolve authority for remaining %s!\n", rh->name);
2352 nah->proc(nah->proc_cls, "");
2354 free_resolver_handle(rh);
2362 * Tries to resolve the authority for name
2365 * @param zone the root zone to look up for
2366 * @param name the name to lookup up
2367 * @param proc the processor to call when finished
2368 * @param cls the closure to pass to the processor
2371 gns_resolver_get_authority(struct GNUNET_CRYPTO_ShortHashCode zone,
2373 GetAuthorityResultProcessor proc,
2376 struct ResolverHandle *rh;
2377 struct GetNameAuthorityHandle *nah;
2379 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2380 "Starting authority resolution for %s!\n", name);
2382 nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
2383 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2384 rh->authority = zone;
2386 if (strcmp(GNUNET_GNS_TLD, name) == 0)
2388 strcpy(rh->name, "\0");
2393 strlen(name)-strlen(GNUNET_GNS_TLD));
2394 memcpy(rh->name, name,
2395 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2398 memset(nah->name, 0,
2400 strcpy(nah->name, name);
2402 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2403 rh->authority_chain_tail = rh->authority_chain_head;
2404 rh->authority_chain_head->zone = zone;
2405 rh->proc = &handle_delegation_result_ns_get_auth;
2406 rh->proc_cls = (void*)nah;
2409 nah->proc_cls = cls;
2411 /* Start delegation resolution in our namestore */
2412 resolve_delegation_ns(rh);
2416 /******** END GET AUTHORITY *************/
2418 /* end of gnunet-service-gns_resolver.c */