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 * Namestore calls this function if we have record for this name.
64 * (or with rd_count=0 to indicate no matches)
66 * @param cls the pending query
67 * @param key the key of the zone we did the lookup
68 * @param expiration expiration date of the namestore entry
69 * @param name the name for which we need an authority
70 * @param rd_count the number of records with 'name'
71 * @param rd the record data
72 * @param signature the signature of the authority for the record data
75 process_pseu_lookup_ns(void* cls,
76 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
77 struct GNUNET_TIME_Absolute expiration,
78 const char *name, unsigned int rd_count,
79 const struct GNUNET_NAMESTORE_RecordData *rd,
80 const struct GNUNET_CRYPTO_RsaSignature *signature)
82 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
83 struct GNUNET_NAMESTORE_RecordData new_pkey;
87 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
88 "Name %s already taken in NS!\n", name);
89 if (0 == strcmp(gph->name, name))
91 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
92 "Intelligent replacement not implemented\n", name);
97 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
98 "Trying delegated name %s\n", gph->name);
99 memcpy(gph->new_name, gph->name, strlen(gph->name)+1);
100 GNUNET_NAMESTORE_lookup_record(namestore_handle,
103 GNUNET_GNS_RECORD_PSEU,
104 &process_pseu_lookup_ns,
110 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
111 "Name %s not taken in NS! Adding\n", gph->new_name);
113 new_pkey.expiration = GNUNET_TIME_absolute_get_forever ();
114 new_pkey.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode);
115 new_pkey.data = &gph->new_zone;
116 new_pkey.record_type = GNUNET_GNS_RECORD_PKEY;
117 GNUNET_NAMESTORE_record_create (namestore_handle,
128 * process result of a dht pseu lookup
130 * @param gph the handle
131 * @param name the pseu result or NULL
134 process_pseu_result(struct GetPseuAuthorityHandle* gph, char* name)
138 memcpy(gph->new_name, name, strlen(gph->name)+1);
142 memcpy(gph->new_name, name, strlen(name)+1);
145 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
146 "Checking %s for collision in NS\n", gph->new_name);
149 * Check for collision
151 GNUNET_NAMESTORE_lookup_record(namestore_handle,
154 GNUNET_GNS_RECORD_PSEU,
155 &process_pseu_lookup_ns,
160 * Handle timeout for dht request
162 * @param cls the request handle as closure
163 * @param tc the task context
166 handle_auth_discovery_timeout(void *cls,
167 const struct GNUNET_SCHEDULER_TaskContext *tc)
169 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
171 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
172 "dht lookup for query PSEU timed out.\n");
173 GNUNET_DHT_get_stop (gph->get_handle);
174 process_pseu_result(gph, NULL);
178 * Function called when we find a PSEU entry in the DHT
180 * @param cls the request handle
181 * @param exp lifetime
182 * @param key the key the record was stored under
183 * @param get_path get path
184 * @param get_path_length get path length
185 * @param put_path put path
186 * @param put_path_length put path length
187 * @param type the block type
188 * @param size the size of the record
189 * @param data the record data
192 process_auth_discovery_dht_result(void* cls,
193 struct GNUNET_TIME_Absolute exp,
194 const GNUNET_HashCode * key,
195 const struct GNUNET_PeerIdentity *get_path,
196 unsigned int get_path_length,
197 const struct GNUNET_PeerIdentity *put_path,
198 unsigned int put_path_length,
199 enum GNUNET_BLOCK_Type type,
200 size_t size, const void *data)
202 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
203 struct GNSNameRecordBlock *nrb;
204 char* rd_data = (char*)data;
210 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "got dht result (size=%d)\n", size);
214 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "got dht result null!\n", size);
220 nrb = (struct GNSNameRecordBlock*)data;
222 /* stop lookup and timeout task */
223 GNUNET_DHT_get_stop (gph->get_handle);
224 GNUNET_SCHEDULER_cancel(gph->timeout);
226 gph->get_handle = NULL;
228 nrb = (struct GNSNameRecordBlock*)data;
230 name = (char*)&nrb[1];
231 num_records = ntohl(nrb->rd_count);
233 struct GNUNET_NAMESTORE_RecordData rd[num_records];
235 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
236 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
238 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
243 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
249 for (i=0; i<num_records; i++)
251 if ((strcmp(name, "+") == 0) &&
252 (rd[i].record_type == GNUNET_GNS_RECORD_PSEU))
255 process_pseu_result(gph, (char*)rd[i].data);
261 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "no pseu in dht!\n");
262 process_pseu_result(gph, NULL);
266 * Callback called by namestore for a zone to name
269 * @param cls the closure
270 * @param zone_key the zone we queried
271 * @param expire the expiration time of the name
272 * @param name the name found or NULL
273 * @param rd_len number of records for the name
274 * @param rd the record data (PKEY) for the name
275 * @param signature the signature for the record data
278 process_zone_to_name_discover(void *cls,
279 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
280 struct GNUNET_TIME_Absolute expire,
283 const struct GNUNET_NAMESTORE_RecordData *rd,
284 const struct GNUNET_CRYPTO_RsaSignature *signature)
286 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
288 /* we found a match in our own zone */
291 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
292 "name for zone in our root %d\n", strlen(name));
302 struct GNUNET_CRYPTO_ShortHashCode name_hash;
303 GNUNET_HashCode lookup_key;
304 struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
305 GNUNET_HashCode name_hash_double;
306 GNUNET_HashCode zone_hash_double;
308 GNUNET_CRYPTO_short_hash("+", strlen("+"), &name_hash);
309 GNUNET_CRYPTO_short_hash_double (&name_hash, &name_hash_double);
310 GNUNET_CRYPTO_short_hash_double (&gph->new_zone, &zone_hash_double);
311 GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
312 GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
314 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
315 "starting dht lookup for %s with key: %s\n",
316 "+", (char*)&lookup_key_string);
318 //gph->timeout = GNUNET_SCHEDULER_add_delayed(DHT_LOOKUP_TIMEOUT,
319 // &handle_auth_discovery_timeout, gph);
321 xquery = htonl(GNUNET_GNS_RECORD_PSEU);
323 gph->get_handle = GNUNET_DHT_get_start(dht_handle,
324 DHT_OPERATION_TIMEOUT,
325 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
327 DHT_GNS_REPLICATION_LEVEL,
331 &process_auth_discovery_dht_result,
339 * Callback for new authories
341 * @param name the name given by delegation
342 * @param zone the authority
343 * @param the private key of our authority
345 static void process_discovered_authority(char* name,
346 struct GNUNET_CRYPTO_ShortHashCode zone,
347 struct GNUNET_CRYPTO_ShortHashCode our_zone,
348 struct GNUNET_CRYPTO_RsaPrivateKey *key)
350 struct GetPseuAuthorityHandle *gph;
353 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "New authority %s discovered\n",
356 gph = GNUNET_malloc(sizeof(struct GetPseuAuthorityHandle));
357 namelen = strlen(name) + 1;
358 memcpy(gph->name, name, namelen);
360 gph->new_zone = zone;
361 gph->zone = our_zone;
364 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
367 &process_zone_to_name_discover,
373 * Initialize the resolver
375 * @param nh the namestore handle
376 * @param dh the dht handle
377 * @return GNUNET_OK on success
380 gns_resolver_init(struct GNUNET_NAMESTORE_Handle *nh,
381 struct GNUNET_DHT_Handle *dh)
383 namestore_handle = nh;
386 GNUNET_CONTAINER_heap_create(GNUNET_CONTAINER_HEAP_ORDER_MIN);
387 if ((namestore_handle != NULL) && (dht_handle != NULL))
391 return GNUNET_SYSERR;
396 * Helper function to free resolver handle
398 * @rh the handle to free
401 free_resolver_handle(struct ResolverHandle* rh)
403 struct AuthorityChain *ac;
404 struct AuthorityChain *ac_next;
409 ac = rh->authority_chain_head;
422 * Callback when record data is put into namestore
424 * @param cls the closure
425 * @param success GNUNET_OK on success
426 * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
429 on_namestore_record_put_result(void *cls,
433 if (GNUNET_NO == success)
435 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "records already in namestore\n");
438 else if (GNUNET_YES == success)
440 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
441 "records successfully put in namestore\n");
445 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
446 "Error putting records into namestore: %s\n", emsg);
451 * Processor for background lookups in the DHT
453 * @param cls closure (NULL)
454 * @param rd_count number of records found (not 0)
455 * @param rd record data
458 background_lookup_result_processor(void *cls,
460 const struct GNUNET_NAMESTORE_RecordData *rd)
462 //We could do sth verbose/more useful here but it doesn't make any difference
463 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
464 "background dht lookup finished.\n");
468 * Handle timeout for DHT requests
470 * @param cls the request handle as closure
471 * @param tc the task context
474 dht_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
476 struct ResolverHandle *rh = cls;
477 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
478 char new_name[MAX_DNS_NAME_LENGTH];
480 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
481 "dht lookup for query %s timed out.\n",
484 * Start resolution in bg
486 strcpy(new_name, rh->name);
487 memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD));
489 gns_resolver_lookup_record(rh->authority,
493 GNUNET_TIME_UNIT_FOREVER_REL,
494 &background_lookup_result_processor,
497 GNUNET_DHT_get_stop (rh->get_handle);
498 rh->proc(rh->proc_cls, rh, 0, NULL);
503 * Function called when we get a result from the dht
504 * for our record query
506 * @param cls the request handle
507 * @param exp lifetime
508 * @param key the key the record was stored under
509 * @param get_path get path
510 * @param get_path_length get path length
511 * @param put_path put path
512 * @param put_path_length put path length
513 * @param type the block type
514 * @param size the size of the record
515 * @param data the record data
518 process_record_result_dht(void* cls,
519 struct GNUNET_TIME_Absolute exp,
520 const GNUNET_HashCode * key,
521 const struct GNUNET_PeerIdentity *get_path,
522 unsigned int get_path_length,
523 const struct GNUNET_PeerIdentity *put_path,
524 unsigned int put_path_length,
525 enum GNUNET_BLOCK_Type type,
526 size_t size, const void *data)
528 struct ResolverHandle *rh;
529 struct RecordLookupHandle *rlh;
530 struct GNSNameRecordBlock *nrb;
531 uint32_t num_records;
533 char* rd_data = (char*)data;
537 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "got dht result (size=%d)\n", size);
542 //FIXME maybe check expiration here, check block type
544 rh = (struct ResolverHandle *)cls;
545 rlh = (struct RecordLookupHandle *) rh->proc_cls;
546 nrb = (struct GNSNameRecordBlock*)data;
548 /* stop lookup and timeout task */
549 GNUNET_DHT_get_stop (rh->get_handle);
551 if (rh->dht_heap_node != NULL)
553 GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
554 rh->dht_heap_node = NULL;
557 if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
558 GNUNET_SCHEDULER_cancel(rh->timeout_task);
560 rh->get_handle = NULL;
561 name = (char*)&nrb[1];
562 num_records = ntohl(nrb->rd_count);
564 struct GNUNET_NAMESTORE_RecordData rd[num_records];
566 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
567 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
569 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
574 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
578 for (i=0; i<num_records; i++)
580 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
581 "Got name: %s (wanted %s)\n", name, rh->name);
582 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
585 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
586 "Got data length: %d\n", rd[i].data_size);
587 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
588 "Got flag %d\n", rd[i].flags);
590 if ((strcmp(name, rh->name) == 0) &&
591 (rd[i].record_type == rlh->record_type))
599 * FIXME check pubkey against existing key in namestore?
600 * https://gnunet.org/bugs/view.php?id=2179
603 /* Save to namestore */
604 GNUNET_NAMESTORE_record_put (namestore_handle,
611 &on_namestore_record_put_result, //cont
616 rh->proc(rh->proc_cls, rh, num_records, rd);
618 rh->proc(rh->proc_cls, rh, 0, NULL);
625 * Start DHT lookup for a (name -> query->record_type) record in
626 * rh->authority's zone
628 * @param rh the pending gns query context
631 resolve_record_dht(struct ResolverHandle *rh)
634 struct GNUNET_CRYPTO_ShortHashCode name_hash;
635 GNUNET_HashCode lookup_key;
636 GNUNET_HashCode name_hash_double;
637 GNUNET_HashCode zone_hash_double;
638 struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
639 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
640 struct ResolverHandle *rh_heap_root;
642 GNUNET_CRYPTO_short_hash(rh->name, strlen(rh->name), &name_hash);
643 GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
644 GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
645 GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
646 GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
648 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
649 "starting dht lookup for %s with key: %s\n",
650 rh->name, (char*)&lookup_key_string);
652 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
653 rh->dht_heap_node = NULL;
655 if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
657 //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
658 // &dht_lookup_timeout,
660 rh->timeout_cont = &dht_lookup_timeout;
661 rh->timeout_cont_cls = rh;
665 if (GNUNET_GNS_MAX_PARALLEL_LOOKUPS >
666 GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
668 rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
669 GNUNET_DHT_get_stop(rh_heap_root->get_handle);
670 rh_heap_root->dht_heap_node = NULL;
671 rh_heap_root->proc(rh_heap_root->proc_cls,
676 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
678 GNUNET_TIME_absolute_get().abs_value);
681 xquery = htonl(rlh->record_type);
682 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
683 DHT_OPERATION_TIMEOUT,
684 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
686 DHT_GNS_REPLICATION_LEVEL,
690 &process_record_result_dht,
697 * Namestore calls this function if we have record for this name.
698 * (or with rd_count=0 to indicate no matches)
700 * @param cls the pending query
701 * @param key the key of the zone we did the lookup
702 * @param expiration expiration date of the namestore entry
703 * @param name the name for which we need an authority
704 * @param rd_count the number of records with 'name'
705 * @param rd the record data
706 * @param signature the signature of the authority for the record data
709 process_record_result_ns(void* cls,
710 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
711 struct GNUNET_TIME_Absolute expiration,
712 const char *name, unsigned int rd_count,
713 const struct GNUNET_NAMESTORE_RecordData *rd,
714 const struct GNUNET_CRYPTO_RsaSignature *signature)
716 struct ResolverHandle *rh;
717 struct RecordLookupHandle *rlh;
718 struct GNUNET_TIME_Relative remaining_time;
719 struct GNUNET_CRYPTO_ShortHashCode zone;
721 rh = (struct ResolverHandle *) cls;
722 rlh = (struct RecordLookupHandle *)rh->proc_cls;
723 GNUNET_CRYPTO_short_hash(key,
724 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
726 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
728 if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
729 GNUNET_SCHEDULER_cancel(rh->timeout_task);
735 rh->status |= EXISTS;
738 if (remaining_time.rel_value == 0)
740 rh->status |= EXPIRED;
746 * Lookup terminated and no results
748 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
749 "Namestore lookup for %s terminated without results\n", name);
751 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
752 "Record %s unknown in namestore\n",
755 * Our zone and no result? Cannot resolve TT
757 rh->proc(rh->proc_cls, rh, 0, NULL);
764 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
765 "Processing additional result %s from namestore\n", name);
767 for (i=0; i<rd_count;i++)
770 if (rd[i].record_type != rlh->record_type)
773 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
776 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
777 "This record is expired. Skipping\n");
788 if (rh->answered == 0)
790 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
791 "No answers found. This is odd!\n");
792 rh->proc(rh->proc_cls, rh, 0, NULL);
796 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Found %d answer(s) to query!\n",
799 rh->proc(rh->proc_cls, rh, rd_count, rd);
805 * The final phase of resolution.
806 * rh->name is a name that is canonical and we do not have a delegation.
807 * Query namestore for this record
809 * @param rh the pending lookup
812 resolve_record_ns(struct ResolverHandle *rh)
814 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
817 * Try to resolve this record in our namestore.
818 * The name to resolve is now in rh->authority_name
819 * since we tried to resolve it to an authority
822 GNUNET_NAMESTORE_lookup_record(namestore_handle,
826 &process_record_result_ns,
831 handle_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
833 struct ResolverHandle *rh = cls;
835 if (rh->timeout_cont)
836 rh->timeout_cont(rh->timeout_cont_cls, tc);
840 * Handle timeout for DHT requests
842 * @param cls the request handle as closure
843 * @param tc the task context
846 dht_authority_lookup_timeout(void *cls,
847 const struct GNUNET_SCHEDULER_TaskContext *tc)
849 struct ResolverHandle *rh = cls;
850 struct RecordLookupHandle *rlh = rh->proc_cls;
851 char new_name[MAX_DNS_NAME_LENGTH];
853 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
854 "dht lookup for query %s timed out.\n",
858 if (strcmp(rh->name, "") == 0)
861 * promote authority back to name and try to resolve record
863 strcpy(rh->name, rh->authority_name);
864 rh->proc(rh->proc_cls, rh, 0, NULL);
869 * Start resolution in bg
871 strcpy(new_name, rh->name);
872 strcpy(new_name+strlen(new_name), ".");
873 memcpy(new_name+strlen(new_name), rh->authority_name,
874 strlen(rh->authority_name));
875 memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD));
877 gns_resolver_lookup_record(rh->authority,
881 GNUNET_TIME_UNIT_FOREVER_REL,
882 &background_lookup_result_processor,
885 GNUNET_DHT_get_stop (rh->get_handle);
887 rh->proc(rh->proc_cls, rh, 0, NULL);
891 static void resolve_delegation_dht(struct ResolverHandle *rh);
894 * Function called when we get a result from the dht
895 * for our query. Recursively tries to resolve authorities
898 * @param cls the request handle
899 * @param exp lifetime
900 * @param key the key the record was stored under
901 * @param get_path get path
902 * @param get_path_length get path length
903 * @param put_path put path
904 * @param put_path_length put path length
905 * @param type the block type
906 * @param size the size of the record
907 * @param data the record data
910 process_delegation_result_dht(void* cls,
911 struct GNUNET_TIME_Absolute exp,
912 const GNUNET_HashCode * key,
913 const struct GNUNET_PeerIdentity *get_path,
914 unsigned int get_path_length,
915 const struct GNUNET_PeerIdentity *put_path,
916 unsigned int put_path_length,
917 enum GNUNET_BLOCK_Type type,
918 size_t size, const void *data)
920 struct ResolverHandle *rh;
921 struct GNSNameRecordBlock *nrb;
922 uint32_t num_records;
924 char* rd_data = (char*) data;
927 struct GNUNET_CRYPTO_ShortHashCode zone, name_hash;
928 GNUNET_HashCode zone_hash_double, name_hash_double;
930 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got DHT result\n");
935 //FIXME check expiration?
937 rh = (struct ResolverHandle *)cls;
938 nrb = (struct GNSNameRecordBlock*)data;
940 /* stop dht lookup and timeout task */
941 GNUNET_DHT_get_stop (rh->get_handle);
943 rh->get_handle = NULL;
945 if (rh->dht_heap_node != NULL)
947 GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
948 rh->dht_heap_node = NULL;
951 num_records = ntohl(nrb->rd_count);
952 name = (char*)&nrb[1];
954 struct GNUNET_NAMESTORE_RecordData rd[num_records];
956 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
957 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
959 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
964 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
968 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
969 "Got name: %s (wanted %s)\n", name, rh->authority_name);
970 for (i=0; i<num_records; i++)
973 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
974 "Got name: %s (wanted %s)\n", name, rh->authority_name);
975 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
976 "Got type: %d (wanted %d)\n",
977 rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
978 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
979 "Got data length: %d\n", rd[i].data_size);
980 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
981 "Got flag %d\n", rd[i].flags);
983 if ((strcmp(name, rh->authority_name) == 0) &&
984 (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
986 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Authority found in DHT\n");
988 memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
989 struct AuthorityChain *auth =
990 GNUNET_malloc(sizeof(struct AuthorityChain));
991 auth->zone = rh->authority;
992 memset(auth->name, 0, strlen(rh->authority_name)+1);
993 strcpy(auth->name, rh->authority_name);
994 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
995 rh->authority_chain_tail,
998 /** try to import pkey if private key available */
1000 process_discovered_authority(name, auth->zone,
1001 rh->authority_chain_tail->zone,
1008 GNUNET_CRYPTO_short_hash(name, strlen(name), &name_hash);
1009 GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1010 GNUNET_CRYPTO_hash_xor(key, &name_hash_double, &zone_hash_double);
1011 GNUNET_CRYPTO_short_hash_from_truncation (&zone_hash_double, &zone);
1013 /* Save to namestore */
1014 if (0 != GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_tail->zone,
1017 GNUNET_NAMESTORE_record_put (namestore_handle,
1024 &on_namestore_record_put_result, //cont
1034 * FIXME in this case. should we ask namestore again?
1036 if (strcmp(rh->name, "") == 0)
1037 rh->proc(rh->proc_cls, rh, 0, NULL);
1039 resolve_delegation_dht(rh);
1044 * No pkey but name exists
1046 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "DHT authority lookup found no match!\n");
1047 rh->proc(rh->proc_cls, rh, 0, NULL);
1050 #define MAX_SOA_LENGTH sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)\
1051 +(MAX_DNS_NAME_LENGTH*2)
1052 #define MAX_MX_LENGTH sizeof(uint16_t)+MAX_DNS_NAME_LENGTH
1056 expand_plus(char** dest, char* src, char* repl)
1059 unsigned int s_len = strlen(src)+1;
1061 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1062 "Got %s to expand with %s\n", src, repl);
1066 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1067 "%s to short\n", src);
1069 /* no postprocessing */
1070 memcpy(*dest, src, s_len+1);
1074 if (0 == strcmp(src+s_len-3, ".+"))
1076 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1077 "Expanding .+ in %s\n", src);
1078 memset(*dest, 0, s_len+strlen(repl)+strlen(GNUNET_GNS_TLD));
1080 pos = *dest+s_len-2;
1082 pos += strlen(repl);
1083 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1084 "Expanded to %s\n", *dest);
1092 finish_lookup(struct ResolverHandle *rh,
1093 struct RecordLookupHandle* rlh,
1094 unsigned int rd_count,
1095 const struct GNUNET_NAMESTORE_RecordData *rd)
1098 char new_rr_data[MAX_DNS_NAME_LENGTH];
1099 char new_mx_data[MAX_MX_LENGTH];
1100 char new_soa_data[MAX_SOA_LENGTH];
1101 struct GNUNET_NAMESTORE_RecordData p_rd[rd_count];
1104 unsigned int offset;
1107 memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData));
1109 for (i = 0; i < rd_count; i++)
1112 if (rd[i].record_type != GNUNET_GNS_RECORD_TYPE_NS &&
1113 rd[i].record_type != GNUNET_GNS_RECORD_TYPE_CNAME &&
1114 rd[i].record_type != GNUNET_GNS_RECORD_MX &&
1115 rd[i].record_type != GNUNET_GNS_RECORD_TYPE_SOA)
1117 p_rd[i].data = rd[i].data;
1122 * for all those records we 'should'
1123 * also try to resolve the A/AAAA records (RFC1035)
1124 * This is a feature and not important
1127 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1128 "Postprocessing\n");
1130 if (strcmp(rh->name, "+") == 0)
1131 repl_string = rlh->name;
1133 repl_string = rlh->name+strlen(rh->name)+1;
1136 if (rd[i].record_type == GNUNET_GNS_RECORD_MX)
1138 memcpy(new_mx_data, (char*)rd[i].data, sizeof(uint16_t));
1139 offset = sizeof(uint16_t);
1140 pos = new_mx_data+offset;
1141 expand_plus(&pos, (char*)rd[i].data+sizeof(uint16_t),
1143 offset += strlen(new_mx_data+sizeof(uint16_t))+1;
1144 p_rd[i].data = new_mx_data;
1145 p_rd[i].data_size = offset;
1147 else if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_SOA)
1149 /* expand mname and rname */
1151 expand_plus(&pos, (char*)rd[i].data, repl_string);
1152 offset = strlen(new_soa_data)+1;
1153 pos = new_soa_data+offset;
1154 expand_plus(&pos, (char*)rd[i].data+offset, repl_string);
1155 offset += strlen(new_soa_data+offset)+1;
1156 /* cpy the 4 numbers serial refresh retry and expire */
1157 memcpy(new_soa_data+offset, (char*)rd[i].data+offset, sizeof(uint32_t)*4);
1158 offset += sizeof(uint32_t)*4;
1159 p_rd[i].data_size = offset;
1160 p_rd[i].data = new_soa_data;
1165 expand_plus(&pos, (char*)rd[i].data, repl_string);
1166 p_rd[i].data_size = strlen(new_rr_data)+1;
1167 p_rd[i].data = new_rr_data;
1172 rlh->proc(rlh->proc_cls, rd_count, p_rd);
1178 * Process DHT lookup result for record.
1180 * @param cls the closure
1181 * @param rh resolver handle
1182 * @param rd_count number of results
1183 * @param rd record data
1186 handle_record_dht(void* cls, struct ResolverHandle *rh,
1187 unsigned int rd_count,
1188 const struct GNUNET_NAMESTORE_RecordData *rd)
1190 struct RecordLookupHandle* rlh;
1192 rlh = (struct RecordLookupHandle*)cls;
1195 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1196 "No records for %s found in DHT. Aborting\n",
1198 /* give up, cannot resolve */
1199 finish_lookup(rh, rlh, 0, NULL);
1200 free_resolver_handle(rh);
1204 /* results found yay */
1205 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1206 "Record resolved from DHT!");
1208 finish_lookup(rh, rlh, rd_count, rd);
1209 free_resolver_handle(rh);
1215 * Process namestore lookup result for record.
1217 * @param cls the closure
1218 * @param rh resolver handle
1219 * @param rd_count number of results
1220 * @param rd record data
1223 handle_record_ns(void* cls, struct ResolverHandle *rh,
1224 unsigned int rd_count,
1225 const struct GNUNET_NAMESTORE_RecordData *rd)
1227 struct RecordLookupHandle* rlh;
1228 rlh = (struct RecordLookupHandle*) cls;
1231 /* ns entry expired and not ours. try dht */
1232 if (rh->status & (EXPIRED | !EXISTS) &&
1233 GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1234 &rh->authority_chain_tail->zone))
1236 rh->proc = &handle_record_dht;
1237 resolve_record_dht(rh);
1240 /* give up, cannot resolve */
1241 finish_lookup(rh, rlh, 0, NULL);
1242 free_resolver_handle(rh);
1246 /* results found yay */
1247 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1248 "Record resolved from namestore!");
1250 finish_lookup(rh, rlh, rd_count, rd);
1252 free_resolver_handle(rh);
1258 * Determine if this name is canonical.
1260 * a.b.gnunet = not canonical
1263 * @param name the name to test
1264 * @return 1 if canonical
1267 is_canonical(char* name)
1269 uint32_t len = strlen(name);
1272 for (i=0; i<len; i++)
1274 if (*(name+i) == '.')
1281 * Move one level up in the domain hierarchy and return the
1282 * passed top level domain.
1284 * @param name the domain
1285 * @param dest the destination where the tld will be put
1288 pop_tld(char* name, char* dest)
1292 if (is_canonical(name))
1299 for (len = strlen(name); len > 0; len--)
1301 if (*(name+len) == '.')
1311 strcpy(dest, (name+len+1));
1315 * Checks if name is in tld
1317 * @param name the name to check
1318 * @return GNUNET_YES or GNUNET_NO
1321 is_tld(const char* name, const char* tld)
1325 if (strlen(name) <= strlen(tld))
1330 offset = strlen(name)-strlen(tld);
1331 if (strcmp(name+offset, tld) != 0)
1333 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1334 "%s is not in .%s TLD\n", name, tld);
1341 * DHT resolution for delegation finished. Processing result.
1343 * @param cls the closure
1344 * @param rh resolver handle
1345 * @param rd_count number of results (always 0)
1346 * @param rd record data (always NULL)
1349 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
1350 unsigned int rd_count,
1351 const struct GNUNET_NAMESTORE_RecordData *rd)
1353 struct RecordLookupHandle* rlh;
1354 rlh = (struct RecordLookupHandle*) cls;
1356 if (strcmp(rh->name, "") == 0)
1358 if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1360 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1361 "Resolved queried PKEY via DHT.\n");
1362 finish_lookup(rh, rlh, rd_count, rd);
1363 free_resolver_handle(rh);
1366 /* We resolved full name for delegation. resolving record */
1367 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1368 "Resolved full name for delegation via DHT. resolving record '' in ns\n");
1369 strcpy(rh->name, "+\0");
1370 rh->proc = &handle_record_ns;
1371 resolve_record_ns(rh);
1376 * we still have some left
1378 if (is_canonical(rh->name))
1380 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1381 "Resolving canonical record %s in ns\n", rh->name);
1382 rh->proc = &handle_record_ns;
1383 resolve_record_ns(rh);
1386 /* give up, cannot resolve */
1387 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1388 "Cannot fully resolve delegation for %s via DHT!\n",
1390 finish_lookup(rh, rlh, 0, NULL);
1391 free_resolver_handle(rh);
1396 * Start DHT lookup for a name -> PKEY (compare NS) record in
1397 * rh->authority's zone
1399 * @param rh the pending gns query
1402 resolve_delegation_dht(struct ResolverHandle *rh)
1405 struct GNUNET_CRYPTO_ShortHashCode name_hash;
1406 GNUNET_HashCode name_hash_double;
1407 GNUNET_HashCode zone_hash_double;
1408 GNUNET_HashCode lookup_key;
1409 struct ResolverHandle *rh_heap_root;
1411 GNUNET_CRYPTO_short_hash(rh->authority_name,
1412 strlen(rh->authority_name),
1414 GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1415 GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
1416 GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
1418 rh->dht_heap_node = NULL;
1420 if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
1422 //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1423 // &dht_authority_lookup_timeout,
1425 rh->timeout_cont = &dht_authority_lookup_timeout;
1426 rh->timeout_cont_cls = rh;
1430 if (GNUNET_GNS_MAX_PARALLEL_LOOKUPS >
1431 GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
1433 /* terminate oldest lookup */
1434 rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
1435 GNUNET_DHT_get_stop(rh_heap_root->get_handle);
1436 rh_heap_root->dht_heap_node = NULL;
1437 rh_heap_root->proc(rh_heap_root->proc_cls,
1442 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
1444 GNUNET_TIME_absolute_get().abs_value);
1447 xquery = htonl(GNUNET_GNS_RECORD_PKEY);
1449 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
1450 DHT_OPERATION_TIMEOUT,
1451 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1453 DHT_GNS_REPLICATION_LEVEL,
1457 &process_delegation_result_dht,
1464 * Namestore resolution for delegation finished. Processing result.
1466 * @param cls the closure
1467 * @param rh resolver handle
1468 * @param rd_count number of results (always 0)
1469 * @param rd record data (always NULL)
1472 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
1473 unsigned int rd_count,
1474 const struct GNUNET_NAMESTORE_RecordData *rd)
1476 struct RecordLookupHandle* rlh;
1477 rlh = (struct RecordLookupHandle*) cls;
1479 if (strcmp(rh->name, "") == 0)
1481 if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1483 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1484 "Resolved queried PKEY in NS.\n");
1485 finish_lookup(rh, rlh, rd_count, rd);
1486 free_resolver_handle(rh);
1489 /* We resolved full name for delegation. resolving record */
1490 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1491 "Resolved full name for delegation. resolving record '+'\n");
1492 strcpy(rh->name, "+\0");
1493 rh->proc = &handle_record_ns;
1494 resolve_record_ns(rh);
1499 * we still have some left
1500 * check if authority in ns is fresh
1502 * or we are authority
1504 if ((rh->status & (EXISTS | !EXPIRED)) ||
1505 !GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1506 &rh->authority_chain_tail->zone))
1508 if (is_canonical(rh->name))
1510 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1511 "Resolving canonical record %s\n", rh->name);
1512 rh->proc = &handle_record_ns;
1513 resolve_record_ns(rh);
1517 /* give up, cannot resolve */
1518 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1519 "Cannot fully resolve delegation for %s!\n",
1521 rlh->proc(rlh->proc_cls, 0, NULL);
1526 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1527 "Trying to resolve delegation for %s via DHT\n",
1529 rh->proc = &handle_delegation_dht;
1530 resolve_delegation_dht(rh);
1534 static void resolve_delegation_ns(struct ResolverHandle *rh);
1538 * This is a callback function that should give us only PKEY
1539 * records. Used to query the namestore for the authority (PKEY)
1540 * for 'name'. It will recursively try to resolve the
1541 * authority for a given name from the namestore.
1543 * @param cls the pending query
1544 * @param key the key of the zone we did the lookup
1545 * @param expiration expiration date of the record data set in the namestore
1546 * @param name the name for which we need an authority
1547 * @param rd_count the number of records with 'name'
1548 * @param rd the record data
1549 * @param signature the signature of the authority for the record data
1552 process_delegation_result_ns(void* cls,
1553 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1554 struct GNUNET_TIME_Absolute expiration,
1556 unsigned int rd_count,
1557 const struct GNUNET_NAMESTORE_RecordData *rd,
1558 const struct GNUNET_CRYPTO_RsaSignature *signature)
1560 struct ResolverHandle *rh;
1561 struct GNUNET_TIME_Relative remaining_time;
1562 struct GNUNET_CRYPTO_ShortHashCode zone;
1563 char new_name[MAX_DNS_NAME_LENGTH];
1565 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got %d records from authority lookup\n",
1568 rh = (struct ResolverHandle *)cls;
1569 GNUNET_CRYPTO_short_hash(key,
1570 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1572 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1578 rh->status |= EXISTS;
1581 if (remaining_time.rel_value == 0)
1583 rh->status |= EXPIRED;
1587 * No authority found in namestore.
1592 * We did not find an authority in the namestore
1597 * Promote this authority back to a name maybe it is
1600 if (strcmp(rh->name, "") == 0)
1602 /* simply promote back */
1603 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1604 "Promoting %s back to name\n", rh->authority_name);
1605 strcpy(rh->name, rh->authority_name);
1609 /* add back to existing name */
1610 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1611 "Adding %s back to %s\n",
1612 rh->authority_name, rh->name);
1613 memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
1614 strcpy(new_name, rh->name);
1615 strcpy(new_name+strlen(new_name)+1, ".");
1616 strcpy(new_name+strlen(new_name)+2, rh->authority_name);
1617 strcpy(rh->name, new_name);
1619 rh->proc(rh->proc_cls, rh, 0, NULL);
1624 * We found an authority that may be able to help us
1625 * move on with query
1626 * Note only 1 pkey should have been returned.. anything else would be strange
1629 for (i=0; i<rd_count;i++)
1632 if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
1635 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
1638 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This pkey is expired.\n");
1639 if (remaining_time.rel_value == 0)
1641 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1642 "This dht entry is expired.\n");
1643 rh->authority_chain_head->fresh = 0;
1644 rh->proc(rh->proc_cls, rh, 0, NULL);
1652 * Resolve rest of query with new authority
1654 GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
1655 memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1656 struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
1657 auth->zone = rh->authority;
1658 memset(auth->name, 0, strlen(rh->authority_name)+1);
1659 strcpy(auth->name, rh->authority_name);
1660 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1661 rh->authority_chain_tail,
1665 * We are done with PKEY resolution if name is empty
1666 * else resolve again with new authority
1668 if (strcmp(rh->name, "") == 0)
1669 rh->proc(rh->proc_cls, rh, 0, NULL);
1671 resolve_delegation_ns(rh);
1678 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1679 "Authority lookup successful but no PKEY... never get here\n");
1680 rh->proc(rh->proc_cls, rh, 0, NULL);
1685 * Resolve the delegation chain for the request in our namestore
1687 * @param rh the resolver handle
1690 resolve_delegation_ns(struct ResolverHandle *rh)
1692 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1693 "Resolving delegation for %s\n", rh->name);
1694 pop_tld(rh->name, rh->authority_name);
1695 GNUNET_NAMESTORE_lookup_record(namestore_handle,
1698 GNUNET_GNS_RECORD_PKEY,
1699 &process_delegation_result_ns,
1706 * Lookup of a record in a specific zone
1707 * calls lookup result processor on result
1709 * @param zone the root zone
1710 * @param record_type the record type to look up
1711 * @param name the name to look up
1712 * @param proc the processor to call on result
1713 * @param cls the closure to pass to proc
1716 gns_resolver_lookup_record(struct GNUNET_CRYPTO_ShortHashCode zone,
1717 uint32_t record_type,
1719 struct GNUNET_CRYPTO_RsaPrivateKey *key,
1720 struct GNUNET_TIME_Relative timeout,
1721 RecordLookupProcessor proc,
1724 struct ResolverHandle *rh;
1725 struct RecordLookupHandle* rlh;
1726 char string_hash[MAX_DNS_LABEL_LENGTH];
1728 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1729 "Starting resolution for %s (type=%d)!\n",
1733 if (is_canonical((char*)name) && (strcmp(GNUNET_GNS_TLD, name) != 0))
1735 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1736 "%s is canonical and not gnunet -> cannot resolve!\n", name);
1741 rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
1742 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1744 rh->authority = zone;
1747 rh->timeout = timeout;
1748 if (timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
1750 rh->timeout_task = GNUNET_SCHEDULER_add_delayed(timeout,
1751 &handle_lookup_timeout,
1753 rh->timeout_cont = &handle_auth_discovery_timeout;
1754 rh->timeout_cont_cls = rh;
1758 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1761 if (strcmp(GNUNET_GNS_TLD, name) == 0)
1764 * Only 'gnunet' given
1766 strcpy(rh->name, "\0");
1770 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1771 "Checking for TLD...\n");
1772 if (is_zkey_tld(name) == GNUNET_YES)
1774 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1777 * This is a zkey tld
1778 * build hash and use as initial authority
1781 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
1782 memcpy(rh->name, name,
1783 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
1784 pop_tld(rh->name, string_hash);
1786 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1787 "ZKEY is %s!\n", string_hash);
1789 if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(string_hash,
1792 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1793 "Cannot convert ZKEY %s to hash!\n", string_hash);
1803 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1806 * Presumably GNUNET tld
1809 strlen(name)-strlen(GNUNET_GNS_TLD));
1810 memcpy(rh->name, name,
1811 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
1816 * Initialize authority chain
1818 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1819 rh->authority_chain_head->prev = NULL;
1820 rh->authority_chain_head->next = NULL;
1821 rh->authority_chain_tail = rh->authority_chain_head;
1822 rh->authority_chain_head->zone = rh->authority;
1825 * Copy original query into lookup handle
1827 rlh->record_type = record_type;
1828 memset(rlh->name, 0, strlen(name) + 1);
1829 strcpy(rlh->name, name);
1831 rlh->proc_cls = cls;
1833 rh->proc = &handle_delegation_ns;
1834 resolve_delegation_ns(rh);
1837 /******** END Record Resolver ***********/
1841 * Callback calles by namestore for a zone to name
1844 * @param cls the closure
1845 * @param zone_key the zone we queried
1846 * @param expire the expiration time of the name
1847 * @param name the name found or NULL
1848 * @param rd_len number of records for the name
1849 * @param rd the record data (PKEY) for the name
1850 * @param signature the signature for the record data
1853 process_zone_to_name_shorten(void *cls,
1854 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1855 struct GNUNET_TIME_Absolute expire,
1857 unsigned int rd_len,
1858 const struct GNUNET_NAMESTORE_RecordData *rd,
1859 const struct GNUNET_CRYPTO_RsaSignature *signature)
1861 struct ResolverHandle *rh = (struct ResolverHandle *)cls;
1862 struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
1863 struct AuthorityChain *next_authority;
1865 char result[MAX_DNS_NAME_LENGTH];
1866 char next_authority_name[MAX_DNS_LABEL_LENGTH];
1869 /* we found a match in our own zone */
1872 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1873 "result strlen %d\n", strlen(name));
1874 answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
1875 memset(result, 0, answer_len);
1876 if (strlen(rh->name) > 0)
1878 strcpy(result, rh->name);
1879 strcpy(result+strlen(rh->name), ".");
1882 strcpy(result+strlen(result), name);
1883 strcpy(result+strlen(result), ".");
1884 strcpy(result+strlen(result), GNUNET_GNS_TLD);
1886 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1887 "Sending shorten result %s\n", result);
1889 nsh->proc(nsh->proc_cls, result);
1891 free_resolver_handle(rh);
1893 else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1894 &rh->authority_chain_tail->zone))
1896 /* our zone, just append .gnunet */
1897 answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
1898 memset(result, 0, answer_len);
1899 strcpy(result, rh->name);
1900 strcpy(result+strlen(rh->name), ".");
1901 strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
1903 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1904 "Our zone: Sending name as shorten result %s\n", rh->name);
1906 nsh->proc(nsh->proc_cls, result);
1908 free_resolver_handle(rh);
1914 * continue with next authority
1916 next_authority = rh->authority_chain_head;
1917 // strlen(next_authority->name) + 2);
1918 memset(next_authority_name, 0, strlen(rh->name)+
1919 strlen(next_authority->name) + 2);
1920 strcpy(next_authority_name, rh->name);
1921 strcpy(next_authority_name+strlen(rh->name)+1, ".");
1922 strcpy(next_authority_name+strlen(rh->name)+2, next_authority->name);
1924 strcpy(rh->name, next_authority_name);
1925 GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
1926 rh->authority_chain_tail,
1929 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1930 &rh->authority_chain_tail->zone,
1931 &rh->authority_chain_head->zone,
1932 &process_zone_to_name_shorten,
1939 * Process result from namestore delegation lookup
1940 * for shorten operation
1942 * @param cls the client shorten handle
1943 * @param rh the resolver handle
1944 * @param rd_count number of results (0)
1945 * @param rd data (NULL)
1948 handle_delegation_ns_shorten(void* cls,
1949 struct ResolverHandle *rh,
1951 const struct GNUNET_NAMESTORE_RecordData *rd)
1953 struct NameShortenHandle *nsh;
1954 char result[MAX_DNS_NAME_LENGTH];
1957 nsh = (struct NameShortenHandle *)cls;
1960 * At this point rh->name contains the part of the name
1961 * that we do not have a PKEY in our namestore to resolve.
1962 * The authority chain in the resolver handle is now
1963 * useful to backtrack if needed
1966 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1967 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
1969 if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1970 &rh->authority_chain_tail->zone) == 0)
1973 * This is our zone append .gnunet unless name is empty
1974 * (it shouldn't be, usually FIXME what happens if we
1975 * shorten to our zone to a "" record??)
1978 answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
1979 memset(result, 0, answer_len);
1980 strcpy(result, rh->name);
1981 strcpy(result+strlen(rh->name), ".");
1982 strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
1984 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1985 "Our zone: Sending name as shorten result %s\n", rh->name);
1987 nsh->proc(nsh->proc_cls, result);
1989 free_resolver_handle(rh);
1993 /* backtrack authorities for names */
1994 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1995 &rh->authority_chain_tail->zone, //ours
1996 &rh->authority_chain_head->zone,
1997 &process_zone_to_name_shorten,
2003 * Shorten api from resolver
2005 * @param zone the zone to use
2006 * @param name the name to shorten
2007 * @param proc the processor to call with result
2008 * @param cls closure to pass to proc
2011 gns_resolver_shorten_name(struct GNUNET_CRYPTO_ShortHashCode zone,
2013 ShortenResultProcessor proc,
2016 struct ResolverHandle *rh;
2017 struct NameShortenHandle *nsh;
2018 char string_hash[MAX_DNS_NAME_LENGTH]; //FIXME LABEL length when shorthash
2020 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2021 "Starting shorten for %s!\n", name);
2023 if (is_canonical((char*)name))
2025 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2026 "%s is canonical. Returning verbatim\n", name);
2031 nsh = GNUNET_malloc(sizeof (struct NameShortenHandle));
2035 nsh->proc_cls = cls;
2037 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2038 rh->authority = zone;
2040 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2041 "Checking for TLD...\n");
2042 if (is_zkey_tld(name) == GNUNET_YES)
2044 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2047 * This is a zkey tld
2048 * build hash and use as initial authority
2051 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
2052 memcpy(rh->name, name,
2053 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
2054 pop_tld(rh->name, string_hash);
2056 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2057 "ZKEY is %s!\n", string_hash);
2059 if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(string_hash,
2062 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2063 "Cannot convert ZKEY %s to hash!\n", string_hash);
2073 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2076 * Presumably GNUNET tld
2079 strlen(name)-strlen(GNUNET_GNS_TLD));
2080 memcpy(rh->name, name,
2081 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2084 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2085 rh->authority_chain_tail = rh->authority_chain_head;
2086 rh->authority_chain_head->zone = zone;
2087 rh->proc = &handle_delegation_ns_shorten;
2090 /* Start delegation resolution in our namestore */
2091 resolve_delegation_ns(rh);
2094 /*********** END NAME SHORTEN ********************/
2098 * Process result from namestore delegation lookup
2099 * for get authority operation
2101 * @param cls the client get auth handle
2102 * @param rh the resolver handle
2103 * @param rd_count number of results (0)
2104 * @param rd data (NULL)
2107 handle_delegation_result_ns_get_auth(void* cls,
2108 struct ResolverHandle *rh,
2110 const struct GNUNET_NAMESTORE_RecordData *rd)
2112 struct GetNameAuthorityHandle* nah;
2113 char result[MAX_DNS_NAME_LENGTH];
2116 nah = (struct GetNameAuthorityHandle*) rh->proc_cls;
2119 * At this point rh->name contains the part of the name
2120 * that we do not have a PKEY in our namestore to resolve.
2121 * The authority chain in the resolver handle is now
2122 * useful to backtrack if needed
2125 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2126 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2128 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2129 "Building response!\n");
2130 if (is_canonical(rh->name))
2133 * We successfully resolved the authority in the ns
2134 * FIXME for our purposes this is fine
2135 * but maybe we want to have an api that also looks
2136 * into the dht (i.e. option in message)
2138 if (strlen(rh->name) > strlen(nah->name))
2140 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2141 "Record name longer than original lookup name... odd!\n");
2145 answer_len = strlen(nah->name) - strlen(rh->name)
2146 + strlen(GNUNET_GNS_TLD) + 1;
2147 memset(result, 0, answer_len);
2148 strcpy(result, nah->name + strlen(rh->name) + 1);
2150 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2151 "Got authority result %s\n", result);
2153 nah->proc(nah->proc_cls, result);
2155 free_resolver_handle(rh);
2159 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2160 "Unable to resolve authority for remaining %s!\n", rh->name);
2161 nah->proc(nah->proc_cls, "");
2163 free_resolver_handle(rh);
2171 * Tries to resolve the authority for name
2174 * @param zone the root zone to look up for
2175 * @param name the name to lookup up
2176 * @param proc the processor to call when finished
2177 * @param cls the closure to pass to the processor
2180 gns_resolver_get_authority(struct GNUNET_CRYPTO_ShortHashCode zone,
2182 GetAuthorityResultProcessor proc,
2185 struct ResolverHandle *rh;
2186 struct GetNameAuthorityHandle *nah;
2188 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2189 "Starting authority resolution for %s!\n", name);
2191 nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
2192 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2193 rh->authority = zone;
2195 if (strcmp(GNUNET_GNS_TLD, name) == 0)
2197 strcpy(rh->name, "\0");
2202 strlen(name)-strlen(GNUNET_GNS_TLD));
2203 memcpy(rh->name, name,
2204 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2207 memset(nah->name, 0,
2209 strcpy(nah->name, name);
2211 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2212 rh->authority_chain_tail = rh->authority_chain_head;
2213 rh->authority_chain_head->zone = zone;
2214 rh->proc = &handle_delegation_result_ns_get_auth;
2215 rh->proc_cls = (void*)nah;
2218 nah->proc_cls = cls;
2220 /* Start delegation resolution in our namestore */
2221 resolve_delegation_ns(rh);
2225 /******** END GET AUTHORITY *************/
2227 /* end of gnunet-service-gns_resolver.c */