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 * a resolution identifier pool variable
75 * This is a non critical identifier useful for debugging
77 static unsigned long long rid = 0;
80 * Namestore calls this function if we have record for this name.
81 * (or with rd_count=0 to indicate no matches)
83 * @param cls the pending query
84 * @param key the key of the zone we did the lookup
85 * @param expiration expiration date of the namestore entry
86 * @param name the name for which we need an authority
87 * @param rd_count the number of records with 'name'
88 * @param rd the record data
89 * @param signature the signature of the authority for the record data
92 process_pseu_lookup_ns(void* cls,
93 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
94 struct GNUNET_TIME_Absolute expiration,
95 const char *name, unsigned int rd_count,
96 const struct GNUNET_NAMESTORE_RecordData *rd,
97 const struct GNUNET_CRYPTO_RsaSignature *signature)
99 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
100 struct GNUNET_NAMESTORE_RecordData new_pkey;
104 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
105 "GNS_AUTO_PSEU: Name %s already taken in NS!\n", name);
106 if (0 == strcmp(gph->name, name))
108 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
109 "GNS_AUTO_PSEU: Intelligent replacement not implemented\n",
115 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
116 "GNS_AUTO_PSEU: Trying delegated name %s\n", gph->name);
117 memcpy(gph->new_name, gph->name, strlen(gph->name)+1);
118 GNUNET_NAMESTORE_lookup_record(namestore_handle,
121 GNUNET_GNS_RECORD_PSEU,
122 &process_pseu_lookup_ns,
128 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
129 "GNS_AUTO_PSEU: Name %s not taken in NS! Adding\n", gph->new_name);
131 new_pkey.expiration = GNUNET_TIME_absolute_get_forever ();
132 new_pkey.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode);
133 new_pkey.data = &gph->new_zone;
134 new_pkey.record_type = GNUNET_GNS_RECORD_PKEY;
135 new_pkey.flags = GNUNET_NAMESTORE_RF_AUTHORITY
136 | GNUNET_NAMESTORE_RF_PRIVATE
137 | GNUNET_NAMESTORE_RF_PENDING;
138 GNUNET_NAMESTORE_record_create (namestore_handle,
149 * process result of a dht pseu lookup
151 * @param gph the handle
152 * @param name the pseu result or NULL
155 process_pseu_result(struct GetPseuAuthorityHandle* gph, char* name)
159 memcpy(gph->new_name, gph->name, strlen(gph->name)+1);
163 memcpy(gph->new_name, name, strlen(name)+1);
166 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
167 "GNS_AUTO_PSEU: Checking %s for collision in NS\n", gph->new_name);
170 * Check for collision
172 GNUNET_NAMESTORE_lookup_record(namestore_handle,
175 GNUNET_NAMESTORE_TYPE_ANY,
176 &process_pseu_lookup_ns,
181 * Handle timeout for dht request
183 * @param cls the request handle as closure
184 * @param tc the task context
187 handle_auth_discovery_timeout(void *cls,
188 const struct GNUNET_SCHEDULER_TaskContext *tc)
190 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
192 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
193 "GNS_GET_AUTH: dht lookup for query PSEU timed out.\n");
194 GNUNET_DHT_get_stop (gph->get_handle);
195 gph->get_handle = NULL;
196 process_pseu_result(gph, NULL);
200 * Function called when we find a PSEU entry in the DHT
202 * @param cls the request handle
203 * @param exp lifetime
204 * @param key the key the record was stored under
205 * @param get_path get path
206 * @param get_path_length get path length
207 * @param put_path put path
208 * @param put_path_length put path length
209 * @param type the block type
210 * @param size the size of the record
211 * @param data the record data
214 process_auth_discovery_dht_result(void* cls,
215 struct GNUNET_TIME_Absolute exp,
216 const GNUNET_HashCode * key,
217 const struct GNUNET_PeerIdentity *get_path,
218 unsigned int get_path_length,
219 const struct GNUNET_PeerIdentity *put_path,
220 unsigned int put_path_length,
221 enum GNUNET_BLOCK_Type type,
222 size_t size, const void *data)
224 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
225 struct GNSNameRecordBlock *nrb;
226 char* rd_data = (char*)data;
232 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
233 "GNS_GET_AUTH: got dht result (size=%d)\n", size);
237 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
238 "GNS_GET_AUTH: got dht result null!\n", size);
244 nrb = (struct GNSNameRecordBlock*)data;
246 /* stop lookup and timeout task */
247 GNUNET_DHT_get_stop (gph->get_handle);
248 gph->get_handle = NULL;
249 GNUNET_SCHEDULER_cancel(gph->timeout);
251 gph->get_handle = NULL;
253 nrb = (struct GNSNameRecordBlock*)data;
255 name = (char*)&nrb[1];
256 num_records = ntohl(nrb->rd_count);
258 struct GNUNET_NAMESTORE_RecordData rd[num_records];
260 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
261 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
263 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
268 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
269 "GNS_GET_AUTH: Error deserializing data!\n");
275 for (i=0; i<num_records; i++)
277 if ((strcmp(name, "+") == 0) &&
278 (rd[i].record_type == GNUNET_GNS_RECORD_PSEU))
281 process_pseu_result(gph, (char*)rd[i].data);
287 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_GET_AUTH: no pseu in dht!\n");
288 process_pseu_result(gph, NULL);
292 process_auth_discovery_ns_result(void* cls,
293 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
294 struct GNUNET_TIME_Absolute expiration,
295 const char *name, unsigned int rd_count,
296 const struct GNUNET_NAMESTORE_RecordData *rd,
297 const struct GNUNET_CRYPTO_RsaSignature *signature)
300 struct GNUNET_CRYPTO_ShortHashCode name_hash;
301 GNUNET_HashCode lookup_key;
302 struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
303 GNUNET_HashCode name_hash_double;
304 GNUNET_HashCode zone_hash_double;
306 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
314 GNUNET_CRYPTO_short_hash("+", strlen("+"), &name_hash);
315 GNUNET_CRYPTO_short_hash_double (&name_hash, &name_hash_double);
316 GNUNET_CRYPTO_short_hash_double (&gph->new_zone, &zone_hash_double);
317 GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
318 GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
320 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
321 "GNS_AUTO_PSEU: starting dht lookup for %s with key: %s\n",
322 "+", (char*)&lookup_key_string);
324 gph->timeout = GNUNET_SCHEDULER_add_delayed(DHT_LOOKUP_TIMEOUT,
325 &handle_auth_discovery_timeout, gph);
327 xquery = htonl(GNUNET_GNS_RECORD_PSEU);
329 GNUNET_assert(gph->get_handle == NULL);
330 gph->get_handle = GNUNET_DHT_get_start(dht_handle,
331 GNUNET_TIME_UNIT_FOREVER_REL,
332 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
334 DHT_GNS_REPLICATION_LEVEL,
338 &process_auth_discovery_dht_result,
342 for (i=0; i<rd_count; i++)
344 if ((strcmp(name, "+") == 0) &&
345 (rd[i].record_type == GNUNET_GNS_RECORD_PSEU))
348 process_pseu_result(gph, (char*)rd[i].data);
355 * Callback called by namestore for a zone to name
358 * @param cls the closure
359 * @param zone_key the zone we queried
360 * @param expire the expiration time of the name
361 * @param name the name found or NULL
362 * @param rd_len number of records for the name
363 * @param rd the record data (PKEY) for the name
364 * @param signature the signature for the record data
367 process_zone_to_name_discover(void *cls,
368 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
369 struct GNUNET_TIME_Absolute expire,
372 const struct GNUNET_NAMESTORE_RecordData *rd,
373 const struct GNUNET_CRYPTO_RsaSignature *signature)
375 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
377 /* we found a match in our own zone */
380 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
381 "GNS_AUTO_PSEU: name for zone in our root %s\n", name);
387 GNUNET_NAMESTORE_lookup_record(namestore_handle,
390 GNUNET_GNS_RECORD_PSEU,
391 &process_auth_discovery_ns_result,
400 * Callback for new authories
402 * @param name the name given by delegation
403 * @param zone the authority
404 * @param our_zone our local zone
405 * @param key the private key of our authority
407 static void process_discovered_authority(char* name,
408 struct GNUNET_CRYPTO_ShortHashCode zone,
409 struct GNUNET_CRYPTO_ShortHashCode our_zone,
410 struct GNUNET_CRYPTO_RsaPrivateKey *key)
412 struct GetPseuAuthorityHandle *gph;
415 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
416 "GNS_AUTO_PSEU: New authority %s discovered\n",
419 gph = GNUNET_malloc(sizeof(struct GetPseuAuthorityHandle));
420 namelen = strlen(name) + 1;
421 memcpy(gph->name, name, namelen);
423 gph->new_zone = zone;
424 gph->zone = our_zone;
427 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
430 &process_zone_to_name_discover,
436 * Initialize the resolver
438 * @param nh the namestore handle
439 * @param dh the dht handle
440 * @param lz the local zone's hash
441 * @param max_bg_queries maximum number of parallel background queries in dht
442 * @return GNUNET_OK on success
445 gns_resolver_init(struct GNUNET_NAMESTORE_Handle *nh,
446 struct GNUNET_DHT_Handle *dh,
447 struct GNUNET_CRYPTO_ShortHashCode lz,
448 unsigned long long max_bg_queries)
450 namestore_handle = nh;
454 GNUNET_CONTAINER_heap_create(GNUNET_CONTAINER_HEAP_ORDER_MIN);
455 max_allowed_background_queries = max_bg_queries;
457 if ((namestore_handle != NULL) && (dht_handle != NULL))
461 return GNUNET_SYSERR;
465 * Cleanup background lookups
467 * @param cls closure to iterator
468 * @param node heap nodes
469 * @param element the resolver handle
470 * @param cost heap cost
471 * @return always GNUNET_YES
474 cleanup_pending_background_queries(void* cls,
475 struct GNUNET_CONTAINER_HeapNode *node,
477 GNUNET_CONTAINER_HeapCostType cost)
479 struct ResolverHandle *rh = (struct ResolverHandle *)element;
480 ResolverCleanupContinuation cont = cls;
482 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
483 "GNS_CLEANUP-%d: Terminating background lookup for %s\n",
485 GNUNET_DHT_get_stop(rh->get_handle);
486 rh->get_handle = NULL;
487 rh->proc(rh->proc_cls, rh, 0, NULL);
489 GNUNET_CONTAINER_heap_remove_node(node);
491 if (GNUNET_CONTAINER_heap_get_size(dht_lookup_heap) == 0)
503 gns_resolver_cleanup(ResolverCleanupContinuation cont)
505 unsigned int s = GNUNET_CONTAINER_heap_get_size(dht_lookup_heap);
506 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
507 "GNS_CLEANUP: %d pending background queries to terminate\n", s);
510 GNUNET_CONTAINER_heap_iterate (dht_lookup_heap,
511 &cleanup_pending_background_queries,
519 * Helper function to free resolver handle
521 * @param rh the handle to free
524 free_resolver_handle(struct ResolverHandle* rh)
526 struct AuthorityChain *ac;
527 struct AuthorityChain *ac_next;
532 ac = rh->authority_chain_head;
545 * Callback when record data is put into namestore
547 * @param cls the closure
548 * @param success GNUNET_OK on success
549 * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
552 on_namestore_record_put_result(void *cls,
556 if (GNUNET_NO == success)
558 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
559 "GNS_NS: records already in namestore\n");
562 else if (GNUNET_YES == success)
564 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
565 "GNS_NS: records successfully put in namestore\n");
569 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
570 "GNS_NS: Error putting records into namestore: %s\n", emsg);
574 handle_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
576 struct ResolverHandle *rh = cls;
578 if (rh->timeout_cont)
579 rh->timeout_cont(rh->timeout_cont_cls, tc);
583 * Processor for background lookups in the DHT
585 * @param cls closure (NULL)
586 * @param rd_count number of records found (not 0)
587 * @param rd record data
590 background_lookup_result_processor(void *cls,
592 const struct GNUNET_NAMESTORE_RecordData *rd)
594 //We could do sth verbose/more useful here but it doesn't make any difference
595 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
596 "GNS_BG: background dht lookup for finished. (%d results)\n",
601 * Handle timeout for DHT requests
603 * @param cls the request handle as closure
604 * @param tc the task context
607 dht_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
609 struct ResolverHandle *rh = cls;
610 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
611 char new_name[MAX_DNS_NAME_LENGTH];
613 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
614 "GNS_PHASE_REC-%d: dht lookup for query %s (%ds)timed out.\n",
615 rh->id, rh->name, rh->timeout.rel_value);
617 * Start resolution in bg
619 //strcpy(new_name, rh->name);
620 //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD));
621 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
622 rh->name, GNUNET_GNS_TLD);
624 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
625 "GNS_PHASE_REC-%d: Starting background lookup for %s type %d\n",
626 rh->id, new_name, rlh->record_type);
628 gns_resolver_lookup_record(rh->authority,
632 GNUNET_TIME_UNIT_FOREVER_REL,
633 &background_lookup_result_processor,
635 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
637 GNUNET_DHT_get_stop (rh->get_handle);
638 rh->get_handle = NULL;
639 rh->proc(rh->proc_cls, rh, 0, NULL);
644 * Function called when we get a result from the dht
645 * for our record query
647 * @param cls the request handle
648 * @param exp lifetime
649 * @param key the key the record was stored under
650 * @param get_path get path
651 * @param get_path_length get path length
652 * @param put_path put path
653 * @param put_path_length put path length
654 * @param type the block type
655 * @param size the size of the record
656 * @param data the record data
659 process_record_result_dht(void* cls,
660 struct GNUNET_TIME_Absolute exp,
661 const GNUNET_HashCode * key,
662 const struct GNUNET_PeerIdentity *get_path,
663 unsigned int get_path_length,
664 const struct GNUNET_PeerIdentity *put_path,
665 unsigned int put_path_length,
666 enum GNUNET_BLOCK_Type type,
667 size_t size, const void *data)
669 struct ResolverHandle *rh;
670 struct RecordLookupHandle *rlh;
671 struct GNSNameRecordBlock *nrb;
672 uint32_t num_records;
674 char* rd_data = (char*)data;
678 rh = (struct ResolverHandle *)cls;
679 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
680 "GNS_PHASE_REC-%d: got dht result (size=%d)\n", rh->id, size);
685 //FIXME maybe check expiration here, check block type
688 rlh = (struct RecordLookupHandle *) rh->proc_cls;
689 nrb = (struct GNSNameRecordBlock*)data;
691 /* stop lookup and timeout task */
692 GNUNET_DHT_get_stop (rh->get_handle);
693 rh->get_handle = NULL;
695 if (rh->dht_heap_node != NULL)
697 GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
698 rh->dht_heap_node = NULL;
701 if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
703 GNUNET_SCHEDULER_cancel(rh->timeout_task);
704 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
707 rh->get_handle = NULL;
708 name = (char*)&nrb[1];
709 num_records = ntohl(nrb->rd_count);
711 struct GNUNET_NAMESTORE_RecordData rd[num_records];
713 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
714 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
716 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
721 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
722 "GNS_PHASE_REC-%d: Error deserializing data!\n", rh->id);
726 for (i=0; i<num_records; i++)
728 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
729 "GNS_PHASE_REC-%d: Got name: %s (wanted %s)\n",
730 rh->id, name, rh->name);
731 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
732 "GNS_PHASE_REC-%d: Got type: %d\n",
733 rh->id, rd[i].record_type);
734 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
735 "GNS_PHASE_REC-%d: Got data length: %d\n",
736 rh->id, rd[i].data_size);
737 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
738 "GNS_PHASE_REC-%d: Got flag %d\n",
739 rh->id, rd[i].flags);
741 if ((strcmp(name, rh->name) == 0) &&
742 (rd[i].record_type == rlh->record_type))
750 * FIXME check pubkey against existing key in namestore?
751 * https://gnunet.org/bugs/view.php?id=2179
754 /* Save to namestore */
755 GNUNET_NAMESTORE_record_put (namestore_handle,
762 &on_namestore_record_put_result, //cont
767 rh->proc(rh->proc_cls, rh, num_records, rd);
769 rh->proc(rh->proc_cls, rh, 0, NULL);
776 * Start DHT lookup for a (name -> query->record_type) record in
777 * rh->authority's zone
779 * @param rh the pending gns query context
782 resolve_record_dht(struct ResolverHandle *rh)
785 struct GNUNET_CRYPTO_ShortHashCode name_hash;
786 GNUNET_HashCode lookup_key;
787 GNUNET_HashCode name_hash_double;
788 GNUNET_HashCode zone_hash_double;
789 struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
790 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
791 struct ResolverHandle *rh_heap_root;
793 GNUNET_CRYPTO_short_hash(rh->name, strlen(rh->name), &name_hash);
794 GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
795 GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
796 GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
797 GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
799 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
800 "GNS_PHASE_REC-%d: starting dht lookup for %s with key: %s\n",
801 rh->id, rh->name, (char*)&lookup_key_string);
803 //rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
804 rh->dht_heap_node = NULL;
806 if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
809 * Update timeout if necessary
811 if (rh->timeout_task == GNUNET_SCHEDULER_NO_TASK)
814 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
815 "GNS_PHASE_REC-%d: Adjusting timeout\n", rh->id);
817 * Set timeout for authority lookup phase to 1/2
819 rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
820 GNUNET_TIME_relative_divide(rh->timeout, 2),
821 &handle_lookup_timeout,
824 //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
825 // &dht_lookup_timeout,
827 rh->timeout_cont = &dht_lookup_timeout;
828 rh->timeout_cont_cls = rh;
832 if (max_allowed_background_queries <=
833 GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
835 rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
836 GNUNET_DHT_get_stop(rh_heap_root->get_handle);
837 rh_heap_root->get_handle = NULL;
838 rh_heap_root->dht_heap_node = NULL;
840 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
841 "GNS_PHASE_REC-%d: Replacing oldest background query for %s\n",
842 rh->id, rh_heap_root->name);
843 rh_heap_root->proc(rh_heap_root->proc_cls,
848 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
850 GNUNET_TIME_absolute_get().abs_value);
853 xquery = htonl(rlh->record_type);
855 GNUNET_assert(rh->get_handle == NULL);
856 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
857 GNUNET_TIME_UNIT_FOREVER_REL,
858 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
860 DHT_GNS_REPLICATION_LEVEL,
864 &process_record_result_dht,
871 * Namestore calls this function if we have record for this name.
872 * (or with rd_count=0 to indicate no matches)
874 * @param cls the pending query
875 * @param key the key of the zone we did the lookup
876 * @param expiration expiration date of the namestore entry
877 * @param name the name for which we need an authority
878 * @param rd_count the number of records with 'name'
879 * @param rd the record data
880 * @param signature the signature of the authority for the record data
883 process_record_result_ns(void* cls,
884 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
885 struct GNUNET_TIME_Absolute expiration,
886 const char *name, unsigned int rd_count,
887 const struct GNUNET_NAMESTORE_RecordData *rd,
888 const struct GNUNET_CRYPTO_RsaSignature *signature)
890 struct ResolverHandle *rh;
891 struct RecordLookupHandle *rlh;
892 struct GNUNET_TIME_Relative remaining_time;
893 struct GNUNET_CRYPTO_ShortHashCode zone;
895 rh = (struct ResolverHandle *) cls;
896 rlh = (struct RecordLookupHandle *)rh->proc_cls;
897 GNUNET_CRYPTO_short_hash(key,
898 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
900 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
908 rh->status |= EXISTS;
911 if (remaining_time.rel_value == 0)
913 rh->status |= EXPIRED;
919 * Lookup terminated and no results
921 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
922 "GNS_PHASE_REC-%d: Namestore lookup for %s terminated without results\n",
925 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
926 "GNS_PHASE_REC-%d: Record %s unknown in namestore\n",
929 * Our zone and no result? Cannot resolve TT
931 rh->proc(rh->proc_cls, rh, 0, NULL);
938 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
939 "GNS_PHASE_REC-%d: Processing additional result %s from namestore\n",
942 for (i=0; i<rd_count;i++)
945 if (rd[i].record_type != rlh->record_type)
948 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
951 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
952 "GNS_PHASE_REC-%d: This record is expired. Skipping\n",
964 if (rh->answered == 0)
966 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
967 "GNS_PHASE_REC-%d: No answers found. This is odd!\n", rh->id);
968 rh->proc(rh->proc_cls, rh, 0, NULL);
972 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
973 "GNS_PHASE_REC-%d: Found %d answer(s) to query in %d records!\n",
974 rh->id, rh->answered, rd_count);
976 rh->proc(rh->proc_cls, rh, rd_count, rd);
982 * The final phase of resolution.
983 * rh->name is a name that is canonical and we do not have a delegation.
984 * Query namestore for this record
986 * @param rh the pending lookup
989 resolve_record_ns(struct ResolverHandle *rh)
991 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
993 /* We cancel here as to not include the ns lookup in the timeout */
994 if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
996 GNUNET_SCHEDULER_cancel(rh->timeout_task);
997 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1001 * Try to resolve this record in our namestore.
1002 * The name to resolve is now in rh->authority_name
1003 * since we tried to resolve it to an authority
1006 GNUNET_NAMESTORE_lookup_record(namestore_handle,
1010 &process_record_result_ns,
1017 * Handle timeout for DHT requests
1019 * @param cls the request handle as closure
1020 * @param tc the task context
1023 dht_authority_lookup_timeout(void *cls,
1024 const struct GNUNET_SCHEDULER_TaskContext *tc)
1026 struct ResolverHandle *rh = cls;
1027 struct RecordLookupHandle *rlh = rh->proc_cls;
1028 char new_name[MAX_DNS_NAME_LENGTH];
1030 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1031 "GNS_PHASE_DELEGATE_DHT-%llu: dht lookup for query %s (%ds)timed out.\n",
1032 rh->id, rh->authority_name, rh->timeout.rel_value);
1034 rh->status |= TIMED_OUT;
1036 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1038 GNUNET_DHT_get_stop (rh->get_handle);
1039 rh->get_handle = NULL;
1041 if (strcmp(rh->name, "") == 0)
1044 * promote authority back to name and try to resolve record
1046 strcpy(rh->name, rh->authority_name);
1047 rh->proc(rh->proc_cls, rh, 0, NULL);
1052 * Start resolution in bg
1054 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH,
1055 "%s.%s.%s", rh->name, rh->authority_name, GNUNET_GNS_TLD);
1056 //strcpy(new_name, rh->name);
1057 //strcpy(new_name+strlen(new_name), ".");
1058 //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD));
1060 strcpy(rh->name, new_name);
1062 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1063 "GNS_PHASE_DELEGATE_DHT-%llu: Starting background query for %s type %d\n",
1064 rh->id, rh->name, rlh->record_type);
1066 gns_resolver_lookup_record(rh->authority,
1070 GNUNET_TIME_UNIT_FOREVER_REL,
1071 &background_lookup_result_processor,
1074 rh->proc(rh->proc_cls, rh, 0, NULL);
1078 static void resolve_delegation_dht(struct ResolverHandle *rh);
1081 static void resolve_delegation_ns(struct ResolverHandle *rh);
1085 * Namestore resolution for delegation finished. Processing result.
1087 * @param cls the closure
1088 * @param rh resolver handle
1089 * @param rd_count number of results (always 0)
1090 * @param rd record data (always NULL)
1093 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
1094 unsigned int rd_count,
1095 const struct GNUNET_NAMESTORE_RecordData *rd);
1099 * Function called when we get a result from the dht
1100 * for our query. Recursively tries to resolve authorities
1103 * @param cls the request handle
1104 * @param exp lifetime
1105 * @param key the key the record was stored under
1106 * @param get_path get path
1107 * @param get_path_length get path length
1108 * @param put_path put path
1109 * @param put_path_length put path length
1110 * @param type the block type
1111 * @param size the size of the record
1112 * @param data the record data
1115 process_delegation_result_dht(void* cls,
1116 struct GNUNET_TIME_Absolute exp,
1117 const GNUNET_HashCode * key,
1118 const struct GNUNET_PeerIdentity *get_path,
1119 unsigned int get_path_length,
1120 const struct GNUNET_PeerIdentity *put_path,
1121 unsigned int put_path_length,
1122 enum GNUNET_BLOCK_Type type,
1123 size_t size, const void *data)
1125 struct ResolverHandle *rh;
1126 struct GNSNameRecordBlock *nrb;
1127 uint32_t num_records;
1129 char* rd_data = (char*) data;
1132 struct GNUNET_CRYPTO_ShortHashCode zone, name_hash;
1133 GNUNET_HashCode zone_hash_double, name_hash_double;
1135 rh = (struct ResolverHandle *)cls;
1137 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1138 "GNS_PHASE_DELEGATE_DHT-%llu: Got DHT result\n", rh->id);
1143 nrb = (struct GNSNameRecordBlock*)data;
1145 /* stop dht lookup and timeout task */
1146 GNUNET_DHT_get_stop (rh->get_handle);
1148 rh->get_handle = NULL;
1150 if (rh->dht_heap_node != NULL)
1152 GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
1153 rh->dht_heap_node = NULL;
1156 num_records = ntohl(nrb->rd_count);
1157 name = (char*)&nrb[1];
1159 struct GNUNET_NAMESTORE_RecordData rd[num_records];
1161 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
1162 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
1164 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
1169 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1170 "GNS_PHASE_DELEGATE_DHT-%llu: Error deserializing data!\n",
1175 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1176 "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n",
1177 rh->id, name, rh->authority_name);
1178 for (i=0; i<num_records; i++)
1181 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1182 "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n",
1183 rh->id, name, rh->authority_name);
1184 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1185 "GNS_PHASE_DELEGATE_DHT-%llu: Got type: %d (wanted %d)\n",
1186 rh->id, rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
1187 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1188 "GNS_PHASE_DELEGATE_DHT-%llu: Got data length: %d\n",
1189 rh->id, rd[i].data_size);
1190 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1191 "GNS_PHASE_DELEGATE_DHT-%llu: Got flag %d\n",
1192 rh->id, rd[i].flags);
1194 if ((strcmp(name, rh->authority_name) == 0) &&
1195 (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
1197 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1198 "GNS_PHASE_DELEGATE_DHT-%llu: Authority found in DHT\n",
1201 memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1202 struct AuthorityChain *auth =
1203 GNUNET_malloc(sizeof(struct AuthorityChain));
1204 auth->zone = rh->authority;
1205 memset(auth->name, 0, strlen(rh->authority_name)+1);
1206 strcpy(auth->name, rh->authority_name);
1207 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1208 rh->authority_chain_tail,
1211 /** try to import pkey if private key available */
1213 process_discovered_authority(name, auth->zone,
1214 rh->authority_chain_tail->zone,
1221 GNUNET_CRYPTO_short_hash(name, strlen(name), &name_hash);
1222 GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1223 GNUNET_CRYPTO_hash_xor(key, &name_hash_double, &zone_hash_double);
1224 GNUNET_CRYPTO_short_hash_from_truncation (&zone_hash_double, &zone);
1226 /* Save to namestore */
1227 if (0 != GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_tail->zone,
1230 GNUNET_NAMESTORE_record_put (namestore_handle,
1237 &on_namestore_record_put_result, //cont
1247 * FIXME in this case. should we ask namestore again?
1249 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1250 "GNS_PHASE_DELEGATE_DHT-%llu: Answer from DHT for %s. Yet to resolve: %s\n",
1251 rh->id, rh->authority_name, rh->name);
1252 if (strcmp(rh->name, "") == 0)
1254 rh->proc(rh->proc_cls, rh, 0, NULL);
1258 rh->proc = &handle_delegation_ns;
1259 resolve_delegation_ns(rh);
1265 * No pkey but name exists
1268 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1269 "GNS_PHASE_DELEGATE_DHT-%llu: Adding %s back to %s\n",
1270 rh->id, rh->authority_name, rh->name);
1271 if (strcmp(rh->name, "") == 0)
1272 strcpy(rh->name, rh->authority_name);
1274 GNUNET_snprintf(rh->name, MAX_DNS_NAME_LENGTH, "%s.%s",
1275 rh->name, rh->authority_name); //FIXME ret
1277 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1278 "GNS_PHASE_DELEGATE_DHT-%llu: %s restored\n", rh->id, rh->name);
1279 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1280 "GNS_PHASE_DELEGATE_DHT-%llu: DHT authority lookup found no match!\n",
1282 rh->proc(rh->proc_cls, rh, 0, NULL);
1285 #define MAX_SOA_LENGTH sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)\
1286 +(MAX_DNS_NAME_LENGTH*2)
1287 #define MAX_MX_LENGTH sizeof(uint16_t)+MAX_DNS_NAME_LENGTH
1291 expand_plus(char** dest, char* src, char* repl)
1294 unsigned int s_len = strlen(src)+1;
1296 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1297 "GNS_POSTPROCESS: Got %s to expand with %s\n", src, repl);
1301 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1302 "GNS_POSTPROCESS: %s to short\n", src);
1304 /* no postprocessing */
1305 memcpy(*dest, src, s_len+1);
1309 if (0 == strcmp(src+s_len-3, ".+"))
1311 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1312 "GNS_POSTPROCESS: Expanding .+ in %s\n", src);
1313 memset(*dest, 0, s_len+strlen(repl)+strlen(GNUNET_GNS_TLD));
1315 pos = *dest+s_len-2;
1317 pos += strlen(repl);
1318 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1319 "GNS_POSTPROCESS: Expanded to %s\n", *dest);
1323 memcpy(*dest, src, s_len+1);
1331 finish_lookup(struct ResolverHandle *rh,
1332 struct RecordLookupHandle* rlh,
1333 unsigned int rd_count,
1334 const struct GNUNET_NAMESTORE_RecordData *rd)
1337 char new_rr_data[MAX_DNS_NAME_LENGTH];
1338 char new_mx_data[MAX_MX_LENGTH];
1339 char new_soa_data[MAX_SOA_LENGTH];
1340 struct GNUNET_NAMESTORE_RecordData p_rd[rd_count];
1343 unsigned int offset;
1345 if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1346 GNUNET_SCHEDULER_cancel(rh->timeout_task);
1349 memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData));
1351 for (i = 0; i < rd_count; i++)
1354 if (rd[i].record_type != GNUNET_GNS_RECORD_TYPE_NS &&
1355 rd[i].record_type != GNUNET_GNS_RECORD_TYPE_CNAME &&
1356 rd[i].record_type != GNUNET_GNS_RECORD_MX &&
1357 rd[i].record_type != GNUNET_GNS_RECORD_TYPE_SOA)
1359 p_rd[i].data = rd[i].data;
1364 * for all those records we 'should'
1365 * also try to resolve the A/AAAA records (RFC1035)
1366 * This is a feature and not important
1369 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1370 "GNS_POSTPROCESS: Postprocessing\n");
1372 if (strcmp(rh->name, "+") == 0)
1373 repl_string = rlh->name;
1375 repl_string = rlh->name+strlen(rh->name)+1;
1378 if (rd[i].record_type == GNUNET_GNS_RECORD_MX)
1380 memcpy(new_mx_data, (char*)rd[i].data, sizeof(uint16_t));
1381 offset = sizeof(uint16_t);
1382 pos = new_mx_data+offset;
1383 expand_plus(&pos, (char*)rd[i].data+sizeof(uint16_t),
1385 offset += strlen(new_mx_data+sizeof(uint16_t))+1;
1386 p_rd[i].data = new_mx_data;
1387 p_rd[i].data_size = offset;
1389 else if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_SOA)
1391 /* expand mname and rname */
1393 expand_plus(&pos, (char*)rd[i].data, repl_string);
1394 offset = strlen(new_soa_data)+1;
1395 pos = new_soa_data+offset;
1396 expand_plus(&pos, (char*)rd[i].data+offset, repl_string);
1397 offset += strlen(new_soa_data+offset)+1;
1398 /* cpy the 4 numbers serial refresh retry and expire */
1399 memcpy(new_soa_data+offset, (char*)rd[i].data+offset, sizeof(uint32_t)*5);
1400 offset += sizeof(uint32_t)*5;
1401 p_rd[i].data_size = offset;
1402 p_rd[i].data = new_soa_data;
1407 expand_plus(&pos, (char*)rd[i].data, repl_string);
1408 p_rd[i].data_size = strlen(new_rr_data)+1;
1409 p_rd[i].data = new_rr_data;
1414 rlh->proc(rlh->proc_cls, rd_count, p_rd);
1420 * Process DHT lookup result for record.
1422 * @param cls the closure
1423 * @param rh resolver handle
1424 * @param rd_count number of results
1425 * @param rd record data
1428 handle_record_dht(void* cls, struct ResolverHandle *rh,
1429 unsigned int rd_count,
1430 const struct GNUNET_NAMESTORE_RecordData *rd)
1432 struct RecordLookupHandle* rlh;
1434 rlh = (struct RecordLookupHandle*)cls;
1437 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1438 "GNS_PHASE_REC-%d: No records for %s found in DHT. Aborting\n",
1440 /* give up, cannot resolve */
1441 finish_lookup(rh, rlh, 0, NULL);
1442 free_resolver_handle(rh);
1446 /* results found yay */
1447 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1448 "GNS_PHASE_REC-%d: Record resolved from DHT!", rh->id);
1450 finish_lookup(rh, rlh, rd_count, rd);
1451 free_resolver_handle(rh);
1457 * Process namestore lookup result for record.
1459 * @param cls the closure
1460 * @param rh resolver handle
1461 * @param rd_count number of results
1462 * @param rd record data
1465 handle_record_ns(void* cls, struct ResolverHandle *rh,
1466 unsigned int rd_count,
1467 const struct GNUNET_NAMESTORE_RecordData *rd)
1469 struct RecordLookupHandle* rlh;
1470 rlh = (struct RecordLookupHandle*) cls;
1473 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1474 "GNS_PHASE_REC-%d: NS returned no records. (status: %d)!\n",
1479 * There are 4 conditions that have to met for us to consult the DHT:
1480 * 1. The entry in the DHT is EXPIRED AND
1481 * 2. No entry in the NS existed AND
1482 * 3. The zone queried is not the local resolver's zone AND
1483 * 4. The name that was looked up is '+'
1484 * because if it was any other canonical name we either already queried
1485 * the DHT for the authority in the authority lookup phase (and thus
1486 * would already have an entry in the NS for the record)
1488 if (rh->status & (EXPIRED | !EXISTS) &&
1489 GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1491 (strcmp(rh->name, "+") == 0))
1493 rh->proc = &handle_record_dht;
1494 resolve_record_dht(rh);
1497 /* give up, cannot resolve */
1498 finish_lookup(rh, rlh, 0, NULL);
1499 free_resolver_handle(rh);
1503 /* results found yay */
1504 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1505 "GNS_PHASE_REC-%d: Record resolved from namestore!", rh->id);
1507 finish_lookup(rh, rlh, rd_count, rd);
1509 free_resolver_handle(rh);
1515 * Determine if this name is canonical.
1517 * a.b.gnunet = not canonical
1520 * @param name the name to test
1521 * @return 1 if canonical
1524 is_canonical(char* name)
1526 uint32_t len = strlen(name);
1529 for (i=0; i<len; i++)
1531 if (*(name+i) == '.')
1538 * Move one level up in the domain hierarchy and return the
1539 * passed top level domain.
1541 * @param name the domain
1542 * @param dest the destination where the tld will be put
1545 pop_tld(char* name, char* dest)
1549 if (is_canonical(name))
1556 for (len = strlen(name); len > 0; len--)
1558 if (*(name+len) == '.')
1568 strcpy(dest, (name+len+1));
1572 * Checks if name is in tld
1574 * @param name the name to check
1575 * @param tld the TLD to check for
1576 * @return GNUNET_YES or GNUNET_NO
1579 is_tld(const char* name, const char* tld)
1583 if (strlen(name) <= strlen(tld))
1588 offset = strlen(name)-strlen(tld);
1589 if (strcmp(name+offset, tld) != 0)
1591 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1592 "%s is not in .%s TLD\n", name, tld);
1599 * DHT resolution for delegation finished. Processing result.
1601 * @param cls the closure
1602 * @param rh resolver handle
1603 * @param rd_count number of results (always 0)
1604 * @param rd record data (always NULL)
1607 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
1608 unsigned int rd_count,
1609 const struct GNUNET_NAMESTORE_RecordData *rd)
1611 struct RecordLookupHandle* rlh;
1612 rlh = (struct RecordLookupHandle*) cls;
1615 if (strcmp(rh->name, "") == 0)
1617 if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1619 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1620 "GNS_PHASE_DELEGATE_DHT-%llu: Resolved queried PKEY via DHT.\n",
1622 finish_lookup(rh, rlh, rd_count, rd);
1623 free_resolver_handle(rh);
1626 /* We resolved full name for delegation. resolving record */
1627 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1628 "GNS_PHASE_DELEGATE_DHT-%llu: Resolved full name for delegation via DHT.\n",
1630 strcpy(rh->name, "+\0");
1631 rh->proc = &handle_record_ns;
1632 resolve_record_ns(rh);
1637 * we still have some left
1639 if (is_canonical(rh->name))
1641 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1642 "GNS_PHASE_DELEGATE_DHT-%llu: Resolving canonical record %s in ns\n",
1645 rh->proc = &handle_record_ns;
1646 resolve_record_ns(rh);
1649 /* give up, cannot resolve */
1650 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1651 "GNS_PHASE_DELEGATE_DHT-%llu: Cannot fully resolve delegation for %s via DHT!\n",
1653 finish_lookup(rh, rlh, 0, NULL);
1654 free_resolver_handle(rh);
1659 * Start DHT lookup for a name -> PKEY (compare NS) record in
1660 * rh->authority's zone
1662 * @param rh the pending gns query
1665 resolve_delegation_dht(struct ResolverHandle *rh)
1668 struct GNUNET_CRYPTO_ShortHashCode name_hash;
1669 GNUNET_HashCode name_hash_double;
1670 GNUNET_HashCode zone_hash_double;
1671 GNUNET_HashCode lookup_key;
1672 struct ResolverHandle *rh_heap_root;
1674 pop_tld(rh->name, rh->authority_name);
1675 GNUNET_CRYPTO_short_hash(rh->authority_name,
1676 strlen(rh->authority_name),
1678 GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1679 GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
1680 GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
1682 rh->dht_heap_node = NULL;
1684 if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
1686 //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1687 // &dht_authority_lookup_timeout,
1689 rh->timeout_cont = &dht_authority_lookup_timeout;
1690 rh->timeout_cont_cls = rh;
1694 if (max_allowed_background_queries <=
1695 GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
1697 /* terminate oldest lookup */
1698 rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
1699 GNUNET_DHT_get_stop(rh_heap_root->get_handle);
1700 rh_heap_root->dht_heap_node = NULL;
1702 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1703 "GNS_PHASE_DELEGATE_DHT-%llu: Replacing oldest background query for %s\n",
1704 rh->id, rh_heap_root->authority_name);
1706 rh_heap_root->proc(rh_heap_root->proc_cls,
1711 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
1713 GNUNET_TIME_absolute_get().abs_value);
1716 xquery = htonl(GNUNET_GNS_RECORD_PKEY);
1718 GNUNET_assert(rh->get_handle == NULL);
1719 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
1720 GNUNET_TIME_UNIT_FOREVER_REL,
1721 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1723 DHT_GNS_REPLICATION_LEVEL,
1727 &process_delegation_result_dht,
1734 * Namestore resolution for delegation finished. Processing result.
1736 * @param cls the closure
1737 * @param rh resolver handle
1738 * @param rd_count number of results (always 0)
1739 * @param rd record data (always NULL)
1742 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
1743 unsigned int rd_count,
1744 const struct GNUNET_NAMESTORE_RecordData *rd)
1746 struct RecordLookupHandle* rlh;
1747 rlh = (struct RecordLookupHandle*) cls;
1749 if (strcmp(rh->name, "") == 0)
1751 if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1753 GNUNET_assert(rd_count == 1);
1754 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1755 "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried PKEY in NS.\n",
1757 finish_lookup(rh, rlh, rd_count, rd);
1758 free_resolver_handle(rh);
1761 /* We resolved full name for delegation. resolving record */
1762 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1763 "GNS_PHASE_DELEGATE_NS-%llu: Resolved full name for delegation.\n",
1765 strcpy(rh->name, "+\0");
1766 rh->proc = &handle_record_ns;
1767 resolve_record_ns(rh);
1772 * we still have some left
1773 * check if authority in ns is fresh
1775 * or we are authority
1777 if ((rh->status & (EXISTS | !EXPIRED)) ||
1778 !GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1779 &rh->authority_chain_tail->zone))
1781 if (is_canonical(rh->name))
1783 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1784 "GNS_PHASE_DELEGATE_NS-%llu: Resolving canonical record %s\n",
1787 rh->proc = &handle_record_ns;
1788 resolve_record_ns(rh);
1792 /* give up, cannot resolve */
1793 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1794 "GNS_PHASE_DELEGATE_NS-%llu: Cannot fully resolve delegation for %s!\n",
1797 finish_lookup(rh, rlh, rd_count, rd);
1798 //rlh->proc(rlh->proc_cls, 0, NULL);
1803 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1804 "GNS_PHASE_DELEGATE_NS-%llu: Trying to resolve delegation for %s via DHT\n",
1806 rh->proc = &handle_delegation_dht;
1807 resolve_delegation_dht(rh);
1813 * This is a callback function that should give us only PKEY
1814 * records. Used to query the namestore for the authority (PKEY)
1815 * for 'name'. It will recursively try to resolve the
1816 * authority for a given name from the namestore.
1818 * @param cls the pending query
1819 * @param key the key of the zone we did the lookup
1820 * @param expiration expiration date of the record data set in the namestore
1821 * @param name the name for which we need an authority
1822 * @param rd_count the number of records with 'name'
1823 * @param rd the record data
1824 * @param signature the signature of the authority for the record data
1827 process_delegation_result_ns(void* cls,
1828 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1829 struct GNUNET_TIME_Absolute expiration,
1831 unsigned int rd_count,
1832 const struct GNUNET_NAMESTORE_RecordData *rd,
1833 const struct GNUNET_CRYPTO_RsaSignature *signature)
1835 struct ResolverHandle *rh;
1836 struct GNUNET_TIME_Relative remaining_time;
1837 struct GNUNET_CRYPTO_ShortHashCode zone;
1838 char new_name[MAX_DNS_NAME_LENGTH];
1840 rh = (struct ResolverHandle *)cls;
1841 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1842 "GNS_PHASE_DELEGATE_NS-%llu: Got %d records from authority lookup\n",
1845 GNUNET_CRYPTO_short_hash(key,
1846 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1848 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1854 rh->status |= EXISTS;
1857 if (remaining_time.rel_value == 0)
1859 rh->status |= EXPIRED;
1863 * No authority found in namestore.
1868 * We did not find an authority in the namestore
1873 * Promote this authority back to a name maybe it is
1876 if (strcmp(rh->name, "") == 0)
1878 /* simply promote back */
1879 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1880 "GNS_PHASE_DELEGATE_NS-%llu: Promoting %s back to name\n",
1881 rh->id, rh->authority_name);
1882 strcpy(rh->name, rh->authority_name);
1886 /* add back to existing name */
1887 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1888 "GNS_PHASE_DELEGATE_NS-%llu: Adding %s back to %s\n",
1889 rh->id, rh->authority_name, rh->name);
1890 //memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
1891 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
1892 rh->name, rh->authority_name);
1893 //strcpy(new_name, rh->name);
1894 //strcpy(new_name+strlen(new_name), ".");
1895 //strcpy(new_name+strlen(new_name), rh->authority_name);
1896 strcpy(rh->name, new_name);
1897 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1898 "GNS_PHASE_DELEGATE_NS-%llu: %s restored\n", rh->id, rh->name);
1900 rh->proc(rh->proc_cls, rh, 0, NULL);
1905 * We found an authority that may be able to help us
1906 * move on with query
1907 * Note only 1 pkey should have been returned.. anything else would be strange
1910 for (i=0; i<rd_count;i++)
1913 if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
1916 if (rd[i].flags & GNUNET_NAMESTORE_RF_PENDING)
1918 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1919 "GNS_PHASE_DELEGATE_NS-%llu: PKEY for %s is pending user confirmation.\n",
1925 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
1928 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1929 "GNS_PHASE_DELEGATE_NS-%llu: This pkey is expired.\n",
1931 if (remaining_time.rel_value == 0)
1933 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1934 "GNS_PHASE_DELEGATE_NS-%llu: This dht entry is expired.\n",
1936 rh->authority_chain_head->fresh = 0;
1937 rh->proc(rh->proc_cls, rh, 0, NULL);
1945 * Resolve rest of query with new authority
1947 GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
1948 memcpy(&rh->authority, rd[i].data,
1949 sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1950 struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
1951 auth->zone = rh->authority;
1952 memset(auth->name, 0, strlen(rh->authority_name)+1);
1953 strcpy(auth->name, rh->authority_name);
1954 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1955 rh->authority_chain_tail,
1958 /** try to import pkey if private key available */
1960 process_discovered_authority((char*)name, auth->zone,
1961 rh->authority_chain_tail->zone,
1964 * We are done with PKEY resolution if name is empty
1965 * else resolve again with new authority
1967 if (strcmp(rh->name, "") == 0)
1968 rh->proc(rh->proc_cls, rh, rd_count, rd);
1970 resolve_delegation_ns(rh);
1977 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1978 "GNS_PHASE_DELEGATE_NS-%llu: Authority lookup and no PKEY...\n", rh->id);
1979 rh->proc(rh->proc_cls, rh, 0, NULL);
1984 * Resolve the delegation chain for the request in our namestore
1986 * @param rh the resolver handle
1989 resolve_delegation_ns(struct ResolverHandle *rh)
1991 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1992 "GNS_PHASE_DELEGATE_NS-%llu: Resolving delegation for %s\n",
1994 pop_tld(rh->name, rh->authority_name);
1995 GNUNET_NAMESTORE_lookup_record(namestore_handle,
1998 GNUNET_GNS_RECORD_PKEY,
1999 &process_delegation_result_ns,
2006 * Lookup of a record in a specific zone
2007 * calls lookup result processor on result
2009 * @param zone the root zone
2010 * @param record_type the record type to look up
2011 * @param name the name to look up
2012 * @param key a private key for use with PSEU import (can be NULL)
2013 * @param timeout timeout for resolution
2014 * @param proc the processor to call on result
2015 * @param cls the closure to pass to proc
2018 gns_resolver_lookup_record(struct GNUNET_CRYPTO_ShortHashCode zone,
2019 uint32_t record_type,
2021 struct GNUNET_CRYPTO_RsaPrivateKey *key,
2022 struct GNUNET_TIME_Relative timeout,
2023 RecordLookupProcessor proc,
2026 struct ResolverHandle *rh;
2027 struct RecordLookupHandle* rlh;
2028 char string_hash[MAX_DNS_LABEL_LENGTH];
2029 char nzkey[MAX_DNS_LABEL_LENGTH];
2030 char* nzkey_ptr = nzkey;
2032 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2033 "Starting resolution for %s (type=%d)!\n",
2037 if (is_canonical((char*)name) && (strcmp(GNUNET_GNS_TLD, name) != 0))
2039 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2040 "%s is canonical and not gnunet -> cannot resolve!\n", name);
2045 rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
2046 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2048 rh->authority = zone;
2052 rh->timeout = timeout;
2053 rh->get_handle = NULL;
2054 if (timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
2057 * Set timeout for authority lookup phase to 1/2
2059 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2060 "Timeout for lookup set to %ds\n", rh->timeout.rel_value);
2061 rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
2062 GNUNET_TIME_relative_divide(timeout, 2),
2063 &handle_lookup_timeout,
2065 rh->timeout_cont = &dht_authority_lookup_timeout;
2066 rh->timeout_cont_cls = rh;
2070 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No timeout for query!\n");
2071 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2074 if (strcmp(GNUNET_GNS_TLD, name) == 0)
2077 * Only 'gnunet' given
2079 strcpy(rh->name, "\0");
2083 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2084 "Checking for TLD...\n");
2085 if (is_zkey_tld(name) == GNUNET_YES)
2087 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2090 * This is a zkey tld
2091 * build hash and use as initial authority
2094 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
2095 memcpy(rh->name, name,
2096 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
2097 pop_tld(rh->name, string_hash);
2099 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2100 "ZKEY is %s!\n", string_hash);
2102 GNUNET_STRINGS_utf8_toupper(string_hash, &nzkey_ptr);
2104 if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(nzkey,
2107 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2108 "Cannot convert ZKEY %s to hash!\n", string_hash);
2118 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2121 * Presumably GNUNET tld
2124 strlen(name)-strlen(GNUNET_GNS_TLD));
2125 memcpy(rh->name, name,
2126 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2131 * Initialize authority chain
2133 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2134 rh->authority_chain_head->prev = NULL;
2135 rh->authority_chain_head->next = NULL;
2136 rh->authority_chain_tail = rh->authority_chain_head;
2137 rh->authority_chain_head->zone = rh->authority;
2140 * Copy original query into lookup handle
2142 rlh->record_type = record_type;
2143 memset(rlh->name, 0, strlen(name) + 1);
2144 strcpy(rlh->name, name);
2146 rlh->proc_cls = cls;
2148 rh->proc = &handle_delegation_ns;
2149 resolve_delegation_ns(rh);
2152 /******** END Record Resolver ***********/
2156 * Callback calles by namestore for a zone to name
2159 * @param cls the closure
2160 * @param zone_key the zone we queried
2161 * @param expire the expiration time of the name
2162 * @param name the name found or NULL
2163 * @param rd_len number of records for the name
2164 * @param rd the record data (PKEY) for the name
2165 * @param signature the signature for the record data
2168 process_zone_to_name_shorten(void *cls,
2169 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
2170 struct GNUNET_TIME_Absolute expire,
2172 unsigned int rd_len,
2173 const struct GNUNET_NAMESTORE_RecordData *rd,
2174 const struct GNUNET_CRYPTO_RsaSignature *signature)
2176 struct ResolverHandle *rh = (struct ResolverHandle *)cls;
2177 struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
2178 struct AuthorityChain *next_authority;
2180 char result[MAX_DNS_NAME_LENGTH];
2181 char next_authority_name[MAX_DNS_LABEL_LENGTH];
2184 /* we found a match in our own zone */
2187 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2188 "result strlen %d\n", strlen(name));
2189 answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
2190 memset(result, 0, answer_len);
2191 if (strlen(rh->name) > 0)
2193 strcpy(result, rh->name);
2194 strcpy(result+strlen(rh->name), ".");
2197 strcpy(result+strlen(result), name);
2198 strcpy(result+strlen(result), ".");
2199 strcpy(result+strlen(result), GNUNET_GNS_TLD);
2201 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2202 "Sending shorten result %s\n", result);
2204 nsh->proc(nsh->proc_cls, result);
2206 free_resolver_handle(rh);
2208 else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2211 /* our zone, just append .gnunet */
2212 answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
2213 memset(result, 0, answer_len);
2214 strcpy(result, rh->name);
2215 strcpy(result+strlen(rh->name), ".");
2216 strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
2218 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2219 "Our zone: Sending name as shorten result %s\n", rh->name);
2221 nsh->proc(nsh->proc_cls, result);
2223 free_resolver_handle(rh);
2229 * continue with next authority
2231 next_authority = rh->authority_chain_head;
2233 GNUNET_snprintf(next_authority_name, MAX_DNS_NAME_LENGTH,
2234 "%s.%s", rh->name, next_authority->name);
2236 strcpy(rh->name, next_authority_name);
2237 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2238 "No PSEU found for authority %s. Promoting back: %s\n",
2239 next_authority->name, rh->name);
2241 GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
2242 rh->authority_chain_tail,
2245 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2246 &rh->authority_chain_tail->zone,
2247 &rh->authority_chain_head->zone,
2248 &process_zone_to_name_shorten,
2254 * DHT resolution for delegation. Processing result.
2256 * @param cls the closure
2257 * @param rh resolver handle
2258 * @param rd_count number of results
2259 * @param rd record data
2262 handle_delegation_dht_bg_shorten(void* cls, struct ResolverHandle *rh,
2263 unsigned int rd_count,
2264 const struct GNUNET_NAMESTORE_RecordData *rd)
2267 /* We resolved full name for delegation. resolving record */
2268 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2269 "GNS_SHORTEN: Resolved up to %s for delegation via DHT in background.\n",
2271 free_resolver_handle(rh);
2275 * Process result from namestore delegation lookup
2276 * for shorten operation
2278 * @param cls the client shorten handle
2279 * @param rh the resolver handle
2280 * @param rd_count number of results (0)
2281 * @param rd data (NULL)
2284 handle_delegation_ns_shorten(void* cls,
2285 struct ResolverHandle *rh,
2287 const struct GNUNET_NAMESTORE_RecordData *rd)
2289 struct NameShortenHandle *nsh;
2290 char result[MAX_DNS_NAME_LENGTH];
2292 struct ResolverHandle *rh_bg;
2294 nsh = (struct NameShortenHandle *)cls;
2297 * At this point rh->name contains the part of the name
2298 * that we do not have a PKEY in our namestore to resolve.
2299 * The authority chain in the resolver handle is now
2300 * useful to backtrack if needed
2303 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2304 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2306 if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2310 * This is our zone append .gnunet unless name is empty
2311 * (it shouldn't be, usually FIXME what happens if we
2312 * shorten to our zone to a "" record??)
2315 answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
2316 memset(result, 0, answer_len);
2317 strcpy(result, rh->name);
2318 strcpy(result+strlen(rh->name), ".");
2319 strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
2321 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2322 "Our zone: Sending name as shorten result %s\n", rh->name);
2324 nsh->proc(nsh->proc_cls, result);
2326 free_resolver_handle(rh);
2331 * we have to this before zone to name for rh might
2335 if (!is_canonical(rh->name))
2337 rh_bg = GNUNET_malloc(sizeof(struct ResolverHandle));
2338 memcpy(rh_bg, rh, sizeof(struct ResolverHandle));
2342 /* backtrack authorities for names */
2343 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2344 &rh->authority_chain_tail->zone, //ours
2345 &rh->authority_chain_head->zone,
2346 &process_zone_to_name_shorten,
2355 * If authority resolution is incomplete we can do a background lookup
2356 * of the full name so that next time we can (likely) fully or at least
2357 * further shorten the name
2359 rh_bg->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2360 rh_bg->authority_chain_tail = rh_bg->authority_chain_head;
2361 rh_bg->authority_chain_head->zone = rh_bg->authority;
2363 rh_bg->proc = &handle_delegation_dht_bg_shorten;
2364 rh_bg->proc_cls = NULL;
2366 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2367 "GNS_SHORTEN: Starting background lookup for %s\n",
2370 resolve_delegation_dht(rh_bg);
2376 * Callback calles by namestore for a zone to name
2379 * @param cls the closure
2380 * @param zone_key the zone we queried
2381 * @param expire the expiration time of the name
2382 * @param name the name found or NULL
2383 * @param rd_len number of records for the name
2384 * @param rd the record data (PKEY) for the name
2385 * @param signature the signature for the record data
2388 process_zone_to_name_zkey(void *cls,
2389 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
2390 struct GNUNET_TIME_Absolute expire,
2392 unsigned int rd_len,
2393 const struct GNUNET_NAMESTORE_RecordData *rd,
2394 const struct GNUNET_CRYPTO_RsaSignature *signature)
2396 struct ResolverHandle *rh = cls;
2397 struct NameShortenHandle *nsh = rh->proc_cls;
2398 struct GNUNET_CRYPTO_ShortHashAsciiEncoded enc;
2399 char new_name[MAX_DNS_NAME_LENGTH];
2401 /* zkey not in our zone */
2405 * In this case we have not given this PKEY a name (yet)
2406 * It is either just not in our zone or not even cached
2407 * Since we do not know at this point we will not try to shorten
2408 * because PKEY import will happen if the user follows the zkey
2411 GNUNET_CRYPTO_short_hash_to_enc ((struct GNUNET_CRYPTO_ShortHashCode*)rd,
2413 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2414 "No name found for zkey %s returning verbatim!\n", enc);
2415 if (strcmp(rh->name, "") != 0)
2416 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s.%s",
2417 rh->name, enc, GNUNET_GNS_TLD_ZKEY);
2419 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
2420 enc, GNUNET_GNS_TLD_ZKEY);
2421 nsh->proc(nsh->proc_cls, new_name);
2423 free_resolver_handle(rh);
2427 if (strcmp(rh->name, "") != 0)
2428 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
2431 strcpy(new_name, name);
2433 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2434 "Continue shorten for %s!\n", new_name);
2436 strcpy(rh->name, new_name);
2438 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2439 rh->authority_chain_tail = rh->authority_chain_head;
2440 rh->authority_chain_head->zone = rh->authority;
2443 /* Start delegation resolution in our namestore */
2444 resolve_delegation_ns(rh);
2449 * Shorten api from resolver
2451 * @param zone the zone to use
2452 * @param name the name to shorten
2453 * @param key optional private key for background lookups and PSEU import
2454 * @param proc the processor to call with result
2455 * @param proc_cls closure to pass to proc
2458 gns_resolver_shorten_name(struct GNUNET_CRYPTO_ShortHashCode zone,
2460 struct GNUNET_CRYPTO_RsaPrivateKey *key,
2461 ShortenResultProcessor proc,
2464 struct ResolverHandle *rh;
2465 struct NameShortenHandle *nsh;
2466 char string_hash[MAX_DNS_LABEL_LENGTH];
2467 struct GNUNET_CRYPTO_ShortHashCode zkey;
2468 char nzkey[MAX_DNS_LABEL_LENGTH];
2469 char* nzkey_ptr = nzkey;
2472 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2473 "Starting shorten for %s!\n", name);
2475 if (is_canonical((char*)name))
2477 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2478 "%s is canonical. Returning verbatim\n", name);
2479 proc(proc_cls, name);
2483 nsh = GNUNET_malloc(sizeof (struct NameShortenHandle));
2486 nsh->proc_cls = proc_cls;
2488 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2489 rh->authority = zone;
2492 rh->proc = &handle_delegation_ns_shorten;
2496 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2497 "Checking for TLD...\n");
2498 if (is_zkey_tld(name) == GNUNET_YES)
2500 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2503 * This is a zkey tld
2504 * build hash and use as initial authority
2508 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
2509 memcpy(rh->name, name,
2510 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
2511 pop_tld(rh->name, string_hash);
2513 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2514 "ZKEY is %s!\n", string_hash);
2516 GNUNET_STRINGS_utf8_toupper(string_hash, &nzkey_ptr);
2518 if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(nzkey,
2521 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2522 "Cannot convert ZKEY %s to hash!\n", nzkey);
2525 proc(proc_cls, name);
2529 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2532 &process_zone_to_name_zkey,
2539 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2542 * Presumably GNUNET tld
2545 strlen(name)-strlen(GNUNET_GNS_TLD));
2546 memcpy(rh->name, name,
2547 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2550 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2551 rh->authority_chain_tail = rh->authority_chain_head;
2552 rh->authority_chain_head->zone = zone;
2555 /* Start delegation resolution in our namestore */
2556 resolve_delegation_ns(rh);
2559 /*********** END NAME SHORTEN ********************/
2563 * Process result from namestore delegation lookup
2564 * for get authority operation
2566 * @param cls the client get auth handle
2567 * @param rh the resolver handle
2568 * @param rd_count number of results (0)
2569 * @param rd data (NULL)
2572 handle_delegation_result_ns_get_auth(void* cls,
2573 struct ResolverHandle *rh,
2575 const struct GNUNET_NAMESTORE_RecordData *rd)
2577 struct GetNameAuthorityHandle* nah;
2578 char result[MAX_DNS_NAME_LENGTH];
2581 nah = (struct GetNameAuthorityHandle*) rh->proc_cls;
2584 * At this point rh->name contains the part of the name
2585 * that we do not have a PKEY in our namestore to resolve.
2586 * The authority chain in the resolver handle is now
2587 * useful to backtrack if needed
2590 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2591 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2593 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2594 "Building response!\n");
2595 if (is_canonical(rh->name))
2598 * We successfully resolved the authority in the ns
2599 * FIXME for our purposes this is fine
2600 * but maybe we want to have an api that also looks
2601 * into the dht (i.e. option in message)
2603 if (strlen(rh->name) > strlen(nah->name))
2605 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2606 "Record name longer than original lookup name... odd!\n");
2610 answer_len = strlen(nah->name) - strlen(rh->name)
2611 + strlen(GNUNET_GNS_TLD) + 1;
2612 memset(result, 0, answer_len);
2613 strcpy(result, nah->name + strlen(rh->name) + 1);
2615 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2616 "Got authority result %s\n", result);
2618 nah->proc(nah->proc_cls, result);
2620 free_resolver_handle(rh);
2624 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2625 "Unable to resolve authority for remaining %s!\n", rh->name);
2626 nah->proc(nah->proc_cls, "");
2628 free_resolver_handle(rh);
2636 * Tries to resolve the authority for name
2639 * @param zone the root zone to look up for
2640 * @param name the name to lookup up
2641 * @param proc the processor to call when finished
2642 * @param proc_cls the closure to pass to the processor
2645 gns_resolver_get_authority(struct GNUNET_CRYPTO_ShortHashCode zone,
2647 GetAuthorityResultProcessor proc,
2650 struct ResolverHandle *rh;
2651 struct GetNameAuthorityHandle *nah;
2653 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2654 "Starting authority resolution for %s!\n", name);
2656 nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
2657 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2658 rh->authority = zone;
2661 if (strcmp(GNUNET_GNS_TLD, name) == 0)
2663 strcpy(rh->name, "\0");
2668 strlen(name)-strlen(GNUNET_GNS_TLD));
2669 memcpy(rh->name, name,
2670 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2673 memset(nah->name, 0,
2675 strcpy(nah->name, name);
2677 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2678 rh->authority_chain_tail = rh->authority_chain_head;
2679 rh->authority_chain_head->zone = zone;
2680 rh->proc = &handle_delegation_result_ns_get_auth;
2681 rh->proc_cls = (void*)nah;
2684 nah->proc_cls = proc_cls;
2686 /* Start delegation resolution in our namestore */
2687 resolve_delegation_ns(rh);
2691 /******** END GET AUTHORITY *************/
2693 /* end of gnunet-service-gns_resolver.c */