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 * Initialize the resolver
61 gns_resolver_init(struct GNUNET_NAMESTORE_Handle *nh,
62 struct GNUNET_DHT_Handle *dh)
64 namestore_handle = nh;
66 if ((namestore_handle != NULL) && (dht_handle != NULL))
75 * Helper function to free resolver handle
77 * @rh the handle to free
80 free_resolver_handle(struct ResolverHandle* rh)
82 struct AuthorityChain *ac;
83 struct AuthorityChain *ac_next;
88 GNUNET_free_non_null (rh->name);
89 GNUNET_free_non_null (rh->authority_name);
91 ac = rh->authority_chain_head;
96 GNUNET_free_non_null (ac->name);
105 * Callback when record data is put into namestore
107 * @param cls the closure
108 * @param success GNUNET_OK on success
109 * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
112 on_namestore_record_put_result(void *cls,
116 if (GNUNET_NO == success)
118 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "records already in namestore\n");
121 else if (GNUNET_YES == success)
123 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
124 "records successfully put in namestore\n");
128 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
129 "Error putting records into namestore: %s\n", emsg);
134 * Handle timeout for DHT requests
136 * @param cls the request handle as closure
137 * @param tc the task context
140 dht_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
142 struct ResolverHandle *rh = cls;
144 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
145 "dht lookup for query %s timed out.\n",
148 GNUNET_DHT_get_stop (rh->get_handle);
149 rh->proc(rh->proc_cls, rh, 0, NULL);
154 * Function called when we get a result from the dht
155 * for our record query
157 * @param cls the request handle
158 * @param exp lifetime
159 * @param key the key the record was stored under
160 * @param get_path get path
161 * @param get_path_length get path length
162 * @param put_path put path
163 * @param put_path_length put path length
164 * @param type the block type
165 * @param size the size of the record
166 * @param data the record data
169 process_record_result_dht(void* cls,
170 struct GNUNET_TIME_Absolute exp,
171 const GNUNET_HashCode * key,
172 const struct GNUNET_PeerIdentity *get_path,
173 unsigned int get_path_length,
174 const struct GNUNET_PeerIdentity *put_path,
175 unsigned int put_path_length,
176 enum GNUNET_BLOCK_Type type,
177 size_t size, const void *data)
179 struct ResolverHandle *rh;
180 struct RecordLookupHandle *rlh;
181 struct GNSNameRecordBlock *nrb;
182 uint32_t num_records;
184 char* rd_data = (char*)data;
188 GNUNET_HashCode zone, name_hash;
189 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "got dht result (size=%d)\n", size);
194 //FIXME maybe check expiration here, check block type
196 rh = (struct ResolverHandle *)cls;
197 rlh = (struct RecordLookupHandle *) rh->proc_cls;
198 nrb = (struct GNSNameRecordBlock*)data;
200 /* stop lookup and timeout task */
201 GNUNET_DHT_get_stop (rh->get_handle);
202 GNUNET_SCHEDULER_cancel(rh->dht_timeout_task);
204 rh->get_handle = NULL;
205 name = (char*)&nrb[1];
206 num_records = ntohl(nrb->rd_count);
208 struct GNUNET_NAMESTORE_RecordData rd[num_records];
210 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
211 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
213 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
218 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
222 for (i=0; i<num_records; i++)
224 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
225 "Got name: %s (wanted %s)\n", name, rh->name);
226 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
229 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
230 "Got data length: %d\n", rd[i].data_size);
231 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
232 "Got flag %d\n", rd[i].flags);
234 if ((strcmp(name, rh->name) == 0) &&
235 (rd[i].record_type == rlh->record_type))
242 GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
243 GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
246 * FIXME check pubkey against existing key in namestore?
247 * https://gnunet.org/bugs/view.php?id=2179
250 /* Save to namestore */
251 GNUNET_NAMESTORE_record_put (namestore_handle,
258 &on_namestore_record_put_result, //cont
262 rh->proc(rh->proc_cls, rh, num_records, rd);
264 rh->proc(rh->proc_cls, rh, 0, NULL);
271 * Start DHT lookup for a (name -> query->record_type) record in
272 * rh->authority's zone
274 * @param rh the pending gns query context
277 resolve_record_dht(struct ResolverHandle *rh)
280 GNUNET_HashCode name_hash;
281 GNUNET_HashCode lookup_key;
282 struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
283 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
285 GNUNET_CRYPTO_hash(rh->name, strlen(rh->name), &name_hash);
286 GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
287 GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
289 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
290 "starting dht lookup for %s with key: %s\n",
291 rh->name, (char*)&lookup_key_string);
293 rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed(DHT_LOOKUP_TIMEOUT,
294 &dht_lookup_timeout, rh);
296 xquery = htonl(rlh->record_type);
297 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
298 DHT_OPERATION_TIMEOUT,
299 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
301 DHT_GNS_REPLICATION_LEVEL,
305 &process_record_result_dht,
312 * Namestore calls this function if we have record for this name.
313 * (or with rd_count=0 to indicate no matches)
315 * @param cls the pending query
316 * @param key the key of the zone we did the lookup
317 * @param expiration expiration date of the namestore entry
318 * @param name the name for which we need an authority
319 * @param rd_count the number of records with 'name'
320 * @param rd the record data
321 * @param signature the signature of the authority for the record data
324 process_record_result_ns(void* cls,
325 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
326 struct GNUNET_TIME_Absolute expiration,
327 const char *name, unsigned int rd_count,
328 const struct GNUNET_NAMESTORE_RecordData *rd,
329 const struct GNUNET_CRYPTO_RsaSignature *signature)
331 struct ResolverHandle *rh;
332 struct RecordLookupHandle *rlh;
333 struct GNUNET_TIME_Relative remaining_time;
334 GNUNET_HashCode zone;
336 rh = (struct ResolverHandle *) cls;
337 rlh = (struct RecordLookupHandle *)rh->proc_cls;
338 GNUNET_CRYPTO_hash(key,
339 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
341 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
347 rh->status |= EXISTS;
350 if (remaining_time.rel_value == 0)
352 rh->status |= EXPIRED;
358 * Lookup terminated and no results
360 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
361 "Namestore lookup for %s terminated without results\n", name);
363 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
364 "Record %s unknown in namestore\n",
367 * Our zone and no result? Cannot resolve TT
369 rh->proc(rh->proc_cls, rh, 0, NULL);
376 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
377 "Processing additional result %s from namestore\n", name);
379 for (i=0; i<rd_count;i++)
382 if (rd[i].record_type != rlh->record_type)
385 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
388 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
389 "This record is expired. Skipping\n");
400 if (rh->answered == 0)
402 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
403 "No answers found. This is odd!\n");
404 rh->proc(rh->proc_cls, rh, 0, NULL);
408 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Found %d answer(s) to query!\n",
411 rh->proc(rh->proc_cls, rh, rd_count, rd);
417 * The final phase of resolution.
418 * rh->name is a name that is canonical and we do not have a delegation.
419 * Query namestore for this record
421 * @param rh the pending lookup
424 resolve_record_ns(struct ResolverHandle *rh)
426 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
429 * Try to resolve this record in our namestore.
430 * The name to resolve is now in rh->authority_name
431 * since we tried to resolve it to an authority
434 GNUNET_NAMESTORE_lookup_record(namestore_handle,
438 &process_record_result_ns,
444 * Handle timeout for DHT requests
446 * @param cls the request handle as closure
447 * @param tc the task context
450 dht_authority_lookup_timeout(void *cls,
451 const struct GNUNET_SCHEDULER_TaskContext *tc)
453 struct ResolverHandle *rh = cls;
455 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
456 "dht lookup for query %s timed out.\n",
459 GNUNET_DHT_get_stop (rh->get_handle);
460 if (strcmp(rh->name, "") == 0)
463 * promote authority back to name and try to resolve record
465 strcpy(rh->name, rh->authority_name);
467 rh->proc(rh->proc_cls, rh, 0, NULL);
471 static void resolve_delegation_dht(struct ResolverHandle *rh);
474 * Function called when we get a result from the dht
475 * for our query. Recursively tries to resolve authorities
478 * @param cls the request handle
479 * @param exp lifetime
480 * @param key the key the record was stored under
481 * @param get_path get path
482 * @param get_path_length get path length
483 * @param put_path put path
484 * @param put_path_length put path length
485 * @param type the block type
486 * @param size the size of the record
487 * @param data the record data
490 process_delegation_result_dht(void* cls,
491 struct GNUNET_TIME_Absolute exp,
492 const GNUNET_HashCode * key,
493 const struct GNUNET_PeerIdentity *get_path,
494 unsigned int get_path_length,
495 const struct GNUNET_PeerIdentity *put_path,
496 unsigned int put_path_length,
497 enum GNUNET_BLOCK_Type type,
498 size_t size, const void *data)
500 struct ResolverHandle *rh;
501 struct GNSNameRecordBlock *nrb;
502 uint32_t num_records;
504 char* rd_data = (char*) data;
507 GNUNET_HashCode zone, name_hash;
509 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got DHT result\n");
514 //FIXME check expiration?
516 rh = (struct ResolverHandle *)cls;
517 nrb = (struct GNSNameRecordBlock*)data;
519 /* stop dht lookup and timeout task */
520 GNUNET_DHT_get_stop (rh->get_handle);
521 GNUNET_SCHEDULER_cancel(rh->dht_timeout_task);
523 rh->get_handle = NULL;
524 num_records = ntohl(nrb->rd_count);
525 name = (char*)&nrb[1];
527 struct GNUNET_NAMESTORE_RecordData rd[num_records];
529 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
530 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
532 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
537 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
541 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
542 "Got name: %s (wanted %s)\n", name, rh->authority_name);
543 for (i=0; i<num_records; i++)
546 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
547 "Got name: %s (wanted %s)\n", name, rh->authority_name);
548 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
549 "Got type: %d (wanted %d)\n",
550 rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
551 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
552 "Got data length: %d\n", rd[i].data_size);
553 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
554 "Got flag %d\n", rd[i].flags);
556 if ((strcmp(name, rh->authority_name) == 0) &&
557 (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
559 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Authority found in DHT\n");
561 memcpy(&rh->authority, rd[i].data, sizeof(GNUNET_HashCode));
562 struct AuthorityChain *auth =
563 GNUNET_malloc(sizeof(struct AuthorityChain));
564 auth->zone = rh->authority;
565 auth->name = GNUNET_malloc(strlen(rh->authority_name)+1);
566 memset(auth->name, 0, strlen(rh->authority_name)+1);
567 strcpy(auth->name, rh->authority_name);
568 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
569 rh->authority_chain_tail,
576 GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
577 GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
579 /* Save to namestore */
580 if (0 != GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_tail->zone, &zone))
582 GNUNET_NAMESTORE_record_put (namestore_handle,
589 &on_namestore_record_put_result, //cont
599 * FIXME in this case. should we ask namestore again?
601 if (strcmp(rh->name, "") == 0)
602 rh->proc(rh->proc_cls, rh, 0, NULL);
604 resolve_delegation_dht(rh);
609 * No pkey but name exists
611 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "DHT authority lookup found no match!\n");
612 rh->proc(rh->proc_cls, rh, 0, NULL);
617 * Process DHT lookup result for record.
619 * @param cls the closure
620 * @param rh resolver handle
621 * @param rd_count number of results
622 * @param rd record data
625 handle_record_dht(void* cls, struct ResolverHandle *rh,
626 unsigned int rd_count,
627 const struct GNUNET_NAMESTORE_RecordData *rd)
629 struct RecordLookupHandle* rlh;
630 rlh = (struct RecordLookupHandle*)cls;
633 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
634 "No records for %s found in DHT. Aborting\n",
636 /* give up, cannot resolve */
637 rlh->proc(rlh->proc_cls, 0, NULL);
638 GNUNET_free(rlh->name);
640 free_resolver_handle(rh);
644 /* results found yay */
645 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
646 "Record resolved from DHT!");
647 rlh->proc(rlh->proc_cls, rd_count, rd);
648 GNUNET_free(rlh->name);
650 free_resolver_handle(rh);
656 * Process namestore lookup result for record.
658 * @param cls the closure
659 * @param rh resolver handle
660 * @param rd_count number of results
661 * @param rd record data
664 handle_record_ns(void* cls, struct ResolverHandle *rh,
665 unsigned int rd_count,
666 const struct GNUNET_NAMESTORE_RecordData *rd)
668 struct RecordLookupHandle* rlh;
669 rlh = (struct RecordLookupHandle*) cls;
672 /* ns entry expired and not ours. try dht */
673 if (rh->status & (EXPIRED | !EXISTS) &&
674 GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
675 &rh->authority_chain_tail->zone))
677 rh->proc = &handle_record_dht;
678 resolve_record_dht(rh);
681 /* give up, cannot resolve */
682 rlh->proc(rlh->proc_cls, 0, NULL);
683 GNUNET_free(rlh->name);
685 free_resolver_handle(rh);
689 /* results found yay */
690 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
691 "Record resolved from namestore!");
692 rlh->proc(rlh->proc_cls, rd_count, rd);
693 GNUNET_free(rlh->name);
695 free_resolver_handle(rh);
701 * Determine if this name is canonical.
703 * a.b.gnunet = not canonical
706 * @param name the name to test
707 * @return 1 if canonical
710 is_canonical(char* name)
712 uint32_t len = strlen(name);
715 for (i=0; i<len; i++)
717 if (*(name+i) == '.')
724 * Move one level up in the domain hierarchy and return the
725 * passed top level domain.
727 * @param name the domain
728 * @param dest the destination where the tld will be put
731 pop_tld(char* name, char* dest)
735 if (is_canonical(name))
742 for (len = strlen(name); len > 0; len--)
744 if (*(name+len) == '.')
754 strcpy(dest, (name+len+1));
758 * DHT resolution for delegation finished. Processing result.
760 * @param cls the closure
761 * @param rh resolver handle
762 * @param rd_count number of results (always 0)
763 * @param rd record data (always NULL)
766 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
767 unsigned int rd_count,
768 const struct GNUNET_NAMESTORE_RecordData *rd)
770 struct RecordLookupHandle* rlh;
771 rlh = (struct RecordLookupHandle*) cls;
773 if (strcmp(rh->name, "") == 0)
775 /* We resolved full name for delegation. resolving record */
776 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
777 "Resolved full name for delegation via DHT. resolving record '' in ns\n");
778 rh->proc = &handle_record_ns;
779 resolve_record_ns(rh);
784 * we still have some left
786 if (is_canonical(rh->name))
788 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
789 "Resolving canonical record %s in ns\n", rh->name);
790 rh->proc = &handle_record_ns;
791 resolve_record_ns(rh);
794 /* give up, cannot resolve */
795 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
796 "Cannot fully resolve delegation for %s via DHT!\n",
798 rlh->proc(rlh->proc_cls, 0, NULL);
799 GNUNET_free(rlh->name);
801 free_resolver_handle(rh);
806 * Start DHT lookup for a name -> PKEY (compare NS) record in
807 * rh->authority's zone
809 * @param rh the pending gns query
812 resolve_delegation_dht(struct ResolverHandle *rh)
815 GNUNET_HashCode name_hash;
816 GNUNET_HashCode lookup_key;
818 GNUNET_CRYPTO_hash(rh->authority_name,
819 strlen(rh->authority_name),
821 GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
823 rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
824 &dht_authority_lookup_timeout,
827 xquery = htonl(GNUNET_GNS_RECORD_PKEY);
829 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
830 DHT_OPERATION_TIMEOUT,
831 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
833 DHT_GNS_REPLICATION_LEVEL,
837 &process_delegation_result_dht,
844 * Namestore resolution for delegation finished. Processing result.
846 * @param cls the closure
847 * @param rh resolver handle
848 * @param rd_count number of results (always 0)
849 * @param rd record data (always NULL)
852 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
853 unsigned int rd_count,
854 const struct GNUNET_NAMESTORE_RecordData *rd)
856 struct RecordLookupHandle* rlh;
857 rlh = (struct RecordLookupHandle*) cls;
859 if (strcmp(rh->name, "") == 0)
861 /* We resolved full name for delegation. resolving record */
862 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
863 "Resolved full name for delegation. resolving record ''\n");
864 rh->proc = &handle_record_ns;
865 resolve_record_ns(rh);
870 * we still have some left
871 * check if authority in ns is fresh
873 * or we are authority
875 if ((rh->status & (EXISTS | !EXPIRED)) ||
876 !GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
877 &rh->authority_chain_tail->zone))
879 if (is_canonical(rh->name))
881 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
882 "Resolving canonical record %s\n", rh->name);
883 rh->proc = &handle_record_ns;
884 resolve_record_ns(rh);
888 /* give up, cannot resolve */
889 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
890 "Cannot fully resolve delegation for %s!\n",
892 rlh->proc(rlh->proc_cls, 0, NULL);
897 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
898 "Trying to resolve delegation for %s via DHT\n",
900 rh->proc = &handle_delegation_dht;
901 resolve_delegation_dht(rh);
905 static void resolve_delegation_ns(struct ResolverHandle *rh);
909 * This is a callback function that should give us only PKEY
910 * records. Used to query the namestore for the authority (PKEY)
911 * for 'name'. It will recursively try to resolve the
912 * authority for a given name from the namestore.
914 * @param cls the pending query
915 * @param key the key of the zone we did the lookup
916 * @param expiration expiration date of the record data set in the namestore
917 * @param name the name for which we need an authority
918 * @param rd_count the number of records with 'name'
919 * @param rd the record data
920 * @param signature the signature of the authority for the record data
923 process_delegation_result_ns(void* cls,
924 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
925 struct GNUNET_TIME_Absolute expiration,
927 unsigned int rd_count,
928 const struct GNUNET_NAMESTORE_RecordData *rd,
929 const struct GNUNET_CRYPTO_RsaSignature *signature)
931 struct ResolverHandle *rh;
932 struct GNUNET_TIME_Relative remaining_time;
933 GNUNET_HashCode zone;
936 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got %d records from authority lookup\n",
939 rh = (struct ResolverHandle *)cls;
940 GNUNET_CRYPTO_hash(key,
941 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
943 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
949 rh->status |= EXISTS;
952 if (remaining_time.rel_value == 0)
954 rh->status |= EXPIRED;
958 * No authority found in namestore.
963 * We did not find an authority in the namestore
968 * Promote this authority back to a name maybe it is
971 if (strcmp(rh->name, "") == 0)
973 /* simply promote back */
974 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
975 "Promoting %s back to name\n", rh->authority_name);
976 strcpy(rh->name, rh->authority_name);
980 /* add back to existing name */
981 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
982 "Adding %s back to %s\n",
983 rh->authority_name, rh->name);
984 new_name = GNUNET_malloc(strlen(rh->name)
985 + strlen(rh->authority_name) + 2);
986 memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
987 strcpy(new_name, rh->name);
988 strcpy(new_name+strlen(new_name)+1, ".");
989 strcpy(new_name+strlen(new_name)+2, rh->authority_name);
990 GNUNET_free(rh->name);
993 rh->proc(rh->proc_cls, rh, 0, NULL);
998 * We found an authority that may be able to help us
1000 * Note only 1 pkey should have been returned.. anything else would be strange
1003 for (i=0; i<rd_count;i++)
1006 if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
1009 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
1012 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This pkey is expired.\n");
1013 if (remaining_time.rel_value == 0)
1015 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1016 "This dht entry is expired.\n");
1017 rh->authority_chain_head->fresh = 0;
1018 rh->proc(rh->proc_cls, rh, 0, NULL);
1026 * Resolve rest of query with new authority
1028 GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
1029 memcpy(&rh->authority, rd[i].data, sizeof(GNUNET_HashCode));
1030 struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
1031 auth->zone = rh->authority;
1032 auth->name = GNUNET_malloc(strlen(rh->authority_name)+1);
1033 memset(auth->name, 0, strlen(rh->authority_name)+1);
1034 strcpy(auth->name, rh->authority_name);
1035 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1036 rh->authority_chain_tail,
1040 * We are done with PKEY resolution if name is empty
1041 * else resolve again with new authority
1043 if (strcmp(rh->name, "") == 0)
1044 rh->proc(rh->proc_cls, rh, 0, NULL);
1046 resolve_delegation_ns(rh);
1053 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1054 "Authority lookup successful but no PKEY... never get here\n");
1055 rh->proc(rh->proc_cls, rh, 0, NULL);
1060 * Resolve the delegation chain for the request in our namestore
1062 * @param rh the resolver handle
1065 resolve_delegation_ns(struct ResolverHandle *rh)
1067 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1068 "Resolving delegation for %s\n", rh->name);
1069 pop_tld(rh->name, rh->authority_name);
1070 GNUNET_NAMESTORE_lookup_record(namestore_handle,
1073 GNUNET_GNS_RECORD_PKEY,
1074 &process_delegation_result_ns,
1081 * Lookup of a record in a specific zone
1082 * calls lookup result processor on result
1084 * @param zone the root zone
1085 * @param record_type the record type to look up
1086 * @param name the name to look up
1087 * @param proc the processor to call on result
1088 * @param cls the closure to pass to proc
1091 gns_resolver_lookup_record(GNUNET_HashCode zone,
1092 uint32_t record_type,
1094 RecordLookupProcessor proc,
1097 struct ResolverHandle *rh;
1098 struct RecordLookupHandle* rlh;
1100 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1101 "Starting resolution for %s (type=%d)!\n",
1105 if (is_canonical((char*)name) && (strcmp(GNUNET_GNS_TLD, name) != 0))
1107 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1108 "%s is canonical and gnunet not our TLD!\n", name);
1113 rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
1114 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1116 rh->authority = zone;
1119 if (strcmp(GNUNET_GNS_TLD, name) == 0)
1121 rh->name = GNUNET_malloc(2);
1122 strcpy(rh->name, "");
1126 rh->name = GNUNET_malloc(strlen(name)
1127 - strlen(GNUNET_GNS_TLD));
1129 strlen(name)-strlen(GNUNET_GNS_TLD));
1130 memcpy(rh->name, name,
1131 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
1134 rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
1135 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1136 rh->authority_chain_head->prev = NULL;
1137 rh->authority_chain_head->next = NULL;
1138 rh->authority_chain_tail = rh->authority_chain_head;
1139 rh->authority_chain_head->zone = zone;
1141 rlh->record_type = record_type;
1142 rlh->name = GNUNET_malloc(strlen(name) + 1);
1143 memset(rlh->name, 0, strlen(name) + 1);
1144 strcpy(rlh->name, name); //FIXME
1146 rlh->proc_cls = cls;
1148 rh->proc = &handle_delegation_ns;
1149 resolve_delegation_ns(rh);
1152 /******** END Record Resolver ***********/
1156 * Callback calles by namestore for a zone to name
1159 * @param cls the closure
1160 * @param zone_key the zone we queried
1161 * @param expire the expiration time of the name
1162 * @param name the name found or NULL
1163 * @param rd_len number of records for the name
1164 * @param rd the record data (PKEY) for the name
1165 * @param signature the signature for the record data
1168 process_zone_to_name_shorten(void *cls,
1169 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1170 struct GNUNET_TIME_Absolute expire,
1172 unsigned int rd_len,
1173 const struct GNUNET_NAMESTORE_RecordData *rd,
1174 const struct GNUNET_CRYPTO_RsaSignature *signature)
1176 struct ResolverHandle *rh = (struct ResolverHandle *)cls;
1177 struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
1178 struct AuthorityChain *next_authority;
1181 char* next_authority_name;
1184 /* we found a match in our own zone */
1187 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1188 "result strlen %d\n", strlen(name));
1189 answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
1190 result = GNUNET_malloc(answer_len);
1191 memset(result, 0, answer_len);
1192 if (strlen(rh->name) > 0)
1194 strcpy(result, rh->name);
1195 strcpy(result+strlen(rh->name), ".");
1198 strcpy(result+strlen(result), name);
1199 strcpy(result+strlen(result), ".");
1200 strcpy(result+strlen(result), GNUNET_GNS_TLD);
1202 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1203 "Sending shorten result %s\n", result);
1205 nsh->proc(nsh->proc_cls, result);
1207 free_resolver_handle(rh);
1208 GNUNET_free(result);
1210 else if (GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
1211 &rh->authority_chain_tail->zone))
1213 /* our zone, just append .gnunet */
1214 answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
1215 result = GNUNET_malloc(answer_len);
1216 memset(result, 0, answer_len);
1217 strcpy(result, rh->name);
1218 strcpy(result+strlen(rh->name), ".");
1219 strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
1221 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1222 "Our zone: Sending name as shorten result %s\n", rh->name);
1224 nsh->proc(nsh->proc_cls, result);
1226 free_resolver_handle(rh);
1227 GNUNET_free(result);
1233 * continue with next authority
1235 next_authority = rh->authority_chain_head;
1236 next_authority_name = GNUNET_malloc(strlen(rh->name)+
1237 strlen(next_authority->name) + 2);
1238 memset(next_authority_name, 0, strlen(rh->name)+
1239 strlen(next_authority->name) + 2);
1240 strcpy(next_authority_name, rh->name);
1241 strcpy(next_authority_name+strlen(rh->name)+1, ".");
1242 strcpy(next_authority_name+strlen(rh->name)+2, next_authority->name);
1244 GNUNET_free(rh->name);
1245 rh->name = next_authority_name;
1246 GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
1247 rh->authority_chain_tail,
1250 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1251 &rh->authority_chain_tail->zone,
1252 &rh->authority_chain_head->zone,
1253 &process_zone_to_name_shorten,
1260 * Process result from namestore delegation lookup
1261 * for shorten operation
1263 * @param cls the client shorten handle
1264 * @param rh the resolver handle
1265 * @param rd_count number of results (0)
1266 * @param rd data (NULL)
1269 handle_delegation_ns_shorten(void* cls,
1270 struct ResolverHandle *rh,
1272 const struct GNUNET_NAMESTORE_RecordData *rd)
1274 struct NameShortenHandle *nsh;
1278 nsh = (struct NameShortenHandle *)cls;
1281 * At this point rh->name contains the part of the name
1282 * that we do not have a PKEY in our namestore to resolve.
1283 * The authority chain in the resolver handle is now
1284 * useful to backtrack if needed
1287 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1288 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
1290 if (GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
1291 &rh->authority_chain_tail->zone) == 0)
1294 * This is our zone append .gnunet unless name is empty
1295 * (it shouldn't be, usually FIXME what happens if we
1296 * shorten to our zone to a "" record??)
1299 answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
1300 result = GNUNET_malloc(answer_len);
1301 memset(result, 0, answer_len);
1302 strcpy(result, rh->name);
1303 strcpy(result+strlen(rh->name), ".");
1304 strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
1306 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1307 "Our zone: Sending name as shorten result %s\n", rh->name);
1309 nsh->proc(nsh->proc_cls, result);
1311 free_resolver_handle(rh);
1312 GNUNET_free(result);
1316 /* backtrack authorities for names */
1317 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1318 &rh->authority_chain_tail->zone, //ours
1319 &rh->authority_chain_head->zone,
1320 &process_zone_to_name_shorten,
1326 * Shorten api from resolver
1328 * @param zone the zone to use
1329 * @param name the name to shorten
1330 * @param proc the processor to call with result
1331 * @param cls closure to pass to proc
1334 gns_resolver_shorten_name(GNUNET_HashCode zone,
1336 ShortenResultProcessor proc,
1339 struct ResolverHandle *rh;
1340 struct NameShortenHandle *nsh;
1342 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1343 "Starting shorten for %s!\n", name);
1345 if (is_canonical((char*)name))
1347 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1348 "%s is canonical. Returning verbatim\n", name);
1353 nsh = GNUNET_malloc(sizeof (struct NameShortenHandle));
1357 nsh->proc_cls = cls;
1359 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1360 rh->authority = zone;
1361 rh->name = GNUNET_malloc(strlen(name)
1362 - strlen(GNUNET_GNS_TLD));
1364 strlen(name)-strlen(GNUNET_GNS_TLD));
1365 memcpy(rh->name, name,
1366 strlen(name)-strlen(GNUNET_GNS_TLD)-1);
1368 rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
1369 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1370 rh->authority_chain_tail = rh->authority_chain_head;
1371 rh->authority_chain_head->zone = zone;
1372 rh->proc = &handle_delegation_ns_shorten;
1375 /* Start delegation resolution in our namestore */
1376 resolve_delegation_ns(rh);
1379 /*********** END NAME SHORTEN ********************/
1383 * Process result from namestore delegation lookup
1384 * for get authority operation
1386 * @param cls the client get auth handle
1387 * @param rh the resolver handle
1388 * @param rd_count number of results (0)
1389 * @param rd data (NULL)
1392 handle_delegation_result_ns_get_auth(void* cls,
1393 struct ResolverHandle *rh,
1395 const struct GNUNET_NAMESTORE_RecordData *rd)
1397 struct GetNameAuthorityHandle* nah;
1401 nah = (struct GetNameAuthorityHandle*) rh->proc_cls;
1404 * At this point rh->name contains the part of the name
1405 * that we do not have a PKEY in our namestore to resolve.
1406 * The authority chain in the resolver handle is now
1407 * useful to backtrack if needed
1410 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1411 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
1413 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1414 "Building response!\n");
1415 if (is_canonical(rh->name))
1418 * We successfully resolved the authority in the ns
1419 * FIXME for our purposes this is fine
1420 * but maybe we want to have an api that also looks
1421 * into the dht (i.e. option in message)
1423 if (strlen(rh->name) > strlen(nah->name))
1425 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1426 "Record name longer than original lookup name... odd!\n");
1430 answer_len = strlen(nah->name) - strlen(rh->name)
1431 + strlen(GNUNET_GNS_TLD) + 1;
1432 result = GNUNET_malloc(answer_len);
1433 memset(result, 0, answer_len);
1434 strcpy(result, nah->name + strlen(rh->name) + 1);
1436 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1437 "Got authority result %s\n", result);
1439 nah->proc(nah->proc_cls, result);
1440 GNUNET_free(nah->name);
1442 free_resolver_handle(rh);
1443 GNUNET_free(result);
1447 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1448 "Unable to resolve authority for remaining %s!\n", rh->name);
1449 nah->proc(nah->proc_cls, "");
1450 GNUNET_free(nah->name);
1452 free_resolver_handle(rh);
1460 * Tries to resolve the authority for name
1463 * @param zone the root zone to look up for
1464 * @param name the name to lookup up
1465 * @param proc the processor to call when finished
1466 * @param cls the closure to pass to the processor
1469 gns_resolver_get_authority(GNUNET_HashCode zone,
1471 GetAuthorityResultProcessor proc,
1474 struct ResolverHandle *rh;
1475 struct GetNameAuthorityHandle *nah;
1477 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1478 "Starting authority resolution for %s!\n", name);
1480 nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
1481 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1482 rh->authority = zone;
1484 if (strcmp(GNUNET_GNS_TLD, name) == 0)
1486 rh->name = GNUNET_malloc(2);
1487 strcpy(rh->name, "");
1491 rh->name = GNUNET_malloc(strlen(name)
1492 - strlen(GNUNET_GNS_TLD));
1494 strlen(name)-strlen(GNUNET_GNS_TLD));
1495 memcpy(rh->name, name,
1496 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
1499 nah->name = GNUNET_malloc(strlen(name)+1);
1500 memset(nah->name, 0,
1502 strcpy(nah->name, name);
1504 rh->authority_name = GNUNET_malloc(MAX_DNS_LABEL_LENGTH);
1506 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1507 rh->authority_chain_tail = rh->authority_chain_head;
1508 rh->authority_chain_head->zone = zone;
1509 rh->proc = &handle_delegation_result_ns_get_auth;
1510 rh->proc_cls = (void*)nah;
1513 nah->proc_cls = cls;
1515 /* Start delegation resolution in our namestore */
1516 resolve_delegation_ns(rh);
1520 /******** END GET AUTHORITY *************/
1522 /* end of gnunet-service-gns_resolver.c */