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, gph->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 our_zone our local zone
354 * @param the private key of our authority
356 static void process_discovered_authority(char* name,
357 struct GNUNET_CRYPTO_ShortHashCode zone,
358 struct GNUNET_CRYPTO_ShortHashCode our_zone,
359 struct GNUNET_CRYPTO_RsaPrivateKey *key)
361 struct GetPseuAuthorityHandle *gph;
364 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "New authority %s discovered\n",
367 gph = GNUNET_malloc(sizeof(struct GetPseuAuthorityHandle));
368 namelen = strlen(name) + 1;
369 memcpy(gph->name, name, namelen);
371 gph->new_zone = zone;
372 gph->zone = our_zone;
375 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
378 &process_zone_to_name_discover,
384 * Initialize the resolver
386 * @param nh the namestore handle
387 * @param dh the dht handle
388 * @param lz the local zone's hash
389 * @return GNUNET_OK on success
392 gns_resolver_init(struct GNUNET_NAMESTORE_Handle *nh,
393 struct GNUNET_DHT_Handle *dh,
394 struct GNUNET_CRYPTO_ShortHashCode lz,
395 unsigned long long max_bg_queries)
397 namestore_handle = nh;
401 GNUNET_CONTAINER_heap_create(GNUNET_CONTAINER_HEAP_ORDER_MIN);
402 max_allowed_background_queries = max_bg_queries;
404 if ((namestore_handle != NULL) && (dht_handle != NULL))
408 return GNUNET_SYSERR;
412 * Cleanup background lookups
414 * @param cks closure to iterator
415 * @param node heap nodes
416 * @param element the resolver handle
417 * @param cost heap cost
418 * @return always GNUNET_YES
421 cleanup_pending_background_queries(void* cls,
422 struct GNUNET_CONTAINER_HeapNode *node,
424 GNUNET_CONTAINER_HeapCostType cost)
426 struct ResolverHandle *rh = (struct ResolverHandle *)element;
428 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
429 "Terminating background lookup for %s\n",
431 GNUNET_DHT_get_stop(rh->get_handle);
432 rh->proc(rh->proc_cls, rh, 0, NULL);
442 gns_resolver_cleanup()
444 if (0 != GNUNET_CONTAINER_heap_get_size(dht_lookup_heap))
446 GNUNET_CONTAINER_heap_iterate (dht_lookup_heap,
447 &cleanup_pending_background_queries,
454 * Helper function to free resolver handle
456 * @param rh the handle to free
459 free_resolver_handle(struct ResolverHandle* rh)
461 struct AuthorityChain *ac;
462 struct AuthorityChain *ac_next;
467 ac = rh->authority_chain_head;
480 * Callback when record data is put into namestore
482 * @param cls the closure
483 * @param success GNUNET_OK on success
484 * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
487 on_namestore_record_put_result(void *cls,
491 if (GNUNET_NO == success)
493 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "records already in namestore\n");
496 else if (GNUNET_YES == success)
498 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
499 "records successfully put in namestore\n");
503 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
504 "Error putting records into namestore: %s\n", emsg);
508 handle_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
510 struct ResolverHandle *rh = cls;
512 if (rh->timeout_cont)
513 rh->timeout_cont(rh->timeout_cont_cls, tc);
517 * Processor for background lookups in the DHT
519 * @param cls closure (NULL)
520 * @param rd_count number of records found (not 0)
521 * @param rd record data
524 background_lookup_result_processor(void *cls,
526 const struct GNUNET_NAMESTORE_RecordData *rd)
528 //We could do sth verbose/more useful here but it doesn't make any difference
529 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
530 "background dht lookup finished.\n");
534 * Handle timeout for DHT requests
536 * @param cls the request handle as closure
537 * @param tc the task context
540 dht_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
542 struct ResolverHandle *rh = cls;
543 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
544 char new_name[MAX_DNS_NAME_LENGTH];
546 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
547 "dht lookup for query %s timed out.\n",
550 * Start resolution in bg
552 //strcpy(new_name, rh->name);
553 //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD));
554 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
555 rh->name, GNUNET_GNS_TLD);
557 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
558 "Starting background lookup for %s type %d\n",
559 new_name, rlh->record_type);
561 gns_resolver_lookup_record(rh->authority,
565 GNUNET_TIME_UNIT_FOREVER_REL,
566 &background_lookup_result_processor,
569 GNUNET_DHT_get_stop (rh->get_handle);
570 rh->proc(rh->proc_cls, rh, 0, NULL);
575 * Function called when we get a result from the dht
576 * for our record query
578 * @param cls the request handle
579 * @param exp lifetime
580 * @param key the key the record was stored under
581 * @param get_path get path
582 * @param get_path_length get path length
583 * @param put_path put path
584 * @param put_path_length put path length
585 * @param type the block type
586 * @param size the size of the record
587 * @param data the record data
590 process_record_result_dht(void* cls,
591 struct GNUNET_TIME_Absolute exp,
592 const GNUNET_HashCode * key,
593 const struct GNUNET_PeerIdentity *get_path,
594 unsigned int get_path_length,
595 const struct GNUNET_PeerIdentity *put_path,
596 unsigned int put_path_length,
597 enum GNUNET_BLOCK_Type type,
598 size_t size, const void *data)
600 struct ResolverHandle *rh;
601 struct RecordLookupHandle *rlh;
602 struct GNSNameRecordBlock *nrb;
603 uint32_t num_records;
605 char* rd_data = (char*)data;
609 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "got dht result (size=%d)\n", size);
614 //FIXME maybe check expiration here, check block type
616 rh = (struct ResolverHandle *)cls;
617 rlh = (struct RecordLookupHandle *) rh->proc_cls;
618 nrb = (struct GNSNameRecordBlock*)data;
620 /* stop lookup and timeout task */
621 GNUNET_DHT_get_stop (rh->get_handle);
623 if (rh->dht_heap_node != NULL)
625 GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
626 rh->dht_heap_node = NULL;
629 if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
630 GNUNET_SCHEDULER_cancel(rh->timeout_task);
632 rh->get_handle = NULL;
633 name = (char*)&nrb[1];
634 num_records = ntohl(nrb->rd_count);
636 struct GNUNET_NAMESTORE_RecordData rd[num_records];
638 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
639 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
641 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
646 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
650 for (i=0; i<num_records; i++)
652 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
653 "Got name: %s (wanted %s)\n", name, rh->name);
654 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
657 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
658 "Got data length: %d\n", rd[i].data_size);
659 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
660 "Got flag %d\n", rd[i].flags);
662 if ((strcmp(name, rh->name) == 0) &&
663 (rd[i].record_type == rlh->record_type))
671 * FIXME check pubkey against existing key in namestore?
672 * https://gnunet.org/bugs/view.php?id=2179
675 /* Save to namestore */
676 GNUNET_NAMESTORE_record_put (namestore_handle,
683 &on_namestore_record_put_result, //cont
688 rh->proc(rh->proc_cls, rh, num_records, rd);
690 rh->proc(rh->proc_cls, rh, 0, NULL);
697 * Start DHT lookup for a (name -> query->record_type) record in
698 * rh->authority's zone
700 * @param rh the pending gns query context
703 resolve_record_dht(struct ResolverHandle *rh)
706 struct GNUNET_CRYPTO_ShortHashCode name_hash;
707 GNUNET_HashCode lookup_key;
708 GNUNET_HashCode name_hash_double;
709 GNUNET_HashCode zone_hash_double;
710 struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
711 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
712 struct ResolverHandle *rh_heap_root;
714 GNUNET_CRYPTO_short_hash(rh->name, strlen(rh->name), &name_hash);
715 GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
716 GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
717 GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
718 GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
720 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
721 "starting dht lookup for %s with key: %s\n",
722 rh->name, (char*)&lookup_key_string);
724 //rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
725 rh->dht_heap_node = NULL;
727 if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
730 * Update timeout if necessary
732 if (rh->timeout_task == GNUNET_SCHEDULER_NO_TASK)
735 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
736 "Adjusting timeout\n");
738 * Set timeout for authority lookup phase to 1/2
740 rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
741 GNUNET_TIME_relative_divide(rh->timeout, 2),
742 &handle_lookup_timeout,
745 //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
746 // &dht_lookup_timeout,
748 rh->timeout_cont = &dht_lookup_timeout;
749 rh->timeout_cont_cls = rh;
753 if (max_allowed_background_queries <=
754 GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
756 rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
757 GNUNET_DHT_get_stop(rh_heap_root->get_handle);
758 rh_heap_root->dht_heap_node = NULL;
759 rh_heap_root->proc(rh_heap_root->proc_cls,
764 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
766 GNUNET_TIME_absolute_get().abs_value);
769 xquery = htonl(rlh->record_type);
770 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
771 GNUNET_TIME_UNIT_FOREVER_REL,
772 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
774 DHT_GNS_REPLICATION_LEVEL,
778 &process_record_result_dht,
785 * Namestore calls this function if we have record for this name.
786 * (or with rd_count=0 to indicate no matches)
788 * @param cls the pending query
789 * @param key the key of the zone we did the lookup
790 * @param expiration expiration date of the namestore entry
791 * @param name the name for which we need an authority
792 * @param rd_count the number of records with 'name'
793 * @param rd the record data
794 * @param signature the signature of the authority for the record data
797 process_record_result_ns(void* cls,
798 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
799 struct GNUNET_TIME_Absolute expiration,
800 const char *name, unsigned int rd_count,
801 const struct GNUNET_NAMESTORE_RecordData *rd,
802 const struct GNUNET_CRYPTO_RsaSignature *signature)
804 struct ResolverHandle *rh;
805 struct RecordLookupHandle *rlh;
806 struct GNUNET_TIME_Relative remaining_time;
807 struct GNUNET_CRYPTO_ShortHashCode zone;
809 rh = (struct ResolverHandle *) cls;
810 rlh = (struct RecordLookupHandle *)rh->proc_cls;
811 GNUNET_CRYPTO_short_hash(key,
812 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
814 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
816 if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
817 GNUNET_SCHEDULER_cancel(rh->timeout_task);
823 rh->status |= EXISTS;
826 if (remaining_time.rel_value == 0)
828 rh->status |= EXPIRED;
834 * Lookup terminated and no results
836 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
837 "Namestore lookup for %s terminated without results\n", name);
839 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
840 "Record %s unknown in namestore\n",
843 * Our zone and no result? Cannot resolve TT
845 rh->proc(rh->proc_cls, rh, 0, NULL);
852 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
853 "Processing additional result %s from namestore\n", name);
855 for (i=0; i<rd_count;i++)
858 if (rd[i].record_type != rlh->record_type)
861 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
864 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
865 "This record is expired. Skipping\n");
876 if (rh->answered == 0)
878 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
879 "No answers found. This is odd!\n");
880 rh->proc(rh->proc_cls, rh, 0, NULL);
884 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
885 "Found %d answer(s) to query in %d records!\n",
886 rh->answered, rd_count);
888 rh->proc(rh->proc_cls, rh, rd_count, rd);
894 * The final phase of resolution.
895 * rh->name is a name that is canonical and we do not have a delegation.
896 * Query namestore for this record
898 * @param rh the pending lookup
901 resolve_record_ns(struct ResolverHandle *rh)
903 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
906 * Try to resolve this record in our namestore.
907 * The name to resolve is now in rh->authority_name
908 * since we tried to resolve it to an authority
911 GNUNET_NAMESTORE_lookup_record(namestore_handle,
915 &process_record_result_ns,
922 * Handle timeout for DHT requests
924 * @param cls the request handle as closure
925 * @param tc the task context
928 dht_authority_lookup_timeout(void *cls,
929 const struct GNUNET_SCHEDULER_TaskContext *tc)
931 struct ResolverHandle *rh = cls;
932 struct RecordLookupHandle *rlh = rh->proc_cls;
933 char new_name[MAX_DNS_NAME_LENGTH];
935 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
936 "dht lookup for query %s timed out.\n",
939 rh->status |= TIMED_OUT;
942 if (strcmp(rh->name, "") == 0)
945 * promote authority back to name and try to resolve record
947 strcpy(rh->name, rh->authority_name);
948 rh->proc(rh->proc_cls, rh, 0, NULL);
953 * Start resolution in bg
955 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH,
956 "%s.%s", rh->name, GNUNET_GNS_TLD);
957 //strcpy(new_name, rh->name);
958 //strcpy(new_name+strlen(new_name), ".");
959 //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD));
961 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
962 "Starting background query for %s type %d\n",
963 new_name, rlh->record_type);
965 gns_resolver_lookup_record(rh->authority,
969 GNUNET_TIME_UNIT_FOREVER_REL,
970 &background_lookup_result_processor,
973 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
974 "Terminating auth lookup\n");
976 GNUNET_DHT_get_stop (rh->get_handle);
978 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
980 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
981 "Terminating auth lookup\n");
983 rh->proc(rh->proc_cls, rh, 0, NULL);
987 static void resolve_delegation_dht(struct ResolverHandle *rh);
990 * Function called when we get a result from the dht
991 * for our query. Recursively tries to resolve authorities
994 * @param cls the request handle
995 * @param exp lifetime
996 * @param key the key the record was stored under
997 * @param get_path get path
998 * @param get_path_length get path length
999 * @param put_path put path
1000 * @param put_path_length put path length
1001 * @param type the block type
1002 * @param size the size of the record
1003 * @param data the record data
1006 process_delegation_result_dht(void* cls,
1007 struct GNUNET_TIME_Absolute exp,
1008 const GNUNET_HashCode * key,
1009 const struct GNUNET_PeerIdentity *get_path,
1010 unsigned int get_path_length,
1011 const struct GNUNET_PeerIdentity *put_path,
1012 unsigned int put_path_length,
1013 enum GNUNET_BLOCK_Type type,
1014 size_t size, const void *data)
1016 struct ResolverHandle *rh;
1017 struct GNSNameRecordBlock *nrb;
1018 uint32_t num_records;
1020 char* rd_data = (char*) data;
1023 struct GNUNET_CRYPTO_ShortHashCode zone, name_hash;
1024 GNUNET_HashCode zone_hash_double, name_hash_double;
1026 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got DHT result\n");
1031 //FIXME check expiration?
1033 rh = (struct ResolverHandle *)cls;
1034 nrb = (struct GNSNameRecordBlock*)data;
1036 /* stop dht lookup and timeout task */
1037 GNUNET_DHT_get_stop (rh->get_handle);
1039 rh->get_handle = NULL;
1041 if (rh->dht_heap_node != NULL)
1043 GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
1044 rh->dht_heap_node = NULL;
1047 num_records = ntohl(nrb->rd_count);
1048 name = (char*)&nrb[1];
1050 struct GNUNET_NAMESTORE_RecordData rd[num_records];
1052 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
1053 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
1055 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
1060 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
1064 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1065 "Got name: %s (wanted %s)\n", name, rh->authority_name);
1066 for (i=0; i<num_records; i++)
1069 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1070 "Got name: %s (wanted %s)\n", name, rh->authority_name);
1071 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1072 "Got type: %d (wanted %d)\n",
1073 rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
1074 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1075 "Got data length: %d\n", rd[i].data_size);
1076 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1077 "Got flag %d\n", rd[i].flags);
1079 if ((strcmp(name, rh->authority_name) == 0) &&
1080 (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
1082 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Authority found in DHT\n");
1084 memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1085 struct AuthorityChain *auth =
1086 GNUNET_malloc(sizeof(struct AuthorityChain));
1087 auth->zone = rh->authority;
1088 memset(auth->name, 0, strlen(rh->authority_name)+1);
1089 strcpy(auth->name, rh->authority_name);
1090 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1091 rh->authority_chain_tail,
1094 /** try to import pkey if private key available */
1096 process_discovered_authority(name, auth->zone,
1097 rh->authority_chain_tail->zone,
1104 GNUNET_CRYPTO_short_hash(name, strlen(name), &name_hash);
1105 GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1106 GNUNET_CRYPTO_hash_xor(key, &name_hash_double, &zone_hash_double);
1107 GNUNET_CRYPTO_short_hash_from_truncation (&zone_hash_double, &zone);
1109 /* Save to namestore */
1110 if (0 != GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_tail->zone,
1113 GNUNET_NAMESTORE_record_put (namestore_handle,
1120 &on_namestore_record_put_result, //cont
1130 * FIXME in this case. should we ask namestore again?
1132 if (strcmp(rh->name, "") == 0)
1133 rh->proc(rh->proc_cls, rh, 0, NULL);
1135 resolve_delegation_dht(rh);
1140 * No pkey but name exists
1142 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "DHT authority lookup found no match!\n");
1143 rh->proc(rh->proc_cls, rh, 0, NULL);
1146 #define MAX_SOA_LENGTH sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)\
1147 +(MAX_DNS_NAME_LENGTH*2)
1148 #define MAX_MX_LENGTH sizeof(uint16_t)+MAX_DNS_NAME_LENGTH
1152 expand_plus(char** dest, char* src, char* repl)
1155 unsigned int s_len = strlen(src)+1;
1157 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1158 "Got %s to expand with %s\n", src, repl);
1162 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1163 "%s to short\n", src);
1165 /* no postprocessing */
1166 memcpy(*dest, src, s_len+1);
1170 if (0 == strcmp(src+s_len-3, ".+"))
1172 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1173 "Expanding .+ in %s\n", src);
1174 memset(*dest, 0, s_len+strlen(repl)+strlen(GNUNET_GNS_TLD));
1176 pos = *dest+s_len-2;
1178 pos += strlen(repl);
1179 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1180 "Expanded to %s\n", *dest);
1184 memcpy(*dest, src, s_len+1);
1192 finish_lookup(struct ResolverHandle *rh,
1193 struct RecordLookupHandle* rlh,
1194 unsigned int rd_count,
1195 const struct GNUNET_NAMESTORE_RecordData *rd)
1198 char new_rr_data[MAX_DNS_NAME_LENGTH];
1199 char new_mx_data[MAX_MX_LENGTH];
1200 char new_soa_data[MAX_SOA_LENGTH];
1201 struct GNUNET_NAMESTORE_RecordData p_rd[rd_count];
1204 unsigned int offset;
1207 memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData));
1209 for (i = 0; i < rd_count; i++)
1212 if (rd[i].record_type != GNUNET_GNS_RECORD_TYPE_NS &&
1213 rd[i].record_type != GNUNET_GNS_RECORD_TYPE_CNAME &&
1214 rd[i].record_type != GNUNET_GNS_RECORD_MX &&
1215 rd[i].record_type != GNUNET_GNS_RECORD_TYPE_SOA)
1217 p_rd[i].data = rd[i].data;
1222 * for all those records we 'should'
1223 * also try to resolve the A/AAAA records (RFC1035)
1224 * This is a feature and not important
1227 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1228 "Postprocessing\n");
1230 if (strcmp(rh->name, "+") == 0)
1231 repl_string = rlh->name;
1233 repl_string = rlh->name+strlen(rh->name)+1;
1236 if (rd[i].record_type == GNUNET_GNS_RECORD_MX)
1238 memcpy(new_mx_data, (char*)rd[i].data, sizeof(uint16_t));
1239 offset = sizeof(uint16_t);
1240 pos = new_mx_data+offset;
1241 expand_plus(&pos, (char*)rd[i].data+sizeof(uint16_t),
1243 offset += strlen(new_mx_data+sizeof(uint16_t))+1;
1244 p_rd[i].data = new_mx_data;
1245 p_rd[i].data_size = offset;
1247 else if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_SOA)
1249 /* expand mname and rname */
1251 expand_plus(&pos, (char*)rd[i].data, repl_string);
1252 offset = strlen(new_soa_data)+1;
1253 pos = new_soa_data+offset;
1254 expand_plus(&pos, (char*)rd[i].data+offset, repl_string);
1255 offset += strlen(new_soa_data+offset)+1;
1256 /* cpy the 4 numbers serial refresh retry and expire */
1257 memcpy(new_soa_data+offset, (char*)rd[i].data+offset, sizeof(uint32_t)*4);
1258 offset += sizeof(uint32_t)*4;
1259 p_rd[i].data_size = offset;
1260 p_rd[i].data = new_soa_data;
1265 expand_plus(&pos, (char*)rd[i].data, repl_string);
1266 p_rd[i].data_size = strlen(new_rr_data)+1;
1267 p_rd[i].data = new_rr_data;
1272 rlh->proc(rlh->proc_cls, rd_count, p_rd);
1278 * Process DHT lookup result for record.
1280 * @param cls the closure
1281 * @param rh resolver handle
1282 * @param rd_count number of results
1283 * @param rd record data
1286 handle_record_dht(void* cls, struct ResolverHandle *rh,
1287 unsigned int rd_count,
1288 const struct GNUNET_NAMESTORE_RecordData *rd)
1290 struct RecordLookupHandle* rlh;
1292 rlh = (struct RecordLookupHandle*)cls;
1295 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1296 "No records for %s found in DHT. Aborting\n",
1298 /* give up, cannot resolve */
1299 finish_lookup(rh, rlh, 0, NULL);
1300 free_resolver_handle(rh);
1304 /* results found yay */
1305 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1306 "Record resolved from DHT!");
1308 finish_lookup(rh, rlh, rd_count, rd);
1309 free_resolver_handle(rh);
1315 * Process namestore lookup result for record.
1317 * @param cls the closure
1318 * @param rh resolver handle
1319 * @param rd_count number of results
1320 * @param rd record data
1323 handle_record_ns(void* cls, struct ResolverHandle *rh,
1324 unsigned int rd_count,
1325 const struct GNUNET_NAMESTORE_RecordData *rd)
1327 struct RecordLookupHandle* rlh;
1328 rlh = (struct RecordLookupHandle*) cls;
1331 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Resolution status: %d!\n", rh->status);
1333 /* ns entry expired and not ours. try dht */
1334 if (rh->status & (EXPIRED | !EXISTS) &&
1335 GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1338 rh->proc = &handle_record_dht;
1339 resolve_record_dht(rh);
1342 /* give up, cannot resolve */
1343 finish_lookup(rh, rlh, 0, NULL);
1344 free_resolver_handle(rh);
1348 /* results found yay */
1349 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1350 "Record resolved from namestore!");
1352 finish_lookup(rh, rlh, rd_count, rd);
1354 free_resolver_handle(rh);
1360 * Determine if this name is canonical.
1362 * a.b.gnunet = not canonical
1365 * @param name the name to test
1366 * @return 1 if canonical
1369 is_canonical(char* name)
1371 uint32_t len = strlen(name);
1374 for (i=0; i<len; i++)
1376 if (*(name+i) == '.')
1383 * Move one level up in the domain hierarchy and return the
1384 * passed top level domain.
1386 * @param name the domain
1387 * @param dest the destination where the tld will be put
1390 pop_tld(char* name, char* dest)
1394 if (is_canonical(name))
1401 for (len = strlen(name); len > 0; len--)
1403 if (*(name+len) == '.')
1413 strcpy(dest, (name+len+1));
1417 * Checks if name is in tld
1419 * @param name the name to check
1420 * @param tld the TLD to check for
1421 * @return GNUNET_YES or GNUNET_NO
1424 is_tld(const char* name, const char* tld)
1428 if (strlen(name) <= strlen(tld))
1433 offset = strlen(name)-strlen(tld);
1434 if (strcmp(name+offset, tld) != 0)
1436 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1437 "%s is not in .%s TLD\n", name, tld);
1444 * DHT resolution for delegation finished. Processing result.
1446 * @param cls the closure
1447 * @param rh resolver handle
1448 * @param rd_count number of results (always 0)
1449 * @param rd record data (always NULL)
1452 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
1453 unsigned int rd_count,
1454 const struct GNUNET_NAMESTORE_RecordData *rd)
1456 struct RecordLookupHandle* rlh;
1457 rlh = (struct RecordLookupHandle*) cls;
1461 if (strcmp(rh->name, "") == 0)
1463 if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1465 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1466 "Resolved queried PKEY via DHT.\n");
1467 finish_lookup(rh, rlh, rd_count, rd);
1468 free_resolver_handle(rh);
1471 /* We resolved full name for delegation. resolving record */
1472 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1473 "Resolved full name for delegation via DHT. resolving record '' in ns\n");
1474 strcpy(rh->name, "+\0");
1475 rh->proc = &handle_record_ns;
1476 resolve_record_ns(rh);
1481 * we still have some left
1483 if (is_canonical(rh->name))
1485 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1486 "Resolving canonical record %s in ns\n", rh->name);
1487 rh->proc = &handle_record_ns;
1488 resolve_record_ns(rh);
1491 /* give up, cannot resolve */
1492 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1493 "Cannot fully resolve delegation for %s via DHT!\n",
1495 finish_lookup(rh, rlh, 0, NULL);
1496 free_resolver_handle(rh);
1501 * Start DHT lookup for a name -> PKEY (compare NS) record in
1502 * rh->authority's zone
1504 * @param rh the pending gns query
1507 resolve_delegation_dht(struct ResolverHandle *rh)
1510 struct GNUNET_CRYPTO_ShortHashCode name_hash;
1511 GNUNET_HashCode name_hash_double;
1512 GNUNET_HashCode zone_hash_double;
1513 GNUNET_HashCode lookup_key;
1514 struct ResolverHandle *rh_heap_root;
1516 GNUNET_CRYPTO_short_hash(rh->authority_name,
1517 strlen(rh->authority_name),
1519 GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1520 GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
1521 GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
1523 rh->dht_heap_node = NULL;
1525 if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
1527 //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1528 // &dht_authority_lookup_timeout,
1530 rh->timeout_cont = &dht_authority_lookup_timeout;
1531 rh->timeout_cont_cls = rh;
1535 if (max_allowed_background_queries <=
1536 GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
1538 /* terminate oldest lookup */
1539 rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
1540 GNUNET_DHT_get_stop(rh_heap_root->get_handle);
1541 rh_heap_root->dht_heap_node = NULL;
1542 rh_heap_root->proc(rh_heap_root->proc_cls,
1547 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
1549 GNUNET_TIME_absolute_get().abs_value);
1552 xquery = htonl(GNUNET_GNS_RECORD_PKEY);
1554 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
1555 GNUNET_TIME_UNIT_FOREVER_REL,
1556 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1558 DHT_GNS_REPLICATION_LEVEL,
1562 &process_delegation_result_dht,
1569 * Namestore resolution for delegation finished. Processing result.
1571 * @param cls the closure
1572 * @param rh resolver handle
1573 * @param rd_count number of results (always 0)
1574 * @param rd record data (always NULL)
1577 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
1578 unsigned int rd_count,
1579 const struct GNUNET_NAMESTORE_RecordData *rd)
1581 struct RecordLookupHandle* rlh;
1582 rlh = (struct RecordLookupHandle*) cls;
1584 if (strcmp(rh->name, "") == 0)
1586 if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1588 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1589 "Resolved queried PKEY in NS.\n");
1590 finish_lookup(rh, rlh, rd_count, rd);
1591 free_resolver_handle(rh);
1594 /* We resolved full name for delegation. resolving record */
1595 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1596 "Resolved full name for delegation. resolving record '+'\n");
1597 strcpy(rh->name, "+\0");
1598 rh->proc = &handle_record_ns;
1599 resolve_record_ns(rh);
1604 * we still have some left
1605 * check if authority in ns is fresh
1607 * or we are authority
1609 if ((rh->status & (EXISTS | !EXPIRED)) ||
1610 !GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1611 &rh->authority_chain_tail->zone))
1613 if (is_canonical(rh->name))
1615 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1616 "Resolving canonical record %s\n", rh->name);
1617 rh->proc = &handle_record_ns;
1618 resolve_record_ns(rh);
1622 /* give up, cannot resolve */
1623 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1624 "Cannot fully resolve delegation for %s!\n",
1626 rlh->proc(rlh->proc_cls, 0, NULL);
1631 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1632 "Trying to resolve delegation for %s via DHT\n",
1634 rh->proc = &handle_delegation_dht;
1635 resolve_delegation_dht(rh);
1639 static void resolve_delegation_ns(struct ResolverHandle *rh);
1643 * This is a callback function that should give us only PKEY
1644 * records. Used to query the namestore for the authority (PKEY)
1645 * for 'name'. It will recursively try to resolve the
1646 * authority for a given name from the namestore.
1648 * @param cls the pending query
1649 * @param key the key of the zone we did the lookup
1650 * @param expiration expiration date of the record data set in the namestore
1651 * @param name the name for which we need an authority
1652 * @param rd_count the number of records with 'name'
1653 * @param rd the record data
1654 * @param signature the signature of the authority for the record data
1657 process_delegation_result_ns(void* cls,
1658 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1659 struct GNUNET_TIME_Absolute expiration,
1661 unsigned int rd_count,
1662 const struct GNUNET_NAMESTORE_RecordData *rd,
1663 const struct GNUNET_CRYPTO_RsaSignature *signature)
1665 struct ResolverHandle *rh;
1666 struct GNUNET_TIME_Relative remaining_time;
1667 struct GNUNET_CRYPTO_ShortHashCode zone;
1668 char new_name[MAX_DNS_NAME_LENGTH];
1670 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got %d records from authority lookup\n",
1673 rh = (struct ResolverHandle *)cls;
1674 GNUNET_CRYPTO_short_hash(key,
1675 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1677 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1683 rh->status |= EXISTS;
1686 if (remaining_time.rel_value == 0)
1688 rh->status |= EXPIRED;
1692 * No authority found in namestore.
1697 * We did not find an authority in the namestore
1702 * Promote this authority back to a name maybe it is
1705 if (strcmp(rh->name, "") == 0)
1707 /* simply promote back */
1708 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1709 "Promoting %s back to name\n", rh->authority_name);
1710 strcpy(rh->name, rh->authority_name);
1714 /* add back to existing name */
1715 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1716 "Adding %s back to %s\n",
1717 rh->authority_name, rh->name);
1718 //memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
1719 strcpy(new_name, rh->name);
1720 strcpy(new_name+strlen(new_name), ".");
1721 strcpy(new_name+strlen(new_name), rh->authority_name);
1722 strcpy(rh->name, new_name);
1723 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1724 "%s restored\n", rh->name);
1726 rh->proc(rh->proc_cls, rh, 0, NULL);
1731 * We found an authority that may be able to help us
1732 * move on with query
1733 * Note only 1 pkey should have been returned.. anything else would be strange
1736 for (i=0; i<rd_count;i++)
1739 if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
1742 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
1745 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This pkey is expired.\n");
1746 if (remaining_time.rel_value == 0)
1748 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1749 "This dht entry is expired.\n");
1750 rh->authority_chain_head->fresh = 0;
1751 rh->proc(rh->proc_cls, rh, 0, NULL);
1759 * Resolve rest of query with new authority
1761 GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
1762 memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1763 struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
1764 auth->zone = rh->authority;
1765 memset(auth->name, 0, strlen(rh->authority_name)+1);
1766 strcpy(auth->name, rh->authority_name);
1767 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1768 rh->authority_chain_tail,
1772 * We are done with PKEY resolution if name is empty
1773 * else resolve again with new authority
1775 if (strcmp(rh->name, "") == 0)
1776 rh->proc(rh->proc_cls, rh, 0, NULL);
1778 resolve_delegation_ns(rh);
1785 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1786 "Authority lookup successful but no PKEY... never get here\n");
1787 rh->proc(rh->proc_cls, rh, 0, NULL);
1792 * Resolve the delegation chain for the request in our namestore
1794 * @param rh the resolver handle
1797 resolve_delegation_ns(struct ResolverHandle *rh)
1799 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1800 "Resolving delegation for %s\n", rh->name);
1801 pop_tld(rh->name, rh->authority_name);
1802 GNUNET_NAMESTORE_lookup_record(namestore_handle,
1805 GNUNET_GNS_RECORD_PKEY,
1806 &process_delegation_result_ns,
1813 * Lookup of a record in a specific zone
1814 * calls lookup result processor on result
1816 * @param zone the root zone
1817 * @param record_type the record type to look up
1818 * @param name the name to look up
1819 * @param key a private key for use with PSEU import (can be NULL)
1820 * @param timeout timeout for resolution
1821 * @param proc the processor to call on result
1822 * @param cls the closure to pass to proc
1825 gns_resolver_lookup_record(struct GNUNET_CRYPTO_ShortHashCode zone,
1826 uint32_t record_type,
1828 struct GNUNET_CRYPTO_RsaPrivateKey *key,
1829 struct GNUNET_TIME_Relative timeout,
1830 RecordLookupProcessor proc,
1833 struct ResolverHandle *rh;
1834 struct RecordLookupHandle* rlh;
1835 char string_hash[MAX_DNS_LABEL_LENGTH];
1837 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1838 "Starting resolution for %s (type=%d)!\n",
1842 if (is_canonical((char*)name) && (strcmp(GNUNET_GNS_TLD, name) != 0))
1844 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1845 "%s is canonical and not gnunet -> cannot resolve!\n", name);
1850 rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
1851 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1853 rh->authority = zone;
1856 rh->timeout = timeout;
1857 if (timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
1860 * Set timeout for authority lookup phase to 1/2
1862 rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
1863 GNUNET_TIME_relative_divide(timeout, 2),
1864 &handle_lookup_timeout,
1866 rh->timeout_cont = &dht_authority_lookup_timeout;
1867 rh->timeout_cont_cls = rh;
1871 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No timeout for query!\n");
1872 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1875 if (strcmp(GNUNET_GNS_TLD, name) == 0)
1878 * Only 'gnunet' given
1880 strcpy(rh->name, "\0");
1884 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1885 "Checking for TLD...\n");
1886 if (is_zkey_tld(name) == GNUNET_YES)
1888 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1891 * This is a zkey tld
1892 * build hash and use as initial authority
1895 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
1896 memcpy(rh->name, name,
1897 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
1898 pop_tld(rh->name, string_hash);
1900 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1901 "ZKEY is %s!\n", string_hash);
1903 if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(string_hash,
1906 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1907 "Cannot convert ZKEY %s to hash!\n", string_hash);
1917 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1920 * Presumably GNUNET tld
1923 strlen(name)-strlen(GNUNET_GNS_TLD));
1924 memcpy(rh->name, name,
1925 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
1930 * Initialize authority chain
1932 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1933 rh->authority_chain_head->prev = NULL;
1934 rh->authority_chain_head->next = NULL;
1935 rh->authority_chain_tail = rh->authority_chain_head;
1936 rh->authority_chain_head->zone = rh->authority;
1939 * Copy original query into lookup handle
1941 rlh->record_type = record_type;
1942 memset(rlh->name, 0, strlen(name) + 1);
1943 strcpy(rlh->name, name);
1945 rlh->proc_cls = cls;
1947 rh->proc = &handle_delegation_ns;
1948 resolve_delegation_ns(rh);
1951 /******** END Record Resolver ***********/
1955 * Callback calles by namestore for a zone to name
1958 * @param cls the closure
1959 * @param zone_key the zone we queried
1960 * @param expire the expiration time of the name
1961 * @param name the name found or NULL
1962 * @param rd_len number of records for the name
1963 * @param rd the record data (PKEY) for the name
1964 * @param signature the signature for the record data
1967 process_zone_to_name_shorten(void *cls,
1968 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1969 struct GNUNET_TIME_Absolute expire,
1971 unsigned int rd_len,
1972 const struct GNUNET_NAMESTORE_RecordData *rd,
1973 const struct GNUNET_CRYPTO_RsaSignature *signature)
1975 struct ResolverHandle *rh = (struct ResolverHandle *)cls;
1976 struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
1977 struct AuthorityChain *next_authority;
1979 char result[MAX_DNS_NAME_LENGTH];
1980 char next_authority_name[MAX_DNS_LABEL_LENGTH];
1983 /* we found a match in our own zone */
1986 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1987 "result strlen %d\n", strlen(name));
1988 answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
1989 memset(result, 0, answer_len);
1990 if (strlen(rh->name) > 0)
1992 strcpy(result, rh->name);
1993 strcpy(result+strlen(rh->name), ".");
1996 strcpy(result+strlen(result), name);
1997 strcpy(result+strlen(result), ".");
1998 strcpy(result+strlen(result), GNUNET_GNS_TLD);
2000 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2001 "Sending shorten result %s\n", result);
2003 nsh->proc(nsh->proc_cls, result);
2005 free_resolver_handle(rh);
2007 else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2010 /* our zone, just append .gnunet */
2011 answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
2012 memset(result, 0, answer_len);
2013 strcpy(result, rh->name);
2014 strcpy(result+strlen(rh->name), ".");
2015 strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
2017 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2018 "Our zone: Sending name as shorten result %s\n", rh->name);
2020 nsh->proc(nsh->proc_cls, result);
2022 free_resolver_handle(rh);
2028 * continue with next authority
2030 next_authority = rh->authority_chain_head;
2031 // strlen(next_authority->name) + 2);
2032 memset(next_authority_name, 0, strlen(rh->name)+
2033 strlen(next_authority->name) + 2);
2034 strcpy(next_authority_name, rh->name);
2035 strcpy(next_authority_name+strlen(rh->name)+1, ".");
2036 strcpy(next_authority_name+strlen(rh->name)+2, next_authority->name);
2038 strcpy(rh->name, next_authority_name);
2039 GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
2040 rh->authority_chain_tail,
2043 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2044 &rh->authority_chain_tail->zone,
2045 &rh->authority_chain_head->zone,
2046 &process_zone_to_name_shorten,
2053 * Process result from namestore delegation lookup
2054 * for shorten operation
2056 * @param cls the client shorten handle
2057 * @param rh the resolver handle
2058 * @param rd_count number of results (0)
2059 * @param rd data (NULL)
2062 handle_delegation_ns_shorten(void* cls,
2063 struct ResolverHandle *rh,
2065 const struct GNUNET_NAMESTORE_RecordData *rd)
2067 struct NameShortenHandle *nsh;
2068 char result[MAX_DNS_NAME_LENGTH];
2071 nsh = (struct NameShortenHandle *)cls;
2074 * At this point rh->name contains the part of the name
2075 * that we do not have a PKEY in our namestore to resolve.
2076 * The authority chain in the resolver handle is now
2077 * useful to backtrack if needed
2080 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2081 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2083 if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2087 * This is our zone append .gnunet unless name is empty
2088 * (it shouldn't be, usually FIXME what happens if we
2089 * shorten to our zone to a "" record??)
2092 answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
2093 memset(result, 0, answer_len);
2094 strcpy(result, rh->name);
2095 strcpy(result+strlen(rh->name), ".");
2096 strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
2098 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2099 "Our zone: Sending name as shorten result %s\n", rh->name);
2101 nsh->proc(nsh->proc_cls, result);
2103 free_resolver_handle(rh);
2107 /* backtrack authorities for names */
2108 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2109 &rh->authority_chain_tail->zone, //ours
2110 &rh->authority_chain_head->zone,
2111 &process_zone_to_name_shorten,
2117 * Shorten api from resolver
2119 * @param zone the zone to use
2120 * @param name the name to shorten
2121 * @param proc the processor to call with result
2122 * @param cls closure to pass to proc
2125 gns_resolver_shorten_name(struct GNUNET_CRYPTO_ShortHashCode zone,
2127 ShortenResultProcessor proc,
2130 struct ResolverHandle *rh;
2131 struct NameShortenHandle *nsh;
2132 char string_hash[MAX_DNS_NAME_LENGTH]; //FIXME LABEL length when shorthash
2134 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2135 "Starting shorten for %s!\n", name);
2137 if (is_canonical((char*)name))
2139 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2140 "%s is canonical. Returning verbatim\n", name);
2145 nsh = GNUNET_malloc(sizeof (struct NameShortenHandle));
2149 nsh->proc_cls = cls;
2151 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2152 rh->authority = zone;
2154 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2155 "Checking for TLD...\n");
2156 if (is_zkey_tld(name) == GNUNET_YES)
2158 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2161 * This is a zkey tld
2162 * build hash and use as initial authority
2165 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
2166 memcpy(rh->name, name,
2167 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
2168 pop_tld(rh->name, string_hash);
2170 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2171 "ZKEY is %s!\n", string_hash);
2173 if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(string_hash,
2176 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2177 "Cannot convert ZKEY %s to hash!\n", string_hash);
2187 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2190 * Presumably GNUNET tld
2193 strlen(name)-strlen(GNUNET_GNS_TLD));
2194 memcpy(rh->name, name,
2195 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2198 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2199 rh->authority_chain_tail = rh->authority_chain_head;
2200 rh->authority_chain_head->zone = zone;
2201 rh->proc = &handle_delegation_ns_shorten;
2204 /* Start delegation resolution in our namestore */
2205 resolve_delegation_ns(rh);
2208 /*********** END NAME SHORTEN ********************/
2212 * Process result from namestore delegation lookup
2213 * for get authority operation
2215 * @param cls the client get auth handle
2216 * @param rh the resolver handle
2217 * @param rd_count number of results (0)
2218 * @param rd data (NULL)
2221 handle_delegation_result_ns_get_auth(void* cls,
2222 struct ResolverHandle *rh,
2224 const struct GNUNET_NAMESTORE_RecordData *rd)
2226 struct GetNameAuthorityHandle* nah;
2227 char result[MAX_DNS_NAME_LENGTH];
2230 nah = (struct GetNameAuthorityHandle*) rh->proc_cls;
2233 * At this point rh->name contains the part of the name
2234 * that we do not have a PKEY in our namestore to resolve.
2235 * The authority chain in the resolver handle is now
2236 * useful to backtrack if needed
2239 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2240 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2242 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2243 "Building response!\n");
2244 if (is_canonical(rh->name))
2247 * We successfully resolved the authority in the ns
2248 * FIXME for our purposes this is fine
2249 * but maybe we want to have an api that also looks
2250 * into the dht (i.e. option in message)
2252 if (strlen(rh->name) > strlen(nah->name))
2254 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2255 "Record name longer than original lookup name... odd!\n");
2259 answer_len = strlen(nah->name) - strlen(rh->name)
2260 + strlen(GNUNET_GNS_TLD) + 1;
2261 memset(result, 0, answer_len);
2262 strcpy(result, nah->name + strlen(rh->name) + 1);
2264 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2265 "Got authority result %s\n", result);
2267 nah->proc(nah->proc_cls, result);
2269 free_resolver_handle(rh);
2273 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2274 "Unable to resolve authority for remaining %s!\n", rh->name);
2275 nah->proc(nah->proc_cls, "");
2277 free_resolver_handle(rh);
2285 * Tries to resolve the authority for name
2288 * @param zone the root zone to look up for
2289 * @param name the name to lookup up
2290 * @param proc the processor to call when finished
2291 * @param cls the closure to pass to the processor
2294 gns_resolver_get_authority(struct GNUNET_CRYPTO_ShortHashCode zone,
2296 GetAuthorityResultProcessor proc,
2299 struct ResolverHandle *rh;
2300 struct GetNameAuthorityHandle *nah;
2302 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2303 "Starting authority resolution for %s!\n", name);
2305 nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
2306 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2307 rh->authority = zone;
2309 if (strcmp(GNUNET_GNS_TLD, name) == 0)
2311 strcpy(rh->name, "\0");
2316 strlen(name)-strlen(GNUNET_GNS_TLD));
2317 memcpy(rh->name, name,
2318 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2321 memset(nah->name, 0,
2323 strcpy(nah->name, name);
2325 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2326 rh->authority_chain_tail = rh->authority_chain_head;
2327 rh->authority_chain_head->zone = zone;
2328 rh->proc = &handle_delegation_result_ns_get_auth;
2329 rh->proc_cls = (void*)nah;
2332 nah->proc_cls = cls;
2334 /* Start delegation resolution in our namestore */
2335 resolve_delegation_ns(rh);
2339 /******** END GET AUTHORITY *************/
2341 /* end of gnunet-service-gns_resolver.c */