2 This file is part of GNUnet.
3 (C) 2011-2013 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
25 * @author Christian Grothoff
28 #include "gnunet_util_lib.h"
29 #include "gnunet_transport_service.h"
30 #include "gnunet_dnsstub_lib.h"
31 #include "gnunet_dht_service.h"
32 #include "gnunet_namestore_service.h"
33 #include "gnunet_dns_service.h"
34 #include "gnunet_resolver_service.h"
35 #include "gnunet_dnsparser_lib.h"
36 #include "gns_protocol.h"
37 #include "gnunet_gns_service.h"
38 #include "gns_common.h"
40 #include "gnunet-service-gns_resolver.h"
41 #include "gnunet_vpn_service.h"
44 #define DHT_OPERATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
46 #define GNUNET_GNS_DEFAULT_LOOKUP_TIMEOUT \
47 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
49 #define DHT_LOOKUP_TIMEOUT DHT_OPERATION_TIMEOUT
51 #define DHT_GNS_REPLICATION_LEVEL 5
53 #define GNUNET_GNS_MAX_PARALLEL_LOOKUPS 500
55 #define GNUNET_GNS_MAX_NS_TASKS 500
61 #define DHT_LOOKUP_TIMEOUT DHT_OPERATION_TIMEOUT
64 * DHT replication level
66 #define DHT_GNS_REPLICATION_LEVEL 5
70 * DLL to hold the authority chain we had to pass in the resolution
78 struct AuthorityChain *prev;
83 struct AuthorityChain *next;
86 * label corresponding to the authority
88 char label[GNUNET_DNSPARSER_MAX_LABEL_LENGTH];
91 * #GNUNET_YES if the authority was a GNS authority,
92 * #GNUNET_NO if the authority was a DNS authority.
97 * Information about the resolver authority for this label.
103 * The zone of the GNS authority
105 struct GNUNET_CRYPTO_EccPublicKey gns_authority;
110 * Domain of the DNS resolver that is the authority.
111 * (appended to construct the DNS name to resolve;
112 * this is NOT the DNS name of the DNS server!).
114 char name[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
117 * IP address of the DNS resolver that is authoritative.
118 * (this implementation currently only supports one
121 struct sockaddr_storage dns_ip;
131 * Resolution status indicator
133 enum ResolutionStatus
136 * the name to lookup exists
138 RSL_RECORD_EXISTS = 1,
141 * the name in the record expired
143 RSL_RECORD_EXPIRED = 2,
146 * resolution timed out
151 * Found VPN delegation
153 RSL_DELEGATE_VPN = 8,
156 * Found NS delegation
158 RSL_DELEGATE_NS = 16,
161 * Found PKEY delegation
163 RSL_DELEGATE_PKEY = 32,
168 RSL_CNAME_FOUND = 64,
171 * Found PKEY has been revoked
173 RSL_PKEY_REVOKED = 128
178 * Handle to a currenty pending resolution. On result (positive or
179 * negative) the #GNS_ResultProcessor is called.
181 struct GNS_ResolverHandle
187 struct GNS_ResolverHandle *next;
192 struct GNS_ResolverHandle *prev;
195 * The top-level GNS authoritative zone to query
197 struct GNUNET_CRYPTO_EccPublicKey authority_zone;
200 * called when resolution phase finishes
202 GNS_ResultProcessor proc;
205 * closure passed to proc
210 * Handle for DHT lookups. should be NULL if no lookups are in progress
212 struct GNUNET_DHT_GetHandle *get_handle;
215 * Handle to a VPN request, NULL if none is active.
217 struct GNUNET_VPN_RedirectionRequest *vpn_handle;
220 * Socket for a DNS request, NULL if none is active.
222 struct GNUNET_DNSSTUB_RequestSocket *dns_request;
225 * Pending Namestore task
227 struct GNUNET_NAMESTORE_QueueEntry *namestore_task;
230 * Heap node associated with this lookup. Used to limit number of
231 * concurrent requests.
233 struct GNUNET_CONTAINER_HeapNode *dht_heap_node;
236 * DLL to store the authority chain
238 struct AuthorityChain *authority_chain_head;
241 * DLL to store the authority chain
243 struct AuthorityChain *authority_chain_tail;
246 * Private key of the shorten zone, NULL to not shorten.
248 struct GNUNET_CRYPTO_EccPrivateKey *shorten_key;
251 * The name to resolve
253 char name[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
256 * Current offset in 'name' where we are resolving.
258 size_t name_resolution_pos;
269 * Handle for a PSEU lookup used to shorten names.
271 struct GetPseuAuthorityHandle
276 struct GetPseuAuthorityHandle *next;
281 struct GetPseuAuthorityHandle *prev;
284 * Private key of the (shorten) zone to store the resulting
287 struct GNUNET_CRYPTO_EccPrivateKey shorten_zone_key;
290 * Original label (used if no PSEU record is found).
292 char label[GNUNET_DNSPARSER_MAX_LABEL_LENGTH + 1];
295 * The zone for which we are trying to find the PSEU record.
297 struct GNUNET_CRYPTO_EccPublicKey target_zone;
300 * Handle for DHT lookups. Should be NULL if no lookups are in progress
302 struct GNUNET_DHT_GetHandle *get_handle;
305 * Handle to namestore request
307 struct GNUNET_NAMESTORE_QueueEntry *namestore_task;
310 * Task to abort DHT lookup operation.
312 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
318 * Our handle to the namestore service
320 static struct GNUNET_NAMESTORE_Handle *namestore_handle;
323 * Our handle to the vpn service
325 static struct GNUNET_VPN_Handle *vpn_handle;
328 * Resolver handle to the dht
330 static struct GNUNET_DHT_Handle *dht_handle;
333 * Handle to perform DNS lookups.
335 static struct GNUNET_DNSSTUB_Context *dns_handle;
338 * Heap for limiting parallel DHT lookups
340 static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
343 * Maximum amount of parallel queries in background
345 static unsigned long long max_allowed_background_queries;
348 * Head of PSEU/shorten operations list.
350 struct GetPseuAuthorityHandle *gph_head;
353 * Tail of PSEU/shorten operations list.
355 struct GetPseuAuthorityHandle *gph_tail;
358 * Head of resolver lookup list
360 static struct GNS_ResolverHandle *rlh_head;
363 * Tail of resolver lookup list
365 static struct GNS_ResolverHandle *rlh_tail;
368 * Global configuration.
370 static const struct GNUNET_CONFIGURATION_Handle *cfg;
374 * Check if name is in srv format (_x._y.xxx)
377 * @return GNUNET_YES if true
380 is_srv (const char *name)
387 if (NULL == strstr (name, "._"))
390 ndup = GNUNET_strdup (name);
392 if (NULL == strtok (NULL, "."))
394 if (NULL == strtok (NULL, "."))
396 if (NULL != strtok (NULL, "."))
404 * Determine if this name is canonical (is a legal name in a zone, without delegation);
405 * note that we do not test that the name does not contain illegal characters, we only
406 * test for delegation. Note that service records (i.e. _foo._srv) are canonical names
407 * even though they consist of multiple labels.
410 * a.b.gads = not canonical
412 * _foo._srv = canonical
413 * _f.bar = not canonical
415 * @param name the name to test
416 * @return GNUNET_YES if canonical
419 is_canonical (const char *name)
424 if (NULL == strchr (name, '.'))
429 while (NULL != (dot = strchr (pos, '.')))
438 /* ******************** Shortening logic ************************ */
442 * Cleanup a 'struct GetPseuAuthorityHandle', terminating all
443 * pending activities.
445 * @param gph handle to terminate
448 free_get_pseu_authority_handle (struct GetPseuAuthorityHandle *gph)
450 if (NULL != gph->get_handle)
452 GNUNET_DHT_get_stop (gph->get_handle);
453 gph->get_handle = NULL;
455 if (NULL != gph->namestore_task)
457 GNUNET_NAMESTORE_cancel (gph->namestore_task);
458 gph->namestore_task = NULL;
460 if (GNUNET_SCHEDULER_NO_TASK != gph->timeout_task)
462 GNUNET_SCHEDULER_cancel (gph->timeout_task);
463 gph->timeout_task = GNUNET_SCHEDULER_NO_TASK;
465 GNUNET_CONTAINER_DLL_remove (gph_head, gph_tail, gph);
471 * Continuation for pkey record creation (shorten)
473 * @param cls a GetPseuAuthorityHandle
474 * @param success unused
478 create_pkey_cont (void* cls,
482 struct GetPseuAuthorityHandle* gph = cls;
484 gph->namestore_task = NULL;
485 free_get_pseu_authority_handle (gph);
490 * Namestore calls this function if we have record for this name.
491 * (or with rd_count=0 to indicate no matches).
493 * @param cls the pending query
494 * @param key the key of the zone we did the lookup
495 * @param name the name for which we need an authority
496 * @param rd_count the number of records with 'name'
497 * @param rd the record data
500 process_pseu_lookup_ns (void *cls,
501 const struct GNUNET_CRYPTO_EccPrivateKey *key,
503 unsigned int rd_count,
504 const struct GNUNET_NAMESTORE_RecordData *rd)
506 struct GetPseuAuthorityHandle *gph = cls;
507 struct GNUNET_NAMESTORE_RecordData new_pkey;
509 gph->namestore_task = NULL;
512 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
513 "Name `%s' already taken, cannot shorten.\n",
515 /* if this was not yet the original label, try one more
516 time, this time not using PSEU but the original label */
517 if (0 == strcmp (name,
519 free_get_pseu_authority_handle (gph);
521 gph->namestore_task = GNUNET_NAMESTORE_lookup (namestore_handle,
522 &gph->shorten_zone_key,
524 GNUNET_NAMESTORE_TYPE_ANY,
525 &process_pseu_lookup_ns,
529 /* name is available */
530 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
531 "Shortening `%s' to `%s'\n",
532 GNUNET_NAMESTORE_z2s (&gph->target_zone),
534 new_pkey.expiration_time = UINT64_MAX;
535 new_pkey.data_size = sizeof (struct GNUNET_CRYPTO_EccPublicKey);
536 new_pkey.data = &gph->target_zone;
537 new_pkey.record_type = GNUNET_NAMESTORE_TYPE_PKEY;
538 new_pkey.flags = GNUNET_NAMESTORE_RF_AUTHORITY
539 | GNUNET_NAMESTORE_RF_PRIVATE
540 | GNUNET_NAMESTORE_RF_PENDING;
542 = GNUNET_NAMESTORE_records_store (namestore_handle,
543 &gph->shorten_zone_key,
546 &create_pkey_cont, gph);
551 * Process result of a DHT lookup for a PSEU record.
553 * @param gph the handle to our shorten operation
554 * @param pseu the pseu result or NULL
557 process_pseu_result (struct GetPseuAuthorityHandle* gph,
562 /* no PSEU found, try original label */
563 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
564 "No PSEU found, trying original label `%s' instead.\n",
566 gph->namestore_task = GNUNET_NAMESTORE_lookup (namestore_handle,
567 &gph->shorten_zone_key,
569 GNUNET_NAMESTORE_TYPE_ANY,
570 &process_pseu_lookup_ns,
575 /* check if 'pseu' is taken */
576 gph->namestore_task = GNUNET_NAMESTORE_lookup (namestore_handle,
577 &gph->shorten_zone_key,
579 GNUNET_NAMESTORE_TYPE_ANY,
580 &process_pseu_lookup_ns,
586 * Handle timeout for DHT request during shortening.
588 * @param cls the request handle as closure
589 * @param tc the task context
592 handle_auth_discovery_timeout (void *cls,
593 const struct GNUNET_SCHEDULER_TaskContext *tc)
595 struct GetPseuAuthorityHandle *gph = cls;
597 gph->timeout_task = GNUNET_SCHEDULER_NO_TASK;
598 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
599 "DHT lookup for PSEU query timed out.\n");
600 GNUNET_DHT_get_stop (gph->get_handle);
601 gph->get_handle = NULL;
602 process_pseu_result (gph, NULL);
607 * Handle decrypted records from DHT result.
609 * @param cls closure with our 'struct GetPseuAuthorityHandle'
610 * @param rd_count number of entries in 'rd' array
611 * @param rd array of records with data to store
614 process_auth_records (void *cls,
615 unsigned int rd_count,
616 const struct GNUNET_NAMESTORE_RecordData *rd)
618 struct GetPseuAuthorityHandle *gph = cls;
621 for (i=0; i < rd_count; i++)
623 if (GNUNET_NAMESTORE_TYPE_PSEU == rd[i].record_type)
626 process_pseu_result (gph,
627 (const char *) rd[i].data);
631 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
632 "No PSEU record found in DHT reply.\n");
633 process_pseu_result (gph, NULL);
638 * Function called when we find a PSEU entry in the DHT
640 * @param cls the request handle
641 * @param exp lifetime
642 * @param key the key the record was stored under
643 * @param get_path get path
644 * @param get_path_length get path length
645 * @param put_path put path
646 * @param put_path_length put path length
647 * @param type the block type
648 * @param size the size of the record
649 * @param data the record data
652 process_auth_discovery_dht_result (void* cls,
653 struct GNUNET_TIME_Absolute exp,
654 const struct GNUNET_HashCode *key,
655 const struct GNUNET_PeerIdentity *get_path,
656 unsigned int get_path_length,
657 const struct GNUNET_PeerIdentity *put_path,
658 unsigned int put_path_length,
659 enum GNUNET_BLOCK_Type type,
663 struct GetPseuAuthorityHandle *gph = cls;
664 const struct GNUNET_NAMESTORE_Block *block;
666 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
667 "Got DHT result for PSEU request\n");
668 GNUNET_DHT_get_stop (gph->get_handle);
669 gph->get_handle = NULL;
670 GNUNET_SCHEDULER_cancel (gph->timeout_task);
671 gph->timeout_task = GNUNET_SCHEDULER_NO_TASK;
675 /* is this allowed!? */
677 process_pseu_result (gph, NULL);
680 if (size < sizeof (struct GNUNET_NAMESTORE_Block))
682 /* how did this pass DHT block validation!? */
684 process_pseu_result (gph, NULL);
689 ntohs (block->purpose.size) +
690 sizeof (struct GNUNET_CRYPTO_EccPublicKey) +
691 sizeof (struct GNUNET_CRYPTO_EccSignature))
693 /* how did this pass DHT block validation!? */
695 process_pseu_result (gph, NULL);
699 GNUNET_NAMESTORE_block_decrypt (block,
702 &process_auth_records,
705 /* other peer encrypted invalid block, complain */
707 process_pseu_result (gph, NULL);
714 * Callback called by namestore for a zone to name result. We're
715 * trying to see if a short name for a given zone already exists.
717 * @param cls the closure
718 * @param zone_key the zone we queried
719 * @param name the name found or NULL
720 * @param rd_len number of records for the name
721 * @param rd the record data (PKEY) for the name
724 process_zone_to_name_discover (void *cls,
725 const struct GNUNET_CRYPTO_EccPrivateKey *zone_key,
728 const struct GNUNET_NAMESTORE_RecordData *rd)
730 struct GetPseuAuthorityHandle* gph = cls;
731 struct GNUNET_HashCode lookup_key;
733 gph->namestore_task = NULL;
736 /* we found a match in our own zone */
737 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
738 "Shortening aborted, name `%s' already reserved for the zone\n",
740 free_get_pseu_authority_handle (gph);
743 /* record does not yet exist, go into DHT to find PSEU record */
744 GNUNET_NAMESTORE_query_from_public_key (&gph->target_zone,
747 gph->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
748 &handle_auth_discovery_timeout,
750 gph->get_handle = GNUNET_DHT_get_start (dht_handle,
751 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
753 DHT_GNS_REPLICATION_LEVEL,
754 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
756 &process_auth_discovery_dht_result,
762 * Start shortening algorithm, try to allocate a nice short
763 * canonical name for @a pub in @a shorten_zone, using
764 * @a original_label as one possible suggestion.
766 * @param original_label original label for the zone
767 * @param pub public key of the zone to shorten
768 * @param shorten_zone private key of the target zone for the new record
771 start_shorten (const char *original_label,
772 const struct GNUNET_CRYPTO_EccPublicKey *pub,
773 const struct GNUNET_CRYPTO_EccPrivateKey *shorten_zone)
775 struct GetPseuAuthorityHandle *gph;
777 if (strlen (original_label) > GNUNET_DNSPARSER_MAX_LABEL_LENGTH)
782 gph = GNUNET_new (struct GetPseuAuthorityHandle);
783 gph->shorten_zone_key = *shorten_zone;
784 gph->target_zone = *pub;
785 strcpy (gph->label, original_label);
786 GNUNET_CONTAINER_DLL_insert (gph_head, gph_tail, gph);
787 /* first, check if we *already* have a record for this zone */
788 gph->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
791 &process_zone_to_name_discover,
796 /* ************************** Resolution **************************** */
800 * Helper function to free resolver handle
802 * @param rh the handle to free
805 free_resolver_handle (struct ResolverHandle* rh)
807 struct AuthorityChain *ac;
808 struct AuthorityChain *ac_next;
813 ac_next = rh->authority_chain_head;
814 while (NULL != (ac = ac_next))
820 if (NULL != rh->get_handle)
821 GNUNET_DHT_get_stop (rh->get_handle);
822 if (NULL != rh->dns_raw_packet)
823 GNUNET_free (rh->dns_raw_packet);
824 if (NULL != rh->namestore_task)
826 GNUNET_NAMESTORE_cancel (rh->namestore_task);
827 rh->namestore_task = NULL;
829 if (GNUNET_SCHEDULER_NO_TASK != rh->dns_read_task)
830 GNUNET_SCHEDULER_cancel (rh->dns_read_task);
831 if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
832 GNUNET_SCHEDULER_cancel (rh->timeout_task);
833 if (NULL != rh->dns_sock)
834 GNUNET_NETWORK_socket_close (rh->dns_sock);
835 if (NULL != rh->dns_resolver_handle)
836 GNUNET_RESOLVER_request_cancel (rh->dns_resolver_handle);
837 if (NULL != rh->rd.data)
838 GNUNET_free ((void*)(rh->rd.data));
839 if (NULL != rh->dht_heap_node)
840 GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
846 * Callback when record data is put into namestore
848 * @param cls the closure
849 * @param success GNUNET_OK on success
850 * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
853 on_namestore_record_put_result (void *cls,
857 struct NamestoreBGTask *nbg = cls;
859 GNUNET_CONTAINER_heap_remove_node (nbg->node);
862 if (GNUNET_NO == success)
864 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
865 "GNS_NS: records already in namestore\n");
868 else if (GNUNET_YES == success)
870 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
871 "GNS_NS: records successfully put in namestore\n");
875 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
876 "GNS_NS: Error putting records into namestore: %s\n", emsg);
881 * Function called when we get a result from the dht
882 * for our record query
884 * @param cls the request handle
885 * @param exp lifetime
886 * @param key the key the record was stored under
887 * @param get_path get path
888 * @param get_path_length get path length
889 * @param put_path put path
890 * @param put_path_length put path length
891 * @param type the block type
892 * @param size the size of the record
893 * @param data the record data
896 process_record_result_dht (void* cls,
897 struct GNUNET_TIME_Absolute exp,
898 const struct GNUNET_HashCode * key,
899 const struct GNUNET_PeerIdentity *get_path,
900 unsigned int get_path_length,
901 const struct GNUNET_PeerIdentity *put_path,
902 unsigned int put_path_length,
903 enum GNUNET_BLOCK_Type type,
904 size_t size, const void *data)
906 struct ResolverHandle *rh = cls;
907 struct RecordLookupHandle *rlh = rh->proc_cls;
908 const struct GNSNameRecordBlock *nrb = data;
909 uint32_t num_records;
915 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
916 "GNS_PHASE_REC-%llu: got dht result (size=%d)\n", rh->id, size);
917 /* stop lookup and timeout task */
918 GNUNET_DHT_get_stop (rh->get_handle);
919 rh->get_handle = NULL;
920 if (rh->dht_heap_node != NULL)
922 GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
923 rh->dht_heap_node = NULL;
925 if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
927 GNUNET_SCHEDULER_cancel (rh->timeout_task);
928 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
930 rh->get_handle = NULL;
931 name = (const char*) &nrb[1];
932 num_records = ntohl (nrb->rd_count);
934 struct GNUNET_NAMESTORE_RecordData rd[num_records];
935 struct NamestoreBGTask *ns_heap_root;
936 struct NamestoreBGTask *namestore_bg_task;
938 rd_data = &name[strlen (name) + 1];
939 rd_size = size - strlen (name) - 1 - sizeof (struct GNSNameRecordBlock);
941 GNUNET_NAMESTORE_records_deserialize (rd_size,
946 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
947 "GNS_PHASE_REC-%llu: Error deserializing data!\n", rh->id);
948 rh->proc (rh->proc_cls, rh, 0, NULL);
951 for (i = 0; i < num_records; i++)
953 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
954 "GNS_PHASE_REC-%llu: Got name: %s (wanted %s)\n",
955 rh->id, name, rh->name);
956 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
957 "GNS_PHASE_REC-%llu: Got type: %d (wanted %d)\n",
958 rh->id, rd[i].record_type, rlh->record_type);
959 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
960 "GNS_PHASE_REC-%llu: Got data length: %d\n",
961 rh->id, rd[i].data_size);
962 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
963 "GNS_PHASE_REC-%llu: Got flag %d\n",
964 rh->id, rd[i].flags);
966 if ((strcmp (name, rh->name) == 0) &&
967 (rd[i].record_type == rlh->record_type))
973 * FIXME check pubkey against existing key in namestore?
974 * https://gnunet.org/bugs/view.php?id=2179
976 if (max_allowed_ns_tasks <=
977 GNUNET_CONTAINER_heap_get_size (ns_task_heap))
979 ns_heap_root = GNUNET_CONTAINER_heap_remove_root (ns_task_heap);
980 GNUNET_NAMESTORE_cancel (ns_heap_root->qe);
982 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
983 "GNS_PHASE_REC-%llu: Replacing oldest background ns task\n",
987 /* Save to namestore */
988 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
989 "GNS_PHASE_REC-%llu: Caching record for %s\n",
991 namestore_bg_task = GNUNET_malloc (sizeof (struct NamestoreBGTask));
992 namestore_bg_task->qe = GNUNET_NAMESTORE_record_put (namestore_handle,
999 &on_namestore_record_put_result, //cont
1002 namestore_bg_task->node = GNUNET_CONTAINER_heap_insert (ns_task_heap,
1004 GNUNET_TIME_absolute_get().abs_value_us);
1005 if (0 < rh->answered)
1006 rh->proc (rh->proc_cls, rh, num_records, rd);
1008 rh->proc (rh->proc_cls, rh, 0, NULL);
1014 * Start DHT lookup for a (name -> query->record_type) record in
1015 * rh->authority's zone
1017 * @param rh the pending gns query context
1020 resolve_record_dht (struct ResolverHandle *rh)
1022 struct RecordLookupHandle *rlh = rh->proc_cls;
1024 struct GNUNET_HashCode lookup_key;
1025 struct ResolverHandle *rh_heap_root;
1027 GNUNET_GNS_get_key_for_record (rh->name, &rh->authority, &lookup_key);
1028 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1029 "GNS_PHASE_REC-%llu: starting dht lookup for %s with key: %s\n",
1030 rh->id, rh->name, GNUNET_h2s (&lookup_key));
1032 rh->dht_heap_node = NULL;
1034 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != rh->timeout.rel_value_us)
1037 * Update timeout if necessary
1039 if (GNUNET_SCHEDULER_NO_TASK == rh->timeout_task)
1041 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1042 "GNS_PHASE_REC-%llu: Adjusting timeout to %s/2\n",
1044 GNUNET_STRINGS_relative_time_to_string (rh->timeout, GNUNET_YES));
1046 * Set timeout for authority lookup phase to 1/2
1048 rh->timeout_task = GNUNET_SCHEDULER_add_delayed (
1049 GNUNET_TIME_relative_divide (rh->timeout, 2),
1050 &handle_lookup_timeout,
1053 rh->timeout_cont = &dht_lookup_timeout;
1054 rh->timeout_cont_cls = rh;
1058 if (max_allowed_background_queries <=
1059 GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
1061 rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
1062 GNUNET_DHT_get_stop (rh_heap_root->get_handle);
1063 rh_heap_root->get_handle = NULL;
1064 rh_heap_root->dht_heap_node = NULL;
1066 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1067 "GNS_PHASE_REC-%llu: Replacing oldest background query for %s\n",
1068 rh->id, rh_heap_root->name);
1069 rh_heap_root->proc (rh_heap_root->proc_cls,
1074 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
1076 GNUNET_TIME_absolute_get ().abs_value_us);
1079 xquery = htonl (rlh->record_type);
1081 GNUNET_assert (rh->get_handle == NULL);
1082 rh->get_handle = GNUNET_DHT_get_start (dht_handle,
1083 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1085 DHT_GNS_REPLICATION_LEVEL,
1086 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
1089 &process_record_result_dht,
1096 * Namestore calls this function if we have record for this name.
1097 * (or with rd_count=0 to indicate no matches)
1099 * @param cls the pending query
1100 * @param key the key of the zone we did the lookup
1101 * @param expiration expiration date of the namestore entry
1102 * @param name the name for which we need an authority
1103 * @param rd_count the number of records with 'name'
1104 * @param rd the record data
1105 * @param signature the signature of the authority for the record data
1108 process_record_result_ns (void* cls,
1109 const struct GNUNET_CRYPTO_EccPublicKey *key,
1110 struct GNUNET_TIME_Absolute expiration,
1111 const char *name, unsigned int rd_count,
1112 const struct GNUNET_NAMESTORE_RecordData *rd,
1113 const struct GNUNET_CRYPTO_EccSignature *signature)
1115 struct ResolverHandle *rh = cls;
1116 struct RecordLookupHandle *rlh = rh->proc_cls;
1117 struct GNUNET_TIME_Relative remaining_time;
1118 struct GNUNET_CRYPTO_ShortHashCode zone;
1119 struct GNUNET_TIME_Absolute et;
1122 rh->namestore_task = NULL;
1123 GNUNET_CRYPTO_short_hash (key,
1124 sizeof (struct GNUNET_CRYPTO_EccPublicKey),
1126 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1130 rh->status |= RSL_RECORD_EXISTS;
1131 if (remaining_time.rel_value_us == 0)
1132 rh->status |= RSL_RECORD_EXPIRED;
1137 * Lookup terminated and no results
1139 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1140 "GNS_PHASE_REC-%llu: Namestore lookup for %s terminated without results\n",
1143 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1144 "GNS_PHASE_REC-%llu: Record %s unknown in namestore\n",
1147 * Our zone and no result? Cannot resolve TT
1149 rh->proc(rh->proc_cls, rh, 0, NULL);
1153 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1154 "GNS_PHASE_REC-%llu: Processing additional result %s from namestore\n",
1156 for (i = 0; i < rd_count;i++)
1158 if (rd[i].record_type != rlh->record_type)
1161 if (ignore_pending_records &&
1162 (rd[i].flags & GNUNET_NAMESTORE_RF_PENDING))
1164 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1165 "GNS_PHASE_REC-%llu: Record %s is awaiting user confirmation. Skipping\n",
1170 //FIXME: eh? do I have to handle this here?
1171 GNUNET_break (0 == (rd[i].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION));
1172 et.abs_value_us = rd[i].expiration_time;
1173 if (0 == (GNUNET_TIME_absolute_get_remaining (et)).rel_value_us)
1175 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1176 "GNS_PHASE_REC-%llu: This record is expired. Skipping\n",
1186 if (0 == rh->answered)
1188 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1189 "GNS_PHASE_REC-%llu: No answers found. This is odd!\n", rh->id);
1190 rh->proc(rh->proc_cls, rh, 0, NULL);
1194 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1195 "GNS_PHASE_REC-%llu: Found %d answer(s) to query in %d records!\n",
1196 rh->id, rh->answered, rd_count);
1197 rh->proc(rh->proc_cls, rh, rd_count, rd);
1203 * VPN redirect result callback
1205 * @param cls the resolver handle
1206 * @param af the requested address family
1207 * @param address in_addr(6) respectively
1210 process_record_result_vpn (void* cls, int af, const void *address)
1212 struct ResolverHandle *rh = cls;
1213 struct RecordLookupHandle *rlh = rh->proc_cls;
1214 struct GNUNET_NAMESTORE_RecordData rd;
1216 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1217 "GNS_PHASE_REC_VPN-%llu: Got answer from VPN to query!\n",
1221 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1222 "GNS_PHASE_REC-%llu: Answer is IPv4!\n",
1224 if (GNUNET_DNSPARSER_TYPE_A != rlh->record_type)
1226 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1227 "GNS_PHASE_REC-%llu: Requested record is not IPv4!\n",
1229 rh->proc (rh->proc_cls, rh, 0, NULL);
1232 rd.record_type = GNUNET_DNSPARSER_TYPE_A;
1233 rd.expiration_time = UINT64_MAX; /* FIXME: should probably pick something shorter... */
1235 rd.data_size = sizeof (struct in_addr);
1237 rh->proc (rh->proc_cls, rh, 1, &rd);
1240 else if (AF_INET6 == af)
1242 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1243 "GNS_PHASE_REC-%llu: Answer is IPv6!\n",
1245 if (GNUNET_DNSPARSER_TYPE_AAAA != rlh->record_type)
1247 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1248 "GNS_PHASE_REC-%llu: Requested record is not IPv6!\n",
1250 rh->proc (rh->proc_cls, rh, 0, NULL);
1253 rd.record_type = GNUNET_DNSPARSER_TYPE_AAAA;
1254 rd.expiration_time = UINT64_MAX; /* FIXME: should probably pick something shorter... */
1256 rd.data_size = sizeof (struct in6_addr);
1258 rh->proc (rh->proc_cls, rh, 1, &rd);
1262 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1263 "GNS_PHASE_REC-%llu: Got garbage from VPN!\n",
1265 rh->proc (rh->proc_cls, rh, 0, NULL);
1271 * Process VPN lookup result for record
1273 * @param cls the record lookup handle
1274 * @param rh resolver handle
1275 * @param rd_count number of results (1)
1276 * @param rd record data containing the result
1279 handle_record_vpn (void* cls, struct ResolverHandle *rh,
1280 unsigned int rd_count,
1281 const struct GNUNET_NAMESTORE_RecordData *rd)
1283 struct RecordLookupHandle* rlh = cls;
1287 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1288 "GNS_PHASE_REC_VPN-%llu: VPN returned no records. (status: %d)!\n",
1291 /* give up, cannot resolve */
1292 finish_lookup(rh, rlh, 0, NULL);
1296 /* results found yay */
1297 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1298 "GNS_PHASE_REC_VPN-%llu: Record resolved from VPN!\n",
1301 finish_lookup(rh, rlh, rd_count, rd);
1306 * The final phase of resoution.
1307 * We found a NS RR and want to resolve via DNS
1309 * @param rh the pending lookup handle
1310 * @param rd_count length of record data
1311 * @param rd record data containing VPN RR
1314 resolve_record_dns (struct ResolverHandle *rh,
1315 unsigned int rd_count,
1316 const struct GNUNET_NAMESTORE_RecordData *rd)
1318 struct RecordLookupHandle *rlh = rh->proc_cls;
1319 struct GNUNET_DNSPARSER_Query query;
1320 struct GNUNET_DNSPARSER_Packet packet;
1321 struct GNUNET_DNSPARSER_Flags flags;
1322 struct in_addr dnsip;
1323 struct sockaddr_in addr;
1324 struct sockaddr *sa;
1327 memset (&packet, 0, sizeof (struct GNUNET_DNSPARSER_Packet));
1328 memset (rh->dns_name, 0, sizeof (rh->dns_name));
1330 /* We cancel here as to not include the ns lookup in the timeout */
1331 if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
1333 GNUNET_SCHEDULER_cancel(rh->timeout_task);
1334 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1336 /* Start shortening */
1337 if ((NULL != rh->priv_key) &&
1338 (GNUNET_YES == is_canonical (rh->name)))
1340 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1341 "GNS_PHASE_REC_DNS-%llu: Trying to shorten authority chain\n",
1343 start_shorten (rh->authority_chain_head,
1347 for (i = 0; i < rd_count; i++)
1349 /* Synthesize dns name */
1350 if (GNUNET_DNSPARSER_TYPE_NS == rd[i].record_type)
1352 strcpy (rh->dns_zone, (char*)rd[i].data);
1353 if (0 == strcmp (rh->name, ""))
1354 strcpy (rh->dns_name, (char*)rd[i].data);
1356 sprintf (rh->dns_name, "%s.%s", rh->name, (char*)rd[i].data);
1359 if (GNUNET_DNSPARSER_TYPE_A == rd[i].record_type)
1360 /* need to use memcpy as .data may be unaligned */
1361 memcpy (&dnsip, rd[i].data, sizeof (dnsip));
1364 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1365 "GNS_PHASE_REC_DNS-%llu: Looking up `%s' from `%s'\n",
1369 rh->dns_sock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0);
1370 if (NULL == rh->dns_sock)
1372 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1373 "GNS_PHASE_REC_DNS-%llu: Error creating udp socket for dns!\n",
1375 finish_lookup (rh, rlh, 0, NULL);
1379 memset (&addr, 0, sizeof (struct sockaddr_in));
1380 sa = (struct sockaddr *) &addr;
1381 sa->sa_family = AF_INET;
1382 if (GNUNET_OK != GNUNET_NETWORK_socket_bind (rh->dns_sock,
1384 sizeof (struct sockaddr_in),
1387 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1388 "GNS_PHASE_REC_DNS-%llu: Error binding UDP socket for DNS lookup!\n",
1390 finish_lookup (rh, rlh, 0, NULL);
1393 query.name = rh->dns_name;
1394 query.type = rlh->record_type;
1395 query.class = GNUNET_DNSPARSER_CLASS_INTERNET;
1396 memset (&flags, 0, sizeof (flags));
1397 flags.recursion_desired = 1;
1398 flags.checking_disabled = 1;
1399 packet.queries = &query;
1400 packet.answers = NULL;
1401 packet.authority_records = NULL;
1402 packet.num_queries = 1;
1403 packet.num_answers = 0;
1404 packet.num_authority_records = 0;
1405 packet.num_additional_records = 0;
1406 packet.flags = flags;
1408 if (GNUNET_OK != GNUNET_DNSPARSER_pack (&packet,
1410 &rh->dns_raw_packet,
1411 &rh->dns_raw_packet_size))
1413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1414 "GNS_PHASE_REC_DNS-%llu: Creating raw dns packet!\n",
1416 GNUNET_NETWORK_socket_close (rh->dns_sock);
1417 finish_lookup (rh, rlh, 0, NULL);
1421 rh->dns_addr.sin_family = AF_INET;
1422 rh->dns_addr.sin_port = htons (53); //domain
1423 rh->dns_addr.sin_addr = dnsip;
1424 #if HAVE_SOCKADDR_IN_SIN_LEN
1425 rh->dns_addr.sin_len = (u_char) sizeof (struct sockaddr_in);
1427 send_dns_packet (rh);
1432 * The final phase of resoution.
1433 * We found a VPN RR and want to request an IPv4/6 address
1435 * @param rh the pending lookup handle
1436 * @param rd_count length of record data
1437 * @param rd record data containing VPN RR
1440 resolve_record_vpn (struct ResolverHandle *rh,
1441 unsigned int rd_count,
1442 const struct GNUNET_NAMESTORE_RecordData *rd)
1444 struct RecordLookupHandle *rlh = rh->proc_cls;
1445 struct GNUNET_HashCode serv_desc;
1446 struct vpn_data* vpn;
1449 /* We cancel here as to not include the ns lookup in the timeout */
1450 if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
1452 GNUNET_SCHEDULER_cancel(rh->timeout_task);
1453 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1455 /* Start shortening */
1456 if ((NULL != rh->priv_key) &&
1457 (GNUNET_YES == is_canonical (rh->name)))
1459 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1460 "GNS_PHASE_REC_VPN-%llu: Trying to shorten authority chain\n",
1462 start_shorten (rh->authority_chain_head,
1466 vpn = (struct vpn_data*)rd->data;
1467 GNUNET_CRYPTO_hash ((char*)&vpn[1],
1468 strlen ((char*)&vpn[1]) + 1,
1470 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1471 "GNS_PHASE_REC_VPN-%llu: proto %hu peer %s!\n",
1474 GNUNET_h2s (&vpn->peer));
1476 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1477 "GNS_PHASE_REC_VPN-%llu: service %s -> %s!\n",
1480 GNUNET_h2s (&serv_desc));
1481 rh->proc = &handle_record_vpn;
1482 if (GNUNET_DNSPARSER_TYPE_A == rlh->record_type)
1487 if (NULL == vpn_handle)
1489 vpn_handle = GNUNET_VPN_connect (cfg);
1490 if (NULL == vpn_handle)
1492 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1493 "GNS_PHASE_INIT: Error connecting to VPN!\n");
1494 finish_lookup (rh, rh->proc_cls, 0, NULL);
1499 rh->vpn_handle = GNUNET_VPN_redirect_to_peer (vpn_handle,
1500 af, ntohs (vpn->proto),
1501 (struct GNUNET_PeerIdentity *)&vpn->peer,
1504 GNUNET_TIME_UNIT_FOREVER_ABS, //FIXME
1505 &process_record_result_vpn,
1508 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1509 "Error connecting to VPN (not available on W32 yet)\n");
1510 finish_lookup (rh, rh->proc_cls, 0, NULL);
1516 * The final phase of resolution.
1517 * rh->name is a name that is canonical and we do not have a delegation.
1518 * Query namestore for this record
1520 * @param rh the pending lookup handle
1523 resolve_record_ns(struct ResolverHandle *rh)
1525 struct RecordLookupHandle *rlh = rh->proc_cls;
1527 /* We cancel here as to not include the ns lookup in the timeout */
1528 if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
1530 GNUNET_SCHEDULER_cancel(rh->timeout_task);
1531 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1533 /* Start shortening */
1534 if ((NULL != rh->priv_key) &&
1535 (GNUNET_YES == is_canonical (rh->name)))
1537 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1538 "GNS_PHASE_REC-%llu: Trying to shorten authority chain\n",
1540 start_shorten (rh->authority_chain_head,
1545 * Try to resolve this record in our namestore.
1546 * The name to resolve is now in rh->authority_name
1547 * since we tried to resolve it to an authority
1550 rh->namestore_task = GNUNET_NAMESTORE_lookup_record(namestore_handle,
1554 &process_record_result_ns,
1560 * Handle timeout for DHT requests
1562 * @param cls the request handle as closure
1563 * @param tc the task context
1566 dht_authority_lookup_timeout (void *cls,
1567 const struct GNUNET_SCHEDULER_TaskContext *tc)
1569 struct ResolverHandle *rh = cls;
1570 struct RecordLookupHandle *rlh = rh->proc_cls;
1571 char new_name[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
1573 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1574 "GNS_PHASE_DELEGATE_DHT-%llu: dht lookup for query %s (%s) timed out.\n",
1575 rh->id, rh->authority_name,
1576 GNUNET_STRINGS_relative_time_to_string (rh->timeout,
1579 rh->status |= RSL_TIMED_OUT;
1580 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1581 if (NULL != rh->get_handle)
1583 GNUNET_DHT_get_stop (rh->get_handle);
1584 rh->get_handle = NULL;
1586 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1588 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1589 "GNS_PHASE_DELEGATE_DHT-%llu: Got shutdown\n",
1591 rh->proc (rh->proc_cls, rh, 0, NULL);
1594 if (0 == strcmp (rh->name, ""))
1597 * promote authority back to name and try to resolve record
1599 strcpy (rh->name, rh->authority_name);
1600 rh->proc (rh->proc_cls, rh, 0, NULL);
1605 * Start resolution in bg
1607 GNUNET_snprintf (new_name, GNUNET_DNSPARSER_MAX_NAME_LENGTH,
1609 rh->name, rh->authority_name, GNUNET_GNS_TLD);
1610 strcpy (rh->name, new_name);
1611 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1612 "GNS_PHASE_DELEGATE_DHT-%llu: Starting background query for %s type %d\n",
1615 gns_resolver_lookup_record (rh->authority,
1616 rh->private_local_zone,
1620 GNUNET_TIME_UNIT_FOREVER_REL,
1622 &background_lookup_result_processor,
1624 rh->proc (rh->proc_cls, rh, 0, NULL);
1629 * This is a callback function that checks for key revocation
1631 * @param cls the pending query
1632 * @param key the key of the zone we did the lookup
1633 * @param expiration expiration date of the record data set in the namestore
1634 * @param name the name for which we need an authority
1635 * @param rd_count the number of records with 'name'
1636 * @param rd the record data
1637 * @param signature the signature of the authority for the record data
1640 process_pkey_revocation_result_ns (void *cls,
1641 const struct GNUNET_CRYPTO_EccPublicKey *key,
1642 struct GNUNET_TIME_Absolute expiration,
1644 unsigned int rd_count,
1645 const struct GNUNET_NAMESTORE_RecordData *rd,
1646 const struct GNUNET_CRYPTO_EccSignature *signature)
1648 struct ResolverHandle *rh = cls;
1649 struct GNUNET_TIME_Relative remaining_time;
1652 rh->namestore_task = NULL;
1653 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1655 for (i = 0; i < rd_count; i++)
1657 if (GNUNET_NAMESTORE_TYPE_REV == rd[i].record_type)
1659 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1660 "GNS_PHASE_DELEGATE_REV-%llu: Zone has been revoked.\n",
1662 rh->status |= RSL_PKEY_REVOKED;
1663 rh->proc (rh->proc_cls, rh, 0, NULL);
1668 if ((NULL == name) ||
1669 (0 == remaining_time.rel_value_us))
1671 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1672 "GNS_PHASE_DELEGATE_REV-%llu: + Records don't exist or are expired.\n",
1675 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != rh->timeout.rel_value_us)
1677 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1678 "GNS_PHASE_DELEGATE_REV-%llu: Starting background lookup for %s type %d\n",
1679 rh->id, "+.gads", GNUNET_NAMESTORE_TYPE_REV);
1681 gns_resolver_lookup_record(rh->authority,
1682 rh->private_local_zone,
1683 GNUNET_NAMESTORE_TYPE_REV,
1686 GNUNET_TIME_UNIT_FOREVER_REL,
1688 &background_lookup_result_processor,
1692 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1693 "GNS_PHASE_DELEGATE_REV-%llu: Revocation check passed\n",
1696 * We are done with PKEY resolution if name is empty
1697 * else resolve again with new authority
1699 if (strcmp (rh->name, "") == 0)
1700 rh->proc (rh->proc_cls, rh, rh->rd_count, &rh->rd);
1702 resolve_delegation_ns (rh);
1707 * Callback when record data is put into namestore
1709 * @param cls the closure
1710 * @param success GNUNET_OK on success
1711 * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
1714 on_namestore_delegation_put_result(void *cls,
1718 struct NamestoreBGTask *nbg = cls;
1720 GNUNET_CONTAINER_heap_remove_node (nbg->node);
1723 if (GNUNET_NO == success)
1725 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1726 "GNS_NS: records already in namestore\n");
1729 else if (GNUNET_YES == success)
1731 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1732 "GNS_NS: records successfully put in namestore\n");
1736 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1737 "GNS_NS: Error putting records into namestore: %s\n", emsg);
1742 * Function called when we get a result from the dht
1743 * for our query. Recursively tries to resolve authorities
1746 * @param cls the request handle
1747 * @param exp lifetime
1748 * @param key the key the record was stored under
1749 * @param get_path get path
1750 * @param get_path_length get path length
1751 * @param put_path put path
1752 * @param put_path_length put path length
1753 * @param type the block type
1754 * @param size the size of the record
1755 * @param data the record data
1758 process_delegation_result_dht (void* cls,
1759 struct GNUNET_TIME_Absolute exp,
1760 const struct GNUNET_HashCode * key,
1761 const struct GNUNET_PeerIdentity *get_path,
1762 unsigned int get_path_length,
1763 const struct GNUNET_PeerIdentity *put_path,
1764 unsigned int put_path_length,
1765 enum GNUNET_BLOCK_Type type,
1766 size_t size, const void *data)
1768 struct ResolverHandle *rh = cls;
1769 const struct GNSNameRecordBlock *nrb = data;
1770 const char* rd_data;
1771 uint32_t num_records;
1775 struct GNUNET_CRYPTO_ShortHashCode zone;
1777 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1778 "GNS_PHASE_DELEGATE_DHT-%llu: Got DHT result\n",
1782 /* stop dht lookup and timeout task */
1783 GNUNET_DHT_get_stop (rh->get_handle);
1784 rh->get_handle = NULL;
1785 if (rh->dht_heap_node != NULL)
1787 GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
1788 rh->dht_heap_node = NULL;
1791 num_records = ntohl(nrb->rd_count);
1792 name = (const char*) &nrb[1];
1794 struct GNUNET_NAMESTORE_RecordData rd[num_records];
1795 struct NamestoreBGTask *ns_heap_root;
1796 struct NamestoreBGTask *namestore_bg_task;
1798 rd_data = name + strlen(name) + 1;
1799 rd_size = size - strlen(name) - 1 - sizeof (struct GNSNameRecordBlock);
1800 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
1805 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1806 "GNS_PHASE_DELEGATE_DHT-%llu: Error deserializing data!\n",
1811 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1812 "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n",
1813 rh->id, name, rh->authority_name);
1814 for (i=0; i<num_records; i++)
1816 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1817 "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n",
1818 rh->id, name, rh->authority_name);
1819 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1820 "GNS_PHASE_DELEGATE_DHT-%llu: Got type: %d (wanted %d)\n",
1821 rh->id, rd[i].record_type, GNUNET_NAMESTORE_TYPE_PKEY);
1822 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1823 "GNS_PHASE_DELEGATE_DHT-%llu: Got data length: %d\n",
1824 rh->id, rd[i].data_size);
1825 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1826 "GNS_PHASE_DELEGATE_DHT-%llu: Got flag %d\n",
1827 rh->id, rd[i].flags);
1829 if ((GNUNET_NAMESTORE_TYPE_VPN == rd[i].record_type) ||
1830 (GNUNET_DNSPARSER_TYPE_NS == rd[i].record_type) ||
1831 (GNUNET_DNSPARSER_TYPE_CNAME == rd[i].record_type))
1834 * This is a VPN,NS,CNAME entry. Let namestore handle this after caching
1836 if (0 == strcmp(rh->name, ""))
1837 strcpy(rh->name, rh->authority_name);
1839 GNUNET_snprintf(rh->name, GNUNET_DNSPARSER_MAX_NAME_LENGTH, "%s.%s",
1840 rh->name, rh->authority_name); //FIXME ret
1845 if ((0 == strcmp(name, rh->authority_name)) &&
1846 (GNUNET_NAMESTORE_TYPE_PKEY == rd[i].record_type))
1848 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1849 "GNS_PHASE_DELEGATE_DHT-%llu: Authority found in DHT\n",
1852 memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1853 struct AuthorityChain *auth =
1854 GNUNET_malloc(sizeof(struct AuthorityChain));
1855 auth->zone = rh->authority;
1856 memset(auth->name, 0, strlen(rh->authority_name)+1);
1857 strcpy(auth->name, rh->authority_name);
1858 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1859 rh->authority_chain_tail,
1862 if (NULL != rh->rd.data)
1863 GNUNET_free ((void*)rh->rd.data);
1865 memcpy (&rh->rd, &rd[i], sizeof (struct GNUNET_NAMESTORE_RecordData));
1866 rh->rd.data = GNUNET_malloc (rd[i].data_size);
1867 memcpy ((void*)(rh->rd.data), rd[i].data, rd[i].data_size);
1870 /** try to import pkey if private key available */
1871 //if (rh->priv_key && is_canonical (rh->name))
1872 // process_discovered_authority(name, auth->zone,
1873 // rh->authority_chain_tail->zone,
1878 GNUNET_GNS_get_zone_from_key (name, key, &zone);
1881 /* Save to namestore
1882 if (0 != GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1885 if (max_allowed_ns_tasks <=
1886 GNUNET_CONTAINER_heap_get_size (ns_task_heap))
1888 ns_heap_root = GNUNET_CONTAINER_heap_remove_root (ns_task_heap);
1889 GNUNET_NAMESTORE_cancel (ns_heap_root->qe);
1891 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1892 "GNS_PHASE_DELEGATE_DHT-%llu: Replacing oldest background ns task\n",
1895 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1896 "GNS_PHASE_DELEGATE_DHT-%llu: Caching record for %s\n",
1898 namestore_bg_task = GNUNET_malloc (sizeof (struct NamestoreBGTask));
1900 namestore_bg_task->node = GNUNET_CONTAINER_heap_insert (ns_task_heap,
1902 GNUNET_TIME_absolute_get().abs_value_us);
1903 namestore_bg_task->qe = GNUNET_NAMESTORE_record_put (namestore_handle,
1910 &on_namestore_delegation_put_result, //cont
1911 namestore_bg_task); //cls
1915 if (0 != rh->answered)
1920 * FIXME in this case. should we ask namestore again?
1922 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1923 "GNS_PHASE_DELEGATE_DHT-%llu: Answer from DHT for %s. Yet to resolve: %s\n",
1924 rh->id, rh->authority_name, rh->name);
1926 if (0 == strcmp(rh->name, ""))
1928 /* Start shortening */
1929 if ((NULL != rh->priv_key) &&
1930 (GNUNET_YES == is_canonical (rh->name)))
1932 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1933 "GNS_PHASE_DELEGATE_DHT-%llu: Trying to shorten authority chain\n",
1935 start_shorten (rh->authority_chain_head,
1940 rh->proc = &handle_delegation_ns;
1943 /* Check for key revocation and delegate */
1944 rh->namestore_task = GNUNET_NAMESTORE_lookup_record (namestore_handle,
1946 GNUNET_GNS_MASTERZONE_STR,
1947 GNUNET_NAMESTORE_TYPE_REV,
1948 &process_pkey_revocation_result_ns,
1955 * No pkey but name exists
1958 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1959 "GNS_PHASE_DELEGATE_DHT-%llu: Adding %s back to %s\n",
1960 rh->id, rh->authority_name, rh->name);
1961 if (0 == strcmp(rh->name, ""))
1962 strcpy(rh->name, rh->authority_name);
1964 GNUNET_snprintf(rh->name, GNUNET_DNSPARSER_MAX_NAME_LENGTH, "%s.%s",
1965 rh->name, rh->authority_name); //FIXME ret
1967 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1968 "GNS_PHASE_DELEGATE_DHT-%llu: %s restored\n", rh->id, rh->name);
1969 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1970 "GNS_PHASE_DELEGATE_DHT-%llu: DHT authority lookup found no match!\n",
1972 rh->proc(rh->proc_cls, rh, 0, NULL);
1975 //FIXME maybe define somewhere else?
1976 #define MAX_SOA_LENGTH sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)\
1977 +(GNUNET_DNSPARSER_MAX_NAME_LENGTH*2)
1978 #define MAX_MX_LENGTH sizeof(uint16_t)+GNUNET_DNSPARSER_MAX_NAME_LENGTH
1979 #define MAX_SRV_LENGTH (sizeof(uint16_t)*3)+GNUNET_DNSPARSER_MAX_NAME_LENGTH
1983 * Exands a name ending in .+ with the zone of origin.
1984 * FIXME: funky api: 'dest' must be large enough to hold
1985 * the result; this is a bit yucky...
1987 * @param dest destination buffer
1988 * @param src the .+ name
1989 * @param repl the string to replace the + with
1992 expand_plus (char* dest,
1997 size_t s_len = strlen (src) + 1;
1999 //Eh? I guess this is at least strlen ('x.+') == 3 FIXME
2002 /* no postprocessing */
2003 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2004 "GNS_POSTPROCESS: %s too short\n", src);
2005 memcpy (dest, src, s_len);
2008 if (0 == strcmp (src + s_len - 3, ".+"))
2010 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2011 "GNS_POSTPROCESS: Expanding .+ in %s\n",
2013 memset (dest, 0, s_len + strlen (repl) + strlen(GNUNET_GNS_TLD));
2015 pos = dest + s_len - 2;
2017 pos += strlen (repl);
2018 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2019 "GNS_POSTPROCESS: Expanded to %s\n",
2024 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2025 "GNS_POSTPROCESS: No postprocessing for %s\n", src);
2026 memcpy (dest, src, s_len);
2035 finish_lookup (struct ResolverHandle *rh,
2036 struct RecordLookupHandle* rlh,
2037 unsigned int rd_count,
2038 const struct GNUNET_NAMESTORE_RecordData *rd)
2041 char new_rr_data[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
2042 char new_mx_data[MAX_MX_LENGTH];
2043 char new_soa_data[MAX_SOA_LENGTH];
2044 char new_srv_data[MAX_SRV_LENGTH];
2045 struct srv_data *old_srv;
2046 struct srv_data *new_srv;
2047 struct soa_data *old_soa;
2048 struct soa_data *new_soa;
2049 struct GNUNET_NAMESTORE_RecordData p_rd[rd_count];
2052 unsigned int offset;
2054 if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
2056 GNUNET_SCHEDULER_cancel(rh->timeout_task);
2057 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2060 GNUNET_CONTAINER_DLL_remove (rlh_head, rlh_tail, rh);
2063 memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData));
2065 for (i = 0; i < rd_count; i++)
2068 if ((GNUNET_DNSPARSER_TYPE_NS != rd[i].record_type) &&
2069 (GNUNET_DNSPARSER_TYPE_PTR != rd[i].record_type) &&
2070 (GNUNET_DNSPARSER_TYPE_CNAME != rd[i].record_type) &&
2071 (GNUNET_DNSPARSER_TYPE_MX != rd[i].record_type) &&
2072 (GNUNET_DNSPARSER_TYPE_SOA != rd[i].record_type) &&
2073 (GNUNET_DNSPARSER_TYPE_SRV != rd[i].record_type))
2075 p_rd[i].data = rd[i].data;
2080 * for all those records we 'should'
2081 * also try to resolve the A/AAAA records (RFC1035)
2082 * This is a feature and not important
2085 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2086 "GNS_POSTPROCESS: Postprocessing\n");
2087 if (0 == strcmp(rh->name, GNUNET_GNS_MASTERZONE_STR))
2088 repl_string = rlh->name;
2090 repl_string = rlh->name+strlen(rh->name)+1;
2093 if (GNUNET_DNSPARSER_TYPE_MX == rd[i].record_type)
2095 memcpy (new_mx_data, (char*)rd[i].data, sizeof(uint16_t));
2096 offset = sizeof (uint16_t);
2097 pos = new_mx_data + offset;
2098 // FIXME: how do we know that 'pos' has enough space for the new name?
2099 expand_plus (pos, (char*)rd[i].data+sizeof(uint16_t),
2101 offset += strlen(new_mx_data+sizeof(uint16_t)) + 1;
2102 p_rd[i].data = new_mx_data;
2103 p_rd[i].data_size = offset;
2105 else if (GNUNET_DNSPARSER_TYPE_SRV == rd[i].record_type)
2108 * Prio, weight and port
2110 new_srv = (struct srv_data*)new_srv_data;
2111 old_srv = (struct srv_data*)rd[i].data;
2112 new_srv->prio = old_srv->prio;
2113 new_srv->weight = old_srv->weight;
2114 new_srv->port = old_srv->port;
2115 // FIXME: how do we know that '&new_srv[1]' has enough space for the new name?
2116 expand_plus((char*)&new_srv[1], (char*)&old_srv[1],
2118 p_rd[i].data = new_srv_data;
2119 p_rd[i].data_size = sizeof (struct srv_data) + strlen ((char*)&new_srv[1]) + 1;
2121 else if (GNUNET_DNSPARSER_TYPE_SOA == rd[i].record_type)
2123 /* expand mname and rname */
2124 old_soa = (struct soa_data*)rd[i].data;
2125 new_soa = (struct soa_data*)new_soa_data;
2126 memcpy (new_soa, old_soa, sizeof (struct soa_data));
2127 // FIXME: how do we know that 'new_soa[1]' has enough space for the new name?
2128 expand_plus((char*)&new_soa[1], (char*)&old_soa[1], repl_string);
2129 offset = strlen ((char*)&new_soa[1]) + 1;
2130 // FIXME: how do we know that 'new_soa[1]' has enough space for the new name?
2131 expand_plus((char*)&new_soa[1] + offset,
2132 (char*)&old_soa[1] + strlen ((char*)&old_soa[1]) + 1,
2134 p_rd[i].data_size = sizeof (struct soa_data)
2136 + strlen ((char*)&new_soa[1] + offset);
2137 p_rd[i].data = new_soa_data;
2142 // FIXME: how do we know that 'rd[i].data' has enough space for the new name?
2143 expand_plus(pos, (char*)rd[i].data, repl_string);
2144 p_rd[i].data_size = strlen(new_rr_data)+1;
2145 p_rd[i].data = new_rr_data;
2150 rlh->proc(rlh->proc_cls, rd_count, p_rd);
2152 free_resolver_handle (rh);
2157 * Process DHT lookup result for record.
2159 * @param cls the closure
2160 * @param rh resolver handle
2161 * @param rd_count number of results
2162 * @param rd record data
2165 handle_record_dht (void* cls, struct ResolverHandle *rh,
2166 unsigned int rd_count,
2167 const struct GNUNET_NAMESTORE_RecordData *rd)
2169 struct RecordLookupHandle* rlh = cls;
2173 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2174 "GNS_PHASE_REC-%llu: No records for %s found in DHT. Aborting\n",
2176 /* give up, cannot resolve */
2177 finish_lookup (rh, rlh, 0, NULL);
2180 /* results found yay */
2181 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2182 "GNS_PHASE_REC-%llu: Record resolved from DHT!", rh->id);
2183 finish_lookup (rh, rlh, rd_count, rd);
2188 * Process namestore lookup result for record.
2190 * @param cls the closure
2191 * @param rh resolver handle
2192 * @param rd_count number of results
2193 * @param rd record data
2196 handle_record_ns (void* cls, struct ResolverHandle *rh,
2197 unsigned int rd_count,
2198 const struct GNUNET_NAMESTORE_RecordData *rd)
2200 struct RecordLookupHandle* rlh = cls;
2201 int check_dht = GNUNET_YES;
2205 /* results found yay */
2206 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2207 "GNS_PHASE_REC-%llu: Record resolved from namestore!\n", rh->id);
2208 finish_lookup (rh, rlh, rd_count, rd);
2212 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2213 "GNS_PHASE_REC-%llu: NS returned no records. (status: %d)!\n",
2217 * There are 5 conditions that have to met for us to consult the DHT:
2218 * 1. The entry in the DHT is RSL_RECORD_EXPIRED OR
2219 * 2. No entry in the NS existed AND
2220 * 3. The zone queried is not the local resolver's zone AND
2221 * 4. The name that was looked up is '+'
2222 * because if it was any other canonical name we either already queried
2223 * the DHT for the authority in the authority lookup phase (and thus
2224 * would already have an entry in the NS for the record)
2225 * 5. We are not in cache only mode
2227 if ((0 != (rh->status & RSL_RECORD_EXPIRED)) &&
2228 (0 == (rh->status & RSL_RECORD_EXISTS)) )
2231 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2232 "GNS_PHASE_REC-%llu: Not expired and exists!\n",
2234 check_dht = GNUNET_NO;
2237 if (0 == GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2238 &rh->private_local_zone))
2241 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2242 "GNS_PHASE_REC-%llu: Our zone!\n",
2244 check_dht = GNUNET_NO;
2247 if ((0 != strcmp (rh->name, GNUNET_GNS_MASTERZONE_STR)) && (GNUNET_YES == is_srv (rh->name)))
2248 check_dht = GNUNET_NO;
2250 if (GNUNET_YES == rh->only_cached)
2251 check_dht = GNUNET_NO;
2253 if (GNUNET_YES == check_dht)
2255 rh->proc = &handle_record_dht;
2256 resolve_record_dht(rh);
2259 /* give up, cannot resolve */
2260 finish_lookup (rh, rlh, 0, NULL);
2265 * Move one level up in the domain hierarchy and return the
2266 * passed top level domain.
2268 * FIXME: funky API: not only 'dest' is updated, so is 'name'!
2270 * @param name the domain
2271 * @param dest the destination where the tld will be put
2274 pop_tld (char* name, char* dest)
2278 if (GNUNET_YES == is_canonical (name))
2280 strcpy (dest, name);
2285 for (len = strlen(name); 0 < len; len--)
2287 if (*(name+len) == '.')
2295 strcpy (dest, (name+len+1));
2300 * DHT resolution for delegation finished. Processing result.
2302 * @param cls the closure
2303 * @param rh resolver handle
2304 * @param rd_count number of results (always 0)
2305 * @param rd record data (always NULL)
2308 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
2309 unsigned int rd_count,
2310 const struct GNUNET_NAMESTORE_RecordData *rd)
2312 struct RecordLookupHandle* rlh = cls;
2314 if (0 == strcmp(rh->name, ""))
2316 if (GNUNET_NAMESTORE_TYPE_PKEY == rlh->record_type)
2318 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2319 "GNS_PHASE_DELEGATE_DHT-%llu: Resolved queried PKEY via DHT.\n",
2321 finish_lookup(rh, rlh, rd_count, rd);
2324 /* We resolved full name for delegation. resolving record */
2325 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2326 "GNS_PHASE_DELEGATE_DHT-%llu: Resolved full name for delegation via DHT.\n",
2328 strcpy(rh->name, "+\0");
2329 rh->proc = &handle_record_ns;
2330 resolve_record_ns(rh);
2335 * we still have some left
2337 if (GNUNET_YES == is_canonical (rh->name))
2339 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2340 "GNS_PHASE_DELEGATE_DHT-%llu: Resolving canonical record %s in ns\n",
2343 rh->proc = &handle_record_ns;
2344 resolve_record_ns(rh);
2347 /* give up, cannot resolve */
2348 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2349 "GNS_PHASE_DELEGATE_DHT-%llu: Cannot fully resolve delegation for %s via DHT!\n",
2351 finish_lookup(rh, rlh, 0, NULL);
2356 * Start DHT lookup for a name -> PKEY (compare NS) record in
2357 * rh->authority's zone
2359 * @param rh the pending gns query
2362 resolve_delegation_dht (struct ResolverHandle *rh)
2365 struct GNUNET_HashCode lookup_key;
2366 struct ResolverHandle *rh_heap_root;
2368 pop_tld (rh->name, rh->authority_name);
2369 GNUNET_GNS_get_key_for_record (rh->authority_name,
2372 rh->dht_heap_node = NULL;
2373 if (rh->timeout.rel_value_us != GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
2375 rh->timeout_cont = &dht_authority_lookup_timeout;
2376 rh->timeout_cont_cls = rh;
2380 if (max_allowed_background_queries <=
2381 GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
2383 /* terminate oldest lookup */
2384 rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
2385 GNUNET_DHT_get_stop (rh_heap_root->get_handle);
2386 rh_heap_root->get_handle = NULL;
2387 rh_heap_root->dht_heap_node = NULL;
2388 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2389 "GNS_PHASE_DELEGATE_DHT-%llu: Replacing oldest background query for %s\n",
2391 rh_heap_root->authority_name);
2392 rh_heap_root->proc (rh_heap_root->proc_cls,
2397 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
2399 GNUNET_TIME_absolute_get().abs_value_us);
2401 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2402 "Beginning DHT lookup for %s in zone %s for request %llu\n",
2404 GNUNET_short_h2s (&rh->authority),
2406 xquery = htonl (GNUNET_NAMESTORE_TYPE_PKEY);
2407 GNUNET_assert (rh->get_handle == NULL);
2408 rh->get_handle = GNUNET_DHT_get_start (dht_handle,
2409 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
2411 DHT_GNS_REPLICATION_LEVEL,
2412 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
2415 &process_delegation_result_dht,
2421 * Namestore resolution for delegation finished. Processing result.
2423 * @param cls the closure
2424 * @param rh resolver handle
2425 * @param rd_count number of results (always 0)
2426 * @param rd record data (always NULL)
2429 handle_delegation_ns (void* cls, struct ResolverHandle *rh,
2430 unsigned int rd_count,
2431 const struct GNUNET_NAMESTORE_RecordData *rd)
2433 struct RecordLookupHandle* rlh = cls;
2437 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2438 "GNS_PHASE_DELEGATE_NS-%llu: Resolution status: %d.\n",
2439 rh->id, rh->status);
2441 if (rh->status & RSL_PKEY_REVOKED)
2443 finish_lookup (rh, rlh, 0, NULL);
2447 if (0 == strcmp(rh->name, ""))
2450 /* We resolved full name for delegation. resolving record */
2451 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2452 "GNS_PHASE_DELEGATE_NS-%llu: Resolved full name for delegation.\n",
2454 if (rh->status & RSL_CNAME_FOUND)
2456 if (GNUNET_DNSPARSER_TYPE_CNAME == rlh->record_type)
2458 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2459 "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried CNAME in NS.\n",
2461 strcpy (rh->name, rh->authority_name);
2462 finish_lookup (rh, rlh, rd_count, rd);
2467 if (GNUNET_YES == is_tld ((char*)rd->data, GNUNET_GNS_TLD_PLUS))
2469 s_len = strlen (rd->data) - 2;
2470 memcpy (rh->name, rd->data, s_len);
2471 rh->name[s_len] = '\0';
2472 resolve_delegation_ns (rh);
2475 else if (GNUNET_YES == is_tld ((char*)rd->data, GNUNET_GNS_TLD_ZKEY))
2477 gns_resolver_lookup_record (rh->authority,
2478 rh->private_local_zone,
2487 GNUNET_CONTAINER_DLL_remove (rlh_head, rlh_tail, rh);
2488 free_resolver_handle (rh);
2494 strcpy (rh->dns_name, (char*)rd->data);
2495 resolve_dns_name (rh);
2500 else if (rh->status & RSL_DELEGATE_VPN)
2502 if (GNUNET_NAMESTORE_TYPE_VPN == rlh->record_type)
2504 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2505 "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried VPNRR in NS.\n",
2507 finish_lookup(rh, rlh, rd_count, rd);
2510 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2511 "GNS_PHASE_DELEGATE_NS-%llu: VPN delegation starting.\n",
2513 GNUNET_assert (NULL != rd);
2514 rh->proc = &handle_record_vpn;
2515 resolve_record_vpn (rh, rd_count, rd);
2518 else if (rh->status & RSL_DELEGATE_NS)
2520 if (GNUNET_DNSPARSER_TYPE_NS == rlh->record_type)
2522 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2523 "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried NSRR in NS.\n",
2525 finish_lookup (rh, rlh, rd_count, rd);
2528 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2529 "GNS_PHASE_DELEGATE_NS-%llu: NS delegation starting.\n",
2531 GNUNET_assert (NULL != rd);
2532 rh->proc = &handle_record_ns;
2533 resolve_record_dns (rh, rd_count, rd);
2536 else if (rh->status & RSL_DELEGATE_PKEY)
2538 if (rh->status & RSL_PKEY_REVOKED)
2540 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2541 "GNS_PHASE_DELEGATE_NS-%llu: Resolved PKEY is revoked.\n",
2543 finish_lookup (rh, rlh, 0, NULL);
2546 else if (GNUNET_NAMESTORE_TYPE_PKEY == rlh->record_type)
2548 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2549 "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried PKEY in NS.\n",
2551 finish_lookup(rh, rlh, rd_count, rd);
2555 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2556 "GNS_PHASE_DELEGATE_NS-%llu: Resolving record +\n",
2558 strcpy(rh->name, "+\0");
2559 rh->proc = &handle_record_ns;
2560 resolve_record_ns(rh);
2564 if (rh->status & RSL_DELEGATE_NS)
2566 if (GNUNET_DNSPARSER_TYPE_NS == rlh->record_type)
2568 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2569 "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried NSRR in NS.\n",
2571 finish_lookup(rh, rlh, rd_count, rd);
2575 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2576 "GNS_PHASE_DELEGATE_NS-%llu: NS delegation starting.\n",
2578 GNUNET_assert (NULL != rd);
2579 rh->proc = &handle_record_ns;
2580 resolve_record_dns (rh, rd_count, rd);
2585 * we still have some left
2586 * check if authority in ns is fresh
2588 * or we are authority
2591 check_dht = GNUNET_YES;
2592 if ((rh->status & RSL_RECORD_EXISTS) &&
2593 !(rh->status & RSL_RECORD_EXPIRED))
2594 check_dht = GNUNET_NO;
2596 if (0 == GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2597 &rh->private_local_zone))
2598 check_dht = GNUNET_NO;
2600 if (GNUNET_YES == rh->only_cached)
2601 check_dht = GNUNET_NO;
2603 if (GNUNET_YES == check_dht)
2606 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2607 "GNS_PHASE_DELEGATE_NS-%llu: Trying to resolve delegation for %s via DHT\n",
2609 rh->proc = &handle_delegation_dht;
2610 resolve_delegation_dht(rh);
2614 if (GNUNET_NO == is_canonical (rh->name))
2616 /* give up, cannot resolve */
2617 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2618 "GNS_PHASE_DELEGATE_NS-%llu: Cannot fully resolve delegation for %s!\n",
2621 finish_lookup(rh, rlh, rd_count, rd);
2624 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2625 "GNS_PHASE_DELEGATE_NS-%llu: Resolving canonical record %s\n",
2628 rh->proc = &handle_record_ns;
2629 resolve_record_ns(rh);
2634 * This is a callback function that should give us only PKEY
2635 * records. Used to query the namestore for the authority (PKEY)
2636 * for 'name'. It will recursively try to resolve the
2637 * authority for a given name from the namestore.
2639 * @param cls the pending query
2640 * @param key the key of the zone we did the lookup
2641 * @param expiration expiration date of the record data set in the namestore
2642 * @param name the name for which we need an authority
2643 * @param rd_count the number of records with 'name'
2644 * @param rd the record data
2645 * @param signature the signature of the authority for the record data
2648 process_delegation_result_ns (void* cls,
2649 const struct GNUNET_CRYPTO_EccPublicKey *key,
2650 struct GNUNET_TIME_Absolute expiration,
2652 unsigned int rd_count,
2653 const struct GNUNET_NAMESTORE_RecordData *rd,
2654 const struct GNUNET_CRYPTO_EccSignature *signature)
2656 struct ResolverHandle *rh = cls;
2657 struct GNUNET_TIME_Relative remaining_time;
2658 struct GNUNET_CRYPTO_ShortHashCode zone;
2659 char new_name[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
2661 struct GNUNET_TIME_Absolute et;
2662 struct AuthorityChain *auth;
2664 rh->namestore_task = NULL;
2665 GNUNET_CRYPTO_short_hash (key,
2666 sizeof (struct GNUNET_CRYPTO_EccPublicKey),
2668 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2669 "GNS_PHASE_DELEGATE_NS-%llu: Got %d records from authority lookup for `%s' in zone %s\n",
2672 GNUNET_short_h2s (&zone));
2674 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
2680 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2681 "GNS_PHASE_DELEGATE_NS-%llu: Records with name `%s' exist in zone %s.\n",
2683 GNUNET_short_h2s (&zone));
2684 rh->status |= RSL_RECORD_EXISTS;
2686 if (0 == remaining_time.rel_value_us)
2688 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2689 "GNS_PHASE_DELEGATE_NS-%llu: Record set %s expired.\n",
2691 rh->status |= RSL_RECORD_EXPIRED;
2696 * No authority found in namestore.
2701 * We did not find an authority in the namestore
2706 * Promote this authority back to a name maybe it is
2709 if (strcmp (rh->name, "") == 0)
2711 /* simply promote back */
2712 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2713 "GNS_PHASE_DELEGATE_NS-%llu: Promoting %s back to name\n",
2714 rh->id, rh->authority_name);
2715 strcpy (rh->name, rh->authority_name);
2719 /* add back to existing name */
2720 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2721 "GNS_PHASE_DELEGATE_NS-%llu: Adding %s back to %s\n",
2722 rh->id, rh->authority_name, rh->name);
2723 GNUNET_snprintf (new_name, GNUNET_DNSPARSER_MAX_NAME_LENGTH, "%s.%s",
2724 rh->name, rh->authority_name);
2725 strcpy (rh->name, new_name);
2726 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2727 "GNS_PHASE_DELEGATE_NS-%llu: %s restored\n",
2731 rh->proc (rh->proc_cls, rh, 0, NULL);
2736 * We found an authority that may be able to help us
2737 * move on with query
2738 * Note only 1 pkey should have been returned.. anything else would be strange
2740 for (i=0; i < rd_count;i++)
2742 switch (rd[i].record_type)
2744 case GNUNET_DNSPARSER_TYPE_CNAME:
2745 /* Like in regular DNS this should mean that there is no other
2746 * record for this name. */
2748 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2749 "GNS_PHASE_DELEGATE_NS-%llu: CNAME `%.*s' found.\n",
2751 (int) rd[i].data_size,
2753 rh->status |= RSL_CNAME_FOUND;
2754 rh->proc (rh->proc_cls, rh, rd_count, rd);
2756 case GNUNET_NAMESTORE_TYPE_VPN:
2757 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2758 "GNS_PHASE_DELEGATE_NS-%llu: VPN found.\n",
2760 rh->status |= RSL_DELEGATE_VPN;
2761 rh->proc (rh->proc_cls, rh, rd_count, rd);
2763 case GNUNET_DNSPARSER_TYPE_NS:
2764 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2765 "GNS_PHASE_DELEGATE_NS-%llu: NS `%.*s' found.\n",
2767 (int) rd[i].data_size,
2769 rh->status |= RSL_DELEGATE_NS;
2770 rh->proc (rh->proc_cls, rh, rd_count, rd);
2772 case GNUNET_NAMESTORE_TYPE_PKEY:
2773 rh->status |= RSL_DELEGATE_PKEY;
2774 if ((ignore_pending_records != 0) &&
2775 (rd[i].flags & GNUNET_NAMESTORE_RF_PENDING))
2777 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2778 "GNS_PHASE_DELEGATE_NS-%llu: PKEY for %s is pending user confirmation.\n",
2783 GNUNET_break (0 == (rd[i].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION));
2784 et.abs_value_us = rd[i].expiration_time;
2785 if (0 == (GNUNET_TIME_absolute_get_remaining (et)).rel_value_us)
2787 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2788 "GNS_PHASE_DELEGATE_NS-%llu: This pkey is expired.\n",
2790 if (remaining_time.rel_value_us == 0)
2792 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2793 "GNS_PHASE_DELEGATE_NS-%llu: This dht entry is expired.\n",
2795 rh->authority_chain_head->fresh = 0;
2796 rh->proc (rh->proc_cls, rh, 0, NULL);
2801 /* Resolve rest of query with new authority */
2802 memcpy (&rh->authority, rd[i].data,
2803 sizeof (struct GNUNET_CRYPTO_ShortHashCode));
2804 auth = GNUNET_malloc(sizeof (struct AuthorityChain));
2805 auth->zone = rh->authority;
2806 memset (auth->name, 0, strlen (rh->authority_name)+1);
2807 strcpy (auth->name, rh->authority_name);
2808 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
2809 rh->authority_chain_tail,
2811 if (NULL != rh->rd.data)
2812 GNUNET_free ((void*)(rh->rd.data));
2813 memcpy (&rh->rd, &rd[i], sizeof (struct GNUNET_NAMESTORE_RecordData));
2814 rh->rd.data = GNUNET_malloc (rd[i].data_size);
2815 memcpy ((void*)rh->rd.data, rd[i].data, rd[i].data_size);
2817 /* Check for key revocation and delegate */
2818 rh->namestore_task = GNUNET_NAMESTORE_lookup_record (namestore_handle,
2820 GNUNET_GNS_MASTERZONE_STR,
2821 GNUNET_NAMESTORE_TYPE_REV,
2822 &process_pkey_revocation_result_ns,
2826 /* ignore, move to next result */
2831 /* no answers that would cause delegation were found */
2832 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2833 "GNS_PHASE_DELEGATE_NS-%llu: Authority lookup failed (no PKEY record)\n",
2836 * If we have found some records for the LAST label
2837 * we return the results. Else NULL.
2839 if (0 == strcmp (rh->name, ""))
2841 /* Start shortening */
2842 if ((rh->priv_key != NULL) &&
2843 (is_canonical (rh->name) == GNUNET_YES))
2845 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2846 "GNS_PHASE_DELEGATE_NS-%llu: Trying to shorten authority chain\n",
2848 start_shorten (rh->authority_chain_head,
2851 /* simply promote back */
2852 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2853 "GNS_PHASE_DELEGATE_NS-%llu: Promoting %s back to name\n",
2854 rh->id, rh->authority_name);
2855 strcpy (rh->name, rh->authority_name);
2856 rh->proc (rh->proc_cls, rh, rd_count, rd);
2860 GNUNET_snprintf (new_name, GNUNET_DNSPARSER_MAX_NAME_LENGTH,
2861 "%s.%s", rh->name, rh->authority_name);
2862 strcpy (rh->name, new_name);
2863 rh->proc (rh->proc_cls, rh, 0, NULL);
2869 * Resolve the delegation chain for the request in our namestore
2870 * (as in, find the respective authority for the leftmost label).
2872 * @param rh the resolver handle
2875 resolve_delegation_ns (struct ResolverHandle *rh)
2877 pop_tld (rh->name, rh->authority_name);
2878 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2879 "GNS_PHASE_DELEGATE_NS-%llu: Finding authority for `%s' by looking up `%s' in GADS zone `%s'\n",
2883 GNUNET_short_h2s (&rh->authority));
2884 rh->namestore_task = GNUNET_NAMESTORE_lookup_record (namestore_handle,
2887 GNUNET_DNSPARSER_TYPE_ANY,
2888 &process_delegation_result_ns,
2897 * Lookup of a record in a specific zone calls lookup result processor
2900 * @param zone the zone to perform the lookup in
2901 * @param record_type the record type to look up
2902 * @param name the name to look up
2903 * @param shorten_key a private key for use with PSEU import (can be NULL)
2904 * @param only_cached GNUNET_NO to only check locally not DHT for performance
2905 * @param proc the processor to call on result
2906 * @param proc_cls the closure to pass to @a proc
2907 * @return handle to cancel operation
2909 struct GNS_ResolverHandle *
2910 GNS_resolver_lookup (const struct GNUNET_CRYPTO_EccPublicKey *zone,
2911 uint32_t record_type,
2913 const struct GNUNET_CRYPTO_EccPrivateKey *shorten_key,
2915 GNS_ResultProcessor proc, void *proc_cls)
2919 struct ResolverHandle *rh;
2920 struct RecordLookupHandle* rlh;
2921 char string_hash[GNUNET_DNSPARSER_MAX_LABEL_LENGTH];
2922 char nzkey[GNUNET_DNSPARSER_MAX_LABEL_LENGTH];
2923 char* nzkey_ptr = nzkey;
2925 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2926 "Starting resolution for `%s' (type=%d) with timeout %s!\n",
2928 GNUNET_STRINGS_relative_time_to_string (timeout, GNUNET_YES));
2930 if ((is_canonical ((char*)name) == GNUNET_YES) &&
2931 (strcmp(GNUNET_GNS_TLD, name) != 0))
2933 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2934 "%s is canonical and not gnunet -> cannot resolve!\n", name);
2939 rlh = GNUNET_malloc (sizeof(struct RecordLookupHandle));
2940 rh = GNUNET_malloc (sizeof (struct ResolverHandle));
2941 rh->authority = zone;
2945 rh->timeout = timeout;
2946 rh->private_local_zone = pzone;
2947 rh->only_cached = only_cached;
2949 GNUNET_CONTAINER_DLL_insert (rlh_head, rlh_tail, rh);
2952 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2953 "No shorten key for resolution\n");
2955 if (timeout.rel_value_us != GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
2958 * Set timeout for authority lookup phase to 1/2
2960 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2961 "Timeout for lookup set to %s/2\n",
2962 GNUNET_STRINGS_relative_time_to_string (rh->timeout, GNUNET_YES));
2963 rh->timeout_task = GNUNET_SCHEDULER_add_delayed (
2964 GNUNET_TIME_relative_divide(timeout, 2),
2965 &handle_lookup_timeout,
2967 rh->timeout_cont = &dht_authority_lookup_timeout;
2968 rh->timeout_cont_cls = rh;
2972 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No timeout for query!\n");
2973 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2976 if (strcmp(GNUNET_GNS_TLD, name) == 0)
2979 * Only '.gads' given
2981 strcpy (rh->name, "\0");
2985 if (is_zkey_tld(name) == GNUNET_YES)
2987 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2990 * This is a zkey tld
2991 * build hash and use as initial authority
2994 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
2995 memcpy(rh->name, name,
2996 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
2997 pop_tld (rh->name, string_hash);
2999 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3000 "ZKEY is %s!\n", string_hash);
3002 GNUNET_STRINGS_utf8_toupper(string_hash, &nzkey_ptr);
3004 if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(nzkey,
3007 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3008 "Cannot convert ZKEY `%s' to hash!\n", string_hash);
3010 if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
3011 GNUNET_SCHEDULER_cancel (rh->timeout_task);
3012 GNUNET_CONTAINER_DLL_remove (rlh_head, rlh_tail, rh);
3015 proc (cls, 0, NULL);
3020 else if (is_gads_tld (name) == GNUNET_YES)
3022 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3025 * Presumably GADS tld
3027 memcpy (rh->name, name,
3028 strlen (name) - strlen(GNUNET_GNS_TLD) - 1);
3029 rh->name[strlen (name) - strlen(GNUNET_GNS_TLD) - 1] = '\0';
3033 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3034 _("Not a GADS TLD: `%s'\n"),
3036 if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
3037 GNUNET_SCHEDULER_cancel (rh->timeout_task);
3038 GNUNET_CONTAINER_DLL_remove (rlh_head, rlh_tail, rh);
3041 proc (cls, 0, NULL);
3047 * Initialize authority chain
3049 rh->authority_chain_head = GNUNET_malloc (sizeof(struct AuthorityChain));
3050 rh->authority_chain_tail = rh->authority_chain_head;
3051 rh->authority_chain_head->zone = rh->authority;
3052 strcpy (rh->authority_chain_head->name, "");
3055 * Copy original query into lookup handle
3057 rlh->record_type = record_type;
3058 memset(rlh->name, 0, strlen(name) + 1);
3059 strcpy(rlh->name, name);
3061 rlh->proc_cls = cls;
3063 rh->proc = &handle_delegation_ns;
3064 resolve_delegation_ns (rh);
3071 * Cancel active resolution (i.e. client disconnected).
3073 * @param h resolution to abort
3076 GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *h)
3081 /* ***************** Resolver initialization ********************* */
3085 * Initialize the resolver
3087 * @param nh the namestore handle
3088 * @param dh the dht handle
3089 * @param c configuration handle
3090 * @param max_bg_queries maximum number of parallel background queries in dht
3091 * @param ignore_pending ignore records that still require user confirmation
3095 GNS_resolver_init (struct GNUNET_NAMESTORE_Handle *nh,
3096 struct GNUNET_DHT_Handle *dh,
3097 const struct GNUNET_CONFIGURATION_Handle *c,
3098 unsigned long long max_bg_queries)
3103 namestore_handle = nh;
3106 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3107 max_allowed_background_queries = max_bg_queries;
3109 GNUNET_CONFIGURATION_get_value_string (c,
3114 /* user did not specify DNS resolver, use 8.8.8.8 */
3115 dns_ip = GNUNET_strdup ("8.8.8.8");
3117 dns_handle = GNUNET_DNSSTUB_start (dns_ip);
3118 GNUNET_free (dns_ip);
3126 GNS_resolver_done ()
3128 while (NULL != gph_head)
3129 free_get_pseu_authority_handle (gph_head);
3130 GNUNET_CONTAINER_heap_destroy (dht_lookup_heap);
3131 dht_lookup_heap = NULL;
3132 GNUNET_DNSSTUB_stop (dns_handle);
3137 /* *************** common helper functions (do not really belong here) *********** */
3140 * Checks if "name" ends in ".tld"
3142 * @param name the name to check
3143 * @param tld the TLD to check for
3144 * @return GNUNET_YES or GNUNET_NO
3147 is_tld (const char* name, const char* tld)
3151 if (strlen (name) <= strlen (tld))
3153 offset = strlen (name) - strlen (tld);
3154 if (0 != strcmp (name + offset, tld))
3162 /* end of gnunet-service-gns_resolver.c */