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
60 * @param nh the namestore handle
61 * @param dh the dht handle
62 * @return GNUNET_OK on success
65 gns_resolver_init(struct GNUNET_NAMESTORE_Handle *nh,
66 struct GNUNET_DHT_Handle *dh)
68 namestore_handle = nh;
70 if ((namestore_handle != NULL) && (dht_handle != NULL))
78 * Set the callback to call when we discover a
79 * new authority via the DHT
81 * @param adb the callback to set
84 gns_resolver_set_auth_discovered_cb(AuthorityDiscoveredProcessor adb)
86 auth_discovered = adb;
91 * Helper function to free resolver handle
93 * @rh the handle to free
96 free_resolver_handle(struct ResolverHandle* rh)
98 struct AuthorityChain *ac;
99 struct AuthorityChain *ac_next;
104 GNUNET_free_non_null (rh->name);
105 GNUNET_free_non_null (rh->authority_name);
107 ac = rh->authority_chain_head;
112 GNUNET_free_non_null (ac->name);
121 * Callback when record data is put into namestore
123 * @param cls the closure
124 * @param success GNUNET_OK on success
125 * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
128 on_namestore_record_put_result(void *cls,
132 if (GNUNET_NO == success)
134 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "records already in namestore\n");
137 else if (GNUNET_YES == success)
139 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
140 "records successfully put in namestore\n");
144 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
145 "Error putting records into namestore: %s\n", emsg);
150 * Handle timeout for DHT requests
152 * @param cls the request handle as closure
153 * @param tc the task context
156 dht_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
158 struct ResolverHandle *rh = cls;
160 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
161 "dht lookup for query %s timed out.\n",
164 GNUNET_DHT_get_stop (rh->get_handle);
165 rh->proc(rh->proc_cls, rh, 0, NULL);
170 * Function called when we get a result from the dht
171 * for our record query
173 * @param cls the request handle
174 * @param exp lifetime
175 * @param key the key the record was stored under
176 * @param get_path get path
177 * @param get_path_length get path length
178 * @param put_path put path
179 * @param put_path_length put path length
180 * @param type the block type
181 * @param size the size of the record
182 * @param data the record data
185 process_record_result_dht(void* cls,
186 struct GNUNET_TIME_Absolute exp,
187 const GNUNET_HashCode * key,
188 const struct GNUNET_PeerIdentity *get_path,
189 unsigned int get_path_length,
190 const struct GNUNET_PeerIdentity *put_path,
191 unsigned int put_path_length,
192 enum GNUNET_BLOCK_Type type,
193 size_t size, const void *data)
195 struct ResolverHandle *rh;
196 struct RecordLookupHandle *rlh;
197 struct GNSNameRecordBlock *nrb;
198 uint32_t num_records;
200 char* rd_data = (char*)data;
204 GNUNET_HashCode zone, name_hash;
205 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "got dht result (size=%d)\n", size);
210 //FIXME maybe check expiration here, check block type
212 rh = (struct ResolverHandle *)cls;
213 rlh = (struct RecordLookupHandle *) rh->proc_cls;
214 nrb = (struct GNSNameRecordBlock*)data;
216 /* stop lookup and timeout task */
217 GNUNET_DHT_get_stop (rh->get_handle);
218 GNUNET_SCHEDULER_cancel(rh->dht_timeout_task);
220 rh->get_handle = NULL;
221 name = (char*)&nrb[1];
222 num_records = ntohl(nrb->rd_count);
224 struct GNUNET_NAMESTORE_RecordData rd[num_records];
226 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
227 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
229 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
234 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
238 for (i=0; i<num_records; i++)
240 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
241 "Got name: %s (wanted %s)\n", name, rh->name);
242 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
245 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
246 "Got data length: %d\n", rd[i].data_size);
247 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
248 "Got flag %d\n", rd[i].flags);
250 if ((strcmp(name, rh->name) == 0) &&
251 (rd[i].record_type == rlh->record_type))
258 GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
259 GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
262 * FIXME check pubkey against existing key in namestore?
263 * https://gnunet.org/bugs/view.php?id=2179
266 /* Save to namestore */
267 GNUNET_NAMESTORE_record_put (namestore_handle,
274 &on_namestore_record_put_result, //cont
278 rh->proc(rh->proc_cls, rh, num_records, rd);
280 rh->proc(rh->proc_cls, rh, 0, NULL);
287 * Start DHT lookup for a (name -> query->record_type) record in
288 * rh->authority's zone
290 * @param rh the pending gns query context
293 resolve_record_dht(struct ResolverHandle *rh)
296 GNUNET_HashCode name_hash;
297 GNUNET_HashCode lookup_key;
298 struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
299 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
301 GNUNET_CRYPTO_hash(rh->name, strlen(rh->name), &name_hash);
302 GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
303 GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
305 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
306 "starting dht lookup for %s with key: %s\n",
307 rh->name, (char*)&lookup_key_string);
309 rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed(DHT_LOOKUP_TIMEOUT,
310 &dht_lookup_timeout, rh);
312 xquery = htonl(rlh->record_type);
313 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
314 DHT_OPERATION_TIMEOUT,
315 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
317 DHT_GNS_REPLICATION_LEVEL,
321 &process_record_result_dht,
328 * Namestore calls this function if we have record for this name.
329 * (or with rd_count=0 to indicate no matches)
331 * @param cls the pending query
332 * @param key the key of the zone we did the lookup
333 * @param expiration expiration date of the namestore entry
334 * @param name the name for which we need an authority
335 * @param rd_count the number of records with 'name'
336 * @param rd the record data
337 * @param signature the signature of the authority for the record data
340 process_record_result_ns(void* cls,
341 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
342 struct GNUNET_TIME_Absolute expiration,
343 const char *name, unsigned int rd_count,
344 const struct GNUNET_NAMESTORE_RecordData *rd,
345 const struct GNUNET_CRYPTO_RsaSignature *signature)
347 struct ResolverHandle *rh;
348 struct RecordLookupHandle *rlh;
349 struct GNUNET_TIME_Relative remaining_time;
350 GNUNET_HashCode zone;
352 rh = (struct ResolverHandle *) cls;
353 rlh = (struct RecordLookupHandle *)rh->proc_cls;
354 GNUNET_CRYPTO_hash(key,
355 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
357 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
363 rh->status |= EXISTS;
366 if (remaining_time.rel_value == 0)
368 rh->status |= EXPIRED;
374 * Lookup terminated and no results
376 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
377 "Namestore lookup for %s terminated without results\n", name);
379 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
380 "Record %s unknown in namestore\n",
383 * Our zone and no result? Cannot resolve TT
385 rh->proc(rh->proc_cls, rh, 0, NULL);
392 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
393 "Processing additional result %s from namestore\n", name);
395 for (i=0; i<rd_count;i++)
398 if (rd[i].record_type != rlh->record_type)
401 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
404 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
405 "This record is expired. Skipping\n");
416 if (rh->answered == 0)
418 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
419 "No answers found. This is odd!\n");
420 rh->proc(rh->proc_cls, rh, 0, NULL);
424 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Found %d answer(s) to query!\n",
427 rh->proc(rh->proc_cls, rh, rd_count, rd);
433 * The final phase of resolution.
434 * rh->name is a name that is canonical and we do not have a delegation.
435 * Query namestore for this record
437 * @param rh the pending lookup
440 resolve_record_ns(struct ResolverHandle *rh)
442 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
445 * Try to resolve this record in our namestore.
446 * The name to resolve is now in rh->authority_name
447 * since we tried to resolve it to an authority
450 GNUNET_NAMESTORE_lookup_record(namestore_handle,
454 &process_record_result_ns,
460 * Handle timeout for DHT requests
462 * @param cls the request handle as closure
463 * @param tc the task context
466 dht_authority_lookup_timeout(void *cls,
467 const struct GNUNET_SCHEDULER_TaskContext *tc)
469 struct ResolverHandle *rh = cls;
471 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
472 "dht lookup for query %s timed out.\n",
475 GNUNET_DHT_get_stop (rh->get_handle);
476 if (strcmp(rh->name, "") == 0)
479 * promote authority back to name and try to resolve record
481 strcpy(rh->name, rh->authority_name);
483 rh->proc(rh->proc_cls, rh, 0, NULL);
487 static void resolve_delegation_dht(struct ResolverHandle *rh);
490 * Function called when we get a result from the dht
491 * for our query. Recursively tries to resolve authorities
494 * @param cls the request handle
495 * @param exp lifetime
496 * @param key the key the record was stored under
497 * @param get_path get path
498 * @param get_path_length get path length
499 * @param put_path put path
500 * @param put_path_length put path length
501 * @param type the block type
502 * @param size the size of the record
503 * @param data the record data
506 process_delegation_result_dht(void* cls,
507 struct GNUNET_TIME_Absolute exp,
508 const GNUNET_HashCode * key,
509 const struct GNUNET_PeerIdentity *get_path,
510 unsigned int get_path_length,
511 const struct GNUNET_PeerIdentity *put_path,
512 unsigned int put_path_length,
513 enum GNUNET_BLOCK_Type type,
514 size_t size, const void *data)
516 struct ResolverHandle *rh;
517 struct GNSNameRecordBlock *nrb;
518 uint32_t num_records;
520 char* rd_data = (char*) data;
523 GNUNET_HashCode zone, name_hash;
525 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got DHT result\n");
530 //FIXME check expiration?
532 rh = (struct ResolverHandle *)cls;
533 nrb = (struct GNSNameRecordBlock*)data;
535 /* stop dht lookup and timeout task */
536 GNUNET_DHT_get_stop (rh->get_handle);
537 GNUNET_SCHEDULER_cancel(rh->dht_timeout_task);
539 rh->get_handle = NULL;
540 num_records = ntohl(nrb->rd_count);
541 name = (char*)&nrb[1];
543 struct GNUNET_NAMESTORE_RecordData rd[num_records];
545 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
546 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
548 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
553 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
557 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
558 "Got name: %s (wanted %s)\n", name, rh->authority_name);
559 for (i=0; i<num_records; i++)
562 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
563 "Got name: %s (wanted %s)\n", name, rh->authority_name);
564 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
565 "Got type: %d (wanted %d)\n",
566 rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
567 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
568 "Got data length: %d\n", rd[i].data_size);
569 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
570 "Got flag %d\n", rd[i].flags);
572 if ((strcmp(name, rh->authority_name) == 0) &&
573 (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
575 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Authority found in DHT\n");
577 memcpy(&rh->authority, rd[i].data, sizeof(GNUNET_HashCode));
578 struct AuthorityChain *auth =
579 GNUNET_malloc(sizeof(struct AuthorityChain));
580 auth->zone = rh->authority;
581 auth->name = GNUNET_malloc(strlen(rh->authority_name)+1);
582 memset(auth->name, 0, strlen(rh->authority_name)+1);
583 strcpy(auth->name, rh->authority_name);
584 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
585 rh->authority_chain_tail,
592 GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
593 GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
595 /* Save to namestore */
596 if (0 != GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_tail->zone, &zone))
598 GNUNET_NAMESTORE_record_put (namestore_handle,
605 &on_namestore_record_put_result, //cont
615 * FIXME in this case. should we ask namestore again?
617 if (strcmp(rh->name, "") == 0)
618 rh->proc(rh->proc_cls, rh, 0, NULL);
620 resolve_delegation_dht(rh);
625 * No pkey but name exists
627 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "DHT authority lookup found no match!\n");
628 rh->proc(rh->proc_cls, rh, 0, NULL);
633 * Process DHT lookup result for record.
635 * @param cls the closure
636 * @param rh resolver handle
637 * @param rd_count number of results
638 * @param rd record data
641 handle_record_dht(void* cls, struct ResolverHandle *rh,
642 unsigned int rd_count,
643 const struct GNUNET_NAMESTORE_RecordData *rd)
645 struct RecordLookupHandle* rlh;
646 rlh = (struct RecordLookupHandle*)cls;
649 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
650 "No records for %s found in DHT. Aborting\n",
652 /* give up, cannot resolve */
653 rlh->proc(rlh->proc_cls, 0, NULL);
654 GNUNET_free(rlh->name);
656 free_resolver_handle(rh);
660 /* results found yay */
661 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
662 "Record resolved from DHT!");
663 rlh->proc(rlh->proc_cls, rd_count, rd);
664 GNUNET_free(rlh->name);
666 free_resolver_handle(rh);
672 * Process namestore lookup result for record.
674 * @param cls the closure
675 * @param rh resolver handle
676 * @param rd_count number of results
677 * @param rd record data
680 handle_record_ns(void* cls, struct ResolverHandle *rh,
681 unsigned int rd_count,
682 const struct GNUNET_NAMESTORE_RecordData *rd)
684 struct RecordLookupHandle* rlh;
685 rlh = (struct RecordLookupHandle*) cls;
688 /* ns entry expired and not ours. try dht */
689 if (rh->status & (EXPIRED | !EXISTS) &&
690 GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
691 &rh->authority_chain_tail->zone))
693 rh->proc = &handle_record_dht;
694 resolve_record_dht(rh);
697 /* give up, cannot resolve */
698 rlh->proc(rlh->proc_cls, 0, NULL);
699 GNUNET_free(rlh->name);
701 free_resolver_handle(rh);
705 /* results found yay */
706 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
707 "Record resolved from namestore!");
708 rlh->proc(rlh->proc_cls, rd_count, rd);
709 GNUNET_free(rlh->name);
711 free_resolver_handle(rh);
717 * Determine if this name is canonical.
719 * a.b.gnunet = not canonical
722 * @param name the name to test
723 * @return 1 if canonical
726 is_canonical(char* name)
728 uint32_t len = strlen(name);
731 for (i=0; i<len; i++)
733 if (*(name+i) == '.')
740 * Move one level up in the domain hierarchy and return the
741 * passed top level domain.
743 * @param name the domain
744 * @param dest the destination where the tld will be put
747 pop_tld(char* name, char* dest)
751 if (is_canonical(name))
758 for (len = strlen(name); len > 0; len--)
760 if (*(name+len) == '.')
770 strcpy(dest, (name+len+1));
774 * DHT resolution for delegation finished. Processing result.
776 * @param cls the closure
777 * @param rh resolver handle
778 * @param rd_count number of results (always 0)
779 * @param rd record data (always NULL)
782 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
783 unsigned int rd_count,
784 const struct GNUNET_NAMESTORE_RecordData *rd)
786 struct RecordLookupHandle* rlh;
787 rlh = (struct RecordLookupHandle*) cls;
789 if (strcmp(rh->name, "") == 0)
791 /* We resolved full name for delegation. resolving record */
792 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
793 "Resolved full name for delegation via DHT. resolving record '' in ns\n");
794 rh->proc = &handle_record_ns;
795 resolve_record_ns(rh);
800 * we still have some left
802 if (is_canonical(rh->name))
804 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
805 "Resolving canonical record %s in ns\n", rh->name);
806 rh->proc = &handle_record_ns;
807 resolve_record_ns(rh);
810 /* give up, cannot resolve */
811 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
812 "Cannot fully resolve delegation for %s via DHT!\n",
814 rlh->proc(rlh->proc_cls, 0, NULL);
815 GNUNET_free(rlh->name);
817 free_resolver_handle(rh);
822 * Start DHT lookup for a name -> PKEY (compare NS) record in
823 * rh->authority's zone
825 * @param rh the pending gns query
828 resolve_delegation_dht(struct ResolverHandle *rh)
831 GNUNET_HashCode name_hash;
832 GNUNET_HashCode lookup_key;
834 GNUNET_CRYPTO_hash(rh->authority_name,
835 strlen(rh->authority_name),
837 GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
839 rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
840 &dht_authority_lookup_timeout,
843 xquery = htonl(GNUNET_GNS_RECORD_PKEY);
845 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
846 DHT_OPERATION_TIMEOUT,
847 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
849 DHT_GNS_REPLICATION_LEVEL,
853 &process_delegation_result_dht,
860 * Namestore resolution for delegation finished. Processing result.
862 * @param cls the closure
863 * @param rh resolver handle
864 * @param rd_count number of results (always 0)
865 * @param rd record data (always NULL)
868 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
869 unsigned int rd_count,
870 const struct GNUNET_NAMESTORE_RecordData *rd)
872 struct RecordLookupHandle* rlh;
873 rlh = (struct RecordLookupHandle*) cls;
875 if (strcmp(rh->name, "") == 0)
877 /* We resolved full name for delegation. resolving record */
878 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
879 "Resolved full name for delegation. resolving record ''\n");
880 rh->proc = &handle_record_ns;
881 resolve_record_ns(rh);
886 * we still have some left
887 * check if authority in ns is fresh
889 * or we are authority
891 if ((rh->status & (EXISTS | !EXPIRED)) ||
892 !GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
893 &rh->authority_chain_tail->zone))
895 if (is_canonical(rh->name))
897 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
898 "Resolving canonical record %s\n", rh->name);
899 rh->proc = &handle_record_ns;
900 resolve_record_ns(rh);
904 /* give up, cannot resolve */
905 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
906 "Cannot fully resolve delegation for %s!\n",
908 rlh->proc(rlh->proc_cls, 0, NULL);
913 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
914 "Trying to resolve delegation for %s via DHT\n",
916 rh->proc = &handle_delegation_dht;
917 resolve_delegation_dht(rh);
921 static void resolve_delegation_ns(struct ResolverHandle *rh);
925 * This is a callback function that should give us only PKEY
926 * records. Used to query the namestore for the authority (PKEY)
927 * for 'name'. It will recursively try to resolve the
928 * authority for a given name from the namestore.
930 * @param cls the pending query
931 * @param key the key of the zone we did the lookup
932 * @param expiration expiration date of the record data set in the namestore
933 * @param name the name for which we need an authority
934 * @param rd_count the number of records with 'name'
935 * @param rd the record data
936 * @param signature the signature of the authority for the record data
939 process_delegation_result_ns(void* cls,
940 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
941 struct GNUNET_TIME_Absolute expiration,
943 unsigned int rd_count,
944 const struct GNUNET_NAMESTORE_RecordData *rd,
945 const struct GNUNET_CRYPTO_RsaSignature *signature)
947 struct ResolverHandle *rh;
948 struct GNUNET_TIME_Relative remaining_time;
949 GNUNET_HashCode zone;
952 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got %d records from authority lookup\n",
955 rh = (struct ResolverHandle *)cls;
956 GNUNET_CRYPTO_hash(key,
957 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
959 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
965 rh->status |= EXISTS;
968 if (remaining_time.rel_value == 0)
970 rh->status |= EXPIRED;
974 * No authority found in namestore.
979 * We did not find an authority in the namestore
984 * Promote this authority back to a name maybe it is
987 if (strcmp(rh->name, "") == 0)
989 /* simply promote back */
990 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
991 "Promoting %s back to name\n", rh->authority_name);
992 strcpy(rh->name, rh->authority_name);
996 /* add back to existing name */
997 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
998 "Adding %s back to %s\n",
999 rh->authority_name, rh->name);
1000 new_name = GNUNET_malloc(strlen(rh->name)
1001 + strlen(rh->authority_name) + 2);
1002 memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
1003 strcpy(new_name, rh->name);
1004 strcpy(new_name+strlen(new_name)+1, ".");
1005 strcpy(new_name+strlen(new_name)+2, rh->authority_name);
1006 GNUNET_free(rh->name);
1007 rh->name = new_name;
1009 rh->proc(rh->proc_cls, rh, 0, NULL);
1014 * We found an authority that may be able to help us
1015 * move on with query
1016 * Note only 1 pkey should have been returned.. anything else would be strange
1019 for (i=0; i<rd_count;i++)
1022 if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
1025 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
1028 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This pkey is expired.\n");
1029 if (remaining_time.rel_value == 0)
1031 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1032 "This dht entry is expired.\n");
1033 rh->authority_chain_head->fresh = 0;
1034 rh->proc(rh->proc_cls, rh, 0, NULL);
1042 * Resolve rest of query with new authority
1044 GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
1045 memcpy(&rh->authority, rd[i].data, sizeof(GNUNET_HashCode));
1046 struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
1047 auth->zone = rh->authority;
1048 auth->name = GNUNET_malloc(strlen(rh->authority_name)+1);
1049 memset(auth->name, 0, strlen(rh->authority_name)+1);
1050 strcpy(auth->name, rh->authority_name);
1051 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1052 rh->authority_chain_tail,
1056 * We are done with PKEY resolution if name is empty
1057 * else resolve again with new authority
1059 if (strcmp(rh->name, "") == 0)
1060 rh->proc(rh->proc_cls, rh, 0, NULL);
1062 resolve_delegation_ns(rh);
1069 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1070 "Authority lookup successful but no PKEY... never get here\n");
1071 rh->proc(rh->proc_cls, rh, 0, NULL);
1076 * Resolve the delegation chain for the request in our namestore
1078 * @param rh the resolver handle
1081 resolve_delegation_ns(struct ResolverHandle *rh)
1083 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1084 "Resolving delegation for %s\n", rh->name);
1085 pop_tld(rh->name, rh->authority_name);
1086 GNUNET_NAMESTORE_lookup_record(namestore_handle,
1089 GNUNET_GNS_RECORD_PKEY,
1090 &process_delegation_result_ns,
1097 * Lookup of a record in a specific zone
1098 * calls lookup result processor on result
1100 * @param zone the root zone
1101 * @param record_type the record type to look up
1102 * @param name the name to look up
1103 * @param proc the processor to call on result
1104 * @param cls the closure to pass to proc
1107 gns_resolver_lookup_record(GNUNET_HashCode zone,
1108 uint32_t record_type,
1110 RecordLookupProcessor proc,
1113 struct ResolverHandle *rh;
1114 struct RecordLookupHandle* rlh;
1116 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1117 "Starting resolution for %s (type=%d)!\n",
1121 if (is_canonical((char*)name) && (strcmp(GNUNET_GNS_TLD, name) != 0))
1123 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1124 "%s is canonical and gnunet not our TLD!\n", name);
1129 rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
1130 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1132 rh->authority = zone;
1135 if (strcmp(GNUNET_GNS_TLD, name) == 0)
1137 rh->name = GNUNET_malloc(2);
1138 strcpy(rh->name, "");
1142 rh->name = GNUNET_malloc(strlen(name)
1143 - strlen(GNUNET_GNS_TLD));
1145 strlen(name)-strlen(GNUNET_GNS_TLD));
1146 memcpy(rh->name, name,
1147 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
1150 rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
1151 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1152 rh->authority_chain_head->prev = NULL;
1153 rh->authority_chain_head->next = NULL;
1154 rh->authority_chain_tail = rh->authority_chain_head;
1155 rh->authority_chain_head->zone = zone;
1157 rlh->record_type = record_type;
1158 rlh->name = GNUNET_malloc(strlen(name) + 1);
1159 memset(rlh->name, 0, strlen(name) + 1);
1160 strcpy(rlh->name, name); //FIXME
1162 rlh->proc_cls = cls;
1164 rh->proc = &handle_delegation_ns;
1165 resolve_delegation_ns(rh);
1168 /******** END Record Resolver ***********/
1172 * Callback calles by namestore for a zone to name
1175 * @param cls the closure
1176 * @param zone_key the zone we queried
1177 * @param expire the expiration time of the name
1178 * @param name the name found or NULL
1179 * @param rd_len number of records for the name
1180 * @param rd the record data (PKEY) for the name
1181 * @param signature the signature for the record data
1184 process_zone_to_name_shorten(void *cls,
1185 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1186 struct GNUNET_TIME_Absolute expire,
1188 unsigned int rd_len,
1189 const struct GNUNET_NAMESTORE_RecordData *rd,
1190 const struct GNUNET_CRYPTO_RsaSignature *signature)
1192 struct ResolverHandle *rh = (struct ResolverHandle *)cls;
1193 struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
1194 struct AuthorityChain *next_authority;
1197 char* next_authority_name;
1200 /* we found a match in our own zone */
1203 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1204 "result strlen %d\n", strlen(name));
1205 answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
1206 result = GNUNET_malloc(answer_len);
1207 memset(result, 0, answer_len);
1208 if (strlen(rh->name) > 0)
1210 strcpy(result, rh->name);
1211 strcpy(result+strlen(rh->name), ".");
1214 strcpy(result+strlen(result), name);
1215 strcpy(result+strlen(result), ".");
1216 strcpy(result+strlen(result), GNUNET_GNS_TLD);
1218 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1219 "Sending shorten result %s\n", result);
1221 nsh->proc(nsh->proc_cls, result);
1223 free_resolver_handle(rh);
1224 GNUNET_free(result);
1226 else if (GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
1227 &rh->authority_chain_tail->zone))
1229 /* our zone, just append .gnunet */
1230 answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
1231 result = GNUNET_malloc(answer_len);
1232 memset(result, 0, answer_len);
1233 strcpy(result, rh->name);
1234 strcpy(result+strlen(rh->name), ".");
1235 strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
1237 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1238 "Our zone: Sending name as shorten result %s\n", rh->name);
1240 nsh->proc(nsh->proc_cls, result);
1242 free_resolver_handle(rh);
1243 GNUNET_free(result);
1249 * continue with next authority
1251 next_authority = rh->authority_chain_head;
1252 next_authority_name = GNUNET_malloc(strlen(rh->name)+
1253 strlen(next_authority->name) + 2);
1254 memset(next_authority_name, 0, strlen(rh->name)+
1255 strlen(next_authority->name) + 2);
1256 strcpy(next_authority_name, rh->name);
1257 strcpy(next_authority_name+strlen(rh->name)+1, ".");
1258 strcpy(next_authority_name+strlen(rh->name)+2, next_authority->name);
1260 GNUNET_free(rh->name);
1261 rh->name = next_authority_name;
1262 GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
1263 rh->authority_chain_tail,
1266 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1267 &rh->authority_chain_tail->zone,
1268 &rh->authority_chain_head->zone,
1269 &process_zone_to_name_shorten,
1276 * Process result from namestore delegation lookup
1277 * for shorten operation
1279 * @param cls the client shorten handle
1280 * @param rh the resolver handle
1281 * @param rd_count number of results (0)
1282 * @param rd data (NULL)
1285 handle_delegation_ns_shorten(void* cls,
1286 struct ResolverHandle *rh,
1288 const struct GNUNET_NAMESTORE_RecordData *rd)
1290 struct NameShortenHandle *nsh;
1294 nsh = (struct NameShortenHandle *)cls;
1297 * At this point rh->name contains the part of the name
1298 * that we do not have a PKEY in our namestore to resolve.
1299 * The authority chain in the resolver handle is now
1300 * useful to backtrack if needed
1303 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1304 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
1306 if (GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
1307 &rh->authority_chain_tail->zone) == 0)
1310 * This is our zone append .gnunet unless name is empty
1311 * (it shouldn't be, usually FIXME what happens if we
1312 * shorten to our zone to a "" record??)
1315 answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
1316 result = GNUNET_malloc(answer_len);
1317 memset(result, 0, answer_len);
1318 strcpy(result, rh->name);
1319 strcpy(result+strlen(rh->name), ".");
1320 strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
1322 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1323 "Our zone: Sending name as shorten result %s\n", rh->name);
1325 nsh->proc(nsh->proc_cls, result);
1327 free_resolver_handle(rh);
1328 GNUNET_free(result);
1332 /* backtrack authorities for names */
1333 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1334 &rh->authority_chain_tail->zone, //ours
1335 &rh->authority_chain_head->zone,
1336 &process_zone_to_name_shorten,
1342 * Shorten api from resolver
1344 * @param zone the zone to use
1345 * @param name the name to shorten
1346 * @param proc the processor to call with result
1347 * @param cls closure to pass to proc
1350 gns_resolver_shorten_name(GNUNET_HashCode zone,
1352 ShortenResultProcessor proc,
1355 struct ResolverHandle *rh;
1356 struct NameShortenHandle *nsh;
1358 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1359 "Starting shorten for %s!\n", name);
1361 if (is_canonical((char*)name))
1363 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1364 "%s is canonical. Returning verbatim\n", name);
1369 nsh = GNUNET_malloc(sizeof (struct NameShortenHandle));
1373 nsh->proc_cls = cls;
1375 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1376 rh->authority = zone;
1377 rh->name = GNUNET_malloc(strlen(name)
1378 - strlen(GNUNET_GNS_TLD));
1380 strlen(name)-strlen(GNUNET_GNS_TLD));
1381 memcpy(rh->name, name,
1382 strlen(name)-strlen(GNUNET_GNS_TLD)-1);
1384 rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
1385 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1386 rh->authority_chain_tail = rh->authority_chain_head;
1387 rh->authority_chain_head->zone = zone;
1388 rh->proc = &handle_delegation_ns_shorten;
1391 /* Start delegation resolution in our namestore */
1392 resolve_delegation_ns(rh);
1395 /*********** END NAME SHORTEN ********************/
1399 * Process result from namestore delegation lookup
1400 * for get authority operation
1402 * @param cls the client get auth handle
1403 * @param rh the resolver handle
1404 * @param rd_count number of results (0)
1405 * @param rd data (NULL)
1408 handle_delegation_result_ns_get_auth(void* cls,
1409 struct ResolverHandle *rh,
1411 const struct GNUNET_NAMESTORE_RecordData *rd)
1413 struct GetNameAuthorityHandle* nah;
1417 nah = (struct GetNameAuthorityHandle*) rh->proc_cls;
1420 * At this point rh->name contains the part of the name
1421 * that we do not have a PKEY in our namestore to resolve.
1422 * The authority chain in the resolver handle is now
1423 * useful to backtrack if needed
1426 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1427 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
1429 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1430 "Building response!\n");
1431 if (is_canonical(rh->name))
1434 * We successfully resolved the authority in the ns
1435 * FIXME for our purposes this is fine
1436 * but maybe we want to have an api that also looks
1437 * into the dht (i.e. option in message)
1439 if (strlen(rh->name) > strlen(nah->name))
1441 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1442 "Record name longer than original lookup name... odd!\n");
1446 answer_len = strlen(nah->name) - strlen(rh->name)
1447 + strlen(GNUNET_GNS_TLD) + 1;
1448 result = GNUNET_malloc(answer_len);
1449 memset(result, 0, answer_len);
1450 strcpy(result, nah->name + strlen(rh->name) + 1);
1452 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1453 "Got authority result %s\n", result);
1455 nah->proc(nah->proc_cls, result);
1456 GNUNET_free(nah->name);
1458 free_resolver_handle(rh);
1459 GNUNET_free(result);
1463 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1464 "Unable to resolve authority for remaining %s!\n", rh->name);
1465 nah->proc(nah->proc_cls, "");
1466 GNUNET_free(nah->name);
1468 free_resolver_handle(rh);
1476 * Tries to resolve the authority for name
1479 * @param zone the root zone to look up for
1480 * @param name the name to lookup up
1481 * @param proc the processor to call when finished
1482 * @param cls the closure to pass to the processor
1485 gns_resolver_get_authority(GNUNET_HashCode zone,
1487 GetAuthorityResultProcessor proc,
1490 struct ResolverHandle *rh;
1491 struct GetNameAuthorityHandle *nah;
1493 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1494 "Starting authority resolution for %s!\n", name);
1496 nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
1497 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1498 rh->authority = zone;
1500 if (strcmp(GNUNET_GNS_TLD, name) == 0)
1502 rh->name = GNUNET_malloc(2);
1503 strcpy(rh->name, "");
1507 rh->name = GNUNET_malloc(strlen(name)
1508 - strlen(GNUNET_GNS_TLD));
1510 strlen(name)-strlen(GNUNET_GNS_TLD));
1511 memcpy(rh->name, name,
1512 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
1515 nah->name = GNUNET_malloc(strlen(name)+1);
1516 memset(nah->name, 0,
1518 strcpy(nah->name, name);
1520 rh->authority_name = GNUNET_malloc(MAX_DNS_LABEL_LENGTH);
1522 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1523 rh->authority_chain_tail = rh->authority_chain_head;
1524 rh->authority_chain_head->zone = zone;
1525 rh->proc = &handle_delegation_result_ns_get_auth;
1526 rh->proc_cls = (void*)nah;
1529 nah->proc_cls = cls;
1531 /* Start delegation resolution in our namestore */
1532 resolve_delegation_ns(rh);
1536 /******** END GET AUTHORITY *************/
1538 /* end of gnunet-service-gns_resolver.c */