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 * - recurive GNS resulution
29 * - recursive DNS resolution
30 * - shortening triggers
31 * - revocation checks (privacy!?)
34 #include "gnunet_util_lib.h"
35 #include "gnunet_transport_service.h"
36 #include "gnunet_dnsstub_lib.h"
37 #include "gnunet_dht_service.h"
38 #include "gnunet_namestore_service.h"
39 #include "gnunet_dns_service.h"
40 #include "gnunet_resolver_service.h"
41 #include "gnunet_dnsparser_lib.h"
42 #include "gns_protocol.h"
43 #include "gnunet_gns_service.h"
44 #include "gns_common.h"
46 #include "gnunet-service-gns_resolver.h"
47 #include "gnunet_vpn_service.h"
51 * Default DHT timeout for lookups.
53 #define DHT_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
56 * Default timeout for DNS lookups.
58 #define DNS_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
61 * DHT replication level
63 #define DHT_GNS_REPLICATION_LEVEL 5
66 * How deep do we allow recursions to go before we abort?
68 #define MAX_RECURSION 256
72 * DLL to hold the authority chain we had to pass in the resolution
80 struct AuthorityChain *prev;
85 struct AuthorityChain *next;
88 * Resolver handle this entry in the chain belongs to.
90 struct GNS_ResolverHandle *rh;
93 * label/name corresponding to the authority
98 * #GNUNET_YES if the authority was a GNS authority,
99 * #GNUNET_NO if the authority was a DNS authority.
104 * Information about the resolver authority for this label.
110 * The zone of the GNS authority
112 struct GNUNET_CRYPTO_EccPublicKey gns_authority;
117 * Domain of the DNS resolver that is the authority.
118 * (appended to construct the DNS name to resolve;
119 * this is NOT the DNS name of the DNS server!).
121 char name[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
124 * IP address of the DNS resolver that is authoritative.
125 * (this implementation currently only supports one
128 struct sockaddr_storage dns_ip;
138 * Resolution status indicator
140 enum ResolutionStatus
143 * the name to lookup exists
145 RSL_RECORD_EXISTS = 1,
148 * the name in the record expired
150 RSL_RECORD_EXPIRED = 2,
153 * resolution timed out
158 * Found VPN delegation
160 RSL_DELEGATE_VPN = 8,
163 * Found NS delegation
165 RSL_DELEGATE_NS = 16,
168 * Found PKEY delegation
170 RSL_DELEGATE_PKEY = 32,
175 RSL_CNAME_FOUND = 64,
178 * Found PKEY has been revoked
180 RSL_PKEY_REVOKED = 128
185 * A result we got from DNS.
193 struct DnsResult *next;
198 struct DnsResult *prev;
201 * Binary value stored in the DNS record (appended to this struct)
206 * Expiration time for the DNS record, 0 if we didn't
207 * get anything useful (i.e. 'gethostbyname' was used).
209 uint64_t expiration_time;
212 * Number of bytes in 'data'.
217 * Type of the GNS/DNS record.
219 uint32_t record_type;
225 * Handle to a currenty pending resolution. On result (positive or
226 * negative) the #GNS_ResultProcessor is called.
228 struct GNS_ResolverHandle
234 struct GNS_ResolverHandle *next;
239 struct GNS_ResolverHandle *prev;
242 * The top-level GNS authoritative zone to query
244 struct GNUNET_CRYPTO_EccPublicKey authority_zone;
247 * called when resolution phase finishes
249 GNS_ResultProcessor proc;
252 * closure passed to proc
257 * Handle for DHT lookups. should be NULL if no lookups are in progress
259 struct GNUNET_DHT_GetHandle *get_handle;
262 * Handle to a VPN request, NULL if none is active.
264 struct GNUNET_VPN_RedirectionRequest *vpn_handle;
267 * Socket for a DNS request, NULL if none is active.
269 struct GNUNET_DNSSTUB_RequestSocket *dns_request;
272 * Handle for standard DNS resolution, NULL if none is active.
274 struct GNUNET_RESOLVER_RequestHandle *std_resolve;
277 * Pending Namestore task
279 struct GNUNET_NAMESTORE_QueueEntry *namestore_qe;
282 * Heap node associated with this lookup. Used to limit number of
283 * concurrent requests.
285 struct GNUNET_CONTAINER_HeapNode *dht_heap_node;
288 * DLL to store the authority chain
290 struct AuthorityChain *ac_head;
293 * DLL to store the authority chain
295 struct AuthorityChain *ac_tail;
298 * Private key of the shorten zone, NULL to not shorten.
300 struct GNUNET_CRYPTO_EccPrivateKey *shorten_key;
303 * ID of a task associated with the resolution process.
305 GNUNET_SCHEDULER_TaskIdentifier task_id;
308 * The name to resolve
313 * DLL of results we got from DNS.
315 struct DnsResult *dns_result_head;
318 * DLL of results we got from DNS.
320 struct DnsResult *dns_result_tail;
323 * Current offset in 'name' where we are resolving.
325 size_t name_resolution_pos;
333 * Desired type for the resolution.
338 * We increment the loop limiter for each step in a recursive
339 * resolution. If it passes our threshold (i.e. due to
340 * self-recursion in the resolution, i.e CNAME fun), we stop.
342 unsigned int loop_limiter;
348 * Handle for a PSEU lookup used to shorten names.
350 struct GetPseuAuthorityHandle
355 struct GetPseuAuthorityHandle *next;
360 struct GetPseuAuthorityHandle *prev;
363 * Private key of the (shorten) zone to store the resulting
366 struct GNUNET_CRYPTO_EccPrivateKey shorten_zone_key;
369 * Original label (used if no PSEU record is found).
371 char label[GNUNET_DNSPARSER_MAX_LABEL_LENGTH + 1];
374 * The zone for which we are trying to find the PSEU record.
376 struct GNUNET_CRYPTO_EccPublicKey target_zone;
379 * Handle for DHT lookups. Should be NULL if no lookups are in progress
381 struct GNUNET_DHT_GetHandle *get_handle;
384 * Handle to namestore request
386 struct GNUNET_NAMESTORE_QueueEntry *namestore_task;
389 * Task to abort DHT lookup operation.
391 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
397 * Our handle to the namestore service
399 static struct GNUNET_NAMESTORE_Handle *namestore_handle;
402 * Our handle to the vpn service
404 static struct GNUNET_VPN_Handle *vpn_handle;
407 * Resolver handle to the dht
409 static struct GNUNET_DHT_Handle *dht_handle;
412 * Handle to perform DNS lookups.
414 static struct GNUNET_DNSSTUB_Context *dns_handle;
417 * Heap for limiting parallel DHT lookups
419 static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
422 * Maximum amount of parallel queries to the DHT
424 static unsigned long long max_allowed_background_queries;
427 * Head of PSEU/shorten operations list.
429 struct GetPseuAuthorityHandle *gph_head;
432 * Tail of PSEU/shorten operations list.
434 struct GetPseuAuthorityHandle *gph_tail;
437 * Head of resolver lookup list
439 static struct GNS_ResolverHandle *rlh_head;
442 * Tail of resolver lookup list
444 static struct GNS_ResolverHandle *rlh_tail;
447 * Global configuration.
449 static const struct GNUNET_CONFIGURATION_Handle *cfg;
453 * Check if name is in srv format (_x._y.xxx)
456 * @return GNUNET_YES if true
459 is_srv (const char *name)
466 if (NULL == strstr (name, "._"))
469 ndup = GNUNET_strdup (name);
471 if (NULL == strtok (NULL, "."))
473 if (NULL == strtok (NULL, "."))
475 if (NULL != strtok (NULL, "."))
483 * Determine if this name is canonical (is a legal name in a zone, without delegation);
484 * note that we do not test that the name does not contain illegal characters, we only
485 * test for delegation. Note that service records (i.e. _foo._srv) are canonical names
486 * even though they consist of multiple labels.
489 * a.b.gads = not canonical
491 * _foo._srv = canonical
492 * _f.bar = not canonical
494 * @param name the name to test
495 * @return GNUNET_YES if canonical
498 is_canonical (const char *name)
503 if (NULL == strchr (name, '.'))
508 while (NULL != (dot = strchr (pos, '.')))
517 /* ******************** Shortening logic ************************ */
521 * Cleanup a 'struct GetPseuAuthorityHandle', terminating all
522 * pending activities.
524 * @param gph handle to terminate
527 free_get_pseu_authority_handle (struct GetPseuAuthorityHandle *gph)
529 if (NULL != gph->get_handle)
531 GNUNET_DHT_get_stop (gph->get_handle);
532 gph->get_handle = NULL;
534 if (NULL != gph->namestore_task)
536 GNUNET_NAMESTORE_cancel (gph->namestore_task);
537 gph->namestore_task = NULL;
539 if (GNUNET_SCHEDULER_NO_TASK != gph->timeout_task)
541 GNUNET_SCHEDULER_cancel (gph->timeout_task);
542 gph->timeout_task = GNUNET_SCHEDULER_NO_TASK;
544 GNUNET_CONTAINER_DLL_remove (gph_head, gph_tail, gph);
550 * Continuation for pkey record creation (shorten)
552 * @param cls a GetPseuAuthorityHandle
553 * @param success unused
557 create_pkey_cont (void* cls,
561 struct GetPseuAuthorityHandle* gph = cls;
563 gph->namestore_task = NULL;
564 free_get_pseu_authority_handle (gph);
569 * Namestore calls this function if we have record for this name.
570 * (or with rd_count=0 to indicate no matches).
572 * @param cls the pending query
573 * @param key the key of the zone we did the lookup
574 * @param name the name for which we need an authority
575 * @param rd_count the number of records with 'name'
576 * @param rd the record data
579 process_pseu_lookup_ns (void *cls,
580 const struct GNUNET_CRYPTO_EccPrivateKey *key,
582 unsigned int rd_count,
583 const struct GNUNET_NAMESTORE_RecordData *rd)
585 struct GetPseuAuthorityHandle *gph = cls;
586 struct GNUNET_NAMESTORE_RecordData new_pkey;
587 struct GNUNET_CRYPTO_EccPublicKey pub;
589 gph->namestore_task = NULL;
592 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
593 "Name `%s' already taken, cannot shorten.\n",
595 /* if this was not yet the original label, try one more
596 time, this time not using PSEU but the original label */
597 if (0 == strcmp (name,
600 free_get_pseu_authority_handle (gph);
604 GNUNET_CRYPTO_ecc_key_get_public (&gph->shorten_zone_key,
606 gph->namestore_task = GNUNET_NAMESTORE_lookup (namestore_handle,
609 &process_pseu_lookup_ns,
614 /* name is available */
615 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
616 "Shortening `%s' to `%s'\n",
617 GNUNET_NAMESTORE_z2s (&gph->target_zone),
619 new_pkey.expiration_time = UINT64_MAX;
620 new_pkey.data_size = sizeof (struct GNUNET_CRYPTO_EccPublicKey);
621 new_pkey.data = &gph->target_zone;
622 new_pkey.record_type = GNUNET_NAMESTORE_TYPE_PKEY;
623 new_pkey.flags = GNUNET_NAMESTORE_RF_AUTHORITY
624 | GNUNET_NAMESTORE_RF_PRIVATE
625 | GNUNET_NAMESTORE_RF_PENDING;
627 = GNUNET_NAMESTORE_records_store (namestore_handle,
628 &gph->shorten_zone_key,
631 &create_pkey_cont, gph);
636 * Process result of a DHT lookup for a PSEU record.
638 * @param gph the handle to our shorten operation
639 * @param pseu the pseu result or NULL
642 process_pseu_result (struct GetPseuAuthorityHandle* gph,
645 struct GNUNET_CRYPTO_EccPublicKey pub;
647 GNUNET_CRYPTO_ecc_key_get_public (&gph->shorten_zone_key,
651 /* no PSEU found, try original label */
652 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
653 "No PSEU found, trying original label `%s' instead.\n",
655 gph->namestore_task = GNUNET_NAMESTORE_lookup (namestore_handle,
658 &process_pseu_lookup_ns,
663 /* check if 'pseu' is taken */
664 gph->namestore_task = GNUNET_NAMESTORE_lookup (namestore_handle,
667 &process_pseu_lookup_ns,
673 * Handle timeout for DHT request during shortening.
675 * @param cls the request handle as closure
676 * @param tc the task context
679 handle_auth_discovery_timeout (void *cls,
680 const struct GNUNET_SCHEDULER_TaskContext *tc)
682 struct GetPseuAuthorityHandle *gph = cls;
684 gph->timeout_task = GNUNET_SCHEDULER_NO_TASK;
685 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
686 "DHT lookup for PSEU query timed out.\n");
687 GNUNET_DHT_get_stop (gph->get_handle);
688 gph->get_handle = NULL;
689 process_pseu_result (gph, NULL);
694 * Handle decrypted records from DHT result.
696 * @param cls closure with our 'struct GetPseuAuthorityHandle'
697 * @param rd_count number of entries in 'rd' array
698 * @param rd array of records with data to store
701 process_auth_records (void *cls,
702 unsigned int rd_count,
703 const struct GNUNET_NAMESTORE_RecordData *rd)
705 struct GetPseuAuthorityHandle *gph = cls;
708 for (i=0; i < rd_count; i++)
710 if (GNUNET_NAMESTORE_TYPE_PSEU == rd[i].record_type)
713 process_pseu_result (gph,
714 (const char *) rd[i].data);
718 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
719 "No PSEU record found in DHT reply.\n");
720 process_pseu_result (gph, NULL);
725 * Function called when we find a PSEU entry in the DHT
727 * @param cls the request handle
728 * @param exp lifetime
729 * @param key the key the record was stored under
730 * @param get_path get path
731 * @param get_path_length get path length
732 * @param put_path put path
733 * @param put_path_length put path length
734 * @param type the block type
735 * @param size the size of the record
736 * @param data the record data
739 process_auth_discovery_dht_result (void* cls,
740 struct GNUNET_TIME_Absolute exp,
741 const struct GNUNET_HashCode *key,
742 const struct GNUNET_PeerIdentity *get_path,
743 unsigned int get_path_length,
744 const struct GNUNET_PeerIdentity *put_path,
745 unsigned int put_path_length,
746 enum GNUNET_BLOCK_Type type,
750 struct GetPseuAuthorityHandle *gph = cls;
751 const struct GNUNET_NAMESTORE_Block *block;
753 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
754 "Got DHT result for PSEU request\n");
755 GNUNET_DHT_get_stop (gph->get_handle);
756 gph->get_handle = NULL;
757 GNUNET_SCHEDULER_cancel (gph->timeout_task);
758 gph->timeout_task = GNUNET_SCHEDULER_NO_TASK;
762 /* is this allowed!? */
764 process_pseu_result (gph, NULL);
767 if (size < sizeof (struct GNUNET_NAMESTORE_Block))
769 /* how did this pass DHT block validation!? */
771 process_pseu_result (gph, NULL);
776 ntohs (block->purpose.size) +
777 sizeof (struct GNUNET_CRYPTO_EccPublicKey) +
778 sizeof (struct GNUNET_CRYPTO_EccSignature))
780 /* how did this pass DHT block validation!? */
782 process_pseu_result (gph, NULL);
786 GNUNET_NAMESTORE_block_decrypt (block,
789 &process_auth_records,
792 /* other peer encrypted invalid block, complain */
794 process_pseu_result (gph, NULL);
801 * Callback called by namestore for a zone to name result. We're
802 * trying to see if a short name for a given zone already exists.
804 * @param cls the closure
805 * @param zone_key the zone we queried
806 * @param name the name found or NULL
807 * @param rd_len number of records for the name
808 * @param rd the record data (PKEY) for the name
811 process_zone_to_name_discover (void *cls,
812 const struct GNUNET_CRYPTO_EccPrivateKey *zone_key,
815 const struct GNUNET_NAMESTORE_RecordData *rd)
817 struct GetPseuAuthorityHandle* gph = cls;
818 struct GNUNET_HashCode lookup_key;
820 gph->namestore_task = NULL;
823 /* we found a match in our own zone */
824 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
825 "Shortening aborted, name `%s' already reserved for the zone\n",
827 free_get_pseu_authority_handle (gph);
830 /* record does not yet exist, go into DHT to find PSEU record */
831 GNUNET_NAMESTORE_query_from_public_key (&gph->target_zone,
834 gph->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
835 &handle_auth_discovery_timeout,
837 gph->get_handle = GNUNET_DHT_get_start (dht_handle,
838 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
840 DHT_GNS_REPLICATION_LEVEL,
841 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
843 &process_auth_discovery_dht_result,
849 * Start shortening algorithm, try to allocate a nice short
850 * canonical name for @a pub in @a shorten_zone, using
851 * @a original_label as one possible suggestion.
853 * @param original_label original label for the zone
854 * @param pub public key of the zone to shorten
855 * @param shorten_zone private key of the target zone for the new record
858 start_shorten (const char *original_label,
859 const struct GNUNET_CRYPTO_EccPublicKey *pub,
860 const struct GNUNET_CRYPTO_EccPrivateKey *shorten_zone)
862 struct GetPseuAuthorityHandle *gph;
864 if (strlen (original_label) > GNUNET_DNSPARSER_MAX_LABEL_LENGTH)
869 gph = GNUNET_new (struct GetPseuAuthorityHandle);
870 gph->shorten_zone_key = *shorten_zone;
871 gph->target_zone = *pub;
872 strcpy (gph->label, original_label);
873 GNUNET_CONTAINER_DLL_insert (gph_head, gph_tail, gph);
874 /* first, check if we *already* have a record for this zone */
875 gph->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
878 &process_zone_to_name_discover,
883 /* ************************** Resolution **************************** */
889 * Namestore calls this function if we have record for this name.
890 * (or with rd_count=0 to indicate no matches)
892 * @param cls the pending query
893 * @param key the key of the zone we did the lookup
894 * @param expiration expiration date of the namestore entry
895 * @param name the name for which we need an authority
896 * @param rd_count the number of records with 'name'
897 * @param rd the record data
898 * @param signature the signature of the authority for the record data
901 process_record_result_ns (void* cls,
902 const struct GNUNET_CRYPTO_EccPublicKey *key,
903 struct GNUNET_TIME_Absolute expiration,
904 const char *name, unsigned int rd_count,
905 const struct GNUNET_NAMESTORE_RecordData *rd,
906 const struct GNUNET_CRYPTO_EccSignature *signature)
908 struct ResolverHandle *rh = cls;
909 struct RecordLookupHandle *rlh = rh->proc_cls;
910 struct GNUNET_TIME_Relative remaining_time;
911 struct GNUNET_CRYPTO_ShortHashCode zone;
912 struct GNUNET_TIME_Absolute et;
915 rh->namestore_task = NULL;
916 GNUNET_CRYPTO_short_hash (key,
917 sizeof (struct GNUNET_CRYPTO_EccPublicKey),
919 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
923 rh->status |= RSL_RECORD_EXISTS;
924 if (remaining_time.rel_value_us == 0)
925 rh->status |= RSL_RECORD_EXPIRED;
930 * Lookup terminated and no results
932 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
933 "GNS_PHASE_REC-%llu: Namestore lookup for %s terminated without results\n",
936 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
937 "GNS_PHASE_REC-%llu: Record %s unknown in namestore\n",
940 * Our zone and no result? Cannot resolve TT
942 rh->proc(rh->proc_cls, rh, 0, NULL);
946 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
947 "GNS_PHASE_REC-%llu: Processing additional result %s from namestore\n",
949 for (i = 0; i < rd_count;i++)
951 if (rd[i].record_type != rlh->record_type)
954 if (ignore_pending_records &&
955 (rd[i].flags & GNUNET_NAMESTORE_RF_PENDING))
957 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
958 "GNS_PHASE_REC-%llu: Record %s is awaiting user confirmation. Skipping\n",
963 //FIXME: eh? do I have to handle this here?
964 GNUNET_break (0 == (rd[i].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION));
965 et.abs_value_us = rd[i].expiration_time;
966 if (0 == (GNUNET_TIME_absolute_get_remaining (et)).rel_value_us)
968 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
969 "GNS_PHASE_REC-%llu: This record is expired. Skipping\n",
979 if (0 == rh->answered)
981 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
982 "GNS_PHASE_REC-%llu: No answers found. This is odd!\n", rh->id);
983 rh->proc(rh->proc_cls, rh, 0, NULL);
987 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
988 "GNS_PHASE_REC-%llu: Found %d answer(s) to query in %d records!\n",
989 rh->id, rh->answered, rd_count);
990 rh->proc(rh->proc_cls, rh, rd_count, rd);
995 * VPN redirect result callback
997 * @param cls the resolver handle
998 * @param af the requested address family
999 * @param address in_addr(6) respectively
1002 process_record_result_vpn (void* cls, int af, const void *address)
1004 struct ResolverHandle *rh = cls;
1005 struct RecordLookupHandle *rlh = rh->proc_cls;
1006 struct GNUNET_NAMESTORE_RecordData rd;
1008 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1009 "GNS_PHASE_REC_VPN-%llu: Got answer from VPN to query!\n",
1013 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1014 "GNS_PHASE_REC-%llu: Answer is IPv4!\n",
1016 if (GNUNET_DNSPARSER_TYPE_A != rlh->record_type)
1018 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1019 "GNS_PHASE_REC-%llu: Requested record is not IPv4!\n",
1021 rh->proc (rh->proc_cls, rh, 0, NULL);
1024 rd.record_type = GNUNET_DNSPARSER_TYPE_A;
1025 rd.expiration_time = UINT64_MAX; /* FIXME: should probably pick something shorter... */
1027 rd.data_size = sizeof (struct in_addr);
1029 rh->proc (rh->proc_cls, rh, 1, &rd);
1032 else if (AF_INET6 == af)
1034 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1035 "GNS_PHASE_REC-%llu: Answer is IPv6!\n",
1037 if (GNUNET_DNSPARSER_TYPE_AAAA != rlh->record_type)
1039 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1040 "GNS_PHASE_REC-%llu: Requested record is not IPv6!\n",
1042 rh->proc (rh->proc_cls, rh, 0, NULL);
1045 rd.record_type = GNUNET_DNSPARSER_TYPE_AAAA;
1046 rd.expiration_time = UINT64_MAX; /* FIXME: should probably pick something shorter... */
1048 rd.data_size = sizeof (struct in6_addr);
1050 rh->proc (rh->proc_cls, rh, 1, &rd);
1054 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1055 "GNS_PHASE_REC-%llu: Got garbage from VPN!\n",
1057 rh->proc (rh->proc_cls, rh, 0, NULL);
1062 * Process VPN lookup result for record
1064 * @param cls the record lookup handle
1065 * @param rh resolver handle
1066 * @param rd_count number of results (1)
1067 * @param rd record data containing the result
1070 handle_record_vpn (void* cls, struct ResolverHandle *rh,
1071 unsigned int rd_count,
1072 const struct GNUNET_NAMESTORE_RecordData *rd)
1074 struct RecordLookupHandle* rlh = cls;
1078 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1079 "GNS_PHASE_REC_VPN-%llu: VPN returned no records. (status: %d)!\n",
1082 /* give up, cannot resolve */
1083 finish_lookup(rh, rlh, 0, NULL);
1087 /* results found yay */
1088 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1089 "GNS_PHASE_REC_VPN-%llu: Record resolved from VPN!\n",
1092 finish_lookup(rh, rlh, rd_count, rd);
1097 * The final phase of resoution.
1098 * We found a NS RR and want to resolve via DNS
1100 * @param rh the pending lookup handle
1101 * @param rd_count length of record data
1102 * @param rd record data containing VPN RR
1105 resolve_record_dns (struct ResolverHandle *rh,
1106 unsigned int rd_count,
1107 const struct GNUNET_NAMESTORE_RecordData *rd)
1109 struct RecordLookupHandle *rlh = rh->proc_cls;
1110 struct GNUNET_DNSPARSER_Query query;
1111 struct GNUNET_DNSPARSER_Packet packet;
1112 struct GNUNET_DNSPARSER_Flags flags;
1113 struct in_addr dnsip;
1114 struct sockaddr_in addr;
1115 struct sockaddr *sa;
1118 memset (&packet, 0, sizeof (struct GNUNET_DNSPARSER_Packet));
1119 memset (rh->dns_name, 0, sizeof (rh->dns_name));
1121 /* We cancel here as to not include the ns lookup in the timeout */
1122 if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
1124 GNUNET_SCHEDULER_cancel(rh->timeout_task);
1125 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1127 /* Start shortening */
1128 if ((NULL != rh->priv_key) &&
1129 (GNUNET_YES == is_canonical (rh->name)))
1131 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1132 "GNS_PHASE_REC_DNS-%llu: Trying to shorten authority chain\n",
1134 start_shorten (rh->authority_chain_head,
1138 for (i = 0; i < rd_count; i++)
1140 /* Synthesize dns name */
1141 if (GNUNET_DNSPARSER_TYPE_NS == rd[i].record_type)
1143 strcpy (rh->dns_zone, (char*)rd[i].data);
1144 if (0 == strcmp (rh->name, ""))
1145 strcpy (rh->dns_name, (char*)rd[i].data);
1147 sprintf (rh->dns_name, "%s.%s", rh->name, (char*)rd[i].data);
1150 if (GNUNET_DNSPARSER_TYPE_A == rd[i].record_type)
1151 /* need to use memcpy as .data may be unaligned */
1152 memcpy (&dnsip, rd[i].data, sizeof (dnsip));
1155 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1156 "GNS_PHASE_REC_DNS-%llu: Looking up `%s' from `%s'\n",
1160 rh->dns_sock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0);
1161 if (NULL == rh->dns_sock)
1163 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1164 "GNS_PHASE_REC_DNS-%llu: Error creating udp socket for dns!\n",
1166 finish_lookup (rh, rlh, 0, NULL);
1170 memset (&addr, 0, sizeof (struct sockaddr_in));
1171 sa = (struct sockaddr *) &addr;
1172 sa->sa_family = AF_INET;
1173 if (GNUNET_OK != GNUNET_NETWORK_socket_bind (rh->dns_sock,
1175 sizeof (struct sockaddr_in),
1178 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1179 "GNS_PHASE_REC_DNS-%llu: Error binding UDP socket for DNS lookup!\n",
1181 finish_lookup (rh, rlh, 0, NULL);
1184 query.name = rh->dns_name;
1185 query.type = rlh->record_type;
1186 query.class = GNUNET_DNSPARSER_CLASS_INTERNET;
1187 memset (&flags, 0, sizeof (flags));
1188 flags.recursion_desired = 1;
1189 flags.checking_disabled = 1;
1190 packet.queries = &query;
1191 packet.answers = NULL;
1192 packet.authority_records = NULL;
1193 packet.num_queries = 1;
1194 packet.num_answers = 0;
1195 packet.num_authority_records = 0;
1196 packet.num_additional_records = 0;
1197 packet.flags = flags;
1199 if (GNUNET_OK != GNUNET_DNSPARSER_pack (&packet,
1201 &rh->dns_raw_packet,
1202 &rh->dns_raw_packet_size))
1204 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1205 "GNS_PHASE_REC_DNS-%llu: Creating raw dns packet!\n",
1207 GNUNET_NETWORK_socket_close (rh->dns_sock);
1208 finish_lookup (rh, rlh, 0, NULL);
1212 rh->dns_addr.sin_family = AF_INET;
1213 rh->dns_addr.sin_port = htons (53); //domain
1214 rh->dns_addr.sin_addr = dnsip;
1215 #if HAVE_SOCKADDR_IN_SIN_LEN
1216 rh->dns_addr.sin_len = (u_char) sizeof (struct sockaddr_in);
1218 send_dns_packet (rh);
1223 * The final phase of resoution.
1224 * We found a VPN RR and want to request an IPv4/6 address
1226 * @param rh the pending lookup handle
1227 * @param rd_count length of record data
1228 * @param rd record data containing VPN RR
1231 resolve_record_vpn (struct ResolverHandle *rh,
1232 unsigned int rd_count,
1233 const struct GNUNET_NAMESTORE_RecordData *rd)
1235 struct RecordLookupHandle *rlh = rh->proc_cls;
1236 struct GNUNET_HashCode serv_desc;
1237 struct vpn_data* vpn;
1240 /* We cancel here as to not include the ns lookup in the timeout */
1241 if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
1243 GNUNET_SCHEDULER_cancel(rh->timeout_task);
1244 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1246 /* Start shortening */
1247 if ((NULL != rh->priv_key) &&
1248 (GNUNET_YES == is_canonical (rh->name)))
1250 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1251 "GNS_PHASE_REC_VPN-%llu: Trying to shorten authority chain\n",
1253 start_shorten (rh->authority_chain_head,
1257 vpn = (struct vpn_data*)rd->data;
1258 GNUNET_CRYPTO_hash ((char*)&vpn[1],
1259 strlen ((char*)&vpn[1]) + 1,
1261 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1262 "GNS_PHASE_REC_VPN-%llu: proto %hu peer %s!\n",
1265 GNUNET_h2s (&vpn->peer));
1267 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1268 "GNS_PHASE_REC_VPN-%llu: service %s -> %s!\n",
1271 GNUNET_h2s (&serv_desc));
1272 rh->proc = &handle_record_vpn;
1273 if (GNUNET_DNSPARSER_TYPE_A == rlh->record_type)
1278 if (NULL == vpn_handle)
1280 vpn_handle = GNUNET_VPN_connect (cfg);
1281 if (NULL == vpn_handle)
1283 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1284 "GNS_PHASE_INIT: Error connecting to VPN!\n");
1285 finish_lookup (rh, rh->proc_cls, 0, NULL);
1290 rh->vpn_handle = GNUNET_VPN_redirect_to_peer (vpn_handle,
1291 af, ntohs (vpn->proto),
1292 (struct GNUNET_PeerIdentity *)&vpn->peer,
1295 GNUNET_TIME_UNIT_FOREVER_ABS, //FIXME
1296 &process_record_result_vpn,
1299 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1300 "Error connecting to VPN (not available on W32 yet)\n");
1301 finish_lookup (rh, rh->proc_cls, 0, NULL);
1307 * The final phase of resolution.
1308 * rh->name is a name that is canonical and we do not have a delegation.
1309 * Query namestore for this record
1311 * @param rh the pending lookup handle
1314 resolve_record_ns(struct ResolverHandle *rh)
1316 struct RecordLookupHandle *rlh = rh->proc_cls;
1318 /* We cancel here as to not include the ns lookup in the timeout */
1319 if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
1321 GNUNET_SCHEDULER_cancel(rh->timeout_task);
1322 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1324 /* Start shortening */
1325 if ((NULL != rh->priv_key) &&
1326 (GNUNET_YES == is_canonical (rh->name)))
1328 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1329 "GNS_PHASE_REC-%llu: Trying to shorten authority chain\n",
1331 start_shorten (rh->authority_chain_head,
1336 * Try to resolve this record in our namestore.
1337 * The name to resolve is now in rh->authority_name
1338 * since we tried to resolve it to an authority
1341 rh->namestore_task = GNUNET_NAMESTORE_lookup_record(namestore_handle,
1345 &process_record_result_ns,
1351 * This is a callback function that checks for key revocation
1353 * @param cls the pending query
1354 * @param key the key of the zone we did the lookup
1355 * @param expiration expiration date of the record data set in the namestore
1356 * @param name the name for which we need an authority
1357 * @param rd_count the number of records with 'name'
1358 * @param rd the record data
1359 * @param signature the signature of the authority for the record data
1362 process_pkey_revocation_result_ns (void *cls,
1363 const struct GNUNET_CRYPTO_EccPublicKey *key,
1364 struct GNUNET_TIME_Absolute expiration,
1366 unsigned int rd_count,
1367 const struct GNUNET_NAMESTORE_RecordData *rd,
1368 const struct GNUNET_CRYPTO_EccSignature *signature)
1370 struct ResolverHandle *rh = cls;
1371 struct GNUNET_TIME_Relative remaining_time;
1374 rh->namestore_task = NULL;
1375 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1377 for (i = 0; i < rd_count; i++)
1379 if (GNUNET_NAMESTORE_TYPE_REV == rd[i].record_type)
1381 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1382 "GNS_PHASE_DELEGATE_REV-%llu: Zone has been revoked.\n",
1384 rh->status |= RSL_PKEY_REVOKED;
1385 rh->proc (rh->proc_cls, rh, 0, NULL);
1390 if ((NULL == name) ||
1391 (0 == remaining_time.rel_value_us))
1393 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1394 "GNS_PHASE_DELEGATE_REV-%llu: + Records don't exist or are expired.\n",
1397 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != rh->timeout.rel_value_us)
1399 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1400 "GNS_PHASE_DELEGATE_REV-%llu: Starting background lookup for %s type %d\n",
1401 rh->id, "+.gads", GNUNET_NAMESTORE_TYPE_REV);
1403 gns_resolver_lookup_record(rh->authority,
1404 rh->private_local_zone,
1405 GNUNET_NAMESTORE_TYPE_REV,
1408 GNUNET_TIME_UNIT_FOREVER_REL,
1410 &background_lookup_result_processor,
1414 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1415 "GNS_PHASE_DELEGATE_REV-%llu: Revocation check passed\n",
1418 * We are done with PKEY resolution if name is empty
1419 * else resolve again with new authority
1421 if (strcmp (rh->name, "") == 0)
1422 rh->proc (rh->proc_cls, rh, rh->rd_count, &rh->rd);
1424 resolve_delegation_ns (rh);
1429 * Function called when we get a result from the dht
1430 * for our query. Recursively tries to resolve authorities
1433 * @param cls the request handle
1434 * @param exp lifetime
1435 * @param key the key the record was stored under
1436 * @param get_path get path
1437 * @param get_path_length get path length
1438 * @param put_path put path
1439 * @param put_path_length put path length
1440 * @param type the block type
1441 * @param size the size of the record
1442 * @param data the record data
1445 process_delegation_result_dht (void* cls,
1446 struct GNUNET_TIME_Absolute exp,
1447 const struct GNUNET_HashCode * key,
1448 const struct GNUNET_PeerIdentity *get_path,
1449 unsigned int get_path_length,
1450 const struct GNUNET_PeerIdentity *put_path,
1451 unsigned int put_path_length,
1452 enum GNUNET_BLOCK_Type type,
1453 size_t size, const void *data)
1455 struct ResolverHandle *rh = cls;
1456 const struct GNSNameRecordBlock *nrb = data;
1457 const char* rd_data;
1458 uint32_t num_records;
1462 struct GNUNET_CRYPTO_ShortHashCode zone;
1464 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1465 "GNS_PHASE_DELEGATE_DHT-%llu: Got DHT result\n",
1469 /* stop dht lookup and timeout task */
1470 GNUNET_DHT_get_stop (rh->get_handle);
1471 rh->get_handle = NULL;
1472 if (rh->dht_heap_node != NULL)
1474 GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
1475 rh->dht_heap_node = NULL;
1478 num_records = ntohl(nrb->rd_count);
1479 name = (const char*) &nrb[1];
1481 struct GNUNET_NAMESTORE_RecordData rd[num_records];
1482 struct NamestoreBGTask *ns_heap_root;
1483 struct NamestoreBGTask *namestore_bg_task;
1485 rd_data = name + strlen(name) + 1;
1486 rd_size = size - strlen(name) - 1 - sizeof (struct GNSNameRecordBlock);
1487 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
1492 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1493 "GNS_PHASE_DELEGATE_DHT-%llu: Error deserializing data!\n",
1498 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1499 "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n",
1500 rh->id, name, rh->authority_name);
1501 for (i=0; i<num_records; i++)
1503 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1504 "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n",
1505 rh->id, name, rh->authority_name);
1506 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1507 "GNS_PHASE_DELEGATE_DHT-%llu: Got type: %d (wanted %d)\n",
1508 rh->id, rd[i].record_type, GNUNET_NAMESTORE_TYPE_PKEY);
1509 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1510 "GNS_PHASE_DELEGATE_DHT-%llu: Got data length: %d\n",
1511 rh->id, rd[i].data_size);
1512 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1513 "GNS_PHASE_DELEGATE_DHT-%llu: Got flag %d\n",
1514 rh->id, rd[i].flags);
1516 if ((GNUNET_NAMESTORE_TYPE_VPN == rd[i].record_type) ||
1517 (GNUNET_DNSPARSER_TYPE_NS == rd[i].record_type) ||
1518 (GNUNET_DNSPARSER_TYPE_CNAME == rd[i].record_type))
1521 * This is a VPN,NS,CNAME entry. Let namestore handle this after caching
1523 if (0 == strcmp(rh->name, ""))
1524 strcpy(rh->name, rh->authority_name);
1526 GNUNET_snprintf(rh->name, GNUNET_DNSPARSER_MAX_NAME_LENGTH, "%s.%s",
1527 rh->name, rh->authority_name); //FIXME ret
1532 if ((0 == strcmp(name, rh->authority_name)) &&
1533 (GNUNET_NAMESTORE_TYPE_PKEY == rd[i].record_type))
1535 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1536 "GNS_PHASE_DELEGATE_DHT-%llu: Authority found in DHT\n",
1539 memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1540 struct AuthorityChain *auth =
1541 GNUNET_malloc(sizeof(struct AuthorityChain));
1542 auth->zone = rh->authority;
1543 memset(auth->name, 0, strlen(rh->authority_name)+1);
1544 strcpy(auth->name, rh->authority_name);
1545 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1546 rh->authority_chain_tail,
1549 if (NULL != rh->rd.data)
1550 GNUNET_free ((void*)rh->rd.data);
1552 memcpy (&rh->rd, &rd[i], sizeof (struct GNUNET_NAMESTORE_RecordData));
1553 rh->rd.data = GNUNET_malloc (rd[i].data_size);
1554 memcpy ((void*)(rh->rd.data), rd[i].data, rd[i].data_size);
1557 /** try to import pkey if private key available */
1558 //if (rh->priv_key && is_canonical (rh->name))
1559 // process_discovered_authority(name, auth->zone,
1560 // rh->authority_chain_tail->zone,
1565 GNUNET_GNS_get_zone_from_key (name, key, &zone);
1568 /* Save to namestore
1569 if (0 != GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1572 if (max_allowed_ns_tasks <=
1573 GNUNET_CONTAINER_heap_get_size (ns_task_heap))
1575 ns_heap_root = GNUNET_CONTAINER_heap_remove_root (ns_task_heap);
1576 GNUNET_NAMESTORE_cancel (ns_heap_root->qe);
1578 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1579 "GNS_PHASE_DELEGATE_DHT-%llu: Replacing oldest background ns task\n",
1582 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1583 "GNS_PHASE_DELEGATE_DHT-%llu: Caching record for %s\n",
1585 namestore_bg_task = GNUNET_malloc (sizeof (struct NamestoreBGTask));
1587 namestore_bg_task->node = GNUNET_CONTAINER_heap_insert (ns_task_heap,
1589 GNUNET_TIME_absolute_get().abs_value_us);
1590 namestore_bg_task->qe = GNUNET_NAMESTORE_record_put (namestore_handle,
1597 &on_namestore_delegation_put_result, //cont
1598 namestore_bg_task); //cls
1602 if (0 != rh->answered)
1607 * FIXME in this case. should we ask namestore again?
1609 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1610 "GNS_PHASE_DELEGATE_DHT-%llu: Answer from DHT for %s. Yet to resolve: %s\n",
1611 rh->id, rh->authority_name, rh->name);
1613 if (0 == strcmp(rh->name, ""))
1615 /* Start shortening */
1616 if ((NULL != rh->priv_key) &&
1617 (GNUNET_YES == is_canonical (rh->name)))
1619 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1620 "GNS_PHASE_DELEGATE_DHT-%llu: Trying to shorten authority chain\n",
1622 start_shorten (rh->authority_chain_head,
1627 rh->proc = &handle_delegation_ns;
1630 /* Check for key revocation and delegate */
1631 rh->namestore_task = GNUNET_NAMESTORE_lookup (namestore_handle,
1633 GNUNET_GNS_MASTERZONE_STR,
1634 GNUNET_NAMESTORE_TYPE_REV,
1635 &process_pkey_revocation_result_ns,
1642 * No pkey but name exists
1645 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1646 "GNS_PHASE_DELEGATE_DHT-%llu: Adding %s back to %s\n",
1647 rh->id, rh->authority_name, rh->name);
1648 if (0 == strcmp(rh->name, ""))
1649 strcpy(rh->name, rh->authority_name);
1651 GNUNET_snprintf(rh->name, GNUNET_DNSPARSER_MAX_NAME_LENGTH, "%s.%s",
1652 rh->name, rh->authority_name); //FIXME ret
1654 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1655 "GNS_PHASE_DELEGATE_DHT-%llu: %s restored\n", rh->id, rh->name);
1656 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1657 "GNS_PHASE_DELEGATE_DHT-%llu: DHT authority lookup found no match!\n",
1659 rh->proc(rh->proc_cls, rh, 0, NULL);
1662 //FIXME maybe define somewhere else?
1663 #define MAX_SOA_LENGTH sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)\
1664 +(GNUNET_DNSPARSER_MAX_NAME_LENGTH*2)
1665 #define MAX_MX_LENGTH sizeof(uint16_t)+GNUNET_DNSPARSER_MAX_NAME_LENGTH
1666 #define MAX_SRV_LENGTH (sizeof(uint16_t)*3)+GNUNET_DNSPARSER_MAX_NAME_LENGTH
1670 * Exands a name ending in .+ with the zone of origin.
1671 * FIXME: funky api: 'dest' must be large enough to hold
1672 * the result; this is a bit yucky...
1674 * @param dest destination buffer
1675 * @param src the .+ name
1676 * @param repl the string to replace the + with
1679 expand_plus (char* dest,
1684 size_t s_len = strlen (src) + 1;
1686 //Eh? I guess this is at least strlen ('x.+') == 3 FIXME
1689 /* no postprocessing */
1690 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1691 "GNS_POSTPROCESS: %s too short\n", src);
1692 memcpy (dest, src, s_len);
1695 if (0 == strcmp (src + s_len - 3, ".+"))
1697 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1698 "GNS_POSTPROCESS: Expanding .+ in %s\n",
1700 memset (dest, 0, s_len + strlen (repl) + strlen(GNUNET_GNS_TLD));
1702 pos = dest + s_len - 2;
1704 pos += strlen (repl);
1705 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1706 "GNS_POSTPROCESS: Expanded to %s\n",
1711 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1712 "GNS_POSTPROCESS: No postprocessing for %s\n", src);
1713 memcpy (dest, src, s_len);
1722 finish_lookup (struct ResolverHandle *rh,
1723 struct RecordLookupHandle* rlh,
1724 unsigned int rd_count,
1725 const struct GNUNET_NAMESTORE_RecordData *rd)
1728 char new_rr_data[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
1729 char new_mx_data[MAX_MX_LENGTH];
1730 char new_soa_data[MAX_SOA_LENGTH];
1731 char new_srv_data[MAX_SRV_LENGTH];
1732 struct srv_data *old_srv;
1733 struct srv_data *new_srv;
1734 struct soa_data *old_soa;
1735 struct soa_data *new_soa;
1736 struct GNUNET_NAMESTORE_RecordData p_rd[rd_count];
1739 unsigned int offset;
1741 if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
1743 GNUNET_SCHEDULER_cancel(rh->timeout_task);
1744 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1747 GNUNET_CONTAINER_DLL_remove (rlh_head, rlh_tail, rh);
1750 memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData));
1752 for (i = 0; i < rd_count; i++)
1755 if ((GNUNET_DNSPARSER_TYPE_NS != rd[i].record_type) &&
1756 (GNUNET_DNSPARSER_TYPE_PTR != rd[i].record_type) &&
1757 (GNUNET_DNSPARSER_TYPE_CNAME != rd[i].record_type) &&
1758 (GNUNET_DNSPARSER_TYPE_MX != rd[i].record_type) &&
1759 (GNUNET_DNSPARSER_TYPE_SOA != rd[i].record_type) &&
1760 (GNUNET_DNSPARSER_TYPE_SRV != rd[i].record_type))
1762 p_rd[i].data = rd[i].data;
1767 * for all those records we 'should'
1768 * also try to resolve the A/AAAA records (RFC1035)
1769 * This is a feature and not important
1772 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1773 "GNS_POSTPROCESS: Postprocessing\n");
1774 if (0 == strcmp(rh->name, GNUNET_GNS_MASTERZONE_STR))
1775 repl_string = rlh->name;
1777 repl_string = rlh->name+strlen(rh->name)+1;
1780 if (GNUNET_DNSPARSER_TYPE_MX == rd[i].record_type)
1782 memcpy (new_mx_data, (char*)rd[i].data, sizeof(uint16_t));
1783 offset = sizeof (uint16_t);
1784 pos = new_mx_data + offset;
1785 // FIXME: how do we know that 'pos' has enough space for the new name?
1786 expand_plus (pos, (char*)rd[i].data+sizeof(uint16_t),
1788 offset += strlen(new_mx_data+sizeof(uint16_t)) + 1;
1789 p_rd[i].data = new_mx_data;
1790 p_rd[i].data_size = offset;
1792 else if (GNUNET_DNSPARSER_TYPE_SRV == rd[i].record_type)
1795 * Prio, weight and port
1797 new_srv = (struct srv_data*)new_srv_data;
1798 old_srv = (struct srv_data*)rd[i].data;
1799 new_srv->prio = old_srv->prio;
1800 new_srv->weight = old_srv->weight;
1801 new_srv->port = old_srv->port;
1802 // FIXME: how do we know that '&new_srv[1]' has enough space for the new name?
1803 expand_plus((char*)&new_srv[1], (char*)&old_srv[1],
1805 p_rd[i].data = new_srv_data;
1806 p_rd[i].data_size = sizeof (struct srv_data) + strlen ((char*)&new_srv[1]) + 1;
1808 else if (GNUNET_DNSPARSER_TYPE_SOA == rd[i].record_type)
1810 /* expand mname and rname */
1811 old_soa = (struct soa_data*)rd[i].data;
1812 new_soa = (struct soa_data*)new_soa_data;
1813 memcpy (new_soa, old_soa, sizeof (struct soa_data));
1814 // FIXME: how do we know that 'new_soa[1]' has enough space for the new name?
1815 expand_plus((char*)&new_soa[1], (char*)&old_soa[1], repl_string);
1816 offset = strlen ((char*)&new_soa[1]) + 1;
1817 // FIXME: how do we know that 'new_soa[1]' has enough space for the new name?
1818 expand_plus((char*)&new_soa[1] + offset,
1819 (char*)&old_soa[1] + strlen ((char*)&old_soa[1]) + 1,
1821 p_rd[i].data_size = sizeof (struct soa_data)
1823 + strlen ((char*)&new_soa[1] + offset);
1824 p_rd[i].data = new_soa_data;
1829 // FIXME: how do we know that 'rd[i].data' has enough space for the new name?
1830 expand_plus(pos, (char*)rd[i].data, repl_string);
1831 p_rd[i].data_size = strlen(new_rr_data)+1;
1832 p_rd[i].data = new_rr_data;
1837 rlh->proc(rlh->proc_cls, rd_count, p_rd);
1839 free_resolver_handle (rh);
1844 * Process DHT lookup result for record.
1846 * @param cls the closure
1847 * @param rh resolver handle
1848 * @param rd_count number of results
1849 * @param rd record data
1852 handle_record_dht (void* cls, struct ResolverHandle *rh,
1853 unsigned int rd_count,
1854 const struct GNUNET_NAMESTORE_RecordData *rd)
1856 struct RecordLookupHandle* rlh = cls;
1860 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1861 "GNS_PHASE_REC-%llu: No records for %s found in DHT. Aborting\n",
1863 /* give up, cannot resolve */
1864 finish_lookup (rh, rlh, 0, NULL);
1867 /* results found yay */
1868 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1869 "GNS_PHASE_REC-%llu: Record resolved from DHT!", rh->id);
1870 finish_lookup (rh, rlh, rd_count, rd);
1875 * Process namestore lookup result for record.
1877 * @param cls the closure
1878 * @param rh resolver handle
1879 * @param rd_count number of results
1880 * @param rd record data
1883 handle_record_ns (void* cls, struct ResolverHandle *rh,
1884 unsigned int rd_count,
1885 const struct GNUNET_NAMESTORE_RecordData *rd)
1887 struct RecordLookupHandle* rlh = cls;
1888 int check_dht = GNUNET_YES;
1892 /* results found yay */
1893 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1894 "GNS_PHASE_REC-%llu: Record resolved from namestore!\n", rh->id);
1895 finish_lookup (rh, rlh, rd_count, rd);
1899 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1900 "GNS_PHASE_REC-%llu: NS returned no records. (status: %d)!\n",
1904 * There are 5 conditions that have to met for us to consult the DHT:
1905 * 1. The entry in the DHT is RSL_RECORD_EXPIRED OR
1906 * 2. No entry in the NS existed AND
1907 * 3. The zone queried is not the local resolver's zone AND
1908 * 4. The name that was looked up is '+'
1909 * because if it was any other canonical name we either already queried
1910 * the DHT for the authority in the authority lookup phase (and thus
1911 * would already have an entry in the NS for the record)
1912 * 5. We are not in cache only mode
1914 if ((0 != (rh->status & RSL_RECORD_EXPIRED)) &&
1915 (0 == (rh->status & RSL_RECORD_EXISTS)) )
1918 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1919 "GNS_PHASE_REC-%llu: Not expired and exists!\n",
1921 check_dht = GNUNET_NO;
1924 if (0 == GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1925 &rh->private_local_zone))
1928 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1929 "GNS_PHASE_REC-%llu: Our zone!\n",
1931 check_dht = GNUNET_NO;
1934 if ((0 != strcmp (rh->name, GNUNET_GNS_MASTERZONE_STR)) && (GNUNET_YES == is_srv (rh->name)))
1935 check_dht = GNUNET_NO;
1937 if (GNUNET_YES == rh->only_cached)
1938 check_dht = GNUNET_NO;
1940 if (GNUNET_YES == check_dht)
1942 rh->proc = &handle_record_dht;
1943 resolve_record_dht(rh);
1946 /* give up, cannot resolve */
1947 finish_lookup (rh, rlh, 0, NULL);
1952 * Move one level up in the domain hierarchy and return the
1953 * passed top level domain.
1955 * FIXME: funky API: not only 'dest' is updated, so is 'name'!
1957 * @param name the domain
1958 * @param dest the destination where the tld will be put
1961 pop_tld (char* name, char* dest)
1965 if (GNUNET_YES == is_canonical (name))
1967 strcpy (dest, name);
1972 for (len = strlen(name); 0 < len; len--)
1974 if (*(name+len) == '.')
1982 strcpy (dest, (name+len+1));
1987 * DHT resolution for delegation finished. Processing result.
1989 * @param cls the closure
1990 * @param rh resolver handle
1991 * @param rd_count number of results (always 0)
1992 * @param rd record data (always NULL)
1995 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
1996 unsigned int rd_count,
1997 const struct GNUNET_NAMESTORE_RecordData *rd)
1999 struct RecordLookupHandle* rlh = cls;
2001 if (0 == strcmp(rh->name, ""))
2003 if (GNUNET_NAMESTORE_TYPE_PKEY == rlh->record_type)
2005 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2006 "GNS_PHASE_DELEGATE_DHT-%llu: Resolved queried PKEY via DHT.\n",
2008 finish_lookup(rh, rlh, rd_count, rd);
2011 /* We resolved full name for delegation. resolving record */
2012 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2013 "GNS_PHASE_DELEGATE_DHT-%llu: Resolved full name for delegation via DHT.\n",
2015 strcpy(rh->name, "+\0");
2016 rh->proc = &handle_record_ns;
2017 resolve_record_ns(rh);
2022 * we still have some left
2024 if (GNUNET_YES == is_canonical (rh->name))
2026 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2027 "GNS_PHASE_DELEGATE_DHT-%llu: Resolving canonical record %s in ns\n",
2030 rh->proc = &handle_record_ns;
2031 resolve_record_ns(rh);
2034 /* give up, cannot resolve */
2035 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2036 "GNS_PHASE_DELEGATE_DHT-%llu: Cannot fully resolve delegation for %s via DHT!\n",
2038 finish_lookup(rh, rlh, 0, NULL);
2043 * Start DHT lookup for a name -> PKEY (compare NS) record in
2044 * rh->authority's zone
2046 * @param rh the pending gns query
2049 resolve_delegation_dht (struct ResolverHandle *rh)
2052 struct GNUNET_HashCode lookup_key;
2053 struct ResolverHandle *rh_heap_root;
2055 pop_tld (rh->name, rh->authority_name);
2056 GNUNET_GNS_get_key_for_record (rh->authority_name,
2059 rh->dht_heap_node = NULL;
2060 if (rh->timeout.rel_value_us != GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
2062 rh->timeout_cont = &dht_authority_lookup_timeout;
2063 rh->timeout_cont_cls = rh;
2067 if (max_allowed_background_queries <=
2068 GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
2070 /* terminate oldest lookup */
2071 rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
2072 GNUNET_DHT_get_stop (rh_heap_root->get_handle);
2073 rh_heap_root->get_handle = NULL;
2074 rh_heap_root->dht_heap_node = NULL;
2075 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2076 "GNS_PHASE_DELEGATE_DHT-%llu: Replacing oldest background query for %s\n",
2078 rh_heap_root->authority_name);
2079 rh_heap_root->proc (rh_heap_root->proc_cls,
2084 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
2086 GNUNET_TIME_absolute_get().abs_value_us);
2088 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2089 "Beginning DHT lookup for %s in zone %s for request %llu\n",
2091 GNUNET_short_h2s (&rh->authority),
2093 xquery = htonl (GNUNET_NAMESTORE_TYPE_PKEY);
2094 GNUNET_assert (rh->get_handle == NULL);
2095 rh->get_handle = GNUNET_DHT_get_start (dht_handle,
2096 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
2098 DHT_GNS_REPLICATION_LEVEL,
2099 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
2102 &process_delegation_result_dht,
2108 * Namestore resolution for delegation finished. Processing result.
2110 * @param cls the closure
2111 * @param rh resolver handle
2112 * @param rd_count number of results (always 0)
2113 * @param rd record data (always NULL)
2116 handle_delegation_ns (void* cls, struct ResolverHandle *rh,
2117 unsigned int rd_count,
2118 const struct GNUNET_NAMESTORE_RecordData *rd)
2120 struct RecordLookupHandle* rlh = cls;
2124 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2125 "GNS_PHASE_DELEGATE_NS-%llu: Resolution status: %d.\n",
2126 rh->id, rh->status);
2128 if (rh->status & RSL_PKEY_REVOKED)
2130 finish_lookup (rh, rlh, 0, NULL);
2134 if (0 == strcmp(rh->name, ""))
2137 /* We resolved full name for delegation. resolving record */
2138 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2139 "GNS_PHASE_DELEGATE_NS-%llu: Resolved full name for delegation.\n",
2141 if (rh->status & RSL_CNAME_FOUND)
2143 if (GNUNET_DNSPARSER_TYPE_CNAME == rlh->record_type)
2145 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2146 "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried CNAME in NS.\n",
2148 strcpy (rh->name, rh->authority_name);
2149 finish_lookup (rh, rlh, rd_count, rd);
2154 if (GNUNET_YES == is_tld ((char*)rd->data, GNUNET_GNS_TLD_PLUS))
2156 s_len = strlen (rd->data) - 2;
2157 memcpy (rh->name, rd->data, s_len);
2158 rh->name[s_len] = '\0';
2159 resolve_delegation_ns (rh);
2162 else if (GNUNET_YES == is_tld ((char*)rd->data, GNUNET_GNS_TLD_ZKEY))
2164 gns_resolver_lookup_record (rh->authority,
2165 rh->private_local_zone,
2174 GNUNET_CONTAINER_DLL_remove (rlh_head, rlh_tail, rh);
2175 free_resolver_handle (rh);
2181 strcpy (rh->dns_name, (char*)rd->data);
2182 resolve_dns_name (rh);
2187 else if (rh->status & RSL_DELEGATE_VPN)
2189 if (GNUNET_NAMESTORE_TYPE_VPN == rlh->record_type)
2191 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2192 "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried VPNRR in NS.\n",
2194 finish_lookup(rh, rlh, rd_count, rd);
2197 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2198 "GNS_PHASE_DELEGATE_NS-%llu: VPN delegation starting.\n",
2200 GNUNET_assert (NULL != rd);
2201 rh->proc = &handle_record_vpn;
2202 resolve_record_vpn (rh, rd_count, rd);
2205 else if (rh->status & RSL_DELEGATE_NS)
2207 if (GNUNET_DNSPARSER_TYPE_NS == rlh->record_type)
2209 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2210 "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried NSRR in NS.\n",
2212 finish_lookup (rh, rlh, rd_count, rd);
2215 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2216 "GNS_PHASE_DELEGATE_NS-%llu: NS delegation starting.\n",
2218 GNUNET_assert (NULL != rd);
2219 rh->proc = &handle_record_ns;
2220 resolve_record_dns (rh, rd_count, rd);
2223 else if (rh->status & RSL_DELEGATE_PKEY)
2225 if (rh->status & RSL_PKEY_REVOKED)
2227 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2228 "GNS_PHASE_DELEGATE_NS-%llu: Resolved PKEY is revoked.\n",
2230 finish_lookup (rh, rlh, 0, NULL);
2233 else if (GNUNET_NAMESTORE_TYPE_PKEY == rlh->record_type)
2235 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2236 "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried PKEY in NS.\n",
2238 finish_lookup(rh, rlh, rd_count, rd);
2242 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2243 "GNS_PHASE_DELEGATE_NS-%llu: Resolving record +\n",
2245 strcpy(rh->name, "+\0");
2246 rh->proc = &handle_record_ns;
2247 resolve_record_ns(rh);
2251 if (rh->status & RSL_DELEGATE_NS)
2253 if (GNUNET_DNSPARSER_TYPE_NS == rlh->record_type)
2255 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2256 "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried NSRR in NS.\n",
2258 finish_lookup(rh, rlh, rd_count, rd);
2262 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2263 "GNS_PHASE_DELEGATE_NS-%llu: NS delegation starting.\n",
2265 GNUNET_assert (NULL != rd);
2266 rh->proc = &handle_record_ns;
2267 resolve_record_dns (rh, rd_count, rd);
2272 * we still have some left
2273 * check if authority in ns is fresh
2275 * or we are authority
2278 check_dht = GNUNET_YES;
2279 if ((rh->status & RSL_RECORD_EXISTS) &&
2280 !(rh->status & RSL_RECORD_EXPIRED))
2281 check_dht = GNUNET_NO;
2283 if (0 == GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2284 &rh->private_local_zone))
2285 check_dht = GNUNET_NO;
2287 if (GNUNET_YES == rh->only_cached)
2288 check_dht = GNUNET_NO;
2290 if (GNUNET_YES == check_dht)
2293 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2294 "GNS_PHASE_DELEGATE_NS-%llu: Trying to resolve delegation for %s via DHT\n",
2296 rh->proc = &handle_delegation_dht;
2297 resolve_delegation_dht(rh);
2301 if (GNUNET_NO == is_canonical (rh->name))
2303 /* give up, cannot resolve */
2304 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2305 "GNS_PHASE_DELEGATE_NS-%llu: Cannot fully resolve delegation for %s!\n",
2308 finish_lookup(rh, rlh, rd_count, rd);
2311 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2312 "GNS_PHASE_DELEGATE_NS-%llu: Resolving canonical record %s\n",
2315 rh->proc = &handle_record_ns;
2316 resolve_record_ns(rh);
2321 * This is a callback function that should give us only PKEY
2322 * records. Used to query the namestore for the authority (PKEY)
2323 * for 'name'. It will recursively try to resolve the
2324 * authority for a given name from the namestore.
2326 * @param cls the pending query
2327 * @param key the key of the zone we did the lookup
2328 * @param expiration expiration date of the record data set in the namestore
2329 * @param name the name for which we need an authority
2330 * @param rd_count the number of records with 'name'
2331 * @param rd the record data
2332 * @param signature the signature of the authority for the record data
2335 process_delegation_result_ns (void* cls,
2336 const struct GNUNET_CRYPTO_EccPublicKey *key,
2337 struct GNUNET_TIME_Absolute expiration,
2339 unsigned int rd_count,
2340 const struct GNUNET_NAMESTORE_RecordData *rd,
2341 const struct GNUNET_CRYPTO_EccSignature *signature)
2343 struct ResolverHandle *rh = cls;
2344 struct GNUNET_TIME_Relative remaining_time;
2345 struct GNUNET_CRYPTO_ShortHashCode zone;
2346 char new_name[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
2348 struct GNUNET_TIME_Absolute et;
2349 struct AuthorityChain *auth;
2351 rh->namestore_task = NULL;
2352 GNUNET_CRYPTO_short_hash (key,
2353 sizeof (struct GNUNET_CRYPTO_EccPublicKey),
2355 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2356 "GNS_PHASE_DELEGATE_NS-%llu: Got %d records from authority lookup for `%s' in zone %s\n",
2359 GNUNET_short_h2s (&zone));
2361 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
2367 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2368 "GNS_PHASE_DELEGATE_NS-%llu: Records with name `%s' exist in zone %s.\n",
2370 GNUNET_short_h2s (&zone));
2371 rh->status |= RSL_RECORD_EXISTS;
2373 if (0 == remaining_time.rel_value_us)
2375 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2376 "GNS_PHASE_DELEGATE_NS-%llu: Record set %s expired.\n",
2378 rh->status |= RSL_RECORD_EXPIRED;
2383 * No authority found in namestore.
2388 * We did not find an authority in the namestore
2393 * Promote this authority back to a name maybe it is
2396 if (strcmp (rh->name, "") == 0)
2398 /* simply promote back */
2399 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2400 "GNS_PHASE_DELEGATE_NS-%llu: Promoting %s back to name\n",
2401 rh->id, rh->authority_name);
2402 strcpy (rh->name, rh->authority_name);
2406 /* add back to existing name */
2407 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2408 "GNS_PHASE_DELEGATE_NS-%llu: Adding %s back to %s\n",
2409 rh->id, rh->authority_name, rh->name);
2410 GNUNET_snprintf (new_name, GNUNET_DNSPARSER_MAX_NAME_LENGTH, "%s.%s",
2411 rh->name, rh->authority_name);
2412 strcpy (rh->name, new_name);
2413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2414 "GNS_PHASE_DELEGATE_NS-%llu: %s restored\n",
2418 rh->proc (rh->proc_cls, rh, 0, NULL);
2423 * We found an authority that may be able to help us
2424 * move on with query
2425 * Note only 1 pkey should have been returned.. anything else would be strange
2427 for (i=0; i < rd_count;i++)
2429 switch (rd[i].record_type)
2431 case GNUNET_DNSPARSER_TYPE_CNAME:
2432 /* Like in regular DNS this should mean that there is no other
2433 * record for this name. */
2435 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2436 "GNS_PHASE_DELEGATE_NS-%llu: CNAME `%.*s' found.\n",
2438 (int) rd[i].data_size,
2440 rh->status |= RSL_CNAME_FOUND;
2441 rh->proc (rh->proc_cls, rh, rd_count, rd);
2443 case GNUNET_NAMESTORE_TYPE_VPN:
2444 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2445 "GNS_PHASE_DELEGATE_NS-%llu: VPN found.\n",
2447 rh->status |= RSL_DELEGATE_VPN;
2448 rh->proc (rh->proc_cls, rh, rd_count, rd);
2450 case GNUNET_DNSPARSER_TYPE_NS:
2451 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2452 "GNS_PHASE_DELEGATE_NS-%llu: NS `%.*s' found.\n",
2454 (int) rd[i].data_size,
2456 rh->status |= RSL_DELEGATE_NS;
2457 rh->proc (rh->proc_cls, rh, rd_count, rd);
2459 case GNUNET_NAMESTORE_TYPE_PKEY:
2460 rh->status |= RSL_DELEGATE_PKEY;
2461 if ((ignore_pending_records != 0) &&
2462 (rd[i].flags & GNUNET_NAMESTORE_RF_PENDING))
2464 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2465 "GNS_PHASE_DELEGATE_NS-%llu: PKEY for %s is pending user confirmation.\n",
2470 GNUNET_break (0 == (rd[i].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION));
2471 et.abs_value_us = rd[i].expiration_time;
2472 if (0 == (GNUNET_TIME_absolute_get_remaining (et)).rel_value_us)
2474 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2475 "GNS_PHASE_DELEGATE_NS-%llu: This pkey is expired.\n",
2477 if (remaining_time.rel_value_us == 0)
2479 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2480 "GNS_PHASE_DELEGATE_NS-%llu: This dht entry is expired.\n",
2482 rh->authority_chain_head->fresh = 0;
2483 rh->proc (rh->proc_cls, rh, 0, NULL);
2488 /* Resolve rest of query with new authority */
2489 memcpy (&rh->authority, rd[i].data,
2490 sizeof (struct GNUNET_CRYPTO_ShortHashCode));
2491 auth = GNUNET_malloc(sizeof (struct AuthorityChain));
2492 auth->zone = rh->authority;
2493 memset (auth->name, 0, strlen (rh->authority_name)+1);
2494 strcpy (auth->name, rh->authority_name);
2495 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
2496 rh->authority_chain_tail,
2498 if (NULL != rh->rd.data)
2499 GNUNET_free ((void*)(rh->rd.data));
2500 memcpy (&rh->rd, &rd[i], sizeof (struct GNUNET_NAMESTORE_RecordData));
2501 rh->rd.data = GNUNET_malloc (rd[i].data_size);
2502 memcpy ((void*)rh->rd.data, rd[i].data, rd[i].data_size);
2504 /* Check for key revocation and delegate */
2505 rh->namestore_task = GNUNET_NAMESTORE_lookup (namestore_handle,
2507 GNUNET_GNS_MASTERZONE_STR,
2508 GNUNET_NAMESTORE_TYPE_REV,
2509 &process_pkey_revocation_result_ns,
2513 /* ignore, move to next result */
2518 /* no answers that would cause delegation were found */
2519 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2520 "GNS_PHASE_DELEGATE_NS-%llu: Authority lookup failed (no PKEY record)\n",
2523 * If we have found some records for the LAST label
2524 * we return the results. Else NULL.
2526 if (0 == strcmp (rh->name, ""))
2528 /* Start shortening */
2529 if ((rh->priv_key != NULL) &&
2530 (is_canonical (rh->name) == GNUNET_YES))
2532 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2533 "GNS_PHASE_DELEGATE_NS-%llu: Trying to shorten authority chain\n",
2535 start_shorten (rh->authority_chain_head,
2538 /* simply promote back */
2539 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2540 "GNS_PHASE_DELEGATE_NS-%llu: Promoting %s back to name\n",
2541 rh->id, rh->authority_name);
2542 strcpy (rh->name, rh->authority_name);
2543 rh->proc (rh->proc_cls, rh, rd_count, rd);
2547 GNUNET_snprintf (new_name, GNUNET_DNSPARSER_MAX_NAME_LENGTH,
2548 "%s.%s", rh->name, rh->authority_name);
2549 strcpy (rh->name, new_name);
2550 rh->proc (rh->proc_cls, rh, 0, NULL);
2557 ///////////////////////////////////////////////////////////////////////////////////////////////////
2558 ///////////////////////////////////////////////////////////////////////////////////////////////////
2559 ///////////////////////////////////////////////////////////////////////////////////////////////////
2560 ///////////////////////////////////////////////////////////////////////////////////////////////////
2561 ///////////////////////////////////////////////////////////////////////////////////////////////////
2565 * Task scheduled to asynchronously fail a resolution.
2567 * @param cls the 'struct GNS_ResolverHandle' of the resolution to fail
2568 * @param tc task context
2571 fail_resolution (void *cls,
2572 const struct GNUNET_SCHEDULER_TaskContext *tc)
2574 struct GNS_ResolverHandle *rh = cls;
2576 rh->task_id = GNUNET_SCHEDULER_NO_TASK;
2577 rh->proc (rh->proc_cls, 0, NULL);
2578 GNS_resolver_lookup_cancel (rh);
2583 * Get the next, rightmost label from the name that we are trying to resolve,
2584 * and update the resolution position accordingly.
2586 * @param rh handle to the resolution operation to get the next label from
2587 * @return NULL if there are no more labels
2590 resolver_lookup_get_next_label (struct GNS_ResolverHandle *rh)
2596 if (0 == rh->name_resolution_pos)
2598 dot = memrchr (rh->name, (int) '.', rh->name_resolution_pos);
2601 /* done, this was the last one */
2602 len = rh->name_resolution_pos;
2604 rh->name_resolution_pos = 0;
2608 /* advance by one label */
2609 len = rh->name_resolution_pos - (dot - rh->name) - 1;
2611 rh->name_resolution_pos = dot - rh->name;
2613 return GNUNET_strndup (rp, len);
2618 * Gives the cummulative result obtained to the callback and clean up the request.
2620 * @param rh resolution process that has culminated in a result
2623 transmit_lookup_dns_result (struct GNS_ResolverHandle *rh)
2625 struct DnsResult *pos;
2630 for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
2633 struct GNUNET_NAMESTORE_RecordData rd[n];
2636 for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
2638 rd[i].data = pos->data;
2639 rd[i].data_size = pos->data_size;
2640 rd[i].record_type = pos->record_type;
2641 if (0 == pos->expiration_time)
2643 rd[i].flags = GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION;
2644 rd[i].expiration_time = 0;
2648 rd[i].flags = GNUNET_NAMESTORE_RF_NONE;
2649 rd[i].expiration_time = pos->expiration_time;
2652 rh->proc (rh->proc_cls,
2656 GNS_resolver_lookup_cancel (rh);
2661 * Add a result from DNS to the records to be returned to the application.
2663 * @param rh resolution request to extend with a result
2664 * @param expiration_time expiration time for the answer
2665 * @param record_type DNS record type of the answer
2666 * @param data_size number of bytes in @a data
2667 * @param data binary data to return in DNS record
2670 add_dns_result (struct GNS_ResolverHandle *rh,
2671 uint64_t expiration_time,
2672 uint32_t record_type,
2676 struct DnsResult *res;
2678 res = GNUNET_malloc (sizeof (struct DnsResult) + data_size);
2679 res->expiration_time = expiration_time;
2680 res->data_size = data_size;
2681 res->record_type = record_type;
2682 res->data = &res[1];
2683 memcpy (&res[1], data, data_size);
2684 GNUNET_CONTAINER_DLL_insert (rh->dns_result_head,
2685 rh->dns_result_tail,
2691 * We had to do a DNS lookup. Convert the result (if any) and return
2694 * @param cls closure with the 'struct GNS_ResolverHandle'
2695 * @param addr one of the addresses of the host, NULL for the last address
2696 * @param addrlen length of the address
2699 handle_dns_result (void *cls,
2700 const struct sockaddr *addr,
2703 struct GNS_ResolverHandle *rh = cls;
2704 const struct sockaddr_in *sa4;
2705 const struct sockaddr_in6 *sa6;
2707 rh->std_resolve = NULL;
2710 transmit_lookup_dns_result (rh);
2713 switch (addr->sa_family)
2716 sa4 = (const struct sockaddr_in *) addr;
2718 0 /* expiration time is unknown */,
2719 GNUNET_DNSPARSER_TYPE_A,
2720 sizeof (struct in_addr),
2724 sa6 = (const struct sockaddr_in6 *) addr;
2726 0 /* expiration time is unknown */,
2727 GNUNET_DNSPARSER_TYPE_AAAA,
2728 sizeof (struct in6_addr),
2739 * Task scheduled to continue with the resolution process.
2741 * @param cls the 'struct GNS_ResolverHandle' of the resolution
2742 * @param tc task context
2745 recursive_resolution (void *cls,
2746 const struct GNUNET_SCHEDULER_TaskContext *tc);
2750 * Function called with the result of a DNS resolution.
2752 * @param cls the request handle of the resolution that
2753 * we were attempting to make
2754 * @param rs socket that received the response
2755 * @param dns dns response, never NULL
2756 * @param dns_len number of bytes in 'dns'
2759 dns_result_parser (void *cls,
2760 struct GNUNET_DNSSTUB_RequestSocket *rs,
2761 const struct GNUNET_TUN_DnsHeader *dns,
2764 struct GNS_ResolverHandle *rh = cls;
2765 struct GNUNET_DNSPARSER_Packet *p;
2767 rh->dns_request = NULL;
2768 GNUNET_SCHEDULER_cancel (rh->task_id);
2769 rh->task_id = GNUNET_SCHEDULER_NO_TASK;
2770 p = GNUNET_DNSPARSER_parse ((const char *) dns,
2774 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2775 _("Failed to parse DNS response\n"));
2776 rh->proc (rh->proc_cls, 0, NULL);
2777 GNS_resolver_lookup_cancel (rh);
2781 // Check if the packet is the final answer, or
2782 // just pointing us to another NS or another name (CNAME), or another domain (DNAME);
2783 // then do the right thing (TM) -- possibly using "recursive_dns_resolution".
2785 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2786 _("NOT IMPLEMENTED\n"));
2787 rh->proc (rh->proc_cls, 0, NULL);
2788 GNS_resolver_lookup_cancel (rh);
2791 GNUNET_DNSPARSER_free_packet (p);
2796 * Perform recursive DNS resolution. Asks the given DNS resolver to
2797 * resolve "rh->dns_name", possibly recursively proceeding following
2798 * NS delegations, CNAMES, etc., until 'rh->loop_limiter' bounds us or
2799 * we find the answer.
2801 * @param rh resolution information
2804 recursive_dns_resolution (struct GNS_ResolverHandle *rh)
2806 struct AuthorityChain *ac;
2808 struct GNUNET_DNSPARSER_Query *query;
2809 struct GNUNET_DNSPARSER_Packet *p;
2811 size_t dns_request_length;
2814 GNUNET_assert (NULL != ac);
2815 GNUNET_assert (GNUNET_NO == ac->gns_authority);
2816 switch (((const struct sockaddr *) &ac->authority_info.dns_authority.dns_ip)->sa_family)
2819 sa_len = sizeof (struct sockaddr_in);
2822 sa_len = sizeof (struct sockaddr_in6);
2826 rh->proc (rh->proc_cls, 0, NULL);
2827 GNS_resolver_lookup_cancel (rh);
2830 query = GNUNET_new (struct GNUNET_DNSPARSER_Query);
2831 query->name = GNUNET_strdup (ac->label);
2832 query->type = rh->record_type;
2833 query->class = GNUNET_DNSPARSER_CLASS_INTERNET;
2834 p = GNUNET_new (struct GNUNET_DNSPARSER_Packet);
2837 p->id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
2839 p->flags.opcode = GNUNET_DNSPARSER_OPCODE_QUERY;
2840 p->flags.recursion_desired = 1;
2842 GNUNET_DNSPARSER_pack (p, 1024, &dns_request, &dns_request_length))
2845 rh->proc (rh->proc_cls, 0, NULL);
2846 GNS_resolver_lookup_cancel (rh);
2850 rh->dns_request = GNUNET_DNSSTUB_resolve (dns_handle,
2851 (const struct sockaddr *) &ac->authority_info.dns_authority.dns_ip,
2857 rh->task_id = GNUNET_SCHEDULER_add_delayed (DNS_LOOKUP_TIMEOUT,
2861 GNUNET_free (dns_request);
2862 GNUNET_DNSPARSER_free_packet (p);
2867 * Process a records that were decrypted from a block.
2869 * @param cls closure with the 'struct GNS_ResolverHandle'
2870 * @param rd_count number of entries in @a rd array
2871 * @param rd array of records with data to store
2874 handle_gns_resolution_result (void *cls,
2875 unsigned int rd_count,
2876 const struct GNUNET_NAMESTORE_RecordData *rd)
2878 struct GNS_ResolverHandle *rh = cls;
2880 // FIXME: not implemented
2881 // if this was the last label, return 'rd' to application
2882 // (possibly first checking about converting records
2883 // to requested type, if possible).
2884 // if not, look for PKEY, CNAME, DNAME or NS to extend
2885 // auth chain and continue with recursion
2887 rh->proc (rh->proc_cls, 0, NULL);
2888 GNS_resolver_lookup_cancel (rh);
2893 * Function called once the namestore has completed the request for
2896 * @param cls closure with the 'struct GNS_ResolverHandle'
2897 * @param success #GNUNET_OK on success
2898 * @param emsg error message
2901 namestore_cache_continuation (void *cls,
2905 struct GNS_ResolverHandle *rh = cls;
2907 rh->namestore_qe = NULL;
2909 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2910 _("Failed to cache GNS resolution: %s\n"),
2916 * Iterator called on each result obtained for a DHT
2917 * operation that expects a reply
2919 * @param cls closure with the 'struct GNS_ResolverHandle'
2920 * @param exp when will this value expire
2921 * @param key key of the result
2922 * @param get_path peers on reply path (or NULL if not recorded)
2923 * [0] = datastore's first neighbor, [length - 1] = local peer
2924 * @param get_path_length number of entries in get_path
2925 * @param put_path peers on the PUT path (or NULL if not recorded)
2926 * [0] = origin, [length - 1] = datastore
2927 * @param put_path_length number of entries in get_path
2928 * @param type type of the result
2929 * @param size number of bytes in data
2930 * @param data pointer to the result data
2933 handle_dht_response (void *cls,
2934 struct GNUNET_TIME_Absolute exp,
2935 const struct GNUNET_HashCode * key,
2936 const struct GNUNET_PeerIdentity *get_path,
2937 unsigned int get_path_length,
2938 const struct GNUNET_PeerIdentity *put_path,
2939 unsigned int put_path_length,
2940 enum GNUNET_BLOCK_Type type,
2941 size_t size, const void *data)
2943 struct GNS_ResolverHandle *rh = cls;
2944 struct AuthorityChain *ac = rh->ac_tail;
2945 const struct GNUNET_NAMESTORE_Block *block;
2947 GNUNET_DHT_get_stop (rh->get_handle);
2948 rh->get_handle = NULL;
2949 GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
2950 rh->dht_heap_node = NULL;
2951 if (size < sizeof (struct GNUNET_NAMESTORE_Block))
2953 /* how did this pass DHT block validation!? */
2955 rh->proc (rh->proc_cls, 0, NULL);
2956 GNS_resolver_lookup_cancel (rh);
2961 ntohs (block->purpose.size) +
2962 sizeof (struct GNUNET_CRYPTO_EccPublicKey) +
2963 sizeof (struct GNUNET_CRYPTO_EccSignature))
2965 /* how did this pass DHT block validation!? */
2967 rh->proc (rh->proc_cls, 0, NULL);
2968 GNS_resolver_lookup_cancel (rh);
2972 GNUNET_NAMESTORE_block_decrypt (block,
2973 &ac->authority_info.gns_authority,
2975 &handle_gns_resolution_result,
2978 GNUNET_break_op (0); /* block was ill-formed */
2979 rh->proc (rh->proc_cls, 0, NULL);
2980 GNS_resolver_lookup_cancel (rh);
2983 /* Cache well-formed blocks */
2984 rh->namestore_qe = GNUNET_NAMESTORE_block_cache (namestore_handle,
2986 &namestore_cache_continuation,
2992 * Process a record that was stored in the namestore.
2994 * @param cls closure with the 'struct GNS_ResolverHandle'
2995 * @param block block that was stored in the namestore
2998 handle_namestore_block_response (void *cls,
2999 const struct GNUNET_NAMESTORE_Block *block)
3001 struct GNS_ResolverHandle *rh = cls;
3002 struct GNS_ResolverHandle *rx;
3003 struct AuthorityChain *ac = rh->ac_tail;
3004 const char *label = ac->label;
3005 const struct GNUNET_CRYPTO_EccPublicKey *auth = &ac->authority_info.gns_authority;
3006 struct GNUNET_HashCode query;
3008 GNUNET_NAMESTORE_query_from_public_key (auth,
3011 rh->namestore_qe = NULL;
3014 /* Namestore knows nothing; try DHT lookup */
3015 rh->get_handle = GNUNET_DHT_get_start (dht_handle,
3016 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
3018 DHT_GNS_REPLICATION_LEVEL,
3019 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
3021 &handle_dht_response, rh);
3022 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
3024 GNUNET_TIME_absolute_get ().abs_value_us);
3025 if (GNUNET_CONTAINER_heap_get_size (dht_lookup_heap) > max_allowed_background_queries)
3027 /* fail longest-standing DHT request */
3028 rx = GNUNET_CONTAINER_heap_peek (dht_lookup_heap);
3029 rx->proc (rx->proc_cls, 0, NULL);
3030 GNS_resolver_lookup_cancel (rx);
3035 GNUNET_NAMESTORE_block_decrypt (block,
3038 &handle_gns_resolution_result,
3041 GNUNET_break_op (0); /* block was ill-formed */
3042 rh->proc (rh->proc_cls, 0, NULL);
3043 GNS_resolver_lookup_cancel (rh);
3050 * Lookup tail of our authority chain in the namestore.
3052 * @param rh query we are processing
3055 recursive_gns_resolution_namestore (struct GNS_ResolverHandle *rh)
3057 struct AuthorityChain *ac = rh->ac_tail;
3058 struct GNUNET_HashCode query;
3060 GNUNET_NAMESTORE_query_from_public_key (&ac->authority_info.gns_authority,
3063 rh->namestore_qe = GNUNET_NAMESTORE_lookup_block (namestore_handle,
3065 &handle_namestore_block_response,
3071 * Task scheduled to continue with the resolution process.
3073 * @param cls the 'struct GNS_ResolverHandle' of the resolution
3074 * @param tc task context
3077 recursive_resolution (void *cls,
3078 const struct GNUNET_SCHEDULER_TaskContext *tc)
3080 struct GNS_ResolverHandle *rh = cls;
3082 rh->task_id = GNUNET_SCHEDULER_NO_TASK;
3083 if (MAX_RECURSION < rh->loop_limiter++)
3085 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3086 "Encountered unbounded recursion resolving `%s'\n",
3088 rh->proc (rh->proc_cls, 0, NULL);
3089 GNS_resolver_lookup_cancel (rh);
3092 if (GNUNET_YES == rh->ac_tail->gns_authority)
3093 recursive_gns_resolution_namestore (rh);
3095 recursive_dns_resolution (rh);
3100 * Lookup of a record in a specific zone calls lookup result processor
3103 * @param zone the zone to perform the lookup in
3104 * @param record_type the record type to look up
3105 * @param name the name to look up
3106 * @param shorten_key a private key for use with PSEU import (can be NULL)
3107 * @param only_cached GNUNET_NO to only check locally not DHT for performance
3108 * @param proc the processor to call on result
3109 * @param proc_cls the closure to pass to @a proc
3110 * @return handle to cancel operation
3112 struct GNS_ResolverHandle *
3113 GNS_resolver_lookup (const struct GNUNET_CRYPTO_EccPublicKey *zone,
3114 uint32_t record_type,
3116 const struct GNUNET_CRYPTO_EccPrivateKey *shorten_key,
3118 GNS_ResultProcessor proc, void *proc_cls)
3120 struct GNS_ResolverHandle *rh;
3121 struct AuthorityChain *ac;
3126 rh = GNUNET_new (struct GNS_ResolverHandle);
3127 GNUNET_CONTAINER_DLL_insert (rlh_head,
3130 rh->authority_zone = *zone;
3132 rh->proc_cls = proc_cls;
3133 rh->only_cached = only_cached;
3134 rh->record_type = record_type;
3135 rh->name = GNUNET_strdup (name);
3136 rh->name_resolution_pos = strlen (name);
3137 if (NULL != shorten_key)
3139 rh->shorten_key = GNUNET_new (struct GNUNET_CRYPTO_EccPrivateKey);
3140 *rh->shorten_key = *shorten_key;
3143 if ( ( (GNUNET_YES == is_canonical (name)) &&
3144 (0 != strcmp (GNUNET_GNS_TLD, name)) ) ||
3145 ( (GNUNET_YES != is_gads_tld (name)) &&
3146 (GNUNET_YES != is_zkey_tld (name)) ) )
3148 /* use standard DNS lookup */
3151 switch (record_type)
3153 case GNUNET_DNSPARSER_TYPE_A:
3156 case GNUNET_DNSPARSER_TYPE_AAAA:
3163 rh->std_resolve = GNUNET_RESOLVER_ip_get (name,
3170 if (is_zkey_tld (name))
3172 /* Name ends with ".zkey", try to replace authority zone with zkey
3174 GNUNET_free (resolver_lookup_get_next_label (rh)); /* will return "zkey" */
3175 x = resolver_lookup_get_next_label (rh); /* will return 'x' coordinate */
3176 y = resolver_lookup_get_next_label (rh); /* will return 'y' coordinate */
3177 GNUNET_asprintf (&pkey,
3183 GNUNET_CRYPTO_ecc_public_key_from_string (pkey,
3185 &rh->authority_zone)) )
3187 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3188 _("Hostname `%s' is not well-formed, resolution fails\n"),
3190 rh->task_id = GNUNET_SCHEDULER_add_now (&fail_resolution, rh);
3192 GNUNET_free_non_null (x);
3193 GNUNET_free_non_null (y);
3198 /* Name ends with ".gnu", eat ".gnu" and continue with resolution */
3199 GNUNET_free (resolver_lookup_get_next_label (rh));
3201 ac = GNUNET_new (struct AuthorityChain);
3203 ac->label = resolver_lookup_get_next_label (rh);
3204 if (NULL == ac->label)
3205 /* name was just "gnu", so we default to label '+' */
3206 ac->label = GNUNET_strdup (GNUNET_GNS_MASTERZONE_STR);
3207 ac->gns_authority = GNUNET_YES;
3208 ac->authority_info.gns_authority = rh->authority_zone;
3209 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
3212 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
3219 * Cancel active resolution (i.e. client disconnected).
3221 * @param rh resolution to abort
3224 GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
3226 struct DnsResult *dr;
3227 struct AuthorityChain *ac;
3229 GNUNET_CONTAINER_DLL_remove (rlh_head,
3232 while (NULL != (ac = rh->ac_head))
3234 GNUNET_CONTAINER_DLL_remove (rh->ac_head,
3237 GNUNET_free (ac->label);
3240 if (GNUNET_SCHEDULER_NO_TASK != rh->task_id)
3242 GNUNET_SCHEDULER_cancel (rh->task_id);
3243 rh->task_id = GNUNET_SCHEDULER_NO_TASK;
3245 if (NULL != rh->get_handle)
3247 GNUNET_DHT_get_stop (rh->get_handle);
3248 rh->get_handle = NULL;
3250 if (NULL != rh->dht_heap_node)
3252 GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
3253 rh->dht_heap_node = NULL;
3255 if (NULL != rh->dns_request)
3257 GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
3258 rh->dns_request = NULL;
3260 if (NULL != rh->namestore_qe)
3262 GNUNET_NAMESTORE_cancel (rh->namestore_qe);
3263 rh->namestore_qe = NULL;
3265 if (NULL != rh->std_resolve)
3267 GNUNET_RESOLVER_request_cancel (rh->std_resolve);
3268 rh->std_resolve = NULL;
3270 while (NULL != (dr = rh->dns_result_head))
3272 GNUNET_CONTAINER_DLL_remove (rh->dns_result_head,
3273 rh->dns_result_tail,
3277 GNUNET_free_non_null (rh->shorten_key);
3278 GNUNET_free (rh->name);
3283 /* ***************** Resolver initialization ********************* */
3287 * Initialize the resolver
3289 * @param nh the namestore handle
3290 * @param dh the dht handle
3291 * @param c configuration handle
3292 * @param max_bg_queries maximum number of parallel background queries in dht
3293 * @param ignore_pending ignore records that still require user confirmation
3297 GNS_resolver_init (struct GNUNET_NAMESTORE_Handle *nh,
3298 struct GNUNET_DHT_Handle *dh,
3299 const struct GNUNET_CONFIGURATION_Handle *c,
3300 unsigned long long max_bg_queries)
3305 namestore_handle = nh;
3308 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3309 max_allowed_background_queries = max_bg_queries;
3311 GNUNET_CONFIGURATION_get_value_string (c,
3316 /* user did not specify DNS resolver, use 8.8.8.8 */
3317 dns_ip = GNUNET_strdup ("8.8.8.8");
3319 dns_handle = GNUNET_DNSSTUB_start (dns_ip);
3320 GNUNET_free (dns_ip);
3328 GNS_resolver_done ()
3330 struct GNS_ResolverHandle *rh;
3332 /* abort active resolutions */
3333 while (NULL != (rh = rlh_head))
3335 rh->proc (rh->proc_cls, 0, NULL);
3336 GNS_resolver_lookup_cancel (rh);
3338 /* abort active shorten operations */
3339 while (NULL != gph_head)
3340 free_get_pseu_authority_handle (gph_head);
3341 GNUNET_CONTAINER_heap_destroy (dht_lookup_heap);
3342 dht_lookup_heap = NULL;
3343 GNUNET_DNSSTUB_stop (dns_handle);
3348 /* *************** common helper functions (do not really belong here) *********** */
3351 * Checks if "name" ends in ".tld"
3353 * @param name the name to check
3354 * @param tld the TLD to check for
3355 * @return GNUNET_YES or GNUNET_NO
3358 is_tld (const char* name, const char* tld)
3362 if (strlen (name) <= strlen (tld))
3364 offset = strlen (name) - strlen (tld);
3365 if (0 != strcmp (name + offset, tld))
3373 /* end of gnunet-service-gns_resolver.c */