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.
22 * @file gns/gnunet-service-gns_resolver.c
23 * @brief GNUnet GNS resolver logic
24 * @author Martin Schanzenbach
27 #include "gnunet_util_lib.h"
28 #include "gnunet_transport_service.h"
29 #include "gnunet_dns_service.h"
30 #include "gnunet_dht_service.h"
31 #include "gnunet_namestore_service.h"
32 #include "gnunet_vpn_service.h"
33 #include "gnunet_dns_service.h"
34 #include "gnunet_resolver_service.h"
35 #include "gnunet_dnsparser_lib.h"
36 #include "../dns/dnsparser.h"
37 #include "gnunet_gns_service.h"
38 #include "block_gns.h"
40 #include "gnunet-service-gns_resolver.h"
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 * Our handle to the vpn service
55 static struct GNUNET_VPN_Handle *vpn_handle;
58 * Resolver handle to the dht
60 static struct GNUNET_DHT_Handle *dht_handle;
63 * Heap for parallel DHT lookups
65 static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
68 * Heap for namestore queues
70 static struct GNUNET_CONTAINER_Heap *ns_task_heap;
73 * Maximum amount of parallel queries in background
75 static unsigned long long max_allowed_background_queries;
78 * Maximum amount of parallel namestore tasks in background
80 static unsigned long long max_allowed_ns_tasks;
83 * Wheather or not to ignore pending records
85 static int ignore_pending_records;
90 static struct GNUNET_CRYPTO_ShortHashCode local_zone;
93 * Background shortening handles
95 static struct GetPseuAuthorityHandle *gph_head;
98 * Background shortening handles
100 static struct GetPseuAuthorityHandle *gph_tail;
103 * Resolver lookup list
105 static struct ResolverHandle *rlh_head;
108 * Resolver lookup list
110 static struct ResolverHandle *rlh_tail;
113 * Resolver shorten list
115 static struct ResolverHandle *nsh_head;
118 * Resolver shorten list
120 static struct ResolverHandle *nsh_tail;
123 * Resolver get auth list
125 static struct ResolverHandle *nah_head;
128 * Resolver get auth list
130 static struct ResolverHandle *nah_tail;
133 * Global configuration.
135 static const struct GNUNET_CONFIGURATION_Handle *cfg;
138 * a resolution identifier pool variable
140 * This is a non critical identifier useful for debugging
142 static unsigned long long rid = 0;
145 * Check if name is in srv format (_x._y.xxx)
148 * @return GNUNET_YES if true
154 int ret = GNUNET_YES;
158 if (NULL == strstr (name, "._"))
161 ndup = GNUNET_strdup (name);
164 if (NULL == strtok (NULL, "."))
167 if (NULL == strtok (NULL, "."))
170 if (NULL != strtok (NULL, "."))
179 * Determine if this name is canonical.
181 * a.b.gnunet = not canonical
184 * @param name the name to test
185 * @return GNUNET_YES if canonical
188 is_canonical (char* name)
193 ndup = GNUNET_strdup (name);
196 for (tok = strtok (NULL, "."); tok != NULL; tok = strtok (NULL, "."))
212 * Callback that shortens authorities
214 * @param gph the handle containing the name to shorten
217 shorten_authority_chain (struct GetPseuAuthorityHandle *gph);
221 * Continueation for pkey record creation (shorten)
223 * @param cls a GetPseuAuthorityHandle
224 * @param success unused
228 create_pkey_cont (void* cls, int32_t success, const char* emsg)
230 //FIXME do sth with error
231 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
233 gph->namestore_task = NULL;
234 GNUNET_free (gph->auth);
235 GNUNET_CRYPTO_rsa_key_free (gph->key);
236 GNUNET_CONTAINER_DLL_remove (gph_head, gph_tail, gph);
242 * Namestore calls this function if we have record for this name.
243 * (or with rd_count=0 to indicate no matches)
245 * @param cls the pending query
246 * @param key the key of the zone we did the lookup
247 * @param expiration expiration date of the namestore entry
248 * @param name the name for which we need an authority
249 * @param rd_count the number of records with 'name'
250 * @param rd the record data
251 * @param signature the signature of the authority for the record data
254 process_pseu_lookup_ns (void* cls,
255 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
256 struct GNUNET_TIME_Absolute expiration,
257 const char *name, unsigned int rd_count,
258 const struct GNUNET_NAMESTORE_RecordData *rd,
259 const struct GNUNET_CRYPTO_RsaSignature *signature)
261 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
262 struct GNUNET_NAMESTORE_RecordData new_pkey;
264 gph->namestore_task = NULL;
267 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
268 "GNS_AUTO_PSEU: Name %s already taken in NS!\n", name);
269 GNUNET_free (gph->auth);
270 GNUNET_CRYPTO_rsa_key_free (gph->key);
271 GNUNET_CONTAINER_DLL_remove (gph_head, gph_tail, gph);
277 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
278 "GNS_AUTO_PSEU: Name %s not taken in NS! Adding\n", gph->test_name);
280 new_pkey.expiration_time = UINT64_MAX;
281 new_pkey.data_size = sizeof (struct GNUNET_CRYPTO_ShortHashCode);
282 new_pkey.data = &gph->auth->zone;
283 new_pkey.record_type = GNUNET_GNS_RECORD_PKEY;
284 new_pkey.flags = GNUNET_NAMESTORE_RF_AUTHORITY
285 | GNUNET_NAMESTORE_RF_PRIVATE
286 | GNUNET_NAMESTORE_RF_PENDING;
287 gph->namestore_task = GNUNET_NAMESTORE_record_create (namestore_handle,
291 &create_pkey_cont, //cont
296 * process result of a dht pseu lookup
298 * @param gph the handle
299 * @param name the pseu result or NULL
302 process_pseu_result (struct GetPseuAuthorityHandle* gph, char* name)
306 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
307 "GNS_AUTO_PSEU: No PSEU, no shorten. Finished.\n");
308 GNUNET_free (gph->auth);
309 GNUNET_CRYPTO_rsa_key_free (gph->key);
310 GNUNET_CONTAINER_DLL_remove (gph_head, gph_tail, gph);
314 memcpy (gph->test_name, name, strlen(name)+1);
316 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
317 "GNS_AUTO_PSEU: Checking %s for collision in NS\n",
320 * Check for collision
322 gph->namestore_task = GNUNET_NAMESTORE_lookup_record (namestore_handle,
325 GNUNET_NAMESTORE_TYPE_ANY,
326 &process_pseu_lookup_ns,
331 * Handle timeout for dht request
333 * @param cls the request handle as closure
334 * @param tc the task context
337 handle_auth_discovery_timeout (void *cls,
338 const struct GNUNET_SCHEDULER_TaskContext *tc)
340 struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
342 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
343 "GNS_GET_AUTH: dht lookup for query PSEU timed out.\n");
344 GNUNET_DHT_get_stop (gph->get_handle);
345 gph->get_handle = NULL;
346 process_pseu_result (gph, NULL);
350 * Function called when we find a PSEU entry in the DHT
352 * @param cls the request handle
353 * @param exp lifetime
354 * @param key the key the record was stored under
355 * @param get_path get path
356 * @param get_path_length get path length
357 * @param put_path put path
358 * @param put_path_length put path length
359 * @param type the block type
360 * @param size the size of the record
361 * @param data the record data
364 process_auth_discovery_dht_result (void* cls,
365 struct GNUNET_TIME_Absolute exp,
366 const struct GNUNET_HashCode * key,
367 const struct GNUNET_PeerIdentity *get_path,
368 unsigned int get_path_length,
369 const struct GNUNET_PeerIdentity *put_path,
370 unsigned int put_path_length,
371 enum GNUNET_BLOCK_Type type,
375 struct GetPseuAuthorityHandle* gph = cls;
376 struct GNSNameRecordBlock *nrb;
377 char* rd_data = (char*)data;
383 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
384 "GNS_GET_AUTH: got dht result (size=%d)\n", size);
386 /* stop lookup and timeout task */
387 GNUNET_DHT_get_stop (gph->get_handle);
388 gph->get_handle = NULL;
389 GNUNET_SCHEDULER_cancel (gph->timeout);
393 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
394 "GNS_GET_AUTH: got dht result null!\n", size);
395 GNUNET_free (gph->auth);
396 GNUNET_CRYPTO_rsa_key_free (gph->key);
397 GNUNET_CONTAINER_DLL_remove (gph_head, gph_tail, gph);
402 nrb = (struct GNSNameRecordBlock*)data;
403 name = (char*)&nrb[1];
404 num_records = ntohl (nrb->rd_count);
406 struct GNUNET_NAMESTORE_RecordData rd[num_records];
408 rd_data += strlen (name) + 1 + sizeof (struct GNSNameRecordBlock);
409 rd_size = size - strlen (name) - 1 - sizeof (struct GNSNameRecordBlock);
411 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
416 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
417 "GNS_GET_AUTH: Error deserializing data!\n");
421 for (i=0; i < num_records; i++)
423 if ((strcmp (name, "+") == 0) &&
424 (rd[i].record_type == GNUNET_GNS_RECORD_PSEU))
427 process_pseu_result (gph, (char*)rd[i].data);
433 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
434 "GNS_GET_AUTH: finished shorten, no results!\n");
435 process_pseu_result (gph, NULL);
439 * Process PSEU discovery for shorten via namestore
441 * @param cls the GetPseuAuthorityHandle
442 * @param key the public key
443 * @param expiration recorddata expiration
444 * @param name the looked up name
445 * @param rd_count number of records in set
446 * @param rd record data
447 * @param signature the signature
450 process_auth_discovery_ns_result (void* cls,
451 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
452 struct GNUNET_TIME_Absolute expiration,
454 unsigned int rd_count,
455 const struct GNUNET_NAMESTORE_RecordData *rd,
456 const struct GNUNET_CRYPTO_RsaSignature *signature)
458 struct GetPseuAuthorityHandle* gph = cls;
459 struct GNUNET_CRYPTO_ShortHashCode name_hash;
460 struct GNUNET_HashCode lookup_key;
461 struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
462 struct GNUNET_HashCode name_hash_double;
463 struct GNUNET_HashCode zone_hash_double;
467 gph->namestore_task = NULL;
474 GNUNET_CRYPTO_short_hash ("+", strlen ("+"), &name_hash);
475 GNUNET_CRYPTO_short_hash_double (&name_hash, &name_hash_double);
476 GNUNET_CRYPTO_short_hash_double (&gph->auth->zone, &zone_hash_double);
477 GNUNET_CRYPTO_hash_xor (&name_hash_double, &zone_hash_double, &lookup_key);
478 GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
480 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
481 "GNS_AUTO_PSEU: starting dht lookup for %s with key: %s\n",
482 "+", (char*)&lookup_key_string);
484 gph->timeout = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
485 &handle_auth_discovery_timeout, gph);
487 xquery = htonl (GNUNET_GNS_RECORD_PSEU);
489 GNUNET_assert (gph->get_handle == NULL);
491 gph->get_handle = GNUNET_DHT_get_start (dht_handle,
492 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
494 DHT_GNS_REPLICATION_LEVEL,
498 &process_auth_discovery_dht_result,
503 for (i=0; i < rd_count; i++)
505 if (0 != (strcmp (name, "+")))
508 if (rd[i].record_type != GNUNET_GNS_RECORD_PSEU)
512 process_pseu_result (gph, (char*)rd[i].data);
516 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNS_GET_AUTH: no pseu in namestore!\n");
517 process_pseu_result (gph, NULL);
521 * Callback called by namestore for a zone to name
524 * @param cls the closure
525 * @param zone_key the zone we queried
526 * @param expire the expiration time of the name
527 * @param name the name found or NULL
528 * @param rd_len number of records for the name
529 * @param rd the record data (PKEY) for the name
530 * @param signature the signature for the record data
533 process_zone_to_name_discover (void *cls,
534 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
535 struct GNUNET_TIME_Absolute expire,
538 const struct GNUNET_NAMESTORE_RecordData *rd,
539 const struct GNUNET_CRYPTO_RsaSignature *signature)
541 struct GetPseuAuthorityHandle* gph = cls;
543 gph->namestore_task = NULL;
546 gph->namestore_task = GNUNET_NAMESTORE_lookup_record (namestore_handle,
549 GNUNET_GNS_RECORD_PSEU,
550 &process_auth_discovery_ns_result,
554 /* we found a match in our own zone */
555 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
556 "GNS_AUTO_PSEU: name for zone in our root %s\n", name);
557 GNUNET_free (gph->auth);
558 GNUNET_CRYPTO_rsa_key_free (gph->key);
559 GNUNET_CONTAINER_DLL_remove (gph_head, gph_tail, gph);
565 * Callback that shortens authorities
567 * @param gph the handle to the shorten request
570 shorten_authority_chain (struct GetPseuAuthorityHandle *gph)
573 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
574 "GNS_AUTO_PSEU: New authority %s discovered\n",
577 gph->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
580 &process_zone_to_name_discover,
586 start_shorten (struct AuthorityChain *auth,
587 struct GNUNET_CRYPTO_RsaPrivateKey *key)
589 struct GetPseuAuthorityHandle *gph;
590 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
591 struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *pb_key;
593 gph = GNUNET_malloc (sizeof (struct GetPseuAuthorityHandle));
595 GNUNET_CRYPTO_rsa_key_get_public (key, &pkey);
596 pb_key = GNUNET_CRYPTO_rsa_encode_key (key);
600 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
601 "Failed to encode RSA key on shorten\n");
605 gph = GNUNET_malloc (sizeof (struct GetPseuAuthorityHandle));
606 gph->key = GNUNET_CRYPTO_rsa_decode_key ((char*)pb_key, ntohs (pb_key->len));
608 if (NULL == gph->key)
610 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
611 "Failed to decode RSA key on shorten\n");
615 GNUNET_CRYPTO_short_hash (&pkey,
616 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
618 gph->auth = GNUNET_malloc (sizeof (struct AuthorityChain));
619 memcpy (gph->auth, auth, sizeof (struct AuthorityChain));
620 GNUNET_CONTAINER_DLL_insert (gph_head, gph_tail, gph);
621 shorten_authority_chain (gph);
625 * Initialize the resolver
627 * @param nh the namestore handle
628 * @param dh the dht handle
629 * @param lz the local zone's hash
630 * @param c configuration handle
631 * @param max_bg_queries maximum number of parallel background queries in dht
632 * @param ignore_pending ignore records that still require user confirmation
634 * @return GNUNET_OK on success
637 gns_resolver_init (struct GNUNET_NAMESTORE_Handle *nh,
638 struct GNUNET_DHT_Handle *dh,
639 struct GNUNET_CRYPTO_ShortHashCode lz,
640 const struct GNUNET_CONFIGURATION_Handle *c,
641 unsigned long long max_bg_queries,
645 return GNUNET_SYSERR;
647 return GNUNET_SYSERR;
650 namestore_handle = nh;
654 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
656 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
657 max_allowed_background_queries = max_bg_queries;
658 max_allowed_ns_tasks = GNUNET_GNS_MAX_NS_TASKS;
659 ignore_pending_records = ignore_pending;
669 GNUNET_RESOLVER_connect (cfg);
677 * @param cls closure to iterator
678 * @param node heap nodes
679 * @param element the namestorebgtask
680 * @param cost heap cost
681 * @return always GNUNET_YES
684 cleanup_pending_ns_tasks (void* cls,
685 struct GNUNET_CONTAINER_HeapNode *node,
687 GNUNET_CONTAINER_HeapCostType cost)
689 struct NamestoreBGTask *nbg = element;
690 ResolverCleanupContinuation cont = cls;
692 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
693 "GNS_CLEANUP: Terminating ns task\n");
694 GNUNET_NAMESTORE_cancel (nbg->qe);
696 GNUNET_CONTAINER_heap_remove_node (node);
698 if (0 == GNUNET_CONTAINER_heap_get_size (ns_task_heap))
708 * @param rh resolver handle
709 * @param rlh record lookup handle
710 * @param rd_count number of results
714 finish_lookup (struct ResolverHandle *rh,
715 struct RecordLookupHandle* rlh,
716 unsigned int rd_count,
717 const struct GNUNET_NAMESTORE_RecordData *rd);
721 * Cleanup background lookups FIXME get rid of this?? YES this doesn't do
722 * anything! => find in code and remove all references to the heap
724 * @param cls closure to iterator
725 * @param node heap nodes
726 * @param element the resolver handle
727 * @param cost heap cost
728 * @return always GNUNET_YES
731 cleanup_pending_background_queries (void* cls,
732 struct GNUNET_CONTAINER_HeapNode *node,
734 GNUNET_CONTAINER_HeapCostType cost)
736 struct ResolverHandle *rh = element;
737 ResolverCleanupContinuation cont = cls;
739 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
740 "GNS_CLEANUP-%llu: Terminating background lookup for %s\n",
742 GNUNET_CONTAINER_heap_remove_node (node);
743 if (0 == GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
745 if (GNUNET_CONTAINER_heap_get_size (ns_task_heap) == 0)
749 GNUNET_CONTAINER_heap_iterate (ns_task_heap,
750 &cleanup_pending_ns_tasks,
761 * Helper function to free resolver handle
763 * @param rh the handle to free
766 free_resolver_handle (struct ResolverHandle* rh)
768 struct AuthorityChain *ac;
769 struct AuthorityChain *ac_next;
774 ac = rh->authority_chain_head;
783 if (NULL != rh->get_handle)
784 GNUNET_DHT_get_stop (rh->get_handle);
786 if (NULL != rh->dns_raw_packet)
787 GNUNET_free (rh->dns_raw_packet);
789 if (NULL != rh->namestore_task)
790 GNUNET_NAMESTORE_cancel (rh->namestore_task);
791 rh->namestore_task = NULL;
793 if (GNUNET_SCHEDULER_NO_TASK != rh->dns_read_task)
794 GNUNET_SCHEDULER_cancel (rh->dns_read_task);
796 if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
797 GNUNET_SCHEDULER_cancel (rh->timeout_task);
799 if (NULL != rh->dns_sock)
800 GNUNET_NETWORK_socket_close (rh->dns_sock);
801 if (NULL != rh->dns_resolver_handle)
802 GNUNET_RESOLVER_request_cancel (rh->dns_resolver_handle);
804 if (NULL != rh->rd.data)
805 GNUNET_free ((void*)(rh->rd.data));
813 * @param rh resolver handle
814 * @param nsh name shorten handle
817 finish_shorten (struct ResolverHandle *rh,
818 struct NameShortenHandle *nsh);
822 * @param rh resolver handle
823 * @param nah get name authority handle
826 finish_get_auth (struct ResolverHandle *rh,
827 struct GetNameAuthorityHandle* rlh);
832 gns_resolver_cleanup (ResolverCleanupContinuation cont)
835 struct GetPseuAuthorityHandle *tmp;
839 for (tmp = gph_head; tmp != NULL; tmp = gph_head)
841 if (tmp->get_handle != NULL)
842 GNUNET_DHT_get_stop (tmp->get_handle);
843 tmp->get_handle = NULL;
844 if (tmp->timeout != GNUNET_SCHEDULER_NO_TASK)
845 GNUNET_SCHEDULER_cancel (tmp->timeout);
846 tmp->timeout = GNUNET_SCHEDULER_NO_TASK;
848 if (NULL != tmp->namestore_task)
849 GNUNET_NAMESTORE_cancel (tmp->namestore_task);
850 tmp->namestore_task = NULL;
851 GNUNET_free (tmp->auth);
852 GNUNET_CRYPTO_rsa_key_free (tmp->key);
853 GNUNET_CONTAINER_DLL_remove (gph_head, gph_tail, tmp);
857 while (NULL != rlh_head)
859 finish_lookup (rlh_head, rlh_head->proc_cls, 0, NULL);
861 while (NULL != nsh_head)
863 finish_shorten (nsh_head, nsh_head->proc_cls);
865 while (NULL != nah_head)
867 finish_get_auth (nah_head, nah_head->proc_cls);
870 s = GNUNET_CONTAINER_heap_get_size (dht_lookup_heap);
871 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
872 "GNS_CLEANUP: %d pending background queries to terminate\n", s);
874 GNUNET_CONTAINER_heap_iterate (dht_lookup_heap,
875 &cleanup_pending_background_queries,
877 else if (0 != GNUNET_CONTAINER_heap_get_size (ns_task_heap))
879 GNUNET_CONTAINER_heap_iterate (ns_task_heap,
880 &cleanup_pending_ns_tasks,
891 * Callback when record data is put into namestore
893 * @param cls the closure
894 * @param success GNUNET_OK on success
895 * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
898 on_namestore_record_put_result (void *cls,
902 struct NamestoreBGTask *nbg = cls;
904 GNUNET_CONTAINER_heap_remove_node (nbg->node);
907 if (GNUNET_NO == success)
909 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
910 "GNS_NS: records already in namestore\n");
913 else if (GNUNET_YES == success)
915 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
916 "GNS_NS: records successfully put in namestore\n");
920 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
921 "GNS_NS: Error putting records into namestore: %s\n", emsg);
925 handle_lookup_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
927 struct ResolverHandle *rh = cls;
929 if (rh->timeout_cont)
930 rh->timeout_cont (rh->timeout_cont_cls, tc);
934 * Processor for background lookups in the DHT
936 * @param cls closure (NULL)
937 * @param rd_count number of records found (not 0)
938 * @param rd record data
941 background_lookup_result_processor (void *cls,
943 const struct GNUNET_NAMESTORE_RecordData *rd)
945 //We could do sth verbose/more useful here but it doesn't make any difference
946 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
947 "GNS_BG: background dht lookup finished. (%d results)\n",
952 * Handle timeout for DHT requests
954 * @param cls the request handle as closure
955 * @param tc the task context
958 dht_lookup_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
960 struct ResolverHandle *rh = cls;
961 struct RecordLookupHandle *rlh = rh->proc_cls;
962 char new_name[MAX_DNS_NAME_LENGTH];
964 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
965 "GNS_PHASE_REC-%llu: dht lookup for query %s (%llus)timed out.\n",
966 rh->id, rh->name, rh->timeout.rel_value);
968 * Start resolution in bg
970 GNUNET_snprintf (new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
971 rh->name, GNUNET_GNS_TLD);
973 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
974 "GNS_PHASE_REC-%llu: Starting background lookup for %s type %d\n",
975 rh->id, new_name, rlh->record_type);
977 gns_resolver_lookup_record (rh->authority,
978 rh->private_local_zone,
982 GNUNET_TIME_UNIT_FOREVER_REL,
984 &background_lookup_result_processor,
986 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
988 GNUNET_DHT_get_stop (rh->get_handle);
989 rh->get_handle = NULL;
990 rh->proc (rh->proc_cls, rh, 0, NULL);
995 * Function called when we get a result from the dht
996 * for our record query
998 * @param cls the request handle
999 * @param exp lifetime
1000 * @param key the key the record was stored under
1001 * @param get_path get path
1002 * @param get_path_length get path length
1003 * @param put_path put path
1004 * @param put_path_length put path length
1005 * @param type the block type
1006 * @param size the size of the record
1007 * @param data the record data
1010 process_record_result_dht (void* cls,
1011 struct GNUNET_TIME_Absolute exp,
1012 const struct GNUNET_HashCode * key,
1013 const struct GNUNET_PeerIdentity *get_path,
1014 unsigned int get_path_length,
1015 const struct GNUNET_PeerIdentity *put_path,
1016 unsigned int put_path_length,
1017 enum GNUNET_BLOCK_Type type,
1018 size_t size, const void *data)
1020 struct ResolverHandle *rh;
1021 struct RecordLookupHandle *rlh;
1022 struct GNSNameRecordBlock *nrb;
1023 uint32_t num_records;
1025 char* rd_data = (char*)data;
1029 rh = (struct ResolverHandle *)cls;
1030 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1031 "GNS_PHASE_REC-%llu: got dht result (size=%d)\n", rh->id, size);
1033 rlh = (struct RecordLookupHandle *) rh->proc_cls;
1034 nrb = (struct GNSNameRecordBlock*)data;
1036 /* stop lookup and timeout task */
1037 GNUNET_DHT_get_stop (rh->get_handle);
1038 rh->get_handle = NULL;
1040 if (rh->dht_heap_node != NULL)
1042 GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
1043 rh->dht_heap_node = NULL;
1046 if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1048 GNUNET_SCHEDULER_cancel (rh->timeout_task);
1049 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1052 rh->get_handle = NULL;
1053 name = (char*)&nrb[1];
1054 num_records = ntohl (nrb->rd_count);
1056 struct GNUNET_NAMESTORE_RecordData rd[num_records];
1057 struct NamestoreBGTask *ns_heap_root;
1058 struct NamestoreBGTask *namestore_bg_task;
1060 rd_data += strlen (name) + 1 + sizeof (struct GNSNameRecordBlock);
1061 rd_size = size - strlen (name) - 1 - sizeof (struct GNSNameRecordBlock);
1063 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
1068 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1069 "GNS_PHASE_REC-%llu: Error deserializing data!\n", rh->id);
1070 rh->proc (rh->proc_cls, rh, 0, NULL);
1074 for (i=0; i<num_records; i++)
1076 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1077 "GNS_PHASE_REC-%llu: Got name: %s (wanted %s)\n",
1078 rh->id, name, rh->name);
1079 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1080 "GNS_PHASE_REC-%llu: Got type: %d (wanted %d)\n",
1081 rh->id, rd[i].record_type, rlh->record_type);
1082 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1083 "GNS_PHASE_REC-%llu: Got data length: %d\n",
1084 rh->id, rd[i].data_size);
1085 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1086 "GNS_PHASE_REC-%llu: Got flag %d\n",
1087 rh->id, rd[i].flags);
1089 if ((strcmp (name, rh->name) == 0) &&
1090 (rd[i].record_type == rlh->record_type))
1098 * FIXME check pubkey against existing key in namestore?
1099 * https://gnunet.org/bugs/view.php?id=2179
1101 if (max_allowed_ns_tasks <=
1102 GNUNET_CONTAINER_heap_get_size (ns_task_heap))
1104 ns_heap_root = GNUNET_CONTAINER_heap_remove_root (ns_task_heap);
1105 GNUNET_NAMESTORE_cancel (ns_heap_root->qe);
1107 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1108 "GNS_PHASE_REC-%llu: Replacing oldest background ns task\n",
1112 /* Save to namestore */
1113 namestore_bg_task = GNUNET_malloc (sizeof (struct NamestoreBGTask));
1114 namestore_bg_task->qe = GNUNET_NAMESTORE_record_put (namestore_handle,
1121 &on_namestore_record_put_result, //cont
1124 namestore_bg_task->node = GNUNET_CONTAINER_heap_insert (ns_task_heap,
1126 GNUNET_TIME_absolute_get().abs_value);
1129 if (0 < rh->answered)
1130 rh->proc (rh->proc_cls, rh, num_records, rd);
1132 rh->proc (rh->proc_cls, rh, 0, NULL);
1139 * Start DHT lookup for a (name -> query->record_type) record in
1140 * rh->authority's zone
1142 * @param rh the pending gns query context
1145 resolve_record_dht (struct ResolverHandle *rh)
1148 struct GNUNET_CRYPTO_ShortHashCode name_hash;
1149 struct GNUNET_HashCode lookup_key;
1150 struct GNUNET_HashCode name_hash_double;
1151 struct GNUNET_HashCode zone_hash_double;
1152 struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
1153 struct RecordLookupHandle *rlh = rh->proc_cls;
1154 struct ResolverHandle *rh_heap_root;
1156 GNUNET_CRYPTO_short_hash (rh->name, strlen (rh->name), &name_hash);
1157 GNUNET_CRYPTO_short_hash_double (&name_hash, &name_hash_double);
1158 GNUNET_CRYPTO_short_hash_double (&rh->authority, &zone_hash_double);
1159 GNUNET_CRYPTO_hash_xor (&name_hash_double, &zone_hash_double, &lookup_key);
1160 GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
1162 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1163 "GNS_PHASE_REC-%llu: starting dht lookup for %s with key: %s\n",
1164 rh->id, rh->name, (char*)&lookup_key_string);
1166 //rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1167 rh->dht_heap_node = NULL;
1169 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value != rh->timeout.rel_value)
1172 * Update timeout if necessary
1174 if (GNUNET_SCHEDULER_NO_TASK == rh->timeout_task)
1176 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1177 "GNS_PHASE_REC-%llu: Adjusting timeout\n", rh->id);
1179 * Set timeout for authority lookup phase to 1/2
1181 rh->timeout_task = GNUNET_SCHEDULER_add_delayed (
1182 GNUNET_TIME_relative_divide (rh->timeout, 2),
1183 &handle_lookup_timeout,
1186 rh->timeout_cont = &dht_lookup_timeout;
1187 rh->timeout_cont_cls = rh;
1191 if (max_allowed_background_queries <=
1192 GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
1194 rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
1195 GNUNET_DHT_get_stop (rh_heap_root->get_handle);
1196 rh_heap_root->get_handle = NULL;
1197 rh_heap_root->dht_heap_node = NULL;
1199 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1200 "GNS_PHASE_REC-%llu: Replacing oldest background query for %s\n",
1201 rh->id, rh_heap_root->name);
1202 rh_heap_root->proc (rh_heap_root->proc_cls,
1207 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
1209 GNUNET_TIME_absolute_get ().abs_value);
1212 xquery = htonl (rlh->record_type);
1214 GNUNET_assert (rh->get_handle == NULL);
1215 rh->get_handle = GNUNET_DHT_get_start (dht_handle,
1216 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1218 DHT_GNS_REPLICATION_LEVEL,
1222 &process_record_result_dht,
1229 * Namestore calls this function if we have record for this name.
1230 * (or with rd_count=0 to indicate no matches)
1232 * @param cls the pending query
1233 * @param key the key of the zone we did the lookup
1234 * @param expiration expiration date of the namestore entry
1235 * @param name the name for which we need an authority
1236 * @param rd_count the number of records with 'name'
1237 * @param rd the record data
1238 * @param signature the signature of the authority for the record data
1241 process_record_result_ns (void* cls,
1242 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1243 struct GNUNET_TIME_Absolute expiration,
1244 const char *name, unsigned int rd_count,
1245 const struct GNUNET_NAMESTORE_RecordData *rd,
1246 const struct GNUNET_CRYPTO_RsaSignature *signature)
1248 struct ResolverHandle *rh;
1249 struct RecordLookupHandle *rlh;
1250 struct GNUNET_TIME_Relative remaining_time;
1251 struct GNUNET_CRYPTO_ShortHashCode zone;
1252 struct GNUNET_TIME_Absolute et;
1258 rh->namestore_task = NULL;
1259 GNUNET_CRYPTO_short_hash (key,
1260 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1262 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1270 rh->status |= RSL_RECORD_EXISTS;
1272 if (remaining_time.rel_value == 0)
1274 rh->status |= RSL_RECORD_EXPIRED;
1281 * Lookup terminated and no results
1283 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1284 "GNS_PHASE_REC-%llu: Namestore lookup for %s terminated without results\n",
1287 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1288 "GNS_PHASE_REC-%llu: Record %s unknown in namestore\n",
1291 * Our zone and no result? Cannot resolve TT
1293 rh->proc(rh->proc_cls, rh, 0, NULL);
1297 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1298 "GNS_PHASE_REC-%llu: Processing additional result %s from namestore\n",
1300 for (i=0; i<rd_count;i++)
1302 if (rd[i].record_type != rlh->record_type)
1305 if (ignore_pending_records &&
1306 (rd[i].flags & GNUNET_NAMESTORE_RF_PENDING))
1308 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1309 "GNS_PHASE_REC-%llu: Record %s is awaiting user confirmation. Skipping\n",
1314 //FIXME: eh? do I have to handle this here?
1315 GNUNET_break (0 == (rd[i].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION));
1316 et.abs_value = rd[i].expiration_time;
1317 if (0 == (GNUNET_TIME_absolute_get_remaining (et)).rel_value)
1319 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1320 "GNS_PHASE_REC-%llu: This record is expired. Skipping\n",
1330 if (0 == rh->answered)
1332 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1333 "GNS_PHASE_REC-%llu: No answers found. This is odd!\n", rh->id);
1334 rh->proc(rh->proc_cls, rh, 0, NULL);
1338 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1339 "GNS_PHASE_REC-%llu: Found %d answer(s) to query in %d records!\n",
1340 rh->id, rh->answered, rd_count);
1341 rh->proc(rh->proc_cls, rh, rd_count, rd);
1346 * VPN redirect result callback
1348 * @param cls the resolver handle
1349 * @param af the requested address family
1350 * @param address in_addr(6) respectively
1353 process_record_result_vpn (void* cls, int af, const void *address)
1355 struct ResolverHandle *rh = cls;
1356 struct RecordLookupHandle *rlh;
1357 struct GNUNET_NAMESTORE_RecordData rd;
1361 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1362 "GNS_PHASE_REC_VPN-%llu: Got answer from VPN to query!\n",
1366 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1367 "GNS_PHASE_REC-%llu: Answer is IPv4!\n",
1369 if (GNUNET_GNS_RECORD_A != rlh->record_type)
1371 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1372 "GNS_PHASE_REC-%llu: Requested record is not IPv4!\n",
1374 rh->proc (rh->proc_cls, rh, 0, NULL);
1377 rd.record_type = GNUNET_GNS_RECORD_A;
1378 rd.expiration_time = UINT64_MAX; /* FIXME: should probably pick something shorter... */
1380 rd.data_size = sizeof (struct in_addr);
1382 rh->proc (rh->proc_cls, rh, 1, &rd);
1385 else if (AF_INET6 == af)
1387 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1388 "GNS_PHASE_REC-%llu: Answer is IPv6!\n",
1390 if (GNUNET_GNS_RECORD_AAAA != rlh->record_type)
1392 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1393 "GNS_PHASE_REC-%llu: Requested record is not IPv6!\n",
1395 rh->proc (rh->proc_cls, rh, 0, NULL);
1398 rd.record_type = GNUNET_GNS_RECORD_AAAA;
1399 rd.expiration_time = UINT64_MAX; /* FIXME: should probably pick something shorter... */
1401 rd.data_size = sizeof (struct in6_addr);
1403 rh->proc (rh->proc_cls, rh, 1, &rd);
1407 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1408 "GNS_PHASE_REC-%llu: Got garbage from VPN!\n",
1410 rh->proc (rh->proc_cls, rh, 0, NULL);
1417 * Process VPN lookup result for record
1419 * @param cls the record lookup handle
1420 * @param rh resolver handle
1421 * @param rd_count number of results (1)
1422 * @param rd record data containing the result
1425 handle_record_vpn (void* cls, struct ResolverHandle *rh,
1426 unsigned int rd_count,
1427 const struct GNUNET_NAMESTORE_RecordData *rd)
1429 struct RecordLookupHandle* rlh = cls;
1433 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1434 "GNS_PHASE_REC_VPN-%llu: VPN returned no records. (status: %d)!\n",
1437 /* give up, cannot resolve */
1438 finish_lookup(rh, rlh, 0, NULL);
1442 /* results found yay */
1443 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1444 "GNS_PHASE_REC_VPN-%llu: Record resolved from VPN!", rh->id);
1446 finish_lookup(rh, rlh, rd_count, rd);
1451 * Sends a UDP dns query to a nameserver specified in the rh
1453 * @param rh the resolver handle
1456 send_dns_packet (struct ResolverHandle *rh);
1460 handle_dns_resolver (void *cls,
1461 const struct sockaddr *addr,
1464 struct ResolverHandle *rh = cls;
1465 struct RecordLookupHandle *rlh = rh->proc_cls;
1466 struct GNUNET_NAMESTORE_RecordData rd;
1467 struct sockaddr_in *sai;
1468 struct sockaddr_in6 *sai6;
1472 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1473 "No address found in DNS!\n");
1474 finish_lookup (rh, rlh, 0, NULL);
1478 if (sizeof (struct sockaddr_in) == addrlen)
1480 sai = (struct sockaddr_in*) addr;
1481 rd.record_type = GNUNET_GNS_RECORD_A;
1482 rd.data_size = sizeof (struct in_addr);
1483 rd.data = &sai->sin_addr;
1485 else if (sizeof (struct sockaddr_in6) == addrlen)
1487 sai6 = (struct sockaddr_in6*) addr;
1488 rd.record_type = GNUNET_GNS_RECORD_AAAA;
1489 rd.data_size = sizeof (struct in6_addr);
1490 rd.data = &sai6->sin6_addr;
1494 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1495 "Address length is garbage!\n");
1496 finish_lookup (rh, rlh, 0, NULL);
1499 rd.expiration_time = UINT64_MAX; /* FIXME: should probably pick something shorter */
1501 finish_lookup (rh, rlh, 1, &rd);
1505 * Resolve DNS name via local stub resolver
1507 * @param rh the resolver handle
1510 resolve_dns_name (struct ResolverHandle *rh)
1512 struct RecordLookupHandle *rlh = rh->proc_cls;
1515 if ((GNUNET_GNS_RECORD_A != rlh->record_type) &&
1516 (GNUNET_GNS_RECORD_AAAA != rlh->record_type))
1518 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1519 "Can only resolve A/AAAA via stub... abort\n");
1520 finish_lookup (rh, rlh, 0, NULL);
1524 if (GNUNET_GNS_RECORD_A == rlh->record_type)
1529 rh->dns_resolver_handle = GNUNET_RESOLVER_ip_get (rh->dns_name,
1532 &handle_dns_resolver,
1538 * Read DNS udp packet from socket
1540 * @param cls the resolver handle
1541 * @param tc task context
1544 read_dns_response (void *cls,
1545 const struct GNUNET_SCHEDULER_TaskContext *tc)
1547 struct ResolverHandle *rh = cls;
1548 struct RecordLookupHandle *rlh = rh->proc_cls;
1549 char buf[UINT16_MAX];
1551 struct sockaddr_in addr;
1553 struct GNUNET_DNSPARSER_Packet *packet;
1554 struct GNUNET_NAMESTORE_RecordData rd;
1555 int found_delegation = GNUNET_NO;
1556 int found_cname = GNUNET_NO;
1557 char* delegation_name = NULL;
1558 int zone_offset = 0;
1561 rh->dns_read_task = GNUNET_SCHEDULER_NO_TASK;
1562 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
1564 /* timeout or shutdown */
1565 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1566 "Terminating DNS query %d\n", tc->reason);
1567 finish_lookup (rh, rlh, 0, NULL);
1571 addrlen = sizeof (addr);
1572 r = GNUNET_NETWORK_socket_recvfrom (rh->dns_sock,
1574 (struct sockaddr*) &addr,
1579 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom");
1580 finish_lookup (rh, rlh, 0, NULL);
1584 packet = GNUNET_DNSPARSER_parse (buf, r);
1588 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1589 "Failed to parse DNS reply!\n");
1590 finish_lookup (rh, rlh, 0, NULL);
1594 for (i = 0; i < packet->num_answers; i++)
1596 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1597 "Got record type %d (want %d)\n",
1598 packet->answers[i].type,
1600 /* http://tools.ietf.org/html/rfc1034#section-3.6.2 */
1601 if (packet->answers[i].type == GNUNET_GNS_RECORD_CNAME)
1603 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1604 "CNAME... restarting query with %s\n",
1605 packet->answers[i].data.hostname
1607 strcpy (rh->dns_name, packet->answers[i].data.hostname);
1608 found_cname = GNUNET_YES;
1612 if ((packet->answers[i].type == rlh->record_type) &&
1613 (0 == strcmp (packet->answers[i].name, rh->dns_name)))
1615 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1617 rd.data = packet->answers[i].data.raw.data;
1618 rd.data_size = packet->answers[i].data.raw.data_len;
1619 rd.record_type = packet->answers[i].type;
1621 rd.expiration_time = packet->answers[i].expiration_time.abs_value;
1622 finish_lookup (rh, rlh, 1, &rd);
1623 GNUNET_DNSPARSER_free_packet (packet);
1628 if (GNUNET_YES == found_cname)
1630 zone_offset = strlen (rh->dns_name) - strlen (rh->dns_zone) - 1;
1632 if (0 > zone_offset)
1635 /* restart query with CNAME */
1636 if (0 == strcmp (rh->dns_name+zone_offset, rh->dns_zone))
1638 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1639 "Asking same server for %s\n", rh->dns_name);
1640 send_dns_packet (rh);
1644 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1645 "Trying system resolver for %s\n", rh->dns_name);
1646 resolve_dns_name (rh);
1649 GNUNET_DNSPARSER_free_packet (packet);
1653 for (i = 0; i < packet->num_authority_records; i++)
1656 if (packet->authority_records[i].type == GNUNET_GNS_RECORD_NS)
1658 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1659 "Found NS delegation!\n");
1660 found_delegation = GNUNET_YES;
1661 delegation_name = packet->authority_records[i].data.hostname;
1666 for (i = 0; i < packet->num_additional_records; i++)
1668 if (GNUNET_NO == found_delegation)
1671 if ((packet->additional_records[i].type == GNUNET_GNS_RECORD_A) &&
1672 (0 == strcmp (packet->additional_records[i].name, delegation_name)))
1674 GNUNET_assert (sizeof (struct in_addr) ==
1675 packet->authority_records[i].data.raw.data_len);
1677 rh->dns_addr.sin_addr =
1678 *((struct in_addr*)packet->authority_records[i].data.raw.data);
1679 send_dns_packet (rh);
1680 GNUNET_DNSPARSER_free_packet (packet);
1685 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1686 "Nothing useful in DNS reply!\n");
1687 finish_lookup (rh, rlh, 0, NULL);
1688 GNUNET_DNSPARSER_free_packet (packet);
1693 * Sends a UDP dns query to a nameserver specified in the rh
1695 * @param rh the request handle
1698 send_dns_packet (struct ResolverHandle *rh)
1700 struct GNUNET_NETWORK_FDSet *rset = GNUNET_NETWORK_fdset_create ();
1701 GNUNET_NETWORK_fdset_set (rset, rh->dns_sock);
1703 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1704 "Sending %dbyte DNS query\n",
1705 rh->dns_raw_packet_size);
1707 GNUNET_NETWORK_socket_sendto (rh->dns_sock,
1709 rh->dns_raw_packet_size,
1710 (struct sockaddr*)&rh->dns_addr,
1711 sizeof (struct sockaddr_in));
1713 rh->dns_read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1714 rh->timeout, //FIXME less?
1720 GNUNET_NETWORK_fdset_destroy (rset);
1725 * The final phase of resoution.
1726 * We found a NS RR and want to resolve via DNS
1728 * @param rh the pending lookup handle
1729 * @param rd_count length of record data
1730 * @param rd record data containing VPN RR
1733 resolve_record_dns (struct ResolverHandle *rh,
1735 const struct GNUNET_NAMESTORE_RecordData *rd)
1737 struct GNUNET_DNSPARSER_Query query;
1738 struct GNUNET_DNSPARSER_Packet packet;
1739 struct GNUNET_DNSPARSER_Flags flags;
1740 struct in_addr dnsip;
1741 struct sockaddr_in addr;
1742 struct sockaddr *sa;
1744 struct RecordLookupHandle *rlh = rh->proc_cls;
1746 memset (&packet, 0, sizeof (struct GNUNET_DNSPARSER_Packet));
1748 /* We cancel here as to not include the ns lookup in the timeout */
1749 if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
1751 GNUNET_SCHEDULER_cancel(rh->timeout_task);
1752 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1754 /* Start shortening */
1755 if ((NULL != rh->priv_key) &&
1756 (GNUNET_YES == is_canonical (rh->name)))
1758 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1759 "GNS_PHASE_REC_DNS-%llu: Trying to shorten authority chain\n",
1761 start_shorten (rh->authority_chain_head,
1765 for (i = 0; i < rd_count; i++)
1767 /* Synthesize dns name */
1768 if (GNUNET_GNS_RECORD_NS == rd[i].record_type)
1770 strcpy (rh->dns_zone, (char*)rd[i].data);
1771 if (0 == strcmp (rh->name, ""))
1772 strcpy (rh->dns_name, (char*)rd[i].data);
1774 sprintf (rh->dns_name, "%s.%s", rh->name, (char*)rd[i].data);
1777 if (GNUNET_GNS_RECORD_A == rd[i].record_type)
1778 dnsip = *((struct in_addr*)rd[i].data);
1781 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1782 "GNS_PHASE_REC_DNS-%llu: Looking up %s from %s\n",
1786 rh->dns_sock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0);
1787 if (NULL == rh->dns_sock)
1789 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1790 "GNS_PHASE_REC_DNS-%llu: Error creating udp socket for dns!\n",
1792 finish_lookup (rh, rlh, 0, NULL);
1796 memset (&addr, 0, sizeof (struct sockaddr_in));
1797 sa = (struct sockaddr *) &addr;
1798 sa->sa_family = AF_INET;
1799 if (GNUNET_OK != GNUNET_NETWORK_socket_bind (rh->dns_sock,
1801 sizeof (struct sockaddr_in)))
1803 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1804 "GNS_PHASE_REC_DNS-%llu: Error binding udp socket for dns!\n",
1806 finish_lookup (rh, rlh, 0, NULL);
1809 query.name = rh->dns_name;
1810 query.type = rlh->record_type;
1811 query.class = GNUNET_DNSPARSER_CLASS_INTERNET;
1812 memset (&flags, 0, sizeof (flags));
1813 flags.recursion_desired = 1;
1814 flags.checking_disabled = 1;
1815 packet.queries = &query;
1816 packet.answers = NULL;
1817 packet.authority_records = NULL;
1818 packet.num_queries = 1;
1819 packet.num_answers = 0;
1820 packet.num_authority_records = 0;
1821 packet.num_additional_records = 0;
1822 packet.flags = flags;
1824 if (GNUNET_OK != GNUNET_DNSPARSER_pack (&packet,
1826 &rh->dns_raw_packet,
1827 &rh->dns_raw_packet_size))
1829 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1830 "GNS_PHASE_REC_DNS-%llu: Creating raw dns packet!\n",
1832 GNUNET_NETWORK_socket_close (rh->dns_sock);
1833 finish_lookup (rh, rlh, 0, NULL);
1837 rh->dns_addr.sin_family = AF_INET;
1838 rh->dns_addr.sin_port = htons (53); //domain
1839 rh->dns_addr.sin_addr = dnsip;
1840 #if HAVE_SOCKADDR_IN_SIN_LEN
1841 rh->dns_addr.sin_len = (u_char) sizeof (struct sockaddr_in);
1844 send_dns_packet (rh);
1849 * The final phase of resoution.
1850 * We found a VPN RR and want to request an IPv4/6 address
1852 * @param rh the pending lookup handle
1853 * @param rd_count length of record data
1854 * @param rd record data containing VPN RR
1857 resolve_record_vpn (struct ResolverHandle *rh,
1859 const struct GNUNET_NAMESTORE_RecordData *rd)
1861 struct RecordLookupHandle *rlh = rh->proc_cls;
1862 struct GNUNET_HashCode serv_desc;
1863 struct vpn_data* vpn;
1866 /* We cancel here as to not include the ns lookup in the timeout */
1867 if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
1869 GNUNET_SCHEDULER_cancel(rh->timeout_task);
1870 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1872 /* Start shortening */
1873 if ((NULL != rh->priv_key) &&
1874 (GNUNET_YES == is_canonical (rh->name)))
1876 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1877 "GNS_PHASE_REC_VPN-%llu: Trying to shorten authority chain\n",
1879 start_shorten (rh->authority_chain_head,
1883 vpn = (struct vpn_data*)rd->data;
1886 GNUNET_CRYPTO_hash ((char*)&vpn[1],
1887 strlen ((char*)&vpn[1]) + 1,
1889 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1890 "GNS_PHASE_REC_VPN-%llu: proto %hu peer %s!\n",
1893 GNUNET_h2s (&vpn->peer));
1895 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1896 "GNS_PHASE_REC_VPN-%llu: service %s -> %s!\n",
1899 GNUNET_h2s (&serv_desc));
1900 rh->proc = &handle_record_vpn;
1901 if (GNUNET_GNS_RECORD_A == rlh->record_type)
1905 if (NULL == vpn_handle)
1907 vpn_handle = GNUNET_VPN_connect (cfg);
1908 if (NULL == vpn_handle)
1910 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1911 "GNS_PHASE_INIT: Error connecting to VPN!\n");
1912 finish_lookup (rh, rh->proc_cls, 0, NULL);
1917 rh->vpn_handle = GNUNET_VPN_redirect_to_peer (vpn_handle,
1918 af, ntohs (vpn->proto),
1919 (struct GNUNET_PeerIdentity *)&vpn->peer,
1922 GNUNET_TIME_UNIT_FOREVER_ABS, //FIXME
1923 &process_record_result_vpn,
1929 * The final phase of resolution.
1930 * rh->name is a name that is canonical and we do not have a delegation.
1931 * Query namestore for this record
1933 * @param rh the pending lookup handle
1936 resolve_record_ns(struct ResolverHandle *rh)
1938 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
1940 /* We cancel here as to not include the ns lookup in the timeout */
1941 if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
1943 GNUNET_SCHEDULER_cancel(rh->timeout_task);
1944 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1946 /* Start shortening */
1947 if ((NULL != rh->priv_key) &&
1948 (GNUNET_YES == is_canonical (rh->name)))
1950 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1951 "GNS_PHASE_REC-%llu: Trying to shorten authority chain\n",
1953 start_shorten (rh->authority_chain_head,
1958 * Try to resolve this record in our namestore.
1959 * The name to resolve is now in rh->authority_name
1960 * since we tried to resolve it to an authority
1963 rh->namestore_task = GNUNET_NAMESTORE_lookup_record(namestore_handle,
1967 &process_record_result_ns,
1974 * Handle timeout for DHT requests
1976 * @param cls the request handle as closure
1977 * @param tc the task context
1980 dht_authority_lookup_timeout(void *cls,
1981 const struct GNUNET_SCHEDULER_TaskContext *tc)
1983 struct ResolverHandle *rh = cls;
1984 struct RecordLookupHandle *rlh = rh->proc_cls;
1985 char new_name[MAX_DNS_NAME_LENGTH];
1987 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1988 "GNS_PHASE_DELEGATE_DHT-%llu: dht lookup for query %s (%llus)timed out.\n",
1989 rh->id, rh->authority_name, rh->timeout.rel_value);
1991 rh->status |= RSL_TIMED_OUT;
1992 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1993 if (NULL != rh->get_handle)
1994 GNUNET_DHT_get_stop (rh->get_handle);
1996 rh->get_handle = NULL;
1997 if (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)
1999 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2000 "GNS_PHASE_DELEGATE_DHT-%llu: Got shutdown\n",
2002 rh->proc(rh->proc_cls, rh, 0, NULL);
2006 if (0 == strcmp(rh->name, ""))
2009 * promote authority back to name and try to resolve record
2011 strcpy(rh->name, rh->authority_name);
2012 rh->proc(rh->proc_cls, rh, 0, NULL);
2017 * Start resolution in bg
2019 GNUNET_assert (0 < GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH,
2020 "%s.%s.%s", rh->name, rh->authority_name, GNUNET_GNS_TLD));
2022 strcpy(rh->name, new_name);
2024 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2025 "GNS_PHASE_DELEGATE_DHT-%llu: Starting background query for %s type %d\n",
2026 rh->id, rh->name, rlh->record_type);
2028 gns_resolver_lookup_record(rh->authority,
2029 rh->private_local_zone,
2033 GNUNET_TIME_UNIT_FOREVER_REL,
2035 &background_lookup_result_processor,
2038 rh->proc(rh->proc_cls, rh, 0, NULL);
2042 static void resolve_delegation_dht(struct ResolverHandle *rh);
2045 static void resolve_delegation_ns(struct ResolverHandle *rh);
2049 * Namestore resolution for delegation finished. Processing result.
2051 * @param cls the closure
2052 * @param rh resolver handle
2053 * @param rd_count number of results (always 0)
2054 * @param rd record data (always NULL)
2057 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
2058 unsigned int rd_count,
2059 const struct GNUNET_NAMESTORE_RecordData *rd);
2063 * This is a callback function that checks for key revocation
2065 * @param cls the pending query
2066 * @param key the key of the zone we did the lookup
2067 * @param expiration expiration date of the record data set in the namestore
2068 * @param name the name for which we need an authority
2069 * @param rd_count the number of records with 'name'
2070 * @param rd the record data
2071 * @param signature the signature of the authority for the record data
2074 process_pkey_revocation_result_ns (void *cls,
2075 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
2076 struct GNUNET_TIME_Absolute expiration,
2078 unsigned int rd_count,
2079 const struct GNUNET_NAMESTORE_RecordData *rd,
2080 const struct GNUNET_CRYPTO_RsaSignature *signature)
2082 struct ResolverHandle *rh = cls;
2083 struct GNUNET_TIME_Relative remaining_time;
2086 rh->namestore_task = NULL;
2087 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
2089 for (i = 0; i < rd_count; i++)
2091 if (GNUNET_GNS_RECORD_REV == rd[i].record_type)
2093 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2094 "GNS_PHASE_DELEGATE_REV-%llu: Zone has been revoked.\n",
2096 rh->status |= RSL_PKEY_REVOKED;
2097 rh->proc (rh->proc_cls, rh, 0, NULL);
2102 if ((NULL == name) ||
2103 (0 == remaining_time.rel_value))
2105 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2106 "GNS_PHASE_DELEGATE_REV-%llu: + Records don't exist or are expired.\n",
2109 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value != rh->timeout.rel_value)
2111 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2112 "GNS_PHASE_DELEGATE_REV-%llu: Starting background lookup for %s type %d\n",
2113 rh->id, "+.gnunet", GNUNET_GNS_RECORD_REV);
2115 gns_resolver_lookup_record(rh->authority,
2116 rh->private_local_zone,
2117 GNUNET_GNS_RECORD_REV,
2120 GNUNET_TIME_UNIT_FOREVER_REL,
2122 &background_lookup_result_processor,
2126 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2127 "GNS_PHASE_DELEGATE_REV-%llu: Revocation check passed\n",
2130 * We are done with PKEY resolution if name is empty
2131 * else resolve again with new authority
2133 if (strcmp (rh->name, "") == 0)
2134 rh->proc (rh->proc_cls, rh, rh->rd_count, &rh->rd);
2136 resolve_delegation_ns (rh);
2141 * Callback when record data is put into namestore
2143 * @param cls the closure
2144 * @param success GNUNET_OK on success
2145 * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
2148 on_namestore_delegation_put_result(void *cls,
2152 struct NamestoreBGTask *nbg = cls;
2154 GNUNET_CONTAINER_heap_remove_node (nbg->node);
2157 if (GNUNET_NO == success)
2159 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2160 "GNS_NS: records already in namestore\n");
2163 else if (GNUNET_YES == success)
2165 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2166 "GNS_NS: records successfully put in namestore\n");
2170 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
2171 "GNS_NS: Error putting records into namestore: %s\n", emsg);
2175 * Function called when we get a result from the dht
2176 * for our query. Recursively tries to resolve authorities
2179 * @param cls the request handle
2180 * @param exp lifetime
2181 * @param key the key the record was stored under
2182 * @param get_path get path
2183 * @param get_path_length get path length
2184 * @param put_path put path
2185 * @param put_path_length put path length
2186 * @param type the block type
2187 * @param size the size of the record
2188 * @param data the record data
2191 process_delegation_result_dht(void* cls,
2192 struct GNUNET_TIME_Absolute exp,
2193 const struct GNUNET_HashCode * key,
2194 const struct GNUNET_PeerIdentity *get_path,
2195 unsigned int get_path_length,
2196 const struct GNUNET_PeerIdentity *put_path,
2197 unsigned int put_path_length,
2198 enum GNUNET_BLOCK_Type type,
2199 size_t size, const void *data)
2201 struct ResolverHandle *rh = cls;
2202 struct GNSNameRecordBlock *nrb;
2203 uint32_t num_records;
2205 char* rd_data = (char*) data;
2208 struct GNUNET_CRYPTO_ShortHashCode zone, name_hash;
2209 struct GNUNET_HashCode zone_hash_double, name_hash_double;
2211 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2212 "GNS_PHASE_DELEGATE_DHT-%llu: Got DHT result\n", rh->id);
2217 nrb = (struct GNSNameRecordBlock*)data;
2219 /* stop dht lookup and timeout task */
2220 GNUNET_DHT_get_stop (rh->get_handle);
2221 rh->get_handle = NULL;
2222 if (rh->dht_heap_node != NULL)
2224 GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
2225 rh->dht_heap_node = NULL;
2228 num_records = ntohl(nrb->rd_count);
2229 name = (char*)&nrb[1];
2231 struct GNUNET_NAMESTORE_RecordData rd[num_records];
2232 struct NamestoreBGTask *ns_heap_root;
2233 struct NamestoreBGTask *namestore_bg_task;
2235 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
2236 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
2237 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
2242 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
2243 "GNS_PHASE_DELEGATE_DHT-%llu: Error deserializing data!\n",
2248 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2249 "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n",
2250 rh->id, name, rh->authority_name);
2251 for (i=0; i<num_records; i++)
2254 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2255 "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n",
2256 rh->id, name, rh->authority_name);
2257 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2258 "GNS_PHASE_DELEGATE_DHT-%llu: Got type: %d (wanted %d)\n",
2259 rh->id, rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
2260 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2261 "GNS_PHASE_DELEGATE_DHT-%llu: Got data length: %d\n",
2262 rh->id, rd[i].data_size);
2263 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2264 "GNS_PHASE_DELEGATE_DHT-%llu: Got flag %d\n",
2265 rh->id, rd[i].flags);
2267 if ((GNUNET_GNS_RECORD_VPN == rd[i].record_type) ||
2268 (GNUNET_GNS_RECORD_NS == rd[i].record_type) ||
2269 (GNUNET_GNS_RECORD_CNAME == rd[i].record_type))
2272 * This is a VPN,NS,CNAME entry. Let namestore handle this after caching
2274 if (0 == strcmp(rh->name, ""))
2275 strcpy(rh->name, rh->authority_name);
2277 GNUNET_snprintf(rh->name, MAX_DNS_NAME_LENGTH, "%s.%s",
2278 rh->name, rh->authority_name); //FIXME ret
2283 if ((0 == strcmp(name, rh->authority_name)) &&
2284 (GNUNET_GNS_RECORD_PKEY == rd[i].record_type))
2286 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2287 "GNS_PHASE_DELEGATE_DHT-%llu: Authority found in DHT\n",
2290 memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
2291 struct AuthorityChain *auth =
2292 GNUNET_malloc(sizeof(struct AuthorityChain));
2293 auth->zone = rh->authority;
2294 memset(auth->name, 0, strlen(rh->authority_name)+1);
2295 strcpy(auth->name, rh->authority_name);
2296 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
2297 rh->authority_chain_tail,
2300 if (NULL != rh->rd.data)
2301 GNUNET_free ((void*)rh->rd.data);
2303 memcpy (&rh->rd, &rd[i], sizeof (struct GNUNET_NAMESTORE_RecordData));
2304 rh->rd.data = GNUNET_malloc (rd[i].data_size);
2305 memcpy ((void*)(rh->rd.data), rd[i].data, rd[i].data_size);
2308 /** try to import pkey if private key available */
2309 //if (rh->priv_key && is_canonical (rh->name))
2310 // process_discovered_authority(name, auth->zone,
2311 // rh->authority_chain_tail->zone,
2318 GNUNET_CRYPTO_short_hash(name, strlen(name), &name_hash);
2319 GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
2320 GNUNET_CRYPTO_hash_xor(key, &name_hash_double, &zone_hash_double);
2321 GNUNET_CRYPTO_short_hash_from_truncation (&zone_hash_double, &zone);
2323 /* Save to namestore */
2324 if (0 != GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_tail->zone,
2327 if (max_allowed_ns_tasks <=
2328 GNUNET_CONTAINER_heap_get_size (ns_task_heap))
2330 ns_heap_root = GNUNET_CONTAINER_heap_remove_root (ns_task_heap);
2331 GNUNET_NAMESTORE_cancel (ns_heap_root->qe);
2333 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2334 "GNS_PHASE_REC-%llu: Replacing oldest background ns task\n",
2338 namestore_bg_task = GNUNET_malloc (sizeof (struct NamestoreBGTask));
2340 namestore_bg_task->node = GNUNET_CONTAINER_heap_insert (ns_task_heap,
2342 GNUNET_TIME_absolute_get().abs_value);
2343 namestore_bg_task->qe = GNUNET_NAMESTORE_record_put (namestore_handle,
2350 &on_namestore_delegation_put_result, //cont
2351 namestore_bg_task); //cls
2355 if (0 != rh->answered)
2360 * FIXME in this case. should we ask namestore again?
2362 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2363 "GNS_PHASE_DELEGATE_DHT-%llu: Answer from DHT for %s. Yet to resolve: %s\n",
2364 rh->id, rh->authority_name, rh->name);
2366 if (0 == strcmp(rh->name, ""))
2368 /* Start shortening */
2369 if ((NULL != rh->priv_key) &&
2370 (GNUNET_YES == is_canonical (rh->name)))
2372 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2373 "GNS_PHASE_DELEGATE_DHT-%llu: Trying to shorten authority chain\n",
2375 start_shorten (rh->authority_chain_head,
2380 rh->proc = &handle_delegation_ns;
2383 /* Check for key revocation and delegate */
2384 rh->namestore_task = GNUNET_NAMESTORE_lookup_record (namestore_handle,
2387 GNUNET_GNS_RECORD_REV,
2388 &process_pkey_revocation_result_ns,
2395 * No pkey but name exists
2398 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2399 "GNS_PHASE_DELEGATE_DHT-%llu: Adding %s back to %s\n",
2400 rh->id, rh->authority_name, rh->name);
2401 if (0 == strcmp(rh->name, ""))
2402 strcpy(rh->name, rh->authority_name);
2404 GNUNET_snprintf(rh->name, MAX_DNS_NAME_LENGTH, "%s.%s",
2405 rh->name, rh->authority_name); //FIXME ret
2407 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2408 "GNS_PHASE_DELEGATE_DHT-%llu: %s restored\n", rh->id, rh->name);
2409 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2410 "GNS_PHASE_DELEGATE_DHT-%llu: DHT authority lookup found no match!\n",
2412 rh->proc(rh->proc_cls, rh, 0, NULL);
2415 //FIXME maybe define somewhere else?
2416 #define MAX_SOA_LENGTH sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)\
2417 +(MAX_DNS_NAME_LENGTH*2)
2418 #define MAX_MX_LENGTH sizeof(uint16_t)+MAX_DNS_NAME_LENGTH
2419 #define MAX_SRV_LENGTH (sizeof(uint16_t)*3)+MAX_DNS_NAME_LENGTH
2423 expand_plus(char* dest, char* src, char* repl)
2426 unsigned int s_len = strlen(src)+1;
2428 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2429 "GNS_POSTPROCESS: Got %s to expand with %s\n", src, repl);
2430 //Eh? I guess this is at least strlen ('x.+') == 3 FIXME
2433 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2434 "GNS_POSTPROCESS: %s too short\n", src);
2436 /* no postprocessing */
2437 memcpy(dest, src, s_len+1);
2441 if (0 == strcmp(src+s_len-3, ".+"))
2443 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2444 "GNS_POSTPROCESS: Expanding .+ in %s\n", src);
2445 memset(dest, 0, s_len+strlen(repl)+strlen(GNUNET_GNS_TLD));
2449 pos += strlen(repl);
2450 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2451 "GNS_POSTPROCESS: Expanded to %s\n", dest);
2455 memcpy(dest, src, s_len+1);
2463 finish_lookup (struct ResolverHandle *rh,
2464 struct RecordLookupHandle* rlh,
2465 unsigned int rd_count,
2466 const struct GNUNET_NAMESTORE_RecordData *rd)
2469 char new_rr_data[MAX_DNS_NAME_LENGTH];
2470 char new_mx_data[MAX_MX_LENGTH];
2471 char new_soa_data[MAX_SOA_LENGTH];
2472 char new_srv_data[MAX_SRV_LENGTH];
2473 struct srv_data *old_srv;
2474 struct srv_data *new_srv;
2475 struct soa_data *old_soa;
2476 struct soa_data *new_soa;
2477 struct GNUNET_NAMESTORE_RecordData p_rd[rd_count];
2480 unsigned int offset;
2482 if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
2484 GNUNET_SCHEDULER_cancel(rh->timeout_task);
2485 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2488 GNUNET_CONTAINER_DLL_remove (rlh_head, rlh_tail, rh);
2491 memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData));
2493 for (i = 0; i < rd_count; i++)
2496 if ((GNUNET_GNS_RECORD_NS != rd[i].record_type) &&
2497 (GNUNET_GNS_RECORD_PTR != rd[i].record_type) &&
2498 (GNUNET_GNS_RECORD_CNAME != rd[i].record_type) &&
2499 (GNUNET_GNS_RECORD_MX != rd[i].record_type) &&
2500 (GNUNET_GNS_RECORD_SOA != rd[i].record_type) &&
2501 (GNUNET_GNS_RECORD_SRV != rd[i].record_type))
2503 p_rd[i].data = rd[i].data;
2508 * for all those records we 'should'
2509 * also try to resolve the A/AAAA records (RFC1035)
2510 * This is a feature and not important
2513 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2514 "GNS_POSTPROCESS: Postprocessing\n");
2515 if (0 == strcmp(rh->name, "+"))
2516 repl_string = rlh->name;
2518 repl_string = rlh->name+strlen(rh->name)+1;
2521 if (GNUNET_GNS_RECORD_MX == rd[i].record_type)
2523 memcpy (new_mx_data, (char*)rd[i].data, sizeof(uint16_t));
2524 offset = sizeof(uint16_t);
2525 pos = new_mx_data+offset;
2526 expand_plus(pos, (char*)rd[i].data+sizeof(uint16_t),
2528 offset += strlen(new_mx_data+sizeof(uint16_t))+1;
2529 p_rd[i].data = new_mx_data;
2530 p_rd[i].data_size = offset;
2532 else if (GNUNET_GNS_RECORD_SRV == rd[i].record_type)
2535 * Prio, weight and port
2537 new_srv = (struct srv_data*)new_srv_data;
2538 old_srv = (struct srv_data*)rd[i].data;
2539 new_srv->prio = old_srv->prio;
2540 new_srv->weight = old_srv->weight;
2541 new_srv->port = old_srv->port;
2542 expand_plus((char*)&new_srv[1], (char*)&old_srv[1],
2544 p_rd[i].data = new_srv_data;
2545 p_rd[i].data_size = sizeof (struct srv_data) + strlen ((char*)&new_srv[1]) + 1;
2547 else if (GNUNET_GNS_RECORD_SOA == rd[i].record_type)
2549 /* expand mname and rname */
2550 old_soa = (struct soa_data*)rd[i].data;
2551 new_soa = (struct soa_data*)new_soa_data;
2552 memcpy (new_soa, old_soa, sizeof (struct soa_data));
2553 expand_plus((char*)&new_soa[1], (char*)&old_soa[1], repl_string);
2554 offset = strlen ((char*)&new_soa[1]) + 1;
2555 expand_plus((char*)&new_soa[1] + offset,
2556 (char*)&old_soa[1] + strlen ((char*)&old_soa[1]) + 1,
2558 p_rd[i].data_size = sizeof (struct soa_data)
2560 + strlen ((char*)&new_soa[1] + offset);
2561 p_rd[i].data = new_soa_data;
2566 expand_plus(pos, (char*)rd[i].data, repl_string);
2567 p_rd[i].data_size = strlen(new_rr_data)+1;
2568 p_rd[i].data = new_rr_data;
2573 rlh->proc(rlh->proc_cls, rd_count, p_rd);
2575 free_resolver_handle (rh);
2579 * Process DHT lookup result for record.
2581 * @param cls the closure
2582 * @param rh resolver handle
2583 * @param rd_count number of results
2584 * @param rd record data
2587 handle_record_dht(void* cls, struct ResolverHandle *rh,
2588 unsigned int rd_count,
2589 const struct GNUNET_NAMESTORE_RecordData *rd)
2591 struct RecordLookupHandle* rlh = cls;
2595 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2596 "GNS_PHASE_REC-%llu: No records for %s found in DHT. Aborting\n",
2598 /* give up, cannot resolve */
2599 finish_lookup(rh, rlh, 0, NULL);
2602 /* results found yay */
2603 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2604 "GNS_PHASE_REC-%llu: Record resolved from DHT!", rh->id);
2605 finish_lookup(rh, rlh, rd_count, rd);
2612 * Process namestore lookup result for record.
2614 * @param cls the closure
2615 * @param rh resolver handle
2616 * @param rd_count number of results
2617 * @param rd record data
2620 handle_record_ns (void* cls, struct ResolverHandle *rh,
2621 unsigned int rd_count,
2622 const struct GNUNET_NAMESTORE_RecordData *rd)
2624 struct RecordLookupHandle* rlh = cls;
2625 int check_dht = GNUNET_YES;
2629 /* results found yay */
2630 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2631 "GNS_PHASE_REC-%llu: Record resolved from namestore!\n", rh->id);
2632 finish_lookup(rh, rlh, rd_count, rd);
2636 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2637 "GNS_PHASE_REC-%llu: NS returned no records. (status: %d)!\n",
2641 * There are 5 conditions that have to met for us to consult the DHT:
2642 * 1. The entry in the DHT is RSL_RECORD_EXPIRED OR
2643 * 2. No entry in the NS existed AND
2644 * 3. The zone queried is not the local resolver's zone AND
2645 * 4. The name that was looked up is '+'
2646 * because if it was any other canonical name we either already queried
2647 * the DHT for the authority in the authority lookup phase (and thus
2648 * would already have an entry in the NS for the record)
2649 * 5. We are not in cache only mode
2651 if ((0 != (rh->status & RSL_RECORD_EXPIRED)) &&
2652 (0 == (rh->status & RSL_RECORD_EXISTS)) )
2653 check_dht = GNUNET_NO;
2655 if (0 != GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2656 &rh->private_local_zone))
2657 check_dht = GNUNET_NO;
2659 if ((0 != strcmp (rh->name, "+")) && (GNUNET_YES == is_srv (rh->name)))
2660 check_dht = GNUNET_NO;
2662 if (GNUNET_YES == rh->only_cached)
2663 check_dht = GNUNET_NO;
2665 if (GNUNET_YES == check_dht)
2667 rh->proc = &handle_record_dht;
2668 resolve_record_dht(rh);
2671 /* give up, cannot resolve */
2672 finish_lookup(rh, rlh, 0, NULL);
2677 * Move one level up in the domain hierarchy and return the
2678 * passed top level domain.
2680 * @param name the domain
2681 * @param dest the destination where the tld will be put
2684 pop_tld(char* name, char* dest)
2688 if (GNUNET_YES == is_canonical (name))
2695 for (len = strlen(name); 0 < len; len--)
2697 if (*(name+len) == '.')
2707 strcpy(dest, (name+len+1));
2711 * Checks if name is in tld
2713 * @param name the name to check
2714 * @param tld the TLD to check for
2715 * @return GNUNET_YES or GNUNET_NO
2718 is_tld(const char* name, const char* tld)
2722 if (strlen(name) <= strlen(tld))
2725 offset = strlen(name)-strlen(tld);
2726 if (0 != strcmp(name+offset, tld))
2728 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2729 "%s is not in .%s TLD\n", name, tld);
2736 * DHT resolution for delegation finished. Processing result.
2738 * @param cls the closure
2739 * @param rh resolver handle
2740 * @param rd_count number of results (always 0)
2741 * @param rd record data (always NULL)
2744 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
2745 unsigned int rd_count,
2746 const struct GNUNET_NAMESTORE_RecordData *rd)
2748 struct RecordLookupHandle* rlh;
2752 if (0 == strcmp(rh->name, ""))
2754 if (GNUNET_GNS_RECORD_PKEY == rlh->record_type)
2756 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2757 "GNS_PHASE_DELEGATE_DHT-%llu: Resolved queried PKEY via DHT.\n",
2759 finish_lookup(rh, rlh, rd_count, rd);
2762 /* We resolved full name for delegation. resolving record */
2763 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2764 "GNS_PHASE_DELEGATE_DHT-%llu: Resolved full name for delegation via DHT.\n",
2766 strcpy(rh->name, "+\0");
2767 rh->proc = &handle_record_ns;
2768 resolve_record_ns(rh);
2773 * we still have some left
2775 if (GNUNET_YES == is_canonical (rh->name))
2777 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2778 "GNS_PHASE_DELEGATE_DHT-%llu: Resolving canonical record %s in ns\n",
2781 rh->proc = &handle_record_ns;
2782 resolve_record_ns(rh);
2785 /* give up, cannot resolve */
2786 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2787 "GNS_PHASE_DELEGATE_DHT-%llu: Cannot fully resolve delegation for %s via DHT!\n",
2789 finish_lookup(rh, rlh, 0, NULL);
2794 * Start DHT lookup for a name -> PKEY (compare NS) record in
2795 * rh->authority's zone
2797 * @param rh the pending gns query
2800 resolve_delegation_dht(struct ResolverHandle *rh)
2803 struct GNUNET_CRYPTO_ShortHashCode name_hash;
2804 struct GNUNET_HashCode name_hash_double;
2805 struct GNUNET_HashCode zone_hash_double;
2806 struct GNUNET_HashCode lookup_key;
2807 struct ResolverHandle *rh_heap_root;
2809 pop_tld(rh->name, rh->authority_name);
2811 //FIXME handle return values here
2812 GNUNET_CRYPTO_short_hash(rh->authority_name,
2813 strlen(rh->authority_name),
2815 GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
2816 GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
2817 GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
2819 rh->dht_heap_node = NULL;
2821 if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
2823 rh->timeout_cont = &dht_authority_lookup_timeout;
2824 rh->timeout_cont_cls = rh;
2828 if (max_allowed_background_queries <=
2829 GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
2831 /* terminate oldest lookup */
2832 rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
2833 GNUNET_DHT_get_stop (rh_heap_root->get_handle);
2834 rh_heap_root->get_handle = NULL;
2835 rh_heap_root->dht_heap_node = NULL;
2837 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2838 "GNS_PHASE_DELEGATE_DHT-%llu: Replacing oldest background query for %s\n",
2839 rh->id, rh_heap_root->authority_name);
2841 rh_heap_root->proc(rh_heap_root->proc_cls,
2846 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
2848 GNUNET_TIME_absolute_get().abs_value);
2851 xquery = htonl(GNUNET_GNS_RECORD_PKEY);
2852 GNUNET_assert(rh->get_handle == NULL);
2853 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
2854 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
2856 DHT_GNS_REPLICATION_LEVEL,
2860 &process_delegation_result_dht,
2866 * Namestore resolution for delegation finished. Processing result.
2868 * @param cls the closure
2869 * @param rh resolver handle
2870 * @param rd_count number of results (always 0)
2871 * @param rd record data (always NULL)
2874 handle_delegation_ns (void* cls, struct ResolverHandle *rh,
2875 unsigned int rd_count,
2876 const struct GNUNET_NAMESTORE_RecordData *rd)
2878 struct RecordLookupHandle* rlh;
2880 int check_dht = GNUNET_YES;
2883 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2884 "GNS_PHASE_DELEGATE_NS-%llu: Resolution status: %d.\n",
2885 rh->id, rh->status);
2887 if (rh->status & RSL_PKEY_REVOKED)
2889 finish_lookup (rh, rlh, 0, NULL);
2893 if (0 == strcmp(rh->name, ""))
2896 /* We resolved full name for delegation. resolving record */
2897 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2898 "GNS_PHASE_DELEGATE_NS-%llu: Resolved full name for delegation.\n",
2900 if (rh->status & RSL_CNAME_FOUND)
2902 if (GNUNET_GNS_RECORD_CNAME == rlh->record_type)
2904 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2905 "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried CNAME in NS.\n",
2907 strcpy (rh->name, rh->authority_name);
2908 finish_lookup (rh, rlh, rd_count, rd);
2913 if (GNUNET_YES == is_tld ((char*)rd->data, GNUNET_GNS_TLD_PLUS))
2915 s_len = strlen (rd->data) - 2;
2916 memcpy (rh->name, rd->data, s_len);
2917 rh->name[s_len] = '\0';
2918 resolve_delegation_ns (rh);
2921 else if (GNUNET_YES == is_tld ((char*)rd->data, GNUNET_GNS_TLD_ZKEY))
2923 gns_resolver_lookup_record (rh->authority,
2924 rh->private_local_zone,
2933 GNUNET_CONTAINER_DLL_remove (rlh_head, rlh_tail, rh);
2934 free_resolver_handle (rh);
2940 strcpy (rh->dns_name, (char*)rd->data);
2941 resolve_dns_name (rh);
2946 else if (rh->status & RSL_DELEGATE_VPN)
2948 if (GNUNET_GNS_RECORD_VPN == rlh->record_type)
2950 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2951 "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried VPNRR in NS.\n",
2953 finish_lookup(rh, rlh, rd_count, rd);
2956 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2957 "GNS_PHASE_DELEGATE_NS-%llu: VPN delegation starting.\n",
2959 GNUNET_assert (NULL != rd);
2960 rh->proc = &handle_record_vpn;
2961 resolve_record_vpn (rh, rd_count, rd);
2964 else if (rh->status & RSL_DELEGATE_NS)
2966 if (GNUNET_GNS_RECORD_NS == rlh->record_type)
2968 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2969 "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried NSRR in NS.\n",
2971 finish_lookup(rh, rlh, rd_count, rd);
2975 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2976 "GNS_PHASE_DELEGATE_NS-%llu: NS delegation starting.\n",
2978 GNUNET_assert (NULL != rd);
2979 rh->proc = &handle_record_ns;
2980 resolve_record_dns (rh, rd_count, rd);
2983 else if (rh->status & RSL_DELEGATE_PKEY)
2985 if (rh->status & RSL_PKEY_REVOKED)
2987 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2988 "GNS_PHASE_DELEGATE_NS-%llu: Resolved PKEY is revoked.\n",
2990 finish_lookup (rh, rlh, 0, NULL);
2993 else if (GNUNET_GNS_RECORD_PKEY == rlh->record_type)
2995 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2996 "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried PKEY in NS.\n",
2998 finish_lookup(rh, rlh, rd_count, rd);
3002 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3003 "GNS_PHASE_DELEGATE_NS-%llu: Resolving record +\n",
3005 strcpy(rh->name, "+\0");
3006 rh->proc = &handle_record_ns;
3007 resolve_record_ns(rh);
3011 if (rh->status & RSL_DELEGATE_NS)
3013 if (GNUNET_GNS_RECORD_NS == rlh->record_type)
3015 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3016 "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried NSRR in NS.\n",
3018 finish_lookup(rh, rlh, rd_count, rd);
3022 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3023 "GNS_PHASE_DELEGATE_NS-%llu: NS delegation starting.\n",
3025 GNUNET_assert (NULL != rd);
3026 rh->proc = &handle_record_ns;
3027 resolve_record_dns (rh, rd_count, rd);
3032 * we still have some left
3033 * check if authority in ns is fresh
3035 * or we are authority
3038 if ((rh->status & RSL_RECORD_EXISTS) &&
3039 !(rh->status & RSL_RECORD_EXPIRED))
3040 check_dht = GNUNET_NO;
3042 if (0 == GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3043 &rh->private_local_zone))
3044 check_dht = GNUNET_NO;
3046 if (GNUNET_YES == rh->only_cached)
3047 check_dht = GNUNET_NO;
3049 if (GNUNET_YES == check_dht)
3052 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3053 "GNS_PHASE_DELEGATE_NS-%llu: Trying to resolve delegation for %s via DHT\n",
3055 rh->proc = &handle_delegation_dht;
3056 resolve_delegation_dht(rh);
3060 if (GNUNET_NO == is_canonical (rh->name))
3062 /* give up, cannot resolve */
3063 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3064 "GNS_PHASE_DELEGATE_NS-%llu: Cannot fully resolve delegation for %s!\n",
3067 finish_lookup(rh, rlh, rd_count, rd);
3070 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3071 "GNS_PHASE_DELEGATE_NS-%llu: Resolving canonical record %s\n",
3074 rh->proc = &handle_record_ns;
3075 resolve_record_ns(rh);
3080 * This is a callback function that should give us only PKEY
3081 * records. Used to query the namestore for the authority (PKEY)
3082 * for 'name'. It will recursively try to resolve the
3083 * authority for a given name from the namestore.
3085 * @param cls the pending query
3086 * @param key the key of the zone we did the lookup
3087 * @param expiration expiration date of the record data set in the namestore
3088 * @param name the name for which we need an authority
3089 * @param rd_count the number of records with 'name'
3090 * @param rd the record data
3091 * @param signature the signature of the authority for the record data
3094 process_delegation_result_ns (void* cls,
3095 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
3096 struct GNUNET_TIME_Absolute expiration,
3098 unsigned int rd_count,
3099 const struct GNUNET_NAMESTORE_RecordData *rd,
3100 const struct GNUNET_CRYPTO_RsaSignature *signature)
3102 struct ResolverHandle *rh;
3103 struct GNUNET_TIME_Relative remaining_time;
3104 struct GNUNET_CRYPTO_ShortHashCode zone;
3105 char new_name[MAX_DNS_NAME_LENGTH];
3107 struct GNUNET_TIME_Absolute et;
3109 rh = (struct ResolverHandle *)cls;
3110 rh->namestore_task = NULL;
3111 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3112 "GNS_PHASE_DELEGATE_NS-%llu: Got %d records from authority lookup\n",
3115 GNUNET_CRYPTO_short_hash (key,
3116 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3118 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
3124 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3125 "GNS_PHASE_DELEGATE_NS-%llu: Records with name %s exist.\n",
3127 rh->status |= RSL_RECORD_EXISTS;
3129 if (remaining_time.rel_value == 0)
3131 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3132 "GNS_PHASE_DELEGATE_NS-%llu: Record set %s expired.\n",
3134 rh->status |= RSL_RECORD_EXPIRED;
3139 * No authority found in namestore.
3144 * We did not find an authority in the namestore
3149 * Promote this authority back to a name maybe it is
3152 if (strcmp (rh->name, "") == 0)
3154 /* simply promote back */
3155 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3156 "GNS_PHASE_DELEGATE_NS-%llu: Promoting %s back to name\n",
3157 rh->id, rh->authority_name);
3158 strcpy (rh->name, rh->authority_name);
3162 /* add back to existing name */
3163 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3164 "GNS_PHASE_DELEGATE_NS-%llu: Adding %s back to %s\n",
3165 rh->id, rh->authority_name, rh->name);
3166 GNUNET_snprintf (new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
3167 rh->name, rh->authority_name);
3168 strcpy (rh->name, new_name);
3169 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3170 "GNS_PHASE_DELEGATE_NS-%llu: %s restored\n",
3174 rh->proc (rh->proc_cls, rh, 0, NULL);
3179 * We found an authority that may be able to help us
3180 * move on with query
3181 * Note only 1 pkey should have been returned.. anything else would be strange
3183 for (i=0; i < rd_count;i++)
3187 * A CNAME. Like regular DNS this means the is no other record for this
3190 if (rd[i].record_type == GNUNET_GNS_RECORD_CNAME)
3192 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3193 "GNS_PHASE_DELEGATE_NS-%llu: CNAME found.\n",
3196 rh->status |= RSL_CNAME_FOUND;
3197 rh->proc (rh->proc_cls, rh, rd_count, rd);
3204 if (rd[i].record_type == GNUNET_GNS_RECORD_VPN)
3206 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3207 "GNS_PHASE_DELEGATE_NS-%llu: VPN found.\n",
3209 rh->status |= RSL_DELEGATE_VPN;
3210 rh->proc (rh->proc_cls, rh, rd_count, rd);
3216 * FIXME make optional
3218 if (rd[i].record_type == GNUNET_GNS_RECORD_NS)
3220 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3221 "GNS_PHASE_DELEGATE_NS-%llu: NS found.\n",
3223 rh->status |= RSL_DELEGATE_NS;
3224 rh->proc (rh->proc_cls, rh, rd_count, rd);
3228 if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
3231 rh->status |= RSL_DELEGATE_PKEY;
3233 if ((ignore_pending_records != 0) &&
3234 (rd[i].flags & GNUNET_NAMESTORE_RF_PENDING))
3236 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3237 "GNS_PHASE_DELEGATE_NS-%llu: PKEY for %s is pending user confirmation.\n",
3243 GNUNET_break (0 == (rd[i].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION));
3244 et.abs_value = rd[i].expiration_time;
3245 if ((GNUNET_TIME_absolute_get_remaining (et)).rel_value
3248 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3249 "GNS_PHASE_DELEGATE_NS-%llu: This pkey is expired.\n",
3251 if (remaining_time.rel_value == 0)
3253 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3254 "GNS_PHASE_DELEGATE_NS-%llu: This dht entry is expired.\n",
3256 rh->authority_chain_head->fresh = 0;
3257 rh->proc (rh->proc_cls, rh, 0, NULL);
3265 * Resolve rest of query with new authority
3267 GNUNET_assert (rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
3268 memcpy (&rh->authority, rd[i].data,
3269 sizeof (struct GNUNET_CRYPTO_ShortHashCode));
3270 struct AuthorityChain *auth = GNUNET_malloc(sizeof (struct AuthorityChain));
3271 auth->zone = rh->authority;
3272 memset (auth->name, 0, strlen (rh->authority_name)+1);
3273 strcpy (auth->name, rh->authority_name);
3274 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
3275 rh->authority_chain_tail,
3277 if (NULL != rh->rd.data)
3278 GNUNET_free ((void*)(rh->rd.data));
3280 memcpy (&rh->rd, &rd[i], sizeof (struct GNUNET_NAMESTORE_RecordData));
3281 rh->rd.data = GNUNET_malloc (rd[i].data_size);
3282 memcpy ((void*)rh->rd.data, rd[i].data, rd[i].data_size);
3284 /* Check for key revocation and delegate */
3285 rh->namestore_task = GNUNET_NAMESTORE_lookup_record (namestore_handle,
3288 GNUNET_GNS_RECORD_REV,
3289 &process_pkey_revocation_result_ns,
3298 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3299 "GNS_PHASE_DELEGATE_NS-%llu: Authority lookup and no PKEY...\n", rh->id);
3301 * If we have found some records for the LAST label
3302 * we return the results. Else null.
3304 if (strcmp (rh->name, "") == 0)
3306 /* Start shortening */
3307 if ((rh->priv_key != NULL) &&
3308 (is_canonical (rh->name) == GNUNET_YES))
3310 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3311 "GNS_PHASE_DELEGATE_NS-%llu: Trying to shorten authority chain\n",
3313 start_shorten (rh->authority_chain_head,
3316 /* simply promote back */
3317 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3318 "GNS_PHASE_DELEGATE_NS-%llu: Promoting %s back to name\n",
3319 rh->id, rh->authority_name);
3320 strcpy (rh->name, rh->authority_name);
3321 rh->proc (rh->proc_cls, rh, rd_count, rd);
3325 GNUNET_snprintf (new_name, MAX_DNS_NAME_LENGTH,
3326 "%s.%s", rh->name, rh->authority_name);
3327 strcpy (rh->name, new_name);
3328 rh->proc (rh->proc_cls, rh, 0, NULL);
3334 * Resolve the delegation chain for the request in our namestore
3336 * @param rh the resolver handle
3339 resolve_delegation_ns (struct ResolverHandle *rh)
3341 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3342 "GNS_PHASE_DELEGATE_NS-%llu: Resolving delegation for %s\n",
3344 pop_tld(rh->name, rh->authority_name);
3345 rh->namestore_task = GNUNET_NAMESTORE_lookup_record(namestore_handle,
3348 GNUNET_GNS_RECORD_ANY,
3349 &process_delegation_result_ns,
3356 * Lookup of a record in a specific zone
3357 * calls lookup result processor on result
3359 * @param zone the root zone
3360 * @param pzone the private local zone
3361 * @param record_type the record type to look up
3362 * @param name the name to look up
3363 * @param key a private key for use with PSEU import (can be NULL)
3364 * @param timeout timeout for resolution
3365 * @param only_cached GNUNET_NO to only check locally not DHT for performance
3366 * @param proc the processor to call on result
3367 * @param cls the closure to pass to proc
3370 gns_resolver_lookup_record (struct GNUNET_CRYPTO_ShortHashCode zone,
3371 struct GNUNET_CRYPTO_ShortHashCode pzone,
3372 uint32_t record_type,
3374 struct GNUNET_CRYPTO_RsaPrivateKey *key,
3375 struct GNUNET_TIME_Relative timeout,
3377 RecordLookupProcessor proc,
3380 struct ResolverHandle *rh;
3381 struct RecordLookupHandle* rlh;
3382 char string_hash[MAX_DNS_LABEL_LENGTH];
3383 char nzkey[MAX_DNS_LABEL_LENGTH];
3384 char* nzkey_ptr = nzkey;
3386 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3387 "Starting resolution for %s (type=%d)!\n",
3391 if ((is_canonical ((char*)name) == GNUNET_YES) &&
3392 (strcmp(GNUNET_GNS_TLD, name) != 0))
3394 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3395 "%s is canonical and not gnunet -> cannot resolve!\n", name);
3400 rlh = GNUNET_malloc (sizeof(struct RecordLookupHandle));
3401 rh = GNUNET_malloc (sizeof (struct ResolverHandle));
3403 memset (rh, 0, sizeof (struct ResolverHandle));
3404 rh->authority = zone;
3408 rh->timeout = timeout;
3409 rh->get_handle = NULL;
3410 rh->private_local_zone = pzone;
3411 rh->only_cached = only_cached;
3412 rh->namestore_task = NULL;
3415 GNUNET_CONTAINER_DLL_insert (rlh_head, rlh_tail, rh);
3419 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3420 "No shorten key for resolution\n");
3423 if (timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
3426 * Set timeout for authority lookup phase to 1/2
3428 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3429 "Timeout for lookup set to %ds\n", rh->timeout.rel_value);
3430 rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
3431 GNUNET_TIME_relative_divide(timeout, 2),
3432 &handle_lookup_timeout,
3434 rh->timeout_cont = &dht_authority_lookup_timeout;
3435 rh->timeout_cont_cls = rh;
3439 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No timeout for query!\n");
3440 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3443 if (strcmp(GNUNET_GNS_TLD, name) == 0)
3446 * Only 'gnunet' given
3448 strcpy(rh->name, "\0");
3452 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3453 "Checking for TLD...\n");
3454 if (is_zkey_tld(name) == GNUNET_YES)
3456 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3459 * This is a zkey tld
3460 * build hash and use as initial authority
3463 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
3464 memcpy(rh->name, name,
3465 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
3466 pop_tld(rh->name, string_hash);
3468 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3469 "ZKEY is %s!\n", string_hash);
3471 GNUNET_STRINGS_utf8_toupper(string_hash, &nzkey_ptr);
3473 if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(nzkey,
3476 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3477 "Cannot convert ZKEY %s to hash!\n", string_hash);
3479 GNUNET_CONTAINER_DLL_remove (rlh_head, rlh_tail, rh);
3482 proc (cls, 0, NULL);
3487 else if (is_gnunet_tld (name) == GNUNET_YES)
3489 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3492 * Presumably GNUNET tld
3494 memset (rh->name, 0,
3495 strlen(name)-strlen(GNUNET_GNS_TLD));
3496 memcpy (rh->name, name,
3497 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
3501 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3502 "Cannot handle this TLD %s\n", string_hash);
3504 if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
3505 GNUNET_SCHEDULER_cancel (rh->timeout_task);
3506 GNUNET_CONTAINER_DLL_remove (rlh_head, rlh_tail, rh);
3509 proc (cls, 0, NULL);
3515 * Initialize authority chain
3517 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
3518 rh->authority_chain_head->prev = NULL;
3519 rh->authority_chain_head->next = NULL;
3520 rh->authority_chain_tail = rh->authority_chain_head;
3521 rh->authority_chain_head->zone = rh->authority;
3522 strcpy (rh->authority_chain_head->name, "");
3525 * Copy original query into lookup handle
3527 rlh->record_type = record_type;
3528 memset(rlh->name, 0, strlen(name) + 1);
3529 strcpy(rlh->name, name);
3531 rlh->proc_cls = cls;
3533 rh->proc = &handle_delegation_ns;
3534 resolve_delegation_ns(rh);
3537 /******** END Record Resolver ***********/
3540 finish_shorten (struct ResolverHandle *rh,
3541 struct NameShortenHandle *nsh)
3543 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3544 "Sending %s as shorten result\n", nsh->result);
3545 nsh->proc (nsh->proc_cls, nsh->result);
3546 GNUNET_CONTAINER_DLL_remove (nsh_head, nsh_tail, rh);
3548 free_resolver_handle (rh);
3553 * Callback calles by namestore for a zone to name
3556 * @param cls the closure
3557 * @param zone_key the zone we queried
3558 * @param expire the expiration time of the name
3559 * @param name the name found or NULL
3560 * @param rd_len number of records for the name
3561 * @param rd the record data (PKEY) for the name
3562 * @param signature the signature for the record data
3565 process_zone_to_name_shorten_root (void *cls,
3566 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
3567 struct GNUNET_TIME_Absolute expire,
3569 unsigned int rd_len,
3570 const struct GNUNET_NAMESTORE_RecordData *rd,
3571 const struct GNUNET_CRYPTO_RsaSignature *signature);
3575 * Callback called by namestore for a zone to name
3578 * @param cls the closure
3579 * @param zone_key the zone we queried
3580 * @param expire the expiration time of the name
3581 * @param name the name found or NULL
3582 * @param rd_len number of records for the name
3583 * @param rd the record data (PKEY) for the name
3584 * @param signature the signature for the record data
3587 process_zone_to_name_shorten_shorten (void *cls,
3588 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
3589 struct GNUNET_TIME_Absolute expire,
3591 unsigned int rd_len,
3592 const struct GNUNET_NAMESTORE_RecordData *rd,
3593 const struct GNUNET_CRYPTO_RsaSignature *signature)
3595 struct ResolverHandle *rh = (struct ResolverHandle *)cls;
3596 struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
3597 struct AuthorityChain *next_authority;
3599 char result[MAX_DNS_NAME_LENGTH];
3600 char tmp_name[MAX_DNS_NAME_LENGTH];
3603 rh->namestore_task = NULL;
3604 /* we found a match in our own root zone */
3607 answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
3608 memset(result, 0, answer_len);
3610 if (strlen(rh->name) > 0)
3612 sprintf (result, "%s.%s.%s.%s",
3614 nsh->shorten_zone_name,
3619 sprintf (result, "%s.%s.%s", name,
3620 nsh->shorten_zone_name,
3624 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3625 "Found shorten result %s\n", result);
3626 if (strlen (nsh->result) > strlen (result))
3627 strcpy (nsh->result, result);
3629 else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3630 nsh->shorten_zone) == 0)
3633 * This is our zone append .gnunet unless name is empty
3634 * (it shouldn't be, usually FIXME what happens if we
3635 * shorten to our zone to a "" record??)
3638 sprintf (result, "%s.%s.%s",
3640 nsh->shorten_zone_name,
3642 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3643 "Our zone: Found %s as shorten result\n", result);
3645 if (strlen (nsh->result) > strlen (result))
3646 strcpy (nsh->result, result);
3647 //nsh->proc(nsh->proc_cls, result);
3649 //free_resolver_handle(rh);
3656 * continue with next authority if exists
3658 if ((rh->authority_chain_head->next == NULL))
3660 finish_shorten (rh, nsh);
3663 next_authority = rh->authority_chain_head;
3665 GNUNET_snprintf(tmp_name, MAX_DNS_NAME_LENGTH,
3666 "%s.%s", rh->name, next_authority->name);
3668 strcpy(rh->name, tmp_name);
3669 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3670 "No PSEU found for authority %s. Promoting back: %s\n",
3671 next_authority->name, rh->name);
3673 GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
3674 rh->authority_chain_tail,
3677 GNUNET_free (next_authority);
3679 rh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3680 &rh->authority_chain_tail->zone,
3681 &rh->authority_chain_head->zone,
3682 &process_zone_to_name_shorten_root,
3687 * Callback calles by namestore for a zone to name
3690 * @param cls the closure
3691 * @param zone_key the zone we queried
3692 * @param expire the expiration time of the name
3693 * @param name the name found or NULL
3694 * @param rd_len number of records for the name
3695 * @param rd the record data (PKEY) for the name
3696 * @param signature the signature for the record data
3699 process_zone_to_name_shorten_private (void *cls,
3700 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
3701 struct GNUNET_TIME_Absolute expire,
3703 unsigned int rd_len,
3704 const struct GNUNET_NAMESTORE_RecordData *rd,
3705 const struct GNUNET_CRYPTO_RsaSignature *signature)
3707 struct ResolverHandle *rh = (struct ResolverHandle *)cls;
3708 struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
3709 struct AuthorityChain *next_authority;
3711 char result[MAX_DNS_NAME_LENGTH];
3712 char tmp_name[MAX_DNS_NAME_LENGTH];
3715 rh->namestore_task = NULL;
3716 /* we found a match in our own root zone */
3719 answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
3720 memset(result, 0, answer_len);
3722 if (strlen(rh->name) > 0)
3724 sprintf (result, "%s.%s.%s", rh->name, name, GNUNET_GNS_TLD);
3728 sprintf (result, "%s.%s", name, GNUNET_GNS_TLD);
3731 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3732 "Found shorten result %s\n", result);
3733 if (strlen (nsh->result) > strlen (result))
3734 strcpy (nsh->result, result);
3736 else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3737 nsh->private_zone) == 0)
3740 * This is our zone append .gnunet unless name is empty
3741 * (it shouldn't be, usually FIXME what happens if we
3742 * shorten to our zone to a "" record??)
3745 sprintf (result, "%s.%s.%s",
3746 rh->name, nsh->private_zone_name, GNUNET_GNS_TLD);
3747 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3748 "Our private zone: Found %s as shorten result %s\n", result);
3749 if (strlen (nsh->result) > strlen (result))
3750 strcpy (nsh->result, result);
3753 if (0 != strcmp (nsh->shorten_zone_name, ""))
3755 /* backtrack authorities for names in priv zone */
3756 rh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3758 &rh->authority_chain_head->zone,
3759 &process_zone_to_name_shorten_shorten,
3766 * continue with next authority if exists
3768 if ((rh->authority_chain_head->next == NULL))
3770 finish_shorten (rh, nsh);
3773 next_authority = rh->authority_chain_head;
3775 GNUNET_snprintf(tmp_name, MAX_DNS_NAME_LENGTH,
3776 "%s.%s", rh->name, next_authority->name);
3778 strcpy(rh->name, tmp_name);
3779 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3780 "No PSEU found for authority %s. Promoting back: %s\n",
3781 next_authority->name, rh->name);
3783 GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
3784 rh->authority_chain_tail,
3787 GNUNET_free (next_authority);
3789 rh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3790 &rh->authority_chain_tail->zone,
3791 &rh->authority_chain_head->zone,
3792 &process_zone_to_name_shorten_root,
3798 * Callback calles by namestore for a zone to name
3801 * @param cls the closure
3802 * @param zone_key the zone we queried
3803 * @param expire the expiration time of the name
3804 * @param name the name found or NULL
3805 * @param rd_len number of records for the name
3806 * @param rd the record data (PKEY) for the name
3807 * @param signature the signature for the record data
3810 process_zone_to_name_shorten_root (void *cls,
3811 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
3812 struct GNUNET_TIME_Absolute expire,
3814 unsigned int rd_len,
3815 const struct GNUNET_NAMESTORE_RecordData *rd,
3816 const struct GNUNET_CRYPTO_RsaSignature *signature)
3818 struct ResolverHandle *rh = (struct ResolverHandle *)cls;
3819 struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
3820 struct AuthorityChain *next_authority;
3822 char result[MAX_DNS_NAME_LENGTH];
3823 char tmp_name[MAX_DNS_NAME_LENGTH];
3826 rh->namestore_task = NULL;
3827 /* we found a match in our own root zone */
3830 answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
3831 memset(result, 0, answer_len);
3833 if (strlen(rh->name) > 0)
3835 sprintf (result, "%s.%s.%s", rh->name, name, GNUNET_GNS_TLD);
3839 sprintf (result, "%s.%s", name, GNUNET_GNS_TLD);
3842 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3843 "Found shorten result %s\n", result);
3844 if (strlen (nsh->result) > strlen (result))
3845 strcpy (nsh->result, result);
3847 else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3848 nsh->root_zone) == 0)
3851 * This is our zone append .gnunet unless name is empty
3852 * (it shouldn't be, usually FIXME what happens if we
3853 * shorten to our zone to a "" record??)
3856 sprintf (result, "%s.%s", rh->name, GNUNET_GNS_TLD);
3857 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3858 "Our zone: Found %s as shorten result\n", result);
3859 if (strlen (nsh->result) > strlen (result))
3860 strcpy (nsh->result, result);
3863 if (NULL != nsh->private_zone)
3865 /* backtrack authorities for names in priv zone */
3866 rh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3868 &rh->authority_chain_head->zone,
3869 &process_zone_to_name_shorten_private,
3872 else if (NULL != nsh->shorten_zone)
3874 /* backtrack authorities for names in shorten zone */
3875 rh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3877 &rh->authority_chain_head->zone,
3878 &process_zone_to_name_shorten_shorten,
3885 * continue with next authority if exists
3887 if ((rh->authority_chain_head->next == NULL))
3889 finish_shorten (rh, nsh);
3892 next_authority = rh->authority_chain_head;
3894 GNUNET_snprintf(tmp_name, MAX_DNS_NAME_LENGTH,
3895 "%s.%s", rh->name, next_authority->name);
3897 strcpy(rh->name, tmp_name);
3898 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3899 "No PSEU found for authority %s. Promoting back: %s\n",
3900 next_authority->name, rh->name);
3902 GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
3903 rh->authority_chain_tail,
3906 GNUNET_free (next_authority);
3908 rh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3909 &rh->authority_chain_tail->zone,
3910 &rh->authority_chain_head->zone,
3911 &process_zone_to_name_shorten_root,
3918 * Process result from namestore delegation lookup
3919 * for shorten operation
3921 * @param cls the client shorten handle
3922 * @param rh the resolver handle
3923 * @param rd_count number of results (0)
3924 * @param rd data (NULL)
3927 handle_delegation_ns_shorten (void* cls,
3928 struct ResolverHandle *rh,
3930 const struct GNUNET_NAMESTORE_RecordData *rd)
3932 struct NameShortenHandle *nsh;
3933 char result[MAX_DNS_NAME_LENGTH];
3935 nsh = (struct NameShortenHandle *)cls;
3938 * At this point rh->name contains the part of the name
3939 * that we do not have a PKEY in our namestore to resolve.
3940 * The authority chain in the resolver handle is now
3941 * useful to backtrack if needed
3944 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3945 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
3946 memset(result, 0, sizeof (result));
3948 if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3949 nsh->root_zone) == 0)
3952 * This is our zone append .gnunet unless name is empty
3953 * (it shouldn't be, usually FIXME what happens if we
3954 * shorten to our zone to a "" record??)
3957 sprintf (result, "%s.%s", rh->name, GNUNET_GNS_TLD);
3958 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3959 "Our zone: Found %s as shorten result\n", result);
3961 if (strlen (nsh->result) > strlen (result))
3962 strcpy (nsh->result, result);
3965 else if (NULL != nsh->private_zone)
3968 * This is our zone append .gnunet unless name is empty
3969 * (it shouldn't be, usually FIXME what happens if we
3970 * shorten to our zone to a "" record??)
3972 if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3973 nsh->private_zone) == 0)
3976 sprintf (result, "%s.%s.%s",
3977 rh->name, nsh->private_zone_name, GNUNET_GNS_TLD);
3978 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3979 "Our zone: Found %s as shorten result in private zone %s\n",
3982 if (strlen (nsh->result) > strlen (result))
3983 strcpy (nsh->result, result);
3986 else if (NULL != nsh->shorten_zone)
3989 * This is our zone append .gnunet unless name is empty
3990 * (it shouldn't be, usually FIXME what happens if we
3991 * shorten to our zone to a "" record??)
3993 if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3994 nsh->shorten_zone) == 0)
3996 sprintf (result, "%s.%s.%s",
3997 rh->name, nsh->private_zone_name, GNUNET_GNS_TLD);
3998 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3999 "Our zone: Found %s as shorten result in shorten zone\n",
4002 if (strlen (nsh->result) > strlen (result))
4003 strcpy (nsh->result, result);
4008 /* backtrack authorities for names */
4009 rh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
4011 &rh->authority_chain_head->zone,
4012 &process_zone_to_name_shorten_root,
4019 * Callback calles by namestore for a zone to name
4022 * @param cls the closure
4023 * @param zone_key the zone we queried
4024 * @param expire the expiration time of the name
4025 * @param name the name found or NULL
4026 * @param rd_len number of records for the name
4027 * @param rd the record data (PKEY) for the name
4028 * @param signature the signature for the record data
4031 process_zone_to_name_zkey(void *cls,
4032 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
4033 struct GNUNET_TIME_Absolute expire,
4035 unsigned int rd_len,
4036 const struct GNUNET_NAMESTORE_RecordData *rd,
4037 const struct GNUNET_CRYPTO_RsaSignature *signature)
4039 struct ResolverHandle *rh = cls;
4040 struct NameShortenHandle *nsh = rh->proc_cls;
4041 struct GNUNET_CRYPTO_ShortHashAsciiEncoded enc;
4042 char new_name[MAX_DNS_NAME_LENGTH];
4044 /* zkey not in our zone */
4048 * In this case we have not given this PKEY a name (yet)
4049 * It is either just not in our zone or not even cached
4050 * Since we do not know at this point we will not try to shorten
4051 * because PKEY import will happen if the user follows the zkey
4054 GNUNET_CRYPTO_short_hash_to_enc ((struct GNUNET_CRYPTO_ShortHashCode*)rd,
4056 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4057 "No name found for zkey %s returning verbatim!\n", enc);
4058 if (strcmp(rh->name, "") != 0)
4059 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s.%s",
4060 rh->name, enc, GNUNET_GNS_TLD_ZKEY);
4062 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
4063 enc, GNUNET_GNS_TLD_ZKEY);
4065 strcpy (nsh->result, new_name);
4067 finish_shorten (rh, nsh);
4071 if (strcmp(rh->name, "") != 0)
4072 GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
4075 strcpy(new_name, name);
4077 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4078 "Continue shorten for %s!\n", new_name);
4080 strcpy(rh->name, new_name);
4082 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
4083 rh->authority_chain_tail = rh->authority_chain_head;
4084 rh->authority_chain_head->zone = rh->authority;
4087 /* Start delegation resolution in our namestore */
4088 resolve_delegation_ns (rh);
4093 * Shorten api from resolver
4095 * @param zone the root zone to use
4096 * @param pzone the private zone to use
4097 * @param szone the shorten zone to use
4098 * @param name the name to shorten
4099 * @param private_zone_name name of the private zone
4100 * @param shorten_zone_name name of the shorten zone
4101 * @param proc the processor to call with result
4102 * @param proc_cls closure to pass to proc
4105 gns_resolver_shorten_name (struct GNUNET_CRYPTO_ShortHashCode *zone,
4106 struct GNUNET_CRYPTO_ShortHashCode *pzone,
4107 struct GNUNET_CRYPTO_ShortHashCode *szone,
4109 const char* private_zone_name,
4110 const char* shorten_zone_name,
4111 ShortenResultProcessor proc,
4114 struct ResolverHandle *rh;
4115 struct NameShortenHandle *nsh;
4116 char string_hash[MAX_DNS_LABEL_LENGTH];
4117 struct GNUNET_CRYPTO_ShortHashCode zkey;
4118 char nzkey[MAX_DNS_LABEL_LENGTH];
4119 char* nzkey_ptr = nzkey;
4122 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4123 "Starting shorten for %s!\n", name);
4125 if (is_canonical ((char*)name) == GNUNET_YES)
4127 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4128 "%s is canonical. Returning verbatim\n", name);
4129 proc (proc_cls, name);
4133 nsh = GNUNET_malloc (sizeof (struct NameShortenHandle));
4136 nsh->proc_cls = proc_cls;
4137 nsh->root_zone = zone;
4138 nsh->private_zone = pzone;
4139 nsh->shorten_zone = szone;
4140 strcpy (nsh->private_zone_name, private_zone_name);
4141 strcpy (nsh->shorten_zone_name, shorten_zone_name);
4142 strcpy (nsh->result, name);
4145 rh = GNUNET_malloc (sizeof (struct ResolverHandle));
4146 rh->authority = *zone;
4148 rh->priv_key = NULL;
4149 rh->namestore_task = NULL;
4150 rh->proc = &handle_delegation_ns_shorten;
4153 rh->private_local_zone = *zone;
4155 GNUNET_CONTAINER_DLL_insert (nsh_head, nsh_tail, rh);
4157 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4158 "Checking for TLD...\n");
4159 if (is_zkey_tld (name) == GNUNET_YES)
4161 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4164 * This is a zkey tld
4165 * build hash and use as initial authority
4168 memset (rh->name, 0,
4169 strlen (name)-strlen (GNUNET_GNS_TLD_ZKEY));
4170 memcpy (rh->name, name,
4171 strlen(name)-strlen (GNUNET_GNS_TLD_ZKEY) - 1);
4172 pop_tld (rh->name, string_hash);
4174 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4175 "ZKEY is %s!\n", string_hash);
4177 GNUNET_STRINGS_utf8_toupper (string_hash, &nzkey_ptr);
4179 if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string (nzkey,
4182 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4183 "Cannot convert ZKEY %s to hash!\n", nzkey);
4186 GNUNET_CONTAINER_DLL_remove (nsh_head, nsh_tail, rh);
4187 proc (proc_cls, name);
4191 rh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
4194 &process_zone_to_name_zkey,
4199 else if (is_gnunet_tld (name) == GNUNET_YES)
4201 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4204 * Presumably GNUNET tld
4206 memset (rh->name, 0,
4207 strlen (name)-strlen (GNUNET_GNS_TLD));
4208 memcpy (rh->name, name,
4209 strlen (name)-strlen (GNUNET_GNS_TLD) - 1);
4213 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unknown TLD in %s\n", name);
4216 GNUNET_CONTAINER_DLL_remove (nsh_head, nsh_tail, rh);
4217 proc (proc_cls, name);
4221 rh->authority_chain_head = GNUNET_malloc (sizeof (struct AuthorityChain));
4222 rh->authority_chain_tail = rh->authority_chain_head;
4223 rh->authority_chain_head->zone = *zone;
4226 /* Start delegation resolution in our namestore */
4227 resolve_delegation_ns (rh);
4230 /*********** END NAME SHORTEN ********************/
4233 * Conclude get authority lookup
4235 * @param rh resolver handle
4236 * @param nah get authority lookup handle
4239 finish_get_auth (struct ResolverHandle *rh,
4240 struct GetNameAuthorityHandle *nah)
4242 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4243 "Got authority result %s\n", nah->result);
4245 nah->proc(nah->proc_cls, nah->result);
4246 GNUNET_CONTAINER_DLL_remove (nah_head, nah_tail, rh);
4248 free_resolver_handle(rh);
4252 * Process result from namestore delegation lookup
4253 * for get authority operation
4255 * @param cls the client get auth handle
4256 * @param rh the resolver handle
4257 * @param rd_count number of results (0)
4258 * @param rd data (NULL)
4261 handle_delegation_result_ns_get_auth(void* cls,
4262 struct ResolverHandle *rh,
4264 const struct GNUNET_NAMESTORE_RecordData *rd)
4266 struct GetNameAuthorityHandle* nah;
4269 nah = (struct GetNameAuthorityHandle*) rh->proc_cls;
4272 * At this point rh->name contains the part of the name
4273 * that we do not have a PKEY in our namestore to resolve.
4274 * The authority chain in the resolver handle is now
4275 * useful to backtrack if needed
4278 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4279 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
4281 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4282 "Building response!\n");
4283 if (is_canonical (rh->name) == GNUNET_YES)
4286 * We successfully resolved the authority in the ns
4287 * FIXME for our purposes this is fine
4288 * but maybe we want to have an api that also looks
4289 * into the dht (i.e. option in message)
4291 if (strlen(rh->name) > strlen(nah->name))
4293 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4294 "Record name longer than original lookup name... odd!\n");
4298 answer_len = strlen(nah->name) - strlen(rh->name)
4299 + strlen(GNUNET_GNS_TLD) + 1;
4300 memset(nah->result, 0, answer_len);
4301 strcpy(nah->result, nah->name + strlen(rh->name) + 1);
4303 finish_get_auth (rh, nah);
4307 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4308 "Unable to resolve authority for remaining %s!\n", rh->name);
4309 strcpy(nah->result, "");
4310 finish_get_auth (rh, nah);
4318 * Tries to resolve the authority for name
4321 * @param zone the root zone to look up for
4322 * @param pzone the private local zone
4323 * @param name the name to lookup up
4324 * @param proc the processor to call when finished
4325 * @param proc_cls the closure to pass to the processor
4328 gns_resolver_get_authority(struct GNUNET_CRYPTO_ShortHashCode zone,
4329 struct GNUNET_CRYPTO_ShortHashCode pzone,
4331 GetAuthorityResultProcessor proc,
4334 struct ResolverHandle *rh;
4335 struct GetNameAuthorityHandle *nah;
4337 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4338 "Starting authority resolution for %s!\n", name);
4340 nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
4341 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
4342 rh->authority = zone;
4344 rh->private_local_zone = pzone;
4345 rh->namestore_task = NULL;
4347 GNUNET_CONTAINER_DLL_insert (nah_head, nah_tail, rh);
4349 if (strcmp(GNUNET_GNS_TLD, name) == 0)
4351 strcpy(rh->name, "\0");
4356 strlen(name)-strlen(GNUNET_GNS_TLD));
4357 memcpy(rh->name, name,
4358 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
4361 memset(nah->name, 0,
4363 strcpy(nah->name, name);
4365 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
4366 rh->authority_chain_tail = rh->authority_chain_head;
4367 rh->authority_chain_head->zone = zone;
4368 rh->proc = &handle_delegation_result_ns_get_auth;
4369 rh->proc_cls = (void*)nah;
4372 nah->proc_cls = proc_cls;
4373 strcpy (nah->result, "");
4375 /* Start delegation resolution in our namestore */
4376 resolve_delegation_ns(rh);
4380 /******** END GET AUTHORITY *************/
4382 /* end of gnunet-service-gns_resolver.c */