2 This file is part of GNUnet.
3 Copyright (C) 2011-2013 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * @file gns/gnunet-service-gns_resolver.c
21 * @brief GNU Name System resolver logic
22 * @author Martin Schanzenbach
23 * @author Christian Grothoff
26 #include "gnunet_util_lib.h"
27 #include "gnunet_dnsstub_lib.h"
28 #include "gnunet_dht_service.h"
29 #include "gnunet_gnsrecord_lib.h"
30 #include "gnunet_namecache_service.h"
31 #include "gnunet_dns_service.h"
32 #include "gnunet_resolver_service.h"
33 #include "gnunet_revocation_service.h"
34 #include "gnunet_dnsparser_lib.h"
35 #include "gnunet_tun_lib.h"
36 #include "gnunet_gns_service.h"
38 #include "gnunet-service-gns.h"
39 #include "gnunet-service-gns_resolver.h"
40 #include "gnunet_vpn_service.h"
44 * Default DHT timeout for lookups.
46 #define DHT_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
49 * Default timeout for DNS lookups.
51 #define DNS_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
54 * Default timeout for VPN redirections.
56 #define VPN_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
59 * DHT replication level
61 #define DHT_GNS_REPLICATION_LEVEL 10
64 * How deep do we allow recursions to go before we abort?
66 #define MAX_RECURSION 256
70 * DLL to hold the authority chain we had to pass in the resolution
73 struct AuthorityChain;
77 * Element of a resolution process for looking up the
78 * responsible DNS server hostname in a GNS2DNS recursive
87 struct Gns2DnsPending *next;
92 struct Gns2DnsPending *prev;
95 * Context this activity belongs with.
97 struct AuthorityChain *ac;
100 * Handle for the resolution of the IP part of the
101 * GNS2DNS record. Will return to us the addresses
102 * of the DNS resolver to use.
104 struct GNS_ResolverHandle *rh;
107 * Handle for DNS resolution of the DNS nameserver.
109 struct GNUNET_RESOLVER_RequestHandle *dns_rh;
112 * How many results did we get?
114 unsigned int num_results;
119 * Handle to a currenty pending resolution. On result (positive or
120 * negative) the #GNS_ResultProcessor is called.
122 struct GNS_ResolverHandle;
126 * DLL to hold the authority chain we had to pass in the resolution
129 struct AuthorityChain
134 struct AuthorityChain *prev;
139 struct AuthorityChain *next;
142 * Resolver handle this entry in the chain belongs to.
144 struct GNS_ResolverHandle *rh;
147 * label/name corresponding to the authority
152 * #GNUNET_YES if the authority was a GNS authority,
153 * #GNUNET_NO if the authority was a DNS authority.
158 * Information about the resolver authority for this label.
164 * The zone of the GNS authority
166 struct GNUNET_CRYPTO_EcdsaPublicKey gns_authority;
171 * Domain of the DNS resolver that is the authority.
172 * (appended to construct the DNS name to resolve;
173 * this is NOT the DNS name of the DNS server!).
175 char name[GNUNET_DNSPARSER_MAX_NAME_LENGTH + 1];
178 * List of resolutions of the 'ip' of the name server that
181 struct Gns2DnsPending *gp_head;
184 * Tail of list of resolutions of the 'ip' of the name server that
187 struct Gns2DnsPending *gp_tail;
190 * Handle to perform DNS lookups with this authority (in GNS2DNS handling).
192 struct GNUNET_DNSSTUB_Context *dns_handle;
195 * Did we succeed in getting an IP address for *any* of the DNS servers listed?
196 * Once we do, we can start with DNS queries.
201 * Did we start the recursive resolution via DNS?
213 * A result we got from DNS.
221 struct DnsResult *next;
226 struct DnsResult *prev;
229 * Binary value stored in the DNS record (appended to this struct)
234 * Expiration time for the DNS record, 0 if we didn't
235 * get anything useful (i.e. 'gethostbyname()' was used).
237 uint64_t expiration_time;
240 * Number of bytes in @e data.
245 * Type of the GNS/DNS record.
247 uint32_t record_type;
253 * Closure for #vpn_allocation_cb.
259 * Which resolution process are we processing.
261 struct GNS_ResolverHandle *rh;
264 * Handle to the VPN request that we were performing.
266 struct GNUNET_VPN_RedirectionRequest *vpn_request;
269 * Number of records serialized in @e rd_data.
271 unsigned int rd_count;
274 * Serialized records.
279 * Number of bytes in @e rd_data.
281 ssize_t rd_data_size;
286 * Handle to a currenty pending resolution. On result (positive or
287 * negative) the #GNS_ResultProcessor is called.
289 struct GNS_ResolverHandle
295 struct GNS_ResolverHandle *next;
300 struct GNS_ResolverHandle *prev;
303 * The top-level GNS authoritative zone to query
305 struct GNUNET_CRYPTO_EcdsaPublicKey authority_zone;
308 * called when resolution phase finishes
310 GNS_ResultProcessor proc;
313 * closure passed to @e proc
318 * Handle for DHT lookups. should be NULL if no lookups are in progress
320 struct GNUNET_DHT_GetHandle *get_handle;
323 * Handle to a VPN request, NULL if none is active.
325 struct VpnContext *vpn_ctx;
328 * Socket for a DNS request, NULL if none is active.
330 struct GNUNET_DNSSTUB_RequestSocket *dns_request;
333 * Handle for standard DNS resolution, NULL if none is active.
335 struct GNUNET_RESOLVER_RequestHandle *std_resolve;
338 * Pending Namecache lookup task
340 struct GNUNET_NAMECACHE_QueueEntry *namecache_qe;
343 * Pending revocation check.
345 struct GNUNET_REVOCATION_Query *rev_check;
348 * Heap node associated with this lookup. Used to limit number of
349 * concurrent requests.
351 struct GNUNET_CONTAINER_HeapNode *dht_heap_node;
354 * DLL to store the authority chain
356 struct AuthorityChain *ac_head;
359 * DLL to store the authority chain
361 struct AuthorityChain *ac_tail;
364 * ID of a task associated with the resolution process.
366 struct GNUNET_SCHEDULER_Task *task_id;
369 * The name to resolve
374 * Legacy Hostname to use if we encountered GNS2DNS record
375 * and thus can deduct the LEHO from that transition.
380 * DLL of results we got from DNS.
382 struct DnsResult *dns_result_head;
385 * DLL of results we got from DNS.
387 struct DnsResult *dns_result_tail;
390 * Current offset in 'name' where we are resolving.
392 size_t name_resolution_pos;
397 enum GNUNET_GNS_LocalOptions options;
400 * For SRV and TLSA records, the number of the
401 * protocol specified in the name. 0 if no protocol was given.
406 * For SRV and TLSA records, the number of the
407 * service specified in the name. 0 if no service was given.
412 * Desired type for the resolution.
417 * We increment the loop limiter for each step in a recursive
418 * resolution. If it passes our threshold (i.e. due to
419 * self-recursion in the resolution, i.e CNAME fun), we stop.
421 unsigned int loop_limiter;
424 * 16 bit random ID we used in the @e dns_request.
426 uint16_t original_dns_id;
432 * Active namestore caching operations.
438 * Organized in a DLL.
440 struct CacheOps *next;
443 * Organized in a DLL.
445 struct CacheOps *prev;
448 * Pending Namestore caching task.
450 struct GNUNET_NAMECACHE_QueueEntry *namecache_qe_cache;
456 * Our handle to the namecache service
458 static struct GNUNET_NAMECACHE_Handle *namecache_handle;
461 * Our handle to the vpn service
463 static struct GNUNET_VPN_Handle *vpn_handle;
466 * Resolver handle to the dht
468 static struct GNUNET_DHT_Handle *dht_handle;
471 * Heap for limiting parallel DHT lookups
473 static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
476 * Maximum amount of parallel queries to the DHT
478 static unsigned long long max_allowed_background_queries;
481 * Head of resolver lookup list
483 static struct GNS_ResolverHandle *rlh_head;
486 * Tail of resolver lookup list
488 static struct GNS_ResolverHandle *rlh_tail;
491 * Organized in a DLL.
493 static struct CacheOps *co_head;
496 * Organized in a DLL.
498 static struct CacheOps *co_tail;
503 static int disable_cache;
506 * Global configuration.
508 static const struct GNUNET_CONFIGURATION_Handle *cfg;
512 * Determine if this name is canonical (is a legal name in a zone, without delegation);
513 * note that we do not test that the name does not contain illegal characters, we only
514 * test for delegation. Note that service records (i.e. _foo._srv) are canonical names
515 * even though they consist of multiple labels.
518 * a.b.gnu = not canonical
520 * _foo._srv = canonical
521 * _f.bar = not canonical
523 * @param name the name to test
524 * @return #GNUNET_YES if canonical
526 /* dead, but keep for now */ int
527 is_canonical (const char *name)
532 if (NULL == strchr (name,
533 (unsigned char) '.'))
538 while (NULL != (dot = strchr (pos,
539 (unsigned char) '.')))
547 /* ************************** Resolution **************************** */
550 * Expands a name ending in .+ with the zone of origin.
552 * @param rh resolution context
553 * @param name name to modify (to be free'd or returned)
554 * @return updated name
557 translate_dot_plus (struct GNS_ResolverHandle *rh,
561 size_t s_len = strlen (name);
563 if (0 != strcmp (&name[s_len - 2],
565 return name; /* did not end in ".+" */
566 GNUNET_assert (GNUNET_YES == rh->ac_tail->gns_authority);
567 GNUNET_asprintf (&ret,
571 GNUNET_GNSRECORD_pkey_to_zkey (&rh->ac_tail->authority_info.gns_authority));
578 * Wrapper around #GNS_resolver_lookup_cancel() as a task.
579 * Used for delayed cleanup so we can unwind the stack first.
581 * @param cls the `struct GNS_ResolverHandle`
584 GNS_resolver_lookup_cancel_ (void *cls)
586 struct GNS_ResolverHandle *rh = cls;
589 GNS_resolver_lookup_cancel (rh);
594 * Function called to asynchronously fail a resolution.
596 * @param rh the resolution to fail
599 fail_resolution (struct GNS_ResolverHandle *rh)
601 rh->proc (rh->proc_cls,
604 GNUNET_assert (NULL == rh->task_id);
605 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
611 * Function called when a resolution times out.
613 * @param cls the `struct GNS_ResolverHandle`
616 timeout_resolution (void *cls)
618 struct GNS_ResolverHandle *rh = cls;
621 fail_resolution (rh);
625 #if (defined WINDOWS) || (defined DARWIN)
626 /* Don't have this on W32, here's a naive implementation
627 * Was somehow removed on OS X ... */
629 memrchr (const void *s,
633 const unsigned char *ucs = s;
636 for (i = n - 1; i >= 0; i--)
637 if (c == (int) ucs[i])
638 return (void *) &ucs[i];
645 * Get the next, rightmost label from the name that we are trying to resolve,
646 * and update the resolution position accordingly. Labels usually consist
647 * of up to 63 characters without a period ("."); however, we use a special
648 * convention to support SRV and TLSA records where the domain name
649 * includes an encoding for a service and protocol in the name. The
650 * syntax (see RFC 2782) here is "_Service._Proto.Name" and in this
651 * special case we include the "_Service._Proto" in the rightmost label.
652 * Thus, for "_443._tcp.foo.bar" we first return the label "bar" and then
653 * the label "_443._tcp.foo". The special case is detected by the
654 * presence of labels beginning with an underscore. Whenever a label
655 * begins with an underscore, it is combined with the label to its right
656 * (and the "." is preserved).
658 * @param rh handle to the resolution operation to get the next label from
659 * @return NULL if there are no more labels
662 resolver_lookup_get_next_label (struct GNS_ResolverHandle *rh)
673 if (0 == rh->name_resolution_pos)
675 dot = memrchr (rh->name,
677 rh->name_resolution_pos);
680 /* done, this was the last one */
681 len = rh->name_resolution_pos;
683 rh->name_resolution_pos = 0;
687 /* advance by one label */
688 len = rh->name_resolution_pos - (dot - rh->name) - 1;
690 rh->name_resolution_pos = dot - rh->name;
694 ret = GNUNET_strndup (rp, len);
695 /* If we have labels starting with underscore with label on
696 * the right (SRV/DANE/BOX case), determine port/protocol;
697 * The format of `rh->name` must be "_PORT._PROTOCOL".
699 if ( ('_' == rh->name[0]) &&
700 (NULL != (dot = memrchr (rh->name,
702 rh->name_resolution_pos))) &&
704 (NULL == memrchr (rh->name,
708 srv_name = GNUNET_strndup (&rh->name[1],
709 (dot - rh->name) - 1);
710 proto_name = GNUNET_strndup (&dot[2],
711 rh->name_resolution_pos - (dot - rh->name) - 1);
712 rh->name_resolution_pos = 0;
713 pe = getprotobyname (proto_name);
716 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
717 _("Protocol `%s' unknown, skipping labels.\n"),
719 GNUNET_free (proto_name);
720 GNUNET_free (srv_name);
723 se = getservbyname (srv_name,
727 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
728 _("Service `%s' unknown for protocol `%s', skipping labels.\n"),
731 GNUNET_free (proto_name);
732 GNUNET_free (srv_name);
735 rh->protocol = pe->p_proto;
736 rh->service = se->s_port;
737 GNUNET_free (proto_name);
738 GNUNET_free (srv_name);
745 * Gives the cummulative result obtained to the callback and clean up the request.
747 * @param rh resolution process that has culminated in a result
750 transmit_lookup_dns_result (struct GNS_ResolverHandle *rh)
752 struct DnsResult *pos;
757 for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
760 struct GNUNET_GNSRECORD_Data rd[n];
763 for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
765 rd[i].data = pos->data;
766 rd[i].data_size = pos->data_size;
767 rd[i].record_type = pos->record_type;
768 if (0 == pos->expiration_time)
770 rd[i].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
771 rd[i].expiration_time = 0;
775 rd[i].flags = GNUNET_GNSRECORD_RF_NONE;
776 rd[i].expiration_time = pos->expiration_time;
780 GNUNET_assert (i == n);
781 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
782 "Transmitting standard DNS result with %u records\n",
784 rh->proc (rh->proc_cls,
788 GNS_resolver_lookup_cancel (rh);
793 * Add a result from DNS to the records to be returned to the application.
795 * @param rh resolution request to extend with a result
796 * @param expiration_time expiration time for the answer
797 * @param record_type DNS record type of the answer
798 * @param data_size number of bytes in @a data
799 * @param data binary data to return in DNS record
802 add_dns_result (struct GNS_ResolverHandle *rh,
803 uint64_t expiration_time,
804 uint32_t record_type,
808 struct DnsResult *res;
810 res = GNUNET_malloc (sizeof (struct DnsResult) + data_size);
811 res->expiration_time = expiration_time;
812 res->data_size = data_size;
813 res->record_type = record_type;
815 GNUNET_memcpy (&res[1],
818 GNUNET_CONTAINER_DLL_insert (rh->dns_result_head,
825 * We had to do a DNS lookup. Convert the result (if any) and return
828 * @param cls closure with the `struct GNS_ResolverHandle`
829 * @param addr one of the addresses of the host, NULL for the last address
830 * @param addrlen length of the address
833 handle_dns_result (void *cls,
834 const struct sockaddr *addr,
837 struct GNS_ResolverHandle *rh = cls;
838 const struct sockaddr_in *sa4;
839 const struct sockaddr_in6 *sa6;
843 rh->std_resolve = NULL;
844 transmit_lookup_dns_result (rh);
847 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
848 "Received %u bytes of DNS IP data\n",
850 switch (addr->sa_family)
853 sa4 = (const struct sockaddr_in *) addr;
855 0 /* expiration time is unknown */,
856 GNUNET_DNSPARSER_TYPE_A,
857 sizeof (struct in_addr),
861 sa6 = (const struct sockaddr_in6 *) addr;
863 0 /* expiration time is unknown */,
864 GNUNET_DNSPARSER_TYPE_AAAA,
865 sizeof (struct in6_addr),
876 * Task scheduled to continue with the resolution process.
878 * @param cls the 'struct GNS_ResolverHandle' of the resolution
879 * @param tc task context
882 recursive_resolution (void *cls);
886 * Begin the resolution process from 'name', starting with
887 * the identification of the zone specified by 'name'.
889 * @param cls closure with `struct GNS_ResolverHandle *rh`
892 start_resolver_lookup (void *cls);
896 * Function called with the result of a DNS resolution.
898 * @param cls the request handle of the resolution that
899 * we were attempting to make
900 * @param dns dns response, never NULL
901 * @param dns_len number of bytes in @a dns
904 dns_result_parser (void *cls,
905 const struct GNUNET_TUN_DnsHeader *dns,
908 struct GNS_ResolverHandle *rh = cls;
909 struct GNUNET_DNSPARSER_Packet *p;
910 const struct GNUNET_DNSPARSER_Record *rec;
911 unsigned int rd_count;
915 rh->dns_request = NULL;
916 GNUNET_SCHEDULER_cancel (rh->task_id);
918 fail_resolution (rh);
921 if (rh->original_dns_id != dns->id)
923 /* DNS answer, but for another query */
926 p = GNUNET_DNSPARSER_parse ((const char *) dns,
930 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
931 _("Failed to parse DNS response\n"));
935 /* We got a result from DNS */
936 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
937 "Received DNS response for `%s' with %u answers\n",
939 (unsigned int) p->num_answers);
940 if ( (p->num_answers > 0) &&
941 (GNUNET_DNSPARSER_TYPE_CNAME == p->answers[0].type) &&
942 (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type) )
946 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
947 "Got CNAME `%s' from DNS for `%s'\n",
948 p->answers[0].data.hostname,
950 if (NULL != rh->std_resolve)
952 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
953 "Multiple CNAME results from DNS resolving `%s'! Not really allowed...\n",
955 GNUNET_RESOLVER_request_cancel (rh->std_resolve);
957 GNUNET_free (rh->name);
958 rh->name = GNUNET_strdup (p->answers[0].data.hostname);
959 rh->name_resolution_pos = strlen (rh->name);
960 switch (rh->record_type)
962 case GNUNET_DNSPARSER_TYPE_A:
965 case GNUNET_DNSPARSER_TYPE_AAAA:
972 if (NULL != rh->leho)
974 GNUNET_TIME_UNIT_HOURS.rel_value_us,
975 GNUNET_GNSRECORD_TYPE_LEHO,
978 rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name,
983 GNUNET_DNSPARSER_free_packet (p);
984 GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
985 rh->dns_request = NULL;
989 /* convert from (parsed) DNS to (binary) GNS format! */
990 rd_count = p->num_answers + p->num_authority_records + p->num_additional_records;
992 struct GNUNET_GNSRECORD_Data rd[rd_count + 1]; /* +1 for LEHO */
994 char buf[UINT16_MAX];
1003 for (unsigned int i=0;i<rd_count;i++)
1005 if (i < p->num_answers)
1006 rec = &p->answers[i];
1007 else if (i < p->num_answers + p->num_authority_records)
1008 rec = &p->authority_records[i - p->num_answers];
1010 rec = &p->additional_records[i - p->num_answers - p->num_authority_records];
1011 /* As we copied the full DNS name to 'rh->ac_tail->label', this
1012 should be the correct check to see if this record is actually
1013 a record for our label... */
1014 if (0 != strcmp (rec->name,
1015 rh->ac_tail->label))
1017 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1018 "Dropping record `%s', does not match desired name `%s'\n",
1020 rh->ac_tail->label);
1024 rd[i - skip].record_type = rec->type;
1025 rd[i - skip].expiration_time = rec->expiration_time.abs_value_us;
1028 case GNUNET_DNSPARSER_TYPE_A:
1029 if (rec->data.raw.data_len != sizeof (struct in_addr))
1031 GNUNET_break_op (0);
1035 rd[i - skip].data_size = rec->data.raw.data_len;
1036 rd[i - skip].data = rec->data.raw.data;
1038 case GNUNET_DNSPARSER_TYPE_AAAA:
1039 if (rec->data.raw.data_len != sizeof (struct in6_addr))
1041 GNUNET_break_op (0);
1045 rd[i - skip].data_size = rec->data.raw.data_len;
1046 rd[i - skip].data = rec->data.raw.data;
1048 case GNUNET_DNSPARSER_TYPE_CNAME:
1049 case GNUNET_DNSPARSER_TYPE_PTR:
1050 case GNUNET_DNSPARSER_TYPE_NS:
1051 buf_start = buf_off;
1053 GNUNET_DNSPARSER_builder_add_name (buf,
1056 rec->data.hostname))
1062 rd[i - skip].data_size = buf_off - buf_start;
1063 rd[i - skip].data = &buf[buf_start];
1065 case GNUNET_DNSPARSER_TYPE_SOA:
1066 buf_start = buf_off;
1068 GNUNET_DNSPARSER_builder_add_soa (buf,
1077 rd[i - skip].data_size = buf_off - buf_start;
1078 rd[i - skip].data = &buf[buf_start];
1080 case GNUNET_DNSPARSER_TYPE_MX:
1081 buf_start = buf_off;
1083 GNUNET_DNSPARSER_builder_add_mx (buf,
1092 rd[i - skip].data_size = buf_off - buf_start;
1093 rd[i - skip].data = &buf[buf_start];
1095 case GNUNET_DNSPARSER_TYPE_SRV:
1096 buf_start = buf_off;
1098 GNUNET_DNSPARSER_builder_add_srv (buf,
1107 rd[i - skip].data_size = buf_off - buf_start;
1108 rd[i - skip].data = &buf[buf_start];
1111 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1112 _("Skipping record of unsupported type %d\n"),
1117 } /* end of for all records in answer */
1118 if (NULL != rh->leho)
1120 rd[rd_count - skip].record_type = GNUNET_GNSRECORD_TYPE_LEHO;
1121 rd[rd_count - skip].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1122 rd[rd_count - skip].expiration_time = GNUNET_TIME_UNIT_HOURS.rel_value_us;
1123 rd[rd_count - skip].data = rh->leho;
1124 rd[rd_count - skip].data_size = strlen (rh->leho);
1125 skip--; /* skip one LESS */
1126 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1130 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1131 "Returning DNS response for `%s' with %u answers\n",
1133 (unsigned int) (rd_count - skip));
1134 rh->proc (rh->proc_cls,
1137 GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
1138 rh->dns_request = NULL;
1140 GNUNET_DNSPARSER_free_packet (p);
1141 if (NULL != rh->task_id)
1142 GNUNET_SCHEDULER_cancel (rh->task_id); /* should be timeout task */
1143 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
1149 * Perform recursive DNS resolution. Asks the given DNS resolver to
1150 * resolve "rh->dns_name", possibly recursively proceeding following
1151 * NS delegations, CNAMES, etc., until 'rh->loop_limiter' bounds us or
1152 * we find the answer.
1154 * @param rh resolution information
1157 recursive_dns_resolution (struct GNS_ResolverHandle *rh)
1159 struct AuthorityChain *ac;
1160 struct GNUNET_DNSPARSER_Query *query;
1161 struct GNUNET_DNSPARSER_Packet *p;
1163 size_t dns_request_length;
1167 GNUNET_assert (NULL != ac);
1168 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1169 "Starting DNS lookup for `%s'\n",
1171 GNUNET_assert (GNUNET_NO == ac->gns_authority);
1172 query = GNUNET_new (struct GNUNET_DNSPARSER_Query);
1173 query->name = GNUNET_strdup (ac->label);
1174 query->type = rh->record_type;
1175 query->dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
1176 p = GNUNET_new (struct GNUNET_DNSPARSER_Packet);
1179 p->id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1181 p->flags.opcode = GNUNET_TUN_DNS_OPCODE_QUERY;
1182 p->flags.recursion_desired = 1;
1183 ret = GNUNET_DNSPARSER_pack (p,
1186 &dns_request_length);
1187 if (GNUNET_OK != ret)
1190 rh->proc (rh->proc_cls,
1193 GNUNET_assert (NULL == rh->task_id);
1194 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
1199 rh->original_dns_id = p->id;
1200 GNUNET_assert (NULL != ac->authority_info.dns_authority.dns_handle);
1201 GNUNET_assert (NULL == rh->dns_request);
1202 rh->leho = GNUNET_strdup (ac->label);
1203 rh->dns_request = GNUNET_DNSSTUB_resolve (ac->authority_info.dns_authority.dns_handle,
1208 rh->task_id = GNUNET_SCHEDULER_add_delayed (DNS_LOOKUP_TIMEOUT,
1209 &timeout_resolution,
1212 if (GNUNET_SYSERR != ret)
1213 GNUNET_free (dns_request);
1214 GNUNET_DNSPARSER_free_packet (p);
1219 * We encountered a CNAME record during our resolution.
1220 * Merge it into our chain.
1222 * @param rh resolution we are performing
1223 * @param cname value of the cname record we got for the current
1224 * authority chain tail
1227 handle_gns_cname_result (struct GNS_ResolverHandle *rh,
1232 struct AuthorityChain *ac;
1235 nlen = strlen (cname);
1238 &cname[nlen - 2])) )
1240 /* CNAME resolution continues relative to current domain */
1241 if (0 == rh->name_resolution_pos)
1243 res = GNUNET_strndup (cname, nlen - 2);
1244 rh->name_resolution_pos = nlen - 2;
1248 GNUNET_asprintf (&res,
1250 (int) rh->name_resolution_pos,
1254 rh->name_resolution_pos = strlen (res);
1256 GNUNET_free (rh->name);
1258 ac = GNUNET_new (struct AuthorityChain);
1260 ac->gns_authority = GNUNET_YES;
1261 ac->authority_info.gns_authority = rh->ac_tail->authority_info.gns_authority;
1262 ac->label = resolver_lookup_get_next_label (rh);
1263 /* add AC to tail */
1264 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1267 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1271 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1272 "Got CNAME `%s' from GNS for `%s'\n",
1275 if (NULL != rh->std_resolve)
1277 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1278 "Multiple CNAME results from GNS resolving `%s'! Not really allowed...\n",
1280 GNUNET_RESOLVER_request_cancel (rh->std_resolve);
1282 /* name is absolute, go to DNS */
1283 GNUNET_free (rh->name);
1284 rh->name = GNUNET_strdup (cname);
1285 rh->name_resolution_pos = strlen (rh->name);
1286 switch (rh->record_type)
1288 case GNUNET_DNSPARSER_TYPE_A:
1291 case GNUNET_DNSPARSER_TYPE_AAAA:
1298 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1299 "Doing standard DNS lookup for `%s'\n",
1301 rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name,
1310 * Process a records that were decrypted from a block.
1312 * @param cls closure with the 'struct GNS_ResolverHandle'
1313 * @param rd_count number of entries in @a rd array
1314 * @param rd array of records with data to store
1317 handle_gns_resolution_result (void *cls,
1318 unsigned int rd_count,
1319 const struct GNUNET_GNSRECORD_Data *rd);
1323 * Callback invoked from the VPN service once a redirection is
1324 * available. Provides the IP address that can now be used to
1325 * reach the requested destination. Replaces the "VPN" record
1326 * with the respective A/AAAA record and continues processing.
1328 * @param cls closure
1329 * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error;
1330 * will match 'result_af' from the request
1331 * @param address IP address (struct in_addr or struct in_addr6, depending on 'af')
1332 * that the VPN allocated for the redirection;
1333 * traffic to this IP will now be redirected to the
1334 * specified target peer; NULL on error
1337 vpn_allocation_cb (void *cls,
1339 const void *address)
1341 struct VpnContext *vpn_ctx = cls;
1342 struct GNS_ResolverHandle *rh = vpn_ctx->rh;
1343 struct GNUNET_GNSRECORD_Data rd[vpn_ctx->rd_count];
1346 vpn_ctx->vpn_request = NULL;
1348 GNUNET_assert (GNUNET_OK ==
1349 GNUNET_GNSRECORD_records_deserialize ((size_t) vpn_ctx->rd_data_size,
1353 for (i=0;i<vpn_ctx->rd_count;i++)
1355 if (GNUNET_GNSRECORD_TYPE_VPN == rd[i].record_type)
1360 rd[i].record_type = GNUNET_DNSPARSER_TYPE_A;
1361 rd[i].data_size = sizeof (struct in_addr);
1362 rd[i].expiration_time = GNUNET_TIME_relative_to_absolute (VPN_TIMEOUT).abs_value_us;
1364 rd[i].data = address;
1367 rd[i].record_type = GNUNET_DNSPARSER_TYPE_AAAA;
1368 rd[i].expiration_time = GNUNET_TIME_relative_to_absolute (VPN_TIMEOUT).abs_value_us;
1370 rd[i].data = address;
1371 rd[i].data_size = sizeof (struct in6_addr);
1379 GNUNET_assert (i < vpn_ctx->rd_count);
1380 if (0 == vpn_ctx->rd_count)
1381 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1382 _("VPN returned empty result for `%s'\n"),
1384 handle_gns_resolution_result (rh,
1387 GNUNET_free (vpn_ctx->rd_data);
1388 GNUNET_free (vpn_ctx);
1393 * We have resolved one or more of the nameservers for a
1394 * GNS2DNS lookup. Once we have some of them, begin using
1395 * the DNSSTUB resolver.
1397 * @param ac context for GNS2DNS resolution
1400 continue_with_gns2dns (struct AuthorityChain *ac)
1402 struct GNS_ResolverHandle *rh = ac->rh;
1404 if ( (NULL != ac->authority_info.dns_authority.gp_head) &&
1405 (GNUNET_NO == ac->authority_info.dns_authority.found) )
1406 return; /* more pending and none found yet */
1407 if (GNUNET_NO == ac->authority_info.dns_authority.found)
1409 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1410 "Failed to resolve DNS server for `%s' in GNS2DNS resolution\n",
1411 ac->authority_info.dns_authority.name);
1412 fail_resolution (rh);
1415 if (GNUNET_NO != ac->authority_info.dns_authority.launched)
1416 return; /* already running, do not launch again! */
1418 ac->authority_info.dns_authority.launched = GNUNET_YES;
1419 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1420 "Will continue resolution using DNS to resolve `%s'\n",
1422 GNUNET_assert (NULL == rh->task_id);
1423 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1430 * We've resolved the IP address for the DNS resolver to use
1431 * after encountering a GNS2DNS record.
1433 * @param cls the `struct Gns2DnsPending` used for this request
1434 * @param rd_count number of records in @a rd
1435 * @param rd addresses for the DNS resolver (presumably)
1438 handle_gns2dns_result (void *cls,
1439 unsigned int rd_count,
1440 const struct GNUNET_GNSRECORD_Data *rd)
1442 struct Gns2DnsPending *gp = cls;
1443 struct AuthorityChain *ac = gp->ac;
1445 GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
1446 ac->authority_info.dns_authority.gp_tail,
1448 /* enable cleanup of 'rh' handle that automatically comes after we return,
1449 and which expects 'rh' to be in the #rlh_head DLL. */
1452 GNUNET_CONTAINER_DLL_insert (rlh_head,
1458 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1459 "Received %u results for IP address of DNS server for GNS2DNS transition\n",
1461 /* find suitable A/AAAA record */
1462 for (unsigned int j=0;j<rd_count;j++)
1464 switch (rd[j].record_type)
1466 case GNUNET_DNSPARSER_TYPE_A:
1468 struct sockaddr_in v4;
1470 if (sizeof (struct in_addr) != rd[j].data_size)
1472 GNUNET_break_op (0);
1478 v4.sin_family = AF_INET;
1479 v4.sin_port = htons (53);
1480 #if HAVE_SOCKADDR_IN_SIN_LEN
1481 v4.sin_len = (u_char) sizeof (v4);
1483 GNUNET_memcpy (&v4.sin_addr,
1485 sizeof (struct in_addr));
1487 GNUNET_DNSSTUB_add_dns_sa (ac->authority_info.dns_authority.dns_handle,
1488 (const struct sockaddr *) &v4))
1489 ac->authority_info.dns_authority.found = GNUNET_YES;
1492 case GNUNET_DNSPARSER_TYPE_AAAA:
1494 struct sockaddr_in6 v6;
1496 if (sizeof (struct in6_addr) != rd[j].data_size)
1498 GNUNET_break_op (0);
1501 /* FIXME: might want to check if we support IPv6 here,
1502 and otherwise skip this one and hope we find another */
1506 v6.sin6_family = AF_INET6;
1507 v6.sin6_port = htons (53);
1508 #if HAVE_SOCKADDR_IN_SIN_LEN
1509 v6.sin6_len = (u_char) sizeof (v6);
1511 GNUNET_memcpy (&v6.sin6_addr,
1513 sizeof (struct in6_addr));
1515 GNUNET_DNSSTUB_add_dns_sa (ac->authority_info.dns_authority.dns_handle,
1516 (const struct sockaddr *) &v6))
1517 ac->authority_info.dns_authority.found = GNUNET_YES;
1524 continue_with_gns2dns (ac);
1529 * Function called by the resolver for each address obtained from DNS.
1531 * @param cls closure, a `struct Gns2DnsPending *`
1532 * @param addr one of the addresses of the host, NULL for the last address
1533 * @param addrlen length of @a addr
1536 handle_gns2dns_ip (void *cls,
1537 const struct sockaddr *addr,
1540 struct Gns2DnsPending *gp = cls;
1541 struct AuthorityChain *ac = gp->ac;
1542 struct sockaddr_storage ss;
1543 struct sockaddr_in *v4;
1544 struct sockaddr_in6 *v6;
1548 /* DNS resolution finished */
1549 if (0 == gp->num_results)
1550 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1551 "Failed to use DNS to resolve name of DNS resolver\n");
1552 GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
1553 ac->authority_info.dns_authority.gp_tail,
1556 continue_with_gns2dns (ac);
1562 switch (ss.ss_family)
1565 v4 = (struct sockaddr_in *) &ss;
1566 v4->sin_port = htons (53);
1570 v6 = (struct sockaddr_in6 *) &ss;
1571 v6->sin6_port = htons (53);
1575 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1576 "Unsupported AF %d\n",
1581 GNUNET_DNSSTUB_add_dns_sa (ac->authority_info.dns_authority.dns_handle,
1582 (struct sockaddr *) &ss))
1583 ac->authority_info.dns_authority.found = GNUNET_YES;
1588 * We found a CNAME record, perform recursive resolution on it.
1590 * @param rh resolution handle
1591 * @param rd record with CNAME to resolve recursively
1594 recursive_cname_resolution (struct GNS_ResolverHandle *rh,
1595 const struct GNUNET_GNSRECORD_Data *rd)
1601 cname = GNUNET_DNSPARSER_parse_name (rd->data,
1604 if ( (NULL == cname) ||
1605 (off != rd->data_size) )
1607 GNUNET_break_op (0); /* record not well-formed */
1608 GNUNET_free_non_null (cname);
1609 fail_resolution (rh);
1612 handle_gns_cname_result (rh,
1614 GNUNET_free (cname);
1619 * We found a PKEY record, perform recursive resolution on it.
1621 * @param rh resolution handle
1622 * @param rd record with PKEY to resolve recursively
1625 recursive_pkey_resolution (struct GNS_ResolverHandle *rh,
1626 const struct GNUNET_GNSRECORD_Data *rd)
1628 struct AuthorityChain *ac;
1630 /* delegation to another zone */
1631 if (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) !=
1634 GNUNET_break_op (0);
1635 fail_resolution (rh);
1638 /* expand authority chain */
1639 ac = GNUNET_new (struct AuthorityChain);
1641 ac->gns_authority = GNUNET_YES;
1642 GNUNET_memcpy (&ac->authority_info.gns_authority,
1644 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1645 ac->label = resolver_lookup_get_next_label (rh);
1646 /* add AC to tail */
1647 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1651 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1657 * We found one or more GNS2DNS records, perform recursive resolution on it.
1658 * (to be precise, one or more records in @a rd is GNS2DNS, there may be others,
1659 * so this function still needs to check which ones are GNS2DNS).
1661 * @param rh resolution handle
1662 * @param rd_count length of the @a rd array
1663 * @param rd record with PKEY to resolve recursively
1664 * @return #GNUNET_OK if this worked, #GNUNET_SYSERR if no GNS2DNS records were in @a rd
1667 recursive_gns2dns_resolution (struct GNS_ResolverHandle *rh,
1668 unsigned int rd_count,
1669 const struct GNUNET_GNSRECORD_Data *rd)
1671 struct AuthorityChain *ac;
1676 /* expand authority chain */
1677 ac = GNUNET_new (struct AuthorityChain);
1679 ac->authority_info.dns_authority.dns_handle = GNUNET_DNSSTUB_start (4);
1681 for (unsigned int i=0;i<rd_count;i++)
1686 struct Gns2DnsPending *gp;
1687 struct GNUNET_CRYPTO_EcdsaPublicKey zone;
1688 struct sockaddr_in v4;
1689 struct sockaddr_in6 v6;
1691 if (GNUNET_GNSRECORD_TYPE_GNS2DNS != rd[i].record_type)
1694 n = GNUNET_DNSPARSER_parse_name (rd[i].data,
1697 ip = GNUNET_DNSPARSER_parse_name (rd[i].data,
1702 (off != rd[i].data_size) )
1704 GNUNET_break_op (0);
1705 GNUNET_free_non_null (n);
1706 GNUNET_free_non_null (ip);
1709 /* resolve 'ip' to determine the IP(s) of the DNS
1710 resolver to use for lookup of 'ns' */
1713 if (0 != strcasecmp (ns,
1716 /* NS values must all be the same for all GNS2DNS records,
1717 anything else leads to insanity */
1718 GNUNET_break_op (0);
1730 /* check if 'ip' is already an IPv4/IPv6 address */
1731 if ( (1 == inet_pton (AF_INET,
1734 (1 == inet_pton (AF_INET6,
1738 GNUNET_break (GNUNET_OK ==
1739 GNUNET_DNSSTUB_add_dns_ip (ac->authority_info.dns_authority.dns_handle,
1741 ac->authority_info.dns_authority.found = GNUNET_YES;
1745 tld = GNS_get_tld (ip);
1746 if (0 != strcmp (tld,
1749 /* 'ip' is a DNS name */
1750 gp = GNUNET_new (struct Gns2DnsPending);
1752 GNUNET_CONTAINER_DLL_insert (ac->authority_info.dns_authority.gp_head,
1753 ac->authority_info.dns_authority.gp_tail,
1755 gp->dns_rh = GNUNET_RESOLVER_ip_get (ip,
1757 GNUNET_TIME_UNIT_FOREVER_REL,
1763 /* 'ip' should be a GNS name */
1764 gp = GNUNET_new (struct Gns2DnsPending);
1766 GNUNET_CONTAINER_DLL_insert (ac->authority_info.dns_authority.gp_head,
1767 ac->authority_info.dns_authority.gp_tail,
1769 gp->rh = GNUNET_new (struct GNS_ResolverHandle);
1770 ip = translate_dot_plus (rh,
1772 tld = GNS_get_tld (ip);
1774 GNUNET_GNSRECORD_zkey_to_pkey (tld,
1777 GNUNET_break_op (0);
1781 gp->rh->authority_zone = zone;
1782 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1783 "Resolving `%s' to determine IP address of DNS server for GNS2DNS transition for `%s'\n",
1787 gp->rh->name_resolution_pos = strlen (ip) - strlen (tld) - 1;
1788 gp->rh->proc = &handle_gns2dns_result;
1789 gp->rh->proc_cls = gp;
1790 gp->rh->record_type = GNUNET_GNSRECORD_TYPE_ANY;
1791 gp->rh->options = GNUNET_GNS_LO_DEFAULT;
1792 gp->rh->loop_limiter = rh->loop_limiter + 1;
1794 = GNUNET_SCHEDULER_add_now (&start_resolver_lookup,
1796 } /* end 'for all records' */
1800 /* not a single GNS2DNS record found */
1802 return GNUNET_SYSERR;
1804 GNUNET_assert (strlen (ns) <= GNUNET_DNSPARSER_MAX_NAME_LENGTH);
1805 strcpy (ac->authority_info.dns_authority.name,
1807 /* for DNS recursion, the label is the full DNS name,
1808 created from the remainder of the GNS name and the
1809 name in the NS record */
1810 GNUNET_asprintf (&ac->label,
1812 (int) rh->name_resolution_pos,
1814 (0 != rh->name_resolution_pos) ? "." : "",
1817 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1820 if (strlen (ac->label) > GNUNET_DNSPARSER_MAX_NAME_LENGTH)
1822 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1823 _("GNS lookup resulted in DNS name that is too long (`%s')\n"),
1825 return GNUNET_SYSERR;
1827 continue_with_gns2dns (ac);
1833 * Process a records that were decrypted from a block.
1835 * @param cls closure with the `struct GNS_ResolverHandle`
1836 * @param rd_count number of entries in @a rd array
1837 * @param rd array of records with data to store
1840 handle_gns_resolution_result (void *cls,
1841 unsigned int rd_count,
1842 const struct GNUNET_GNSRECORD_Data *rd)
1844 struct GNS_ResolverHandle *rh = cls;
1846 struct VpnContext *vpn_ctx;
1847 const struct GNUNET_TUN_GnsVpnRecord *vpn;
1849 struct GNUNET_HashCode vhash;
1851 char scratch[UINT16_MAX];
1853 size_t scratch_start;
1855 struct GNUNET_GNSRECORD_Data rd_new[rd_count];
1856 unsigned int rd_off;
1858 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1859 "Resolution succeeded for `%s' in zone %s, got %u records\n",
1861 GNUNET_GNSRECORD_z2s (&rh->ac_tail->authority_info.gns_authority),
1865 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1866 _("GNS lookup failed (zero records found for `%s')\n"),
1868 fail_resolution (rh);
1872 if (0 == rh->name_resolution_pos)
1874 /* top-level match, are we done yet? */
1875 if ( (rd_count > 0) &&
1876 (GNUNET_DNSPARSER_TYPE_CNAME == rd[0].record_type) &&
1877 (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type) )
1880 cname = GNUNET_DNSPARSER_parse_name (rd[0].data,
1883 if ( (NULL == cname) ||
1884 (off != rd[0].data_size) )
1886 GNUNET_break_op (0);
1887 GNUNET_free_non_null (cname);
1888 fail_resolution (rh);
1891 handle_gns_cname_result (rh,
1893 GNUNET_free (cname);
1896 /* If A/AAAA was requested, but we got a VPN
1897 record, we convert it to A/AAAA using GNUnet VPN */
1898 if ( (GNUNET_DNSPARSER_TYPE_A == rh->record_type) ||
1899 (GNUNET_DNSPARSER_TYPE_AAAA == rh->record_type) )
1901 for (unsigned int i=0;i<rd_count;i++)
1903 switch (rd[i].record_type)
1905 case GNUNET_GNSRECORD_TYPE_VPN:
1907 af = (GNUNET_DNSPARSER_TYPE_A == rh->record_type) ? AF_INET : AF_INET6;
1908 if (sizeof (struct GNUNET_TUN_GnsVpnRecord) >
1911 GNUNET_break_op (0);
1912 fail_resolution (rh);
1915 vpn = (const struct GNUNET_TUN_GnsVpnRecord *) rd[i].data;
1916 vname = (const char *) &vpn[1];
1917 if ('\0' != vname[rd[i].data_size - 1 - sizeof (struct GNUNET_TUN_GnsVpnRecord)])
1919 GNUNET_break_op (0);
1920 fail_resolution (rh);
1923 GNUNET_TUN_service_name_to_hash (vname,
1925 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1926 "Attempting VPN allocation for %s-%s (AF: %d, proto %d)\n",
1927 GNUNET_i2s (&vpn->peer),
1930 (int) ntohs (vpn->proto));
1931 vpn_ctx = GNUNET_new (struct VpnContext);
1932 rh->vpn_ctx = vpn_ctx;
1934 vpn_ctx->rd_data_size = GNUNET_GNSRECORD_records_get_size (rd_count,
1936 if (vpn_ctx->rd_data_size < 0)
1938 GNUNET_break_op (0);
1939 GNUNET_free (vpn_ctx);
1940 fail_resolution (rh);
1943 vpn_ctx->rd_data = GNUNET_malloc ((size_t) vpn_ctx->rd_data_size);
1944 vpn_ctx->rd_count = rd_count;
1945 GNUNET_assert (vpn_ctx->rd_data_size ==
1946 GNUNET_GNSRECORD_records_serialize (rd_count,
1948 (size_t) vpn_ctx->rd_data_size,
1950 vpn_ctx->vpn_request = GNUNET_VPN_redirect_to_peer (vpn_handle,
1955 GNUNET_TIME_relative_to_absolute (VPN_TIMEOUT),
1960 case GNUNET_GNSRECORD_TYPE_GNS2DNS:
1962 /* delegation to DNS */
1963 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1964 "Found GNS2DNS record, delegating to DNS!\n");
1966 recursive_gns2dns_resolution (rh,
1977 } /* end: name_resolution_pos */
1978 /* convert relative names in record values to absolute names,
1979 using 'scratch' array for memory allocations */
1982 for (unsigned int i=0;i<rd_count;i++)
1984 GNUNET_assert (rd_off <= i);
1985 if ( (0 != rh->protocol) &&
1986 (0 != rh->service) &&
1987 (GNUNET_GNSRECORD_TYPE_BOX != rd[i].record_type) )
1988 continue; /* we _only_ care about boxed records */
1990 GNUNET_assert (rd_off < rd_count);
1991 rd_new[rd_off] = rd[i];
1992 /* Check if the embedded name(s) end in "+", and if so,
1993 replace the "+" with the zone at "ac_tail", changing the name
1994 to a ".ZONEKEY". The name is allocated on the 'scratch' array,
1995 so we can free it afterwards. */
1996 switch (rd[i].record_type)
1998 case GNUNET_DNSPARSER_TYPE_CNAME:
2003 cname = GNUNET_DNSPARSER_parse_name (rd[i].data,
2006 if ( (NULL == cname) ||
2007 (off != rd[i].data_size) )
2009 GNUNET_break_op (0); /* record not well-formed */
2013 cname = translate_dot_plus (rh, cname);
2014 GNUNET_break (NULL != cname);
2015 scratch_start = scratch_off;
2017 GNUNET_DNSPARSER_builder_add_name (scratch,
2026 GNUNET_assert (rd_off < rd_count);
2027 rd_new[rd_off].data = &scratch[scratch_start];
2028 rd_new[rd_off].data_size = scratch_off - scratch_start;
2032 GNUNET_free_non_null (cname);
2035 case GNUNET_DNSPARSER_TYPE_SOA:
2037 struct GNUNET_DNSPARSER_SoaRecord *soa;
2040 soa = GNUNET_DNSPARSER_parse_soa (rd[i].data,
2043 if ( (NULL == soa) ||
2044 (off != rd[i].data_size) )
2046 GNUNET_break_op (0); /* record not well-formed */
2050 soa->mname = translate_dot_plus (rh, soa->mname);
2051 soa->rname = translate_dot_plus (rh, soa->rname);
2052 scratch_start = scratch_off;
2054 GNUNET_DNSPARSER_builder_add_soa (scratch,
2063 GNUNET_assert (rd_off < rd_count);
2064 rd_new[rd_off].data = &scratch[scratch_start];
2065 rd_new[rd_off].data_size = scratch_off - scratch_start;
2070 GNUNET_DNSPARSER_free_soa (soa);
2073 case GNUNET_DNSPARSER_TYPE_MX:
2075 struct GNUNET_DNSPARSER_MxRecord *mx;
2078 mx = GNUNET_DNSPARSER_parse_mx (rd[i].data,
2081 if ( (NULL == mx) ||
2082 (off != rd[i].data_size) )
2084 GNUNET_break_op (0); /* record not well-formed */
2088 mx->mxhost = translate_dot_plus (rh, mx->mxhost);
2089 scratch_start = scratch_off;
2091 GNUNET_DNSPARSER_builder_add_mx (scratch,
2100 GNUNET_assert (rd_off < rd_count);
2101 rd_new[rd_off].data = &scratch[scratch_start];
2102 rd_new[rd_off].data_size = scratch_off - scratch_start;
2107 GNUNET_DNSPARSER_free_mx (mx);
2110 case GNUNET_DNSPARSER_TYPE_SRV:
2112 struct GNUNET_DNSPARSER_SrvRecord *srv;
2115 srv = GNUNET_DNSPARSER_parse_srv (rd[i].data,
2118 if ( (NULL == srv) ||
2119 (off != rd[i].data_size) )
2121 GNUNET_break_op (0); /* record not well-formed */
2125 srv->target = translate_dot_plus (rh, srv->target);
2126 scratch_start = scratch_off;
2128 GNUNET_DNSPARSER_builder_add_srv (scratch,
2137 GNUNET_assert (rd_off < rd_count);
2138 rd_new[rd_off].data = &scratch[scratch_start];
2139 rd_new[rd_off].data_size = scratch_off - scratch_start;
2144 GNUNET_DNSPARSER_free_srv (srv);
2148 case GNUNET_GNSRECORD_TYPE_NICK:
2153 if ((rd[i].data_size > 0) &&
2154 (nick[rd[i].data_size -1] != '\0'))
2156 GNUNET_break_op (0);
2161 case GNUNET_GNSRECORD_TYPE_PKEY:
2163 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
2165 if (rd[i].data_size != sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))
2167 GNUNET_break_op (0);
2170 GNUNET_memcpy (&pub,
2174 if (GNUNET_GNSRECORD_TYPE_PKEY != rh->record_type)
2176 /* try to resolve "@" */
2177 struct AuthorityChain *ac;
2179 ac = GNUNET_new (struct AuthorityChain);
2181 ac->gns_authority = GNUNET_YES;
2182 ac->authority_info.gns_authority = pub;
2183 ac->label = GNUNET_strdup (GNUNET_GNS_EMPTY_LABEL_AT);
2184 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
2187 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
2193 case GNUNET_GNSRECORD_TYPE_GNS2DNS:
2195 /* delegation to DNS */
2196 if (GNUNET_GNSRECORD_TYPE_GNS2DNS == rh->record_type)
2199 break; /* do not follow to DNS, we wanted the GNS2DNS record! */
2201 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2202 "Found GNS2DNS record, delegating to DNS!\n");
2204 recursive_gns2dns_resolution (rh,
2211 case GNUNET_GNSRECORD_TYPE_BOX:
2213 /* unbox SRV/TLSA records if a specific one was requested */
2214 if ( (0 != rh->protocol) &&
2215 (0 != rh->service) &&
2216 (rd[i].data_size >= sizeof (struct GNUNET_GNSRECORD_BoxRecord)) )
2218 const struct GNUNET_GNSRECORD_BoxRecord *box;
2221 if ( (ntohs (box->protocol) == rh->protocol) &&
2222 (ntohs (box->service) == rh->service) )
2224 /* Box matches, unbox! */
2225 GNUNET_assert (rd_off < rd_count);
2226 rd_new[rd_off].record_type = ntohl (box->record_type);
2227 rd_new[rd_off].data_size -= sizeof (struct GNUNET_GNSRECORD_BoxRecord);
2228 rd_new[rd_off].data = &box[1];
2234 /* no specific protocol/service specified, preserve all BOX
2235 records (for modern, GNS-enabled applications) */
2244 } /* end: for rd_count */
2246 /* yes, we are done, return result */
2247 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2248 "Returning GNS response for `%s' with %u answers\n",
2251 rh->proc (rh->proc_cls,
2254 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2259 switch (rd[0].record_type)
2261 case GNUNET_DNSPARSER_TYPE_CNAME:
2262 GNUNET_break_op (1 == rd_count); /* CNAME should be unique */
2263 recursive_cname_resolution (rh,
2266 case GNUNET_GNSRECORD_TYPE_PKEY:
2267 GNUNET_break_op (1 == rd_count); /* PKEY should be unique */
2268 recursive_pkey_resolution (rh,
2273 recursive_gns2dns_resolution (rh,
2280 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2281 _("GNS lookup recursion failed (no delegation record found)\n"));
2282 fail_resolution (rh);
2287 * Function called once the namestore has completed the request for
2290 * @param cls closure with the `struct CacheOps`
2291 * @param success #GNUNET_OK on success
2292 * @param emsg error message
2295 namecache_cache_continuation (void *cls,
2299 struct CacheOps *co = cls;
2301 co->namecache_qe_cache = NULL;
2302 if (GNUNET_OK != success)
2303 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2304 _("Failed to cache GNS resolution: %s\n"),
2306 GNUNET_CONTAINER_DLL_remove (co_head,
2314 * Iterator called on each result obtained for a DHT
2315 * operation that expects a reply
2317 * @param cls closure with the `struct GNS_ResolverHandle`
2318 * @param exp when will this value expire
2319 * @param key key of the result
2320 * @param get_path peers on reply path (or NULL if not recorded)
2321 * [0] = datastore's first neighbor, [length - 1] = local peer
2322 * @param get_path_length number of entries in @a get_path
2323 * @param put_path peers on the PUT path (or NULL if not recorded)
2324 * [0] = origin, [length - 1] = datastore
2325 * @param put_path_length number of entries in @a put_path
2326 * @param type type of the result
2327 * @param size number of bytes in data
2328 * @param data pointer to the result data
2331 handle_dht_response (void *cls,
2332 struct GNUNET_TIME_Absolute exp,
2333 const struct GNUNET_HashCode *key,
2334 const struct GNUNET_PeerIdentity *get_path,
2335 unsigned int get_path_length,
2336 const struct GNUNET_PeerIdentity *put_path,
2337 unsigned int put_path_length,
2338 enum GNUNET_BLOCK_Type type,
2342 struct GNS_ResolverHandle *rh = cls;
2343 struct AuthorityChain *ac = rh->ac_tail;
2344 const struct GNUNET_GNSRECORD_Block *block;
2345 struct CacheOps *co;
2350 (void) get_path_length;
2352 (void) put_path_length;
2354 GNUNET_DHT_get_stop (rh->get_handle);
2355 rh->get_handle = NULL;
2356 GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
2357 rh->dht_heap_node = NULL;
2358 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2359 "Handling response from the DHT\n");
2360 if (size < sizeof (struct GNUNET_GNSRECORD_Block))
2362 /* how did this pass DHT block validation!? */
2364 fail_resolution (rh);
2369 ntohl (block->purpose.size) +
2370 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) +
2371 sizeof (struct GNUNET_CRYPTO_EcdsaSignature))
2373 /* how did this pass DHT block validation!? */
2375 fail_resolution (rh);
2378 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2379 "Decrypting DHT block of size %u for `%s', expires %s\n",
2380 ntohl (block->purpose.size),
2382 GNUNET_STRINGS_absolute_time_to_string (exp));
2384 GNUNET_GNSRECORD_block_decrypt (block,
2385 &ac->authority_info.gns_authority,
2387 &handle_gns_resolution_result,
2390 GNUNET_break_op (0); /* block was ill-formed */
2391 fail_resolution (rh);
2394 if (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (block->expiration_time)).rel_value_us)
2396 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2397 "Received expired block from the DHT, will not cache it.\n");
2400 if (GNUNET_YES == disable_cache)
2402 /* Cache well-formed blocks */
2403 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2404 "Caching response from the DHT in namecache\n");
2405 co = GNUNET_new (struct CacheOps);
2406 co->namecache_qe_cache = GNUNET_NAMECACHE_block_cache (namecache_handle,
2408 &namecache_cache_continuation,
2410 GNUNET_CONTAINER_DLL_insert (co_head,
2417 * Initiate a DHT query for a set of GNS records.
2419 * @param rh resolution handle
2420 * @param query key to use in the DHT lookup
2423 start_dht_request (struct GNS_ResolverHandle *rh,
2424 const struct GNUNET_HashCode *query)
2426 struct GNS_ResolverHandle *rx;
2428 GNUNET_assert (NULL == rh->get_handle);
2429 rh->get_handle = GNUNET_DHT_get_start (dht_handle,
2430 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
2432 DHT_GNS_REPLICATION_LEVEL,
2433 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
2435 &handle_dht_response, rh);
2436 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
2438 GNUNET_TIME_absolute_get ().abs_value_us);
2439 if (GNUNET_CONTAINER_heap_get_size (dht_lookup_heap) > max_allowed_background_queries)
2441 /* fail longest-standing DHT request */
2442 rx = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
2443 rx->dht_heap_node = NULL;
2444 GNUNET_assert (NULL != rx);
2445 fail_resolution (rx);
2451 * Process a records that were decrypted from a block that we got from
2452 * the namecache. Simply calls #handle_gns_resolution_result().
2454 * @param cls closure with the `struct GNS_ResolverHandle`
2455 * @param rd_count number of entries in @a rd array
2456 * @param rd array of records with data to store
2459 handle_gns_namecache_resolution_result (void *cls,
2460 unsigned int rd_count,
2461 const struct GNUNET_GNSRECORD_Data *rd)
2463 struct GNS_ResolverHandle *rh = cls;
2466 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2467 _("GNS namecache returned empty result for `%s'\n"),
2469 handle_gns_resolution_result (rh,
2476 * Process a record that was stored in the namecache.
2478 * @param cls closure with the `struct GNS_ResolverHandle`
2479 * @param block block that was stored in the namecache
2482 handle_namecache_block_response (void *cls,
2483 const struct GNUNET_GNSRECORD_Block *block)
2485 struct GNS_ResolverHandle *rh = cls;
2486 struct AuthorityChain *ac = rh->ac_tail;
2487 const char *label = ac->label;
2488 const struct GNUNET_CRYPTO_EcdsaPublicKey *auth = &ac->authority_info.gns_authority;
2489 struct GNUNET_HashCode query;
2491 GNUNET_assert (NULL != rh->namecache_qe);
2492 rh->namecache_qe = NULL;
2493 if ( ( (GNUNET_GNS_LO_DEFAULT == rh->options) ||
2494 ( (GNUNET_GNS_LO_LOCAL_MASTER == rh->options) &&
2495 (ac != rh->ac_head) ) ) &&
2496 ( (NULL == block) ||
2497 (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (block->expiration_time)).rel_value_us) ) )
2499 /* namecache knows nothing; try DHT lookup */
2500 GNUNET_GNSRECORD_query_from_public_key (auth,
2503 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2504 "Starting DHT lookup for `%s' in zone `%s' under key `%s'\n",
2506 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority),
2507 GNUNET_h2s (&query));
2508 start_dht_request (rh, &query);
2512 if ( (NULL == block) ||
2513 (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (block->expiration_time)).rel_value_us) )
2515 /* DHT not permitted and no local result, fail */
2516 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2517 "Resolution failed for `%s' in zone %s (DHT lookup not permitted by configuration)\n",
2519 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2520 fail_resolution (rh);
2523 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2524 "Received result from namecache for label `%s'\n",
2528 GNUNET_GNSRECORD_block_decrypt (block,
2531 &handle_gns_namecache_resolution_result,
2534 GNUNET_break_op (0); /* block was ill-formed */
2535 /* try DHT instead */
2536 GNUNET_GNSRECORD_query_from_public_key (auth,
2539 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2540 "Starting DHT lookup for `%s' in zone `%s' under key `%s'\n",
2542 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority),
2543 GNUNET_h2s (&query));
2544 start_dht_request (rh, &query);
2551 * Lookup tail of our authority chain in the namecache.
2553 * @param rh query we are processing
2556 recursive_gns_resolution_namecache (struct GNS_ResolverHandle *rh)
2558 struct AuthorityChain *ac = rh->ac_tail;
2559 struct GNUNET_HashCode query;
2561 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2562 "Starting GNS resolution for `%s' in zone %s\n",
2564 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2565 GNUNET_GNSRECORD_query_from_public_key (&ac->authority_info.gns_authority,
2568 if (GNUNET_YES != disable_cache)
2571 = GNUNET_NAMECACHE_lookup_block (namecache_handle,
2573 &handle_namecache_block_response,
2575 GNUNET_assert (NULL != rh->namecache_qe);
2579 start_dht_request (rh,
2586 * Function called with the result from a revocation check.
2588 * @param cls the `struct GNS_ResovlerHandle`
2589 * @param is_valid #GNUNET_YES if the zone was not yet revoked
2592 handle_revocation_result (void *cls,
2595 struct GNS_ResolverHandle *rh = cls;
2596 struct AuthorityChain *ac = rh->ac_tail;
2598 rh->rev_check = NULL;
2599 if (GNUNET_YES != is_valid)
2601 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2602 _("Zone %s was revoked, resolution fails\n"),
2603 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2604 fail_resolution (rh);
2607 recursive_gns_resolution_namecache (rh);
2612 * Perform revocation check on tail of our authority chain.
2614 * @param rh query we are processing
2617 recursive_gns_resolution_revocation (struct GNS_ResolverHandle *rh)
2619 struct AuthorityChain *ac = rh->ac_tail;
2621 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2622 "Starting revocation check for zone %s\n",
2623 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2624 rh->rev_check = GNUNET_REVOCATION_query (cfg,
2625 &ac->authority_info.gns_authority,
2626 &handle_revocation_result,
2628 GNUNET_assert (NULL != rh->rev_check);
2633 * Task scheduled to continue with the resolution process.
2635 * @param cls the `struct GNS_ResolverHandle` of the resolution
2638 recursive_resolution (void *cls)
2640 struct GNS_ResolverHandle *rh = cls;
2643 if (MAX_RECURSION < rh->loop_limiter++)
2645 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2646 "Encountered unbounded recursion resolving `%s'\n",
2648 fail_resolution (rh);
2651 if (GNUNET_YES == rh->ac_tail->gns_authority)
2652 recursive_gns_resolution_revocation (rh);
2654 recursive_dns_resolution (rh);
2659 * Begin the resolution process from 'name', starting with
2660 * the identification of the zone specified by 'name'.
2662 * @param cls the `struct GNS_ResolverHandle`
2665 start_resolver_lookup (void *cls)
2667 struct GNS_ResolverHandle *rh = cls;
2668 struct AuthorityChain *ac;
2673 if (1 == inet_pton (AF_INET,
2677 /* name is IPv4 address, pretend it's an A record */
2678 struct GNUNET_GNSRECORD_Data rd;
2681 rd.data_size = sizeof (v4);
2682 rd.expiration_time = UINT64_MAX;
2683 rd.record_type = GNUNET_DNSPARSER_TYPE_A;
2685 rh->proc (rh->proc_cls,
2688 GNUNET_assert (NULL == rh->task_id);
2689 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2693 if (1 == inet_pton (AF_INET6,
2697 /* name is IPv6 address, pretend it's an AAAA record */
2698 struct GNUNET_GNSRECORD_Data rd;
2701 rd.data_size = sizeof (v6);
2702 rd.expiration_time = UINT64_MAX;
2703 rd.record_type = GNUNET_DNSPARSER_TYPE_AAAA;
2705 rh->proc (rh->proc_cls,
2708 GNUNET_assert (NULL == rh->task_id);
2709 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2714 ac = GNUNET_new (struct AuthorityChain);
2716 ac->label = resolver_lookup_get_next_label (rh);
2717 if (NULL == ac->label)
2718 /* name was just the "TLD", so we default to label
2719 #GNUNET_GNS_EMPTY_LABEL_AT */
2720 ac->label = GNUNET_strdup (GNUNET_GNS_EMPTY_LABEL_AT);
2721 ac->gns_authority = GNUNET_YES;
2722 ac->authority_info.gns_authority = rh->authority_zone;
2723 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
2726 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
2732 * Lookup of a record in a specific zone calls lookup result processor
2735 * @param zone the zone to perform the lookup in
2736 * @param record_type the record type to look up
2737 * @param name the name to look up
2738 * @param options local options to control local lookup
2739 * @param proc the processor to call on result
2740 * @param proc_cls the closure to pass to @a proc
2741 * @return handle to cancel operation
2743 struct GNS_ResolverHandle *
2744 GNS_resolver_lookup (const struct GNUNET_CRYPTO_EcdsaPublicKey *zone,
2745 uint32_t record_type,
2747 enum GNUNET_GNS_LocalOptions options,
2748 GNS_ResultProcessor proc,
2751 struct GNS_ResolverHandle *rh;
2753 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2754 "Starting lookup for `%s'\n",
2756 rh = GNUNET_new (struct GNS_ResolverHandle);
2757 GNUNET_CONTAINER_DLL_insert (rlh_head,
2760 rh->authority_zone = *zone;
2762 rh->proc_cls = proc_cls;
2763 rh->options = options;
2764 rh->record_type = record_type;
2765 rh->name = GNUNET_strdup (name);
2766 rh->name_resolution_pos = strlen (name);
2767 rh->task_id = GNUNET_SCHEDULER_add_now (&start_resolver_lookup,
2774 * Cancel active resolution (i.e. client disconnected).
2776 * @param rh resolution to abort
2779 GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
2781 struct DnsResult *dr;
2782 struct AuthorityChain *ac;
2783 struct VpnContext *vpn_ctx;
2785 GNUNET_CONTAINER_DLL_remove (rlh_head,
2788 if (NULL != rh->dns_request)
2790 GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
2791 rh->dns_request = NULL;
2793 while (NULL != (ac = rh->ac_head))
2795 GNUNET_CONTAINER_DLL_remove (rh->ac_head,
2798 if (GNUNET_NO == ac->gns_authority)
2800 struct Gns2DnsPending *gp;
2802 while (NULL != (gp = ac->authority_info.dns_authority.gp_head))
2804 GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
2805 ac->authority_info.dns_authority.gp_tail,
2809 /* rh->g2dc->rh is NOT in the DLL yet, so to enable us
2810 using GNS_resolver_lookup_cancel here, we need to
2812 GNUNET_CONTAINER_DLL_insert (rlh_head,
2815 GNUNET_assert (NULL == gp->rh->task_id);
2816 gp->rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2820 if (NULL != gp->dns_rh)
2822 GNUNET_RESOLVER_request_cancel (gp->dns_rh);
2827 GNUNET_DNSSTUB_stop (ac->authority_info.dns_authority.dns_handle);
2829 GNUNET_free (ac->label);
2832 if (NULL != rh->task_id)
2834 GNUNET_SCHEDULER_cancel (rh->task_id);
2837 if (NULL != rh->get_handle)
2839 GNUNET_DHT_get_stop (rh->get_handle);
2840 rh->get_handle = NULL;
2842 if (NULL != rh->dht_heap_node)
2844 GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
2845 rh->dht_heap_node = NULL;
2847 if (NULL != (vpn_ctx = rh->vpn_ctx))
2849 GNUNET_VPN_cancel_request (vpn_ctx->vpn_request);
2850 GNUNET_free (vpn_ctx->rd_data);
2851 GNUNET_free (vpn_ctx);
2853 if (NULL != rh->namecache_qe)
2855 GNUNET_NAMECACHE_cancel (rh->namecache_qe);
2856 rh->namecache_qe = NULL;
2858 if (NULL != rh->rev_check)
2860 GNUNET_REVOCATION_query_cancel (rh->rev_check);
2861 rh->rev_check = NULL;
2863 if (NULL != rh->std_resolve)
2865 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2866 "Canceling standard DNS resolution\n");
2867 GNUNET_RESOLVER_request_cancel (rh->std_resolve);
2868 rh->std_resolve = NULL;
2870 while (NULL != (dr = rh->dns_result_head))
2872 GNUNET_CONTAINER_DLL_remove (rh->dns_result_head,
2873 rh->dns_result_tail,
2877 GNUNET_free_non_null (rh->leho);
2878 GNUNET_free (rh->name);
2883 /* ***************** Resolver initialization ********************* */
2887 * Initialize the resolver
2889 * @param nc the namecache handle
2890 * @param dht the dht handle
2891 * @param c configuration handle
2892 * @param max_bg_queries maximum number of parallel background queries in dht
2895 GNS_resolver_init (struct GNUNET_NAMECACHE_Handle *nc,
2896 struct GNUNET_DHT_Handle *dht,
2897 const struct GNUNET_CONFIGURATION_Handle *c,
2898 unsigned long long max_bg_queries)
2901 namecache_handle = nc;
2904 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
2905 max_allowed_background_queries = max_bg_queries;
2906 disable_cache = GNUNET_CONFIGURATION_get_value_yesno (cfg,
2909 if (GNUNET_YES == disable_cache)
2910 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2911 "Namecache disabled\n");
2912 vpn_handle = GNUNET_VPN_connect (cfg);
2920 GNS_resolver_done ()
2922 struct GNS_ResolverHandle *rh;
2923 struct CacheOps *co;
2925 /* abort active resolutions */
2926 while (NULL != (rh = rlh_head))
2928 rh->proc (rh->proc_cls,
2931 GNS_resolver_lookup_cancel (rh);
2933 while (NULL != (co = co_head))
2935 GNUNET_CONTAINER_DLL_remove (co_head,
2938 GNUNET_NAMECACHE_cancel (co->namecache_qe_cache);
2941 GNUNET_CONTAINER_heap_destroy (dht_lookup_heap);
2942 dht_lookup_heap = NULL;
2943 GNUNET_VPN_disconnect (vpn_handle);
2946 namecache_handle = NULL;
2950 /* end of gnunet-service-gns_resolver.c */