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 struct GNUNET_NAMESTORE_Handle *namestore_handle;
53 * Resolver handle to the dht
55 struct GNUNET_DHT_Handle *dht_handle;
58 * Connects resolver to the dht
68 * Helper function to free resolver handle
70 * @rh the handle to free
73 free_resolver_handle(struct ResolverHandle* rh)
75 struct AuthorityChain *ac;
76 struct AuthorityChain *ac_next;
81 GNUNET_free_non_null (rh->name);
82 GNUNET_free_non_null (rh->authority_name);
84 ac = rh->authority_chain_head;
89 GNUNET_free_non_null (ac->name);
98 * Callback when record data is put into namestore
100 * @param cls the closure
101 * @param success GNUNET_OK on success
102 * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
105 on_namestore_record_put_result(void *cls,
109 if (GNUNET_NO == success)
111 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "records already in namestore\n");
114 else if (GNUNET_YES == success)
116 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
117 "records successfully put in namestore\n");
121 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
122 "Error putting records into namestore: %s\n", emsg);
127 * Handle timeout for DHT requests
129 * @param cls the request handle as closure
130 * @param tc the task context
133 dht_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
135 struct ResolverHandle *rh = cls;
137 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
138 "dht lookup for query %s timed out.\n",
141 GNUNET_DHT_get_stop (rh->get_handle);
142 rh->proc(rh->proc_cls, rh, 0, NULL);
147 * Function called when we get a result from the dht
148 * for our record query
150 * @param cls the request handle
151 * @param exp lifetime
152 * @param key the key the record was stored under
153 * @param get_path get path
154 * @param get_path_length get path length
155 * @param put_path put path
156 * @param put_path_length put path length
157 * @param type the block type
158 * @param size the size of the record
159 * @param data the record data
162 process_record_result_dht(void* cls,
163 struct GNUNET_TIME_Absolute exp,
164 const GNUNET_HashCode * key,
165 const struct GNUNET_PeerIdentity *get_path,
166 unsigned int get_path_length,
167 const struct GNUNET_PeerIdentity *put_path,
168 unsigned int put_path_length,
169 enum GNUNET_BLOCK_Type type,
170 size_t size, const void *data)
172 struct ResolverHandle *rh;
173 struct RecordLookupHandle *rlh;
174 struct GNSNameRecordBlock *nrb;
175 uint32_t num_records;
177 char* rd_data = (char*)data;
181 GNUNET_HashCode zone, name_hash;
182 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "got dht result (size=%d)\n", size);
187 //FIXME maybe check expiration here, check block type
189 rh = (struct ResolverHandle *)cls;
190 rlh = (struct RecordLookupHandle *) rh->proc_cls;
191 nrb = (struct GNSNameRecordBlock*)data;
193 /* stop lookup and timeout task */
194 GNUNET_DHT_get_stop (rh->get_handle);
195 GNUNET_SCHEDULER_cancel(rh->dht_timeout_task);
197 rh->get_handle = NULL;
198 name = (char*)&nrb[1];
199 num_records = ntohl(nrb->rd_count);
201 struct GNUNET_NAMESTORE_RecordData rd[num_records];
203 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
204 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
206 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
211 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
215 for (i=0; i<num_records; i++)
217 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
218 "Got name: %s (wanted %s)\n", name, rh->name);
219 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
222 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
223 "Got data length: %d\n", rd[i].data_size);
224 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
225 "Got flag %d\n", rd[i].flags);
227 if ((strcmp(name, rh->name) == 0) &&
228 (rd[i].record_type == rlh->record_type))
235 GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
236 GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
239 * FIXME check pubkey against existing key in namestore?
240 * https://gnunet.org/bugs/view.php?id=2179
243 /* Save to namestore */
244 GNUNET_NAMESTORE_record_put (namestore_handle,
251 &on_namestore_record_put_result, //cont
255 rh->proc(rh->proc_cls, rh, num_records, rd);
257 rh->proc(rh->proc_cls, rh, 0, NULL);
264 * Start DHT lookup for a (name -> query->record_type) record in
265 * rh->authority's zone
267 * @param rh the pending gns query context
270 resolve_record_dht(struct ResolverHandle *rh)
273 GNUNET_HashCode name_hash;
274 GNUNET_HashCode lookup_key;
275 struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
276 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
278 GNUNET_CRYPTO_hash(rh->name, strlen(rh->name), &name_hash);
279 GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
280 GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
282 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
283 "starting dht lookup for %s with key: %s\n",
284 rh->name, (char*)&lookup_key_string);
286 rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed(DHT_LOOKUP_TIMEOUT,
287 &dht_lookup_timeout, rh);
289 xquery = htonl(rlh->record_type);
290 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
291 DHT_OPERATION_TIMEOUT,
292 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
294 DHT_GNS_REPLICATION_LEVEL,
298 &process_record_result_dht,
305 * Namestore calls this function if we have record for this name.
306 * (or with rd_count=0 to indicate no matches)
308 * @param cls the pending query
309 * @param key the key of the zone we did the lookup
310 * @param expiration expiration date of the namestore entry
311 * @param name the name for which we need an authority
312 * @param rd_count the number of records with 'name'
313 * @param rd the record data
314 * @param signature the signature of the authority for the record data
317 process_record_result_ns(void* cls,
318 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
319 struct GNUNET_TIME_Absolute expiration,
320 const char *name, unsigned int rd_count,
321 const struct GNUNET_NAMESTORE_RecordData *rd,
322 const struct GNUNET_CRYPTO_RsaSignature *signature)
324 struct ResolverHandle *rh;
325 struct RecordLookupHandle *rlh;
326 struct GNUNET_TIME_Relative remaining_time;
327 GNUNET_HashCode zone;
329 rh = (struct ResolverHandle *) cls;
330 rlh = (struct RecordLookupHandle *)rh->proc_cls;
331 GNUNET_CRYPTO_hash(key,
332 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
334 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
340 rh->status |= EXISTS;
343 if (remaining_time.rel_value == 0)
345 rh->status |= EXPIRED;
351 * Lookup terminated and no results
353 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
354 "Namestore lookup for %s terminated without results\n", name);
356 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
357 "Record %s unknown in namestore\n",
360 * Our zone and no result? Cannot resolve TT
362 rh->proc(rh->proc_cls, rh, 0, NULL);
369 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
370 "Processing additional result %s from namestore\n", name);
372 for (i=0; i<rd_count;i++)
375 if (rd[i].record_type != rlh->record_type)
378 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
381 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
382 "This record is expired. Skipping\n");
393 if (rh->answered == 0)
395 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
396 "No answers found. This is odd!\n");
397 rh->proc(rh->proc_cls, rh, 0, NULL);
401 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Found %d answer(s) to query!\n",
404 rh->proc(rh->proc_cls, rh, rd_count, rd);
410 * The final phase of resolution.
411 * rh->name is a name that is canonical and we do not have a delegation.
412 * Query namestore for this record
414 * @param rh the pending lookup
417 resolve_record_ns(struct ResolverHandle *rh)
419 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
422 * Try to resolve this record in our namestore.
423 * The name to resolve is now in rh->authority_name
424 * since we tried to resolve it to an authority
427 GNUNET_NAMESTORE_lookup_record(namestore_handle,
431 &process_record_result_ns,
437 * Handle timeout for DHT requests
439 * @param cls the request handle as closure
440 * @param tc the task context
443 dht_authority_lookup_timeout(void *cls,
444 const struct GNUNET_SCHEDULER_TaskContext *tc)
446 struct ResolverHandle *rh = cls;
448 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
449 "dht lookup for query %s timed out.\n",
452 GNUNET_DHT_get_stop (rh->get_handle);
453 if (strcmp(rh->name, "") == 0)
456 * promote authority back to name and try to resolve record
458 strcpy(rh->name, rh->authority_name);
460 rh->proc(rh->proc_cls, rh, 0, NULL);
464 static void resolve_delegation_dht(struct ResolverHandle *rh);
467 * Function called when we get a result from the dht
468 * for our query. Recursively tries to resolve authorities
471 * @param cls the request handle
472 * @param exp lifetime
473 * @param key the key the record was stored under
474 * @param get_path get path
475 * @param get_path_length get path length
476 * @param put_path put path
477 * @param put_path_length put path length
478 * @param type the block type
479 * @param size the size of the record
480 * @param data the record data
483 process_delegation_result_dht(void* cls,
484 struct GNUNET_TIME_Absolute exp,
485 const GNUNET_HashCode * key,
486 const struct GNUNET_PeerIdentity *get_path,
487 unsigned int get_path_length,
488 const struct GNUNET_PeerIdentity *put_path,
489 unsigned int put_path_length,
490 enum GNUNET_BLOCK_Type type,
491 size_t size, const void *data)
493 struct ResolverHandle *rh;
494 struct GNSNameRecordBlock *nrb;
495 uint32_t num_records;
497 char* rd_data = (char*) data;
500 GNUNET_HashCode zone, name_hash;
502 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got DHT result\n");
507 //FIXME check expiration?
509 rh = (struct ResolverHandle *)cls;
510 nrb = (struct GNSNameRecordBlock*)data;
512 /* stop dht lookup and timeout task */
513 GNUNET_DHT_get_stop (rh->get_handle);
514 GNUNET_SCHEDULER_cancel(rh->dht_timeout_task);
516 rh->get_handle = NULL;
517 num_records = ntohl(nrb->rd_count);
518 name = (char*)&nrb[1];
520 struct GNUNET_NAMESTORE_RecordData rd[num_records];
522 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
523 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
525 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
530 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
534 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
535 "Got name: %s (wanted %s)\n", name, rh->authority_name);
536 for (i=0; i<num_records; i++)
539 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
540 "Got name: %s (wanted %s)\n", name, rh->authority_name);
541 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
542 "Got type: %d (wanted %d)\n",
543 rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
544 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
545 "Got data length: %d\n", rd[i].data_size);
546 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
547 "Got flag %d\n", rd[i].flags);
549 if ((strcmp(name, rh->authority_name) == 0) &&
550 (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
552 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Authority found in DHT\n");
554 memcpy(&rh->authority, rd[i].data, sizeof(GNUNET_HashCode));
555 struct AuthorityChain *auth =
556 GNUNET_malloc(sizeof(struct AuthorityChain));
557 auth->zone = rh->authority;
558 auth->name = GNUNET_malloc(strlen(rh->authority_name)+1);
559 memset(auth->name, 0, strlen(rh->authority_name)+1);
560 strcpy(auth->name, rh->authority_name);
561 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
562 rh->authority_chain_tail,
569 GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
570 GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
572 /* Save to namestore */
573 if (0 != GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_tail->zone, &zone))
575 GNUNET_NAMESTORE_record_put (namestore_handle,
582 &on_namestore_record_put_result, //cont
592 * FIXME in this case. should we ask namestore again?
594 if (strcmp(rh->name, "") == 0)
595 rh->proc(rh->proc_cls, rh, 0, NULL);
597 resolve_delegation_dht(rh);
602 * should never get here unless false dht key/put
603 * block plugin should handle this
605 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "DHT authority lookup found no match!\n");
606 rh->proc(rh->proc_cls, rh, 0, NULL);
611 * Process DHT lookup result for record.
613 * @param cls the closure
614 * @param rh resolver handle
615 * @param rd_count number of results
616 * @param rd record data
619 handle_record_dht(void* cls, struct ResolverHandle *rh,
620 unsigned int rd_count,
621 const struct GNUNET_NAMESTORE_RecordData *rd)
623 struct RecordLookupHandle* rlh;
624 rlh = (struct RecordLookupHandle*)cls;
627 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
628 "No records for %s found in DHT. Aborting\n",
630 /* give up, cannot resolve */
631 rlh->proc(rlh->proc_cls, 0, NULL);
632 GNUNET_free(rlh->name);
634 free_resolver_handle(rh);
638 /* results found yay */
639 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
640 "Record resolved from DHT!");
641 rlh->proc(rlh->proc_cls, rd_count, rd);
642 GNUNET_free(rlh->name);
644 free_resolver_handle(rh);
650 * Process namestore lookup result for record.
652 * @param cls the closure
653 * @param rh resolver handle
654 * @param rd_count number of results
655 * @param rd record data
658 handle_record_ns(void* cls, struct ResolverHandle *rh,
659 unsigned int rd_count,
660 const struct GNUNET_NAMESTORE_RecordData *rd)
662 struct RecordLookupHandle* rlh;
663 rlh = (struct RecordLookupHandle*) cls;
666 /* ns entry expired and not ours. try dht */
667 if (rh->status & (EXPIRED | !EXISTS) &&
668 GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
669 &rh->authority_chain_tail->zone))
671 rh->proc = &handle_record_dht;
672 resolve_record_dht(rh);
675 /* give up, cannot resolve */
676 rlh->proc(rlh->proc_cls, 0, NULL);
677 GNUNET_free(rlh->name);
679 free_resolver_handle(rh);
683 /* results found yay */
684 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
685 "Record resolved from namestore!");
686 rlh->proc(rlh->proc_cls, rd_count, rd);
687 GNUNET_free(rlh->name);
689 free_resolver_handle(rh);
695 * Determine if this name is canonical.
697 * a.b.gnunet = not canonical
700 * @param name the name to test
701 * @return 1 if canonical
704 is_canonical(char* name)
706 uint32_t len = strlen(name);
709 for (i=0; i<len; i++)
711 if (*(name+i) == '.')
718 * Move one level up in the domain hierarchy and return the
719 * passed top level domain.
721 * @param name the domain
722 * @param dest the destination where the tld will be put
725 pop_tld(char* name, char* dest)
729 if (is_canonical(name))
736 for (len = strlen(name); len > 0; len--)
738 if (*(name+len) == '.')
748 strcpy(dest, (name+len+1));
752 * DHT resolution for delegation finished. Processing result.
754 * @param cls the closure
755 * @param rh resolver handle
756 * @param rd_count number of results (always 0)
757 * @param rd record data (always NULL)
760 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
761 unsigned int rd_count,
762 const struct GNUNET_NAMESTORE_RecordData *rd)
764 struct RecordLookupHandle* rlh;
765 rlh = (struct RecordLookupHandle*) cls;
767 if (strcmp(rh->name, "") == 0)
769 /* We resolved full name for delegation. resolving record */
770 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
771 "Resolved full name for delegation via DHT. resolving record '' in ns\n");
772 rh->proc = &handle_record_ns;
773 resolve_record_ns(rh);
778 * we still have some left
780 if (is_canonical(rh->name))
782 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
783 "Resolving canonical record %s in ns\n", rh->name);
784 rh->proc = &handle_record_ns;
785 resolve_record_ns(rh);
788 /* give up, cannot resolve */
789 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
790 "Cannot fully resolve delegation for %s via DHT!\n",
792 rlh->proc(rlh->proc_cls, 0, NULL);
793 GNUNET_free(rlh->name);
795 free_resolver_handle(rh);
800 * Start DHT lookup for a name -> PKEY (compare NS) record in
801 * rh->authority's zone
803 * @param rh the pending gns query
806 resolve_delegation_dht(struct ResolverHandle *rh)
809 GNUNET_HashCode name_hash;
810 GNUNET_HashCode lookup_key;
812 GNUNET_CRYPTO_hash(rh->authority_name,
813 strlen(rh->authority_name),
815 GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
817 rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
818 &dht_authority_lookup_timeout,
821 xquery = htonl(GNUNET_GNS_RECORD_PKEY);
823 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
824 DHT_OPERATION_TIMEOUT,
825 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
827 DHT_GNS_REPLICATION_LEVEL,
831 &process_delegation_result_dht,
838 * Namestore resolution for delegation finished. Processing result.
840 * @param cls the closure
841 * @param rh resolver handle
842 * @param rd_count number of results (always 0)
843 * @param rd record data (always NULL)
846 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
847 unsigned int rd_count,
848 const struct GNUNET_NAMESTORE_RecordData *rd)
850 struct RecordLookupHandle* rlh;
851 rlh = (struct RecordLookupHandle*) cls;
853 if (strcmp(rh->name, "") == 0)
855 /* We resolved full name for delegation. resolving record */
856 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
857 "Resolved full name for delegation. resolving record ''\n");
858 rh->proc = &handle_record_ns;
859 resolve_record_ns(rh);
864 * we still have some left
865 * check if authority in ns is fresh
867 * or we are authority
869 if ((rh->status & (EXISTS | !EXPIRED)) ||
870 !GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
871 &rh->authority_chain_tail->zone))
873 if (is_canonical(rh->name))
875 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
876 "Resolving canonical record %s\n", rh->name);
877 rh->proc = &handle_record_ns;
878 resolve_record_ns(rh);
882 /* give up, cannot resolve */
883 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
884 "Cannot fully resolve delegation for %s!\n",
886 rlh->proc(rlh->proc_cls, 0, NULL);
891 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
892 "Trying to resolve delegation for %s via DHT\n",
894 rh->proc = &handle_delegation_dht;
895 resolve_delegation_dht(rh);
899 static void resolve_delegation_ns(struct ResolverHandle *rh);
903 * This is a callback function that should give us only PKEY
904 * records. Used to query the namestore for the authority (PKEY)
905 * for 'name'. It will recursively try to resolve the
906 * authority for a given name from the namestore.
908 * @param cls the pending query
909 * @param key the key of the zone we did the lookup
910 * @param expiration expiration date of the record data set in the namestore
911 * @param name the name for which we need an authority
912 * @param rd_count the number of records with 'name'
913 * @param rd the record data
914 * @param signature the signature of the authority for the record data
917 process_delegation_result_ns(void* cls,
918 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
919 struct GNUNET_TIME_Absolute expiration,
921 unsigned int rd_count,
922 const struct GNUNET_NAMESTORE_RecordData *rd,
923 const struct GNUNET_CRYPTO_RsaSignature *signature)
925 struct ResolverHandle *rh;
926 struct GNUNET_TIME_Relative remaining_time;
927 GNUNET_HashCode zone;
930 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got %d records from authority lookup\n",
933 rh = (struct ResolverHandle *)cls;
934 GNUNET_CRYPTO_hash(key,
935 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
937 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
943 rh->status |= EXISTS;
946 if (remaining_time.rel_value == 0)
948 rh->status |= EXPIRED;
952 * No authority found in namestore.
957 * We did not find an authority in the namestore
962 * Promote this authority back to a name maybe it is
965 if (strcmp(rh->name, "") == 0)
967 /* simply promote back */
968 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
969 "Promoting %s back to name\n", rh->authority_name);
970 strcpy(rh->name, rh->authority_name);
974 /* add back to existing name */
975 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
976 "Adding %s back to %s\n",
977 rh->authority_name, rh->name);
978 new_name = GNUNET_malloc(strlen(rh->name)
979 + strlen(rh->authority_name) + 2);
980 memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
981 strcpy(new_name, rh->name);
982 strcpy(new_name+strlen(new_name)+1, ".");
983 strcpy(new_name+strlen(new_name)+2, rh->authority_name);
984 GNUNET_free(rh->name);
987 rh->proc(rh->proc_cls, rh, 0, NULL);
992 * We found an authority that may be able to help us
994 * Note only 1 pkey should have been returned.. anything else would be strange
997 for (i=0; i<rd_count;i++)
1000 if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
1003 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
1006 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This pkey is expired.\n");
1007 if (remaining_time.rel_value == 0)
1009 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1010 "This dht entry is expired.\n");
1011 rh->authority_chain_head->fresh = 0;
1012 rh->proc(rh->proc_cls, rh, 0, NULL);
1020 * Resolve rest of query with new authority
1022 GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
1023 memcpy(&rh->authority, rd[i].data, sizeof(GNUNET_HashCode));
1024 struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
1025 auth->zone = rh->authority;
1026 auth->name = GNUNET_malloc(strlen(rh->authority_name)+1);
1027 memset(auth->name, 0, strlen(rh->authority_name)+1);
1028 strcpy(auth->name, rh->authority_name);
1029 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1030 rh->authority_chain_tail,
1034 * We are done with PKEY resolution if name is empty
1035 * else resolve again with new authority
1037 if (strcmp(rh->name, "") == 0)
1038 rh->proc(rh->proc_cls, rh, 0, NULL);
1040 resolve_delegation_ns(rh);
1047 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1048 "Authority lookup successful but no PKEY... never get here\n");
1049 rh->proc(rh->proc_cls, rh, 0, NULL);
1054 * Resolve the delegation chain for the request in our namestore
1056 * @param rh the resolver handle
1059 resolve_delegation_ns(struct ResolverHandle *rh)
1061 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1062 "Resolving delegation for %s\n", rh->name);
1063 pop_tld(rh->name, rh->authority_name);
1064 GNUNET_NAMESTORE_lookup_record(namestore_handle,
1067 GNUNET_GNS_RECORD_PKEY,
1068 &process_delegation_result_ns,
1075 * Lookup of a record in a specific zone
1076 * calls lookup result processor on result
1078 * @param zone the root zone
1079 * @param record_type the record type to look up
1080 * @param name the name to look up
1081 * @param proc the processor to call on result
1082 * @param cls the closure to pass to proc
1085 gns_resolver_lookup_record(GNUNET_HashCode zone,
1086 uint32_t record_type,
1088 RecordLookupProcessor proc,
1091 struct ResolverHandle *rh;
1092 struct RecordLookupHandle* rlh;
1094 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1095 "Starting resolution for %s (type=%d)!\n",
1099 if (is_canonical((char*)name) && (strcmp(GNUNET_GNS_TLD, name) != 0))
1101 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1102 "%s is canonical and gnunet not our TLD!\n", name);
1107 rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
1108 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1110 rh->authority = zone;
1113 if (strcmp(GNUNET_GNS_TLD, name) == 0)
1115 rh->name = GNUNET_malloc(2);
1116 strcpy(rh->name, "");
1120 rh->name = GNUNET_malloc(strlen(name)
1121 - strlen(GNUNET_GNS_TLD));
1123 strlen(name)-strlen(GNUNET_GNS_TLD));
1124 memcpy(rh->name, name,
1125 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
1128 rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
1129 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1130 rh->authority_chain_head->prev = NULL;
1131 rh->authority_chain_head->next = NULL;
1132 rh->authority_chain_tail = rh->authority_chain_head;
1133 rh->authority_chain_head->zone = zone;
1135 rlh->record_type = record_type;
1136 rlh->name = GNUNET_malloc(strlen(name) + 1);
1137 memset(rlh->name, 0, strlen(name) + 1);
1138 strcpy(rlh->name, name); //FIXME
1140 rlh->proc_cls = cls;
1142 rh->proc = &handle_delegation_ns;
1143 resolve_delegation_ns(rh);
1146 /******** END Record Resolver ***********/
1150 * Callback calles by namestore for a zone to name
1153 * @param cls the closure
1154 * @param zone_key the zone we queried
1155 * @param expire the expiration time of the name
1156 * @param name the name found or NULL
1157 * @param rd_len number of records for the name
1158 * @param rd the record data (PKEY) for the name
1159 * @param signature the signature for the record data
1162 process_zone_to_name_shorten(void *cls,
1163 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1164 struct GNUNET_TIME_Absolute expire,
1166 unsigned int rd_len,
1167 const struct GNUNET_NAMESTORE_RecordData *rd,
1168 const struct GNUNET_CRYPTO_RsaSignature *signature)
1170 struct ResolverHandle *rh = (struct ResolverHandle *)cls;
1171 struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
1172 struct AuthorityChain *next_authority;
1175 char* next_authority_name;
1178 /* we found a match in our own zone */
1181 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1182 "result strlen %d\n", strlen(name));
1183 answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
1184 result = GNUNET_malloc(answer_len);
1185 memset(result, 0, answer_len);
1186 if (strlen(rh->name) > 0)
1188 strcpy(result, rh->name);
1189 strcpy(result+strlen(rh->name), ".");
1192 strcpy(result+strlen(result), name);
1193 strcpy(result+strlen(result), ".");
1194 strcpy(result+strlen(result), GNUNET_GNS_TLD);
1196 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1197 "Sending shorten result %s\n", result);
1199 nsh->proc(nsh->proc_cls, result);
1201 free_resolver_handle(rh);
1202 GNUNET_free(result);
1204 else if (GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
1205 &rh->authority_chain_tail->zone))
1207 /* our zone, just append .gnunet */
1208 answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
1209 result = GNUNET_malloc(answer_len);
1210 memset(result, 0, answer_len);
1211 strcpy(result, rh->name);
1212 strcpy(result+strlen(rh->name), ".");
1213 strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
1215 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1216 "Our zone: Sending name as shorten result %s\n", rh->name);
1218 nsh->proc(nsh->proc_cls, result);
1220 free_resolver_handle(rh);
1221 GNUNET_free(result);
1227 * continue with next authority
1229 next_authority = rh->authority_chain_head;
1230 next_authority_name = GNUNET_malloc(strlen(rh->name)+
1231 strlen(next_authority->name) + 2);
1232 memset(next_authority_name, 0, strlen(rh->name)+
1233 strlen(next_authority->name) + 2);
1234 strcpy(next_authority_name, rh->name);
1235 strcpy(next_authority_name+strlen(rh->name)+1, ".");
1236 strcpy(next_authority_name+strlen(rh->name)+2, next_authority->name);
1238 GNUNET_free(rh->name);
1239 rh->name = next_authority_name;
1240 GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
1241 rh->authority_chain_tail,
1244 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1245 &rh->authority_chain_tail->zone,
1246 &rh->authority_chain_head->zone,
1247 &process_zone_to_name_shorten,
1254 * Process result from namestore delegation lookup
1255 * for shorten operation
1257 * @param cls the client shorten handle
1258 * @param rh the resolver handle
1259 * @param rd_count number of results (0)
1260 * @param rd data (NULL)
1263 handle_delegation_ns_shorten(void* cls,
1264 struct ResolverHandle *rh,
1266 const struct GNUNET_NAMESTORE_RecordData *rd)
1268 struct NameShortenHandle *nsh;
1272 nsh = (struct NameShortenHandle *)cls;
1275 * At this point rh->name contains the part of the name
1276 * that we do not have a PKEY in our namestore to resolve.
1277 * The authority chain in the resolver handle is now
1278 * useful to backtrack if needed
1281 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1282 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
1284 if (GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
1285 &rh->authority_chain_tail->zone) == 0)
1288 * This is our zone append .gnunet unless name is empty
1289 * (it shouldn't be, usually FIXME what happens if we
1290 * shorten to our zone to a "" record??)
1293 answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
1294 result = GNUNET_malloc(answer_len);
1295 memset(result, 0, answer_len);
1296 strcpy(result, rh->name);
1297 strcpy(result+strlen(rh->name), ".");
1298 strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
1300 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1301 "Our zone: Sending name as shorten result %s\n", rh->name);
1303 nsh->proc(nsh->proc_cls, result);
1305 free_resolver_handle(rh);
1306 GNUNET_free(result);
1310 /* backtrack authorities for names */
1311 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1312 &rh->authority_chain_tail->zone, //ours
1313 &rh->authority_chain_head->zone,
1314 &process_zone_to_name_shorten,
1320 * Shorten api from resolver
1322 * @param zone the zone to use
1323 * @param name the name to shorten
1324 * @param proc the processor to call with result
1325 * @param cls closure to pass to proc
1328 gns_resolver_shorten_name(GNUNET_HashCode zone,
1330 ShortenResultProcessor proc,
1333 struct ResolverHandle *rh;
1334 struct NameShortenHandle *nsh;
1336 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1337 "Starting shorten for %s!\n", name);
1339 if (is_canonical((char*)name))
1341 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1342 "%s is canonical. Returning verbatim\n", name);
1347 nsh = GNUNET_malloc(sizeof (struct NameShortenHandle));
1351 nsh->proc_cls = cls;
1353 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1354 rh->authority = zone;
1355 rh->name = GNUNET_malloc(strlen(name)
1356 - strlen(GNUNET_GNS_TLD));
1358 strlen(name)-strlen(GNUNET_GNS_TLD));
1359 memcpy(rh->name, name,
1360 strlen(name)-strlen(GNUNET_GNS_TLD)-1);
1362 rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
1363 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1364 rh->authority_chain_tail = rh->authority_chain_head;
1365 rh->authority_chain_head->zone = zone;
1366 rh->proc = &handle_delegation_ns_shorten;
1369 /* Start delegation resolution in our namestore */
1370 resolve_delegation_ns(rh);
1373 /*********** END NAME SHORTEN ********************/
1377 * Process result from namestore delegation lookup
1378 * for get authority operation
1380 * @param cls the client get auth handle
1381 * @param rh the resolver handle
1382 * @param rd_count number of results (0)
1383 * @param rd data (NULL)
1386 handle_delegation_result_ns_get_auth(void* cls,
1387 struct ResolverHandle *rh,
1389 const struct GNUNET_NAMESTORE_RecordData *rd)
1391 struct GetNameAuthorityHandle* nah;
1395 nah = (struct GetNameAuthorityHandle*) rh->proc_cls;
1398 * At this point rh->name contains the part of the name
1399 * that we do not have a PKEY in our namestore to resolve.
1400 * The authority chain in the resolver handle is now
1401 * useful to backtrack if needed
1404 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1405 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
1407 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1408 "Building response!\n");
1409 if (is_canonical(rh->name))
1412 * We successfully resolved the authority in the ns
1413 * FIXME for our purposes this is fine
1414 * but maybe we want to have an api that also looks
1415 * into the dht (i.e. option in message)
1417 if (strlen(rh->name) > strlen(nah->name))
1419 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1420 "Record name longer than original lookup name... odd!\n");
1424 answer_len = strlen(nah->name) - strlen(rh->name)
1425 + strlen(GNUNET_GNS_TLD) + 1;
1426 result = GNUNET_malloc(answer_len);
1427 memset(result, 0, answer_len);
1428 strcpy(result, nah->name + strlen(rh->name) + 1);
1430 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1431 "Got authority result %s\n", result);
1433 nah->proc(nah->proc_cls, result);
1434 GNUNET_free(nah->name);
1436 free_resolver_handle(rh);
1437 GNUNET_free(result);
1441 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1442 "Unable to resolve authority for remaining %s!\n", rh->name);
1443 nah->proc(nah->proc_cls, "");
1444 GNUNET_free(nah->name);
1446 free_resolver_handle(rh);
1454 * Tries to resolve the authority for name
1457 * @param zone the root zone to look up for
1458 * @param name the name to lookup up
1459 * @param proc the processor to call when finished
1460 * @param cls the closure to pass to the processor
1463 gns_resolver_get_authority(GNUNET_HashCode zone,
1465 GetAuthorityResultProcessor proc,
1468 struct ResolverHandle *rh;
1469 struct GetNameAuthorityHandle *nah;
1471 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1472 "Starting authority resolution for %s!\n", name);
1474 nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
1475 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1476 rh->authority = zone;
1478 if (strcmp(GNUNET_GNS_TLD, name) == 0)
1480 rh->name = GNUNET_malloc(2);
1481 strcpy(rh->name, "");
1485 rh->name = GNUNET_malloc(strlen(name)
1486 - strlen(GNUNET_GNS_TLD));
1488 strlen(name)-strlen(GNUNET_GNS_TLD));
1489 memcpy(rh->name, name,
1490 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
1493 nah->name = GNUNET_malloc(strlen(name)+1);
1494 memset(nah->name, 0,
1496 strcpy(nah->name, name);
1498 rh->authority_name = GNUNET_malloc(MAX_DNS_LABEL_LENGTH);
1500 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1501 rh->authority_chain_tail = rh->authority_chain_head;
1502 rh->authority_chain_head->zone = zone;
1503 rh->proc = &handle_delegation_result_ns_get_auth;
1504 rh->proc_cls = (void*)nah;
1507 nah->proc_cls = cls;
1509 /* Start delegation resolution in our namestore */
1510 resolve_delegation_ns(rh);
1514 /******** END GET AUTHORITY *************/
1516 /* end of gnunet-service-gns_resolver.c */