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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
22 * @file gns/gnunet-service-gns_resolver.c
23 * @brief GNU Name System resolver logic
24 * @author Martin Schanzenbach
25 * @author Christian Grothoff
31 #elif HAVE_IDN2_IDN2_H
32 #include <idn2/idn2.h>
41 #include "gnunet_util_lib.h"
42 #include "gnunet_dnsstub_lib.h"
43 #include "gnunet_dht_service.h"
44 #include "gnunet_gnsrecord_lib.h"
45 #include "gnunet_namecache_service.h"
46 #include "gnunet_dns_service.h"
47 #include "gnunet_resolver_service.h"
48 #include "gnunet_revocation_service.h"
49 #include "gnunet_dnsparser_lib.h"
50 #include "gnunet_tun_lib.h"
51 #include "gnunet_gns_service.h"
53 #include "gnunet-service-gns.h"
54 #include "gnunet-service-gns_resolver.h"
55 #include "gnunet_vpn_service.h"
59 * Default DHT timeout for lookups.
61 #define DHT_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply ( \
62 GNUNET_TIME_UNIT_SECONDS, 60)
65 * Default timeout for DNS lookups.
67 #define DNS_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply ( \
68 GNUNET_TIME_UNIT_SECONDS, 15)
71 * Default timeout for VPN redirections.
73 #define VPN_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
76 * DHT replication level
78 #define DHT_GNS_REPLICATION_LEVEL 10
81 * How deep do we allow recursions to go before we abort?
83 #define MAX_RECURSION 256
87 * DLL to hold the authority chain we had to pass in the resolution
90 struct AuthorityChain;
94 * Element of a resolution process for looking up the
95 * responsible DNS server hostname in a GNS2DNS recursive
103 struct Gns2DnsPending *next;
108 struct Gns2DnsPending *prev;
111 * Context this activity belongs with.
113 struct AuthorityChain *ac;
116 * Handle for the resolution of the IP part of the
117 * GNS2DNS record. Will return to us the addresses
118 * of the DNS resolver to use.
120 struct GNS_ResolverHandle *rh;
123 * Handle for DNS resolution of the DNS nameserver.
125 struct GNUNET_RESOLVER_RequestHandle *dns_rh;
128 * How many results did we get?
130 unsigned int num_results;
135 * Handle to a currenty pending resolution. On result (positive or
136 * negative) the #GNS_ResultProcessor is called.
138 struct GNS_ResolverHandle;
142 * DLL to hold the authority chain we had to pass in the resolution
145 struct AuthorityChain
150 struct AuthorityChain *prev;
155 struct AuthorityChain *next;
158 * Resolver handle this entry in the chain belongs to.
160 struct GNS_ResolverHandle *rh;
163 * label/name corresponding to the authority
168 * #GNUNET_YES if the authority was a GNS authority,
169 * #GNUNET_NO if the authority was a DNS authority.
174 * Information about the resolver authority for this label.
179 * The zone of the GNS authority
181 struct GNUNET_CRYPTO_EcdsaPublicKey gns_authority;
186 * Domain of the DNS resolver that is the authority.
187 * (appended to construct the DNS name to resolve;
188 * this is NOT the DNS name of the DNS server!).
190 char name[GNUNET_DNSPARSER_MAX_NAME_LENGTH + 1];
193 * List of resolutions of the 'ip' of the name server that
196 struct Gns2DnsPending *gp_head;
199 * Tail of list of resolutions of the 'ip' of the name server that
202 struct Gns2DnsPending *gp_tail;
205 * Handle to perform DNS lookups with this authority (in GNS2DNS handling).
207 struct GNUNET_DNSSTUB_Context *dns_handle;
210 * Did we succeed in getting an IP address for *any* of the DNS servers listed?
211 * Once we do, we can start with DNS queries.
216 * Did we start the recursive resolution via DNS?
225 * A result we got from DNS.
232 struct DnsResult *next;
237 struct DnsResult *prev;
240 * Binary value stored in the DNS record (appended to this struct)
245 * Expiration time for the DNS record, 0 if we didn't
246 * get anything useful (i.e. 'gethostbyname()' was used).
248 uint64_t expiration_time;
251 * Number of bytes in @e data.
256 * Type of the GNS/DNS record.
258 uint32_t record_type;
263 * Closure for #vpn_allocation_cb.
268 * Which resolution process are we processing.
270 struct GNS_ResolverHandle *rh;
273 * Handle to the VPN request that we were performing.
275 struct GNUNET_VPN_RedirectionRequest *vpn_request;
278 * Number of records serialized in @e rd_data.
280 unsigned int rd_count;
283 * Serialized records.
288 * Number of bytes in @e rd_data.
290 ssize_t rd_data_size;
295 * Handle to a currenty pending resolution. On result (positive or
296 * negative) the #GNS_ResultProcessor is called.
298 struct GNS_ResolverHandle
303 struct GNS_ResolverHandle *next;
308 struct GNS_ResolverHandle *prev;
311 * The top-level GNS authoritative zone to query
313 struct GNUNET_CRYPTO_EcdsaPublicKey authority_zone;
316 * called when resolution phase finishes
318 GNS_ResultProcessor proc;
321 * closure passed to @e proc
326 * Handle for DHT lookups. should be NULL if no lookups are in progress
328 struct GNUNET_DHT_GetHandle *get_handle;
331 * Handle to a VPN request, NULL if none is active.
333 struct VpnContext *vpn_ctx;
336 * Socket for a DNS request, NULL if none is active.
338 struct GNUNET_DNSSTUB_RequestSocket *dns_request;
341 * Handle for standard DNS resolution, NULL if none is active.
343 struct GNUNET_RESOLVER_RequestHandle *std_resolve;
346 * Pending Namecache lookup task
348 struct GNUNET_NAMECACHE_QueueEntry *namecache_qe;
351 * Pending revocation check.
353 struct GNUNET_REVOCATION_Query *rev_check;
356 * Heap node associated with this lookup. Used to limit number of
357 * concurrent requests.
359 struct GNUNET_CONTAINER_HeapNode *dht_heap_node;
362 * DLL to store the authority chain
364 struct AuthorityChain *ac_head;
367 * DLL to store the authority chain
369 struct AuthorityChain *ac_tail;
372 * ID of a task associated with the resolution process.
374 struct GNUNET_SCHEDULER_Task *task_id;
377 * The name to resolve
382 * Legacy Hostname to use if we encountered GNS2DNS record
383 * and thus can deduct the LEHO from that transition.
388 * DLL of results we got from DNS.
390 struct DnsResult *dns_result_head;
393 * DLL of results we got from DNS.
395 struct DnsResult *dns_result_tail;
398 * Current offset in 'name' where we are resolving.
400 size_t name_resolution_pos;
405 enum GNUNET_GNS_LocalOptions options;
408 * For SRV and TLSA records, the number of the
409 * protocol specified in the name. 0 if no protocol was given.
414 * For SRV and TLSA records, the number of the
415 * service specified in the name. 0 if no service was given.
420 * Desired type for the resolution.
425 * We increment the loop limiter for each step in a recursive
426 * resolution. If it passes our threshold (i.e. due to
427 * self-recursion in the resolution, i.e CNAME fun), we stop.
429 unsigned int loop_limiter;
432 * 16 bit random ID we used in the @e dns_request.
434 uint16_t original_dns_id;
439 * Active namestore caching operations.
444 * Organized in a DLL.
446 struct CacheOps *next;
449 * Organized in a DLL.
451 struct CacheOps *prev;
454 * Pending Namestore caching task.
456 struct GNUNET_NAMECACHE_QueueEntry *namecache_qe_cache;
461 * Our handle to the namecache service
463 static struct GNUNET_NAMECACHE_Handle *namecache_handle;
466 * Our handle to the vpn service
468 static struct GNUNET_VPN_Handle *vpn_handle;
471 * Resolver handle to the dht
473 static struct GNUNET_DHT_Handle *dht_handle;
476 * Heap for limiting parallel DHT lookups
478 static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
481 * Maximum amount of parallel queries to the DHT
483 static unsigned long long max_allowed_background_queries;
486 * Head of resolver lookup list
488 static struct GNS_ResolverHandle *rlh_head;
491 * Tail of resolver lookup list
493 static struct GNS_ResolverHandle *rlh_tail;
496 * Organized in a DLL.
498 static struct CacheOps *co_head;
501 * Organized in a DLL.
503 static struct CacheOps *co_tail;
508 static int disable_cache;
511 * Global configuration.
513 static const struct GNUNET_CONFIGURATION_Handle *cfg;
517 * Determine if this name is canonical (is a legal name in a zone, without delegation);
518 * note that we do not test that the name does not contain illegal characters, we only
519 * test for delegation. Note that service records (i.e. _foo._srv) are canonical names
520 * even though they consist of multiple labels.
523 * a.b.gnu = not canonical
525 * _foo._srv = canonical
526 * _f.bar = not canonical
528 * @param name the name to test
529 * @return #GNUNET_YES if canonical
531 /* dead, but keep for now */ int
532 is_canonical (const char *name)
537 if (NULL == strchr (name,
538 (unsigned char) '.'))
543 while (NULL != (dot = strchr (pos,
544 (unsigned char) '.')))
553 /* ************************** Resolution **************************** */
556 * Expands a name ending in .+ with the zone of origin.
558 * @param rh resolution context
559 * @param name name to modify (to be free'd or returned)
560 * @return updated name
563 translate_dot_plus (struct GNS_ResolverHandle *rh,
567 size_t s_len = strlen (name);
569 if (0 != strcmp (&name[s_len - 2],
571 return name; /* did not end in ".+" */
572 GNUNET_assert (GNUNET_YES == rh->ac_tail->gns_authority);
573 GNUNET_asprintf (&ret,
577 GNUNET_GNSRECORD_pkey_to_zkey (
578 &rh->ac_tail->authority_info.gns_authority));
585 * Wrapper around #GNS_resolver_lookup_cancel() as a task.
586 * Used for delayed cleanup so we can unwind the stack first.
588 * @param cls the `struct GNS_ResolverHandle`
591 GNS_resolver_lookup_cancel_ (void *cls)
593 struct GNS_ResolverHandle *rh = cls;
596 GNS_resolver_lookup_cancel (rh);
601 * Function called to asynchronously fail a resolution.
603 * @param rh the resolution to fail
606 fail_resolution (struct GNS_ResolverHandle *rh)
608 rh->proc (rh->proc_cls,
611 GNUNET_assert (NULL == rh->task_id);
612 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
618 * Function called when a resolution times out.
620 * @param cls the `struct GNS_ResolverHandle`
623 timeout_resolution (void *cls)
625 struct GNS_ResolverHandle *rh = cls;
628 fail_resolution (rh);
633 * Get the next, rightmost label from the name that we are trying to resolve,
634 * and update the resolution position accordingly. Labels usually consist
635 * of up to 63 characters without a period ("."); however, we use a special
636 * convention to support SRV and TLSA records where the domain name
637 * includes an encoding for a service and protocol in the name. The
638 * syntax (see RFC 2782) here is "_Service._Proto.Name" and in this
639 * special case we include the "_Service._Proto" in the rightmost label.
640 * Thus, for "_443._tcp.foo.bar" we first return the label "bar" and then
641 * the label "_443._tcp.foo". The special case is detected by the
642 * presence of labels beginning with an underscore. Whenever a label
643 * begins with an underscore, it is combined with the label to its right
644 * (and the "." is preserved).
646 * @param rh handle to the resolution operation to get the next label from
647 * @return NULL if there are no more labels
650 resolver_lookup_get_next_label (struct GNS_ResolverHandle *rh)
661 if (0 == rh->name_resolution_pos)
663 dot = memrchr (rh->name,
665 rh->name_resolution_pos);
668 /* done, this was the last one */
669 len = rh->name_resolution_pos;
671 rh->name_resolution_pos = 0;
675 /* advance by one label */
676 len = rh->name_resolution_pos - (dot - rh->name) - 1;
678 rh->name_resolution_pos = dot - rh->name;
682 ret = GNUNET_strndup (rp, len);
683 /* If we have labels starting with underscore with label on
684 * the right (SRV/DANE/BOX case), determine port/protocol;
685 * The format of `rh->name` must be "_PORT._PROTOCOL".
687 if (('_' == rh->name[0]) &&
688 (NULL != (dot = memrchr (rh->name,
690 rh->name_resolution_pos))) &&
692 (NULL == memrchr (rh->name,
696 srv_name = GNUNET_strndup (&rh->name[1],
697 (dot - rh->name) - 1);
698 proto_name = GNUNET_strndup (&dot[2],
699 rh->name_resolution_pos - (dot - rh->name)
701 rh->name_resolution_pos = 0;
702 pe = getprotobyname (proto_name);
705 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
706 _ ("Protocol `%s' unknown, skipping labels.\n"),
708 GNUNET_free (proto_name);
709 GNUNET_free (srv_name);
712 se = getservbyname (srv_name,
716 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
718 "Service `%s' unknown for protocol `%s', skipping labels.\n"),
721 GNUNET_free (proto_name);
722 GNUNET_free (srv_name);
725 rh->protocol = pe->p_proto;
726 rh->service = se->s_port;
727 GNUNET_free (proto_name);
728 GNUNET_free (srv_name);
735 * Gives the cummulative result obtained to the callback and clean up the request.
737 * @param rh resolution process that has culminated in a result
740 transmit_lookup_dns_result (struct GNS_ResolverHandle *rh)
742 struct DnsResult *pos;
747 for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
750 struct GNUNET_GNSRECORD_Data rd[n];
753 for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
755 rd[i].data = pos->data;
756 rd[i].data_size = pos->data_size;
757 rd[i].record_type = pos->record_type;
758 if (0 == pos->expiration_time)
760 rd[i].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
761 rd[i].expiration_time = 0;
765 rd[i].flags = GNUNET_GNSRECORD_RF_NONE;
766 rd[i].expiration_time = pos->expiration_time;
770 GNUNET_assert (i == n);
771 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
772 "Transmitting standard DNS result with %u records\n",
774 rh->proc (rh->proc_cls,
778 GNS_resolver_lookup_cancel (rh);
783 * Add a result from DNS to the records to be returned to the application.
785 * @param rh resolution request to extend with a result
786 * @param expiration_time expiration time for the answer
787 * @param record_type DNS record type of the answer
788 * @param data_size number of bytes in @a data
789 * @param data binary data to return in DNS record
792 add_dns_result (struct GNS_ResolverHandle *rh,
793 uint64_t expiration_time,
794 uint32_t record_type,
798 struct DnsResult *res;
800 res = GNUNET_malloc (sizeof(struct DnsResult) + data_size);
801 res->expiration_time = expiration_time;
802 res->data_size = data_size;
803 res->record_type = record_type;
805 GNUNET_memcpy (&res[1],
808 GNUNET_CONTAINER_DLL_insert (rh->dns_result_head,
815 * We had to do a DNS lookup. Convert the result (if any) and return
818 * @param cls closure with the `struct GNS_ResolverHandle`
819 * @param addr one of the addresses of the host, NULL for the last address
820 * @param addrlen length of the address
823 handle_dns_result (void *cls,
824 const struct sockaddr *addr,
827 struct GNS_ResolverHandle *rh = cls;
828 const struct sockaddr_in *sa4;
829 const struct sockaddr_in6 *sa6;
833 rh->std_resolve = NULL;
834 transmit_lookup_dns_result (rh);
837 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
838 "Received %u bytes of DNS IP data\n",
840 switch (addr->sa_family)
843 sa4 = (const struct sockaddr_in *) addr;
845 0 /* expiration time is unknown */,
846 GNUNET_DNSPARSER_TYPE_A,
847 sizeof(struct in_addr),
852 sa6 = (const struct sockaddr_in6 *) addr;
854 0 /* expiration time is unknown */,
855 GNUNET_DNSPARSER_TYPE_AAAA,
856 sizeof(struct in6_addr),
868 * Task scheduled to continue with the resolution process.
870 * @param cls the 'struct GNS_ResolverHandle' of the resolution
871 * @param tc task context
874 recursive_resolution (void *cls);
878 * Begin the resolution process from 'name', starting with
879 * the identification of the zone specified by 'name'.
881 * @param cls closure with `struct GNS_ResolverHandle *rh`
884 start_resolver_lookup (void *cls);
888 * Function called with the result of a DNS resolution.
890 * @param cls the request handle of the resolution that
891 * we were attempting to make
892 * @param dns dns response, never NULL
893 * @param dns_len number of bytes in @a dns
896 dns_result_parser (void *cls,
897 const struct GNUNET_TUN_DnsHeader *dns,
900 struct GNS_ResolverHandle *rh = cls;
901 struct GNUNET_DNSPARSER_Packet *p;
902 const struct GNUNET_DNSPARSER_Record *rec;
903 unsigned int rd_count;
907 rh->dns_request = NULL;
908 GNUNET_SCHEDULER_cancel (rh->task_id);
910 fail_resolution (rh);
913 if (rh->original_dns_id != dns->id)
915 /* DNS answer, but for another query */
918 p = GNUNET_DNSPARSER_parse ((const char *) dns,
922 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
923 _ ("Failed to parse DNS response\n"));
927 /* We got a result from DNS */
928 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
929 "Received DNS response for `%s' with %u answers\n",
931 (unsigned int) p->num_answers);
932 if ((p->num_answers > 0) &&
933 (GNUNET_DNSPARSER_TYPE_CNAME == p->answers[0].type) &&
934 (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type))
938 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
939 "Got CNAME `%s' from DNS for `%s'\n",
940 p->answers[0].data.hostname,
942 if (NULL != rh->std_resolve)
944 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
945 "Multiple CNAME results from DNS resolving `%s'! Not really allowed...\n",
947 GNUNET_RESOLVER_request_cancel (rh->std_resolve);
949 GNUNET_free (rh->name);
950 rh->name = GNUNET_strdup (p->answers[0].data.hostname);
951 rh->name_resolution_pos = strlen (rh->name);
952 switch (rh->record_type)
954 case GNUNET_DNSPARSER_TYPE_A:
958 case GNUNET_DNSPARSER_TYPE_AAAA:
966 if (NULL != rh->leho)
968 GNUNET_TIME_UNIT_HOURS.rel_value_us,
969 GNUNET_GNSRECORD_TYPE_LEHO,
972 rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name,
977 GNUNET_DNSPARSER_free_packet (p);
978 GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
979 rh->dns_request = NULL;
983 /* convert from (parsed) DNS to (binary) GNS format! */
984 rd_count = p->num_answers + p->num_authority_records
985 + p->num_additional_records;
987 struct GNUNET_GNSRECORD_Data rd[rd_count + 1]; /* +1 for LEHO */
989 char buf[UINT16_MAX];
998 for (unsigned int i = 0; i < rd_count; i++)
1000 if (i < p->num_answers)
1001 rec = &p->answers[i];
1002 else if (i < p->num_answers + p->num_authority_records)
1003 rec = &p->authority_records[i - p->num_answers];
1005 rec = &p->additional_records[i - p->num_answers
1006 - p->num_authority_records];
1007 /* As we copied the full DNS name to 'rh->ac_tail->label', this
1008 should be the correct check to see if this record is actually
1009 a record for our label... */
1010 if (0 != strcmp (rec->name,
1011 rh->ac_tail->label))
1013 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1014 "Dropping record `%s', does not match desired name `%s'\n",
1016 rh->ac_tail->label);
1020 rd[i - skip].record_type = rec->type;
1021 rd[i - skip].expiration_time = rec->expiration_time.abs_value_us;
1024 case GNUNET_DNSPARSER_TYPE_A:
1025 if (rec->data.raw.data_len != sizeof(struct in_addr))
1027 GNUNET_break_op (0);
1031 rd[i - skip].data_size = rec->data.raw.data_len;
1032 rd[i - skip].data = rec->data.raw.data;
1035 case GNUNET_DNSPARSER_TYPE_AAAA:
1036 if (rec->data.raw.data_len != sizeof(struct in6_addr))
1038 GNUNET_break_op (0);
1042 rd[i - skip].data_size = rec->data.raw.data_len;
1043 rd[i - skip].data = rec->data.raw.data;
1046 case GNUNET_DNSPARSER_TYPE_CNAME:
1047 case GNUNET_DNSPARSER_TYPE_PTR:
1048 case GNUNET_DNSPARSER_TYPE_NS:
1049 buf_start = buf_off;
1051 GNUNET_DNSPARSER_builder_add_name (buf,
1054 rec->data.hostname))
1060 rd[i - skip].data_size = buf_off - buf_start;
1061 rd[i - skip].data = &buf[buf_start];
1064 case GNUNET_DNSPARSER_TYPE_SOA:
1065 buf_start = buf_off;
1067 GNUNET_DNSPARSER_builder_add_soa (buf,
1076 rd[i - skip].data_size = buf_off - buf_start;
1077 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];
1096 case GNUNET_DNSPARSER_TYPE_SRV:
1097 buf_start = buf_off;
1099 GNUNET_DNSPARSER_builder_add_srv (buf,
1108 rd[i - skip].data_size = buf_off - buf_start;
1109 rd[i - skip].data = &buf[buf_start];
1113 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1114 _ ("Skipping record of unsupported type %d\n"),
1119 } /* end of for all records in answer */
1120 if (NULL != rh->leho)
1122 rd[rd_count - skip].record_type = GNUNET_GNSRECORD_TYPE_LEHO;
1123 rd[rd_count - skip].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1124 rd[rd_count - skip].expiration_time = GNUNET_TIME_UNIT_HOURS.rel_value_us;
1125 rd[rd_count - skip].data = rh->leho;
1126 rd[rd_count - skip].data_size = strlen (rh->leho);
1127 skip--; /* skip one LESS */
1128 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1132 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1133 "Returning DNS response for `%s' with %u answers\n",
1135 (unsigned int) (rd_count - skip));
1136 rh->proc (rh->proc_cls,
1139 GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
1140 rh->dns_request = NULL;
1142 GNUNET_DNSPARSER_free_packet (p);
1143 if (NULL != rh->task_id)
1144 GNUNET_SCHEDULER_cancel (rh->task_id); /* should be timeout task */
1145 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
1151 * Perform recursive DNS resolution. Asks the given DNS resolver to
1152 * resolve "rh->dns_name", possibly recursively proceeding following
1153 * NS delegations, CNAMES, etc., until 'rh->loop_limiter' bounds us or
1154 * we find the answer.
1156 * @param rh resolution information
1159 recursive_dns_resolution (struct GNS_ResolverHandle *rh)
1161 struct AuthorityChain *ac;
1162 struct GNUNET_DNSPARSER_Query *query;
1163 struct GNUNET_DNSPARSER_Packet *p;
1165 size_t dns_request_length;
1169 GNUNET_assert (NULL != ac);
1170 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1171 "Starting DNS lookup for `%s'\n",
1173 GNUNET_assert (GNUNET_NO == ac->gns_authority);
1174 query = GNUNET_new (struct GNUNET_DNSPARSER_Query);
1175 query->name = GNUNET_strdup (ac->label);
1176 query->type = rh->record_type;
1177 query->dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
1178 p = GNUNET_new (struct GNUNET_DNSPARSER_Packet);
1181 p->id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1183 p->flags.opcode = GNUNET_TUN_DNS_OPCODE_QUERY;
1184 p->flags.recursion_desired = 1;
1185 ret = GNUNET_DNSPARSER_pack (p,
1188 &dns_request_length);
1189 if (GNUNET_OK != ret)
1192 rh->proc (rh->proc_cls,
1195 GNUNET_assert (NULL == rh->task_id);
1196 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
1201 rh->original_dns_id = p->id;
1202 GNUNET_assert (NULL != ac->authority_info.dns_authority.dns_handle);
1203 GNUNET_assert (NULL == rh->dns_request);
1204 rh->leho = GNUNET_strdup (ac->label);
1205 rh->dns_request = GNUNET_DNSSTUB_resolve (
1206 ac->authority_info.dns_authority.dns_handle,
1211 rh->task_id = GNUNET_SCHEDULER_add_delayed (DNS_LOOKUP_TIMEOUT,
1212 &timeout_resolution,
1215 if (GNUNET_SYSERR != ret)
1216 GNUNET_free (dns_request);
1217 GNUNET_DNSPARSER_free_packet (p);
1222 * We encountered a CNAME record during our resolution.
1223 * Merge it into our chain.
1225 * @param rh resolution we are performing
1226 * @param cname value of the cname record we got for the current
1227 * authority chain tail
1230 handle_gns_cname_result (struct GNS_ResolverHandle *rh,
1236 struct AuthorityChain *ac;
1238 struct GNUNET_CRYPTO_EcdsaPublicKey zone;
1240 nlen = strlen (cname);
1241 tld = GNS_get_tld (cname);
1242 if (0 == strcmp ("+", tld))
1244 /* CNAME resolution continues relative to current domain */
1245 if (0 == rh->name_resolution_pos)
1247 res = GNUNET_strndup (cname, nlen - 2);
1248 rh->name_resolution_pos = nlen - 2;
1252 GNUNET_asprintf (&res,
1254 (int) rh->name_resolution_pos,
1258 rh->name_resolution_pos = strlen (res);
1260 GNUNET_free (rh->name);
1262 ac = GNUNET_new (struct AuthorityChain);
1264 ac->gns_authority = GNUNET_YES;
1265 ac->authority_info.gns_authority =
1266 rh->ac_tail->authority_info.gns_authority;
1267 ac->label = resolver_lookup_get_next_label (rh);
1268 /* add AC to tail */
1269 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1272 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1276 if (GNUNET_OK == GNUNET_GNSRECORD_zkey_to_pkey (tld, &zone))
1278 /* CNAME resolution continues relative to current domain */
1279 if (0 == rh->name_resolution_pos)
1281 GNUNET_asprintf (&res,
1283 strlen (cname) - (strlen (tld) + 1),
1288 GNUNET_asprintf (&res,
1290 (int) rh->name_resolution_pos,
1292 (int) strlen (cname) - (strlen (tld) + 1),
1295 rh->name_resolution_pos = strlen (res);
1296 GNUNET_free (rh->name);
1298 ac = GNUNET_new (struct AuthorityChain);
1300 ac->gns_authority = GNUNET_YES;
1301 ac->authority_info.gns_authority = zone;
1302 ac->label = resolver_lookup_get_next_label (rh);
1303 /* add AC to tail */
1304 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1307 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1312 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1313 "Got CNAME `%s' from GNS for `%s'\n",
1316 if (NULL != rh->std_resolve)
1318 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1319 "Multiple CNAME results from GNS resolving `%s'! Not really allowed...\n",
1321 GNUNET_RESOLVER_request_cancel (rh->std_resolve);
1323 /* name is absolute, go to DNS */
1324 GNUNET_free (rh->name);
1325 rh->name = GNUNET_strdup (cname);
1326 rh->name_resolution_pos = strlen (rh->name);
1327 switch (rh->record_type)
1329 case GNUNET_DNSPARSER_TYPE_A:
1333 case GNUNET_DNSPARSER_TYPE_AAAA:
1341 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1342 "Doing standard DNS lookup for `%s'\n",
1344 rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name,
1353 * Process a records that were decrypted from a block.
1355 * @param cls closure with the 'struct GNS_ResolverHandle'
1356 * @param rd_count number of entries in @a rd array
1357 * @param rd array of records with data to store
1360 handle_gns_resolution_result (void *cls,
1361 unsigned int rd_count,
1362 const struct GNUNET_GNSRECORD_Data *rd);
1366 * Callback invoked from the VPN service once a redirection is
1367 * available. Provides the IP address that can now be used to
1368 * reach the requested destination. Replaces the "VPN" record
1369 * with the respective A/AAAA record and continues processing.
1371 * @param cls closure
1372 * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error;
1373 * will match 'result_af' from the request
1374 * @param address IP address (struct in_addr or struct in_addr6, depending on 'af')
1375 * that the VPN allocated for the redirection;
1376 * traffic to this IP will now be redirected to the
1377 * specified target peer; NULL on error
1380 vpn_allocation_cb (void *cls,
1382 const void *address)
1384 struct VpnContext *vpn_ctx = cls;
1385 struct GNS_ResolverHandle *rh = vpn_ctx->rh;
1386 struct GNUNET_GNSRECORD_Data rd[vpn_ctx->rd_count];
1389 vpn_ctx->vpn_request = NULL;
1391 GNUNET_assert (GNUNET_OK ==
1392 GNUNET_GNSRECORD_records_deserialize (
1393 (size_t) vpn_ctx->rd_data_size,
1397 for (i = 0; i < vpn_ctx->rd_count; i++)
1399 if (GNUNET_GNSRECORD_TYPE_VPN == rd[i].record_type)
1404 rd[i].record_type = GNUNET_DNSPARSER_TYPE_A;
1405 rd[i].data_size = sizeof(struct in_addr);
1406 rd[i].expiration_time = GNUNET_TIME_relative_to_absolute (
1407 VPN_TIMEOUT).abs_value_us;
1409 rd[i].data = address;
1413 rd[i].record_type = GNUNET_DNSPARSER_TYPE_AAAA;
1414 rd[i].expiration_time = GNUNET_TIME_relative_to_absolute (
1415 VPN_TIMEOUT).abs_value_us;
1417 rd[i].data = address;
1418 rd[i].data_size = sizeof(struct in6_addr);
1427 GNUNET_assert (i < vpn_ctx->rd_count);
1428 if (0 == vpn_ctx->rd_count)
1429 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1430 _ ("VPN returned empty result for `%s'\n"),
1432 handle_gns_resolution_result (rh,
1435 GNUNET_free (vpn_ctx->rd_data);
1436 GNUNET_free (vpn_ctx);
1441 * We have resolved one or more of the nameservers for a
1442 * GNS2DNS lookup. Once we have some of them, begin using
1443 * the DNSSTUB resolver.
1445 * @param ac context for GNS2DNS resolution
1448 continue_with_gns2dns (struct AuthorityChain *ac)
1450 struct GNS_ResolverHandle *rh = ac->rh;
1452 if ((NULL != ac->authority_info.dns_authority.gp_head) &&
1453 (GNUNET_NO == ac->authority_info.dns_authority.found))
1454 return; /* more pending and none found yet */
1455 if (GNUNET_NO == ac->authority_info.dns_authority.found)
1457 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1458 "Failed to resolve DNS server for `%s' in GNS2DNS resolution\n",
1459 ac->authority_info.dns_authority.name);
1460 fail_resolution (rh);
1463 if (GNUNET_NO != ac->authority_info.dns_authority.launched)
1464 return; /* already running, do not launch again! */
1466 ac->authority_info.dns_authority.launched = GNUNET_YES;
1467 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1468 "Will continue resolution using DNS to resolve `%s'\n",
1470 GNUNET_assert (NULL == rh->task_id);
1471 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1477 * We've resolved the IP address for the DNS resolver to use
1478 * after encountering a GNS2DNS record.
1480 * @param cls the `struct Gns2DnsPending` used for this request
1481 * @param rd_count number of records in @a rd
1482 * @param rd addresses for the DNS resolver (presumably)
1485 handle_gns2dns_result (void *cls,
1486 unsigned int rd_count,
1487 const struct GNUNET_GNSRECORD_Data *rd)
1489 struct Gns2DnsPending *gp = cls;
1490 struct AuthorityChain *ac = gp->ac;
1492 GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
1493 ac->authority_info.dns_authority.gp_tail,
1495 /* enable cleanup of 'rh' handle that automatically comes after we return,
1496 and which expects 'rh' to be in the #rlh_head DLL. */
1499 GNUNET_CONTAINER_DLL_insert (rlh_head,
1505 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1506 "Received %u results for IP address of DNS server for GNS2DNS transition\n",
1508 /* find suitable A/AAAA record */
1509 for (unsigned int j = 0; j < rd_count; j++)
1511 switch (rd[j].record_type)
1513 case GNUNET_DNSPARSER_TYPE_A:
1515 struct sockaddr_in v4;
1517 if (sizeof(struct in_addr) != rd[j].data_size)
1519 GNUNET_break_op (0);
1525 v4.sin_family = AF_INET;
1526 v4.sin_port = htons (53);
1527 #if HAVE_SOCKADDR_IN_SIN_LEN
1528 v4.sin_len = (u_char) sizeof(v4);
1530 GNUNET_memcpy (&v4.sin_addr,
1532 sizeof(struct in_addr));
1534 GNUNET_DNSSTUB_add_dns_sa (
1535 ac->authority_info.dns_authority.dns_handle,
1536 (const struct sockaddr *) &v4))
1537 ac->authority_info.dns_authority.found = GNUNET_YES;
1541 case GNUNET_DNSPARSER_TYPE_AAAA:
1543 struct sockaddr_in6 v6;
1545 if (sizeof(struct in6_addr) != rd[j].data_size)
1547 GNUNET_break_op (0);
1550 /* FIXME: might want to check if we support IPv6 here,
1551 and otherwise skip this one and hope we find another */
1555 v6.sin6_family = AF_INET6;
1556 v6.sin6_port = htons (53);
1557 #if HAVE_SOCKADDR_IN_SIN_LEN
1558 v6.sin6_len = (u_char) sizeof(v6);
1560 GNUNET_memcpy (&v6.sin6_addr,
1562 sizeof(struct in6_addr));
1564 GNUNET_DNSSTUB_add_dns_sa (
1565 ac->authority_info.dns_authority.dns_handle,
1566 (const struct sockaddr *) &v6))
1567 ac->authority_info.dns_authority.found = GNUNET_YES;
1575 continue_with_gns2dns (ac);
1580 * Function called by the resolver for each address obtained from DNS.
1582 * @param cls closure, a `struct Gns2DnsPending *`
1583 * @param addr one of the addresses of the host, NULL for the last address
1584 * @param addrlen length of @a addr
1587 handle_gns2dns_ip (void *cls,
1588 const struct sockaddr *addr,
1591 struct Gns2DnsPending *gp = cls;
1592 struct AuthorityChain *ac = gp->ac;
1593 struct sockaddr_storage ss;
1594 struct sockaddr_in *v4;
1595 struct sockaddr_in6 *v6;
1599 /* DNS resolution finished */
1600 if (0 == gp->num_results)
1601 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1602 "Failed to use DNS to resolve name of DNS resolver\n");
1603 GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
1604 ac->authority_info.dns_authority.gp_tail,
1607 continue_with_gns2dns (ac);
1613 switch (ss.ss_family)
1616 v4 = (struct sockaddr_in *) &ss;
1617 v4->sin_port = htons (53);
1622 v6 = (struct sockaddr_in6 *) &ss;
1623 v6->sin6_port = htons (53);
1628 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1629 "Unsupported AF %d\n",
1634 GNUNET_DNSSTUB_add_dns_sa (ac->authority_info.dns_authority.dns_handle,
1635 (struct sockaddr *) &ss))
1636 ac->authority_info.dns_authority.found = GNUNET_YES;
1641 * We found a CNAME record, perform recursive resolution on it.
1643 * @param rh resolution handle
1644 * @param rd record with CNAME to resolve recursively
1647 recursive_cname_resolution (struct GNS_ResolverHandle *rh,
1648 const struct GNUNET_GNSRECORD_Data *rd)
1654 cname = GNUNET_DNSPARSER_parse_name (rd->data,
1657 if ((NULL == cname) ||
1658 (off != rd->data_size))
1660 GNUNET_break_op (0); /* record not well-formed */
1661 GNUNET_free_non_null (cname);
1662 fail_resolution (rh);
1665 handle_gns_cname_result (rh,
1667 GNUNET_free (cname);
1672 * We found a PKEY record, perform recursive resolution on it.
1674 * @param rh resolution handle
1675 * @param rd record with PKEY to resolve recursively
1678 recursive_pkey_resolution (struct GNS_ResolverHandle *rh,
1679 const struct GNUNET_GNSRECORD_Data *rd)
1681 struct AuthorityChain *ac;
1683 /* delegation to another zone */
1684 if (sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey) !=
1687 GNUNET_break_op (0);
1688 fail_resolution (rh);
1691 /* expand authority chain */
1692 ac = GNUNET_new (struct AuthorityChain);
1694 ac->gns_authority = GNUNET_YES;
1695 GNUNET_memcpy (&ac->authority_info.gns_authority,
1697 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey));
1698 ac->label = resolver_lookup_get_next_label (rh);
1699 /* add AC to tail */
1700 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1704 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1710 * We found one or more GNS2DNS records, perform recursive resolution on it.
1711 * (to be precise, one or more records in @a rd is GNS2DNS, there may be others,
1712 * so this function still needs to check which ones are GNS2DNS).
1714 * @param rh resolution handle
1715 * @param rd_count length of the @a rd array
1716 * @param rd record with PKEY to resolve recursively
1717 * @return #GNUNET_OK if this worked, #GNUNET_SYSERR if no GNS2DNS records were in @a rd
1720 recursive_gns2dns_resolution (struct GNS_ResolverHandle *rh,
1721 unsigned int rd_count,
1722 const struct GNUNET_GNSRECORD_Data *rd)
1724 struct AuthorityChain *ac;
1729 /* expand authority chain */
1730 ac = GNUNET_new (struct AuthorityChain);
1732 ac->authority_info.dns_authority.dns_handle = GNUNET_DNSSTUB_start (4);
1734 for (unsigned int i = 0; i < rd_count; i++)
1739 struct Gns2DnsPending *gp;
1740 struct GNUNET_CRYPTO_EcdsaPublicKey zone;
1741 struct sockaddr_in v4;
1742 struct sockaddr_in6 v6;
1744 if (GNUNET_GNSRECORD_TYPE_GNS2DNS != rd[i].record_type)
1747 n = GNUNET_DNSPARSER_parse_name (rd[i].data,
1750 ip = GNUNET_strdup (&rd[i].data[off]);
1751 off += strlen (ip) + 1;
1755 (off != rd[i].data_size))
1757 GNUNET_break_op (0);
1758 GNUNET_free_non_null (n);
1759 GNUNET_free_non_null (ip);
1762 /* resolve 'ip' to determine the IP(s) of the DNS
1763 resolver to use for lookup of 'ns' */
1766 if (0 != strcasecmp (ns,
1769 /* NS values must all be the same for all GNS2DNS records,
1770 anything else leads to insanity */
1771 GNUNET_break_op (0);
1783 /* check if 'ip' is already an IPv4/IPv6 address */
1784 if ((1 == inet_pton (AF_INET,
1787 (1 == inet_pton (AF_INET6,
1791 GNUNET_break (GNUNET_OK ==
1792 GNUNET_DNSSTUB_add_dns_ip (
1793 ac->authority_info.dns_authority.dns_handle,
1795 ac->authority_info.dns_authority.found = GNUNET_YES;
1799 tld = GNS_get_tld (ip);
1800 if ((0 != strcmp (tld, "+")) &&
1801 (GNUNET_OK != GNUNET_GNSRECORD_zkey_to_pkey (tld, &zone)))
1803 /* 'ip' is a DNS name */
1804 gp = GNUNET_new (struct Gns2DnsPending);
1806 GNUNET_CONTAINER_DLL_insert (ac->authority_info.dns_authority.gp_head,
1807 ac->authority_info.dns_authority.gp_tail,
1809 gp->dns_rh = GNUNET_RESOLVER_ip_get (ip,
1811 GNUNET_TIME_UNIT_FOREVER_REL,
1817 /* 'ip' should be a GNS name */
1818 gp = GNUNET_new (struct Gns2DnsPending);
1820 GNUNET_CONTAINER_DLL_insert (ac->authority_info.dns_authority.gp_head,
1821 ac->authority_info.dns_authority.gp_tail,
1823 gp->rh = GNUNET_new (struct GNS_ResolverHandle);
1824 if (0 == strcmp (tld, "+"))
1826 ip = translate_dot_plus (rh,
1828 tld = GNS_get_tld (ip);
1830 GNUNET_GNSRECORD_zkey_to_pkey (tld,
1833 GNUNET_break_op (0);
1838 gp->rh->authority_zone = zone;
1839 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1840 "Resolving `%s' to determine IP address of DNS server for GNS2DNS transition for `%s'\n",
1844 gp->rh->name_resolution_pos = strlen (ip) - strlen (tld) - 1;
1845 gp->rh->proc = &handle_gns2dns_result;
1846 gp->rh->proc_cls = gp;
1847 gp->rh->record_type = GNUNET_GNSRECORD_TYPE_ANY;
1848 gp->rh->options = GNUNET_GNS_LO_DEFAULT;
1849 gp->rh->loop_limiter = rh->loop_limiter + 1;
1851 = GNUNET_SCHEDULER_add_now (&start_resolver_lookup,
1853 } /* end 'for all records' */
1857 /* not a single GNS2DNS record found */
1859 return GNUNET_SYSERR;
1861 GNUNET_assert (strlen (ns) <= GNUNET_DNSPARSER_MAX_NAME_LENGTH);
1862 strcpy (ac->authority_info.dns_authority.name,
1864 /* for DNS recursion, the label is the full DNS name,
1865 created from the remainder of the GNS name and the
1866 name in the NS record */
1867 GNUNET_asprintf (&ac->label,
1869 (int) rh->name_resolution_pos,
1871 (0 != rh->name_resolution_pos) ? "." : "",
1876 /* the GNS name is UTF-8 and may include multibyte chars.
1877 * We have to convert the combined name to a DNS-compatible IDNA.
1879 char *tmp = ac->label;
1881 if (IDNA_SUCCESS != idna_to_ascii_8z (tmp,
1883 IDNA_ALLOW_UNASSIGNED))
1885 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1886 _ ("Name `%s' cannot be converted to IDNA."),
1888 return GNUNET_SYSERR;
1893 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1896 if (strlen (ac->label) > GNUNET_DNSPARSER_MAX_NAME_LENGTH)
1898 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1899 _ ("GNS lookup resulted in DNS name that is too long (`%s')\n"),
1901 return GNUNET_SYSERR;
1903 continue_with_gns2dns (ac);
1909 * Process a records that were decrypted from a block.
1911 * @param cls closure with the `struct GNS_ResolverHandle`
1912 * @param rd_count number of entries in @a rd array
1913 * @param rd array of records with data to store
1916 handle_gns_resolution_result (void *cls,
1917 unsigned int rd_count,
1918 const struct GNUNET_GNSRECORD_Data *rd)
1920 struct GNS_ResolverHandle *rh = cls;
1922 struct VpnContext *vpn_ctx;
1923 const struct GNUNET_TUN_GnsVpnRecord *vpn;
1925 struct GNUNET_HashCode vhash;
1927 char scratch[UINT16_MAX];
1929 size_t scratch_start;
1931 struct GNUNET_GNSRECORD_Data rd_new[rd_count];
1932 unsigned int rd_off;
1934 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1935 "Resolution succeeded for `%s' in zone %s, got %u records\n",
1937 GNUNET_GNSRECORD_z2s (&rh->ac_tail->authority_info.gns_authority),
1941 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1942 _ ("GNS lookup failed (zero records found for `%s')\n"),
1944 fail_resolution (rh);
1948 if (0 == rh->name_resolution_pos)
1950 /* top-level match, are we done yet? */
1951 if ((rd_count > 0) &&
1952 (GNUNET_DNSPARSER_TYPE_CNAME == rd[0].record_type) &&
1953 (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type))
1956 cname = GNUNET_DNSPARSER_parse_name (rd[0].data,
1959 if ((NULL == cname) ||
1960 (off != rd[0].data_size))
1962 GNUNET_break_op (0);
1963 GNUNET_free_non_null (cname);
1964 fail_resolution (rh);
1967 handle_gns_cname_result (rh,
1969 GNUNET_free (cname);
1972 /* If A/AAAA was requested, but we got a VPN
1973 record, we convert it to A/AAAA using GNUnet VPN */
1974 if ((GNUNET_DNSPARSER_TYPE_A == rh->record_type) ||
1975 (GNUNET_DNSPARSER_TYPE_AAAA == rh->record_type))
1977 for (unsigned int i = 0; i < rd_count; i++)
1979 switch (rd[i].record_type)
1981 case GNUNET_GNSRECORD_TYPE_VPN:
1983 af = (GNUNET_DNSPARSER_TYPE_A == rh->record_type) ? AF_INET :
1985 if (sizeof(struct GNUNET_TUN_GnsVpnRecord) >
1988 GNUNET_break_op (0);
1989 fail_resolution (rh);
1992 vpn = (const struct GNUNET_TUN_GnsVpnRecord *) rd[i].data;
1993 vname = (const char *) &vpn[1];
1994 if ('\0' != vname[rd[i].data_size - 1 - sizeof(struct
1995 GNUNET_TUN_GnsVpnRecord)
1998 GNUNET_break_op (0);
1999 fail_resolution (rh);
2002 GNUNET_TUN_service_name_to_hash (vname,
2004 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2005 "Attempting VPN allocation for %s-%s (AF: %d, proto %d)\n",
2006 GNUNET_i2s (&vpn->peer),
2009 (int) ntohs (vpn->proto));
2010 vpn_ctx = GNUNET_new (struct VpnContext);
2011 rh->vpn_ctx = vpn_ctx;
2013 vpn_ctx->rd_data_size = GNUNET_GNSRECORD_records_get_size (rd_count,
2015 if (vpn_ctx->rd_data_size < 0)
2017 GNUNET_break_op (0);
2018 GNUNET_free (vpn_ctx);
2019 fail_resolution (rh);
2022 vpn_ctx->rd_data = GNUNET_malloc ((size_t) vpn_ctx->rd_data_size);
2023 vpn_ctx->rd_count = rd_count;
2024 GNUNET_assert (vpn_ctx->rd_data_size ==
2025 GNUNET_GNSRECORD_records_serialize (rd_count,
2030 vpn_ctx->vpn_request = GNUNET_VPN_redirect_to_peer (vpn_handle,
2036 GNUNET_TIME_relative_to_absolute (
2044 case GNUNET_GNSRECORD_TYPE_GNS2DNS:
2046 /* delegation to DNS */
2047 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2048 "Found GNS2DNS record, delegating to DNS!\n");
2050 recursive_gns2dns_resolution (rh,
2062 } /* end: name_resolution_pos */
2063 /* convert relative names in record values to absolute names,
2064 using 'scratch' array for memory allocations */
2067 for (unsigned int i = 0; i < rd_count; i++)
2069 GNUNET_assert (rd_off <= i);
2070 if ((0 != rh->protocol) &&
2071 (0 != rh->service) &&
2072 (GNUNET_GNSRECORD_TYPE_BOX != rd[i].record_type))
2073 continue; /* we _only_ care about boxed records */
2075 GNUNET_assert (rd_off < rd_count);
2076 rd_new[rd_off] = rd[i];
2077 /* Check if the embedded name(s) end in "+", and if so,
2078 replace the "+" with the zone at "ac_tail", changing the name
2079 to a ".ZONEKEY". The name is allocated on the 'scratch' array,
2080 so we can free it afterwards. */
2081 switch (rd[i].record_type)
2083 case GNUNET_DNSPARSER_TYPE_CNAME:
2088 cname = GNUNET_DNSPARSER_parse_name (rd[i].data,
2091 if ((NULL == cname) ||
2092 (off != rd[i].data_size))
2094 GNUNET_break_op (0); /* record not well-formed */
2098 cname = translate_dot_plus (rh, cname);
2099 GNUNET_break (NULL != cname);
2100 scratch_start = scratch_off;
2102 GNUNET_DNSPARSER_builder_add_name (scratch,
2111 GNUNET_assert (rd_off < rd_count);
2112 rd_new[rd_off].data = &scratch[scratch_start];
2113 rd_new[rd_off].data_size = scratch_off - scratch_start;
2117 GNUNET_free_non_null (cname);
2121 case GNUNET_DNSPARSER_TYPE_SOA:
2123 struct GNUNET_DNSPARSER_SoaRecord *soa;
2126 soa = GNUNET_DNSPARSER_parse_soa (rd[i].data,
2129 if ((NULL == soa) ||
2130 (off != rd[i].data_size))
2132 GNUNET_break_op (0); /* record not well-formed */
2136 soa->mname = translate_dot_plus (rh, soa->mname);
2137 soa->rname = translate_dot_plus (rh, soa->rname);
2138 scratch_start = scratch_off;
2140 GNUNET_DNSPARSER_builder_add_soa (scratch,
2149 GNUNET_assert (rd_off < rd_count);
2150 rd_new[rd_off].data = &scratch[scratch_start];
2151 rd_new[rd_off].data_size = scratch_off - scratch_start;
2156 GNUNET_DNSPARSER_free_soa (soa);
2160 case GNUNET_DNSPARSER_TYPE_MX:
2162 struct GNUNET_DNSPARSER_MxRecord *mx;
2165 mx = GNUNET_DNSPARSER_parse_mx (rd[i].data,
2169 (off != rd[i].data_size))
2171 GNUNET_break_op (0); /* record not well-formed */
2175 mx->mxhost = translate_dot_plus (rh, mx->mxhost);
2176 scratch_start = scratch_off;
2178 GNUNET_DNSPARSER_builder_add_mx (scratch,
2187 GNUNET_assert (rd_off < rd_count);
2188 rd_new[rd_off].data = &scratch[scratch_start];
2189 rd_new[rd_off].data_size = scratch_off - scratch_start;
2194 GNUNET_DNSPARSER_free_mx (mx);
2198 case GNUNET_DNSPARSER_TYPE_SRV:
2200 struct GNUNET_DNSPARSER_SrvRecord *srv;
2203 srv = GNUNET_DNSPARSER_parse_srv (rd[i].data,
2206 if ((NULL == srv) ||
2207 (off != rd[i].data_size))
2209 GNUNET_break_op (0); /* record not well-formed */
2213 srv->target = translate_dot_plus (rh, srv->target);
2214 scratch_start = scratch_off;
2216 GNUNET_DNSPARSER_builder_add_srv (scratch,
2225 GNUNET_assert (rd_off < rd_count);
2226 rd_new[rd_off].data = &scratch[scratch_start];
2227 rd_new[rd_off].data_size = scratch_off - scratch_start;
2232 GNUNET_DNSPARSER_free_srv (srv);
2236 case GNUNET_GNSRECORD_TYPE_NICK:
2240 case GNUNET_GNSRECORD_TYPE_PKEY:
2242 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
2244 if (rd[i].data_size != sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey))
2246 GNUNET_break_op (0);
2249 GNUNET_memcpy (&pub,
2253 if (GNUNET_GNSRECORD_TYPE_PKEY != rh->record_type)
2255 /* try to resolve "@" */
2256 struct AuthorityChain *ac;
2258 ac = GNUNET_new (struct AuthorityChain);
2260 ac->gns_authority = GNUNET_YES;
2261 ac->authority_info.gns_authority = pub;
2262 ac->label = GNUNET_strdup (GNUNET_GNS_EMPTY_LABEL_AT);
2263 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
2266 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
2273 case GNUNET_GNSRECORD_TYPE_GNS2DNS:
2275 /* delegation to DNS */
2276 if (GNUNET_GNSRECORD_TYPE_GNS2DNS == rh->record_type)
2279 break; /* do not follow to DNS, we wanted the GNS2DNS record! */
2281 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2282 "Found GNS2DNS record, delegating to DNS!\n");
2284 recursive_gns2dns_resolution (rh,
2292 case GNUNET_GNSRECORD_TYPE_BOX:
2294 /* unbox SRV/TLSA records if a specific one was requested */
2295 if ((0 != rh->protocol) &&
2296 (0 != rh->service) &&
2297 (rd[i].data_size >= sizeof(struct GNUNET_GNSRECORD_BoxRecord)))
2299 const struct GNUNET_GNSRECORD_BoxRecord *box;
2302 if ((ntohs (box->protocol) == rh->protocol) &&
2303 (ntohs (box->service) == rh->service))
2305 /* Box matches, unbox! */
2306 GNUNET_assert (rd_off < rd_count);
2307 rd_new[rd_off].record_type = ntohl (box->record_type);
2308 rd_new[rd_off].data_size -= sizeof(struct
2309 GNUNET_GNSRECORD_BoxRecord);
2310 rd_new[rd_off].data = &box[1];
2316 /* no specific protocol/service specified, preserve all BOX
2317 records (for modern, GNS-enabled applications) */
2327 } /* end: for rd_count */
2329 /* yes, we are done, return result */
2330 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2331 "Returning GNS response for `%s' with %u answers\n",
2334 rh->proc (rh->proc_cls,
2337 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2342 switch (rd[0].record_type)
2344 case GNUNET_DNSPARSER_TYPE_CNAME:
2345 GNUNET_break_op (1 == rd_count); /* CNAME should be unique */
2346 recursive_cname_resolution (rh,
2350 case GNUNET_GNSRECORD_TYPE_PKEY:
2351 GNUNET_break_op (1 == rd_count); /* PKEY should be unique */
2352 recursive_pkey_resolution (rh,
2358 recursive_gns2dns_resolution (rh,
2365 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2366 _ ("GNS lookup recursion failed (no delegation record found)\n"));
2367 fail_resolution (rh);
2372 * Function called once the namestore has completed the request for
2375 * @param cls closure with the `struct CacheOps`
2376 * @param success #GNUNET_OK on success
2377 * @param emsg error message
2380 namecache_cache_continuation (void *cls,
2384 struct CacheOps *co = cls;
2386 co->namecache_qe_cache = NULL;
2387 if (GNUNET_OK != success)
2388 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2389 _ ("Failed to cache GNS resolution: %s\n"),
2391 GNUNET_CONTAINER_DLL_remove (co_head,
2399 * Iterator called on each result obtained for a DHT
2400 * operation that expects a reply
2402 * @param cls closure with the `struct GNS_ResolverHandle`
2403 * @param exp when will this value expire
2404 * @param key key of the result
2405 * @param get_path peers on reply path (or NULL if not recorded)
2406 * [0] = datastore's first neighbor, [length - 1] = local peer
2407 * @param get_path_length number of entries in @a get_path
2408 * @param put_path peers on the PUT path (or NULL if not recorded)
2409 * [0] = origin, [length - 1] = datastore
2410 * @param put_path_length number of entries in @a put_path
2411 * @param type type of the result
2412 * @param size number of bytes in data
2413 * @param data pointer to the result data
2416 handle_dht_response (void *cls,
2417 struct GNUNET_TIME_Absolute exp,
2418 const struct GNUNET_HashCode *key,
2419 const struct GNUNET_PeerIdentity *get_path,
2420 unsigned int get_path_length,
2421 const struct GNUNET_PeerIdentity *put_path,
2422 unsigned int put_path_length,
2423 enum GNUNET_BLOCK_Type type,
2427 struct GNS_ResolverHandle *rh = cls;
2428 struct AuthorityChain *ac = rh->ac_tail;
2429 const struct GNUNET_GNSRECORD_Block *block;
2430 struct CacheOps *co;
2435 (void) get_path_length;
2437 (void) put_path_length;
2439 GNUNET_DHT_get_stop (rh->get_handle);
2440 rh->get_handle = NULL;
2441 GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
2442 rh->dht_heap_node = NULL;
2443 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2444 "Handling response from the DHT\n");
2445 if (size < sizeof(struct GNUNET_GNSRECORD_Block))
2447 /* how did this pass DHT block validation!? */
2449 fail_resolution (rh);
2454 ntohl (block->purpose.size)
2455 + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)
2456 + sizeof(struct GNUNET_CRYPTO_EcdsaSignature))
2458 /* how did this pass DHT block validation!? */
2460 fail_resolution (rh);
2463 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2464 "Decrypting DHT block of size %u for `%s', expires %s\n",
2465 ntohl (block->purpose.size),
2467 GNUNET_STRINGS_absolute_time_to_string (exp));
2469 GNUNET_GNSRECORD_block_decrypt (block,
2470 &ac->authority_info.gns_authority,
2472 &handle_gns_resolution_result,
2475 GNUNET_break_op (0); /* block was ill-formed */
2476 fail_resolution (rh);
2479 if (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (
2480 block->expiration_time)).
2483 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2484 "Received expired block from the DHT, will not cache it.\n");
2487 if (GNUNET_YES == disable_cache)
2489 /* Cache well-formed blocks */
2490 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2491 "Caching response from the DHT in namecache\n");
2492 co = GNUNET_new (struct CacheOps);
2493 co->namecache_qe_cache = GNUNET_NAMECACHE_block_cache (namecache_handle,
2496 namecache_cache_continuation,
2498 GNUNET_CONTAINER_DLL_insert (co_head,
2505 * Initiate a DHT query for a set of GNS records.
2507 * @param rh resolution handle
2508 * @param query key to use in the DHT lookup
2511 start_dht_request (struct GNS_ResolverHandle *rh,
2512 const struct GNUNET_HashCode *query)
2514 struct GNS_ResolverHandle *rx;
2516 GNUNET_assert (NULL == rh->get_handle);
2517 rh->get_handle = GNUNET_DHT_get_start (dht_handle,
2518 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
2520 DHT_GNS_REPLICATION_LEVEL,
2521 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
2523 &handle_dht_response, rh);
2524 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
2526 GNUNET_TIME_absolute_get ().
2528 if (GNUNET_CONTAINER_heap_get_size (dht_lookup_heap) >
2529 max_allowed_background_queries)
2531 /* fail longest-standing DHT request */
2532 rx = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
2533 rx->dht_heap_node = NULL;
2534 GNUNET_assert (NULL != rx);
2535 fail_resolution (rx);
2541 * Process a records that were decrypted from a block that we got from
2542 * the namecache. Simply calls #handle_gns_resolution_result().
2544 * @param cls closure with the `struct GNS_ResolverHandle`
2545 * @param rd_count number of entries in @a rd array
2546 * @param rd array of records with data to store
2549 handle_gns_namecache_resolution_result (void *cls,
2550 unsigned int rd_count,
2551 const struct GNUNET_GNSRECORD_Data *rd)
2553 struct GNS_ResolverHandle *rh = cls;
2556 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2557 _ ("GNS namecache returned empty result for `%s'\n"),
2559 handle_gns_resolution_result (rh,
2566 * Process a record that was stored in the namecache.
2568 * @param cls closure with the `struct GNS_ResolverHandle`
2569 * @param block block that was stored in the namecache
2572 handle_namecache_block_response (void *cls,
2573 const struct GNUNET_GNSRECORD_Block *block)
2575 struct GNS_ResolverHandle *rh = cls;
2576 struct AuthorityChain *ac = rh->ac_tail;
2577 const char *label = ac->label;
2578 const struct GNUNET_CRYPTO_EcdsaPublicKey *auth =
2579 &ac->authority_info.gns_authority;
2580 struct GNUNET_HashCode query;
2582 GNUNET_assert (NULL != rh->namecache_qe);
2583 rh->namecache_qe = NULL;
2584 if (((GNUNET_GNS_LO_DEFAULT == rh->options) ||
2585 ((GNUNET_GNS_LO_LOCAL_MASTER == rh->options) &&
2586 (ac != rh->ac_head))) &&
2588 (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (
2589 block->expiration_time)).
2592 /* namecache knows nothing; try DHT lookup */
2593 GNUNET_GNSRECORD_query_from_public_key (auth,
2596 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2597 "Starting DHT lookup for `%s' in zone `%s' under key `%s'\n",
2599 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority),
2600 GNUNET_h2s (&query));
2601 start_dht_request (rh, &query);
2605 if ((NULL == block) ||
2606 (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (
2607 block->expiration_time)).
2610 /* DHT not permitted and no local result, fail */
2611 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2612 "Resolution failed for `%s' in zone %s (DHT lookup not permitted by configuration)\n",
2614 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2615 fail_resolution (rh);
2618 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2619 "Received result from namecache for label `%s'\n",
2623 GNUNET_GNSRECORD_block_decrypt (block,
2626 &handle_gns_namecache_resolution_result,
2629 GNUNET_break_op (0); /* block was ill-formed */
2630 /* try DHT instead */
2631 GNUNET_GNSRECORD_query_from_public_key (auth,
2634 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2635 "Starting DHT lookup for `%s' in zone `%s' under key `%s'\n",
2637 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority),
2638 GNUNET_h2s (&query));
2639 start_dht_request (rh, &query);
2646 * Lookup tail of our authority chain in the namecache.
2648 * @param rh query we are processing
2651 recursive_gns_resolution_namecache (struct GNS_ResolverHandle *rh)
2653 struct AuthorityChain *ac = rh->ac_tail;
2654 struct GNUNET_HashCode query;
2656 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2657 "Starting GNS resolution for `%s' in zone %s\n",
2659 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2660 GNUNET_GNSRECORD_query_from_public_key (&ac->authority_info.gns_authority,
2663 if (GNUNET_YES != disable_cache)
2666 = GNUNET_NAMECACHE_lookup_block (namecache_handle,
2668 &handle_namecache_block_response,
2670 GNUNET_assert (NULL != rh->namecache_qe);
2674 start_dht_request (rh,
2681 * Function called with the result from a revocation check.
2683 * @param cls the `struct GNS_ResovlerHandle`
2684 * @param is_valid #GNUNET_YES if the zone was not yet revoked
2687 handle_revocation_result (void *cls,
2690 struct GNS_ResolverHandle *rh = cls;
2691 struct AuthorityChain *ac = rh->ac_tail;
2693 rh->rev_check = NULL;
2694 if (GNUNET_YES != is_valid)
2696 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2697 _ ("Zone %s was revoked, resolution fails\n"),
2698 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2699 fail_resolution (rh);
2702 recursive_gns_resolution_namecache (rh);
2707 * Perform revocation check on tail of our authority chain.
2709 * @param rh query we are processing
2712 recursive_gns_resolution_revocation (struct GNS_ResolverHandle *rh)
2714 struct AuthorityChain *ac = rh->ac_tail;
2716 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2717 "Starting revocation check for zone %s\n",
2718 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2719 rh->rev_check = GNUNET_REVOCATION_query (cfg,
2720 &ac->authority_info.gns_authority,
2721 &handle_revocation_result,
2723 GNUNET_assert (NULL != rh->rev_check);
2728 * Task scheduled to continue with the resolution process.
2730 * @param cls the `struct GNS_ResolverHandle` of the resolution
2733 recursive_resolution (void *cls)
2735 struct GNS_ResolverHandle *rh = cls;
2738 if (MAX_RECURSION < rh->loop_limiter++)
2740 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2741 "Encountered unbounded recursion resolving `%s'\n",
2743 fail_resolution (rh);
2746 if (GNUNET_YES == rh->ac_tail->gns_authority)
2747 recursive_gns_resolution_revocation (rh);
2749 recursive_dns_resolution (rh);
2754 * Begin the resolution process from 'name', starting with
2755 * the identification of the zone specified by 'name'.
2757 * @param cls the `struct GNS_ResolverHandle`
2760 start_resolver_lookup (void *cls)
2762 struct GNS_ResolverHandle *rh = cls;
2763 struct AuthorityChain *ac;
2768 if (1 == inet_pton (AF_INET,
2772 /* name is IPv4 address, pretend it's an A record */
2773 struct GNUNET_GNSRECORD_Data rd;
2776 rd.data_size = sizeof(v4);
2777 rd.expiration_time = UINT64_MAX;
2778 rd.record_type = GNUNET_DNSPARSER_TYPE_A;
2780 rh->proc (rh->proc_cls,
2783 GNUNET_assert (NULL == rh->task_id);
2784 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2788 if (1 == inet_pton (AF_INET6,
2792 /* name is IPv6 address, pretend it's an AAAA record */
2793 struct GNUNET_GNSRECORD_Data rd;
2796 rd.data_size = sizeof(v6);
2797 rd.expiration_time = UINT64_MAX;
2798 rd.record_type = GNUNET_DNSPARSER_TYPE_AAAA;
2800 rh->proc (rh->proc_cls,
2803 GNUNET_assert (NULL == rh->task_id);
2804 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2809 ac = GNUNET_new (struct AuthorityChain);
2811 ac->label = resolver_lookup_get_next_label (rh);
2812 if (NULL == ac->label)
2813 /* name was just the "TLD", so we default to label
2814 #GNUNET_GNS_EMPTY_LABEL_AT */
2815 ac->label = GNUNET_strdup (GNUNET_GNS_EMPTY_LABEL_AT);
2816 ac->gns_authority = GNUNET_YES;
2817 ac->authority_info.gns_authority = rh->authority_zone;
2818 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
2821 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
2827 * Lookup of a record in a specific zone calls lookup result processor
2830 * @param zone the zone to perform the lookup in
2831 * @param record_type the record type to look up
2832 * @param name the name to look up
2833 * @param options local options to control local lookup
2834 * @param proc the processor to call on result
2835 * @param proc_cls the closure to pass to @a proc
2836 * @return handle to cancel operation
2838 struct GNS_ResolverHandle *
2839 GNS_resolver_lookup (const struct GNUNET_CRYPTO_EcdsaPublicKey *zone,
2840 uint32_t record_type,
2842 enum GNUNET_GNS_LocalOptions options,
2843 GNS_ResultProcessor proc,
2846 struct GNS_ResolverHandle *rh;
2848 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2849 "Starting lookup for `%s'\n",
2851 rh = GNUNET_new (struct GNS_ResolverHandle);
2852 GNUNET_CONTAINER_DLL_insert (rlh_head,
2855 rh->authority_zone = *zone;
2857 rh->proc_cls = proc_cls;
2858 rh->options = options;
2859 rh->record_type = record_type;
2860 rh->name = GNUNET_strdup (name);
2861 rh->name_resolution_pos = strlen (name);
2862 rh->task_id = GNUNET_SCHEDULER_add_now (&start_resolver_lookup,
2869 * Cancel active resolution (i.e. client disconnected).
2871 * @param rh resolution to abort
2874 GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
2876 struct DnsResult *dr;
2877 struct AuthorityChain *ac;
2878 struct VpnContext *vpn_ctx;
2880 GNUNET_CONTAINER_DLL_remove (rlh_head,
2883 if (NULL != rh->dns_request)
2885 GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
2886 rh->dns_request = NULL;
2888 while (NULL != (ac = rh->ac_head))
2890 GNUNET_CONTAINER_DLL_remove (rh->ac_head,
2893 if (GNUNET_NO == ac->gns_authority)
2895 struct Gns2DnsPending *gp;
2897 while (NULL != (gp = ac->authority_info.dns_authority.gp_head))
2899 GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
2900 ac->authority_info.dns_authority.gp_tail,
2904 /* rh->g2dc->rh is NOT in the DLL yet, so to enable us
2905 using GNS_resolver_lookup_cancel here, we need to
2907 GNUNET_CONTAINER_DLL_insert (rlh_head,
2910 GNUNET_assert (NULL == gp->rh->task_id);
2911 gp->rh->task_id = GNUNET_SCHEDULER_add_now (
2912 &GNS_resolver_lookup_cancel_,
2916 if (NULL != gp->dns_rh)
2918 GNUNET_RESOLVER_request_cancel (gp->dns_rh);
2923 GNUNET_DNSSTUB_stop (ac->authority_info.dns_authority.dns_handle);
2925 GNUNET_free (ac->label);
2928 if (NULL != rh->task_id)
2930 GNUNET_SCHEDULER_cancel (rh->task_id);
2933 if (NULL != rh->get_handle)
2935 GNUNET_DHT_get_stop (rh->get_handle);
2936 rh->get_handle = NULL;
2938 if (NULL != rh->dht_heap_node)
2940 GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
2941 rh->dht_heap_node = NULL;
2943 if (NULL != (vpn_ctx = rh->vpn_ctx))
2945 GNUNET_VPN_cancel_request (vpn_ctx->vpn_request);
2946 GNUNET_free (vpn_ctx->rd_data);
2947 GNUNET_free (vpn_ctx);
2949 if (NULL != rh->namecache_qe)
2951 GNUNET_NAMECACHE_cancel (rh->namecache_qe);
2952 rh->namecache_qe = NULL;
2954 if (NULL != rh->rev_check)
2956 GNUNET_REVOCATION_query_cancel (rh->rev_check);
2957 rh->rev_check = NULL;
2959 if (NULL != rh->std_resolve)
2961 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2962 "Canceling standard DNS resolution\n");
2963 GNUNET_RESOLVER_request_cancel (rh->std_resolve);
2964 rh->std_resolve = NULL;
2966 while (NULL != (dr = rh->dns_result_head))
2968 GNUNET_CONTAINER_DLL_remove (rh->dns_result_head,
2969 rh->dns_result_tail,
2973 GNUNET_free_non_null (rh->leho);
2974 GNUNET_free (rh->name);
2979 /* ***************** Resolver initialization ********************* */
2983 * Initialize the resolver
2985 * @param nc the namecache handle
2986 * @param dht the dht handle
2987 * @param c configuration handle
2988 * @param max_bg_queries maximum number of parallel background queries in dht
2991 GNS_resolver_init (struct GNUNET_NAMECACHE_Handle *nc,
2992 struct GNUNET_DHT_Handle *dht,
2993 const struct GNUNET_CONFIGURATION_Handle *c,
2994 unsigned long long max_bg_queries)
2997 namecache_handle = nc;
3000 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3001 max_allowed_background_queries = max_bg_queries;
3002 disable_cache = GNUNET_CONFIGURATION_get_value_yesno (cfg,
3005 if (GNUNET_YES == disable_cache)
3006 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3007 "Namecache disabled\n");
3008 vpn_handle = GNUNET_VPN_connect (cfg);
3016 GNS_resolver_done ()
3018 struct GNS_ResolverHandle *rh;
3019 struct CacheOps *co;
3021 /* abort active resolutions */
3022 while (NULL != (rh = rlh_head))
3024 rh->proc (rh->proc_cls,
3027 GNS_resolver_lookup_cancel (rh);
3029 while (NULL != (co = co_head))
3031 GNUNET_CONTAINER_DLL_remove (co_head,
3034 GNUNET_NAMECACHE_cancel (co->namecache_qe_cache);
3037 GNUNET_CONTAINER_heap_destroy (dht_lookup_heap);
3038 dht_lookup_heap = NULL;
3039 GNUNET_VPN_disconnect (vpn_handle);
3042 namecache_handle = NULL;
3046 /* end of gnunet-service-gns_resolver.c */