2 This file is part of GNUnet.
3 (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
24 * @file gns/gnunet-service-gns_resolver.c
25 * @brief GNUnet GNS resolver logic
26 * @author Martin Schanzenbach
29 #include "gnunet_util_lib.h"
30 #include "gnunet_transport_service.h"
31 #include "gnunet_dns_service.h"
32 #include "gnunet_dht_service.h"
33 #include "gnunet_namestore_service.h"
34 #include "gnunet_dns_service.h"
35 #include "gnunet_dnsparser_lib.h"
36 #include "gnunet_gns_service.h"
37 #include "block_gns.h"
39 #include "gnunet-service-gns_resolver.h"
41 #define DHT_OPERATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)
42 #define DHT_LOOKUP_TIMEOUT DHT_OPERATION_TIMEOUT
43 #define DHT_GNS_REPLICATION_LEVEL 5
44 #define MAX_DNS_LABEL_LENGTH 63
48 * Our handle to the namestore service
50 static struct GNUNET_NAMESTORE_Handle *namestore_handle;
53 * Resolver handle to the dht
55 static struct GNUNET_DHT_Handle *dht_handle;
58 * Heap for parallel DHT lookups
60 static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
63 * Maximum amount of parallel queries in background
65 static unsigned long long max_allowed_background_queries;
70 static struct GNUNET_CRYPTO_ShortHashCode local_zone;
73 * Namestore calls this function if we have record for this name.
74 * (or with rd_count=0 to indicate no matches)
76 * @param cls the pending query
77 * @param key the key of the zone we did the lookup
78 * @param expiration expiration date of the namestore entry
79 * @param name the name for which we need an authority
80 * @param rd_count the number of records with 'name'
81 * @param rd the record data
82 * @param signature the signature of the authority for the record data
85 process_pseu_lookup_ns(void* cls,
86 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
87 struct GNUNET_TIME_Absolute expiration,
88 const char *name, unsigned int rd_count,
89 const struct GNUNET_NAMESTORE_RecordData *rd,
90 const struct GNUNET_CRYPTO_RsaSignature *signature)
92 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
93 struct GNUNET_NAMESTORE_RecordData new_pkey;
97 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
98 "Name %s already taken in NS!\n", name);
99 if (0 == strcmp(gph->name, name))
101 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
102 "Intelligent replacement not implemented\n", name);
107 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
108 "Trying delegated name %s\n", gph->name);
109 memcpy(gph->new_name, gph->name, strlen(gph->name)+1);
110 GNUNET_NAMESTORE_lookup_record(namestore_handle,
113 GNUNET_GNS_RECORD_PSEU,
114 &process_pseu_lookup_ns,
120 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
121 "Name %s not taken in NS! Adding\n", gph->new_name);
123 new_pkey.expiration = GNUNET_TIME_absolute_get_forever ();
124 new_pkey.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode);
125 new_pkey.data = &gph->new_zone;
126 new_pkey.record_type = GNUNET_GNS_RECORD_PKEY;
127 GNUNET_NAMESTORE_record_create (namestore_handle,
138 * process result of a dht pseu lookup
140 * @param gph the handle
141 * @param name the pseu result or NULL
144 process_pseu_result(struct GetPseuAuthorityHandle* gph, char* name)
148 memcpy(gph->new_name, name, strlen(gph->name)+1);
152 memcpy(gph->new_name, name, strlen(name)+1);
155 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
156 "Checking %s for collision in NS\n", gph->new_name);
159 * Check for collision
161 GNUNET_NAMESTORE_lookup_record(namestore_handle,
164 GNUNET_GNS_RECORD_PSEU,
165 &process_pseu_lookup_ns,
170 * Handle timeout for dht request
172 * @param cls the request handle as closure
173 * @param tc the task context
176 handle_auth_discovery_timeout(void *cls,
177 const struct GNUNET_SCHEDULER_TaskContext *tc)
179 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
181 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
182 "dht lookup for query PSEU timed out.\n");
183 GNUNET_DHT_get_stop (gph->get_handle);
184 process_pseu_result(gph, NULL);
188 * Function called when we find a PSEU entry in the DHT
190 * @param cls the request handle
191 * @param exp lifetime
192 * @param key the key the record was stored under
193 * @param get_path get path
194 * @param get_path_length get path length
195 * @param put_path put path
196 * @param put_path_length put path length
197 * @param type the block type
198 * @param size the size of the record
199 * @param data the record data
202 process_auth_discovery_dht_result(void* cls,
203 struct GNUNET_TIME_Absolute exp,
204 const GNUNET_HashCode * key,
205 const struct GNUNET_PeerIdentity *get_path,
206 unsigned int get_path_length,
207 const struct GNUNET_PeerIdentity *put_path,
208 unsigned int put_path_length,
209 enum GNUNET_BLOCK_Type type,
210 size_t size, const void *data)
212 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
213 struct GNSNameRecordBlock *nrb;
214 char* rd_data = (char*)data;
220 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "got dht result (size=%d)\n", size);
224 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "got dht result null!\n", size);
230 nrb = (struct GNSNameRecordBlock*)data;
232 /* stop lookup and timeout task */
233 GNUNET_DHT_get_stop (gph->get_handle);
234 GNUNET_SCHEDULER_cancel(gph->timeout);
236 gph->get_handle = NULL;
238 nrb = (struct GNSNameRecordBlock*)data;
240 name = (char*)&nrb[1];
241 num_records = ntohl(nrb->rd_count);
243 struct GNUNET_NAMESTORE_RecordData rd[num_records];
245 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
246 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
248 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
253 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
259 for (i=0; i<num_records; i++)
261 if ((strcmp(name, "+") == 0) &&
262 (rd[i].record_type == GNUNET_GNS_RECORD_PSEU))
265 process_pseu_result(gph, (char*)rd[i].data);
271 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "no pseu in dht!\n");
272 process_pseu_result(gph, NULL);
276 * Callback called by namestore for a zone to name
279 * @param cls the closure
280 * @param zone_key the zone we queried
281 * @param expire the expiration time of the name
282 * @param name the name found or NULL
283 * @param rd_len number of records for the name
284 * @param rd the record data (PKEY) for the name
285 * @param signature the signature for the record data
288 process_zone_to_name_discover(void *cls,
289 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
290 struct GNUNET_TIME_Absolute expire,
293 const struct GNUNET_NAMESTORE_RecordData *rd,
294 const struct GNUNET_CRYPTO_RsaSignature *signature)
296 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
298 /* we found a match in our own zone */
301 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
302 "name for zone in our root %d\n", strlen(name));
312 struct GNUNET_CRYPTO_ShortHashCode name_hash;
313 GNUNET_HashCode lookup_key;
314 struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
315 GNUNET_HashCode name_hash_double;
316 GNUNET_HashCode zone_hash_double;
318 GNUNET_CRYPTO_short_hash("+", strlen("+"), &name_hash);
319 GNUNET_CRYPTO_short_hash_double (&name_hash, &name_hash_double);
320 GNUNET_CRYPTO_short_hash_double (&gph->new_zone, &zone_hash_double);
321 GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
322 GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
324 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
325 "starting dht lookup for %s with key: %s\n",
326 "+", (char*)&lookup_key_string);
328 //gph->timeout = GNUNET_SCHEDULER_add_delayed(DHT_LOOKUP_TIMEOUT,
329 // &handle_auth_discovery_timeout, gph);
331 xquery = htonl(GNUNET_GNS_RECORD_PSEU);
333 gph->get_handle = GNUNET_DHT_get_start(dht_handle,
334 GNUNET_TIME_UNIT_FOREVER_REL,
335 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
337 DHT_GNS_REPLICATION_LEVEL,
341 &process_auth_discovery_dht_result,
349 * Callback for new authories
351 * @param name the name given by delegation
352 * @param zone the authority
353 * @param the private key of our authority
355 static void process_discovered_authority(char* name,
356 struct GNUNET_CRYPTO_ShortHashCode zone,
357 struct GNUNET_CRYPTO_ShortHashCode our_zone,
358 struct GNUNET_CRYPTO_RsaPrivateKey *key)
360 struct GetPseuAuthorityHandle *gph;
363 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "New authority %s discovered\n",
366 gph = GNUNET_malloc(sizeof(struct GetPseuAuthorityHandle));
367 namelen = strlen(name) + 1;
368 memcpy(gph->name, name, namelen);
370 gph->new_zone = zone;
371 gph->zone = our_zone;
374 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
377 &process_zone_to_name_discover,
383 * Initialize the resolver
385 * @param nh the namestore handle
386 * @param dh the dht handle
387 * @return GNUNET_OK on success
390 gns_resolver_init(struct GNUNET_NAMESTORE_Handle *nh,
391 struct GNUNET_DHT_Handle *dh,
392 struct GNUNET_CRYPTO_ShortHashCode lz,
393 unsigned long long max_bg_queries)
395 namestore_handle = nh;
399 GNUNET_CONTAINER_heap_create(GNUNET_CONTAINER_HEAP_ORDER_MIN);
400 max_allowed_background_queries = max_bg_queries;
402 if ((namestore_handle != NULL) && (dht_handle != NULL))
406 return GNUNET_SYSERR;
410 * Cleanup background lookups
413 cleanup_pending_background_queries(void* cls,
414 struct GNUNET_CONTAINER_HeapNode *node,
416 GNUNET_CONTAINER_HeapCostType cost)
418 struct ResolverHandle *rh = (struct ResolverHandle *)element;
420 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
421 "Terminating background lookup for %s\n",
423 GNUNET_DHT_get_stop(rh->get_handle);
424 rh->proc(rh->proc_cls, rh, 0, NULL);
434 gns_resolver_cleanup()
436 if (0 != GNUNET_CONTAINER_heap_get_size(dht_lookup_heap))
438 GNUNET_CONTAINER_heap_iterate (dht_lookup_heap,
439 &cleanup_pending_background_queries,
446 * Helper function to free resolver handle
448 * @rh the handle to free
451 free_resolver_handle(struct ResolverHandle* rh)
453 struct AuthorityChain *ac;
454 struct AuthorityChain *ac_next;
459 ac = rh->authority_chain_head;
472 * Callback when record data is put into namestore
474 * @param cls the closure
475 * @param success GNUNET_OK on success
476 * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
479 on_namestore_record_put_result(void *cls,
483 if (GNUNET_NO == success)
485 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "records already in namestore\n");
488 else if (GNUNET_YES == success)
490 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
491 "records successfully put in namestore\n");
495 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
496 "Error putting records into namestore: %s\n", emsg);
500 handle_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
502 struct ResolverHandle *rh = cls;
504 if (rh->timeout_cont)
505 rh->timeout_cont(rh->timeout_cont_cls, tc);
509 * Processor for background lookups in the DHT
511 * @param cls closure (NULL)
512 * @param rd_count number of records found (not 0)
513 * @param rd record data
516 background_lookup_result_processor(void *cls,
518 const struct GNUNET_NAMESTORE_RecordData *rd)
520 //We could do sth verbose/more useful here but it doesn't make any difference
521 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
522 "background dht lookup finished.\n");
526 * Handle timeout for DHT requests
528 * @param cls the request handle as closure
529 * @param tc the task context
532 dht_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
534 struct ResolverHandle *rh = cls;
535 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
536 char new_name[MAX_DNS_NAME_LENGTH];
538 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
539 "dht lookup for query %s timed out.\n",
542 * Start resolution in bg
544 strcpy(new_name, rh->name);
545 memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD));
547 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
548 "Starting background lookup for %s type %d\n",
549 new_name, rlh->record_type);
551 gns_resolver_lookup_record(rh->authority,
555 GNUNET_TIME_UNIT_FOREVER_REL,
556 &background_lookup_result_processor,
559 GNUNET_DHT_get_stop (rh->get_handle);
560 rh->proc(rh->proc_cls, rh, 0, NULL);
565 * Function called when we get a result from the dht
566 * for our record query
568 * @param cls the request handle
569 * @param exp lifetime
570 * @param key the key the record was stored under
571 * @param get_path get path
572 * @param get_path_length get path length
573 * @param put_path put path
574 * @param put_path_length put path length
575 * @param type the block type
576 * @param size the size of the record
577 * @param data the record data
580 process_record_result_dht(void* cls,
581 struct GNUNET_TIME_Absolute exp,
582 const GNUNET_HashCode * key,
583 const struct GNUNET_PeerIdentity *get_path,
584 unsigned int get_path_length,
585 const struct GNUNET_PeerIdentity *put_path,
586 unsigned int put_path_length,
587 enum GNUNET_BLOCK_Type type,
588 size_t size, const void *data)
590 struct ResolverHandle *rh;
591 struct RecordLookupHandle *rlh;
592 struct GNSNameRecordBlock *nrb;
593 uint32_t num_records;
595 char* rd_data = (char*)data;
599 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "got dht result (size=%d)\n", size);
604 //FIXME maybe check expiration here, check block type
606 rh = (struct ResolverHandle *)cls;
607 rlh = (struct RecordLookupHandle *) rh->proc_cls;
608 nrb = (struct GNSNameRecordBlock*)data;
610 /* stop lookup and timeout task */
611 GNUNET_DHT_get_stop (rh->get_handle);
613 if (rh->dht_heap_node != NULL)
615 GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
616 rh->dht_heap_node = NULL;
619 if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
620 GNUNET_SCHEDULER_cancel(rh->timeout_task);
622 rh->get_handle = NULL;
623 name = (char*)&nrb[1];
624 num_records = ntohl(nrb->rd_count);
626 struct GNUNET_NAMESTORE_RecordData rd[num_records];
628 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
629 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
631 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
636 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
640 for (i=0; i<num_records; i++)
642 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
643 "Got name: %s (wanted %s)\n", name, rh->name);
644 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
647 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
648 "Got data length: %d\n", rd[i].data_size);
649 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
650 "Got flag %d\n", rd[i].flags);
652 if ((strcmp(name, rh->name) == 0) &&
653 (rd[i].record_type == rlh->record_type))
661 * FIXME check pubkey against existing key in namestore?
662 * https://gnunet.org/bugs/view.php?id=2179
665 /* Save to namestore */
666 GNUNET_NAMESTORE_record_put (namestore_handle,
673 &on_namestore_record_put_result, //cont
678 rh->proc(rh->proc_cls, rh, num_records, rd);
680 rh->proc(rh->proc_cls, rh, 0, NULL);
687 * Start DHT lookup for a (name -> query->record_type) record in
688 * rh->authority's zone
690 * @param rh the pending gns query context
693 resolve_record_dht(struct ResolverHandle *rh)
696 struct GNUNET_CRYPTO_ShortHashCode name_hash;
697 GNUNET_HashCode lookup_key;
698 GNUNET_HashCode name_hash_double;
699 GNUNET_HashCode zone_hash_double;
700 struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
701 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
702 struct ResolverHandle *rh_heap_root;
704 GNUNET_CRYPTO_short_hash(rh->name, strlen(rh->name), &name_hash);
705 GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
706 GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
707 GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
708 GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
710 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
711 "starting dht lookup for %s with key: %s\n",
712 rh->name, (char*)&lookup_key_string);
714 //rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
715 rh->dht_heap_node = NULL;
717 if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
720 * Update timeout if necessary
722 if (rh->timeout_task == GNUNET_SCHEDULER_NO_TASK)
725 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
726 "Adjusting timeout\n");
728 * Set timeout for authority lookup phase to 1/2
730 rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
731 GNUNET_TIME_relative_divide(rh->timeout, 2),
732 &handle_lookup_timeout,
735 //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
736 // &dht_lookup_timeout,
738 rh->timeout_cont = &dht_lookup_timeout;
739 rh->timeout_cont_cls = rh;
743 if (max_allowed_background_queries <=
744 GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
746 rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
747 GNUNET_DHT_get_stop(rh_heap_root->get_handle);
748 rh_heap_root->dht_heap_node = NULL;
749 rh_heap_root->proc(rh_heap_root->proc_cls,
754 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
756 GNUNET_TIME_absolute_get().abs_value);
759 xquery = htonl(rlh->record_type);
760 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
761 GNUNET_TIME_UNIT_FOREVER_REL,
762 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
764 DHT_GNS_REPLICATION_LEVEL,
768 &process_record_result_dht,
775 * Namestore calls this function if we have record for this name.
776 * (or with rd_count=0 to indicate no matches)
778 * @param cls the pending query
779 * @param key the key of the zone we did the lookup
780 * @param expiration expiration date of the namestore entry
781 * @param name the name for which we need an authority
782 * @param rd_count the number of records with 'name'
783 * @param rd the record data
784 * @param signature the signature of the authority for the record data
787 process_record_result_ns(void* cls,
788 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
789 struct GNUNET_TIME_Absolute expiration,
790 const char *name, unsigned int rd_count,
791 const struct GNUNET_NAMESTORE_RecordData *rd,
792 const struct GNUNET_CRYPTO_RsaSignature *signature)
794 struct ResolverHandle *rh;
795 struct RecordLookupHandle *rlh;
796 struct GNUNET_TIME_Relative remaining_time;
797 struct GNUNET_CRYPTO_ShortHashCode zone;
799 rh = (struct ResolverHandle *) cls;
800 rlh = (struct RecordLookupHandle *)rh->proc_cls;
801 GNUNET_CRYPTO_short_hash(key,
802 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
804 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
806 if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
807 GNUNET_SCHEDULER_cancel(rh->timeout_task);
813 rh->status |= EXISTS;
816 if (remaining_time.rel_value == 0)
818 rh->status |= EXPIRED;
824 * Lookup terminated and no results
826 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
827 "Namestore lookup for %s terminated without results\n", name);
829 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
830 "Record %s unknown in namestore\n",
833 * Our zone and no result? Cannot resolve TT
835 rh->proc(rh->proc_cls, rh, 0, NULL);
842 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
843 "Processing additional result %s from namestore\n", name);
845 for (i=0; i<rd_count;i++)
848 if (rd[i].record_type != rlh->record_type)
851 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
854 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
855 "This record is expired. Skipping\n");
866 if (rh->answered == 0)
868 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
869 "No answers found. This is odd!\n");
870 rh->proc(rh->proc_cls, rh, 0, NULL);
874 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Found %d answer(s) to query!\n",
877 rh->proc(rh->proc_cls, rh, rd_count, rd);
883 * The final phase of resolution.
884 * rh->name is a name that is canonical and we do not have a delegation.
885 * Query namestore for this record
887 * @param rh the pending lookup
890 resolve_record_ns(struct ResolverHandle *rh)
892 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
895 * Try to resolve this record in our namestore.
896 * The name to resolve is now in rh->authority_name
897 * since we tried to resolve it to an authority
900 GNUNET_NAMESTORE_lookup_record(namestore_handle,
904 &process_record_result_ns,
911 * Handle timeout for DHT requests
913 * @param cls the request handle as closure
914 * @param tc the task context
917 dht_authority_lookup_timeout(void *cls,
918 const struct GNUNET_SCHEDULER_TaskContext *tc)
920 struct ResolverHandle *rh = cls;
921 struct RecordLookupHandle *rlh = rh->proc_cls;
922 char new_name[MAX_DNS_NAME_LENGTH];
924 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
925 "dht lookup for query %s timed out.\n",
928 rh->status |= TIMED_OUT;
931 if (strcmp(rh->name, "") == 0)
934 * promote authority back to name and try to resolve record
936 strcpy(rh->name, rh->authority_name);
937 rh->proc(rh->proc_cls, rh, 0, NULL);
942 * Start resolution in bg
944 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH,
945 "%s.%s", rh->name, GNUNET_GNS_TLD);
946 //strcpy(new_name, rh->name);
947 //strcpy(new_name+strlen(new_name), ".");
948 //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD));
950 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
951 "Starting background query for %s type %d\n",
952 new_name, rlh->record_type);
954 gns_resolver_lookup_record(rh->authority,
958 GNUNET_TIME_UNIT_FOREVER_REL,
959 &background_lookup_result_processor,
962 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
963 "Terminating auth lookup\n");
965 GNUNET_DHT_get_stop (rh->get_handle);
967 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
969 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
970 "Terminating auth lookup\n");
972 rh->proc(rh->proc_cls, rh, 0, NULL);
976 static void resolve_delegation_dht(struct ResolverHandle *rh);
979 * Function called when we get a result from the dht
980 * for our query. Recursively tries to resolve authorities
983 * @param cls the request handle
984 * @param exp lifetime
985 * @param key the key the record was stored under
986 * @param get_path get path
987 * @param get_path_length get path length
988 * @param put_path put path
989 * @param put_path_length put path length
990 * @param type the block type
991 * @param size the size of the record
992 * @param data the record data
995 process_delegation_result_dht(void* cls,
996 struct GNUNET_TIME_Absolute exp,
997 const GNUNET_HashCode * key,
998 const struct GNUNET_PeerIdentity *get_path,
999 unsigned int get_path_length,
1000 const struct GNUNET_PeerIdentity *put_path,
1001 unsigned int put_path_length,
1002 enum GNUNET_BLOCK_Type type,
1003 size_t size, const void *data)
1005 struct ResolverHandle *rh;
1006 struct GNSNameRecordBlock *nrb;
1007 uint32_t num_records;
1009 char* rd_data = (char*) data;
1012 struct GNUNET_CRYPTO_ShortHashCode zone, name_hash;
1013 GNUNET_HashCode zone_hash_double, name_hash_double;
1015 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got DHT result\n");
1020 //FIXME check expiration?
1022 rh = (struct ResolverHandle *)cls;
1023 nrb = (struct GNSNameRecordBlock*)data;
1025 /* stop dht lookup and timeout task */
1026 GNUNET_DHT_get_stop (rh->get_handle);
1028 rh->get_handle = NULL;
1030 if (rh->dht_heap_node != NULL)
1032 GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
1033 rh->dht_heap_node = NULL;
1036 num_records = ntohl(nrb->rd_count);
1037 name = (char*)&nrb[1];
1039 struct GNUNET_NAMESTORE_RecordData rd[num_records];
1041 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
1042 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
1044 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
1049 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
1053 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1054 "Got name: %s (wanted %s)\n", name, rh->authority_name);
1055 for (i=0; i<num_records; i++)
1058 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1059 "Got name: %s (wanted %s)\n", name, rh->authority_name);
1060 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1061 "Got type: %d (wanted %d)\n",
1062 rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
1063 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1064 "Got data length: %d\n", rd[i].data_size);
1065 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1066 "Got flag %d\n", rd[i].flags);
1068 if ((strcmp(name, rh->authority_name) == 0) &&
1069 (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
1071 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Authority found in DHT\n");
1073 memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1074 struct AuthorityChain *auth =
1075 GNUNET_malloc(sizeof(struct AuthorityChain));
1076 auth->zone = rh->authority;
1077 memset(auth->name, 0, strlen(rh->authority_name)+1);
1078 strcpy(auth->name, rh->authority_name);
1079 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1080 rh->authority_chain_tail,
1083 /** try to import pkey if private key available */
1085 process_discovered_authority(name, auth->zone,
1086 rh->authority_chain_tail->zone,
1093 GNUNET_CRYPTO_short_hash(name, strlen(name), &name_hash);
1094 GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1095 GNUNET_CRYPTO_hash_xor(key, &name_hash_double, &zone_hash_double);
1096 GNUNET_CRYPTO_short_hash_from_truncation (&zone_hash_double, &zone);
1098 /* Save to namestore */
1099 if (0 != GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_tail->zone,
1102 GNUNET_NAMESTORE_record_put (namestore_handle,
1109 &on_namestore_record_put_result, //cont
1119 * FIXME in this case. should we ask namestore again?
1121 if (strcmp(rh->name, "") == 0)
1122 rh->proc(rh->proc_cls, rh, 0, NULL);
1124 resolve_delegation_dht(rh);
1129 * No pkey but name exists
1131 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "DHT authority lookup found no match!\n");
1132 rh->proc(rh->proc_cls, rh, 0, NULL);
1135 #define MAX_SOA_LENGTH sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)\
1136 +(MAX_DNS_NAME_LENGTH*2)
1137 #define MAX_MX_LENGTH sizeof(uint16_t)+MAX_DNS_NAME_LENGTH
1141 expand_plus(char** dest, char* src, char* repl)
1144 unsigned int s_len = strlen(src)+1;
1146 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1147 "Got %s to expand with %s\n", src, repl);
1151 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1152 "%s to short\n", src);
1154 /* no postprocessing */
1155 memcpy(*dest, src, s_len+1);
1159 if (0 == strcmp(src+s_len-3, ".+"))
1161 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1162 "Expanding .+ in %s\n", src);
1163 memset(*dest, 0, s_len+strlen(repl)+strlen(GNUNET_GNS_TLD));
1165 pos = *dest+s_len-2;
1167 pos += strlen(repl);
1168 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1169 "Expanded to %s\n", *dest);
1173 memcpy(*dest, src, s_len+1);
1181 finish_lookup(struct ResolverHandle *rh,
1182 struct RecordLookupHandle* rlh,
1183 unsigned int rd_count,
1184 const struct GNUNET_NAMESTORE_RecordData *rd)
1187 char new_rr_data[MAX_DNS_NAME_LENGTH];
1188 char new_mx_data[MAX_MX_LENGTH];
1189 char new_soa_data[MAX_SOA_LENGTH];
1190 struct GNUNET_NAMESTORE_RecordData p_rd[rd_count];
1193 unsigned int offset;
1196 memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData));
1198 for (i = 0; i < rd_count; i++)
1201 if (rd[i].record_type != GNUNET_GNS_RECORD_TYPE_NS &&
1202 rd[i].record_type != GNUNET_GNS_RECORD_TYPE_CNAME &&
1203 rd[i].record_type != GNUNET_GNS_RECORD_MX &&
1204 rd[i].record_type != GNUNET_GNS_RECORD_TYPE_SOA)
1206 p_rd[i].data = rd[i].data;
1211 * for all those records we 'should'
1212 * also try to resolve the A/AAAA records (RFC1035)
1213 * This is a feature and not important
1216 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1217 "Postprocessing\n");
1219 if (strcmp(rh->name, "+") == 0)
1220 repl_string = rlh->name;
1222 repl_string = rlh->name+strlen(rh->name)+1;
1225 if (rd[i].record_type == GNUNET_GNS_RECORD_MX)
1227 memcpy(new_mx_data, (char*)rd[i].data, sizeof(uint16_t));
1228 offset = sizeof(uint16_t);
1229 pos = new_mx_data+offset;
1230 expand_plus(&pos, (char*)rd[i].data+sizeof(uint16_t),
1232 offset += strlen(new_mx_data+sizeof(uint16_t))+1;
1233 p_rd[i].data = new_mx_data;
1234 p_rd[i].data_size = offset;
1236 else if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_SOA)
1238 /* expand mname and rname */
1240 expand_plus(&pos, (char*)rd[i].data, repl_string);
1241 offset = strlen(new_soa_data)+1;
1242 pos = new_soa_data+offset;
1243 expand_plus(&pos, (char*)rd[i].data+offset, repl_string);
1244 offset += strlen(new_soa_data+offset)+1;
1245 /* cpy the 4 numbers serial refresh retry and expire */
1246 memcpy(new_soa_data+offset, (char*)rd[i].data+offset, sizeof(uint32_t)*4);
1247 offset += sizeof(uint32_t)*4;
1248 p_rd[i].data_size = offset;
1249 p_rd[i].data = new_soa_data;
1254 expand_plus(&pos, (char*)rd[i].data, repl_string);
1255 p_rd[i].data_size = strlen(new_rr_data)+1;
1256 p_rd[i].data = new_rr_data;
1261 rlh->proc(rlh->proc_cls, rd_count, p_rd);
1267 * Process DHT lookup result for record.
1269 * @param cls the closure
1270 * @param rh resolver handle
1271 * @param rd_count number of results
1272 * @param rd record data
1275 handle_record_dht(void* cls, struct ResolverHandle *rh,
1276 unsigned int rd_count,
1277 const struct GNUNET_NAMESTORE_RecordData *rd)
1279 struct RecordLookupHandle* rlh;
1281 rlh = (struct RecordLookupHandle*)cls;
1284 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1285 "No records for %s found in DHT. Aborting\n",
1287 /* give up, cannot resolve */
1288 finish_lookup(rh, rlh, 0, NULL);
1289 free_resolver_handle(rh);
1293 /* results found yay */
1294 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1295 "Record resolved from DHT!");
1297 finish_lookup(rh, rlh, rd_count, rd);
1298 free_resolver_handle(rh);
1304 * Process namestore lookup result for record.
1306 * @param cls the closure
1307 * @param rh resolver handle
1308 * @param rd_count number of results
1309 * @param rd record data
1312 handle_record_ns(void* cls, struct ResolverHandle *rh,
1313 unsigned int rd_count,
1314 const struct GNUNET_NAMESTORE_RecordData *rd)
1316 struct RecordLookupHandle* rlh;
1317 rlh = (struct RecordLookupHandle*) cls;
1320 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Resolution status: %d!\n", rh->status);
1322 /* ns entry expired and not ours. try dht */
1323 if (rh->status & (EXPIRED | !EXISTS) &&
1324 GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1327 rh->proc = &handle_record_dht;
1328 resolve_record_dht(rh);
1331 /* give up, cannot resolve */
1332 finish_lookup(rh, rlh, 0, NULL);
1333 free_resolver_handle(rh);
1337 /* results found yay */
1338 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1339 "Record resolved from namestore!");
1341 finish_lookup(rh, rlh, rd_count, rd);
1343 free_resolver_handle(rh);
1349 * Determine if this name is canonical.
1351 * a.b.gnunet = not canonical
1354 * @param name the name to test
1355 * @return 1 if canonical
1358 is_canonical(char* name)
1360 uint32_t len = strlen(name);
1363 for (i=0; i<len; i++)
1365 if (*(name+i) == '.')
1372 * Move one level up in the domain hierarchy and return the
1373 * passed top level domain.
1375 * @param name the domain
1376 * @param dest the destination where the tld will be put
1379 pop_tld(char* name, char* dest)
1383 if (is_canonical(name))
1390 for (len = strlen(name); len > 0; len--)
1392 if (*(name+len) == '.')
1402 strcpy(dest, (name+len+1));
1406 * Checks if name is in tld
1408 * @param name the name to check
1409 * @return GNUNET_YES or GNUNET_NO
1412 is_tld(const char* name, const char* tld)
1416 if (strlen(name) <= strlen(tld))
1421 offset = strlen(name)-strlen(tld);
1422 if (strcmp(name+offset, tld) != 0)
1424 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1425 "%s is not in .%s TLD\n", name, tld);
1432 * DHT resolution for delegation finished. Processing result.
1434 * @param cls the closure
1435 * @param rh resolver handle
1436 * @param rd_count number of results (always 0)
1437 * @param rd record data (always NULL)
1440 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
1441 unsigned int rd_count,
1442 const struct GNUNET_NAMESTORE_RecordData *rd)
1444 struct RecordLookupHandle* rlh;
1445 rlh = (struct RecordLookupHandle*) cls;
1449 if (strcmp(rh->name, "") == 0)
1451 if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1453 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1454 "Resolved queried PKEY via DHT.\n");
1455 finish_lookup(rh, rlh, rd_count, rd);
1456 free_resolver_handle(rh);
1459 /* We resolved full name for delegation. resolving record */
1460 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1461 "Resolved full name for delegation via DHT. resolving record '' in ns\n");
1462 strcpy(rh->name, "+\0");
1463 rh->proc = &handle_record_ns;
1464 resolve_record_ns(rh);
1469 * we still have some left
1471 if (is_canonical(rh->name))
1473 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1474 "Resolving canonical record %s in ns\n", rh->name);
1475 rh->proc = &handle_record_ns;
1476 resolve_record_ns(rh);
1479 /* give up, cannot resolve */
1480 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1481 "Cannot fully resolve delegation for %s via DHT!\n",
1483 finish_lookup(rh, rlh, 0, NULL);
1484 free_resolver_handle(rh);
1489 * Start DHT lookup for a name -> PKEY (compare NS) record in
1490 * rh->authority's zone
1492 * @param rh the pending gns query
1495 resolve_delegation_dht(struct ResolverHandle *rh)
1498 struct GNUNET_CRYPTO_ShortHashCode name_hash;
1499 GNUNET_HashCode name_hash_double;
1500 GNUNET_HashCode zone_hash_double;
1501 GNUNET_HashCode lookup_key;
1502 struct ResolverHandle *rh_heap_root;
1504 GNUNET_CRYPTO_short_hash(rh->authority_name,
1505 strlen(rh->authority_name),
1507 GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1508 GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
1509 GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
1511 rh->dht_heap_node = NULL;
1513 if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
1515 //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1516 // &dht_authority_lookup_timeout,
1518 rh->timeout_cont = &dht_authority_lookup_timeout;
1519 rh->timeout_cont_cls = rh;
1523 if (max_allowed_background_queries <=
1524 GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
1526 /* terminate oldest lookup */
1527 rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
1528 GNUNET_DHT_get_stop(rh_heap_root->get_handle);
1529 rh_heap_root->dht_heap_node = NULL;
1530 rh_heap_root->proc(rh_heap_root->proc_cls,
1535 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
1537 GNUNET_TIME_absolute_get().abs_value);
1540 xquery = htonl(GNUNET_GNS_RECORD_PKEY);
1542 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
1543 GNUNET_TIME_UNIT_FOREVER_REL,
1544 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1546 DHT_GNS_REPLICATION_LEVEL,
1550 &process_delegation_result_dht,
1557 * Namestore resolution for delegation finished. Processing result.
1559 * @param cls the closure
1560 * @param rh resolver handle
1561 * @param rd_count number of results (always 0)
1562 * @param rd record data (always NULL)
1565 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
1566 unsigned int rd_count,
1567 const struct GNUNET_NAMESTORE_RecordData *rd)
1569 struct RecordLookupHandle* rlh;
1570 rlh = (struct RecordLookupHandle*) cls;
1572 if (strcmp(rh->name, "") == 0)
1574 if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1576 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1577 "Resolved queried PKEY in NS.\n");
1578 finish_lookup(rh, rlh, rd_count, rd);
1579 free_resolver_handle(rh);
1582 /* We resolved full name for delegation. resolving record */
1583 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1584 "Resolved full name for delegation. resolving record '+'\n");
1585 strcpy(rh->name, "+\0");
1586 rh->proc = &handle_record_ns;
1587 resolve_record_ns(rh);
1592 * we still have some left
1593 * check if authority in ns is fresh
1595 * or we are authority
1597 if ((rh->status & (EXISTS | !EXPIRED)) ||
1598 !GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1599 &rh->authority_chain_tail->zone))
1601 if (is_canonical(rh->name))
1603 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1604 "Resolving canonical record %s\n", rh->name);
1605 rh->proc = &handle_record_ns;
1606 resolve_record_ns(rh);
1610 /* give up, cannot resolve */
1611 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1612 "Cannot fully resolve delegation for %s!\n",
1614 rlh->proc(rlh->proc_cls, 0, NULL);
1619 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1620 "Trying to resolve delegation for %s via DHT\n",
1622 rh->proc = &handle_delegation_dht;
1623 resolve_delegation_dht(rh);
1627 static void resolve_delegation_ns(struct ResolverHandle *rh);
1631 * This is a callback function that should give us only PKEY
1632 * records. Used to query the namestore for the authority (PKEY)
1633 * for 'name'. It will recursively try to resolve the
1634 * authority for a given name from the namestore.
1636 * @param cls the pending query
1637 * @param key the key of the zone we did the lookup
1638 * @param expiration expiration date of the record data set in the namestore
1639 * @param name the name for which we need an authority
1640 * @param rd_count the number of records with 'name'
1641 * @param rd the record data
1642 * @param signature the signature of the authority for the record data
1645 process_delegation_result_ns(void* cls,
1646 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1647 struct GNUNET_TIME_Absolute expiration,
1649 unsigned int rd_count,
1650 const struct GNUNET_NAMESTORE_RecordData *rd,
1651 const struct GNUNET_CRYPTO_RsaSignature *signature)
1653 struct ResolverHandle *rh;
1654 struct GNUNET_TIME_Relative remaining_time;
1655 struct GNUNET_CRYPTO_ShortHashCode zone;
1656 char new_name[MAX_DNS_NAME_LENGTH];
1658 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got %d records from authority lookup\n",
1661 rh = (struct ResolverHandle *)cls;
1662 GNUNET_CRYPTO_short_hash(key,
1663 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1665 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1671 rh->status |= EXISTS;
1674 if (remaining_time.rel_value == 0)
1676 rh->status |= EXPIRED;
1680 * No authority found in namestore.
1685 * We did not find an authority in the namestore
1690 * Promote this authority back to a name maybe it is
1693 if (strcmp(rh->name, "") == 0)
1695 /* simply promote back */
1696 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1697 "Promoting %s back to name\n", rh->authority_name);
1698 strcpy(rh->name, rh->authority_name);
1702 /* add back to existing name */
1703 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1704 "Adding %s back to %s\n",
1705 rh->authority_name, rh->name);
1706 //memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
1707 strcpy(new_name, rh->name);
1708 strcpy(new_name+strlen(new_name), ".");
1709 strcpy(new_name+strlen(new_name), rh->authority_name);
1710 strcpy(rh->name, new_name);
1711 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1712 "%s restored\n", rh->name);
1714 rh->proc(rh->proc_cls, rh, 0, NULL);
1719 * We found an authority that may be able to help us
1720 * move on with query
1721 * Note only 1 pkey should have been returned.. anything else would be strange
1724 for (i=0; i<rd_count;i++)
1727 if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
1730 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
1733 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This pkey is expired.\n");
1734 if (remaining_time.rel_value == 0)
1736 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1737 "This dht entry is expired.\n");
1738 rh->authority_chain_head->fresh = 0;
1739 rh->proc(rh->proc_cls, rh, 0, NULL);
1747 * Resolve rest of query with new authority
1749 GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
1750 memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1751 struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
1752 auth->zone = rh->authority;
1753 memset(auth->name, 0, strlen(rh->authority_name)+1);
1754 strcpy(auth->name, rh->authority_name);
1755 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1756 rh->authority_chain_tail,
1760 * We are done with PKEY resolution if name is empty
1761 * else resolve again with new authority
1763 if (strcmp(rh->name, "") == 0)
1764 rh->proc(rh->proc_cls, rh, 0, NULL);
1766 resolve_delegation_ns(rh);
1773 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1774 "Authority lookup successful but no PKEY... never get here\n");
1775 rh->proc(rh->proc_cls, rh, 0, NULL);
1780 * Resolve the delegation chain for the request in our namestore
1782 * @param rh the resolver handle
1785 resolve_delegation_ns(struct ResolverHandle *rh)
1787 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1788 "Resolving delegation for %s\n", rh->name);
1789 pop_tld(rh->name, rh->authority_name);
1790 GNUNET_NAMESTORE_lookup_record(namestore_handle,
1793 GNUNET_GNS_RECORD_PKEY,
1794 &process_delegation_result_ns,
1801 * Lookup of a record in a specific zone
1802 * calls lookup result processor on result
1804 * @param zone the root zone
1805 * @param record_type the record type to look up
1806 * @param name the name to look up
1807 * @param proc the processor to call on result
1808 * @param cls the closure to pass to proc
1811 gns_resolver_lookup_record(struct GNUNET_CRYPTO_ShortHashCode zone,
1812 uint32_t record_type,
1814 struct GNUNET_CRYPTO_RsaPrivateKey *key,
1815 struct GNUNET_TIME_Relative timeout,
1816 RecordLookupProcessor proc,
1819 struct ResolverHandle *rh;
1820 struct RecordLookupHandle* rlh;
1821 char string_hash[MAX_DNS_LABEL_LENGTH];
1823 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1824 "Starting resolution for %s (type=%d)!\n",
1828 if (is_canonical((char*)name) && (strcmp(GNUNET_GNS_TLD, name) != 0))
1830 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1831 "%s is canonical and not gnunet -> cannot resolve!\n", name);
1836 rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
1837 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1839 rh->authority = zone;
1842 rh->timeout = timeout;
1843 if (timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
1846 * Set timeout for authority lookup phase to 1/2
1848 rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
1849 GNUNET_TIME_relative_divide(timeout, 2),
1850 &handle_lookup_timeout,
1852 rh->timeout_cont = &dht_authority_lookup_timeout;
1853 rh->timeout_cont_cls = rh;
1857 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No timeout for query!\n");
1858 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1861 if (strcmp(GNUNET_GNS_TLD, name) == 0)
1864 * Only 'gnunet' given
1866 strcpy(rh->name, "\0");
1870 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1871 "Checking for TLD...\n");
1872 if (is_zkey_tld(name) == GNUNET_YES)
1874 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1877 * This is a zkey tld
1878 * build hash and use as initial authority
1881 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
1882 memcpy(rh->name, name,
1883 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
1884 pop_tld(rh->name, string_hash);
1886 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1887 "ZKEY is %s!\n", string_hash);
1889 if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(string_hash,
1892 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1893 "Cannot convert ZKEY %s to hash!\n", string_hash);
1903 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1906 * Presumably GNUNET tld
1909 strlen(name)-strlen(GNUNET_GNS_TLD));
1910 memcpy(rh->name, name,
1911 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
1916 * Initialize authority chain
1918 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1919 rh->authority_chain_head->prev = NULL;
1920 rh->authority_chain_head->next = NULL;
1921 rh->authority_chain_tail = rh->authority_chain_head;
1922 rh->authority_chain_head->zone = rh->authority;
1925 * Copy original query into lookup handle
1927 rlh->record_type = record_type;
1928 memset(rlh->name, 0, strlen(name) + 1);
1929 strcpy(rlh->name, name);
1931 rlh->proc_cls = cls;
1933 rh->proc = &handle_delegation_ns;
1934 resolve_delegation_ns(rh);
1937 /******** END Record Resolver ***********/
1941 * Callback calles by namestore for a zone to name
1944 * @param cls the closure
1945 * @param zone_key the zone we queried
1946 * @param expire the expiration time of the name
1947 * @param name the name found or NULL
1948 * @param rd_len number of records for the name
1949 * @param rd the record data (PKEY) for the name
1950 * @param signature the signature for the record data
1953 process_zone_to_name_shorten(void *cls,
1954 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1955 struct GNUNET_TIME_Absolute expire,
1957 unsigned int rd_len,
1958 const struct GNUNET_NAMESTORE_RecordData *rd,
1959 const struct GNUNET_CRYPTO_RsaSignature *signature)
1961 struct ResolverHandle *rh = (struct ResolverHandle *)cls;
1962 struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
1963 struct AuthorityChain *next_authority;
1965 char result[MAX_DNS_NAME_LENGTH];
1966 char next_authority_name[MAX_DNS_LABEL_LENGTH];
1969 /* we found a match in our own zone */
1972 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1973 "result strlen %d\n", strlen(name));
1974 answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
1975 memset(result, 0, answer_len);
1976 if (strlen(rh->name) > 0)
1978 strcpy(result, rh->name);
1979 strcpy(result+strlen(rh->name), ".");
1982 strcpy(result+strlen(result), name);
1983 strcpy(result+strlen(result), ".");
1984 strcpy(result+strlen(result), GNUNET_GNS_TLD);
1986 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1987 "Sending shorten result %s\n", result);
1989 nsh->proc(nsh->proc_cls, result);
1991 free_resolver_handle(rh);
1993 else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1996 /* our zone, just append .gnunet */
1997 answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
1998 memset(result, 0, answer_len);
1999 strcpy(result, rh->name);
2000 strcpy(result+strlen(rh->name), ".");
2001 strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
2003 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2004 "Our zone: Sending name as shorten result %s\n", rh->name);
2006 nsh->proc(nsh->proc_cls, result);
2008 free_resolver_handle(rh);
2014 * continue with next authority
2016 next_authority = rh->authority_chain_head;
2017 // strlen(next_authority->name) + 2);
2018 memset(next_authority_name, 0, strlen(rh->name)+
2019 strlen(next_authority->name) + 2);
2020 strcpy(next_authority_name, rh->name);
2021 strcpy(next_authority_name+strlen(rh->name)+1, ".");
2022 strcpy(next_authority_name+strlen(rh->name)+2, next_authority->name);
2024 strcpy(rh->name, next_authority_name);
2025 GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
2026 rh->authority_chain_tail,
2029 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2030 &rh->authority_chain_tail->zone,
2031 &rh->authority_chain_head->zone,
2032 &process_zone_to_name_shorten,
2039 * Process result from namestore delegation lookup
2040 * for shorten operation
2042 * @param cls the client shorten handle
2043 * @param rh the resolver handle
2044 * @param rd_count number of results (0)
2045 * @param rd data (NULL)
2048 handle_delegation_ns_shorten(void* cls,
2049 struct ResolverHandle *rh,
2051 const struct GNUNET_NAMESTORE_RecordData *rd)
2053 struct NameShortenHandle *nsh;
2054 char result[MAX_DNS_NAME_LENGTH];
2057 nsh = (struct NameShortenHandle *)cls;
2060 * At this point rh->name contains the part of the name
2061 * that we do not have a PKEY in our namestore to resolve.
2062 * The authority chain in the resolver handle is now
2063 * useful to backtrack if needed
2066 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2067 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2069 if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2073 * This is our zone append .gnunet unless name is empty
2074 * (it shouldn't be, usually FIXME what happens if we
2075 * shorten to our zone to a "" record??)
2078 answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
2079 memset(result, 0, answer_len);
2080 strcpy(result, rh->name);
2081 strcpy(result+strlen(rh->name), ".");
2082 strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
2084 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2085 "Our zone: Sending name as shorten result %s\n", rh->name);
2087 nsh->proc(nsh->proc_cls, result);
2089 free_resolver_handle(rh);
2093 /* backtrack authorities for names */
2094 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2095 &rh->authority_chain_tail->zone, //ours
2096 &rh->authority_chain_head->zone,
2097 &process_zone_to_name_shorten,
2103 * Shorten api from resolver
2105 * @param zone the zone to use
2106 * @param name the name to shorten
2107 * @param proc the processor to call with result
2108 * @param cls closure to pass to proc
2111 gns_resolver_shorten_name(struct GNUNET_CRYPTO_ShortHashCode zone,
2113 ShortenResultProcessor proc,
2116 struct ResolverHandle *rh;
2117 struct NameShortenHandle *nsh;
2118 char string_hash[MAX_DNS_NAME_LENGTH]; //FIXME LABEL length when shorthash
2120 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2121 "Starting shorten for %s!\n", name);
2123 if (is_canonical((char*)name))
2125 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2126 "%s is canonical. Returning verbatim\n", name);
2131 nsh = GNUNET_malloc(sizeof (struct NameShortenHandle));
2135 nsh->proc_cls = cls;
2137 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2138 rh->authority = zone;
2140 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2141 "Checking for TLD...\n");
2142 if (is_zkey_tld(name) == GNUNET_YES)
2144 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2147 * This is a zkey tld
2148 * build hash and use as initial authority
2151 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
2152 memcpy(rh->name, name,
2153 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
2154 pop_tld(rh->name, string_hash);
2156 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2157 "ZKEY is %s!\n", string_hash);
2159 if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(string_hash,
2162 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2163 "Cannot convert ZKEY %s to hash!\n", string_hash);
2173 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2176 * Presumably GNUNET tld
2179 strlen(name)-strlen(GNUNET_GNS_TLD));
2180 memcpy(rh->name, name,
2181 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2184 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2185 rh->authority_chain_tail = rh->authority_chain_head;
2186 rh->authority_chain_head->zone = zone;
2187 rh->proc = &handle_delegation_ns_shorten;
2190 /* Start delegation resolution in our namestore */
2191 resolve_delegation_ns(rh);
2194 /*********** END NAME SHORTEN ********************/
2198 * Process result from namestore delegation lookup
2199 * for get authority operation
2201 * @param cls the client get auth handle
2202 * @param rh the resolver handle
2203 * @param rd_count number of results (0)
2204 * @param rd data (NULL)
2207 handle_delegation_result_ns_get_auth(void* cls,
2208 struct ResolverHandle *rh,
2210 const struct GNUNET_NAMESTORE_RecordData *rd)
2212 struct GetNameAuthorityHandle* nah;
2213 char result[MAX_DNS_NAME_LENGTH];
2216 nah = (struct GetNameAuthorityHandle*) rh->proc_cls;
2219 * At this point rh->name contains the part of the name
2220 * that we do not have a PKEY in our namestore to resolve.
2221 * The authority chain in the resolver handle is now
2222 * useful to backtrack if needed
2225 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2226 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2228 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2229 "Building response!\n");
2230 if (is_canonical(rh->name))
2233 * We successfully resolved the authority in the ns
2234 * FIXME for our purposes this is fine
2235 * but maybe we want to have an api that also looks
2236 * into the dht (i.e. option in message)
2238 if (strlen(rh->name) > strlen(nah->name))
2240 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2241 "Record name longer than original lookup name... odd!\n");
2245 answer_len = strlen(nah->name) - strlen(rh->name)
2246 + strlen(GNUNET_GNS_TLD) + 1;
2247 memset(result, 0, answer_len);
2248 strcpy(result, nah->name + strlen(rh->name) + 1);
2250 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2251 "Got authority result %s\n", result);
2253 nah->proc(nah->proc_cls, result);
2255 free_resolver_handle(rh);
2259 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2260 "Unable to resolve authority for remaining %s!\n", rh->name);
2261 nah->proc(nah->proc_cls, "");
2263 free_resolver_handle(rh);
2271 * Tries to resolve the authority for name
2274 * @param zone the root zone to look up for
2275 * @param name the name to lookup up
2276 * @param proc the processor to call when finished
2277 * @param cls the closure to pass to the processor
2280 gns_resolver_get_authority(struct GNUNET_CRYPTO_ShortHashCode zone,
2282 GetAuthorityResultProcessor proc,
2285 struct ResolverHandle *rh;
2286 struct GetNameAuthorityHandle *nah;
2288 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2289 "Starting authority resolution for %s!\n", name);
2291 nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
2292 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2293 rh->authority = zone;
2295 if (strcmp(GNUNET_GNS_TLD, name) == 0)
2297 strcpy(rh->name, "\0");
2302 strlen(name)-strlen(GNUNET_GNS_TLD));
2303 memcpy(rh->name, name,
2304 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2307 memset(nah->name, 0,
2309 strcpy(nah->name, name);
2311 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2312 rh->authority_chain_tail = rh->authority_chain_head;
2313 rh->authority_chain_head->zone = zone;
2314 rh->proc = &handle_delegation_result_ns_get_auth;
2315 rh->proc_cls = (void*)nah;
2318 nah->proc_cls = cls;
2320 /* Start delegation resolution in our namestore */
2321 resolve_delegation_ns(rh);
2325 /******** END GET AUTHORITY *************/
2327 /* end of gnunet-service-gns_resolver.c */