2 This file is part of GNUnet.
3 (C) 2011-2013 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file gns/gnunet-service-gns_resolver.c
23 * @brief GNU Name System resolver logic
24 * @author Martin Schanzenbach
25 * @author Christian Grothoff
28 * - GNS: handle special SRV names --- no delegation, direct lookup;
29 * can likely be done in 'resolver_lookup_get_next_label'. (#3003)
30 * - revocation checks (use REVOCATION service!), (#3004)
31 * - DNAME support (#3005)
34 #include "gnunet_util_lib.h"
35 #include "gnunet_dnsstub_lib.h"
36 #include "gnunet_dht_service.h"
37 #include "gnunet_gnsrecord_lib.h"
38 #include "gnunet_namecache_service.h"
39 #include "gnunet_namestore_service.h"
40 #include "gnunet_dns_service.h"
41 #include "gnunet_resolver_service.h"
42 #include "gnunet_revocation_service.h"
43 #include "gnunet_dnsparser_lib.h"
44 #include "gnunet_tun_lib.h"
45 #include "gnunet_gns_service.h"
47 #include "gnunet-service-gns_resolver.h"
48 #include "gnunet-service-gns_shorten.h"
49 #include "gnunet_vpn_service.h"
53 * Default DHT timeout for lookups.
55 #define DHT_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
58 * Default timeout for DNS lookups.
60 #define DNS_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
63 * Default timeout for VPN redirections.
65 #define VPN_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
68 * DHT replication level
70 #define DHT_GNS_REPLICATION_LEVEL 5
73 * How deep do we allow recursions to go before we abort?
75 #define MAX_RECURSION 256
79 * DLL to hold the authority chain we had to pass in the resolution
87 struct AuthorityChain *prev;
92 struct AuthorityChain *next;
95 * Resolver handle this entry in the chain belongs to.
97 struct GNS_ResolverHandle *rh;
100 * label/name corresponding to the authority
105 * label/name suggested for shortening to the authority
107 char *suggested_shortening_label;
110 * Do we already try to shorten this authority?
112 int shortening_started;
115 * #GNUNET_YES if the authority was a GNS authority,
116 * #GNUNET_NO if the authority was a DNS authority.
121 * Information about the resolver authority for this label.
127 * The zone of the GNS authority
129 struct GNUNET_CRYPTO_EcdsaPublicKey gns_authority;
134 * Domain of the DNS resolver that is the authority.
135 * (appended to construct the DNS name to resolve;
136 * this is NOT the DNS name of the DNS server!).
138 char name[GNUNET_DNSPARSER_MAX_NAME_LENGTH + 1];
141 * IP address of the DNS resolver that is authoritative.
142 * (this implementation currently only supports one
145 struct sockaddr_storage dns_ip;
155 * A result we got from DNS.
163 struct DnsResult *next;
168 struct DnsResult *prev;
171 * Binary value stored in the DNS record (appended to this struct)
176 * Expiration time for the DNS record, 0 if we didn't
177 * get anything useful (i.e. 'gethostbyname' was used).
179 uint64_t expiration_time;
182 * Number of bytes in @e data.
187 * Type of the GNS/DNS record.
189 uint32_t record_type;
195 * Closure for #vpn_allocation_cb.
201 * Which resolution process are we processing.
203 struct GNS_ResolverHandle *rh;
206 * Handle to the VPN request that we were performing.
208 struct GNUNET_VPN_RedirectionRequest *vpn_request;
211 * Number of records serialized in @e rd_data.
213 unsigned int rd_count;
216 * Serialized records.
221 * Number of bytes in @e rd_data.
228 * Information we keep during the resolution of an
229 * IP address for a DNS server while handling a
232 struct Gns2DnsContext
236 * DNS domain in which the resolution will continue
237 * (first part of the GNS2DNS record).
242 * Handle for the resolution of the IP part of the
243 * GNS2DNS record. Will return to us the addresses
244 * of the DNS resolver to use.
246 struct GNS_ResolverHandle *rh;
252 * Handle to a currenty pending resolution. On result (positive or
253 * negative) the #GNS_ResultProcessor is called.
255 struct GNS_ResolverHandle
261 struct GNS_ResolverHandle *next;
266 struct GNS_ResolverHandle *prev;
269 * The top-level GNS authoritative zone to query
271 struct GNUNET_CRYPTO_EcdsaPublicKey authority_zone;
274 * called when resolution phase finishes
276 GNS_ResultProcessor proc;
279 * closure passed to @e proc
284 * Handle used during GNS2DNS resolution for looking up the
285 * IP address of the DNS server.
287 struct Gns2DnsContext *g2dc;
290 * Handle for DHT lookups. should be NULL if no lookups are in progress
292 struct GNUNET_DHT_GetHandle *get_handle;
295 * Handle to a VPN request, NULL if none is active.
297 struct VpnContext *vpn_ctx;
300 * Socket for a DNS request, NULL if none is active.
302 struct GNUNET_DNSSTUB_RequestSocket *dns_request;
305 * Handle for standard DNS resolution, NULL if none is active.
307 struct GNUNET_RESOLVER_RequestHandle *std_resolve;
310 * Pending Namecache lookup task
312 struct GNUNET_NAMECACHE_QueueEntry *namecache_qe;
315 * Pending revocation check.
317 struct GNUNET_REVOCATION_Query *rev_check;
320 * Heap node associated with this lookup. Used to limit number of
321 * concurrent requests.
323 struct GNUNET_CONTAINER_HeapNode *dht_heap_node;
326 * DLL to store the authority chain
328 struct AuthorityChain *ac_head;
331 * DLL to store the authority chain
333 struct AuthorityChain *ac_tail;
336 * Private key of the shorten zone, NULL to not shorten.
338 struct GNUNET_CRYPTO_EcdsaPrivateKey *shorten_key;
341 * ID of a task associated with the resolution process.
343 GNUNET_SCHEDULER_TaskIdentifier task_id;
346 * The name to resolve
351 * DLL of results we got from DNS.
353 struct DnsResult *dns_result_head;
356 * DLL of results we got from DNS.
358 struct DnsResult *dns_result_tail;
361 * Current offset in 'name' where we are resolving.
363 size_t name_resolution_pos;
371 * Desired type for the resolution.
376 * We increment the loop limiter for each step in a recursive
377 * resolution. If it passes our threshold (i.e. due to
378 * self-recursion in the resolution, i.e CNAME fun), we stop.
380 unsigned int loop_limiter;
386 * Active namestore caching operations.
392 * Organized in a DLL.
394 struct CacheOps *next;
397 * Organized in a DLL.
399 struct CacheOps *prev;
402 * Pending Namestore caching task.
404 struct GNUNET_NAMECACHE_QueueEntry *namecache_qe_cache;
410 * Our handle to the namecache service
412 static struct GNUNET_NAMECACHE_Handle *namecache_handle;
415 * Our handle to the vpn service
417 static struct GNUNET_VPN_Handle *vpn_handle;
420 * Resolver handle to the dht
422 static struct GNUNET_DHT_Handle *dht_handle;
425 * Handle to perform DNS lookups.
427 static struct GNUNET_DNSSTUB_Context *dns_handle;
430 * Heap for limiting parallel DHT lookups
432 static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
435 * Maximum amount of parallel queries to the DHT
437 static unsigned long long max_allowed_background_queries;
440 * Head of resolver lookup list
442 static struct GNS_ResolverHandle *rlh_head;
445 * Tail of resolver lookup list
447 static struct GNS_ResolverHandle *rlh_tail;
450 * Organized in a DLL.
452 static struct CacheOps *co_head;
455 * Organized in a DLL.
457 static struct CacheOps *co_tail;
462 static int use_cache;
465 * Global configuration.
467 static const struct GNUNET_CONFIGURATION_Handle *cfg;
471 * Check if name is in srv format (_x._y.xxx)
474 * @return #GNUNET_YES if true
477 is_srv (const char *name)
484 if (NULL == strstr (name, "._"))
487 ndup = GNUNET_strdup (name);
489 if (NULL == strtok (NULL, "."))
491 if (NULL == strtok (NULL, "."))
493 if (NULL != strtok (NULL, "."))
502 * Determine if this name is canonical (is a legal name in a zone, without delegation);
503 * note that we do not test that the name does not contain illegal characters, we only
504 * test for delegation. Note that service records (i.e. _foo._srv) are canonical names
505 * even though they consist of multiple labels.
508 * a.b.gnu = not canonical
510 * _foo._srv = canonical
511 * _f.bar = not canonical
513 * @param name the name to test
514 * @return #GNUNET_YES if canonical
517 is_canonical (const char *name)
522 if (NULL == strchr (name, '.'))
527 while (NULL != (dot = strchr (pos, '.')))
535 /* ************************** Resolution **************************** */
538 * Expands a name ending in .+ with the zone of origin.
540 * @param rh resolution context
541 * @param name name to modify (to be free'd or returned)
542 * @return updated name
545 translate_dot_plus (struct GNS_ResolverHandle *rh,
549 size_t s_len = strlen (name);
551 if (0 != strcmp (&name[s_len - 2],
553 return name; /* did not end in ".+" */
554 GNUNET_assert (GNUNET_YES == rh->ac_tail->gns_authority);
555 GNUNET_asprintf (&ret,
559 GNUNET_GNSRECORD_pkey_to_zkey (&rh->ac_tail->authority_info.gns_authority));
566 * Task scheduled to asynchronously fail a resolution.
568 * @param cls the 'struct GNS_ResolverHandle' of the resolution to fail
569 * @param tc task context
572 fail_resolution (void *cls,
573 const struct GNUNET_SCHEDULER_TaskContext *tc)
575 struct GNS_ResolverHandle *rh = cls;
577 rh->task_id = GNUNET_SCHEDULER_NO_TASK;
578 rh->proc (rh->proc_cls, 0, NULL);
579 GNS_resolver_lookup_cancel (rh);
583 #if (defined WINDOWS) || (defined DARWIN)
584 /* Don't have this on W32, here's a naive implementation
585 * Was somehow removed on OS X ... */
587 memrchr (const void *s,
591 const unsigned char *ucs = s;
594 for (i = n - 1; i >= 0; i--)
595 if (c == (int) ucs[i])
596 return (void *) &ucs[i];
603 * Get the next, rightmost label from the name that we are trying to resolve,
604 * and update the resolution position accordingly.
606 * @param rh handle to the resolution operation to get the next label from
607 * @return NULL if there are no more labels
610 resolver_lookup_get_next_label (struct GNS_ResolverHandle *rh)
616 if (0 == rh->name_resolution_pos)
618 dot = memrchr (rh->name, (int) '.', rh->name_resolution_pos);
621 /* done, this was the last one */
622 len = rh->name_resolution_pos;
624 rh->name_resolution_pos = 0;
628 /* advance by one label */
629 len = rh->name_resolution_pos - (dot - rh->name) - 1;
631 rh->name_resolution_pos = dot - rh->name;
633 return GNUNET_strndup (rp, len);
638 * Gives the cummulative result obtained to the callback and clean up the request.
640 * @param rh resolution process that has culminated in a result
643 transmit_lookup_dns_result (struct GNS_ResolverHandle *rh)
645 struct DnsResult *pos;
650 for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
653 struct GNUNET_GNSRECORD_Data rd[n];
656 for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
658 rd[i].data = pos->data;
659 rd[i].data_size = pos->data_size;
660 rd[i].record_type = pos->record_type;
661 if (0 == pos->expiration_time)
663 rd[i].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
664 rd[i].expiration_time = 0;
668 rd[i].flags = GNUNET_GNSRECORD_RF_NONE;
669 rd[i].expiration_time = pos->expiration_time;
673 GNUNET_assert (i == n);
674 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
675 "Transmitting standard DNS result with %u records\n",
677 rh->proc (rh->proc_cls,
681 GNS_resolver_lookup_cancel (rh);
686 * Add a result from DNS to the records to be returned to the application.
688 * @param rh resolution request to extend with a result
689 * @param expiration_time expiration time for the answer
690 * @param record_type DNS record type of the answer
691 * @param data_size number of bytes in @a data
692 * @param data binary data to return in DNS record
695 add_dns_result (struct GNS_ResolverHandle *rh,
696 uint64_t expiration_time,
697 uint32_t record_type,
701 struct DnsResult *res;
703 res = GNUNET_malloc (sizeof (struct DnsResult) + data_size);
704 res->expiration_time = expiration_time;
705 res->data_size = data_size;
706 res->record_type = record_type;
708 memcpy (&res[1], data, data_size);
709 GNUNET_CONTAINER_DLL_insert (rh->dns_result_head,
716 * We had to do a DNS lookup. Convert the result (if any) and return
719 * @param cls closure with the `struct GNS_ResolverHandle`
720 * @param addr one of the addresses of the host, NULL for the last address
721 * @param addrlen length of the address
724 handle_dns_result (void *cls,
725 const struct sockaddr *addr,
728 struct GNS_ResolverHandle *rh = cls;
729 const struct sockaddr_in *sa4;
730 const struct sockaddr_in6 *sa6;
732 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
733 "Received %u bytes of DNS IP data\n",
737 rh->std_resolve = NULL;
738 transmit_lookup_dns_result (rh);
741 switch (addr->sa_family)
744 sa4 = (const struct sockaddr_in *) addr;
746 0 /* expiration time is unknown */,
747 GNUNET_DNSPARSER_TYPE_A,
748 sizeof (struct in_addr),
752 sa6 = (const struct sockaddr_in6 *) addr;
754 0 /* expiration time is unknown */,
755 GNUNET_DNSPARSER_TYPE_AAAA,
756 sizeof (struct in6_addr),
767 * Task scheduled to continue with the resolution process.
769 * @param cls the 'struct GNS_ResolverHandle' of the resolution
770 * @param tc task context
773 recursive_resolution (void *cls,
774 const struct GNUNET_SCHEDULER_TaskContext *tc);
778 * Begin the resolution process from 'name', starting with
779 * the identification of the zone specified by 'name'.
781 * @param rh resolution to perform
784 start_resolver_lookup (struct GNS_ResolverHandle *rh);
788 * Function called with the result of a DNS resolution.
790 * @param cls the request handle of the resolution that
791 * we were attempting to make
792 * @param rs socket that received the response
793 * @param dns dns response, never NULL
794 * @param dns_len number of bytes in @a dns
797 dns_result_parser (void *cls,
798 struct GNUNET_DNSSTUB_RequestSocket *rs,
799 const struct GNUNET_TUN_DnsHeader *dns,
802 struct GNS_ResolverHandle *rh = cls;
803 struct GNUNET_DNSPARSER_Packet *p;
804 const struct GNUNET_DNSPARSER_Record *rec;
805 unsigned int rd_count;
808 rh->dns_request = NULL;
809 GNUNET_SCHEDULER_cancel (rh->task_id);
810 rh->task_id = GNUNET_SCHEDULER_NO_TASK;
811 p = GNUNET_DNSPARSER_parse ((const char *) dns,
815 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
816 _("Failed to parse DNS response\n"));
817 rh->proc (rh->proc_cls, 0, NULL);
818 GNS_resolver_lookup_cancel (rh);
821 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
822 "Received DNS response for `%s' with %u answers\n",
824 (unsigned int) p->num_answers);
825 if ( (p->num_answers > 0) &&
826 (GNUNET_DNSPARSER_TYPE_CNAME == p->answers[0].type) &&
827 (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type) )
829 GNUNET_free (rh->name);
830 rh->name = GNUNET_strdup (p->answers[0].data.hostname);
831 start_resolver_lookup (rh);
832 GNUNET_DNSPARSER_free_packet (p);
835 /* FIXME: add DNAME support */
837 /* convert from (parsed) DNS to (binary) GNS format! */
838 rd_count = p->num_answers + p->num_authority_records + p->num_additional_records;
840 struct GNUNET_GNSRECORD_Data rd[rd_count];
842 char buf[UINT16_MAX];
848 memset (rd, 0, sizeof (rd));
849 for (i=0;i<rd_count;i++)
851 if (i < p->num_answers)
852 rec = &p->answers[i];
853 else if (i < p->num_answers + p->num_authority_records)
854 rec = &p->authority_records[i - p->num_answers];
856 rec = &p->authority_records[i - p->num_answers - p->num_authority_records];
857 /* As we copied the full DNS name to 'rh->ac_tail->label', this
858 should be the correct check to see if this record is actually
859 a record for our label... */
860 if (0 != strcmp (rec->name,
863 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
864 "Dropping record `%s', does not match desired name `%s'\n",
870 rd[i - skip].record_type = rec->type;
871 rd[i - skip].expiration_time = rec->expiration_time.abs_value_us;
874 case GNUNET_DNSPARSER_TYPE_A:
875 if (rec->data.raw.data_len != sizeof (struct in_addr))
881 rd[i - skip].data_size = rec->data.raw.data_len;
882 rd[i - skip].data = rec->data.raw.data;
884 case GNUNET_DNSPARSER_TYPE_AAAA:
885 if (rec->data.raw.data_len != sizeof (struct in6_addr))
891 rd[i - skip].data_size = rec->data.raw.data_len;
892 rd[i - skip].data = rec->data.raw.data;
894 case GNUNET_DNSPARSER_TYPE_CNAME:
895 case GNUNET_DNSPARSER_TYPE_PTR:
896 case GNUNET_DNSPARSER_TYPE_NS:
899 GNUNET_DNSPARSER_builder_add_name (buf,
908 rd[i - skip].data_size = buf_off - buf_start;
909 rd[i - skip].data = &buf[buf_start];
911 case GNUNET_DNSPARSER_TYPE_SOA:
914 GNUNET_DNSPARSER_builder_add_soa (buf,
923 rd[i - skip].data_size = buf_off - buf_start;
924 rd[i - skip].data = &buf[buf_start];
926 case GNUNET_DNSPARSER_TYPE_MX:
929 GNUNET_DNSPARSER_builder_add_mx (buf,
938 rd[i - skip].data_size = buf_off - buf_start;
939 rd[i - skip].data = &buf[buf_start];
941 case GNUNET_DNSPARSER_TYPE_SRV:
944 GNUNET_DNSPARSER_builder_add_srv (buf,
953 rd[i - skip].data_size = buf_off - buf_start;
954 rd[i - skip].data = &buf[buf_start];
957 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
958 _("Skipping record of unsupported type %d\n"),
964 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
965 "Returning DNS response for `%s' with %u answers\n",
967 (unsigned int) p->num_answers);
968 rh->proc (rh->proc_cls, rd_count - skip, rd);
969 GNS_resolver_lookup_cancel (rh);
971 GNUNET_DNSPARSER_free_packet (p);
976 * Perform recursive DNS resolution. Asks the given DNS resolver to
977 * resolve "rh->dns_name", possibly recursively proceeding following
978 * NS delegations, CNAMES, etc., until 'rh->loop_limiter' bounds us or
979 * we find the answer.
981 * @param rh resolution information
984 recursive_dns_resolution (struct GNS_ResolverHandle *rh)
986 struct AuthorityChain *ac;
988 struct GNUNET_DNSPARSER_Query *query;
989 struct GNUNET_DNSPARSER_Packet *p;
991 size_t dns_request_length;
994 GNUNET_assert (NULL != ac);
995 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
996 "Starting DNS lookup for `%s'\n",
998 GNUNET_assert (GNUNET_NO == ac->gns_authority);
999 switch (((const struct sockaddr *) &ac->authority_info.dns_authority.dns_ip)->sa_family)
1002 sa_len = sizeof (struct sockaddr_in);
1005 sa_len = sizeof (struct sockaddr_in6);
1009 rh->proc (rh->proc_cls, 0, NULL);
1010 GNS_resolver_lookup_cancel (rh);
1013 query = GNUNET_new (struct GNUNET_DNSPARSER_Query);
1014 query->name = GNUNET_strdup (ac->label);
1015 query->type = rh->record_type;
1016 query->dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
1017 p = GNUNET_new (struct GNUNET_DNSPARSER_Packet);
1020 p->id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1022 p->flags.opcode = GNUNET_TUN_DNS_OPCODE_QUERY;
1023 p->flags.recursion_desired = 1;
1025 GNUNET_DNSPARSER_pack (p, 1024, &dns_request, &dns_request_length))
1028 rh->proc (rh->proc_cls, 0, NULL);
1029 GNS_resolver_lookup_cancel (rh);
1033 rh->dns_request = GNUNET_DNSSTUB_resolve (dns_handle,
1034 (const struct sockaddr *) &ac->authority_info.dns_authority.dns_ip,
1040 rh->task_id = GNUNET_SCHEDULER_add_delayed (DNS_LOOKUP_TIMEOUT,
1044 GNUNET_free (dns_request);
1045 GNUNET_DNSPARSER_free_packet (p);
1050 * We encountered a CNAME record during our resolution.
1051 * Merge it into our chain.
1053 * @param rh resolution we are performing
1054 * @param cname value of the cname record we got for the current
1055 * authority chain tail
1058 handle_gns_cname_result (struct GNS_ResolverHandle *rh,
1063 struct AuthorityChain *ac;
1065 nlen = strlen (cname);
1068 &cname[nlen - 2])) )
1070 /* CNAME resolution continues relative to current domain */
1071 if (0 == rh->name_resolution_pos)
1073 res = GNUNET_strndup (cname, nlen - 2);
1074 rh->name_resolution_pos = nlen - 2;
1078 GNUNET_asprintf (&res,
1080 (int) rh->name_resolution_pos,
1084 rh->name_resolution_pos = strlen (res);
1086 GNUNET_free (rh->name);
1088 ac = GNUNET_new (struct AuthorityChain);
1090 ac->gns_authority = GNUNET_YES;
1091 ac->authority_info.gns_authority = rh->ac_tail->authority_info.gns_authority;
1092 ac->label = resolver_lookup_get_next_label (rh);
1093 ac->suggested_shortening_label = NULL;
1094 ac->shortening_started = GNUNET_NO;
1095 /* add AC to tail */
1096 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1099 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1103 /* name is absolute, start from the beginning */
1104 GNUNET_free (rh->name);
1105 rh->name = GNUNET_strdup (cname);
1106 start_resolver_lookup (rh);
1111 * Process a records that were decrypted from a block.
1113 * @param cls closure with the 'struct GNS_ResolverHandle'
1114 * @param rd_count number of entries in @a rd array
1115 * @param rd array of records with data to store
1118 handle_gns_resolution_result (void *cls,
1119 unsigned int rd_count,
1120 const struct GNUNET_GNSRECORD_Data *rd);
1124 * Callback invoked from the VPN service once a redirection is
1125 * available. Provides the IP address that can now be used to
1126 * reach the requested destination. Replaces the "VPN" record
1127 * with the respective A/AAAA record and continues processing.
1129 * @param cls closure
1130 * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error;
1131 * will match 'result_af' from the request
1132 * @param address IP address (struct in_addr or struct in_addr6, depending on 'af')
1133 * that the VPN allocated for the redirection;
1134 * traffic to this IP will now be redirected to the
1135 * specified target peer; NULL on error
1138 vpn_allocation_cb (void *cls,
1140 const void *address)
1142 struct VpnContext *vpn_ctx = cls;
1143 struct GNS_ResolverHandle *rh = vpn_ctx->rh;
1144 struct GNUNET_GNSRECORD_Data rd[vpn_ctx->rd_count];
1147 vpn_ctx->vpn_request = NULL;
1149 GNUNET_assert (GNUNET_OK ==
1150 GNUNET_GNSRECORD_records_deserialize (vpn_ctx->rd_data_size,
1154 for (i=0;i<vpn_ctx->rd_count;i++)
1156 if (GNUNET_GNSRECORD_TYPE_VPN == rd[i].record_type)
1161 rd[i].record_type = GNUNET_DNSPARSER_TYPE_A;
1162 rd[i].data_size = sizeof (struct in_addr);
1163 rd[i].expiration_time = GNUNET_TIME_relative_to_absolute (VPN_TIMEOUT).abs_value_us;
1165 rd[i].data = address;
1168 rd[i].record_type = GNUNET_DNSPARSER_TYPE_AAAA;
1169 rd[i].expiration_time = GNUNET_TIME_relative_to_absolute (VPN_TIMEOUT).abs_value_us;
1171 rd[i].data = address;
1172 rd[i].data_size = sizeof (struct in6_addr);
1180 GNUNET_assert (i < vpn_ctx->rd_count);
1181 handle_gns_resolution_result (rh,
1184 GNUNET_free (vpn_ctx->rd_data);
1185 GNUNET_free (vpn_ctx);
1190 * We've resolved the IP address for the DNS resolver to use
1191 * after encountering a GNS2DNS record.
1193 * TODO: Right now we only foward the request to ONE DNS resolver,
1194 * even if we get multiple IP addresses back; a correct implementation
1195 * should try all DNS resolvers.
1197 * @param cls the `struct GNS_ResolverHandle` where we encountered
1198 * the GNS2DNS record
1199 * @param rd_count number of records in @a rd
1200 * @param rd addresses for the DNS resolver (presumably)
1203 handle_gns2dns_result (void *cls,
1204 unsigned int rd_count,
1205 const struct GNUNET_GNSRECORD_Data *rd)
1207 struct GNS_ResolverHandle *rh = cls;
1208 struct AuthorityChain *ac;
1210 struct sockaddr *sa;
1211 struct sockaddr_in v4;
1212 struct sockaddr_in6 v6;
1215 /* find suitable A/AAAA record */
1216 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1217 "Received %u results for IP address of DNS server for GNS2DNS transition\n",
1219 /* enable cleanup of 'rh' handle that comes next... */
1220 GNUNET_CONTAINER_DLL_insert (rlh_head,
1223 rh->g2dc->rh = NULL;
1226 for (j=0;j<rd_count;j++)
1228 switch (rd[j].record_type)
1230 case GNUNET_DNSPARSER_TYPE_A:
1231 if (sizeof (struct in_addr) != rd[j].data_size)
1233 GNUNET_break_op (0);
1234 rh->proc (rh->proc_cls, 0, NULL);
1235 GNS_resolver_lookup_cancel (rh);
1238 /* FIXME: might want to check if we support IPv4 here,
1239 and otherwise skip this one and hope we find another */
1240 memset (&v4, 0, sizeof (v4));
1241 sa_len = sizeof (v4);
1242 v4.sin_family = AF_INET;
1243 v4.sin_port = htons (53);
1244 #if HAVE_SOCKADDR_IN_SIN_LEN
1245 v4.sin_len = (u_char) sa_len;
1247 memcpy (&v4.sin_addr,
1249 sizeof (struct in_addr));
1250 sa = (struct sockaddr *) &v4;
1252 case GNUNET_DNSPARSER_TYPE_AAAA:
1253 if (sizeof (struct in6_addr) != rd[j].data_size)
1255 GNUNET_break_op (0);
1256 rh->proc (rh->proc_cls, 0, NULL);
1257 GNS_resolver_lookup_cancel (rh);
1260 /* FIXME: might want to check if we support IPv6 here,
1261 and otherwise skip this one and hope we find another */
1262 memset (&v6, 0, sizeof (v6));
1263 sa_len = sizeof (v6);
1264 v6.sin6_family = AF_INET6;
1265 v6.sin6_port = htons (53);
1266 #if HAVE_SOCKADDR_IN_SIN_LEN
1267 v6.sin6_len = (u_char) sa_len;
1269 memcpy (&v6.sin6_addr,
1271 sizeof (struct in6_addr));
1272 sa = (struct sockaddr *) &v6;
1282 /* we cannot continue; NS without A/AAAA */
1283 rh->proc (rh->proc_cls, 0, NULL);
1284 GNS_resolver_lookup_cancel (rh);
1287 /* expand authority chain */
1288 ac = GNUNET_new (struct AuthorityChain);
1290 strcpy (ac->authority_info.dns_authority.name,
1292 memcpy (&ac->authority_info.dns_authority.dns_ip,
1295 /* for DNS recursion, the label is the full DNS name,
1296 created from the remainder of the GNS name and the
1297 name in the NS record */
1298 GNUNET_asprintf (&ac->label,
1300 (int) rh->name_resolution_pos,
1302 (0 != rh->name_resolution_pos) ? "." : "",
1304 GNUNET_free (rh->g2dc->ns);
1305 GNUNET_free (rh->g2dc);
1307 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1308 "Will continue resolution using DNS server `%s' to resolve `%s'\n",
1309 GNUNET_a2s (sa, sa_len),
1311 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1314 if (strlen (ac->label) > GNUNET_DNSPARSER_MAX_NAME_LENGTH)
1316 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1317 _("GNS lookup resulted in DNS name that is too long (`%s')\n"),
1319 rh->proc (rh->proc_cls, 0, NULL);
1320 GNS_resolver_lookup_cancel (rh);
1324 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1330 * Process a records that were decrypted from a block.
1332 * @param cls closure with the `struct GNS_ResolverHandle`
1333 * @param rd_count number of entries in @a rd array
1334 * @param rd array of records with data to store
1337 handle_gns_resolution_result (void *cls,
1338 unsigned int rd_count,
1339 const struct GNUNET_GNSRECORD_Data *rd)
1341 struct GNS_ResolverHandle *rh = cls;
1342 struct AuthorityChain *ac;
1343 struct AuthorityChain *shorten_ac;
1346 struct VpnContext *vpn_ctx;
1347 const struct GNUNET_TUN_GnsVpnRecord *vpn;
1349 struct GNUNET_HashCode vhash;
1351 char scratch[UINT16_MAX];
1353 size_t scratch_start;
1355 struct GNUNET_GNSRECORD_Data rd_new[rd_count];
1356 unsigned int rd_off;
1358 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1359 "Resolution succeeded for `%s' in zone %s, got %u records\n",
1361 GNUNET_GNSRECORD_z2s (&rh->ac_tail->authority_info.gns_authority),
1363 if (0 == rh->name_resolution_pos)
1365 /* top-level match, are we done yet? */
1366 if ( (rd_count > 0) &&
1367 (GNUNET_DNSPARSER_TYPE_CNAME == rd[0].record_type) &&
1368 (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type) )
1371 cname = GNUNET_DNSPARSER_parse_name (rd[0].data,
1374 if ( (NULL == cname) ||
1375 (off != rd[0].data_size) )
1377 GNUNET_break_op (0);
1378 rh->proc (rh->proc_cls, 0, NULL);
1379 GNS_resolver_lookup_cancel (rh);
1380 GNUNET_free_non_null (cname);
1383 handle_gns_cname_result (rh,
1385 GNUNET_free (cname);
1388 /* If A/AAAA was requested, but we got a VPN
1389 record, we convert it to A/AAAA using GNUnet VPN */
1390 if ( (GNUNET_DNSPARSER_TYPE_A == rh->record_type) ||
1391 (GNUNET_DNSPARSER_TYPE_AAAA == rh->record_type) )
1393 for (i=0;i<rd_count;i++)
1395 switch (rd[i].record_type)
1397 case GNUNET_GNSRECORD_TYPE_VPN:
1399 af = (GNUNET_DNSPARSER_TYPE_A == rh->record_type) ? AF_INET : AF_INET6;
1400 if (sizeof (struct GNUNET_TUN_GnsVpnRecord) >
1403 GNUNET_break_op (0);
1404 rh->proc (rh->proc_cls, 0, NULL);
1405 GNS_resolver_lookup_cancel (rh);
1408 vpn = (const struct GNUNET_TUN_GnsVpnRecord *) rd[i].data;
1409 vname = (const char *) &vpn[1];
1410 if ('\0' != vname[rd[i].data_size - 1 - sizeof (struct GNUNET_TUN_GnsVpnRecord)])
1412 GNUNET_break_op (0);
1413 rh->proc (rh->proc_cls, 0, NULL);
1414 GNS_resolver_lookup_cancel (rh);
1417 GNUNET_TUN_service_name_to_hash (vname,
1419 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1420 "Attempting VPN allocation for %s-%s (AF: %d, proto %d)\n",
1421 GNUNET_i2s (&vpn->peer),
1424 (int) ntohs (vpn->proto));
1425 vpn_ctx = GNUNET_new (struct VpnContext);
1426 rh->vpn_ctx = vpn_ctx;
1428 vpn_ctx->rd_data_size = GNUNET_GNSRECORD_records_get_size (rd_count,
1430 vpn_ctx->rd_data = GNUNET_malloc (vpn_ctx->rd_data_size);
1431 vpn_ctx->rd_count = rd_count;
1432 GNUNET_assert (vpn_ctx->rd_data_size ==
1433 GNUNET_GNSRECORD_records_serialize (rd_count,
1435 vpn_ctx->rd_data_size,
1437 vpn_ctx->vpn_request = GNUNET_VPN_redirect_to_peer (vpn_handle,
1442 GNUNET_TIME_relative_to_absolute (VPN_TIMEOUT),
1447 case GNUNET_GNSRECORD_TYPE_GNS2DNS:
1449 /* delegation to DNS */
1450 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1451 "Found GNS2DNS record, delegating to DNS!\n");
1458 } /* end: name_resolution_pos */
1459 /* convert relative names in record values to absolute names,
1460 using 'scratch' array for memory allocations */
1463 shorten_ac = rh->ac_tail;
1464 for (i=0;i<rd_count;i++)
1466 rd_new[rd_off] = rd[i];
1467 /* Check if the embedded name(s) end in "+", and if so,
1468 replace the "+" with the zone at "ac_tail", changing the name
1469 to a ".zkey". The name is allocated on the 'scratch' array,
1470 so we can free it afterwards. */
1471 switch (rd[i].record_type)
1473 case GNUNET_DNSPARSER_TYPE_CNAME:
1478 cname = GNUNET_DNSPARSER_parse_name (rd[i].data,
1481 if ( (NULL == cname) ||
1482 (off != rd[i].data_size) )
1484 GNUNET_break_op (0); /* record not well-formed */
1488 cname = translate_dot_plus (rh, cname);
1489 GNUNET_break (NULL != cname);
1490 scratch_start = scratch_off;
1492 GNUNET_DNSPARSER_builder_add_name (scratch,
1501 rd_new[rd_off].data = &scratch[scratch_start];
1502 rd_new[rd_off].data_size = scratch_off - scratch_start;
1506 GNUNET_free_non_null (cname);
1509 case GNUNET_DNSPARSER_TYPE_SOA:
1511 struct GNUNET_DNSPARSER_SoaRecord *soa;
1514 soa = GNUNET_DNSPARSER_parse_soa (rd[i].data,
1517 if ( (NULL == soa) ||
1518 (off != rd[i].data_size) )
1520 GNUNET_break_op (0); /* record not well-formed */
1524 soa->mname = translate_dot_plus (rh, soa->mname);
1525 soa->rname = translate_dot_plus (rh, soa->rname);
1526 scratch_start = scratch_off;
1528 GNUNET_DNSPARSER_builder_add_soa (scratch,
1537 rd_new[rd_off].data = &scratch[scratch_start];
1538 rd_new[rd_off].data_size = scratch_off - scratch_start;
1543 GNUNET_DNSPARSER_free_soa (soa);
1546 case GNUNET_DNSPARSER_TYPE_MX:
1548 struct GNUNET_DNSPARSER_MxRecord *mx;
1551 mx = GNUNET_DNSPARSER_parse_mx (rd[i].data,
1554 if ( (NULL == mx) ||
1555 (off != rd[i].data_size) )
1557 GNUNET_break_op (0); /* record not well-formed */
1561 mx->mxhost = translate_dot_plus (rh, mx->mxhost);
1562 scratch_start = scratch_off;
1564 GNUNET_DNSPARSER_builder_add_mx (scratch,
1573 rd_new[rd_off].data = &scratch[scratch_start];
1574 rd_new[rd_off].data_size = scratch_off - scratch_start;
1579 GNUNET_DNSPARSER_free_mx (mx);
1582 case GNUNET_DNSPARSER_TYPE_SRV:
1584 struct GNUNET_DNSPARSER_SrvRecord *srv;
1587 /* FIXME: passing rh->name here is is not necessarily what we want
1588 (SRV support not finished) */
1589 srv = GNUNET_DNSPARSER_parse_srv (rh->name,
1593 if ( (NULL == srv) ||
1594 (off != rd[i].data_size) )
1596 GNUNET_break_op (0); /* record not well-formed */
1600 srv->domain_name = translate_dot_plus (rh, srv->domain_name);
1601 srv->target = translate_dot_plus (rh, srv->target);
1602 scratch_start = scratch_off;
1604 GNUNET_DNSPARSER_builder_add_srv (scratch,
1613 rd_new[rd_off].data = &scratch[scratch_start];
1614 rd_new[rd_off].data_size = scratch_off - scratch_start;
1619 GNUNET_DNSPARSER_free_srv (srv);
1623 case GNUNET_GNSRECORD_TYPE_NICK:
1627 if ((rd[i].data_size > 0) &&
1628 (nick[rd[i].data_size -1] != '\0'))
1630 GNUNET_break_op (0);
1633 if (NULL == shorten_ac->suggested_shortening_label)
1634 shorten_ac->suggested_shortening_label = GNUNET_strdup (nick);
1637 case GNUNET_GNSRECORD_TYPE_PKEY:
1639 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
1641 if (rd[i].data_size != sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))
1643 GNUNET_break_op (0);
1646 memcpy (&pub, rd[i].data, rd[i].data_size);
1648 if (GNUNET_GNSRECORD_TYPE_PKEY != rh->record_type)
1650 /* try to resolve "+" */
1651 struct AuthorityChain *ac;
1653 ac = GNUNET_new (struct AuthorityChain);
1655 ac->gns_authority = GNUNET_YES;
1656 ac->authority_info.gns_authority = pub;
1657 ac->label = GNUNET_strdup (GNUNET_GNS_MASTERZONE_STR);
1658 ac->suggested_shortening_label = NULL;
1659 ac->shortening_started = GNUNET_NO;
1660 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1663 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1669 case GNUNET_GNSRECORD_TYPE_GNS2DNS:
1671 /* delegation to DNS */
1672 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1673 "Found GNS2DNS record, delegating to DNS!\n");
1680 } /* end: for rd_count */
1682 /* trigger shortening */
1683 if ((NULL != rh->shorten_key) &&
1684 (NULL != shorten_ac) &&
1685 (GNUNET_NO == shorten_ac->shortening_started) &&
1686 (NULL != shorten_ac->suggested_shortening_label))
1688 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1689 "Start shortening for label `%s' based on nick `%s'\n",
1691 shorten_ac->suggested_shortening_label);
1692 shorten_ac->shortening_started = GNUNET_YES;
1693 GNS_shorten_start (shorten_ac->label,
1694 shorten_ac->suggested_shortening_label,
1695 &shorten_ac->authority_info.gns_authority,
1699 /* yes, we are done, return result */
1700 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1701 "Returning GNS response for `%s' with %u answers\n",
1704 rh->proc (rh->proc_cls, rd_off, rd_new);
1705 GNS_resolver_lookup_cancel (rh);
1709 /* need to recurse, check if we can */
1710 for (i=0;i<rd_count;i++)
1712 switch (rd[i].record_type)
1714 case GNUNET_GNSRECORD_TYPE_PKEY:
1715 /* delegation to another zone */
1716 if (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) !=
1719 GNUNET_break_op (0);
1720 rh->proc (rh->proc_cls, 0, NULL);
1721 GNS_resolver_lookup_cancel (rh);
1724 /* expand authority chain */
1725 ac = GNUNET_new (struct AuthorityChain);
1727 ac->gns_authority = GNUNET_YES;
1728 ac->suggested_shortening_label = NULL;
1729 ac->shortening_started = GNUNET_NO;
1730 memcpy (&ac->authority_info.gns_authority,
1732 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1733 ac->label = resolver_lookup_get_next_label (rh);
1734 /* add AC to tail */
1735 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1739 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1742 case GNUNET_GNSRECORD_TYPE_GNS2DNS:
1744 /* resolution continues within DNS */
1745 struct Gns2DnsContext *g2dc;
1750 ns = GNUNET_DNSPARSER_parse_name (rd[i].data,
1753 ip = GNUNET_DNSPARSER_parse_name (rd[i].data,
1756 if ( (NULL == ns) ||
1758 (off != rd[i].data_size) )
1760 GNUNET_break_op (0);
1761 GNUNET_free_non_null (ns);
1762 GNUNET_free_non_null (ip);
1763 rh->proc (rh->proc_cls, 0, NULL);
1764 GNS_resolver_lookup_cancel (rh);
1767 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1768 "Resolving `%s' to determine IP address of DNS server for GNS2DNS transition\n",
1770 /* resolve 'ip' to determine the IP(s) of the DNS
1772 g2dc = GNUNET_new (struct Gns2DnsContext);
1774 g2dc->rh = GNUNET_new (struct GNS_ResolverHandle);
1775 g2dc->rh->authority_zone = rh->ac_tail->authority_info.gns_authority;
1776 ip = translate_dot_plus (rh, ip);
1777 g2dc->rh->name = ip;
1778 g2dc->rh->name_resolution_pos = strlen (ip);
1779 g2dc->rh->proc = &handle_gns2dns_result;
1780 g2dc->rh->proc_cls = rh;
1781 g2dc->rh->record_type = GNUNET_GNSRECORD_TYPE_ANY;
1782 g2dc->rh->only_cached = GNUNET_NO;
1783 g2dc->rh->loop_limiter = rh->loop_limiter + 1;
1785 start_resolver_lookup (g2dc->rh);
1788 case GNUNET_DNSPARSER_TYPE_CNAME:
1793 cname = GNUNET_DNSPARSER_parse_name (rd[i].data,
1796 if ( (NULL == cname) ||
1797 (off != rd[i].data_size) )
1799 GNUNET_break_op (0); /* record not well-formed */
1800 rh->proc (rh->proc_cls, 0, NULL);
1801 GNS_resolver_lookup_cancel (rh);
1802 GNUNET_free_non_null (cname);
1805 handle_gns_cname_result (rh,
1807 GNUNET_free (cname);
1810 /* FIXME: handle DNAME */
1816 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1817 _("GNS lookup recursion failed (no delegation record found)\n"));
1818 rh->proc (rh->proc_cls, 0, NULL);
1819 GNS_resolver_lookup_cancel (rh);
1824 * Function called once the namestore has completed the request for
1827 * @param cls closure with the `struct CacheOps`
1828 * @param success #GNUNET_OK on success
1829 * @param emsg error message
1832 namecache_cache_continuation (void *cls,
1836 struct CacheOps *co = cls;
1838 co->namecache_qe_cache = NULL;
1840 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1841 _("Failed to cache GNS resolution: %s\n"),
1843 GNUNET_CONTAINER_DLL_remove (co_head,
1851 * Iterator called on each result obtained for a DHT
1852 * operation that expects a reply
1854 * @param cls closure with the `struct GNS_ResolverHandle`
1855 * @param exp when will this value expire
1856 * @param key key of the result
1857 * @param get_path peers on reply path (or NULL if not recorded)
1858 * [0] = datastore's first neighbor, [length - 1] = local peer
1859 * @param get_path_length number of entries in @a get_path
1860 * @param put_path peers on the PUT path (or NULL if not recorded)
1861 * [0] = origin, [length - 1] = datastore
1862 * @param put_path_length number of entries in @a put_path
1863 * @param type type of the result
1864 * @param size number of bytes in data
1865 * @param data pointer to the result data
1868 handle_dht_response (void *cls,
1869 struct GNUNET_TIME_Absolute exp,
1870 const struct GNUNET_HashCode *key,
1871 const struct GNUNET_PeerIdentity *get_path,
1872 unsigned int get_path_length,
1873 const struct GNUNET_PeerIdentity *put_path,
1874 unsigned int put_path_length,
1875 enum GNUNET_BLOCK_Type type,
1876 size_t size, const void *data)
1878 struct GNS_ResolverHandle *rh = cls;
1879 struct AuthorityChain *ac = rh->ac_tail;
1880 const struct GNUNET_GNSRECORD_Block *block;
1881 struct CacheOps *co;
1883 GNUNET_DHT_get_stop (rh->get_handle);
1884 rh->get_handle = NULL;
1885 GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
1886 rh->dht_heap_node = NULL;
1887 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1888 "Handling response from the DHT\n");
1889 if (size < sizeof (struct GNUNET_GNSRECORD_Block))
1891 /* how did this pass DHT block validation!? */
1893 rh->proc (rh->proc_cls, 0, NULL);
1894 GNS_resolver_lookup_cancel (rh);
1899 ntohl (block->purpose.size) +
1900 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) +
1901 sizeof (struct GNUNET_CRYPTO_EcdsaSignature))
1903 /* how did this pass DHT block validation!? */
1905 rh->proc (rh->proc_cls, 0, NULL);
1906 GNS_resolver_lookup_cancel (rh);
1910 GNUNET_GNSRECORD_block_decrypt (block,
1911 &ac->authority_info.gns_authority,
1913 &handle_gns_resolution_result,
1916 GNUNET_break_op (0); /* block was ill-formed */
1917 rh->proc (rh->proc_cls, 0, NULL);
1918 GNS_resolver_lookup_cancel (rh);
1921 if (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (block->expiration_time)).rel_value_us)
1923 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1924 "Received expired block from the DHT, will not cache it.\n");
1927 /* Cache well-formed blocks */
1928 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1929 "Caching response from the DHT in namecache\n");
1930 co = GNUNET_new (struct CacheOps);
1931 co->namecache_qe_cache = GNUNET_NAMECACHE_block_cache (namecache_handle,
1933 &namecache_cache_continuation,
1935 GNUNET_CONTAINER_DLL_insert (co_head,
1942 * Initiate a DHT query for a set of GNS records.
1944 * @param rh resolution handle
1945 * @param query key to use in the DHT lookup
1948 start_dht_request (struct GNS_ResolverHandle *rh,
1949 const struct GNUNET_HashCode *query)
1951 struct GNS_ResolverHandle *rx;
1953 GNUNET_assert (NULL == rh->get_handle);
1954 rh->get_handle = GNUNET_DHT_get_start (dht_handle,
1955 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1957 DHT_GNS_REPLICATION_LEVEL,
1958 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
1960 &handle_dht_response, rh);
1961 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
1963 GNUNET_TIME_absolute_get ().abs_value_us);
1964 if (GNUNET_CONTAINER_heap_get_size (dht_lookup_heap) > max_allowed_background_queries)
1966 /* fail longest-standing DHT request */
1967 rx = GNUNET_CONTAINER_heap_peek (dht_lookup_heap);
1968 GNUNET_assert (NULL != rx);
1969 rx->proc (rx->proc_cls, 0, NULL);
1970 GNS_resolver_lookup_cancel (rx);
1976 * Process a records that were decrypted from a block that we
1977 * got from the namecache. If the desired record type is not
1978 * included, we should query the DHT. Otherwise, we should
1979 * simply call #handle_gns_resolution_result().
1981 * @param cls closure with the `struct GNS_ResolverHandle`
1982 * @param rd_count number of entries in @a rd array
1983 * @param rd array of records with data to store
1986 handle_gns_namecache_resolution_result (void *cls,
1987 unsigned int rd_count,
1988 const struct GNUNET_GNSRECORD_Data *rd)
1990 struct GNS_ResolverHandle *rh = cls;
1995 for (i=0;i<rd_count;i++)
1997 if (rd[i].record_type == rh->record_type)
2002 switch (rd[i].record_type)
2004 case GNUNET_GNSRECORD_TYPE_VPN:
2005 if ( (GNUNET_DNSPARSER_TYPE_A == rh->record_type) ||
2006 (GNUNET_DNSPARSER_TYPE_AAAA == rh->record_type) )
2012 case GNUNET_DNSPARSER_TYPE_CNAME:
2013 case GNUNET_GNSRECORD_TYPE_PKEY:
2014 case GNUNET_GNSRECORD_TYPE_GNS2DNS:
2015 /* delegations always count as 'found' */
2022 if (GNUNET_YES == found)
2024 handle_gns_resolution_result (rh,
2031 struct AuthorityChain *ac = rh->ac_tail;
2032 const char *label = ac->label;
2033 const struct GNUNET_CRYPTO_EcdsaPublicKey *auth = &ac->authority_info.gns_authority;
2034 struct GNUNET_HashCode query;
2036 GNUNET_GNSRECORD_query_from_public_key (auth,
2039 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2040 "Starting DHT lookup for `%s' in zone `%s' under key `%s'\n",
2042 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority),
2043 GNUNET_h2s (&query));
2044 start_dht_request (rh, &query);
2050 * Process a record that was stored in the namecache.
2052 * @param cls closure with the `struct GNS_ResolverHandle`
2053 * @param block block that was stored in the namecache
2056 handle_namecache_block_response (void *cls,
2057 const struct GNUNET_GNSRECORD_Block *block)
2059 struct GNS_ResolverHandle *rh = cls;
2060 struct AuthorityChain *ac = rh->ac_tail;
2061 const char *label = ac->label;
2062 const struct GNUNET_CRYPTO_EcdsaPublicKey *auth = &ac->authority_info.gns_authority;
2063 struct GNUNET_HashCode query;
2065 GNUNET_assert (NULL != rh->namecache_qe);
2066 rh->namecache_qe = NULL;
2067 if ( (GNUNET_NO == rh->only_cached) &&
2068 ( (NULL == block) ||
2069 (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (block->expiration_time)).rel_value_us) ) )
2071 /* namecache knows nothing; try DHT lookup */
2072 GNUNET_GNSRECORD_query_from_public_key (auth,
2075 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2076 "Starting DHT lookup for `%s' in zone `%s' under key `%s'\n",
2078 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority),
2079 GNUNET_h2s (&query));
2080 start_dht_request (rh, &query);
2084 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2085 "Received result from namecache for label `%s'\n",
2088 if ( (NULL == block) ||
2089 (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (block->expiration_time)).rel_value_us) )
2091 /* DHT not permitted and no local result, fail */
2092 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2093 "Resolution failed for `%s' in zone %s (DHT lookup not permitted by configuration)\n",
2095 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2096 rh->proc (rh->proc_cls, 0, NULL);
2097 GNS_resolver_lookup_cancel (rh);
2101 GNUNET_GNSRECORD_block_decrypt (block,
2104 &handle_gns_namecache_resolution_result,
2107 GNUNET_break_op (0); /* block was ill-formed */
2108 /* try DHT instead */
2109 GNUNET_GNSRECORD_query_from_public_key (auth,
2112 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2113 "Starting DHT lookup for `%s' in zone `%s' under key `%s'\n",
2115 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority),
2116 GNUNET_h2s (&query));
2117 start_dht_request (rh, &query);
2124 * Lookup tail of our authority chain in the namecache.
2126 * @param rh query we are processing
2129 recursive_gns_resolution_namecache (struct GNS_ResolverHandle *rh)
2131 struct AuthorityChain *ac = rh->ac_tail;
2132 struct GNUNET_HashCode query;
2134 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2135 "Starting GNS resolution for `%s' in zone %s\n",
2137 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2138 GNUNET_GNSRECORD_query_from_public_key (&ac->authority_info.gns_authority,
2141 if (GNUNET_YES == use_cache)
2143 rh->namecache_qe = GNUNET_NAMECACHE_lookup_block (namecache_handle,
2145 &handle_namecache_block_response,
2147 GNUNET_assert (NULL != rh->namecache_qe);
2151 start_dht_request (rh, &query);
2157 * Function called with the result from a revocation check.
2159 * @param cls the `struct GNS_ResovlerHandle`
2160 * @param is_valid #GNUNET_YES if the zone was not yet revoked
2163 handle_revocation_result (void *cls,
2166 struct GNS_ResolverHandle *rh = cls;
2167 struct AuthorityChain *ac = rh->ac_tail;
2169 rh->rev_check = NULL;
2170 if (GNUNET_YES != is_valid)
2172 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2173 _("Zone %s was revoked, resolution fails\n"),
2174 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2175 rh->proc (rh->proc_cls, 0, NULL);
2176 GNS_resolver_lookup_cancel (rh);
2179 recursive_gns_resolution_namecache (rh);
2184 * Perform revocation check on tail of our authority chain.
2186 * @param rh query we are processing
2189 recursive_gns_resolution_revocation (struct GNS_ResolverHandle *rh)
2191 struct AuthorityChain *ac = rh->ac_tail;
2193 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2194 "Starting revocation check for zone %s\n",
2195 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2196 rh->rev_check = GNUNET_REVOCATION_query (cfg,
2197 &ac->authority_info.gns_authority,
2198 &handle_revocation_result,
2200 GNUNET_assert (NULL != rh->rev_check);
2205 * Task scheduled to continue with the resolution process.
2207 * @param cls the `struct GNS_ResolverHandle` of the resolution
2208 * @param tc task context
2211 recursive_resolution (void *cls,
2212 const struct GNUNET_SCHEDULER_TaskContext *tc)
2214 struct GNS_ResolverHandle *rh = cls;
2216 rh->task_id = GNUNET_SCHEDULER_NO_TASK;
2217 if (MAX_RECURSION < rh->loop_limiter++)
2219 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2220 "Encountered unbounded recursion resolving `%s'\n",
2222 rh->proc (rh->proc_cls, 0, NULL);
2223 GNS_resolver_lookup_cancel (rh);
2226 if (GNUNET_YES == rh->ac_tail->gns_authority)
2227 recursive_gns_resolution_revocation (rh);
2229 recursive_dns_resolution (rh);
2234 * Begin the resolution process from 'name', starting with
2235 * the identification of the zone specified by 'name'.
2237 * @param rh resolution to perform
2240 start_resolver_lookup (struct GNS_ResolverHandle *rh)
2242 struct AuthorityChain *ac;
2247 if (1 == inet_pton (AF_INET,
2251 /* name is IPv4 address, pretend it's an A record */
2252 struct GNUNET_GNSRECORD_Data rd;
2255 rd.data_size = sizeof (v4);
2256 rd.expiration_time = UINT64_MAX;
2257 rd.record_type = GNUNET_DNSPARSER_TYPE_A;
2259 rh->proc (rh->proc_cls, 1, &rd);
2260 GNS_resolver_lookup_cancel (rh);
2263 if (1 == inet_pton (AF_INET6,
2267 /* name is IPv6 address, pretend it's an AAAA record */
2268 struct GNUNET_GNSRECORD_Data rd;
2271 rd.data_size = sizeof (v6);
2272 rd.expiration_time = UINT64_MAX;
2273 rd.record_type = GNUNET_DNSPARSER_TYPE_AAAA;
2275 rh->proc (rh->proc_cls, 1, &rd);
2276 GNS_resolver_lookup_cancel (rh);
2279 if ( ( (GNUNET_YES == is_canonical (rh->name)) &&
2280 (0 != strcmp (GNUNET_GNS_TLD, rh->name)) ) ||
2281 ( (GNUNET_YES != is_gnu_tld (rh->name)) &&
2282 (GNUNET_YES != is_zkey_tld (rh->name)) ) )
2284 /* use standard DNS lookup */
2287 switch (rh->record_type)
2289 case GNUNET_DNSPARSER_TYPE_A:
2292 case GNUNET_DNSPARSER_TYPE_AAAA:
2299 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2300 "Doing standard DNS lookup for `%s'\n",
2302 rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name,
2309 if (is_zkey_tld (rh->name))
2311 /* Name ends with ".zkey", try to replace authority zone with zkey
2313 GNUNET_free (resolver_lookup_get_next_label (rh)); /* will return "zkey" */
2314 y = resolver_lookup_get_next_label (rh); /* will return 'y' coordinate */
2317 GNUNET_CRYPTO_ecdsa_public_key_from_string (y,
2319 &rh->authority_zone)) )
2321 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2322 _("Hostname `%s' is not well-formed, resolution fails\n"),
2324 rh->task_id = GNUNET_SCHEDULER_add_now (&fail_resolution, rh);
2326 GNUNET_free_non_null (y);
2330 /* Name ends with ".gnu", eat ".gnu" and continue with resolution */
2331 GNUNET_free (resolver_lookup_get_next_label (rh));
2333 ac = GNUNET_new (struct AuthorityChain);
2335 ac->label = resolver_lookup_get_next_label (rh);
2336 ac->suggested_shortening_label = NULL;
2337 if (NULL == ac->label)
2338 /* name was just "gnu", so we default to label '+' */
2339 ac->label = GNUNET_strdup (GNUNET_GNS_MASTERZONE_STR);
2340 ac->gns_authority = GNUNET_YES;
2341 ac->authority_info.gns_authority = rh->authority_zone;
2342 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
2345 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
2351 * Lookup of a record in a specific zone calls lookup result processor
2354 * @param zone the zone to perform the lookup in
2355 * @param record_type the record type to look up
2356 * @param name the name to look up
2357 * @param shorten_key a private key for use with PSEU import (can be NULL)
2358 * @param only_cached #GNUNET_NO to only check locally not DHT for performance
2359 * @param proc the processor to call on result
2360 * @param proc_cls the closure to pass to @a proc
2361 * @return handle to cancel operation
2363 struct GNS_ResolverHandle *
2364 GNS_resolver_lookup (const struct GNUNET_CRYPTO_EcdsaPublicKey *zone,
2365 uint32_t record_type,
2367 const struct GNUNET_CRYPTO_EcdsaPrivateKey *shorten_key,
2369 GNS_ResultProcessor proc, void *proc_cls)
2371 struct GNS_ResolverHandle *rh;
2373 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2374 (NULL == shorten_key)
2375 ? "Starting lookup for `%s' with shortening disabled\n"
2376 : "Starting lookup for `%s' with shortening enabled\n",
2378 rh = GNUNET_new (struct GNS_ResolverHandle);
2379 GNUNET_CONTAINER_DLL_insert (rlh_head,
2382 rh->authority_zone = *zone;
2384 rh->proc_cls = proc_cls;
2385 rh->only_cached = only_cached;
2386 rh->record_type = record_type;
2387 rh->name = GNUNET_strdup (name);
2388 rh->name_resolution_pos = strlen (name);
2389 if (NULL != shorten_key)
2391 rh->shorten_key = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
2392 *rh->shorten_key = *shorten_key;
2394 start_resolver_lookup (rh);
2400 * Cancel active resolution (i.e. client disconnected).
2402 * @param rh resolution to abort
2405 GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
2407 struct DnsResult *dr;
2408 struct AuthorityChain *ac;
2409 struct VpnContext *vpn_ctx;
2411 GNUNET_CONTAINER_DLL_remove (rlh_head,
2414 while (NULL != (ac = rh->ac_head))
2416 GNUNET_CONTAINER_DLL_remove (rh->ac_head,
2419 GNUNET_free (ac->label);
2420 GNUNET_free_non_null (ac->suggested_shortening_label);
2423 if (NULL != rh->g2dc)
2425 /* rh->g2dc->rh is NOT in the DLL yet, so to enable us
2426 using GNS_resolver_lookup_cancel here, we need to
2428 if (NULL != rh->g2dc->rh)
2430 GNUNET_CONTAINER_DLL_insert (rlh_head,
2433 GNS_resolver_lookup_cancel (rh->g2dc->rh);
2434 rh->g2dc->rh = NULL;
2436 GNUNET_free (rh->g2dc->ns);
2437 GNUNET_free (rh->g2dc);
2440 if (GNUNET_SCHEDULER_NO_TASK != rh->task_id)
2442 GNUNET_SCHEDULER_cancel (rh->task_id);
2443 rh->task_id = GNUNET_SCHEDULER_NO_TASK;
2445 if (NULL != rh->get_handle)
2447 GNUNET_DHT_get_stop (rh->get_handle);
2448 rh->get_handle = NULL;
2450 if (NULL != rh->dht_heap_node)
2452 GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
2453 rh->dht_heap_node = NULL;
2455 if (NULL != (vpn_ctx = rh->vpn_ctx))
2457 GNUNET_VPN_cancel_request (vpn_ctx->vpn_request);
2458 GNUNET_free (vpn_ctx->rd_data);
2459 GNUNET_free (vpn_ctx);
2461 if (NULL != rh->dns_request)
2463 GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
2464 rh->dns_request = NULL;
2466 if (NULL != rh->namecache_qe)
2468 GNUNET_NAMECACHE_cancel (rh->namecache_qe);
2469 rh->namecache_qe = NULL;
2471 if (NULL != rh->rev_check)
2473 GNUNET_REVOCATION_query_cancel (rh->rev_check);
2474 rh->rev_check = NULL;
2476 if (NULL != rh->std_resolve)
2478 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2479 "Canceling standard DNS resolution\n");
2480 GNUNET_RESOLVER_request_cancel (rh->std_resolve);
2481 rh->std_resolve = NULL;
2483 while (NULL != (dr = rh->dns_result_head))
2485 GNUNET_CONTAINER_DLL_remove (rh->dns_result_head,
2486 rh->dns_result_tail,
2490 GNUNET_free_non_null (rh->shorten_key);
2491 GNUNET_free (rh->name);
2496 /* ***************** Resolver initialization ********************* */
2500 * Initialize the resolver
2502 * @param nc the namecache handle
2503 * @param dht the dht handle
2504 * @param c configuration handle
2505 * @param max_bg_queries maximum number of parallel background queries in dht
2508 GNS_resolver_init (struct GNUNET_NAMECACHE_Handle *nc,
2509 struct GNUNET_DHT_Handle *dht,
2510 const struct GNUNET_CONFIGURATION_Handle *c,
2511 unsigned long long max_bg_queries)
2516 namecache_handle = nc;
2519 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
2520 max_allowed_background_queries = max_bg_queries;
2521 if (GNUNET_SYSERR == (use_cache = GNUNET_CONFIGURATION_get_value_yesno (c,
2524 use_cache = GNUNET_YES;
2525 if (GNUNET_NO == use_cache)
2526 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Namecache disabled\n");
2529 GNUNET_CONFIGURATION_get_value_string (c,
2534 /* user did not specify DNS resolver, use 8.8.8.8 */
2535 dns_ip = GNUNET_strdup ("8.8.8.8");
2537 dns_handle = GNUNET_DNSSTUB_start (dns_ip);
2538 GNUNET_free (dns_ip);
2539 vpn_handle = GNUNET_VPN_connect (cfg);
2547 GNS_resolver_done ()
2549 struct GNS_ResolverHandle *rh;
2550 struct CacheOps *co;
2552 /* abort active resolutions */
2553 while (NULL != (rh = rlh_head))
2555 rh->proc (rh->proc_cls, 0, NULL);
2556 GNS_resolver_lookup_cancel (rh);
2558 while (NULL != (co = co_head))
2560 GNUNET_CONTAINER_DLL_remove (co_head,
2563 GNUNET_NAMECACHE_cancel (co->namecache_qe_cache);
2566 GNUNET_CONTAINER_heap_destroy (dht_lookup_heap);
2567 dht_lookup_heap = NULL;
2568 GNUNET_DNSSTUB_stop (dns_handle);
2570 GNUNET_VPN_disconnect (vpn_handle);
2573 namecache_handle = NULL;
2577 /* *************** common helper functions (do not really belong here) *********** */
2580 * Checks if @a name ends in ".TLD"
2582 * @param name the name to check
2583 * @param tld the TLD to check for
2584 * @return GNUNET_YES or GNUNET_NO
2587 is_tld (const char* name, const char* tld)
2591 if (strlen (name) <= strlen (tld))
2593 offset = strlen (name) - strlen (tld);
2594 if (0 != strcmp (name + offset, tld))
2600 /* end of gnunet-service-gns_resolver.c */