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 error!\n");
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);
635 /* results found yay */
636 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
637 "Record resolved from DHT!");
638 rlh->proc(rlh->proc_cls, rd_count, rd);
644 * Process namestore lookup result for record.
646 * @param cls the closure
647 * @param rh resolver handle
648 * @param rd_count number of results
649 * @param rd record data
652 handle_record_ns(void* cls, struct ResolverHandle *rh,
653 unsigned int rd_count,
654 const struct GNUNET_NAMESTORE_RecordData *rd)
656 struct RecordLookupHandle* rlh;
657 rlh = (struct RecordLookupHandle*) cls;
660 /* ns entry expired and not ours. try dht */
661 if (rh->status & (EXPIRED | !EXISTS) &&
662 GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
663 &rh->authority_chain_tail->zone))
665 rh->proc = &handle_record_dht;
666 resolve_record_dht(rh);
669 /* give up, cannot resolve */
670 rlh->proc(rlh->proc_cls, 0, NULL);
674 /* results found yay */
675 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
676 "Record resolved from namestore!");
677 rlh->proc(rlh->proc_cls, rd_count, rd);
683 * Determine if this name is canonical.
685 * a.b.gnunet = not canonical
688 * @param name the name to test
689 * @return 1 if canonical
692 is_canonical(char* name)
694 uint32_t len = strlen(name);
697 for (i=0; i<len; i++)
699 if (*(name+i) == '.')
706 * Move one level up in the domain hierarchy and return the
707 * passed top level domain.
709 * @param name the domain
710 * @param dest the destination where the tld will be put
713 pop_tld(char* name, char* dest)
717 if (is_canonical(name))
724 for (len = strlen(name); len > 0; len--)
726 if (*(name+len) == '.')
736 strcpy(dest, (name+len+1));
740 * DHT resolution for delegation finished. Processing result.
742 * @param cls the closure
743 * @param rh resolver handle
744 * @param rd_count number of results (always 0)
745 * @param rd record data (always NULL)
748 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
749 unsigned int rd_count,
750 const struct GNUNET_NAMESTORE_RecordData *rd)
752 struct RecordLookupHandle* rlh;
753 rlh = (struct RecordLookupHandle*) cls;
755 if (strcmp(rh->name, "") == 0)
757 /* We resolved full name for delegation. resolving record */
758 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
759 "Resolved full name for delegation via DHT. resolving record '' in ns\n");
760 rh->proc = &handle_record_ns;
761 resolve_record_ns(rh);
766 * we still have some left
768 if (is_canonical(rh->name))
770 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
771 "Resolving canonical record %s in ns\n", rh->name);
772 rh->proc = &handle_record_ns;
773 resolve_record_ns(rh);
776 /* give up, cannot resolve */
777 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
778 "Cannot fully resolve delegation for %s via DHT!\n",
780 rlh->proc(rlh->proc_cls, 0, NULL);
785 * Start DHT lookup for a name -> PKEY (compare NS) record in
786 * rh->authority's zone
788 * @param rh the pending gns query
791 resolve_delegation_dht(struct ResolverHandle *rh)
794 GNUNET_HashCode name_hash;
795 GNUNET_HashCode lookup_key;
797 GNUNET_CRYPTO_hash(rh->authority_name,
798 strlen(rh->authority_name),
800 GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
802 rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
803 &dht_authority_lookup_timeout,
806 xquery = htonl(GNUNET_GNS_RECORD_PKEY);
808 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
809 DHT_OPERATION_TIMEOUT,
810 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
812 DHT_GNS_REPLICATION_LEVEL,
816 &process_delegation_result_dht,
823 * Namestore resolution for delegation finished. Processing result.
825 * @param cls the closure
826 * @param rh resolver handle
827 * @param rd_count number of results (always 0)
828 * @param rd record data (always NULL)
831 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
832 unsigned int rd_count,
833 const struct GNUNET_NAMESTORE_RecordData *rd)
835 struct RecordLookupHandle* rlh;
836 rlh = (struct RecordLookupHandle*) cls;
838 if (strcmp(rh->name, "") == 0)
840 /* We resolved full name for delegation. resolving record */
841 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
842 "Resolved full name for delegation. resolving record ''\n");
843 rh->proc = &handle_record_ns;
844 resolve_record_ns(rh);
849 * we still have some left
850 * check if authority in ns is fresh
852 * or we are authority
854 if ((rh->status & (EXISTS | !EXPIRED)) ||
855 !GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
856 &rh->authority_chain_tail->zone))
858 if (is_canonical(rh->name))
860 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
861 "Resolving canonical record %s\n", rh->name);
862 rh->proc = &handle_record_ns;
863 resolve_record_ns(rh);
867 /* give up, cannot resolve */
868 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
869 "Cannot fully resolve delegation for %s!\n",
871 rlh->proc(rlh->proc_cls, 0, NULL);
876 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
877 "Trying to resolve delegation for %s via DHT\n",
879 rh->proc = &handle_delegation_dht;
880 resolve_delegation_dht(rh);
884 static void resolve_delegation_ns(struct ResolverHandle *rh);
888 * This is a callback function that should give us only PKEY
889 * records. Used to query the namestore for the authority (PKEY)
890 * for 'name'. It will recursively try to resolve the
891 * authority for a given name from the namestore.
893 * @param cls the pending query
894 * @param key the key of the zone we did the lookup
895 * @param expiration expiration date of the record data set in the namestore
896 * @param name the name for which we need an authority
897 * @param rd_count the number of records with 'name'
898 * @param rd the record data
899 * @param signature the signature of the authority for the record data
902 process_delegation_result_ns(void* cls,
903 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
904 struct GNUNET_TIME_Absolute expiration,
906 unsigned int rd_count,
907 const struct GNUNET_NAMESTORE_RecordData *rd,
908 const struct GNUNET_CRYPTO_RsaSignature *signature)
910 struct ResolverHandle *rh;
911 struct GNUNET_TIME_Relative remaining_time;
912 GNUNET_HashCode zone;
915 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got %d records from authority lookup\n",
918 rh = (struct ResolverHandle *)cls;
919 GNUNET_CRYPTO_hash(key,
920 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
922 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
928 rh->status |= EXISTS;
931 if (remaining_time.rel_value == 0)
933 rh->status |= EXPIRED;
937 * No authority found in namestore.
942 * We did not find an authority in the namestore
947 * Promote this authority back to a name maybe it is
950 if (strcmp(rh->name, "") == 0)
952 /* simply promote back */
953 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
954 "Promoting %s back to name\n", rh->authority_name);
955 strcpy(rh->name, rh->authority_name);
959 /* add back to existing name */
960 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
961 "Adding %s back to %s\n",
962 rh->authority_name, rh->name);
963 new_name = GNUNET_malloc(strlen(rh->name)
964 + strlen(rh->authority_name) + 2);
965 memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
966 strcpy(new_name, rh->name);
967 strcpy(new_name+strlen(new_name)+1, ".");
968 strcpy(new_name+strlen(new_name)+2, rh->authority_name);
969 GNUNET_free(rh->name);
972 rh->proc(rh->proc_cls, rh, 0, NULL);
977 * We found an authority that may be able to help us
979 * Note only 1 pkey should have been returned.. anything else would be strange
982 for (i=0; i<rd_count;i++)
985 if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
988 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
991 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This pkey is expired.\n");
992 if (remaining_time.rel_value == 0)
994 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
995 "This dht entry is expired.\n");
996 rh->authority_chain_head->fresh = 0;
997 rh->proc(rh->proc_cls, rh, 0, NULL);
1005 * Resolve rest of query with new authority
1007 GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
1008 memcpy(&rh->authority, rd[i].data, sizeof(GNUNET_HashCode));
1009 struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
1010 auth->zone = rh->authority;
1011 auth->name = GNUNET_malloc(strlen(rh->authority_name)+1);
1012 memset(auth->name, 0, strlen(rh->authority_name)+1);
1013 strcpy(auth->name, rh->authority_name);
1014 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1015 rh->authority_chain_tail,
1019 * We are done with PKEY resolution if name is empty
1020 * else resolve again with new authority
1022 if (strcmp(rh->name, "") == 0)
1023 rh->proc(rh->proc_cls, rh, 0, NULL);
1025 resolve_delegation_ns(rh);
1032 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1033 "Authority lookup successful but no PKEY... never get here\n");
1034 rh->proc(rh->proc_cls, rh, 0, NULL);
1039 * Resolve the delegation chain for the request in our namestore
1041 * @param rh the resolver handle
1044 resolve_delegation_ns(struct ResolverHandle *rh)
1046 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1047 "Resolving delegation for %s\n", rh->name);
1048 pop_tld(rh->name, rh->authority_name);
1049 GNUNET_NAMESTORE_lookup_record(namestore_handle,
1052 GNUNET_GNS_RECORD_PKEY,
1053 &process_delegation_result_ns,
1060 * Lookup of a record in a specific zone
1061 * calls lookup result processor on result
1063 * @param zone the root zone
1064 * @param record_type the record type to look up
1065 * @param name the name to look up
1066 * @param proc the processor to call on result
1067 * @param cls the closure to pass to proc
1070 gns_resolver_lookup_record(GNUNET_HashCode zone,
1071 uint32_t record_type,
1073 RecordLookupProcessor proc,
1076 struct ResolverHandle *rh;
1077 struct RecordLookupHandle* rlh;
1079 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1080 "Starting resolution for %s (type=%d)!\n",
1083 rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
1084 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1086 rh->authority = zone;
1088 rh->name = GNUNET_malloc(strlen(name)
1089 - strlen(GNUNET_GNS_TLD));
1091 strlen(name)-strlen(GNUNET_GNS_TLD));
1092 memcpy(rh->name, name,
1093 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
1094 rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
1095 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1096 rh->authority_chain_head->prev = NULL;
1097 rh->authority_chain_head->next = NULL;
1098 rh->authority_chain_tail = rh->authority_chain_head;
1099 rh->authority_chain_head->zone = zone;
1101 rlh->record_type = record_type;
1102 rlh->name = (char*)name; //FIXME
1104 rlh->proc_cls = cls;
1106 rh->proc = &handle_delegation_ns;
1107 resolve_delegation_ns(rh);
1110 /******** END Record Resolver ***********/
1114 * Callback calles by namestore for a zone to name
1117 * @param cls the closure
1118 * @param zone_key the zone we queried
1119 * @param expire the expiration time of the name
1120 * @param name the name found or NULL
1121 * @param rd_len number of records for the name
1122 * @param rd the record data (PKEY) for the name
1123 * @param signature the signature for the record data
1126 process_zone_to_name_shorten(void *cls,
1127 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1128 struct GNUNET_TIME_Absolute expire,
1130 unsigned int rd_len,
1131 const struct GNUNET_NAMESTORE_RecordData *rd,
1132 const struct GNUNET_CRYPTO_RsaSignature *signature)
1134 struct ResolverHandle *rh = (struct ResolverHandle *)cls;
1135 struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
1136 struct AuthorityChain *next_authority;
1139 char* next_authority_name;
1142 /* we found a match in our own zone */
1145 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1146 "result strlen %d\n", strlen(name));
1147 answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
1148 result = GNUNET_malloc(answer_len);
1149 memset(result, 0, answer_len);
1150 strcpy(result, rh->name);
1151 strcpy(result+strlen(rh->name), ".");
1152 strcpy(result+strlen(rh->name)+1, name);
1153 strcpy(result+strlen(rh->name)+strlen(name)+1, ".");
1154 strcpy(result+strlen(rh->name)+strlen(name)+2, GNUNET_GNS_TLD);
1156 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1157 "Sending shorten result %s\n", result);
1159 nsh->proc(nsh->proc_cls, result);
1160 free_resolver_handle(rh);
1161 GNUNET_free(result);
1163 else if (GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
1164 &rh->authority_chain_tail->zone))
1166 /* our zone, just append .gnunet */
1167 answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
1168 result = GNUNET_malloc(answer_len);
1169 memset(result, 0, answer_len);
1170 strcpy(result, rh->name);
1171 strcpy(result+strlen(rh->name), ".");
1172 strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
1174 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1175 "Our zone: Sending name as shorten result %s\n", rh->name);
1177 nsh->proc(nsh->proc_cls, result);
1178 free_resolver_handle(rh);
1179 GNUNET_free(result);
1185 * continue with next authority
1187 next_authority = rh->authority_chain_head;
1188 next_authority_name = GNUNET_malloc(strlen(rh->name)+
1189 strlen(next_authority->name) + 2);
1190 memset(next_authority_name, 0, strlen(rh->name)+
1191 strlen(next_authority->name) + 2);
1192 strcpy(next_authority_name, rh->name);
1193 strcpy(next_authority_name+strlen(rh->name)+1, ".");
1194 strcpy(next_authority_name+strlen(rh->name)+2, next_authority->name);
1196 GNUNET_free(rh->name);
1197 rh->name = next_authority_name;
1198 GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
1199 rh->authority_chain_tail,
1202 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1203 &rh->authority_chain_tail->zone,
1204 &rh->authority_chain_head->zone,
1205 &process_zone_to_name_shorten,
1212 * Process result from namestore delegation lookup
1213 * for shorten operation
1215 * @param cls the client shorten handle
1216 * @param rh the resolver handle
1217 * @param rd_count number of results (0)
1218 * @param rd data (NULL)
1221 handle_delegation_ns_shorten(void* cls,
1222 struct ResolverHandle *rh,
1224 const struct GNUNET_NAMESTORE_RecordData *rd)
1226 struct NameShortenHandle *nsh;
1230 nsh = (struct NameShortenHandle *)cls;
1233 * At this point rh->name contains the part of the name
1234 * that we do not have a PKEY in our namestore to resolve.
1235 * The authority chain in the resolver handle is now
1236 * useful to backtrack if needed
1239 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1240 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
1242 if (GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
1243 &rh->authority_chain_tail->zone) == 0)
1246 * This is our zone append .gnunet unless name is empty
1247 * (it shouldn't be, usually FIXME what happens if we
1248 * shorten to our zone to a "" record??)
1251 answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
1252 result = GNUNET_malloc(answer_len);
1253 memset(result, 0, answer_len);
1254 strcpy(result, rh->name);
1255 strcpy(result+strlen(rh->name), ".");
1256 strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
1258 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1259 "Our zone: Sending name as shorten result %s\n", rh->name);
1261 nsh->proc(nsh->proc_cls, result);
1262 free_resolver_handle(rh);
1263 GNUNET_free(result);
1267 /* backtrack authorities for names */
1268 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1269 &rh->authority_chain_tail->zone, //ours
1270 &rh->authority_chain_head->zone,
1271 &process_zone_to_name_shorten,
1277 * Shorten api from resolver
1279 * @param zone the zone to use
1280 * @param name the name to shorten
1281 * @param proc the processor to call with result
1282 * @param cls closure to pass to proc
1285 gns_resolver_shorten_name(GNUNET_HashCode zone,
1287 ShortenResultProcessor proc,
1290 struct ResolverHandle *rh;
1291 struct NameShortenHandle *nsh;
1293 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1294 "Starting shorten for %s!\n", name);
1296 nsh = GNUNET_malloc(sizeof (struct NameShortenHandle));
1297 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1298 rh->authority = zone;
1299 rh->name = GNUNET_malloc(strlen(name)
1300 - strlen(GNUNET_GNS_TLD));
1302 strlen(name)-strlen(GNUNET_GNS_TLD));
1303 memcpy(rh->name, name,
1304 strlen(name)-strlen(GNUNET_GNS_TLD)-1);
1306 rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
1307 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1308 rh->authority_chain_tail = rh->authority_chain_head;
1309 rh->authority_chain_head->zone = zone;
1310 rh->proc = &handle_delegation_ns_shorten;
1314 nsh->proc_cls = cls;
1316 /* Start delegation resolution in our namestore */
1317 resolve_delegation_ns(rh);
1320 /*********** END NAME SHORTEN ********************/
1324 * Process result from namestore delegation lookup
1325 * for get authority operation
1327 * @param cls the client get auth handle
1328 * @param rh the resolver handle
1329 * @param rd_count number of results (0)
1330 * @param rd data (NULL)
1333 handle_delegation_result_ns_get_auth(void* cls,
1334 struct ResolverHandle *rh,
1336 const struct GNUNET_NAMESTORE_RecordData *rd)
1338 struct GetNameAuthorityHandle* nah;
1342 nah = (struct GetNameAuthorityHandle*) rh->proc_cls;
1345 * At this point rh->name contains the part of the name
1346 * that we do not have a PKEY in our namestore to resolve.
1347 * The authority chain in the resolver handle is now
1348 * useful to backtrack if needed
1351 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1352 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
1354 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1355 "Building response!\n");
1356 if (is_canonical(rh->name))
1359 * We successfully resolved the authority in the ns
1360 * FIXME for our purposes this is fine
1361 * but maybe we want to have an api that also looks
1362 * into the dht (i.e. option in message)
1364 if (strlen(rh->name) > strlen(nah->name))
1366 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1367 "Record name longer than original lookup name... odd!\n");
1371 answer_len = strlen(nah->name) - strlen(rh->name)
1372 + strlen(GNUNET_GNS_TLD) + 1;
1373 result = GNUNET_malloc(answer_len);
1374 memset(result, 0, answer_len);
1375 strcpy(result, nah->name + strlen(rh->name) + 1);
1377 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1378 "Got authority result %s\n", result);
1380 nah->proc(nah->proc_cls, result);
1381 free_resolver_handle(rh);
1382 GNUNET_free(result);
1387 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1388 "Unable to resolve authority for remaining %s!\n", rh->name);
1389 nah->proc(nah->proc_cls, "");
1390 free_resolver_handle(rh);
1399 * Tries to resolve the authority for name
1402 * @param zone the root zone to look up for
1403 * @param name the name to lookup up
1404 * @param proc the processor to call when finished
1405 * @param cls the closure to pass to the processor
1408 gns_resolver_get_authority(GNUNET_HashCode zone,
1410 GetAuthorityResultProcessor proc,
1413 struct ResolverHandle *rh;
1414 struct GetNameAuthorityHandle *nah;
1416 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1417 "Starting authority resolution for %s!\n", name);
1419 nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
1420 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1421 rh->authority = zone;
1423 rh->name = GNUNET_malloc(strlen(name)
1424 - strlen(GNUNET_GNS_TLD));
1426 strlen(name)-strlen(GNUNET_GNS_TLD));
1427 memcpy(rh->name, name,
1428 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
1430 nah->name = GNUNET_malloc(strlen(name)+1);
1431 memset(nah->name, 0,
1433 strcpy(nah->name, name);
1435 rh->authority_name = GNUNET_malloc(MAX_DNS_LABEL_LENGTH);
1437 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1438 rh->authority_chain_tail = rh->authority_chain_head;
1439 rh->authority_chain_head->zone = zone;
1440 rh->proc = &handle_delegation_result_ns_get_auth;
1441 rh->proc_cls = (void*)nah;
1444 nah->proc_cls = cls;
1446 /* Start delegation resolution in our namestore */
1447 resolve_delegation_ns(rh);
1451 /******** END GET AUTHORITY *************/
1453 /* end of gnunet-service-gns_resolver.c */