aboutsummaryrefslogtreecommitdiff
path: root/src/gns/gnunet-service-gns_resolver.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gns/gnunet-service-gns_resolver.c')
-rw-r--r--src/gns/gnunet-service-gns_resolver.c3087
1 files changed, 0 insertions, 3087 deletions
diff --git a/src/gns/gnunet-service-gns_resolver.c b/src/gns/gnunet-service-gns_resolver.c
deleted file mode 100644
index 958bf2e94..000000000
--- a/src/gns/gnunet-service-gns_resolver.c
+++ /dev/null
@@ -1,3087 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011-2013 GNUnet e.V.
4
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.
9
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.
14
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/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file gns/gnunet-service-gns_resolver.c
23 * @brief GNU Name System resolver logic
24 * @author Martin Schanzenbach
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#if HAVE_LIBIDN2
29#if HAVE_IDN2_H
30#include <idn2.h>
31#elif HAVE_IDN2_IDN2_H
32#include <idn2/idn2.h>
33#endif
34#elif HAVE_LIBIDN
35#if HAVE_IDNA_H
36#include <idna.h>
37#elif HAVE_IDN_IDNA_H
38#include <idn/idna.h>
39#endif
40#endif
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"
52#include "gns.h"
53#include "gnunet-service-gns.h"
54#include "gnunet-service-gns_resolver.h"
55#include "gnunet_vpn_service.h"
56
57
58/**
59 * Default DHT timeout for lookups.
60 */
61#define DHT_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply ( \
62 GNUNET_TIME_UNIT_SECONDS, 60)
63
64/**
65 * Default timeout for DNS lookups.
66 */
67#define DNS_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply ( \
68 GNUNET_TIME_UNIT_SECONDS, 15)
69
70/**
71 * Default timeout for VPN redirections.
72 */
73#define VPN_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
74
75/**
76 * DHT replication level
77 */
78#define DHT_GNS_REPLICATION_LEVEL 10
79
80
81/**
82 * DLL to hold the authority chain we had to pass in the resolution
83 * process.
84 */
85struct AuthorityChain;
86
87
88/**
89 * Element of a resolution process for looking up the
90 * responsible DNS server hostname in a GNS2DNS recursive
91 * resolution.
92 */
93struct Gns2DnsPending
94{
95 /**
96 * Kept in a DLL.
97 */
98 struct Gns2DnsPending *next;
99
100 /**
101 * Kept in a DLL.
102 */
103 struct Gns2DnsPending *prev;
104
105 /**
106 * Context this activity belongs with.
107 */
108 struct AuthorityChain *ac;
109
110 /**
111 * Handle for the resolution of the IP part of the
112 * GNS2DNS record. Will return to us the addresses
113 * of the DNS resolver to use.
114 */
115 struct GNS_ResolverHandle *rh;
116
117 /**
118 * Handle for DNS resolution of the DNS nameserver.
119 */
120 struct GNUNET_RESOLVER_RequestHandle *dns_rh;
121
122 /**
123 * How many results did we get?
124 */
125 unsigned int num_results;
126};
127
128
129/**
130 * Handle to a currently pending resolution. On result (positive or
131 * negative) the #GNS_ResultProcessor is called.
132 */
133struct GNS_ResolverHandle;
134
135
136/**
137 * DLL to hold the authority chain we had to pass in the resolution
138 * process.
139 */
140struct AuthorityChain
141{
142 /**
143 * This is a DLL.
144 */
145 struct AuthorityChain *prev;
146
147 /**
148 * This is a DLL.
149 */
150 struct AuthorityChain *next;
151
152 /**
153 * Resolver handle this entry in the chain belongs to.
154 */
155 struct GNS_ResolverHandle *rh;
156
157 /**
158 * label/name corresponding to the authority
159 */
160 char *label;
161
162 /**
163 * #GNUNET_YES if the authority was a GNS authority,
164 * #GNUNET_NO if the authority was a DNS authority.
165 */
166 int gns_authority;
167
168 /**
169 * Information about the resolver authority for this label.
170 */
171 union
172 {
173 /**
174 * The zone of the GNS authority
175 */
176 struct GNUNET_IDENTITY_PublicKey gns_authority;
177
178 struct
179 {
180 /**
181 * Domain of the DNS resolver that is the authority.
182 * (appended to construct the DNS name to resolve;
183 * this is NOT the DNS name of the DNS server!).
184 */
185 char name[GNUNET_DNSPARSER_MAX_NAME_LENGTH + 1];
186
187 /**
188 * List of resolutions of the 'ip' of the name server that
189 * are still pending.
190 */
191 struct Gns2DnsPending *gp_head;
192
193 /**
194 * Tail of list of resolutions of the 'ip' of the name server that
195 * are still pending.
196 */
197 struct Gns2DnsPending *gp_tail;
198
199 /**
200 * Handle to perform DNS lookups with this authority (in GNS2DNS handling).
201 */
202 struct GNUNET_DNSSTUB_Context *dns_handle;
203
204 /**
205 * Did we succeed in getting an IP address for *any* of the DNS servers listed?
206 * Once we do, we can start with DNS queries.
207 */
208 int found;
209
210 /**
211 * Did we start the recursive resolution via DNS?
212 */
213 int launched;
214 } dns_authority;
215 } authority_info;
216};
217
218
219/**
220 * A result we got from DNS.
221 */
222struct DnsResult
223{
224 /**
225 * Kept in DLL.
226 */
227 struct DnsResult *next;
228
229 /**
230 * Kept in DLL.
231 */
232 struct DnsResult *prev;
233
234 /**
235 * Binary value stored in the DNS record (appended to this struct)
236 */
237 const void *data;
238
239 /**
240 * Expiration time for the DNS record, 0 if we didn't
241 * get anything useful (i.e. 'gethostbyname()' was used).
242 */
243 uint64_t expiration_time;
244
245 /**
246 * Number of bytes in @e data.
247 */
248 size_t data_size;
249
250 /**
251 * Type of the GNS/DNS record.
252 */
253 uint32_t record_type;
254};
255
256
257/**
258 * Closure for #vpn_allocation_cb.
259 */
260struct VpnContext
261{
262 /**
263 * Which resolution process are we processing.
264 */
265 struct GNS_ResolverHandle *rh;
266
267 /**
268 * Handle to the VPN request that we were performing.
269 */
270 struct GNUNET_VPN_RedirectionRequest *vpn_request;
271
272 /**
273 * Number of records serialized in @e rd_data.
274 */
275 unsigned int rd_count;
276
277 /**
278 * Serialized records.
279 */
280 char *rd_data;
281
282 /**
283 * Number of bytes in @e rd_data.
284 */
285 ssize_t rd_data_size;
286};
287
288
289/**
290 * Handle to a currently pending resolution. On result (positive or
291 * negative) the #GNS_ResultProcessor is called.
292 */
293struct GNS_ResolverHandle
294{
295 /**
296 * DLL
297 */
298 struct GNS_ResolverHandle *next;
299
300 /**
301 * DLL
302 */
303 struct GNS_ResolverHandle *prev;
304
305 /**
306 * The top-level GNS authoritative zone to query
307 */
308 struct GNUNET_IDENTITY_PublicKey authority_zone;
309
310 /**
311 * called when resolution phase finishes
312 */
313 GNS_ResultProcessor proc;
314
315 /**
316 * closure passed to @e proc
317 */
318 void *proc_cls;
319
320 /**
321 * Handle for DHT lookups. should be NULL if no lookups are in progress
322 */
323 struct GNUNET_DHT_GetHandle *get_handle;
324
325 /**
326 * Handle to a VPN request, NULL if none is active.
327 */
328 struct VpnContext *vpn_ctx;
329
330 /**
331 * Socket for a DNS request, NULL if none is active.
332 */
333 struct GNUNET_DNSSTUB_RequestSocket *dns_request;
334
335 /**
336 * Handle for standard DNS resolution, NULL if none is active.
337 */
338 struct GNUNET_RESOLVER_RequestHandle *std_resolve;
339
340 /**
341 * Pending Namecache lookup task
342 */
343 struct GNUNET_NAMECACHE_QueueEntry *namecache_qe;
344
345 /**
346 * Pending revocation check.
347 */
348 struct GNUNET_REVOCATION_Query *rev_check;
349
350 /**
351 * Heap node associated with this lookup. Used to limit number of
352 * concurrent requests.
353 */
354 struct GNUNET_CONTAINER_HeapNode *dht_heap_node;
355
356 /**
357 * DLL to store the authority chain
358 */
359 struct AuthorityChain *ac_head;
360
361 /**
362 * DLL to store the authority chain
363 */
364 struct AuthorityChain *ac_tail;
365
366 /**
367 * ID of a task associated with the resolution process.
368 */
369 struct GNUNET_SCHEDULER_Task *task_id;
370
371 /**
372 * The name to resolve
373 */
374 char *name;
375
376 /**
377 * Legacy Hostname to use if we encountered GNS2DNS record
378 * and thus can deduct the LEHO from that transition.
379 */
380 char *leho;
381
382 /**
383 * DLL of results we got from DNS.
384 */
385 struct DnsResult *dns_result_head;
386
387 /**
388 * DLL of results we got from DNS.
389 */
390 struct DnsResult *dns_result_tail;
391
392 /**
393 * Current offset in @e name where we are resolving.
394 */
395 size_t name_resolution_pos;
396
397 /**
398 * Use only cache
399 */
400 enum GNUNET_GNS_LocalOptions options;
401
402 /**
403 * For SRV and TLSA records, the number of the
404 * protocol specified in the name. 0 if no protocol was given.
405 */
406 int protocol;
407
408 /**
409 * For SRV and TLSA records, the number of the
410 * service specified in the name. 0 if no service was given.
411 */
412 int service;
413
414 /**
415 * Desired type for the resolution.
416 */
417 int record_type;
418
419 /**
420 * We increment the loop limiter for each step in a recursive
421 * resolution. If it passes our @e loop_threshold (e.g. due to
422 * self-recursion in the resolution, i.e CNAME fun), we stop.
423 */
424 unsigned int loop_limiter;
425
426 /**
427 * Maximum value of @e loop_limiter allowed by client.
428 */
429 unsigned int loop_threshold;
430
431 /**
432 * 16 bit random ID we used in the @e dns_request.
433 */
434 uint16_t original_dns_id;
435};
436
437
438/**
439 * Active namestore caching operations.
440 */
441struct CacheOps
442{
443 /**
444 * Organized in a DLL.
445 */
446 struct CacheOps *next;
447
448 /**
449 * Organized in a DLL.
450 */
451 struct CacheOps *prev;
452
453 /**
454 * Pending Namestore caching task.
455 */
456 struct GNUNET_NAMECACHE_QueueEntry *namecache_qe_cache;
457};
458
459
460/**
461 * Our handle to the namecache service
462 */
463static struct GNUNET_NAMECACHE_Handle *namecache_handle;
464
465/**
466 * Our handle to the vpn service
467 */
468static struct GNUNET_VPN_Handle *vpn_handle;
469
470/**
471 * Resolver handle to the dht
472 */
473static struct GNUNET_DHT_Handle *dht_handle;
474
475/**
476 * Heap for limiting parallel DHT lookups
477 */
478static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
479
480/**
481 * Maximum amount of parallel queries to the DHT
482 */
483static unsigned long long max_allowed_background_queries;
484
485/**
486 * Head of resolver lookup list
487 */
488static struct GNS_ResolverHandle *rlh_head;
489
490/**
491 * Tail of resolver lookup list
492 */
493static struct GNS_ResolverHandle *rlh_tail;
494
495/**
496 * Organized in a DLL.
497 */
498static struct CacheOps *co_head;
499
500/**
501 * Organized in a DLL.
502 */
503static struct CacheOps *co_tail;
504
505/**
506 * Use namecache
507 */
508static int disable_cache;
509
510/**
511 * Global configuration.
512 */
513static const struct GNUNET_CONFIGURATION_Handle *cfg;
514
515
516/**
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 (like _foo._srv) are canonical names
520 * even though they consist of multiple labels.
521 *
522 * Examples:
523 * a.b.gnu = not canonical
524 * a = canonical
525 * _foo._srv = canonical
526 * _f.bar = not canonical
527 *
528 * @param name the name to test
529 * @return #GNUNET_YES if canonical
530 */
531/* dead, but keep for now */ int
532is_canonical (const char *name)
533{
534 const char *pos;
535 const char *dot;
536
537 if (NULL == strchr (name,
538 (unsigned char) '.'))
539 return GNUNET_YES;
540 if ('_' != name[0])
541 return GNUNET_NO;
542 pos = &name[1];
543 while (NULL != (dot = strchr (pos,
544 (unsigned char) '.')))
545 if ('_' != dot[1])
546 return GNUNET_NO;
547 else
548 pos = dot + 1;
549 return GNUNET_YES;
550}
551
552
553/* ************************** Resolution **************************** */
554
555/**
556 * Expands a name ending in .+ with the zone of origin.
557 *
558 * @param rh resolution context
559 * @param name name to modify (to be free'd or returned)
560 * @return updated name
561 */
562static char *
563translate_dot_plus (struct GNS_ResolverHandle *rh,
564 char *name)
565{
566 char *ret;
567 size_t s_len = strlen (name);
568
569 if (0 != strcmp (&name[s_len - 2],
570 ".+"))
571 return name; /* did not end in ".+" */
572 GNUNET_assert (GNUNET_YES == rh->ac_tail->gns_authority);
573 GNUNET_asprintf (&ret,
574 "%.*s.%s",
575 (int) (s_len - 2),
576 name,
577 GNUNET_GNSRECORD_pkey_to_zkey (
578 &rh->ac_tail->authority_info.gns_authority));
579 GNUNET_free (name);
580 return ret;
581}
582
583
584/**
585 * Wrapper around #GNS_resolver_lookup_cancel() as a task.
586 * Used for delayed cleanup so we can unwind the stack first.
587 *
588 * @param cls the `struct GNS_ResolverHandle`
589 */
590static void
591GNS_resolver_lookup_cancel_ (void *cls)
592{
593 struct GNS_ResolverHandle *rh = cls;
594
595 rh->task_id = NULL;
596 GNS_resolver_lookup_cancel (rh);
597}
598
599
600/**
601 * Function called to asynchronously fail a resolution.
602 *
603 * @param rh the resolution to fail
604 */
605static void
606fail_resolution (struct GNS_ResolverHandle *rh)
607{
608 rh->proc (rh->proc_cls,
609 0,
610 NULL);
611 GNUNET_assert (NULL == rh->task_id);
612 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
613 rh);
614}
615
616
617/**
618 * Function called when a resolution times out.
619 *
620 * @param cls the `struct GNS_ResolverHandle`
621 */
622static void
623timeout_resolution (void *cls)
624{
625 struct GNS_ResolverHandle *rh = cls;
626
627 rh->task_id = NULL;
628 fail_resolution (rh);
629}
630
631
632/**
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).
645 *
646 * @param rh handle to the resolution operation to get the next label from
647 * @return NULL if there are no more labels
648 */
649static char *
650resolver_lookup_get_next_label (struct GNS_ResolverHandle *rh)
651{
652 const char *rp;
653 const char *dot;
654 size_t len;
655 char *ret;
656 char *srv_name;
657 char *proto_name;
658 struct protoent *pe;
659 struct servent *se;
660
661 if (0 == rh->name_resolution_pos)
662 return NULL;
663 dot = memrchr (rh->name,
664 (int) '.',
665 rh->name_resolution_pos);
666 if (NULL == dot)
667 {
668 /* done, this was the last one */
669 len = rh->name_resolution_pos;
670 rp = rh->name;
671 rh->name_resolution_pos = 0;
672 }
673 else
674 {
675 /* advance by one label */
676 len = rh->name_resolution_pos - (dot - rh->name) - 1;
677 rp = dot + 1;
678 rh->name_resolution_pos = dot - rh->name;
679 }
680 rh->protocol = 0;
681 rh->service = 0;
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".
686 */
687 if (('_' == rh->name[0]) &&
688 (NULL != (dot = memrchr (rh->name,
689 (int) '.',
690 rh->name_resolution_pos))) &&
691 ('_' == dot[1]) &&
692 (NULL == memrchr (rh->name,
693 (int) '.',
694 dot - rh->name)))
695 {
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)
700 - 2);
701 rh->name_resolution_pos = 0;
702 pe = getprotobyname (proto_name);
703 if (NULL == pe)
704 {
705 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
706 _ ("Protocol `%s' unknown, skipping labels.\n"),
707 proto_name);
708 GNUNET_free (proto_name);
709 GNUNET_free (srv_name);
710 return ret;
711 }
712 se = getservbyname (srv_name,
713 proto_name);
714 if (NULL == se)
715 {
716 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
717 _ (
718 "Service `%s' unknown for protocol `%s', trying as number.\n"),
719 srv_name,
720 proto_name);
721 if (1 != sscanf (srv_name, "%u", &rh->service))
722 {
723 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
724 _ ("Service `%s' not a port, skipping service labels.\n"),
725 srv_name);
726 GNUNET_free (proto_name);
727 GNUNET_free (srv_name);
728 return ret;
729 }
730 }
731 else
732 {
733 rh->service = se->s_port;
734 }
735 rh->protocol = pe->p_proto;
736 GNUNET_free (proto_name);
737 GNUNET_free (srv_name);
738 }
739 return ret;
740}
741
742
743/**
744 * Gives the cumulative result obtained to the callback and clean up the request.
745 *
746 * @param rh resolution process that has culminated in a result
747 */
748static void
749transmit_lookup_dns_result (struct GNS_ResolverHandle *rh)
750{
751 struct DnsResult *pos;
752 unsigned int n;
753 unsigned int i;
754
755 n = 0;
756 for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
757 n++;
758 {
759 struct GNUNET_GNSRECORD_Data rd[n];
760
761 i = 0;
762 for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
763 {
764 rd[i].data = pos->data;
765 rd[i].data_size = pos->data_size;
766 rd[i].record_type = pos->record_type;
767 rd[i].flags = GNUNET_GNSRECORD_RF_NONE;
768 /**
769 * If this is a LEHO, we added this before. It must be a supplemental
770 * record #LSD0001
771 */
772 if (GNUNET_GNSRECORD_TYPE_LEHO == rd[i].record_type)
773 rd[i].flags |= GNUNET_GNSRECORD_RF_SUPPLEMENTAL;
774 if (0 == pos->expiration_time)
775 {
776 rd[i].flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
777 rd[i].expiration_time = 0;
778 }
779 else
780 {
781 rd[i].expiration_time = pos->expiration_time;
782 }
783 i++;
784 }
785 GNUNET_assert (i == n);
786 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
787 "Transmitting standard DNS result with %u records\n",
788 n);
789 rh->proc (rh->proc_cls,
790 n,
791 rd);
792 }
793 GNS_resolver_lookup_cancel (rh);
794}
795
796
797/**
798 * Add a result from DNS to the records to be returned to the application.
799 *
800 * @param rh resolution request to extend with a result
801 * @param expiration_time expiration time for the answer
802 * @param record_type DNS record type of the answer
803 * @param data_size number of bytes in @a data
804 * @param data binary data to return in DNS record
805 */
806static void
807add_dns_result (struct GNS_ResolverHandle *rh,
808 uint64_t expiration_time,
809 uint32_t record_type,
810 size_t data_size,
811 const void *data)
812{
813 struct DnsResult *res;
814
815 res = GNUNET_malloc (sizeof(struct DnsResult) + data_size);
816 res->expiration_time = expiration_time;
817 res->data_size = data_size;
818 res->record_type = record_type;
819 res->data = &res[1];
820 GNUNET_memcpy (&res[1],
821 data,
822 data_size);
823 GNUNET_CONTAINER_DLL_insert (rh->dns_result_head,
824 rh->dns_result_tail,
825 res);
826}
827
828
829/**
830 * We had to do a DNS lookup. Convert the result (if any) and return
831 * it.
832 *
833 * @param cls closure with the `struct GNS_ResolverHandle`
834 * @param addr one of the addresses of the host, NULL for the last address
835 * @param addrlen length of the address
836 */
837static void
838handle_dns_result (void *cls,
839 const struct sockaddr *addr,
840 socklen_t addrlen)
841{
842 struct GNS_ResolverHandle *rh = cls;
843 const struct sockaddr_in *sa4;
844 const struct sockaddr_in6 *sa6;
845
846 if (NULL == addr)
847 {
848 rh->std_resolve = NULL;
849 transmit_lookup_dns_result (rh);
850 return;
851 }
852 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
853 "Received %u bytes of DNS IP data\n",
854 addrlen);
855 switch (addr->sa_family)
856 {
857 case AF_INET:
858 sa4 = (const struct sockaddr_in *) addr;
859 add_dns_result (rh,
860 0 /* expiration time is unknown */,
861 GNUNET_DNSPARSER_TYPE_A,
862 sizeof(struct in_addr),
863 &sa4->sin_addr);
864 break;
865
866 case AF_INET6:
867 sa6 = (const struct sockaddr_in6 *) addr;
868 add_dns_result (rh,
869 0 /* expiration time is unknown */,
870 GNUNET_DNSPARSER_TYPE_AAAA,
871 sizeof(struct in6_addr),
872 &sa6->sin6_addr);
873 break;
874
875 default:
876 GNUNET_break (0);
877 break;
878 }
879}
880
881
882/**
883 * Task scheduled to continue with the resolution process.
884 *
885 * @param cls the 'struct GNS_ResolverHandle' of the resolution
886 * @param tc task context
887 */
888static void
889recursive_resolution (void *cls);
890
891
892/**
893 * Begin the resolution process from 'name', starting with
894 * the identification of the zone specified by 'name'.
895 *
896 * @param cls closure with `struct GNS_ResolverHandle *rh`
897 */
898static void
899start_resolver_lookup (void *cls);
900
901
902/**
903 * Function called with the result of a DNS resolution.
904 *
905 * @param cls the request handle of the resolution that
906 * we were attempting to make
907 * @param dns dns response, never NULL
908 * @param dns_len number of bytes in @a dns
909 */
910static void
911dns_result_parser (void *cls,
912 const struct GNUNET_TUN_DnsHeader *dns,
913 size_t dns_len)
914{
915 struct GNS_ResolverHandle *rh = cls;
916 struct GNUNET_DNSPARSER_Packet *p;
917 const struct GNUNET_DNSPARSER_Record *rec;
918 unsigned int rd_count;
919
920 if (NULL == dns)
921 {
922 rh->dns_request = NULL;
923 GNUNET_SCHEDULER_cancel (rh->task_id);
924 rh->task_id = NULL;
925 fail_resolution (rh);
926 return;
927 }
928 if (rh->original_dns_id != dns->id)
929 {
930 /* DNS answer, but for another query */
931 return;
932 }
933 p = GNUNET_DNSPARSER_parse ((const char *) dns,
934 dns_len);
935 if (NULL == p)
936 {
937 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
938 _ ("Failed to parse DNS response\n"));
939 return;
940 }
941
942 /* We got a result from DNS */
943 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
944 "Received DNS response for `%s' with %u answers\n",
945 rh->ac_tail->label,
946 (unsigned int) p->num_answers);
947 if ((p->num_answers > 0) &&
948 (GNUNET_DNSPARSER_TYPE_CNAME == p->answers[0].type) &&
949 (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type))
950 {
951 int af;
952
953 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
954 "Got CNAME `%s' from DNS for `%s'\n",
955 p->answers[0].data.hostname,
956 rh->name);
957 if (NULL != rh->std_resolve)
958 {
959 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
960 "Multiple CNAME results from DNS resolving `%s'! Not really allowed...\n",
961 rh->name);
962 GNUNET_RESOLVER_request_cancel (rh->std_resolve);
963 }
964 GNUNET_free (rh->name);
965 rh->name = GNUNET_strdup (p->answers[0].data.hostname);
966 rh->name_resolution_pos = strlen (rh->name);
967 switch (rh->record_type)
968 {
969 case GNUNET_DNSPARSER_TYPE_A:
970 af = AF_INET;
971 break;
972
973 case GNUNET_DNSPARSER_TYPE_AAAA:
974 af = AF_INET6;
975 break;
976
977 default:
978 af = AF_UNSPEC;
979 break;
980 }
981 if (NULL != rh->leho)
982 add_dns_result (rh,
983 GNUNET_TIME_UNIT_HOURS.rel_value_us,
984 GNUNET_GNSRECORD_TYPE_LEHO,
985 strlen (rh->leho),
986 rh->leho);
987 rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name,
988 af,
989 DNS_LOOKUP_TIMEOUT,
990 &handle_dns_result,
991 rh);
992 GNUNET_DNSPARSER_free_packet (p);
993 GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
994 rh->dns_request = NULL;
995 return;
996 }
997
998 /* convert from (parsed) DNS to (binary) GNS format! */
999 rd_count = p->num_answers + p->num_authority_records
1000 + p->num_additional_records;
1001 {
1002 struct GNUNET_GNSRECORD_Data rd[rd_count + 1]; /* +1 for LEHO */
1003 int skip;
1004 char buf[UINT16_MAX];
1005 size_t buf_off;
1006 size_t buf_start;
1007
1008 buf_off = 0;
1009 skip = 0;
1010 memset (rd,
1011 0,
1012 sizeof(rd));
1013 for (unsigned int i = 0; i < rd_count; i++)
1014 {
1015 if (i < p->num_answers)
1016 rec = &p->answers[i];
1017 else if (i < p->num_answers + p->num_authority_records)
1018 rec = &p->authority_records[i - p->num_answers];
1019 else
1020 rec = &p->additional_records[i - p->num_answers
1021 - p->num_authority_records];
1022 /* As we copied the full DNS name to 'rh->ac_tail->label', this
1023 should be the correct check to see if this record is actually
1024 a record for our label... */
1025 if (0 != strcmp (rec->name,
1026 rh->ac_tail->label))
1027 {
1028 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1029 "Dropping record `%s', does not match desired name `%s'\n",
1030 rec->name,
1031 rh->ac_tail->label);
1032 skip++;
1033 continue;
1034 }
1035 rd[i - skip].record_type = rec->type;
1036 rd[i - skip].expiration_time = rec->expiration_time.abs_value_us;
1037 switch (rec->type)
1038 {
1039 case GNUNET_DNSPARSER_TYPE_A:
1040 if (rec->data.raw.data_len != sizeof(struct in_addr))
1041 {
1042 GNUNET_break_op (0);
1043 skip++;
1044 continue;
1045 }
1046 rd[i - skip].data_size = rec->data.raw.data_len;
1047 rd[i - skip].data = rec->data.raw.data;
1048 break;
1049
1050 case GNUNET_DNSPARSER_TYPE_AAAA:
1051 if (rec->data.raw.data_len != sizeof(struct in6_addr))
1052 {
1053 GNUNET_break_op (0);
1054 skip++;
1055 continue;
1056 }
1057 rd[i - skip].data_size = rec->data.raw.data_len;
1058 rd[i - skip].data = rec->data.raw.data;
1059 break;
1060
1061 case GNUNET_DNSPARSER_TYPE_CNAME:
1062 case GNUNET_DNSPARSER_TYPE_PTR:
1063 case GNUNET_DNSPARSER_TYPE_NS:
1064 buf_start = buf_off;
1065 if (GNUNET_OK !=
1066 GNUNET_DNSPARSER_builder_add_name (buf,
1067 sizeof(buf),
1068 &buf_off,
1069 rec->data.hostname))
1070 {
1071 GNUNET_break (0);
1072 skip++;
1073 continue;
1074 }
1075 rd[i - skip].data_size = buf_off - buf_start;
1076 rd[i - skip].data = &buf[buf_start];
1077 break;
1078
1079 case GNUNET_DNSPARSER_TYPE_SOA:
1080 buf_start = buf_off;
1081 if (GNUNET_OK !=
1082 GNUNET_DNSPARSER_builder_add_soa (buf,
1083 sizeof(buf),
1084 &buf_off,
1085 rec->data.soa))
1086 {
1087 GNUNET_break (0);
1088 skip++;
1089 continue;
1090 }
1091 rd[i - skip].data_size = buf_off - buf_start;
1092 rd[i - skip].data = &buf[buf_start];
1093 break;
1094
1095 case GNUNET_DNSPARSER_TYPE_MX:
1096 buf_start = buf_off;
1097 if (GNUNET_OK !=
1098 GNUNET_DNSPARSER_builder_add_mx (buf,
1099 sizeof(buf),
1100 &buf_off,
1101 rec->data.mx))
1102 {
1103 GNUNET_break (0);
1104 skip++;
1105 continue;
1106 }
1107 rd[i - skip].data_size = buf_off - buf_start;
1108 rd[i - skip].data = &buf[buf_start];
1109 break;
1110
1111 case GNUNET_DNSPARSER_TYPE_SRV:
1112 buf_start = buf_off;
1113 if (GNUNET_OK !=
1114 GNUNET_DNSPARSER_builder_add_srv (buf,
1115 sizeof(buf),
1116 &buf_off,
1117 rec->data.srv))
1118 {
1119 GNUNET_break (0);
1120 skip++;
1121 continue;
1122 }
1123 rd[i - skip].data_size = buf_off - buf_start;
1124 rd[i - skip].data = &buf[buf_start];
1125 break;
1126
1127 default:
1128 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1129 _ ("Skipping record of unsupported type %d\n"),
1130 rec->type);
1131 skip++;
1132 continue;
1133 }
1134 } /* end of for all records in answer */
1135 if (NULL != rh->leho)
1136 {
1137 rd[rd_count - skip].record_type = GNUNET_GNSRECORD_TYPE_LEHO;
1138 rd[rd_count - skip].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1139 rd[rd_count - skip].flags |= GNUNET_GNSRECORD_RF_SUPPLEMENTAL;
1140 rd[rd_count - skip].expiration_time = GNUNET_TIME_UNIT_HOURS.rel_value_us;
1141 rd[rd_count - skip].data = rh->leho;
1142 rd[rd_count - skip].data_size = strlen (rh->leho);
1143 skip--; /* skip one LESS */
1144 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1145 "Adding LEHO %s\n",
1146 rh->leho);
1147 }
1148 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1149 "Returning DNS response for `%s' with %u answers\n",
1150 rh->ac_tail->label,
1151 (unsigned int) (rd_count - skip));
1152 rh->proc (rh->proc_cls,
1153 rd_count - skip,
1154 rd);
1155 GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
1156 rh->dns_request = NULL;
1157 }
1158 GNUNET_DNSPARSER_free_packet (p);
1159 if (NULL != rh->task_id)
1160 GNUNET_SCHEDULER_cancel (rh->task_id); /* should be timeout task */
1161 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
1162 rh);
1163}
1164
1165
1166/**
1167 * Perform recursive DNS resolution. Asks the given DNS resolver to
1168 * resolve "rh->dns_name", possibly recursively proceeding following
1169 * NS delegations, CNAMES, etc., until 'rh->loop_limiter' bounds us or
1170 * we find the answer.
1171 *
1172 * @param rh resolution information
1173 */
1174static void
1175recursive_dns_resolution (struct GNS_ResolverHandle *rh)
1176{
1177 struct AuthorityChain *ac;
1178 struct GNUNET_DNSPARSER_Query *query;
1179 struct GNUNET_DNSPARSER_Packet *p;
1180 char *dns_request;
1181 size_t dns_request_length;
1182 int ret;
1183
1184 ac = rh->ac_tail;
1185 GNUNET_assert (NULL != ac);
1186 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1187 "Starting DNS lookup for `%s'\n",
1188 ac->label);
1189 GNUNET_assert (GNUNET_NO == ac->gns_authority);
1190 query = GNUNET_new (struct GNUNET_DNSPARSER_Query);
1191 query->name = GNUNET_strdup (ac->label);
1192 query->type = rh->record_type;
1193 query->dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
1194 p = GNUNET_new (struct GNUNET_DNSPARSER_Packet);
1195 p->queries = query;
1196 p->num_queries = 1;
1197 p->id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1198 UINT16_MAX);
1199 p->flags.opcode = GNUNET_TUN_DNS_OPCODE_QUERY;
1200 p->flags.recursion_desired = 1;
1201 ret = GNUNET_DNSPARSER_pack (p,
1202 1024,
1203 &dns_request,
1204 &dns_request_length);
1205 if (GNUNET_OK != ret)
1206 {
1207 GNUNET_break (0);
1208 rh->proc (rh->proc_cls,
1209 0,
1210 NULL);
1211 GNUNET_assert (NULL == rh->task_id);
1212 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
1213 rh);
1214 }
1215 else
1216 {
1217 rh->original_dns_id = p->id;
1218 GNUNET_assert (NULL != ac->authority_info.dns_authority.dns_handle);
1219 GNUNET_assert (NULL == rh->dns_request);
1220 rh->leho = GNUNET_strdup (ac->label);
1221 rh->dns_request = GNUNET_DNSSTUB_resolve (
1222 ac->authority_info.dns_authority.dns_handle,
1223 dns_request,
1224 dns_request_length,
1225 &dns_result_parser,
1226 rh);
1227 rh->task_id = GNUNET_SCHEDULER_add_delayed (DNS_LOOKUP_TIMEOUT,
1228 &timeout_resolution,
1229 rh);
1230 }
1231 if (GNUNET_SYSERR != ret)
1232 GNUNET_free (dns_request);
1233 GNUNET_DNSPARSER_free_packet (p);
1234}
1235
1236
1237/**
1238 * We encountered a CNAME record during our resolution.
1239 * Merge it into our chain.
1240 *
1241 * @param rh resolution we are performing
1242 * @param cname value of the cname record we got for the current
1243 * authority chain tail
1244 */
1245static void
1246handle_gns_cname_result (struct GNS_ResolverHandle *rh,
1247 const char *cname)
1248{
1249 size_t nlen;
1250 char *res;
1251 const char *tld;
1252 struct AuthorityChain *ac;
1253 int af;
1254 struct GNUNET_IDENTITY_PublicKey zone;
1255
1256 nlen = strlen (cname);
1257 tld = GNS_get_tld (cname);
1258 if (0 == strcmp ("+", tld))
1259 {
1260 /* CNAME resolution continues relative to current domain */
1261 if (0 == rh->name_resolution_pos)
1262 {
1263 res = GNUNET_strndup (cname, nlen - 2);
1264 rh->name_resolution_pos = nlen - 2;
1265 }
1266 else
1267 {
1268 GNUNET_asprintf (&res,
1269 "%.*s.%.*s",
1270 (int) rh->name_resolution_pos,
1271 rh->name,
1272 (int) (nlen - 2),
1273 cname);
1274 rh->name_resolution_pos = strlen (res);
1275 }
1276 GNUNET_free (rh->name);
1277 rh->name = res;
1278 ac = GNUNET_new (struct AuthorityChain);
1279 ac->rh = rh;
1280 ac->gns_authority = GNUNET_YES;
1281 ac->authority_info.gns_authority =
1282 rh->ac_tail->authority_info.gns_authority;
1283 ac->label = resolver_lookup_get_next_label (rh);
1284 /* add AC to tail */
1285 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1286 rh->ac_tail,
1287 ac);
1288 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1289 rh);
1290 return;
1291 }
1292 if (GNUNET_OK == GNUNET_GNSRECORD_zkey_to_pkey (tld, &zone))
1293 {
1294 /* CNAME resolution continues relative to current domain */
1295 if (0 == rh->name_resolution_pos)
1296 {
1297 GNUNET_asprintf (&res,
1298 "%.*s",
1299 (int) (strlen (cname) - (strlen (tld) + 1)),
1300 cname);
1301 }
1302 else
1303 {
1304 GNUNET_asprintf (&res,
1305 "%.*s.%.*s",
1306 (int) rh->name_resolution_pos,
1307 rh->name,
1308 (int) (strlen (cname) - (strlen (tld) + 1)),
1309 cname);
1310 }
1311 rh->name_resolution_pos = strlen (res);
1312 GNUNET_free (rh->name);
1313 rh->name = res;
1314 ac = GNUNET_new (struct AuthorityChain);
1315 ac->rh = rh;
1316 ac->gns_authority = GNUNET_YES;
1317 ac->authority_info.gns_authority = zone;
1318 ac->label = resolver_lookup_get_next_label (rh);
1319 /* add AC to tail */
1320 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1321 rh->ac_tail,
1322 ac);
1323 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1324 rh);
1325 return;
1326 }
1327
1328 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1329 "Got CNAME `%s' from GNS for `%s'\n",
1330 cname,
1331 rh->name);
1332 if (NULL != rh->std_resolve)
1333 {
1334 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1335 "Multiple CNAME results from GNS resolving `%s'! Not really allowed...\n",
1336 rh->name);
1337 GNUNET_RESOLVER_request_cancel (rh->std_resolve);
1338 }
1339 /* name is absolute, go to DNS */
1340 GNUNET_free (rh->name);
1341 rh->name = GNUNET_strdup (cname);
1342 rh->name_resolution_pos = strlen (rh->name);
1343 switch (rh->record_type)
1344 {
1345 case GNUNET_DNSPARSER_TYPE_A:
1346 af = AF_INET;
1347 break;
1348
1349 case GNUNET_DNSPARSER_TYPE_AAAA:
1350 af = AF_INET6;
1351 break;
1352
1353 default:
1354 af = AF_UNSPEC;
1355 break;
1356 }
1357 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1358 "Doing standard DNS lookup for `%s'\n",
1359 rh->name);
1360
1361 rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name,
1362 af,
1363 DNS_LOOKUP_TIMEOUT,
1364 &handle_dns_result,
1365 rh);
1366}
1367
1368
1369/**
1370 * Process a records that were decrypted from a block.
1371 *
1372 * @param cls closure with the 'struct GNS_ResolverHandle'
1373 * @param rd_count number of entries in @a rd array
1374 * @param rd array of records with data to store
1375 */
1376static void
1377handle_gns_resolution_result (void *cls,
1378 unsigned int rd_count,
1379 const struct GNUNET_GNSRECORD_Data *rd);
1380
1381
1382/**
1383 * Callback invoked from the VPN service once a redirection is
1384 * available. Provides the IP address that can now be used to
1385 * reach the requested destination. Replaces the "VPN" record
1386 * with the respective A/AAAA record and continues processing.
1387 *
1388 * @param cls closure
1389 * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error;
1390 * will match 'result_af' from the request
1391 * @param address IP address (struct in_addr or struct in_addr6, depending on 'af')
1392 * that the VPN allocated for the redirection;
1393 * traffic to this IP will now be redirected to the
1394 * specified target peer; NULL on error
1395 */
1396static void
1397vpn_allocation_cb (void *cls,
1398 int af,
1399 const void *address)
1400{
1401 struct VpnContext *vpn_ctx = cls;
1402 struct GNS_ResolverHandle *rh = vpn_ctx->rh;
1403 struct GNUNET_GNSRECORD_Data rd[vpn_ctx->rd_count];
1404 unsigned int i;
1405
1406 vpn_ctx->vpn_request = NULL;
1407 rh->vpn_ctx = NULL;
1408 GNUNET_assert (GNUNET_OK ==
1409 GNUNET_GNSRECORD_records_deserialize (
1410 (size_t) vpn_ctx->rd_data_size,
1411 vpn_ctx->rd_data,
1412 vpn_ctx->rd_count,
1413 rd));
1414 for (i = 0; i < vpn_ctx->rd_count; i++)
1415 {
1416 if (GNUNET_GNSRECORD_TYPE_VPN == rd[i].record_type)
1417 {
1418 switch (af)
1419 {
1420 case AF_INET:
1421 rd[i].record_type = GNUNET_DNSPARSER_TYPE_A;
1422 rd[i].data_size = sizeof(struct in_addr);
1423 rd[i].expiration_time = GNUNET_TIME_relative_to_absolute (
1424 VPN_TIMEOUT).abs_value_us;
1425 rd[i].flags = 0;
1426 rd[i].data = address;
1427 break;
1428
1429 case AF_INET6:
1430 rd[i].record_type = GNUNET_DNSPARSER_TYPE_AAAA;
1431 rd[i].expiration_time = GNUNET_TIME_relative_to_absolute (
1432 VPN_TIMEOUT).abs_value_us;
1433 rd[i].flags = 0;
1434 rd[i].data = address;
1435 rd[i].data_size = sizeof(struct in6_addr);
1436 break;
1437
1438 default:
1439 GNUNET_assert (0);
1440 }
1441 break;
1442 }
1443 }
1444 GNUNET_assert (i < vpn_ctx->rd_count);
1445 if (0 == vpn_ctx->rd_count)
1446 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1447 _ ("VPN returned empty result for `%s'\n"),
1448 rh->name);
1449 handle_gns_resolution_result (rh,
1450 vpn_ctx->rd_count,
1451 rd);
1452 GNUNET_free (vpn_ctx->rd_data);
1453 GNUNET_free (vpn_ctx);
1454}
1455
1456
1457/**
1458 * We have resolved one or more of the nameservers for a
1459 * GNS2DNS lookup. Once we have some of them, begin using
1460 * the DNSSTUB resolver.
1461 *
1462 * @param ac context for GNS2DNS resolution
1463 */
1464static void
1465continue_with_gns2dns (struct AuthorityChain *ac)
1466{
1467 struct GNS_ResolverHandle *rh = ac->rh;
1468
1469 if ((NULL != ac->authority_info.dns_authority.gp_head) &&
1470 (GNUNET_NO == ac->authority_info.dns_authority.found))
1471 return; /* more pending and none found yet */
1472 if (GNUNET_NO == ac->authority_info.dns_authority.found)
1473 {
1474 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1475 "Failed to resolve DNS server for `%s' in GNS2DNS resolution\n",
1476 ac->authority_info.dns_authority.name);
1477 fail_resolution (rh);
1478 return;
1479 }
1480 if (GNUNET_NO != ac->authority_info.dns_authority.launched)
1481 return; /* already running, do not launch again! */
1482 /* recurse */
1483 ac->authority_info.dns_authority.launched = GNUNET_YES;
1484 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1485 "Will continue resolution using DNS to resolve `%s'\n",
1486 ac->label);
1487 GNUNET_assert (NULL == rh->task_id);
1488 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1489 rh);
1490}
1491
1492
1493/**
1494 * We've resolved the IP address for the DNS resolver to use
1495 * after encountering a GNS2DNS record.
1496 *
1497 * @param cls the `struct Gns2DnsPending` used for this request
1498 * @param rd_count number of records in @a rd
1499 * @param rd addresses for the DNS resolver (presumably)
1500 */
1501static void
1502handle_gns2dns_result (void *cls,
1503 unsigned int rd_count,
1504 const struct GNUNET_GNSRECORD_Data *rd)
1505{
1506 struct Gns2DnsPending *gp = cls;
1507 struct AuthorityChain *ac = gp->ac;
1508
1509 GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
1510 ac->authority_info.dns_authority.gp_tail,
1511 gp);
1512 /* enable cleanup of 'rh' handle that automatically comes after we return,
1513 and which expects 'rh' to be in the #rlh_head DLL. */
1514 if (NULL != gp->rh)
1515 {
1516 GNUNET_CONTAINER_DLL_insert (rlh_head,
1517 rlh_tail,
1518 gp->rh);
1519 gp->rh = NULL;
1520 }
1521 GNUNET_free (gp);
1522 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1523 "Received %u results for IP address of DNS server for GNS2DNS transition\n",
1524 rd_count);
1525 /* find suitable A/AAAA record */
1526 for (unsigned int j = 0; j < rd_count; j++)
1527 {
1528 switch (rd[j].record_type)
1529 {
1530 case GNUNET_DNSPARSER_TYPE_A:
1531 {
1532 struct sockaddr_in v4;
1533
1534 if (sizeof(struct in_addr) != rd[j].data_size)
1535 {
1536 GNUNET_break_op (0);
1537 continue;
1538 }
1539 memset (&v4,
1540 0,
1541 sizeof(v4));
1542 v4.sin_family = AF_INET;
1543 v4.sin_port = htons (53);
1544#if HAVE_SOCKADDR_IN_SIN_LEN
1545 v4.sin_len = (u_char) sizeof(v4);
1546#endif
1547 GNUNET_memcpy (&v4.sin_addr,
1548 rd[j].data,
1549 sizeof(struct in_addr));
1550 if (GNUNET_OK ==
1551 GNUNET_DNSSTUB_add_dns_sa (
1552 ac->authority_info.dns_authority.dns_handle,
1553 (const struct sockaddr *) &v4))
1554 ac->authority_info.dns_authority.found = GNUNET_YES;
1555 break;
1556 }
1557
1558 case GNUNET_DNSPARSER_TYPE_AAAA:
1559 {
1560 struct sockaddr_in6 v6;
1561
1562 if (sizeof(struct in6_addr) != rd[j].data_size)
1563 {
1564 GNUNET_break_op (0);
1565 continue;
1566 }
1567 /* FIXME: might want to check if we support IPv6 here,
1568 and otherwise skip this one and hope we find another */
1569 memset (&v6,
1570 0,
1571 sizeof(v6));
1572 v6.sin6_family = AF_INET6;
1573 v6.sin6_port = htons (53);
1574#if HAVE_SOCKADDR_IN_SIN_LEN
1575 v6.sin6_len = (u_char) sizeof(v6);
1576#endif
1577 GNUNET_memcpy (&v6.sin6_addr,
1578 rd[j].data,
1579 sizeof(struct in6_addr));
1580 if (GNUNET_OK ==
1581 GNUNET_DNSSTUB_add_dns_sa (
1582 ac->authority_info.dns_authority.dns_handle,
1583 (const struct sockaddr *) &v6))
1584 ac->authority_info.dns_authority.found = GNUNET_YES;
1585 break;
1586 }
1587
1588 default:
1589 break;
1590 }
1591 }
1592 continue_with_gns2dns (ac);
1593}
1594
1595
1596/**
1597 * Function called by the resolver for each address obtained from DNS.
1598 *
1599 * @param cls closure, a `struct Gns2DnsPending *`
1600 * @param addr one of the addresses of the host, NULL for the last address
1601 * @param addrlen length of @a addr
1602 */
1603static void
1604handle_gns2dns_ip (void *cls,
1605 const struct sockaddr *addr,
1606 socklen_t addrlen)
1607{
1608 struct Gns2DnsPending *gp = cls;
1609 struct AuthorityChain *ac = gp->ac;
1610 struct sockaddr_storage ss;
1611 struct sockaddr_in *v4;
1612 struct sockaddr_in6 *v6;
1613
1614 if (NULL == addr)
1615 {
1616 /* DNS resolution finished */
1617 if (0 == gp->num_results)
1618 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1619 "Failed to use DNS to resolve name of DNS resolver\n");
1620 GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
1621 ac->authority_info.dns_authority.gp_tail,
1622 gp);
1623 GNUNET_free (gp);
1624 continue_with_gns2dns (ac);
1625 return;
1626 }
1627 GNUNET_memcpy (&ss,
1628 addr,
1629 addrlen);
1630 switch (ss.ss_family)
1631 {
1632 case AF_INET:
1633 v4 = (struct sockaddr_in *) &ss;
1634 v4->sin_port = htons (53);
1635 gp->num_results++;
1636 break;
1637
1638 case AF_INET6:
1639 v6 = (struct sockaddr_in6 *) &ss;
1640 v6->sin6_port = htons (53);
1641 gp->num_results++;
1642 break;
1643
1644 default:
1645 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1646 "Unsupported AF %d\n",
1647 ss.ss_family);
1648 return;
1649 }
1650 if (GNUNET_OK ==
1651 GNUNET_DNSSTUB_add_dns_sa (ac->authority_info.dns_authority.dns_handle,
1652 (struct sockaddr *) &ss))
1653 ac->authority_info.dns_authority.found = GNUNET_YES;
1654}
1655
1656
1657/**
1658 * We found a CNAME record, perform recursive resolution on it.
1659 *
1660 * @param rh resolution handle
1661 * @param rd record with CNAME to resolve recursively
1662 */
1663static void
1664recursive_cname_resolution (struct GNS_ResolverHandle *rh,
1665 const struct GNUNET_GNSRECORD_Data *rd)
1666{
1667 char *cname;
1668 size_t off;
1669
1670 off = 0;
1671 cname = GNUNET_DNSPARSER_parse_name (rd->data,
1672 rd->data_size,
1673 &off);
1674 if ((NULL == cname) ||
1675 (off != rd->data_size))
1676 {
1677 GNUNET_break_op (0); /* record not well-formed */
1678 GNUNET_free (cname);
1679 fail_resolution (rh);
1680 return;
1681 }
1682 handle_gns_cname_result (rh,
1683 cname);
1684 GNUNET_free (cname);
1685}
1686
1687
1688/**
1689 * We found a PKEY record, perform recursive resolution on it.
1690 *
1691 * @param rh resolution handle
1692 * @param rd record with PKEY to resolve recursively
1693 */
1694static void
1695recursive_pkey_resolution (struct GNS_ResolverHandle *rh,
1696 const struct GNUNET_GNSRECORD_Data *rd)
1697{
1698 struct AuthorityChain *ac;
1699 struct GNUNET_IDENTITY_PublicKey auth;
1700
1701 /* delegation to another zone */
1702 if (GNUNET_OK != GNUNET_GNSRECORD_identity_from_data (rd->data,
1703 rd->data_size,
1704 rd->record_type,
1705 &auth))
1706 {
1707 GNUNET_break_op (0);
1708 fail_resolution (rh);
1709 return;
1710 }
1711 /* expand authority chain */
1712 ac = GNUNET_new (struct AuthorityChain);
1713 ac->rh = rh;
1714 ac->gns_authority = GNUNET_YES;
1715 ac->authority_info.gns_authority = auth;
1716 ac->label = resolver_lookup_get_next_label (rh);
1717 /* add AC to tail */
1718 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1719 rh->ac_tail,
1720 ac);
1721 /* recurse */
1722 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1723 rh);
1724}
1725
1726
1727/**
1728 * We found one or more GNS2DNS records, perform recursive resolution on it.
1729 * (to be precise, one or more records in @a rd is GNS2DNS, there may be others,
1730 * so this function still needs to check which ones are GNS2DNS).
1731 *
1732 * @param rh resolution handle
1733 * @param rd_count length of the @a rd array
1734 * @param rd record with PKEY to resolve recursively
1735 * @return #GNUNET_OK if this worked, #GNUNET_SYSERR if no GNS2DNS records were in @a rd
1736 */
1737static int
1738recursive_gns2dns_resolution (struct GNS_ResolverHandle *rh,
1739 unsigned int rd_count,
1740 const struct GNUNET_GNSRECORD_Data *rd)
1741{
1742 struct AuthorityChain *ac;
1743 const char *tld;
1744 char *ns;
1745
1746 ns = NULL;
1747 /* expand authority chain */
1748 ac = GNUNET_new (struct AuthorityChain);
1749 ac->rh = rh;
1750 ac->authority_info.dns_authority.dns_handle = GNUNET_DNSSTUB_start (4);
1751
1752 for (unsigned int i = 0; i < rd_count; i++)
1753 {
1754 char *ip;
1755 char *n;
1756 size_t off;
1757 struct Gns2DnsPending *gp;
1758 struct GNUNET_IDENTITY_PublicKey zone;
1759 struct sockaddr_in v4;
1760 struct sockaddr_in6 v6;
1761
1762 if (GNUNET_GNSRECORD_TYPE_GNS2DNS != rd[i].record_type)
1763 {
1764 /**
1765 * Records other than GNS2DNS not allowed
1766 */
1767 GNUNET_free (ns);
1768 GNUNET_free (ac);
1769 return GNUNET_SYSERR;
1770 }
1771 off = 0;
1772 n = GNUNET_DNSPARSER_parse_name (rd[i].data,
1773 rd[i].data_size,
1774 &off);
1775 ip = GNUNET_strdup (&((const char *) rd[i].data)[off]);
1776 if ((NULL == n) ||
1777 (NULL == ip))
1778 {
1779 GNUNET_break_op (0);
1780 GNUNET_free (n);
1781 GNUNET_free (ip);
1782 continue;
1783 }
1784
1785 off += strlen (ip) + 1;
1786
1787 if (off != rd[i].data_size)
1788 {
1789 GNUNET_break_op (0);
1790 GNUNET_free (n);
1791 GNUNET_free (ip);
1792 continue;
1793 }
1794 /* resolve 'ip' to determine the IP(s) of the DNS
1795 resolver to use for lookup of 'ns' */
1796 if (NULL != ns)
1797 {
1798 if (0 != strcasecmp (ns,
1799 n))
1800 {
1801 /* NS values must all be the same for all GNS2DNS records,
1802 anything else leads to insanity */
1803 GNUNET_break_op (0);
1804 GNUNET_free (n);
1805 GNUNET_free (ip);
1806 continue;
1807 }
1808 GNUNET_free (n);
1809 }
1810 else
1811 {
1812 ns = n;
1813 }
1814
1815 /* check if 'ip' is already an IPv4/IPv6 address */
1816 if ((1 == inet_pton (AF_INET,
1817 ip,
1818 &v4)) ||
1819 (1 == inet_pton (AF_INET6,
1820 ip,
1821 &v6)))
1822 {
1823 GNUNET_break (GNUNET_OK ==
1824 GNUNET_DNSSTUB_add_dns_ip (
1825 ac->authority_info.dns_authority.dns_handle,
1826 ip));
1827 ac->authority_info.dns_authority.found = GNUNET_YES;
1828 GNUNET_free (ip);
1829 continue;
1830 }
1831 tld = GNS_get_tld (ip);
1832 if ((0 != strcmp (tld, "+")) &&
1833 (GNUNET_OK != GNUNET_GNSRECORD_zkey_to_pkey (tld, &zone)))
1834 {
1835 /* 'ip' is a DNS name */
1836 gp = GNUNET_new (struct Gns2DnsPending);
1837 gp->ac = ac;
1838 GNUNET_CONTAINER_DLL_insert (ac->authority_info.dns_authority.gp_head,
1839 ac->authority_info.dns_authority.gp_tail,
1840 gp);
1841 gp->dns_rh = GNUNET_RESOLVER_ip_get (ip,
1842 AF_UNSPEC,
1843 GNUNET_TIME_UNIT_FOREVER_REL,
1844 &handle_gns2dns_ip,
1845 gp);
1846 GNUNET_free (ip);
1847 continue;
1848 }
1849 /* 'ip' should be a GNS name */
1850 gp = GNUNET_new (struct Gns2DnsPending);
1851 gp->ac = ac;
1852 GNUNET_CONTAINER_DLL_insert (ac->authority_info.dns_authority.gp_head,
1853 ac->authority_info.dns_authority.gp_tail,
1854 gp);
1855 gp->rh = GNUNET_new (struct GNS_ResolverHandle);
1856 if (0 == strcmp (tld, "+"))
1857 {
1858 ip = translate_dot_plus (rh,
1859 ip);
1860 tld = GNS_get_tld (ip);
1861 if (GNUNET_OK !=
1862 GNUNET_GNSRECORD_zkey_to_pkey (tld,
1863 &zone))
1864 {
1865 GNUNET_break_op (0);
1866 GNUNET_free (ip);
1867 continue;
1868 }
1869 }
1870 gp->rh->authority_zone = zone;
1871 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1872 "Resolving `%s' to determine IP address of DNS server for GNS2DNS transition for `%s'\n",
1873 ip,
1874 ns);
1875 gp->rh->name = ip;
1876 gp->rh->name_resolution_pos = strlen (ip) - strlen (tld) - 1;
1877 gp->rh->proc = &handle_gns2dns_result;
1878 gp->rh->proc_cls = gp;
1879 gp->rh->record_type = GNUNET_GNSRECORD_TYPE_ANY;
1880 gp->rh->options = GNUNET_GNS_LO_DEFAULT;
1881 gp->rh->loop_limiter = rh->loop_limiter + 1;
1882 gp->rh->loop_threshold = rh->loop_threshold;
1883 gp->rh->task_id
1884 = GNUNET_SCHEDULER_add_now (&start_resolver_lookup,
1885 gp->rh);
1886 } /* end 'for all records' */
1887
1888 if (NULL == ns)
1889 {
1890 /* not a single GNS2DNS record found */
1891 GNUNET_free (ac);
1892 return GNUNET_SYSERR;
1893 }
1894 GNUNET_assert (strlen (ns) <= GNUNET_DNSPARSER_MAX_NAME_LENGTH);
1895 strcpy (ac->authority_info.dns_authority.name,
1896 ns);
1897 /* for DNS recursion, the label is the full DNS name,
1898 created from the remainder of the GNS name and the
1899 name in the NS record */
1900 GNUNET_asprintf (&ac->label,
1901 "%.*s%s%s",
1902 (int) rh->name_resolution_pos,
1903 rh->name,
1904 (0 != rh->name_resolution_pos) ? "." : "",
1905 ns);
1906 GNUNET_free (ns);
1907
1908 {
1909 /* the GNS name is UTF-8 and may include multibyte chars.
1910 * We have to convert the combined name to a DNS-compatible IDNA.
1911 */
1912 char *tmp = ac->label;
1913
1914 if (IDNA_SUCCESS != idna_to_ascii_8z (tmp,
1915 &ac->label,
1916 IDNA_ALLOW_UNASSIGNED))
1917 {
1918 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1919 _ ("Name `%s' cannot be converted to IDNA."),
1920 tmp);
1921 GNUNET_free (tmp);
1922 GNUNET_free (ac);
1923 return GNUNET_SYSERR;
1924 }
1925 GNUNET_free (tmp);
1926 }
1927
1928 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1929 rh->ac_tail,
1930 ac);
1931 if (strlen (ac->label) > GNUNET_DNSPARSER_MAX_NAME_LENGTH)
1932 {
1933 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1934 _ ("GNS lookup resulted in DNS name that is too long (`%s')\n"),
1935 ac->label);
1936 GNUNET_free (ac->label);
1937 GNUNET_free (ac);
1938 return GNUNET_SYSERR;
1939 }
1940 continue_with_gns2dns (ac);
1941 return GNUNET_OK;
1942}
1943
1944
1945/**
1946 * Process a records that were decrypted from a block.
1947 *
1948 * @param cls closure with the `struct GNS_ResolverHandle`
1949 * @param rd_count number of entries in @a rd array
1950 * @param rd array of records with data to store
1951 */
1952static void
1953handle_gns_resolution_result (void *cls,
1954 unsigned int rd_count,
1955 const struct GNUNET_GNSRECORD_Data *rd)
1956{
1957 struct GNS_ResolverHandle *rh = cls;
1958 char *cname;
1959 struct VpnContext *vpn_ctx;
1960 const struct GNUNET_TUN_GnsVpnRecord *vpn;
1961 const char *vname;
1962 struct GNUNET_HashCode vhash;
1963 int af;
1964 char scratch[UINT16_MAX];
1965 size_t scratch_off;
1966 size_t scratch_start;
1967 size_t off;
1968 struct GNUNET_GNSRECORD_Data rd_new[rd_count];
1969 unsigned int rd_off;
1970
1971 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1972 "Resolution succeeded for `%s' in zone %s, got %u records\n",
1973 rh->ac_tail->label,
1974 GNUNET_GNSRECORD_z2s (&rh->ac_tail->authority_info.gns_authority),
1975 rd_count);
1976 if (0 == rd_count)
1977 {
1978 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1979 _ ("GNS lookup failed (zero records found for `%s')\n"),
1980 rh->name);
1981 fail_resolution (rh);
1982 return;
1983 }
1984
1985 if (0 == rh->name_resolution_pos)
1986 {
1987 /* top-level match, are we done yet? */
1988 if ((rd_count > 0) &&
1989 (GNUNET_DNSPARSER_TYPE_CNAME == rd[0].record_type) &&
1990 (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type))
1991 {
1992 off = 0;
1993 cname = GNUNET_DNSPARSER_parse_name (rd[0].data,
1994 rd[0].data_size,
1995 &off);
1996 if ((NULL == cname) ||
1997 (off != rd[0].data_size))
1998 {
1999 GNUNET_break_op (0);
2000 GNUNET_free (cname);
2001 fail_resolution (rh);
2002 return;
2003 }
2004 handle_gns_cname_result (rh,
2005 cname);
2006 GNUNET_free (cname);
2007 return;
2008 }
2009 /* If A/AAAA was requested, but we got a VPN
2010 record, we convert it to A/AAAA using GNUnet VPN */
2011 if ((GNUNET_DNSPARSER_TYPE_A == rh->record_type) ||
2012 (GNUNET_DNSPARSER_TYPE_AAAA == rh->record_type))
2013 {
2014 for (unsigned int i = 0; i < rd_count; i++)
2015 {
2016 switch (rd[i].record_type)
2017 {
2018 case GNUNET_GNSRECORD_TYPE_VPN:
2019 {
2020 af = (GNUNET_DNSPARSER_TYPE_A == rh->record_type) ? AF_INET :
2021 AF_INET6;
2022 if (sizeof(struct GNUNET_TUN_GnsVpnRecord) >
2023 rd[i].data_size)
2024 {
2025 GNUNET_break_op (0);
2026 fail_resolution (rh);
2027 return;
2028 }
2029 vpn = (const struct GNUNET_TUN_GnsVpnRecord *) rd[i].data;
2030 vname = (const char *) &vpn[1];
2031 if ('\0' != vname[rd[i].data_size - 1 - sizeof(struct
2032 GNUNET_TUN_GnsVpnRecord)
2033 ])
2034 {
2035 GNUNET_break_op (0);
2036 fail_resolution (rh);
2037 return;
2038 }
2039 GNUNET_TUN_service_name_to_hash (vname,
2040 &vhash);
2041 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2042 "Attempting VPN allocation for %s-%s (AF: %d, proto %d)\n",
2043 GNUNET_i2s (&vpn->peer),
2044 vname,
2045 (int) af,
2046 (int) ntohs (vpn->proto));
2047 vpn_ctx = GNUNET_new (struct VpnContext);
2048 rh->vpn_ctx = vpn_ctx;
2049 vpn_ctx->rh = rh;
2050 vpn_ctx->rd_data_size = GNUNET_GNSRECORD_records_get_size (rd_count,
2051 rd);
2052 if (vpn_ctx->rd_data_size < 0)
2053 {
2054 GNUNET_break_op (0);
2055 GNUNET_free (vpn_ctx);
2056 fail_resolution (rh);
2057 return;
2058 }
2059 vpn_ctx->rd_data = GNUNET_malloc ((size_t) vpn_ctx->rd_data_size);
2060 vpn_ctx->rd_count = rd_count;
2061 GNUNET_assert (vpn_ctx->rd_data_size ==
2062 GNUNET_GNSRECORD_records_serialize (rd_count,
2063 rd,
2064 (size_t) vpn_ctx
2065 ->rd_data_size,
2066 vpn_ctx->rd_data));
2067 vpn_ctx->vpn_request = GNUNET_VPN_redirect_to_peer (vpn_handle,
2068 af,
2069 ntohs (
2070 vpn->proto),
2071 &vpn->peer,
2072 &vhash,
2073 GNUNET_TIME_relative_to_absolute (
2074 VPN_TIMEOUT),
2075 &
2076 vpn_allocation_cb,
2077 vpn_ctx);
2078 return;
2079 }
2080
2081 case GNUNET_GNSRECORD_TYPE_GNS2DNS:
2082 {
2083 /* delegation to DNS */
2084 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2085 "Found GNS2DNS record, delegating to DNS!\n");
2086 if (GNUNET_OK ==
2087 recursive_gns2dns_resolution (rh,
2088 rd_count,
2089 rd))
2090 return;
2091 else
2092 goto fail;
2093 }
2094
2095 default:
2096 break;
2097 } /* end: switch */
2098 } /* end: for rd */
2099 } /* end: name_resolution_pos */
2100 /* convert relative names in record values to absolute names,
2101 using 'scratch' array for memory allocations */
2102 scratch_off = 0;
2103 rd_off = 0;
2104 for (unsigned int i = 0; i < rd_count; i++)
2105 {
2106 GNUNET_assert (rd_off <= i);
2107 if ((0 != rh->protocol) &&
2108 (0 != rh->service) &&
2109 (GNUNET_GNSRECORD_TYPE_BOX != rd[i].record_type))
2110 continue; /* we _only_ care about boxed records */
2111
2112 GNUNET_assert (rd_off < rd_count);
2113 rd_new[rd_off] = rd[i];
2114 /* Check if the embedded name(s) end in "+", and if so,
2115 replace the "+" with the zone at "ac_tail", changing the name
2116 to a ".ZONEKEY". The name is allocated on the 'scratch' array,
2117 so we can free it afterwards. */
2118 switch (rd[i].record_type)
2119 {
2120 case GNUNET_DNSPARSER_TYPE_CNAME:
2121 {
2122 char *cname;
2123
2124 off = 0;
2125 cname = GNUNET_DNSPARSER_parse_name (rd[i].data,
2126 rd[i].data_size,
2127 &off);
2128 if ((NULL == cname) ||
2129 (off != rd[i].data_size))
2130 {
2131 GNUNET_break_op (0); /* record not well-formed */
2132 }
2133 else
2134 {
2135 cname = translate_dot_plus (rh, cname);
2136 GNUNET_break (NULL != cname);
2137 scratch_start = scratch_off;
2138 if (GNUNET_OK !=
2139 GNUNET_DNSPARSER_builder_add_name (scratch,
2140 sizeof(scratch),
2141 &scratch_off,
2142 cname))
2143 {
2144 GNUNET_break (0);
2145 }
2146 else
2147 {
2148 GNUNET_assert (rd_off < rd_count);
2149 rd_new[rd_off].data = &scratch[scratch_start];
2150 rd_new[rd_off].data_size = scratch_off - scratch_start;
2151 rd_off++;
2152 }
2153 }
2154 GNUNET_free (cname);
2155 }
2156 break;
2157
2158 case GNUNET_DNSPARSER_TYPE_SOA:
2159 {
2160 struct GNUNET_DNSPARSER_SoaRecord *soa;
2161
2162 off = 0;
2163 soa = GNUNET_DNSPARSER_parse_soa (rd[i].data,
2164 rd[i].data_size,
2165 &off);
2166 if ((NULL == soa) ||
2167 (off != rd[i].data_size))
2168 {
2169 GNUNET_break_op (0); /* record not well-formed */
2170 }
2171 else
2172 {
2173 soa->mname = translate_dot_plus (rh, soa->mname);
2174 soa->rname = translate_dot_plus (rh, soa->rname);
2175 scratch_start = scratch_off;
2176 if (GNUNET_OK !=
2177 GNUNET_DNSPARSER_builder_add_soa (scratch,
2178 sizeof(scratch),
2179 &scratch_off,
2180 soa))
2181 {
2182 GNUNET_break (0);
2183 }
2184 else
2185 {
2186 GNUNET_assert (rd_off < rd_count);
2187 rd_new[rd_off].data = &scratch[scratch_start];
2188 rd_new[rd_off].data_size = scratch_off - scratch_start;
2189 rd_off++;
2190 }
2191 }
2192 if (NULL != soa)
2193 GNUNET_DNSPARSER_free_soa (soa);
2194 }
2195 break;
2196
2197 case GNUNET_DNSPARSER_TYPE_MX:
2198 {
2199 struct GNUNET_DNSPARSER_MxRecord *mx;
2200
2201 off = 0;
2202 mx = GNUNET_DNSPARSER_parse_mx (rd[i].data,
2203 rd[i].data_size,
2204 &off);
2205 if ((NULL == mx) ||
2206 (off != rd[i].data_size))
2207 {
2208 GNUNET_break_op (0); /* record not well-formed */
2209 }
2210 else
2211 {
2212 mx->mxhost = translate_dot_plus (rh, mx->mxhost);
2213 scratch_start = scratch_off;
2214 if (GNUNET_OK !=
2215 GNUNET_DNSPARSER_builder_add_mx (scratch,
2216 sizeof(scratch),
2217 &scratch_off,
2218 mx))
2219 {
2220 GNUNET_break (0);
2221 }
2222 else
2223 {
2224 GNUNET_assert (rd_off < rd_count);
2225 rd_new[rd_off].data = &scratch[scratch_start];
2226 rd_new[rd_off].data_size = scratch_off - scratch_start;
2227 rd_off++;
2228 }
2229 }
2230 if (NULL != mx)
2231 GNUNET_DNSPARSER_free_mx (mx);
2232 }
2233 break;
2234
2235 case GNUNET_DNSPARSER_TYPE_SRV:
2236 {
2237 struct GNUNET_DNSPARSER_SrvRecord *srv;
2238
2239 off = 0;
2240 srv = GNUNET_DNSPARSER_parse_srv (rd[i].data,
2241 rd[i].data_size,
2242 &off);
2243 if ((NULL == srv) ||
2244 (off != rd[i].data_size))
2245 {
2246 GNUNET_break_op (0); /* record not well-formed */
2247 }
2248 else
2249 {
2250 srv->target = translate_dot_plus (rh, srv->target);
2251 scratch_start = scratch_off;
2252 if (GNUNET_OK !=
2253 GNUNET_DNSPARSER_builder_add_srv (scratch,
2254 sizeof(scratch),
2255 &scratch_off,
2256 srv))
2257 {
2258 GNUNET_break (0);
2259 }
2260 else
2261 {
2262 GNUNET_assert (rd_off < rd_count);
2263 rd_new[rd_off].data = &scratch[scratch_start];
2264 rd_new[rd_off].data_size = scratch_off - scratch_start;
2265 rd_off++;
2266 }
2267 }
2268 if (NULL != srv)
2269 GNUNET_DNSPARSER_free_srv (srv);
2270 }
2271 break;
2272
2273 case GNUNET_GNSRECORD_TYPE_PKEY:
2274 case GNUNET_GNSRECORD_TYPE_EDKEY:
2275 {
2276 struct GNUNET_IDENTITY_PublicKey pubkey;
2277 if (rd[i].data_size < sizeof(uint32_t))
2278 {
2279 GNUNET_break_op (0);
2280 break;
2281 }
2282 if (GNUNET_OK !=
2283 GNUNET_GNSRECORD_identity_from_data (rd[i].data,
2284 rd[i].data_size,
2285 rd[i].record_type,
2286 &pubkey))
2287 {
2288 GNUNET_break_op (0);
2289 break;
2290 }
2291 rd_off++;
2292 if (rd[i].record_type != rh->record_type)
2293 {
2294 /* try to resolve "@" */
2295 struct AuthorityChain *ac;
2296
2297 ac = GNUNET_new (struct AuthorityChain);
2298 ac->rh = rh;
2299 ac->gns_authority = GNUNET_YES;
2300 ac->authority_info.gns_authority = pubkey;
2301 ac->label = GNUNET_strdup (GNUNET_GNS_EMPTY_LABEL_AT);
2302 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
2303 rh->ac_tail,
2304 ac);
2305 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
2306 rh);
2307 return;
2308 }
2309 }
2310 break;
2311
2312 case GNUNET_GNSRECORD_TYPE_GNS2DNS:
2313 {
2314 /* delegation to DNS */
2315 if (GNUNET_GNSRECORD_TYPE_GNS2DNS == rh->record_type)
2316 {
2317 rd_off++;
2318 break; /* do not follow to DNS, we wanted the GNS2DNS record! */
2319 }
2320 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2321 "Found GNS2DNS record, delegating to DNS!\n");
2322 if (GNUNET_OK ==
2323 recursive_gns2dns_resolution (rh,
2324 rd_count,
2325 rd))
2326 return;
2327 else
2328 goto fail;
2329 }
2330
2331 case GNUNET_GNSRECORD_TYPE_BOX:
2332 {
2333 /* unbox SRV/TLSA records if a specific one was requested */
2334 if ((0 != rh->protocol) &&
2335 (0 != rh->service) &&
2336 (rd[i].data_size >= sizeof(struct GNUNET_GNSRECORD_BoxRecord)))
2337 {
2338 const struct GNUNET_GNSRECORD_BoxRecord *box;
2339
2340 box = rd[i].data;
2341 if ((ntohs (box->protocol) == rh->protocol) &&
2342 (ntohs (box->service) == rh->service))
2343 {
2344 /* Box matches, unbox! */
2345 GNUNET_assert (rd_off < rd_count);
2346 rd_new[rd_off].record_type = ntohl (box->record_type);
2347 rd_new[rd_off].data_size -= sizeof(struct
2348 GNUNET_GNSRECORD_BoxRecord);
2349 rd_new[rd_off].data = &box[1];
2350 rd_off++;
2351 }
2352 }
2353 else
2354 {
2355 /* no specific protocol/service specified, preserve all BOX
2356 records (for modern, GNS-enabled applications) */
2357 rd_off++;
2358 }
2359 break;
2360 }
2361
2362 default:
2363 rd_off++;
2364 break;
2365 } /* end: switch */
2366 } /* end: for rd_count */
2367
2368 /* yes, we are done, return result */
2369 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2370 "Returning GNS response for `%s' with %u answers\n",
2371 rh->ac_tail->label,
2372 rd_off);
2373 rh->proc (rh->proc_cls,
2374 rd_off,
2375 rd_new);
2376 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2377 rh);
2378 return;
2379 }
2380
2381 switch (rd[0].record_type)
2382 {
2383 case GNUNET_DNSPARSER_TYPE_CNAME:
2384 GNUNET_break_op (1 == rd_count); /* CNAME should be unique */
2385 recursive_cname_resolution (rh,
2386 &rd[0]);
2387 return;
2388
2389 case GNUNET_GNSRECORD_TYPE_PKEY:
2390 case GNUNET_GNSRECORD_TYPE_EDKEY:
2391 GNUNET_break_op (1 == rd_count); /* PKEY should be unique */
2392 recursive_pkey_resolution (rh,
2393 &rd[0]);
2394 return;
2395
2396 default:
2397 if (GNUNET_OK ==
2398 recursive_gns2dns_resolution (rh,
2399 rd_count,
2400 rd))
2401 return;
2402 break;
2403 }
2404fail:
2405 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2406 _ ("GNS lookup recursion failed (no delegation record found)\n"));
2407 fail_resolution (rh);
2408}
2409
2410
2411/**
2412 * Function called once the namestore has completed the request for
2413 * caching a block.
2414 *
2415 * @param cls closure with the `struct CacheOps`
2416 * @param success #GNUNET_OK on success
2417 * @param emsg error message
2418 */
2419static void
2420namecache_cache_continuation (void *cls,
2421 int32_t success,
2422 const char *emsg)
2423{
2424 struct CacheOps *co = cls;
2425
2426 co->namecache_qe_cache = NULL;
2427 if (GNUNET_OK != success)
2428 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2429 _ ("Failed to cache GNS resolution: %s\n"),
2430 emsg);
2431 GNUNET_CONTAINER_DLL_remove (co_head,
2432 co_tail,
2433 co);
2434 GNUNET_free (co);
2435}
2436
2437
2438/**
2439 * Iterator called on each result obtained for a DHT
2440 * operation that expects a reply
2441 *
2442 * @param cls closure with the `struct GNS_ResolverHandle`
2443 * @param exp when will this value expire
2444 * @param key key of the result
2445 * @param get_path peers on reply path (or NULL if not recorded)
2446 * [0] = datastore's first neighbor, [length - 1] = local peer
2447 * @param get_path_length number of entries in @a get_path
2448 * @param put_path peers on the PUT path (or NULL if not recorded)
2449 * [0] = origin, [length - 1] = datastore
2450 * @param put_path_length number of entries in @a put_path
2451 * @param type type of the result
2452 * @param size number of bytes in data
2453 * @param data pointer to the result data
2454 */
2455static void
2456handle_dht_response (void *cls,
2457 struct GNUNET_TIME_Absolute exp,
2458 const struct GNUNET_HashCode *key,
2459 const struct GNUNET_PeerIdentity *get_path,
2460 unsigned int get_path_length,
2461 const struct GNUNET_PeerIdentity *put_path,
2462 unsigned int put_path_length,
2463 enum GNUNET_BLOCK_Type type,
2464 size_t size,
2465 const void *data)
2466{
2467 struct GNS_ResolverHandle *rh = cls;
2468 struct AuthorityChain *ac = rh->ac_tail;
2469 const struct GNUNET_GNSRECORD_Block *block;
2470 struct CacheOps *co;
2471
2472 (void) exp;
2473 (void) key;
2474 (void) get_path;
2475 (void) get_path_length;
2476 (void) put_path;
2477 (void) put_path_length;
2478 (void) type;
2479 GNUNET_DHT_get_stop (rh->get_handle);
2480 rh->get_handle = NULL;
2481 GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
2482 rh->dht_heap_node = NULL;
2483 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2484 "Handling response from the DHT\n");
2485 if (size < sizeof(struct GNUNET_GNSRECORD_Block))
2486 {
2487 /* how did this pass DHT block validation!? */
2488 GNUNET_break (0);
2489 fail_resolution (rh);
2490 return;
2491 }
2492 block = data;
2493 if (size != GNUNET_GNSRECORD_block_get_size (block))
2494 {
2495 /* how did this pass DHT block validation!? */
2496 GNUNET_break (0);
2497 fail_resolution (rh);
2498 return;
2499 }
2500 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2501 "Decrypting DHT block of size %lu for `%s', expires %s\n",
2502 GNUNET_GNSRECORD_block_get_size (block),
2503 rh->name,
2504 GNUNET_STRINGS_absolute_time_to_string (exp));
2505 if (GNUNET_OK !=
2506 GNUNET_GNSRECORD_block_decrypt (block,
2507 &ac->authority_info.gns_authority,
2508 ac->label,
2509 &handle_gns_resolution_result,
2510 rh))
2511 {
2512 GNUNET_break_op (0); /* block was ill-formed */
2513 fail_resolution (rh);
2514 return;
2515 }
2516 if (0 == GNUNET_TIME_absolute_get_remaining (
2517 GNUNET_GNSRECORD_block_get_expiration (block)).
2518 rel_value_us)
2519 {
2520 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2521 "Received expired block from the DHT, will not cache it.\n");
2522 return;
2523 }
2524 if (GNUNET_YES == disable_cache)
2525 return;
2526 /* Cache well-formed blocks */
2527 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2528 "Caching response from the DHT in namecache\n");
2529 co = GNUNET_new (struct CacheOps);
2530 co->namecache_qe_cache = GNUNET_NAMECACHE_block_cache (namecache_handle,
2531 block,
2532 &
2533 namecache_cache_continuation,
2534 co);
2535 GNUNET_CONTAINER_DLL_insert (co_head,
2536 co_tail,
2537 co);
2538}
2539
2540
2541/**
2542 * Initiate a DHT query for a set of GNS records.
2543 *
2544 * @param rh resolution handle
2545 * @param query key to use in the DHT lookup
2546 */
2547static void
2548start_dht_request (struct GNS_ResolverHandle *rh,
2549 const struct GNUNET_HashCode *query)
2550{
2551 struct GNS_ResolverHandle *rx;
2552
2553 GNUNET_assert (NULL == rh->get_handle);
2554 rh->get_handle = GNUNET_DHT_get_start (dht_handle,
2555 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
2556 query,
2557 DHT_GNS_REPLICATION_LEVEL,
2558 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
2559 NULL, 0,
2560 &handle_dht_response, rh);
2561 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
2562 rh,
2563 GNUNET_TIME_absolute_get ().
2564 abs_value_us);
2565 if (GNUNET_CONTAINER_heap_get_size (dht_lookup_heap) >
2566 max_allowed_background_queries)
2567 {
2568 /* fail longest-standing DHT request */
2569 rx = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
2570 rx->dht_heap_node = NULL;
2571 GNUNET_assert (NULL != rx);
2572 fail_resolution (rx);
2573 }
2574}
2575
2576
2577/**
2578 * Process a records that were decrypted from a block that we got from
2579 * the namecache. Simply calls #handle_gns_resolution_result().
2580 *
2581 * @param cls closure with the `struct GNS_ResolverHandle`
2582 * @param rd_count number of entries in @a rd array
2583 * @param rd array of records with data to store
2584 */
2585static void
2586handle_gns_namecache_resolution_result (void *cls,
2587 unsigned int rd_count,
2588 const struct GNUNET_GNSRECORD_Data *rd)
2589{
2590 struct GNS_ResolverHandle *rh = cls;
2591
2592 if (0 == rd_count)
2593 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2594 _ ("GNS namecache returned empty result for `%s'\n"),
2595 rh->name);
2596 handle_gns_resolution_result (rh,
2597 rd_count,
2598 rd);
2599}
2600
2601
2602/**
2603 * Process a record that was stored in the namecache.
2604 *
2605 * @param cls closure with the `struct GNS_ResolverHandle`
2606 * @param block block that was stored in the namecache
2607 */
2608static void
2609handle_namecache_block_response (void *cls,
2610 const struct GNUNET_GNSRECORD_Block *block)
2611{
2612 struct GNS_ResolverHandle *rh = cls;
2613 struct AuthorityChain *ac = rh->ac_tail;
2614 const char *label = ac->label;
2615 const struct GNUNET_IDENTITY_PublicKey *auth =
2616 &ac->authority_info.gns_authority;
2617 struct GNUNET_HashCode query;
2618
2619 GNUNET_assert (NULL != rh->namecache_qe);
2620 rh->namecache_qe = NULL;
2621 if (((GNUNET_GNS_LO_DEFAULT == rh->options) ||
2622 ((GNUNET_GNS_LO_LOCAL_MASTER == rh->options) &&
2623 (ac != rh->ac_head))) &&
2624 ((NULL == block) ||
2625 (0 == GNUNET_TIME_absolute_get_remaining (
2626 GNUNET_GNSRECORD_block_get_expiration (block)).
2627 rel_value_us)))
2628 {
2629 /* namecache knows nothing; try DHT lookup */
2630 GNUNET_GNSRECORD_query_from_public_key (auth,
2631 label,
2632 &query);
2633 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2634 "Starting DHT lookup for `%s' in zone `%s' under key `%s'\n",
2635 ac->label,
2636 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority),
2637 GNUNET_h2s (&query));
2638 start_dht_request (rh, &query);
2639 return;
2640 }
2641
2642 if ((NULL == block) ||
2643 (0 == GNUNET_TIME_absolute_get_remaining (
2644 GNUNET_GNSRECORD_block_get_expiration (block)).
2645 rel_value_us))
2646 {
2647 /* DHT not permitted and no local result, fail */
2648 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2649 "Resolution failed for `%s' in zone %s (DHT lookup not permitted by configuration)\n",
2650 ac->label,
2651 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2652 fail_resolution (rh);
2653 return;
2654 }
2655 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2656 "Received result from namecache for label `%s'\n",
2657 ac->label);
2658
2659 if (GNUNET_OK !=
2660 GNUNET_GNSRECORD_block_decrypt (block,
2661 auth,
2662 label,
2663 &handle_gns_namecache_resolution_result,
2664 rh))
2665 {
2666 GNUNET_break_op (0); /* block was ill-formed */
2667 /* try DHT instead */
2668 GNUNET_GNSRECORD_query_from_public_key (auth,
2669 label,
2670 &query);
2671 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2672 "Starting DHT lookup for `%s' in zone `%s' under key `%s'\n",
2673 ac->label,
2674 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority),
2675 GNUNET_h2s (&query));
2676 start_dht_request (rh, &query);
2677 return;
2678 }
2679}
2680
2681
2682/**
2683 * Lookup tail of our authority chain in the namecache.
2684 *
2685 * @param rh query we are processing
2686 */
2687static void
2688recursive_gns_resolution_namecache (struct GNS_ResolverHandle *rh)
2689{
2690 struct AuthorityChain *ac = rh->ac_tail;
2691 struct GNUNET_HashCode query;
2692
2693 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2694 "Starting GNS resolution for `%s' in zone %s\n",
2695 ac->label,
2696 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2697 GNUNET_GNSRECORD_query_from_public_key (&ac->authority_info.gns_authority,
2698 ac->label,
2699 &query);
2700 if (GNUNET_YES != disable_cache)
2701 {
2702 rh->namecache_qe
2703 = GNUNET_NAMECACHE_lookup_block (namecache_handle,
2704 &query,
2705 &handle_namecache_block_response,
2706 rh);
2707 GNUNET_assert (NULL != rh->namecache_qe);
2708 }
2709 else
2710 {
2711 start_dht_request (rh,
2712 &query);
2713 }
2714}
2715
2716
2717/**
2718 * Function called with the result from a revocation check.
2719 *
2720 * @param cls the `struct GNS_ResovlerHandle`
2721 * @param is_valid #GNUNET_YES if the zone was not yet revoked
2722 */
2723static void
2724handle_revocation_result (void *cls,
2725 int is_valid)
2726{
2727 struct GNS_ResolverHandle *rh = cls;
2728 struct AuthorityChain *ac = rh->ac_tail;
2729
2730 rh->rev_check = NULL;
2731 if (GNUNET_YES != is_valid)
2732 {
2733 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2734 _ ("Zone %s was revoked, resolution fails\n"),
2735 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2736 fail_resolution (rh);
2737 return;
2738 }
2739 recursive_gns_resolution_namecache (rh);
2740}
2741
2742
2743/**
2744 * Perform revocation check on tail of our authority chain.
2745 *
2746 * @param rh query we are processing
2747 */
2748static void
2749recursive_gns_resolution_revocation (struct GNS_ResolverHandle *rh)
2750{
2751 struct AuthorityChain *ac = rh->ac_tail;
2752
2753 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2754 "Starting revocation check for zone %s\n",
2755 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2756 rh->rev_check = GNUNET_REVOCATION_query (cfg,
2757 &ac->authority_info.gns_authority,
2758 &handle_revocation_result,
2759 rh);
2760 GNUNET_assert (NULL != rh->rev_check);
2761}
2762
2763
2764/**
2765 * Task scheduled to continue with the resolution process.
2766 *
2767 * @param cls the `struct GNS_ResolverHandle` of the resolution
2768 */
2769static void
2770recursive_resolution (void *cls)
2771{
2772 struct GNS_ResolverHandle *rh = cls;
2773
2774 rh->task_id = NULL;
2775 if (rh->loop_threshold < rh->loop_limiter++)
2776 {
2777 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2778 "Encountered unbounded recursion resolving `%s'\n",
2779 rh->name);
2780 fail_resolution (rh);
2781 return;
2782 }
2783 if (GNUNET_YES == rh->ac_tail->gns_authority)
2784 recursive_gns_resolution_revocation (rh);
2785 else
2786 recursive_dns_resolution (rh);
2787}
2788
2789
2790/**
2791 * Begin the resolution process from 'name', starting with
2792 * the identification of the zone specified by 'name'.
2793 *
2794 * @param cls the `struct GNS_ResolverHandle`
2795 */
2796static void
2797start_resolver_lookup (void *cls)
2798{
2799 struct GNS_ResolverHandle *rh = cls;
2800 struct AuthorityChain *ac;
2801 struct in_addr v4;
2802 struct in6_addr v6;
2803
2804 rh->task_id = NULL;
2805 if (1 == inet_pton (AF_INET,
2806 rh->name,
2807 &v4))
2808 {
2809 /* name is IPv4 address, pretend it's an A record */
2810 struct GNUNET_GNSRECORD_Data rd;
2811
2812 rd.data = &v4;
2813 rd.data_size = sizeof(v4);
2814 rd.expiration_time = UINT64_MAX;
2815 rd.record_type = GNUNET_DNSPARSER_TYPE_A;
2816 rd.flags = 0;
2817 rh->proc (rh->proc_cls,
2818 1,
2819 &rd);
2820 GNUNET_assert (NULL == rh->task_id);
2821 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2822 rh);
2823 return;
2824 }
2825 if (1 == inet_pton (AF_INET6,
2826 rh->name,
2827 &v6))
2828 {
2829 /* name is IPv6 address, pretend it's an AAAA record */
2830 struct GNUNET_GNSRECORD_Data rd;
2831
2832 rd.data = &v6;
2833 rd.data_size = sizeof(v6);
2834 rd.expiration_time = UINT64_MAX;
2835 rd.record_type = GNUNET_DNSPARSER_TYPE_AAAA;
2836 rd.flags = 0;
2837 rh->proc (rh->proc_cls,
2838 1,
2839 &rd);
2840 GNUNET_assert (NULL == rh->task_id);
2841 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2842 rh);
2843 return;
2844 }
2845
2846 ac = GNUNET_new (struct AuthorityChain);
2847 ac->rh = rh;
2848 ac->label = resolver_lookup_get_next_label (rh);
2849 if (NULL == ac->label)
2850 /* name was just the "TLD", so we default to label
2851 #GNUNET_GNS_EMPTY_LABEL_AT */
2852 ac->label = GNUNET_strdup (GNUNET_GNS_EMPTY_LABEL_AT);
2853 ac->gns_authority = GNUNET_YES;
2854 ac->authority_info.gns_authority = rh->authority_zone;
2855 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
2856 rh->ac_tail,
2857 ac);
2858 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
2859 rh);
2860}
2861
2862
2863/**
2864 * Lookup of a record in a specific zone calls lookup result processor
2865 * on result.
2866 *
2867 * @param zone the zone to perform the lookup in
2868 * @param record_type the record type to look up
2869 * @param name the name to look up
2870 * @param options local options to control local lookup
2871 * @param recursion_depth_limit how many zones to traverse
2872 * at most
2873 * @param proc the processor to call on result
2874 * @param proc_cls the closure to pass to @a proc
2875 * @return handle to cancel operation
2876 */
2877struct GNS_ResolverHandle *
2878GNS_resolver_lookup (const struct GNUNET_IDENTITY_PublicKey *zone,
2879 uint32_t record_type,
2880 const char *name,
2881 enum GNUNET_GNS_LocalOptions options,
2882 uint16_t recursion_depth_limit,
2883 GNS_ResultProcessor proc,
2884 void *proc_cls)
2885{
2886 struct GNS_ResolverHandle *rh;
2887
2888 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2889 "Starting lookup for `%s'\n",
2890 name);
2891 rh = GNUNET_new (struct GNS_ResolverHandle);
2892 GNUNET_CONTAINER_DLL_insert (rlh_head,
2893 rlh_tail,
2894 rh);
2895 rh->authority_zone = *zone;
2896 rh->proc = proc;
2897 rh->proc_cls = proc_cls;
2898 rh->options = options;
2899 rh->record_type = record_type;
2900 rh->name = GNUNET_strdup (name);
2901 rh->name_resolution_pos = strlen (name);
2902 rh->loop_threshold = recursion_depth_limit;
2903 rh->task_id = GNUNET_SCHEDULER_add_now (&start_resolver_lookup,
2904 rh);
2905 return rh;
2906}
2907
2908
2909/**
2910 * Cancel active resolution (i.e. client disconnected).
2911 *
2912 * @param rh resolution to abort
2913 */
2914void
2915GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
2916{
2917 struct DnsResult *dr;
2918 struct AuthorityChain *ac;
2919 struct VpnContext *vpn_ctx;
2920
2921 GNUNET_CONTAINER_DLL_remove (rlh_head,
2922 rlh_tail,
2923 rh);
2924 if (NULL != rh->dns_request)
2925 {
2926 GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
2927 rh->dns_request = NULL;
2928 }
2929 while (NULL != (ac = rh->ac_head))
2930 {
2931 GNUNET_CONTAINER_DLL_remove (rh->ac_head,
2932 rh->ac_tail,
2933 ac);
2934 if (GNUNET_NO == ac->gns_authority)
2935 {
2936 struct Gns2DnsPending *gp;
2937
2938 while (NULL != (gp = ac->authority_info.dns_authority.gp_head))
2939 {
2940 GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
2941 ac->authority_info.dns_authority.gp_tail,
2942 gp);
2943 if (NULL != gp->rh)
2944 {
2945 /* rh->g2dc->rh is NOT in the DLL yet, so to enable us
2946 using GNS_resolver_lookup_cancel here, we need to
2947 add it first... */
2948 GNUNET_CONTAINER_DLL_insert (rlh_head,
2949 rlh_tail,
2950 gp->rh);
2951 GNUNET_assert (NULL == gp->rh->task_id);
2952 gp->rh->task_id = GNUNET_SCHEDULER_add_now (
2953 &GNS_resolver_lookup_cancel_,
2954 gp->rh);
2955 gp->rh = NULL;
2956 }
2957 if (NULL != gp->dns_rh)
2958 {
2959 GNUNET_RESOLVER_request_cancel (gp->dns_rh);
2960 gp->dns_rh = NULL;
2961 }
2962 GNUNET_free (gp);
2963 }
2964 GNUNET_DNSSTUB_stop (ac->authority_info.dns_authority.dns_handle);
2965 }
2966 GNUNET_free (ac->label);
2967 GNUNET_free (ac);
2968 }
2969 if (NULL != rh->task_id)
2970 {
2971 GNUNET_SCHEDULER_cancel (rh->task_id);
2972 rh->task_id = NULL;
2973 }
2974 if (NULL != rh->get_handle)
2975 {
2976 GNUNET_DHT_get_stop (rh->get_handle);
2977 rh->get_handle = NULL;
2978 }
2979 if (NULL != rh->dht_heap_node)
2980 {
2981 GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
2982 rh->dht_heap_node = NULL;
2983 }
2984 if (NULL != (vpn_ctx = rh->vpn_ctx))
2985 {
2986 GNUNET_VPN_cancel_request (vpn_ctx->vpn_request);
2987 GNUNET_free (vpn_ctx->rd_data);
2988 GNUNET_free (vpn_ctx);
2989 }
2990 if (NULL != rh->namecache_qe)
2991 {
2992 GNUNET_NAMECACHE_cancel (rh->namecache_qe);
2993 rh->namecache_qe = NULL;
2994 }
2995 if (NULL != rh->rev_check)
2996 {
2997 GNUNET_REVOCATION_query_cancel (rh->rev_check);
2998 rh->rev_check = NULL;
2999 }
3000 if (NULL != rh->std_resolve)
3001 {
3002 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3003 "Canceling standard DNS resolution\n");
3004 GNUNET_RESOLVER_request_cancel (rh->std_resolve);
3005 rh->std_resolve = NULL;
3006 }
3007 while (NULL != (dr = rh->dns_result_head))
3008 {
3009 GNUNET_CONTAINER_DLL_remove (rh->dns_result_head,
3010 rh->dns_result_tail,
3011 dr);
3012 GNUNET_free (dr);
3013 }
3014 GNUNET_free (rh->leho);
3015 GNUNET_free (rh->name);
3016 GNUNET_free (rh);
3017}
3018
3019
3020/* ***************** Resolver initialization ********************* */
3021
3022
3023/**
3024 * Initialize the resolver
3025 *
3026 * @param nc the namecache handle
3027 * @param dht the dht handle
3028 * @param c configuration handle
3029 * @param max_bg_queries maximum number of parallel background queries in dht
3030 */
3031void
3032GNS_resolver_init (struct GNUNET_NAMECACHE_Handle *nc,
3033 struct GNUNET_DHT_Handle *dht,
3034 const struct GNUNET_CONFIGURATION_Handle *c,
3035 unsigned long long max_bg_queries)
3036{
3037 cfg = c;
3038 namecache_handle = nc;
3039 dht_handle = dht;
3040 dht_lookup_heap =
3041 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3042 max_allowed_background_queries = max_bg_queries;
3043 disable_cache = GNUNET_CONFIGURATION_get_value_yesno (cfg,
3044 "namecache",
3045 "DISABLE");
3046 if (GNUNET_YES == disable_cache)
3047 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3048 "Namecache disabled\n");
3049 vpn_handle = GNUNET_VPN_connect (cfg);
3050}
3051
3052
3053/**
3054 * Shutdown resolver
3055 */
3056void
3057GNS_resolver_done ()
3058{
3059 struct GNS_ResolverHandle *rh;
3060 struct CacheOps *co;
3061
3062 /* abort active resolutions */
3063 while (NULL != (rh = rlh_head))
3064 {
3065 rh->proc (rh->proc_cls,
3066 0,
3067 NULL);
3068 GNS_resolver_lookup_cancel (rh);
3069 }
3070 while (NULL != (co = co_head))
3071 {
3072 GNUNET_CONTAINER_DLL_remove (co_head,
3073 co_tail,
3074 co);
3075 GNUNET_NAMECACHE_cancel (co->namecache_qe_cache);
3076 GNUNET_free (co);
3077 }
3078 GNUNET_CONTAINER_heap_destroy (dht_lookup_heap);
3079 dht_lookup_heap = NULL;
3080 GNUNET_VPN_disconnect (vpn_handle);
3081 vpn_handle = NULL;
3082 dht_handle = NULL;
3083 namecache_handle = NULL;
3084}
3085
3086
3087/* end of gnunet-service-gns_resolver.c */