2 This file is part of GNUnet.
3 (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
24 * @file gns/gnunet-service-gns_resolver.c
25 * @brief GNUnet GNS resolver logic
26 * @author Martin Schanzenbach
30 #include "gnunet_util_lib.h"
31 #include "gnunet_transport_service.h"
32 #include "gnunet_dns_service.h"
33 #include "gnunet_dht_service.h"
34 #include "gnunet_namestore_service.h"
35 #include "gnunet_dns_service.h"
36 #include "gnunet_dnsparser_lib.h"
37 #include "gnunet_gns_service.h"
38 #include "block_gns.h"
40 #include "gnunet-service-gns_resolver.h"
42 #define DHT_OPERATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)
43 #define DHT_LOOKUP_TIMEOUT DHT_OPERATION_TIMEOUT
44 #define DHT_GNS_REPLICATION_LEVEL 5
45 #define MAX_DNS_LABEL_LENGTH 63
49 * Our handle to the namestore service
51 static struct GNUNET_NAMESTORE_Handle *namestore_handle;
54 * Resolver handle to the dht
56 static struct GNUNET_DHT_Handle *dht_handle;
59 * Heap for parallel DHT lookups
61 static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
64 * Maximum amount of parallel queries in background
66 static unsigned long long max_allowed_background_queries;
71 static struct GNUNET_CRYPTO_ShortHashCode local_zone;
74 * Namestore calls this function if we have record for this name.
75 * (or with rd_count=0 to indicate no matches)
77 * @param cls the pending query
78 * @param key the key of the zone we did the lookup
79 * @param expiration expiration date of the namestore entry
80 * @param name the name for which we need an authority
81 * @param rd_count the number of records with 'name'
82 * @param rd the record data
83 * @param signature the signature of the authority for the record data
86 process_pseu_lookup_ns(void* cls,
87 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
88 struct GNUNET_TIME_Absolute expiration,
89 const char *name, unsigned int rd_count,
90 const struct GNUNET_NAMESTORE_RecordData *rd,
91 const struct GNUNET_CRYPTO_RsaSignature *signature)
93 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
94 struct GNUNET_NAMESTORE_RecordData new_pkey;
98 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
99 "GNS_AUTO_PSEU: Name %s already taken in NS!\n", name);
100 if (0 == strcmp(gph->name, name))
102 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
103 "GNS_AUTO_PSEU: Intelligent replacement not implemented\n",
109 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
110 "GNS_AUTO_PSEU: Trying delegated name %s\n", gph->name);
111 memcpy(gph->new_name, gph->name, strlen(gph->name)+1);
112 GNUNET_NAMESTORE_lookup_record(namestore_handle,
115 GNUNET_GNS_RECORD_PSEU,
116 &process_pseu_lookup_ns,
122 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
123 "GNS_AUTO_PSEU: Name %s not taken in NS! Adding\n", gph->new_name);
125 new_pkey.expiration = GNUNET_TIME_absolute_get_forever ();
126 new_pkey.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode);
127 new_pkey.data = &gph->new_zone;
128 new_pkey.record_type = GNUNET_GNS_RECORD_PKEY;
129 GNUNET_NAMESTORE_record_create (namestore_handle,
140 * process result of a dht pseu lookup
142 * @param gph the handle
143 * @param name the pseu result or NULL
146 process_pseu_result(struct GetPseuAuthorityHandle* gph, char* name)
150 memcpy(gph->new_name, gph->name, strlen(gph->name)+1);
154 memcpy(gph->new_name, name, strlen(name)+1);
157 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
158 "GNS_AUTO_PSEU: Checking %s for collision in NS\n", gph->new_name);
161 * Check for collision
163 GNUNET_NAMESTORE_lookup_record(namestore_handle,
166 GNUNET_GNS_RECORD_PSEU,
167 &process_pseu_lookup_ns,
172 * Handle timeout for dht request
174 * @param cls the request handle as closure
175 * @param tc the task context
178 handle_auth_discovery_timeout(void *cls,
179 const struct GNUNET_SCHEDULER_TaskContext *tc)
181 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
183 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
184 "GNS_GET_AUTH: dht lookup for query PSEU timed out.\n");
185 GNUNET_DHT_get_stop (gph->get_handle);
186 gph->get_handle = NULL;
187 process_pseu_result(gph, NULL);
191 * Function called when we find a PSEU entry in the DHT
193 * @param cls the request handle
194 * @param exp lifetime
195 * @param key the key the record was stored under
196 * @param get_path get path
197 * @param get_path_length get path length
198 * @param put_path put path
199 * @param put_path_length put path length
200 * @param type the block type
201 * @param size the size of the record
202 * @param data the record data
205 process_auth_discovery_dht_result(void* cls,
206 struct GNUNET_TIME_Absolute exp,
207 const GNUNET_HashCode * key,
208 const struct GNUNET_PeerIdentity *get_path,
209 unsigned int get_path_length,
210 const struct GNUNET_PeerIdentity *put_path,
211 unsigned int put_path_length,
212 enum GNUNET_BLOCK_Type type,
213 size_t size, const void *data)
215 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
216 struct GNSNameRecordBlock *nrb;
217 char* rd_data = (char*)data;
223 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
224 "GNS_GET_AUTH: got dht result (size=%d)\n", size);
228 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
229 "GNS_GET_AUTH: got dht result null!\n", size);
235 nrb = (struct GNSNameRecordBlock*)data;
237 /* stop lookup and timeout task */
238 GNUNET_DHT_get_stop (gph->get_handle);
239 gph->get_handle = NULL;
240 GNUNET_SCHEDULER_cancel(gph->timeout);
242 gph->get_handle = NULL;
244 nrb = (struct GNSNameRecordBlock*)data;
246 name = (char*)&nrb[1];
247 num_records = ntohl(nrb->rd_count);
249 struct GNUNET_NAMESTORE_RecordData rd[num_records];
251 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
252 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
254 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
259 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
260 "GNS_GET_AUTH: Error deserializing data!\n");
266 for (i=0; i<num_records; i++)
268 if ((strcmp(name, "+") == 0) &&
269 (rd[i].record_type == GNUNET_GNS_RECORD_PSEU))
272 process_pseu_result(gph, (char*)rd[i].data);
278 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_GET_AUTH: no pseu in dht!\n");
279 process_pseu_result(gph, NULL);
283 process_auth_discovery_ns_result(void* cls,
284 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
285 struct GNUNET_TIME_Absolute expiration,
286 const char *name, unsigned int rd_count,
287 const struct GNUNET_NAMESTORE_RecordData *rd,
288 const struct GNUNET_CRYPTO_RsaSignature *signature)
291 struct GNUNET_CRYPTO_ShortHashCode name_hash;
292 GNUNET_HashCode lookup_key;
293 struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
294 GNUNET_HashCode name_hash_double;
295 GNUNET_HashCode zone_hash_double;
297 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
305 GNUNET_CRYPTO_short_hash("+", strlen("+"), &name_hash);
306 GNUNET_CRYPTO_short_hash_double (&name_hash, &name_hash_double);
307 GNUNET_CRYPTO_short_hash_double (&gph->new_zone, &zone_hash_double);
308 GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
309 GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
311 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
312 "GNS_AUTO_PSEU: starting dht lookup for %s with key: %s\n",
313 "+", (char*)&lookup_key_string);
315 gph->timeout = GNUNET_SCHEDULER_add_delayed(DHT_LOOKUP_TIMEOUT,
316 &handle_auth_discovery_timeout, gph);
318 xquery = htonl(GNUNET_GNS_RECORD_PSEU);
320 GNUNET_assert(gph->get_handle == NULL);
321 gph->get_handle = GNUNET_DHT_get_start(dht_handle,
322 GNUNET_TIME_UNIT_FOREVER_REL,
323 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
325 DHT_GNS_REPLICATION_LEVEL,
329 &process_auth_discovery_dht_result,
333 for (i=0; i<rd_count; i++)
335 if ((strcmp(name, "+") == 0) &&
336 (rd[i].record_type == GNUNET_GNS_RECORD_PSEU))
339 process_pseu_result(gph, (char*)rd[i].data);
346 * Callback called by namestore for a zone to name
349 * @param cls the closure
350 * @param zone_key the zone we queried
351 * @param expire the expiration time of the name
352 * @param name the name found or NULL
353 * @param rd_len number of records for the name
354 * @param rd the record data (PKEY) for the name
355 * @param signature the signature for the record data
358 process_zone_to_name_discover(void *cls,
359 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
360 struct GNUNET_TIME_Absolute expire,
363 const struct GNUNET_NAMESTORE_RecordData *rd,
364 const struct GNUNET_CRYPTO_RsaSignature *signature)
366 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
368 /* we found a match in our own zone */
371 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
372 "GNS_AUTO_PSEU: name for zone in our root %s\n", name);
378 GNUNET_NAMESTORE_lookup_record(namestore_handle,
381 GNUNET_GNS_RECORD_PSEU,
382 &process_auth_discovery_ns_result,
391 * Callback for new authories
393 * @param name the name given by delegation
394 * @param zone the authority
395 * @param our_zone our local zone
396 * @param key the private key of our authority
398 static void process_discovered_authority(char* name,
399 struct GNUNET_CRYPTO_ShortHashCode zone,
400 struct GNUNET_CRYPTO_ShortHashCode our_zone,
401 struct GNUNET_CRYPTO_RsaPrivateKey *key)
403 struct GetPseuAuthorityHandle *gph;
406 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
407 "GNS_AUTO_PSEU: New authority %s discovered\n",
410 gph = GNUNET_malloc(sizeof(struct GetPseuAuthorityHandle));
411 namelen = strlen(name) + 1;
412 memcpy(gph->name, name, namelen);
414 gph->new_zone = zone;
415 gph->zone = our_zone;
418 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
421 &process_zone_to_name_discover,
427 * Initialize the resolver
429 * @param nh the namestore handle
430 * @param dh the dht handle
431 * @param lz the local zone's hash
432 * @param max_bg_queries maximum number of parallel background queries in dht
433 * @return GNUNET_OK on success
436 gns_resolver_init(struct GNUNET_NAMESTORE_Handle *nh,
437 struct GNUNET_DHT_Handle *dh,
438 struct GNUNET_CRYPTO_ShortHashCode lz,
439 unsigned long long max_bg_queries)
441 namestore_handle = nh;
445 GNUNET_CONTAINER_heap_create(GNUNET_CONTAINER_HEAP_ORDER_MIN);
446 max_allowed_background_queries = max_bg_queries;
448 if ((namestore_handle != NULL) && (dht_handle != NULL))
452 return GNUNET_SYSERR;
456 * Cleanup background lookups
458 * @param cls closure to iterator
459 * @param node heap nodes
460 * @param element the resolver handle
461 * @param cost heap cost
462 * @return always GNUNET_YES
465 cleanup_pending_background_queries(void* cls,
466 struct GNUNET_CONTAINER_HeapNode *node,
468 GNUNET_CONTAINER_HeapCostType cost)
470 struct ResolverHandle *rh = (struct ResolverHandle *)element;
471 ResolverCleanupContinuation cont = cls;
473 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
474 "GNS_CLEANUP: Terminating background lookup for %s\n",
476 GNUNET_DHT_get_stop(rh->get_handle);
477 rh->get_handle = NULL;
478 rh->proc(rh->proc_cls, rh, 0, NULL);
480 GNUNET_CONTAINER_heap_remove_node(node);
482 if (GNUNET_CONTAINER_heap_get_size(dht_lookup_heap) == 0)
494 gns_resolver_cleanup(ResolverCleanupContinuation cont)
496 unsigned int s = GNUNET_CONTAINER_heap_get_size(dht_lookup_heap);
497 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
498 "GNS_CLEANUP: %d pending background queries to terminate\n", s);
501 GNUNET_CONTAINER_heap_iterate (dht_lookup_heap,
502 &cleanup_pending_background_queries,
510 * Helper function to free resolver handle
512 * @param rh the handle to free
515 free_resolver_handle(struct ResolverHandle* rh)
517 struct AuthorityChain *ac;
518 struct AuthorityChain *ac_next;
523 ac = rh->authority_chain_head;
536 * Callback when record data is put into namestore
538 * @param cls the closure
539 * @param success GNUNET_OK on success
540 * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
543 on_namestore_record_put_result(void *cls,
547 if (GNUNET_NO == success)
549 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
550 "GNS_NS: records already in namestore\n");
553 else if (GNUNET_YES == success)
555 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
556 "GNS_NS: records successfully put in namestore\n");
560 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
561 "GNS_NS: Error putting records into namestore: %s\n", emsg);
565 handle_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
567 struct ResolverHandle *rh = cls;
569 if (rh->timeout_cont)
570 rh->timeout_cont(rh->timeout_cont_cls, tc);
574 * Processor for background lookups in the DHT
576 * @param cls closure (NULL)
577 * @param rd_count number of records found (not 0)
578 * @param rd record data
581 background_lookup_result_processor(void *cls,
583 const struct GNUNET_NAMESTORE_RecordData *rd)
585 //We could do sth verbose/more useful here but it doesn't make any difference
586 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
587 "GNS_BG: background dht lookup for finished. (%d results)\n",
592 * Handle timeout for DHT requests
594 * @param cls the request handle as closure
595 * @param tc the task context
598 dht_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
600 struct ResolverHandle *rh = cls;
601 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
602 char new_name[MAX_DNS_NAME_LENGTH];
604 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
605 "GNS_PHASE_REC: dht lookup for query %s timed out.\n",
608 * Start resolution in bg
610 //strcpy(new_name, rh->name);
611 //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD));
612 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
613 rh->name, GNUNET_GNS_TLD);
615 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
616 "GNS_PHASE_REC: Starting background lookup for %s type %d\n",
617 new_name, rlh->record_type);
619 gns_resolver_lookup_record(rh->authority,
623 GNUNET_TIME_UNIT_FOREVER_REL,
624 &background_lookup_result_processor,
626 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
628 GNUNET_DHT_get_stop (rh->get_handle);
629 rh->get_handle = NULL;
630 rh->proc(rh->proc_cls, rh, 0, NULL);
635 * Function called when we get a result from the dht
636 * for our record query
638 * @param cls the request handle
639 * @param exp lifetime
640 * @param key the key the record was stored under
641 * @param get_path get path
642 * @param get_path_length get path length
643 * @param put_path put path
644 * @param put_path_length put path length
645 * @param type the block type
646 * @param size the size of the record
647 * @param data the record data
650 process_record_result_dht(void* cls,
651 struct GNUNET_TIME_Absolute exp,
652 const GNUNET_HashCode * key,
653 const struct GNUNET_PeerIdentity *get_path,
654 unsigned int get_path_length,
655 const struct GNUNET_PeerIdentity *put_path,
656 unsigned int put_path_length,
657 enum GNUNET_BLOCK_Type type,
658 size_t size, const void *data)
660 struct ResolverHandle *rh;
661 struct RecordLookupHandle *rlh;
662 struct GNSNameRecordBlock *nrb;
663 uint32_t num_records;
665 char* rd_data = (char*)data;
669 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
670 "GNS_PHASE_REC: got dht result (size=%d)\n", size);
675 //FIXME maybe check expiration here, check block type
677 rh = (struct ResolverHandle *)cls;
678 rlh = (struct RecordLookupHandle *) rh->proc_cls;
679 nrb = (struct GNSNameRecordBlock*)data;
681 /* stop lookup and timeout task */
682 GNUNET_DHT_get_stop (rh->get_handle);
683 rh->get_handle = NULL;
685 if (rh->dht_heap_node != NULL)
687 GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
688 rh->dht_heap_node = NULL;
691 if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
693 GNUNET_SCHEDULER_cancel(rh->timeout_task);
694 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
697 rh->get_handle = NULL;
698 name = (char*)&nrb[1];
699 num_records = ntohl(nrb->rd_count);
701 struct GNUNET_NAMESTORE_RecordData rd[num_records];
703 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
704 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
706 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
711 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
715 for (i=0; i<num_records; i++)
717 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
718 "GNS_PHASE_REC: Got name: %s (wanted %s)\n", name, rh->name);
719 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
720 "GNS_PHASE_REC: Got type: %d\n",
722 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
723 "GNS_PHASE_REC: Got data length: %d\n", rd[i].data_size);
724 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
725 "GNS_PHASE_REC: Got flag %d\n", rd[i].flags);
727 if ((strcmp(name, rh->name) == 0) &&
728 (rd[i].record_type == rlh->record_type))
736 * FIXME check pubkey against existing key in namestore?
737 * https://gnunet.org/bugs/view.php?id=2179
740 /* Save to namestore */
741 GNUNET_NAMESTORE_record_put (namestore_handle,
748 &on_namestore_record_put_result, //cont
753 rh->proc(rh->proc_cls, rh, num_records, rd);
755 rh->proc(rh->proc_cls, rh, 0, NULL);
762 * Start DHT lookup for a (name -> query->record_type) record in
763 * rh->authority's zone
765 * @param rh the pending gns query context
768 resolve_record_dht(struct ResolverHandle *rh)
771 struct GNUNET_CRYPTO_ShortHashCode name_hash;
772 GNUNET_HashCode lookup_key;
773 GNUNET_HashCode name_hash_double;
774 GNUNET_HashCode zone_hash_double;
775 struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
776 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
777 struct ResolverHandle *rh_heap_root;
779 GNUNET_CRYPTO_short_hash(rh->name, strlen(rh->name), &name_hash);
780 GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
781 GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
782 GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
783 GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
785 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
786 "GNS_PHASE_REC: starting dht lookup for %s with key: %s\n",
787 rh->name, (char*)&lookup_key_string);
789 //rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
790 rh->dht_heap_node = NULL;
792 if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
795 * Update timeout if necessary
797 if (rh->timeout_task == GNUNET_SCHEDULER_NO_TASK)
800 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
801 "GNS_PHASE_REC: Adjusting timeout\n");
803 * Set timeout for authority lookup phase to 1/2
805 rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
806 GNUNET_TIME_relative_divide(rh->timeout, 2),
807 &handle_lookup_timeout,
810 //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
811 // &dht_lookup_timeout,
813 rh->timeout_cont = &dht_lookup_timeout;
814 rh->timeout_cont_cls = rh;
818 if (max_allowed_background_queries <=
819 GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
821 rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
822 GNUNET_DHT_get_stop(rh_heap_root->get_handle);
823 rh_heap_root->get_handle = NULL;
824 rh_heap_root->dht_heap_node = NULL;
826 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
827 "GNS_PHASE_REC: Replacing oldest background query for %s\n",
829 rh_heap_root->proc(rh_heap_root->proc_cls,
834 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
836 GNUNET_TIME_absolute_get().abs_value);
839 xquery = htonl(rlh->record_type);
841 GNUNET_assert(rh->get_handle == NULL);
842 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
843 GNUNET_TIME_UNIT_FOREVER_REL,
844 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
846 DHT_GNS_REPLICATION_LEVEL,
850 &process_record_result_dht,
857 * Namestore calls this function if we have record for this name.
858 * (or with rd_count=0 to indicate no matches)
860 * @param cls the pending query
861 * @param key the key of the zone we did the lookup
862 * @param expiration expiration date of the namestore entry
863 * @param name the name for which we need an authority
864 * @param rd_count the number of records with 'name'
865 * @param rd the record data
866 * @param signature the signature of the authority for the record data
869 process_record_result_ns(void* cls,
870 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
871 struct GNUNET_TIME_Absolute expiration,
872 const char *name, unsigned int rd_count,
873 const struct GNUNET_NAMESTORE_RecordData *rd,
874 const struct GNUNET_CRYPTO_RsaSignature *signature)
876 struct ResolverHandle *rh;
877 struct RecordLookupHandle *rlh;
878 struct GNUNET_TIME_Relative remaining_time;
879 struct GNUNET_CRYPTO_ShortHashCode zone;
881 rh = (struct ResolverHandle *) cls;
882 rlh = (struct RecordLookupHandle *)rh->proc_cls;
883 GNUNET_CRYPTO_short_hash(key,
884 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
886 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
894 rh->status |= EXISTS;
897 if (remaining_time.rel_value == 0)
899 rh->status |= EXPIRED;
905 * Lookup terminated and no results
907 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
908 "GNS_PHASE_REC: Namestore lookup for %s terminated without results\n",
911 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
912 "GNS_PHASE_REC: Record %s unknown in namestore\n",
915 * Our zone and no result? Cannot resolve TT
917 rh->proc(rh->proc_cls, rh, 0, NULL);
924 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
925 "GNS_PHASE_REC: Processing additional result %s from namestore\n",
928 for (i=0; i<rd_count;i++)
931 if (rd[i].record_type != rlh->record_type)
934 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
937 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
938 "GNS_PHASE_REC: This record is expired. Skipping\n");
949 if (rh->answered == 0)
951 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
952 "GNS_PHASE_REC: No answers found. This is odd!\n");
953 rh->proc(rh->proc_cls, rh, 0, NULL);
957 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
958 "GNS_PHASE_REC: Found %d answer(s) to query in %d records!\n",
959 rh->answered, rd_count);
961 rh->proc(rh->proc_cls, rh, rd_count, rd);
967 * The final phase of resolution.
968 * rh->name is a name that is canonical and we do not have a delegation.
969 * Query namestore for this record
971 * @param rh the pending lookup
974 resolve_record_ns(struct ResolverHandle *rh)
976 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
978 /* We cancel here as to not include the ns lookup in the timeout */
979 if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
981 GNUNET_SCHEDULER_cancel(rh->timeout_task);
982 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
986 * Try to resolve this record in our namestore.
987 * The name to resolve is now in rh->authority_name
988 * since we tried to resolve it to an authority
991 GNUNET_NAMESTORE_lookup_record(namestore_handle,
995 &process_record_result_ns,
1002 * Handle timeout for DHT requests
1004 * @param cls the request handle as closure
1005 * @param tc the task context
1008 dht_authority_lookup_timeout(void *cls,
1009 const struct GNUNET_SCHEDULER_TaskContext *tc)
1011 struct ResolverHandle *rh = cls;
1012 struct RecordLookupHandle *rlh = rh->proc_cls;
1013 char new_name[MAX_DNS_NAME_LENGTH];
1015 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1016 "GNS_PHASE_DELEGATE_DHT: dht lookup for query %s timed out.\n",
1017 rh->authority_name);
1019 rh->status |= TIMED_OUT;
1021 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1023 GNUNET_DHT_get_stop (rh->get_handle);
1024 rh->get_handle = NULL;
1026 if (strcmp(rh->name, "") == 0)
1029 * promote authority back to name and try to resolve record
1031 strcpy(rh->name, rh->authority_name);
1032 rh->proc(rh->proc_cls, rh, 0, NULL);
1037 * Start resolution in bg
1039 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH,
1040 "%s.%s.%s", rh->name, rh->authority_name, GNUNET_GNS_TLD);
1041 //strcpy(new_name, rh->name);
1042 //strcpy(new_name+strlen(new_name), ".");
1043 //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD));
1045 strcpy(rh->name, new_name);
1047 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1048 "GNS_PHASE_DELEGATE_DHT: Starting background query for %s type %d\n",
1049 rh->name, rlh->record_type);
1051 gns_resolver_lookup_record(rh->authority,
1055 GNUNET_TIME_UNIT_FOREVER_REL,
1056 &background_lookup_result_processor,
1059 rh->proc(rh->proc_cls, rh, 0, NULL);
1063 static void resolve_delegation_dht(struct ResolverHandle *rh);
1066 static void resolve_delegation_ns(struct ResolverHandle *rh);
1070 * Namestore resolution for delegation finished. Processing result.
1072 * @param cls the closure
1073 * @param rh resolver handle
1074 * @param rd_count number of results (always 0)
1075 * @param rd record data (always NULL)
1078 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
1079 unsigned int rd_count,
1080 const struct GNUNET_NAMESTORE_RecordData *rd);
1084 * Function called when we get a result from the dht
1085 * for our query. Recursively tries to resolve authorities
1088 * @param cls the request handle
1089 * @param exp lifetime
1090 * @param key the key the record was stored under
1091 * @param get_path get path
1092 * @param get_path_length get path length
1093 * @param put_path put path
1094 * @param put_path_length put path length
1095 * @param type the block type
1096 * @param size the size of the record
1097 * @param data the record data
1100 process_delegation_result_dht(void* cls,
1101 struct GNUNET_TIME_Absolute exp,
1102 const GNUNET_HashCode * key,
1103 const struct GNUNET_PeerIdentity *get_path,
1104 unsigned int get_path_length,
1105 const struct GNUNET_PeerIdentity *put_path,
1106 unsigned int put_path_length,
1107 enum GNUNET_BLOCK_Type type,
1108 size_t size, const void *data)
1110 struct ResolverHandle *rh;
1111 struct GNSNameRecordBlock *nrb;
1112 uint32_t num_records;
1114 char* rd_data = (char*) data;
1117 struct GNUNET_CRYPTO_ShortHashCode zone, name_hash;
1118 GNUNET_HashCode zone_hash_double, name_hash_double;
1120 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1121 "GNS_PHASE_DELEGATE_DHT: Got DHT result\n");
1126 //FIXME check expiration?
1128 rh = (struct ResolverHandle *)cls;
1129 nrb = (struct GNSNameRecordBlock*)data;
1131 /* stop dht lookup and timeout task */
1132 GNUNET_DHT_get_stop (rh->get_handle);
1134 rh->get_handle = NULL;
1136 if (rh->dht_heap_node != NULL)
1138 GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
1139 rh->dht_heap_node = NULL;
1142 num_records = ntohl(nrb->rd_count);
1143 name = (char*)&nrb[1];
1145 struct GNUNET_NAMESTORE_RecordData rd[num_records];
1147 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
1148 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
1150 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
1155 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1156 "GNS_PHASE_DELEGATE_DHT: Error deserializing data!\n");
1160 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1161 "GNS_PHASE_DELEGATE_DHT: Got name: %s (wanted %s)\n",
1162 name, rh->authority_name);
1163 for (i=0; i<num_records; i++)
1166 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1167 "GNS_PHASE_DELEGATE_DHT: Got name: %s (wanted %s)\n",
1168 name, rh->authority_name);
1169 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1170 "GNS_PHASE_DELEGATE_DHT: Got type: %d (wanted %d)\n",
1171 rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
1172 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1173 "GNS_PHASE_DELEGATE_DHT: Got data length: %d\n",
1175 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1176 "GNS_PHASE_DELEGATE_DHT: Got flag %d\n", rd[i].flags);
1178 if ((strcmp(name, rh->authority_name) == 0) &&
1179 (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
1181 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1182 "GNS_PHASE_DELEGATE_DHT: Authority found in DHT\n");
1184 memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1185 struct AuthorityChain *auth =
1186 GNUNET_malloc(sizeof(struct AuthorityChain));
1187 auth->zone = rh->authority;
1188 memset(auth->name, 0, strlen(rh->authority_name)+1);
1189 strcpy(auth->name, rh->authority_name);
1190 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1191 rh->authority_chain_tail,
1194 /** try to import pkey if private key available */
1196 process_discovered_authority(name, auth->zone,
1197 rh->authority_chain_tail->zone,
1204 GNUNET_CRYPTO_short_hash(name, strlen(name), &name_hash);
1205 GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1206 GNUNET_CRYPTO_hash_xor(key, &name_hash_double, &zone_hash_double);
1207 GNUNET_CRYPTO_short_hash_from_truncation (&zone_hash_double, &zone);
1209 /* Save to namestore */
1210 if (0 != GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_tail->zone,
1213 GNUNET_NAMESTORE_record_put (namestore_handle,
1220 &on_namestore_record_put_result, //cont
1230 * FIXME in this case. should we ask namestore again?
1232 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1233 "GNS_PHASE_DELEGATE_DHT: Answer from DHT for %s. Yet to resolve: %s\n",
1234 rh->authority_name, rh->name);
1235 if (strcmp(rh->name, "") == 0)
1237 rh->proc(rh->proc_cls, rh, 0, NULL);
1241 rh->proc = &handle_delegation_ns;
1242 resolve_delegation_ns(rh);
1248 * No pkey but name exists
1251 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1252 "GNS_PHASE_DELEGATE_DHT: Adding %s back to %s\n",
1253 rh->authority_name, rh->name);
1254 if (strcmp(rh->name, "") == 0)
1255 strcpy(rh->name, rh->authority_name);
1257 GNUNET_snprintf(rh->name, MAX_DNS_NAME_LENGTH, "%s.%s",
1258 rh->name, rh->authority_name); //FIXME ret
1260 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1261 "GNS_PHASE_DELEGATE_DHT: %s restored\n", rh->name);
1262 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1263 "GNS_PHASE_DELEGATE_DHT: DHT authority lookup found no match!\n");
1264 rh->proc(rh->proc_cls, rh, 0, NULL);
1267 #define MAX_SOA_LENGTH sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)\
1268 +(MAX_DNS_NAME_LENGTH*2)
1269 #define MAX_MX_LENGTH sizeof(uint16_t)+MAX_DNS_NAME_LENGTH
1273 expand_plus(char** dest, char* src, char* repl)
1276 unsigned int s_len = strlen(src)+1;
1278 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1279 "GNS_POSTPROCESS: Got %s to expand with %s\n", src, repl);
1283 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1284 "GNS_POSTPROCESS: %s to short\n", src);
1286 /* no postprocessing */
1287 memcpy(*dest, src, s_len+1);
1291 if (0 == strcmp(src+s_len-3, ".+"))
1293 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1294 "GNS_POSTPROCESS: Expanding .+ in %s\n", src);
1295 memset(*dest, 0, s_len+strlen(repl)+strlen(GNUNET_GNS_TLD));
1297 pos = *dest+s_len-2;
1299 pos += strlen(repl);
1300 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1301 "GNS_POSTPROCESS: Expanded to %s\n", *dest);
1305 memcpy(*dest, src, s_len+1);
1313 finish_lookup(struct ResolverHandle *rh,
1314 struct RecordLookupHandle* rlh,
1315 unsigned int rd_count,
1316 const struct GNUNET_NAMESTORE_RecordData *rd)
1319 char new_rr_data[MAX_DNS_NAME_LENGTH];
1320 char new_mx_data[MAX_MX_LENGTH];
1321 char new_soa_data[MAX_SOA_LENGTH];
1322 struct GNUNET_NAMESTORE_RecordData p_rd[rd_count];
1325 unsigned int offset;
1327 if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1328 GNUNET_SCHEDULER_cancel(rh->timeout_task);
1331 memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData));
1333 for (i = 0; i < rd_count; i++)
1336 if (rd[i].record_type != GNUNET_GNS_RECORD_TYPE_NS &&
1337 rd[i].record_type != GNUNET_GNS_RECORD_TYPE_CNAME &&
1338 rd[i].record_type != GNUNET_GNS_RECORD_MX &&
1339 rd[i].record_type != GNUNET_GNS_RECORD_TYPE_SOA)
1341 p_rd[i].data = rd[i].data;
1346 * for all those records we 'should'
1347 * also try to resolve the A/AAAA records (RFC1035)
1348 * This is a feature and not important
1351 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1352 "GNS_POSTPROCESS: Postprocessing\n");
1354 if (strcmp(rh->name, "+") == 0)
1355 repl_string = rlh->name;
1357 repl_string = rlh->name+strlen(rh->name)+1;
1360 if (rd[i].record_type == GNUNET_GNS_RECORD_MX)
1362 memcpy(new_mx_data, (char*)rd[i].data, sizeof(uint16_t));
1363 offset = sizeof(uint16_t);
1364 pos = new_mx_data+offset;
1365 expand_plus(&pos, (char*)rd[i].data+sizeof(uint16_t),
1367 offset += strlen(new_mx_data+sizeof(uint16_t))+1;
1368 p_rd[i].data = new_mx_data;
1369 p_rd[i].data_size = offset;
1371 else if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_SOA)
1373 /* expand mname and rname */
1375 expand_plus(&pos, (char*)rd[i].data, repl_string);
1376 offset = strlen(new_soa_data)+1;
1377 pos = new_soa_data+offset;
1378 expand_plus(&pos, (char*)rd[i].data+offset, repl_string);
1379 offset += strlen(new_soa_data+offset)+1;
1380 /* cpy the 4 numbers serial refresh retry and expire */
1381 memcpy(new_soa_data+offset, (char*)rd[i].data+offset, sizeof(uint32_t)*5);
1382 offset += sizeof(uint32_t)*5;
1383 p_rd[i].data_size = offset;
1384 p_rd[i].data = new_soa_data;
1389 expand_plus(&pos, (char*)rd[i].data, repl_string);
1390 p_rd[i].data_size = strlen(new_rr_data)+1;
1391 p_rd[i].data = new_rr_data;
1396 rlh->proc(rlh->proc_cls, rd_count, p_rd);
1402 * Process DHT lookup result for record.
1404 * @param cls the closure
1405 * @param rh resolver handle
1406 * @param rd_count number of results
1407 * @param rd record data
1410 handle_record_dht(void* cls, struct ResolverHandle *rh,
1411 unsigned int rd_count,
1412 const struct GNUNET_NAMESTORE_RecordData *rd)
1414 struct RecordLookupHandle* rlh;
1416 rlh = (struct RecordLookupHandle*)cls;
1419 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1420 "GNS_PHASE_REC: No records for %s found in DHT. Aborting\n",
1422 /* give up, cannot resolve */
1423 finish_lookup(rh, rlh, 0, NULL);
1424 free_resolver_handle(rh);
1428 /* results found yay */
1429 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1430 "GNS_PHASE_REC: Record resolved from DHT!");
1432 finish_lookup(rh, rlh, rd_count, rd);
1433 free_resolver_handle(rh);
1439 * Process namestore lookup result for record.
1441 * @param cls the closure
1442 * @param rh resolver handle
1443 * @param rd_count number of results
1444 * @param rd record data
1447 handle_record_ns(void* cls, struct ResolverHandle *rh,
1448 unsigned int rd_count,
1449 const struct GNUNET_NAMESTORE_RecordData *rd)
1451 struct RecordLookupHandle* rlh;
1452 rlh = (struct RecordLookupHandle*) cls;
1455 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1456 "GNS_PHASE_REC: NS returned no records. (status: %d)!\n",
1460 * There are 4 conditions that have to met for us to consult the DHT:
1461 * 1. The entry in the DHT is EXPIRED AND
1462 * 2. No entry in the NS existed AND
1463 * 3. The zone queried is not the local resolver's zone AND
1464 * 4. The name that was looked up is '+'
1465 * because if it was any other canonical name we either already queried
1466 * the DHT for the authority in the authority lookup phase (and thus
1467 * would already have an entry in the NS for the record)
1469 if (rh->status & (EXPIRED | !EXISTS) &&
1470 GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1472 (strcmp(rh->name, "+") == 0))
1474 rh->proc = &handle_record_dht;
1475 resolve_record_dht(rh);
1478 /* give up, cannot resolve */
1479 finish_lookup(rh, rlh, 0, NULL);
1480 free_resolver_handle(rh);
1484 /* results found yay */
1485 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1486 "GNS_PHASE_REC: Record resolved from namestore!");
1488 finish_lookup(rh, rlh, rd_count, rd);
1490 free_resolver_handle(rh);
1496 * Determine if this name is canonical.
1498 * a.b.gnunet = not canonical
1501 * @param name the name to test
1502 * @return 1 if canonical
1505 is_canonical(char* name)
1507 uint32_t len = strlen(name);
1510 for (i=0; i<len; i++)
1512 if (*(name+i) == '.')
1519 * Move one level up in the domain hierarchy and return the
1520 * passed top level domain.
1522 * @param name the domain
1523 * @param dest the destination where the tld will be put
1526 pop_tld(char* name, char* dest)
1530 if (is_canonical(name))
1537 for (len = strlen(name); len > 0; len--)
1539 if (*(name+len) == '.')
1549 strcpy(dest, (name+len+1));
1553 * Checks if name is in tld
1555 * @param name the name to check
1556 * @param tld the TLD to check for
1557 * @return GNUNET_YES or GNUNET_NO
1560 is_tld(const char* name, const char* tld)
1564 if (strlen(name) <= strlen(tld))
1569 offset = strlen(name)-strlen(tld);
1570 if (strcmp(name+offset, tld) != 0)
1572 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1573 "%s is not in .%s TLD\n", name, tld);
1580 * DHT resolution for delegation finished. Processing result.
1582 * @param cls the closure
1583 * @param rh resolver handle
1584 * @param rd_count number of results (always 0)
1585 * @param rd record data (always NULL)
1588 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
1589 unsigned int rd_count,
1590 const struct GNUNET_NAMESTORE_RecordData *rd)
1592 struct RecordLookupHandle* rlh;
1593 rlh = (struct RecordLookupHandle*) cls;
1596 if (strcmp(rh->name, "") == 0)
1598 if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1600 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1601 "GNS_PHASE_DELEGATE_DHT: Resolved queried PKEY via DHT.\n");
1602 finish_lookup(rh, rlh, rd_count, rd);
1603 free_resolver_handle(rh);
1606 /* We resolved full name for delegation. resolving record */
1607 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1608 "GNS_PHASE_DELEGATE_DHT: Resolved full name for delegation via DHT.\n");
1609 strcpy(rh->name, "+\0");
1610 rh->proc = &handle_record_ns;
1611 resolve_record_ns(rh);
1616 * we still have some left
1618 if (is_canonical(rh->name))
1620 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1621 "GNS_PHASE_DELEGATE_DHT: Resolving canonical record %s in ns\n",
1623 rh->proc = &handle_record_ns;
1624 resolve_record_ns(rh);
1627 /* give up, cannot resolve */
1628 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1629 "GNS_PHASE_DELEGATE_DHT: Cannot fully resolve delegation for %s via DHT!\n",
1631 finish_lookup(rh, rlh, 0, NULL);
1632 free_resolver_handle(rh);
1637 * Start DHT lookup for a name -> PKEY (compare NS) record in
1638 * rh->authority's zone
1640 * @param rh the pending gns query
1643 resolve_delegation_dht(struct ResolverHandle *rh)
1646 struct GNUNET_CRYPTO_ShortHashCode name_hash;
1647 GNUNET_HashCode name_hash_double;
1648 GNUNET_HashCode zone_hash_double;
1649 GNUNET_HashCode lookup_key;
1650 struct ResolverHandle *rh_heap_root;
1652 pop_tld(rh->name, rh->authority_name);
1653 GNUNET_CRYPTO_short_hash(rh->authority_name,
1654 strlen(rh->authority_name),
1656 GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1657 GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
1658 GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
1660 rh->dht_heap_node = NULL;
1662 if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
1664 //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1665 // &dht_authority_lookup_timeout,
1667 rh->timeout_cont = &dht_authority_lookup_timeout;
1668 rh->timeout_cont_cls = rh;
1672 if (max_allowed_background_queries <=
1673 GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
1675 /* terminate oldest lookup */
1676 rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
1677 GNUNET_DHT_get_stop(rh_heap_root->get_handle);
1678 rh_heap_root->dht_heap_node = NULL;
1680 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1681 "GNS_PHASE_DELEGATE_DHT: Replacing oldest background query for %s\n",
1682 rh_heap_root->authority_name);
1684 rh_heap_root->proc(rh_heap_root->proc_cls,
1689 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
1691 GNUNET_TIME_absolute_get().abs_value);
1694 xquery = htonl(GNUNET_GNS_RECORD_PKEY);
1696 GNUNET_assert(rh->get_handle == NULL);
1697 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
1698 GNUNET_TIME_UNIT_FOREVER_REL,
1699 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1701 DHT_GNS_REPLICATION_LEVEL,
1705 &process_delegation_result_dht,
1712 * Namestore resolution for delegation finished. Processing result.
1714 * @param cls the closure
1715 * @param rh resolver handle
1716 * @param rd_count number of results (always 0)
1717 * @param rd record data (always NULL)
1720 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
1721 unsigned int rd_count,
1722 const struct GNUNET_NAMESTORE_RecordData *rd)
1724 struct RecordLookupHandle* rlh;
1725 rlh = (struct RecordLookupHandle*) cls;
1727 if (strcmp(rh->name, "") == 0)
1729 if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1731 GNUNET_assert(rd_count == 1);
1732 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1733 "GNS_PHASE_DELEGATE_NS: Resolved queried PKEY in NS.\n");
1734 finish_lookup(rh, rlh, rd_count, rd);
1735 free_resolver_handle(rh);
1738 /* We resolved full name for delegation. resolving record */
1739 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1740 "GNS_PHASE_DELEGATE_NS: Resolved full name for delegation.\n");
1741 strcpy(rh->name, "+\0");
1742 rh->proc = &handle_record_ns;
1743 resolve_record_ns(rh);
1748 * we still have some left
1749 * check if authority in ns is fresh
1751 * or we are authority
1753 if ((rh->status & (EXISTS | !EXPIRED)) ||
1754 !GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1755 &rh->authority_chain_tail->zone))
1757 if (is_canonical(rh->name))
1759 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1760 "GNS_PHASE_DELEGATE_NS: Resolving canonical record %s\n",
1762 rh->proc = &handle_record_ns;
1763 resolve_record_ns(rh);
1767 /* give up, cannot resolve */
1768 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1769 "GNS_PHASE_DELEGATE_NS: Cannot fully resolve delegation for %s!\n",
1771 finish_lookup(rh, rlh, rd_count, rd);
1772 //rlh->proc(rlh->proc_cls, 0, NULL);
1777 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1778 "GNS_PHASE_DELEGATE_NS: Trying to resolve delegation for %s via DHT\n",
1780 rh->proc = &handle_delegation_dht;
1781 resolve_delegation_dht(rh);
1787 * This is a callback function that should give us only PKEY
1788 * records. Used to query the namestore for the authority (PKEY)
1789 * for 'name'. It will recursively try to resolve the
1790 * authority for a given name from the namestore.
1792 * @param cls the pending query
1793 * @param key the key of the zone we did the lookup
1794 * @param expiration expiration date of the record data set in the namestore
1795 * @param name the name for which we need an authority
1796 * @param rd_count the number of records with 'name'
1797 * @param rd the record data
1798 * @param signature the signature of the authority for the record data
1801 process_delegation_result_ns(void* cls,
1802 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1803 struct GNUNET_TIME_Absolute expiration,
1805 unsigned int rd_count,
1806 const struct GNUNET_NAMESTORE_RecordData *rd,
1807 const struct GNUNET_CRYPTO_RsaSignature *signature)
1809 struct ResolverHandle *rh;
1810 struct GNUNET_TIME_Relative remaining_time;
1811 struct GNUNET_CRYPTO_ShortHashCode zone;
1812 char new_name[MAX_DNS_NAME_LENGTH];
1814 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1815 "GNS_PHASE_DELEGATE_NS: Got %d records from authority lookup\n",
1818 rh = (struct ResolverHandle *)cls;
1819 GNUNET_CRYPTO_short_hash(key,
1820 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1822 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1828 rh->status |= EXISTS;
1831 if (remaining_time.rel_value == 0)
1833 rh->status |= EXPIRED;
1837 * No authority found in namestore.
1842 * We did not find an authority in the namestore
1847 * Promote this authority back to a name maybe it is
1850 if (strcmp(rh->name, "") == 0)
1852 /* simply promote back */
1853 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1854 "GNS_PHASE_DELEGATE_NS: Promoting %s back to name\n",
1855 rh->authority_name);
1856 strcpy(rh->name, rh->authority_name);
1860 /* add back to existing name */
1861 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1862 "GNS_PHASE_DELEGATE_NS: Adding %s back to %s\n",
1863 rh->authority_name, rh->name);
1864 //memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
1865 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
1866 rh->name, rh->authority_name);
1867 //strcpy(new_name, rh->name);
1868 //strcpy(new_name+strlen(new_name), ".");
1869 //strcpy(new_name+strlen(new_name), rh->authority_name);
1870 strcpy(rh->name, new_name);
1871 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1872 "GNS_PHASE_DELEGATE_NS: %s restored\n", rh->name);
1874 rh->proc(rh->proc_cls, rh, 0, NULL);
1879 * We found an authority that may be able to help us
1880 * move on with query
1881 * Note only 1 pkey should have been returned.. anything else would be strange
1884 for (i=0; i<rd_count;i++)
1887 if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
1890 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
1893 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1894 "GNS_PHASE_DELEGATE_NS: This pkey is expired.\n");
1895 if (remaining_time.rel_value == 0)
1897 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1898 "GNS_PHASE_DELEGATE_NS: This dht entry is expired.\n");
1899 rh->authority_chain_head->fresh = 0;
1900 rh->proc(rh->proc_cls, rh, 0, NULL);
1908 * Resolve rest of query with new authority
1910 GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
1911 memcpy(&rh->authority, rd[i].data,
1912 sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1913 struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
1914 auth->zone = rh->authority;
1915 memset(auth->name, 0, strlen(rh->authority_name)+1);
1916 strcpy(auth->name, rh->authority_name);
1917 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1918 rh->authority_chain_tail,
1921 /** try to import pkey if private key available */
1923 process_discovered_authority((char*)name, auth->zone,
1924 rh->authority_chain_tail->zone,
1927 * We are done with PKEY resolution if name is empty
1928 * else resolve again with new authority
1930 if (strcmp(rh->name, "") == 0)
1931 rh->proc(rh->proc_cls, rh, rd_count, rd);
1933 resolve_delegation_ns(rh);
1940 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1941 "GNS_PHASE_DELEGATE_NS: Authority lookup and no PKEY...\n");
1942 rh->proc(rh->proc_cls, rh, 0, NULL);
1947 * Resolve the delegation chain for the request in our namestore
1949 * @param rh the resolver handle
1952 resolve_delegation_ns(struct ResolverHandle *rh)
1954 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1955 "GNS_PHASE_DELEGATE_NS: Resolving delegation for %s\n", rh->name);
1956 pop_tld(rh->name, rh->authority_name);
1957 GNUNET_NAMESTORE_lookup_record(namestore_handle,
1960 GNUNET_GNS_RECORD_PKEY,
1961 &process_delegation_result_ns,
1968 * Lookup of a record in a specific zone
1969 * calls lookup result processor on result
1971 * @param zone the root zone
1972 * @param record_type the record type to look up
1973 * @param name the name to look up
1974 * @param key a private key for use with PSEU import (can be NULL)
1975 * @param timeout timeout for resolution
1976 * @param proc the processor to call on result
1977 * @param cls the closure to pass to proc
1980 gns_resolver_lookup_record(struct GNUNET_CRYPTO_ShortHashCode zone,
1981 uint32_t record_type,
1983 struct GNUNET_CRYPTO_RsaPrivateKey *key,
1984 struct GNUNET_TIME_Relative timeout,
1985 RecordLookupProcessor proc,
1988 struct ResolverHandle *rh;
1989 struct RecordLookupHandle* rlh;
1990 char string_hash[MAX_DNS_LABEL_LENGTH];
1991 uint8_t* normalized_zkey;
1992 char nzkey[MAX_DNS_LABEL_LENGTH];
1995 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1996 "Starting resolution for %s (type=%d)!\n",
2000 if (is_canonical((char*)name) && (strcmp(GNUNET_GNS_TLD, name) != 0))
2002 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2003 "%s is canonical and not gnunet -> cannot resolve!\n", name);
2008 rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
2009 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2011 rh->authority = zone;
2014 rh->timeout = timeout;
2015 rh->get_handle = NULL;
2016 if (timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
2019 * Set timeout for authority lookup phase to 1/2
2021 rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
2022 GNUNET_TIME_relative_divide(timeout, 2),
2023 &handle_lookup_timeout,
2025 rh->timeout_cont = &dht_authority_lookup_timeout;
2026 rh->timeout_cont_cls = rh;
2030 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No timeout for query!\n");
2031 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2034 if (strcmp(GNUNET_GNS_TLD, name) == 0)
2037 * Only 'gnunet' given
2039 strcpy(rh->name, "\0");
2043 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2044 "Checking for TLD...\n");
2045 if (is_zkey_tld(name) == GNUNET_YES)
2047 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2050 * This is a zkey tld
2051 * build hash and use as initial authority
2054 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
2055 memcpy(rh->name, name,
2056 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
2057 pop_tld(rh->name, string_hash);
2059 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2060 "ZKEY is %s!\n", string_hash);
2062 normalized_zkey = u8_toupper ((uint8_t*)string_hash,
2063 strlen ((char *) string_hash),
2064 NULL, UNINORM_NFD, NULL, &normal_len);
2067 memcpy(nzkey, normalized_zkey, normal_len);
2068 nzkey[normal_len] = '\0';
2069 free(normalized_zkey);
2071 if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(nzkey,
2074 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2075 "Cannot convert ZKEY %s to hash!\n", string_hash);
2085 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2088 * Presumably GNUNET tld
2091 strlen(name)-strlen(GNUNET_GNS_TLD));
2092 memcpy(rh->name, name,
2093 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2098 * Initialize authority chain
2100 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2101 rh->authority_chain_head->prev = NULL;
2102 rh->authority_chain_head->next = NULL;
2103 rh->authority_chain_tail = rh->authority_chain_head;
2104 rh->authority_chain_head->zone = rh->authority;
2107 * Copy original query into lookup handle
2109 rlh->record_type = record_type;
2110 memset(rlh->name, 0, strlen(name) + 1);
2111 strcpy(rlh->name, name);
2113 rlh->proc_cls = cls;
2115 rh->proc = &handle_delegation_ns;
2116 resolve_delegation_ns(rh);
2119 /******** END Record Resolver ***********/
2123 * Callback calles by namestore for a zone to name
2126 * @param cls the closure
2127 * @param zone_key the zone we queried
2128 * @param expire the expiration time of the name
2129 * @param name the name found or NULL
2130 * @param rd_len number of records for the name
2131 * @param rd the record data (PKEY) for the name
2132 * @param signature the signature for the record data
2135 process_zone_to_name_shorten(void *cls,
2136 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
2137 struct GNUNET_TIME_Absolute expire,
2139 unsigned int rd_len,
2140 const struct GNUNET_NAMESTORE_RecordData *rd,
2141 const struct GNUNET_CRYPTO_RsaSignature *signature)
2143 struct ResolverHandle *rh = (struct ResolverHandle *)cls;
2144 struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
2145 struct AuthorityChain *next_authority;
2147 char result[MAX_DNS_NAME_LENGTH];
2148 char next_authority_name[MAX_DNS_LABEL_LENGTH];
2151 /* we found a match in our own zone */
2154 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2155 "result strlen %d\n", strlen(name));
2156 answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
2157 memset(result, 0, answer_len);
2158 if (strlen(rh->name) > 0)
2160 strcpy(result, rh->name);
2161 strcpy(result+strlen(rh->name), ".");
2164 strcpy(result+strlen(result), name);
2165 strcpy(result+strlen(result), ".");
2166 strcpy(result+strlen(result), GNUNET_GNS_TLD);
2168 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2169 "Sending shorten result %s\n", result);
2171 nsh->proc(nsh->proc_cls, result);
2173 free_resolver_handle(rh);
2175 else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2178 /* our zone, just append .gnunet */
2179 answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
2180 memset(result, 0, answer_len);
2181 strcpy(result, rh->name);
2182 strcpy(result+strlen(rh->name), ".");
2183 strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
2185 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2186 "Our zone: Sending name as shorten result %s\n", rh->name);
2188 nsh->proc(nsh->proc_cls, result);
2190 free_resolver_handle(rh);
2196 * continue with next authority
2198 next_authority = rh->authority_chain_head;
2199 // strlen(next_authority->name) + 2);
2200 memset(next_authority_name, 0, strlen(rh->name)+
2201 strlen(next_authority->name) + 2);
2202 strcpy(next_authority_name, rh->name);
2203 strcpy(next_authority_name+strlen(rh->name)+1, ".");
2204 strcpy(next_authority_name+strlen(rh->name)+2, next_authority->name);
2206 strcpy(rh->name, next_authority_name);
2207 GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
2208 rh->authority_chain_tail,
2211 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2212 &rh->authority_chain_tail->zone,
2213 &rh->authority_chain_head->zone,
2214 &process_zone_to_name_shorten,
2220 * DHT resolution for delegation finished. Processing result.
2222 * @param cls the closure
2223 * @param rh resolver handle
2224 * @param rd_count number of results (always 0)
2225 * @param rd record data (always NULL)
2228 handle_delegation_dht_bg_shorten(void* cls, struct ResolverHandle *rh,
2229 unsigned int rd_count,
2230 const struct GNUNET_NAMESTORE_RecordData *rd)
2233 /* We resolved full name for delegation. resolving record */
2234 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2235 "GNS_SHORTEN: Resolved up to %s for delegation via DHT in background.\n",
2237 free_resolver_handle(rh);
2241 * Process result from namestore delegation lookup
2242 * for shorten operation
2244 * @param cls the client shorten handle
2245 * @param rh the resolver handle
2246 * @param rd_count number of results (0)
2247 * @param rd data (NULL)
2250 handle_delegation_ns_shorten(void* cls,
2251 struct ResolverHandle *rh,
2253 const struct GNUNET_NAMESTORE_RecordData *rd)
2255 struct NameShortenHandle *nsh;
2256 char result[MAX_DNS_NAME_LENGTH];
2258 struct ResolverHandle *rh_bg;
2260 nsh = (struct NameShortenHandle *)cls;
2263 * At this point rh->name contains the part of the name
2264 * that we do not have a PKEY in our namestore to resolve.
2265 * The authority chain in the resolver handle is now
2266 * useful to backtrack if needed
2269 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2270 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2272 if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2276 * This is our zone append .gnunet unless name is empty
2277 * (it shouldn't be, usually FIXME what happens if we
2278 * shorten to our zone to a "" record??)
2281 answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
2282 memset(result, 0, answer_len);
2283 strcpy(result, rh->name);
2284 strcpy(result+strlen(rh->name), ".");
2285 strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
2287 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2288 "Our zone: Sending name as shorten result %s\n", rh->name);
2290 nsh->proc(nsh->proc_cls, result);
2292 free_resolver_handle(rh);
2297 * we have to this before zone to name for rh might
2301 if (!is_canonical(rh->name))
2303 rh_bg = GNUNET_malloc(sizeof(struct ResolverHandle));
2304 memcpy(rh_bg, rh, sizeof(struct ResolverHandle));
2307 /* backtrack authorities for names */
2308 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2309 &rh->authority_chain_tail->zone, //ours
2310 &rh->authority_chain_head->zone,
2311 &process_zone_to_name_shorten,
2320 * If authority resolution is incomplete we can do a background lookup
2321 * of the full name so that next time we can (likely) fully or at least
2322 * further shorten the name
2324 rh_bg->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2325 rh_bg->authority_chain_tail = rh_bg->authority_chain_head;
2326 rh_bg->authority_chain_head->zone = rh_bg->authority;
2328 rh_bg->proc = &handle_delegation_dht_bg_shorten;
2329 rh_bg->proc_cls = NULL;
2331 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2332 "GNS_SHORTEN: Starting background lookup for %s\n",
2335 resolve_delegation_dht(rh_bg);
2341 * Callback calles by namestore for a zone to name
2344 * @param cls the closure
2345 * @param zone_key the zone we queried
2346 * @param expire the expiration time of the name
2347 * @param name the name found or NULL
2348 * @param rd_len number of records for the name
2349 * @param rd the record data (PKEY) for the name
2350 * @param signature the signature for the record data
2353 process_zone_to_name_zkey(void *cls,
2354 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
2355 struct GNUNET_TIME_Absolute expire,
2357 unsigned int rd_len,
2358 const struct GNUNET_NAMESTORE_RecordData *rd,
2359 const struct GNUNET_CRYPTO_RsaSignature *signature)
2361 struct ResolverHandle *rh = cls;
2362 struct NameShortenHandle *nsh = rh->proc_cls;
2363 struct GNUNET_CRYPTO_ShortHashAsciiEncoded enc;
2364 char new_name[MAX_DNS_NAME_LENGTH];
2366 /* zkey not in our zone */
2370 * In this case we have not given this PKEY a name (yet)
2371 * It is either just not in our zone or not even cached
2372 * Since we do not know at this point we will not try to shorten
2373 * because PKEY import will happen if the user follows the zkey
2376 GNUNET_CRYPTO_short_hash_to_enc ((struct GNUNET_CRYPTO_ShortHashCode*)rd,
2378 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2379 "No name found for zkey %s returning verbatim!\n", enc);
2380 if (strcmp(rh->name, "") != 0)
2381 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s.%s",
2382 rh->name, enc, GNUNET_GNS_TLD_ZKEY);
2384 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
2385 enc, GNUNET_GNS_TLD_ZKEY);
2386 nsh->proc(nsh->proc_cls, new_name);
2388 free_resolver_handle(rh);
2392 if (strcmp(rh->name, "") != 0)
2393 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
2396 strcpy(new_name, name);
2398 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2399 "Continue shorten for %s!\n", new_name);
2401 strcpy(rh->name, new_name);
2403 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2404 rh->authority_chain_tail = rh->authority_chain_head;
2405 rh->authority_chain_head->zone = rh->authority;
2408 /* Start delegation resolution in our namestore */
2409 resolve_delegation_ns(rh);
2413 * Shorten api from resolver
2415 * @param zone the zone to use
2416 * @param name the name to shorten
2417 * @param key optional private key for background lookups and PSEU import
2418 * @param proc the processor to call with result
2419 * @param proc_cls closure to pass to proc
2422 gns_resolver_shorten_name(struct GNUNET_CRYPTO_ShortHashCode zone,
2424 struct GNUNET_CRYPTO_RsaPrivateKey *key,
2425 ShortenResultProcessor proc,
2428 struct ResolverHandle *rh;
2429 struct NameShortenHandle *nsh;
2430 char string_hash[MAX_DNS_LABEL_LENGTH];
2431 struct GNUNET_CRYPTO_ShortHashCode zkey;
2432 uint8_t* normalized_zkey;
2434 char nzkey[MAX_DNS_LABEL_LENGTH];
2437 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2438 "Starting shorten for %s!\n", name);
2440 if (is_canonical((char*)name))
2442 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2443 "%s is canonical. Returning verbatim\n", name);
2444 proc(proc_cls, name);
2448 nsh = GNUNET_malloc(sizeof (struct NameShortenHandle));
2451 nsh->proc_cls = proc_cls;
2453 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2454 rh->authority = zone;
2456 rh->proc = &handle_delegation_ns_shorten;
2459 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2460 "Checking for TLD...\n");
2461 if (is_zkey_tld(name) == GNUNET_YES)
2463 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2466 * This is a zkey tld
2467 * build hash and use as initial authority
2471 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
2472 memcpy(rh->name, name,
2473 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
2474 pop_tld(rh->name, string_hash);
2476 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2477 "ZKEY is %s!\n", string_hash);
2479 normalized_zkey = u8_toupper ((uint8_t*)string_hash, strlen ((char *) string_hash),
2480 NULL, UNINORM_NFD, NULL, &normal_len);
2482 memcpy(nzkey, normalized_zkey, normal_len);
2483 nzkey[normal_len] = '\0';
2484 free(normalized_zkey);
2486 if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(nzkey,
2489 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2490 "Cannot convert ZKEY %s to hash!\n", nzkey);
2493 proc(proc_cls, name);
2497 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2500 &process_zone_to_name_zkey,
2507 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2510 * Presumably GNUNET tld
2513 strlen(name)-strlen(GNUNET_GNS_TLD));
2514 memcpy(rh->name, name,
2515 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2518 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2519 rh->authority_chain_tail = rh->authority_chain_head;
2520 rh->authority_chain_head->zone = zone;
2523 /* Start delegation resolution in our namestore */
2524 resolve_delegation_ns(rh);
2527 /*********** END NAME SHORTEN ********************/
2531 * Process result from namestore delegation lookup
2532 * for get authority operation
2534 * @param cls the client get auth handle
2535 * @param rh the resolver handle
2536 * @param rd_count number of results (0)
2537 * @param rd data (NULL)
2540 handle_delegation_result_ns_get_auth(void* cls,
2541 struct ResolverHandle *rh,
2543 const struct GNUNET_NAMESTORE_RecordData *rd)
2545 struct GetNameAuthorityHandle* nah;
2546 char result[MAX_DNS_NAME_LENGTH];
2549 nah = (struct GetNameAuthorityHandle*) rh->proc_cls;
2552 * At this point rh->name contains the part of the name
2553 * that we do not have a PKEY in our namestore to resolve.
2554 * The authority chain in the resolver handle is now
2555 * useful to backtrack if needed
2558 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2559 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2561 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2562 "Building response!\n");
2563 if (is_canonical(rh->name))
2566 * We successfully resolved the authority in the ns
2567 * FIXME for our purposes this is fine
2568 * but maybe we want to have an api that also looks
2569 * into the dht (i.e. option in message)
2571 if (strlen(rh->name) > strlen(nah->name))
2573 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2574 "Record name longer than original lookup name... odd!\n");
2578 answer_len = strlen(nah->name) - strlen(rh->name)
2579 + strlen(GNUNET_GNS_TLD) + 1;
2580 memset(result, 0, answer_len);
2581 strcpy(result, nah->name + strlen(rh->name) + 1);
2583 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2584 "Got authority result %s\n", result);
2586 nah->proc(nah->proc_cls, result);
2588 free_resolver_handle(rh);
2592 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2593 "Unable to resolve authority for remaining %s!\n", rh->name);
2594 nah->proc(nah->proc_cls, "");
2596 free_resolver_handle(rh);
2604 * Tries to resolve the authority for name
2607 * @param zone the root zone to look up for
2608 * @param name the name to lookup up
2609 * @param proc the processor to call when finished
2610 * @param proc_cls the closure to pass to the processor
2613 gns_resolver_get_authority(struct GNUNET_CRYPTO_ShortHashCode zone,
2615 GetAuthorityResultProcessor proc,
2618 struct ResolverHandle *rh;
2619 struct GetNameAuthorityHandle *nah;
2621 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2622 "Starting authority resolution for %s!\n", name);
2624 nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
2625 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2626 rh->authority = zone;
2628 if (strcmp(GNUNET_GNS_TLD, name) == 0)
2630 strcpy(rh->name, "\0");
2635 strlen(name)-strlen(GNUNET_GNS_TLD));
2636 memcpy(rh->name, name,
2637 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2640 memset(nah->name, 0,
2642 strcpy(nah->name, name);
2644 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2645 rh->authority_chain_tail = rh->authority_chain_head;
2646 rh->authority_chain_head->zone = zone;
2647 rh->proc = &handle_delegation_result_ns_get_auth;
2648 rh->proc_cls = (void*)nah;
2651 nah->proc_cls = proc_cls;
2653 /* Start delegation resolution in our namestore */
2654 resolve_delegation_ns(rh);
2658 /******** END GET AUTHORITY *************/
2660 /* end of gnunet-service-gns_resolver.c */