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