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.c2995
1 files changed, 0 insertions, 2995 deletions
diff --git a/src/gns/gnunet-service-gns_resolver.c b/src/gns/gnunet-service-gns_resolver.c
deleted file mode 100644
index 45d971c85..000000000
--- a/src/gns/gnunet-service-gns_resolver.c
+++ /dev/null
@@ -1,2995 +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 */
853static void
854recursive_resolution (void *cls);
855
856
857/**
858 * Begin the resolution process from 'name', starting with
859 * the identification of the zone specified by 'name'.
860 *
861 * @param cls closure with `struct GNS_ResolverHandle *rh`
862 */
863static void
864start_resolver_lookup (void *cls);
865
866
867/**
868 * Function called with the result of a DNS resolution.
869 *
870 * @param cls the request handle of the resolution that
871 * we were attempting to make
872 * @param dns dns response, never NULL
873 * @param dns_len number of bytes in @a dns
874 */
875static void
876dns_result_parser (void *cls,
877 const struct GNUNET_TUN_DnsHeader *dns,
878 size_t dns_len)
879{
880 struct GNS_ResolverHandle *rh = cls;
881 struct GNUNET_DNSPARSER_Packet *p;
882 const struct GNUNET_DNSPARSER_Record *rec;
883 unsigned int rd_count;
884
885 if (NULL == dns)
886 {
887 rh->dns_request = NULL;
888 GNUNET_SCHEDULER_cancel (rh->task_id);
889 rh->task_id = NULL;
890 fail_resolution (rh);
891 return;
892 }
893 if (rh->original_dns_id != dns->id)
894 {
895 /* DNS answer, but for another query */
896 return;
897 }
898 p = GNUNET_DNSPARSER_parse ((const char *) dns,
899 dns_len);
900 if (NULL == p)
901 {
902 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
903 _ ("Failed to parse DNS response\n"));
904 return;
905 }
906
907 /* We got a result from DNS */
908 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
909 "Received DNS response for `%s' with %u answers\n",
910 rh->ac_tail->label,
911 (unsigned int) p->num_answers);
912 if ((p->num_answers > 0) &&
913 (GNUNET_DNSPARSER_TYPE_CNAME == p->answers[0].type) &&
914 (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type))
915 {
916 int af;
917
918 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
919 "Got CNAME `%s' from DNS for `%s'\n",
920 p->answers[0].data.hostname,
921 rh->name);
922 if (NULL != rh->std_resolve)
923 {
924 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
925 "Multiple CNAME results from DNS resolving `%s'! Not really allowed...\n",
926 rh->name);
927 GNUNET_RESOLVER_request_cancel (rh->std_resolve);
928 }
929 GNUNET_free (rh->name);
930 rh->name = GNUNET_strdup (p->answers[0].data.hostname);
931 rh->name_resolution_pos = strlen (rh->name);
932 switch (rh->record_type)
933 {
934 case GNUNET_DNSPARSER_TYPE_A:
935 af = AF_INET;
936 break;
937
938 case GNUNET_DNSPARSER_TYPE_AAAA:
939 af = AF_INET6;
940 break;
941
942 default:
943 af = AF_UNSPEC;
944 break;
945 }
946 if (NULL != rh->leho)
947 add_dns_result (rh,
948 GNUNET_TIME_UNIT_HOURS.rel_value_us,
949 GNUNET_GNSRECORD_TYPE_LEHO,
950 strlen (rh->leho),
951 rh->leho);
952 rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name,
953 af,
954 DNS_LOOKUP_TIMEOUT,
955 &handle_dns_result,
956 rh);
957 GNUNET_DNSPARSER_free_packet (p);
958 GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
959 rh->dns_request = NULL;
960 return;
961 }
962
963 /* convert from (parsed) DNS to (binary) GNS format! */
964 rd_count = p->num_answers + p->num_authority_records
965 + p->num_additional_records;
966 {
967 struct GNUNET_GNSRECORD_Data rd[rd_count + 1]; /* +1 for LEHO */
968 int skip;
969 char buf[UINT16_MAX];
970 size_t buf_off;
971 size_t buf_start;
972
973 buf_off = 0;
974 skip = 0;
975 memset (rd,
976 0,
977 sizeof(rd));
978 for (unsigned int i = 0; i < rd_count; i++)
979 {
980 if (i < p->num_answers)
981 rec = &p->answers[i];
982 else if (i < p->num_answers + p->num_authority_records)
983 rec = &p->authority_records[i - p->num_answers];
984 else
985 rec = &p->additional_records[i - p->num_answers
986 - p->num_authority_records];
987 /* As we copied the full DNS name to 'rh->ac_tail->label', this
988 should be the correct check to see if this record is actually
989 a record for our label... */
990 if (0 != strcmp (rec->name,
991 rh->ac_tail->label))
992 {
993 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
994 "Dropping record `%s', does not match desired name `%s'\n",
995 rec->name,
996 rh->ac_tail->label);
997 skip++;
998 continue;
999 }
1000 rd[i - skip].record_type = rec->type;
1001 rd[i - skip].expiration_time = rec->expiration_time.abs_value_us;
1002 switch (rec->type)
1003 {
1004 case GNUNET_DNSPARSER_TYPE_A:
1005 if (rec->data.raw.data_len != sizeof(struct in_addr))
1006 {
1007 GNUNET_break_op (0);
1008 skip++;
1009 continue;
1010 }
1011 rd[i - skip].data_size = rec->data.raw.data_len;
1012 rd[i - skip].data = rec->data.raw.data;
1013 break;
1014
1015 case GNUNET_DNSPARSER_TYPE_AAAA:
1016 if (rec->data.raw.data_len != sizeof(struct in6_addr))
1017 {
1018 GNUNET_break_op (0);
1019 skip++;
1020 continue;
1021 }
1022 rd[i - skip].data_size = rec->data.raw.data_len;
1023 rd[i - skip].data = rec->data.raw.data;
1024 break;
1025
1026 case GNUNET_DNSPARSER_TYPE_CNAME:
1027 case GNUNET_DNSPARSER_TYPE_PTR:
1028 case GNUNET_DNSPARSER_TYPE_NS:
1029 buf_start = buf_off;
1030 if (GNUNET_OK !=
1031 GNUNET_DNSPARSER_builder_add_name (buf,
1032 sizeof(buf),
1033 &buf_off,
1034 rec->data.hostname))
1035 {
1036 GNUNET_break (0);
1037 skip++;
1038 continue;
1039 }
1040 rd[i - skip].data_size = buf_off - buf_start;
1041 rd[i - skip].data = &buf[buf_start];
1042 break;
1043
1044 case GNUNET_DNSPARSER_TYPE_SOA:
1045 buf_start = buf_off;
1046 if (GNUNET_OK !=
1047 GNUNET_DNSPARSER_builder_add_soa (buf,
1048 sizeof(buf),
1049 &buf_off,
1050 rec->data.soa))
1051 {
1052 GNUNET_break (0);
1053 skip++;
1054 continue;
1055 }
1056 rd[i - skip].data_size = buf_off - buf_start;
1057 rd[i - skip].data = &buf[buf_start];
1058 break;
1059
1060 case GNUNET_DNSPARSER_TYPE_MX:
1061 buf_start = buf_off;
1062 if (GNUNET_OK !=
1063 GNUNET_DNSPARSER_builder_add_mx (buf,
1064 sizeof(buf),
1065 &buf_off,
1066 rec->data.mx))
1067 {
1068 GNUNET_break (0);
1069 skip++;
1070 continue;
1071 }
1072 rd[i - skip].data_size = buf_off - buf_start;
1073 rd[i - skip].data = &buf[buf_start];
1074 break;
1075
1076 case GNUNET_DNSPARSER_TYPE_SRV:
1077 buf_start = buf_off;
1078 if (GNUNET_OK !=
1079 GNUNET_DNSPARSER_builder_add_srv (buf,
1080 sizeof(buf),
1081 &buf_off,
1082 rec->data.srv))
1083 {
1084 GNUNET_break (0);
1085 skip++;
1086 continue;
1087 }
1088 rd[i - skip].data_size = buf_off - buf_start;
1089 rd[i - skip].data = &buf[buf_start];
1090 break;
1091
1092 default:
1093 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1094 _ ("Skipping record of unsupported type %d\n"),
1095 rec->type);
1096 skip++;
1097 continue;
1098 }
1099 } /* end of for all records in answer */
1100 if (NULL != rh->leho)
1101 {
1102 rd[rd_count - skip].record_type = GNUNET_GNSRECORD_TYPE_LEHO;
1103 rd[rd_count - skip].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1104 rd[rd_count - skip].flags |= GNUNET_GNSRECORD_RF_SUPPLEMENTAL;
1105 rd[rd_count - skip].expiration_time = GNUNET_TIME_UNIT_HOURS.rel_value_us;
1106 rd[rd_count - skip].data = rh->leho;
1107 rd[rd_count - skip].data_size = strlen (rh->leho);
1108 skip--; /* skip one LESS */
1109 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1110 "Adding LEHO %s\n",
1111 rh->leho);
1112 }
1113 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1114 "Returning DNS response for `%s' with %u answers\n",
1115 rh->ac_tail->label,
1116 (unsigned int) (rd_count - skip));
1117 rh->proc (rh->proc_cls,
1118 rd_count - skip,
1119 rd);
1120 GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
1121 rh->dns_request = NULL;
1122 }
1123 GNUNET_DNSPARSER_free_packet (p);
1124 if (NULL != rh->task_id)
1125 GNUNET_SCHEDULER_cancel (rh->task_id); /* should be timeout task */
1126 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
1127 rh);
1128}
1129
1130
1131/**
1132 * Perform recursive DNS resolution. Asks the given DNS resolver to
1133 * resolve "rh->dns_name", possibly recursively proceeding following
1134 * NS delegations, CNAMES, etc., until 'rh->loop_limiter' bounds us or
1135 * we find the answer.
1136 *
1137 * @param rh resolution information
1138 */
1139static void
1140recursive_dns_resolution (struct GNS_ResolverHandle *rh)
1141{
1142 struct AuthorityChain *ac;
1143 struct GNUNET_DNSPARSER_Query *query;
1144 struct GNUNET_DNSPARSER_Packet *p;
1145 char *dns_request;
1146 size_t dns_request_length;
1147 int ret;
1148
1149 ac = rh->ac_tail;
1150 GNUNET_assert (NULL != ac);
1151 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1152 "Starting DNS lookup for `%s'\n",
1153 ac->label);
1154 GNUNET_assert (GNUNET_NO == ac->gns_authority);
1155 query = GNUNET_new (struct GNUNET_DNSPARSER_Query);
1156 query->name = GNUNET_strdup (ac->label);
1157 query->type = rh->record_type;
1158 query->dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
1159 p = GNUNET_new (struct GNUNET_DNSPARSER_Packet);
1160 p->queries = query;
1161 p->num_queries = 1;
1162 p->id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1163 UINT16_MAX);
1164 p->flags.opcode = GNUNET_TUN_DNS_OPCODE_QUERY;
1165 p->flags.recursion_desired = 1;
1166 ret = GNUNET_DNSPARSER_pack (p,
1167 1024,
1168 &dns_request,
1169 &dns_request_length);
1170 if (GNUNET_OK != ret)
1171 {
1172 GNUNET_break (0);
1173 rh->proc (rh->proc_cls,
1174 0,
1175 NULL);
1176 GNUNET_assert (NULL == rh->task_id);
1177 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
1178 rh);
1179 }
1180 else
1181 {
1182 rh->original_dns_id = p->id;
1183 GNUNET_assert (NULL != ac->authority_info.dns_authority.dns_handle);
1184 GNUNET_assert (NULL == rh->dns_request);
1185 rh->leho = GNUNET_strdup (ac->label);
1186 rh->dns_request = GNUNET_DNSSTUB_resolve (
1187 ac->authority_info.dns_authority.dns_handle,
1188 dns_request,
1189 dns_request_length,
1190 &dns_result_parser,
1191 rh);
1192 rh->task_id = GNUNET_SCHEDULER_add_delayed (DNS_LOOKUP_TIMEOUT,
1193 &timeout_resolution,
1194 rh);
1195 }
1196 if (GNUNET_SYSERR != ret)
1197 GNUNET_free (dns_request);
1198 GNUNET_DNSPARSER_free_packet (p);
1199}
1200
1201
1202/**
1203 * We encountered a REDIRECT record during our resolution.
1204 * Merge it into our chain.
1205 *
1206 * @param rh resolution we are performing
1207 * @param rname value of the redirect record we got for the current
1208 * authority chain tail
1209 */
1210static void
1211handle_gns_redirect_result (struct GNS_ResolverHandle *rh,
1212 const char *rname)
1213{
1214 size_t nlen;
1215 char *res;
1216 const char *tld;
1217 struct AuthorityChain *ac;
1218 int af;
1219 struct GNUNET_IDENTITY_PublicKey zone;
1220
1221 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1222 "Handling GNS REDIRECT result `%s'\n",
1223 rname);
1224 nlen = strlen (rname);
1225 tld = GNS_get_tld (rname);
1226 if (0 == strcmp ("+", tld))
1227 {
1228 /* REDIRECT resolution continues relative to current domain */
1229 if (0 == rh->name_resolution_pos)
1230 {
1231 res = GNUNET_strndup (rname, nlen - 2);
1232 rh->name_resolution_pos = nlen - 2;
1233 }
1234 else
1235 {
1236 GNUNET_asprintf (&res,
1237 "%.*s.%.*s",
1238 (int) rh->name_resolution_pos,
1239 rh->name,
1240 (int) (nlen - 2),
1241 rname);
1242 rh->name_resolution_pos = strlen (res);
1243 }
1244 GNUNET_free (rh->name);
1245 rh->name = res;
1246 ac = GNUNET_new (struct AuthorityChain);
1247 ac->rh = rh;
1248 ac->gns_authority = GNUNET_YES;
1249 ac->authority_info.gns_authority =
1250 rh->ac_tail->authority_info.gns_authority;
1251 ac->label = resolver_lookup_get_next_label (rh);
1252 /* add AC to tail */
1253 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1254 rh->ac_tail,
1255 ac);
1256 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1257 rh);
1258 return;
1259 }
1260 if (GNUNET_OK == GNUNET_GNSRECORD_zkey_to_pkey (tld, &zone))
1261 {
1262 /* REDIRECT resolution continues relative to current domain */
1263 if (0 == rh->name_resolution_pos)
1264 {
1265 GNUNET_asprintf (&res,
1266 "%.*s",
1267 (int) (strlen (rname) - (strlen (tld) + 1)),
1268 rname);
1269 }
1270 else
1271 {
1272 GNUNET_asprintf (&res,
1273 "%.*s.%.*s",
1274 (int) rh->name_resolution_pos,
1275 rh->name,
1276 (int) (strlen (rname) - (strlen (tld) + 1)),
1277 rname);
1278 }
1279 rh->name_resolution_pos = strlen (res);
1280 GNUNET_free (rh->name);
1281 rh->name = res;
1282 ac = GNUNET_new (struct AuthorityChain);
1283 ac->rh = rh;
1284 ac->gns_authority = GNUNET_YES;
1285 ac->authority_info.gns_authority = zone;
1286 ac->label = resolver_lookup_get_next_label (rh);
1287 /* add AC to tail */
1288 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1289 rh->ac_tail,
1290 ac);
1291 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1292 rh);
1293 return;
1294 }
1295
1296 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1297 "Got REDIRECT `%s' from GNS for `%s'\n",
1298 rname,
1299 rh->name);
1300 if (NULL != rh->std_resolve)
1301 {
1302 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1303 "Multiple REDIRECT results from GNS resolving `%s'! Not really allowed...\n",
1304 rh->name);
1305 GNUNET_RESOLVER_request_cancel (rh->std_resolve);
1306 }
1307 /* name is absolute, go to DNS */
1308 GNUNET_free (rh->name);
1309 rh->name = GNUNET_strdup (rname);
1310 rh->name_resolution_pos = strlen (rh->name);
1311 switch (rh->record_type)
1312 {
1313 case GNUNET_DNSPARSER_TYPE_A:
1314 af = AF_INET;
1315 break;
1316
1317 case GNUNET_DNSPARSER_TYPE_AAAA:
1318 af = AF_INET6;
1319 break;
1320
1321 default:
1322 af = AF_UNSPEC;
1323 break;
1324 }
1325 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1326 "Doing standard DNS lookup for `%s'\n",
1327 rh->name);
1328
1329 rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name,
1330 af,
1331 DNS_LOOKUP_TIMEOUT,
1332 &handle_dns_result,
1333 rh);
1334}
1335
1336
1337/**
1338 * We encountered a CNAME record during our resolution.
1339 * Merge it into our chain.
1340 *
1341 * @param rh resolution we are performing
1342 * @param cname value of the cname record we got for the current
1343 * authority chain tail
1344 */
1345static void
1346handle_gns_cname_result (struct GNS_ResolverHandle *rh,
1347 const char *cname)
1348{
1349 int af;
1350
1351 GNUNET_free (rh->name);
1352 rh->name = GNUNET_strdup (cname);
1353 rh->name_resolution_pos = strlen (rh->name);
1354 switch (rh->record_type)
1355 {
1356 case GNUNET_DNSPARSER_TYPE_A:
1357 af = AF_INET;
1358 break;
1359
1360 case GNUNET_DNSPARSER_TYPE_AAAA:
1361 af = AF_INET6;
1362 break;
1363
1364 default:
1365 af = AF_UNSPEC;
1366 break;
1367 }
1368 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1369 "Doing standard DNS lookup for `%s'\n",
1370 rh->name);
1371
1372 rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name,
1373 af,
1374 DNS_LOOKUP_TIMEOUT,
1375 &handle_dns_result,
1376 rh);
1377}
1378
1379
1380/**
1381 * Process records that were decrypted from a block.
1382 *
1383 * @param cls closure with the 'struct GNS_ResolverHandle'
1384 * @param rd_count number of entries in @a rd array
1385 * @param rd array of records with data to store
1386 */
1387static void
1388handle_gns_resolution_result (void *cls,
1389 unsigned int rd_count,
1390 const struct GNUNET_GNSRECORD_Data *rd);
1391
1392
1393/**
1394 * We have resolved one or more of the nameservers for a
1395 * GNS2DNS lookup. Once we have some of them, begin using
1396 * the DNSSTUB resolver.
1397 *
1398 * @param ac context for GNS2DNS resolution
1399 */
1400static void
1401continue_with_gns2dns (struct AuthorityChain *ac)
1402{
1403 struct GNS_ResolverHandle *rh = ac->rh;
1404
1405 if ((NULL != ac->authority_info.dns_authority.gp_head) &&
1406 (GNUNET_NO == ac->authority_info.dns_authority.found))
1407 return; /* more pending and none found yet */
1408 if (GNUNET_NO == ac->authority_info.dns_authority.found)
1409 {
1410 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1411 "Failed to resolve DNS server for `%s' in GNS2DNS resolution\n",
1412 ac->authority_info.dns_authority.name);
1413 fail_resolution (rh);
1414 return;
1415 }
1416 if (GNUNET_NO != ac->authority_info.dns_authority.launched)
1417 return; /* already running, do not launch again! */
1418 /* recurse */
1419 ac->authority_info.dns_authority.launched = GNUNET_YES;
1420 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1421 "Will continue resolution using DNS to resolve `%s'\n",
1422 ac->label);
1423 GNUNET_assert (NULL == rh->task_id);
1424 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1425 rh);
1426}
1427
1428
1429/**
1430 * We've resolved the IP address for the DNS resolver to use
1431 * after encountering a GNS2DNS record.
1432 *
1433 * @param cls the `struct Gns2DnsPending` used for this request
1434 * @param rd_count number of records in @a rd
1435 * @param rd addresses for the DNS resolver (presumably)
1436 */
1437static void
1438handle_gns2dns_result (void *cls,
1439 unsigned int rd_count,
1440 const struct GNUNET_GNSRECORD_Data *rd)
1441{
1442 struct Gns2DnsPending *gp = cls;
1443 struct AuthorityChain *ac = gp->ac;
1444
1445 GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
1446 ac->authority_info.dns_authority.gp_tail,
1447 gp);
1448 /* enable cleanup of 'rh' handle that automatically comes after we return,
1449 and which expects 'rh' to be in the #rlh_head DLL. */
1450 if (NULL != gp->rh)
1451 {
1452 GNUNET_CONTAINER_DLL_insert (rlh_head,
1453 rlh_tail,
1454 gp->rh);
1455 gp->rh = NULL;
1456 }
1457 GNUNET_free (gp);
1458 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1459 "Received %u results for IP address of DNS server for GNS2DNS transition\n",
1460 rd_count);
1461 /* find suitable A/AAAA record */
1462 for (unsigned int j = 0; j < rd_count; j++)
1463 {
1464 switch (rd[j].record_type)
1465 {
1466 case GNUNET_DNSPARSER_TYPE_A:
1467 {
1468 struct sockaddr_in v4;
1469
1470 if (sizeof(struct in_addr) != rd[j].data_size)
1471 {
1472 GNUNET_break_op (0);
1473 continue;
1474 }
1475 memset (&v4,
1476 0,
1477 sizeof(v4));
1478 v4.sin_family = AF_INET;
1479 v4.sin_port = htons (53);
1480#if HAVE_SOCKADDR_IN_SIN_LEN
1481 v4.sin_len = (u_char) sizeof(v4);
1482#endif
1483 GNUNET_memcpy (&v4.sin_addr,
1484 rd[j].data,
1485 sizeof(struct in_addr));
1486 if (GNUNET_OK ==
1487 GNUNET_DNSSTUB_add_dns_sa (
1488 ac->authority_info.dns_authority.dns_handle,
1489 (const struct sockaddr *) &v4))
1490 ac->authority_info.dns_authority.found = GNUNET_YES;
1491 break;
1492 }
1493
1494 case GNUNET_DNSPARSER_TYPE_AAAA:
1495 {
1496 struct sockaddr_in6 v6;
1497
1498 if (sizeof(struct in6_addr) != rd[j].data_size)
1499 {
1500 GNUNET_break_op (0);
1501 continue;
1502 }
1503 /* FIXME: might want to check if we support IPv6 here,
1504 and otherwise skip this one and hope we find another */
1505 memset (&v6,
1506 0,
1507 sizeof(v6));
1508 v6.sin6_family = AF_INET6;
1509 v6.sin6_port = htons (53);
1510#if HAVE_SOCKADDR_IN_SIN_LEN
1511 v6.sin6_len = (u_char) sizeof(v6);
1512#endif
1513 GNUNET_memcpy (&v6.sin6_addr,
1514 rd[j].data,
1515 sizeof(struct in6_addr));
1516 if (GNUNET_OK ==
1517 GNUNET_DNSSTUB_add_dns_sa (
1518 ac->authority_info.dns_authority.dns_handle,
1519 (const struct sockaddr *) &v6))
1520 ac->authority_info.dns_authority.found = GNUNET_YES;
1521 break;
1522 }
1523
1524 default:
1525 break;
1526 }
1527 }
1528 continue_with_gns2dns (ac);
1529}
1530
1531
1532/**
1533 * Function called by the resolver for each address obtained from DNS.
1534 *
1535 * @param cls closure, a `struct Gns2DnsPending *`
1536 * @param addr one of the addresses of the host, NULL for the last address
1537 * @param addrlen length of @a addr
1538 */
1539static void
1540handle_gns2dns_ip (void *cls,
1541 const struct sockaddr *addr,
1542 socklen_t addrlen)
1543{
1544 struct Gns2DnsPending *gp = cls;
1545 struct AuthorityChain *ac = gp->ac;
1546 struct sockaddr_storage ss;
1547 struct sockaddr_in *v4;
1548 struct sockaddr_in6 *v6;
1549
1550 if (NULL == addr)
1551 {
1552 /* DNS resolution finished */
1553 if (0 == gp->num_results)
1554 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1555 "Failed to use DNS to resolve name of DNS resolver\n");
1556 GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
1557 ac->authority_info.dns_authority.gp_tail,
1558 gp);
1559 GNUNET_free (gp);
1560 continue_with_gns2dns (ac);
1561 return;
1562 }
1563 GNUNET_memcpy (&ss,
1564 addr,
1565 addrlen);
1566 switch (ss.ss_family)
1567 {
1568 case AF_INET:
1569 v4 = (struct sockaddr_in *) &ss;
1570 v4->sin_port = htons (53);
1571 gp->num_results++;
1572 break;
1573
1574 case AF_INET6:
1575 v6 = (struct sockaddr_in6 *) &ss;
1576 v6->sin6_port = htons (53);
1577 gp->num_results++;
1578 break;
1579
1580 default:
1581 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1582 "Unsupported AF %d\n",
1583 ss.ss_family);
1584 return;
1585 }
1586 if (GNUNET_OK ==
1587 GNUNET_DNSSTUB_add_dns_sa (ac->authority_info.dns_authority.dns_handle,
1588 (struct sockaddr *) &ss))
1589 ac->authority_info.dns_authority.found = GNUNET_YES;
1590}
1591
1592
1593/**
1594 * We found a REDIRECT record, perform recursive resolution on it.
1595 *
1596 * @param rh resolution handle
1597 * @param rd record with CNAME to resolve recursively
1598 */
1599static void
1600recursive_redirect_resolution (struct GNS_ResolverHandle *rh,
1601 const struct GNUNET_GNSRECORD_Data *rd)
1602{
1603 handle_gns_redirect_result (rh,
1604 rd->data);
1605}
1606
1607
1608/**
1609 * We found a CNAME record, perform recursive resolution on it.
1610 *
1611 * @param rh resolution handle
1612 * @param rd record with CNAME to resolve recursively
1613 */
1614static void
1615recursive_cname_resolution (struct GNS_ResolverHandle *rh,
1616 const struct GNUNET_GNSRECORD_Data *rd)
1617{
1618 char *cname;
1619 size_t off;
1620
1621 off = 0;
1622 cname = GNUNET_DNSPARSER_parse_name (rd->data,
1623 rd->data_size,
1624 &off);
1625 if ((NULL == cname) ||
1626 (off != rd->data_size))
1627 {
1628 GNUNET_break_op (0); /* record not well-formed */
1629 GNUNET_free (cname);
1630 fail_resolution (rh);
1631 return;
1632 }
1633 handle_gns_cname_result (rh,
1634 cname);
1635 GNUNET_free (cname);
1636}
1637
1638
1639/**
1640 * We found a PKEY record, perform recursive resolution on it.
1641 *
1642 * @param rh resolution handle
1643 * @param rd record with PKEY to resolve recursively
1644 */
1645static void
1646recursive_pkey_resolution (struct GNS_ResolverHandle *rh,
1647 const struct GNUNET_GNSRECORD_Data *rd)
1648{
1649 struct AuthorityChain *ac;
1650 struct GNUNET_IDENTITY_PublicKey auth;
1651
1652 /* delegation to another zone */
1653 if (GNUNET_OK != GNUNET_GNSRECORD_identity_from_data (rd->data,
1654 rd->data_size,
1655 rd->record_type,
1656 &auth))
1657 {
1658 GNUNET_break_op (0);
1659 fail_resolution (rh);
1660 return;
1661 }
1662 /* expand authority chain */
1663 ac = GNUNET_new (struct AuthorityChain);
1664 ac->rh = rh;
1665 ac->gns_authority = GNUNET_YES;
1666 ac->authority_info.gns_authority = auth;
1667 ac->label = resolver_lookup_get_next_label (rh);
1668 /* add AC to tail */
1669 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1670 rh->ac_tail,
1671 ac);
1672 /* recurse */
1673 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1674 rh);
1675}
1676
1677
1678/**
1679 * We found one or more GNS2DNS records, perform recursive resolution on it.
1680 * (to be precise, one or more records in @a rd is GNS2DNS, there may be others,
1681 * so this function still needs to check which ones are GNS2DNS).
1682 *
1683 * @param rh resolution handle
1684 * @param rd_count length of the @a rd array
1685 * @param rd record with PKEY to resolve recursively
1686 * @return #GNUNET_OK if this worked, #GNUNET_SYSERR if no GNS2DNS records were in @a rd
1687 */
1688static int
1689recursive_gns2dns_resolution (struct GNS_ResolverHandle *rh,
1690 unsigned int rd_count,
1691 const struct GNUNET_GNSRECORD_Data *rd)
1692{
1693 struct AuthorityChain *ac;
1694 const char *tld;
1695 char *ns;
1696
1697 ns = NULL;
1698 /* expand authority chain */
1699 ac = GNUNET_new (struct AuthorityChain);
1700 ac->rh = rh;
1701 ac->authority_info.dns_authority.dns_handle = GNUNET_DNSSTUB_start (4);
1702
1703 for (unsigned int i = 0; i < rd_count; i++)
1704 {
1705 char *ip;
1706 char *n;
1707 size_t off;
1708 struct Gns2DnsPending *gp;
1709 struct GNUNET_IDENTITY_PublicKey zone;
1710 struct sockaddr_in v4;
1711 struct sockaddr_in6 v6;
1712
1713 if (GNUNET_GNSRECORD_TYPE_GNS2DNS != rd[i].record_type)
1714 {
1715 /**
1716 * Records other than GNS2DNS not allowed
1717 */
1718 GNUNET_free (ns);
1719 GNUNET_free (ac);
1720 return GNUNET_SYSERR;
1721 }
1722 off = 0;
1723 n = GNUNET_DNSPARSER_parse_name (rd[i].data,
1724 rd[i].data_size,
1725 &off);
1726 ip = GNUNET_strdup (&((const char *) rd[i].data)[off]);
1727 if ((NULL == n) ||
1728 (NULL == ip))
1729 {
1730 GNUNET_break_op (0);
1731 GNUNET_free (n);
1732 GNUNET_free (ip);
1733 continue;
1734 }
1735
1736 off += strlen (ip) + 1;
1737
1738 if (off != rd[i].data_size)
1739 {
1740 GNUNET_break_op (0);
1741 GNUNET_free (n);
1742 GNUNET_free (ip);
1743 continue;
1744 }
1745 /* resolve 'ip' to determine the IP(s) of the DNS
1746 resolver to use for lookup of 'ns' */
1747 if (NULL != ns)
1748 {
1749 if (0 != strcasecmp (ns,
1750 n))
1751 {
1752 /* NS values must all be the same for all GNS2DNS records,
1753 anything else leads to insanity */
1754 GNUNET_break_op (0);
1755 GNUNET_free (n);
1756 GNUNET_free (ip);
1757 continue;
1758 }
1759 GNUNET_free (n);
1760 }
1761 else
1762 {
1763 ns = n;
1764 }
1765
1766 /* check if 'ip' is already an IPv4/IPv6 address */
1767 if ((1 == inet_pton (AF_INET,
1768 ip,
1769 &v4)) ||
1770 (1 == inet_pton (AF_INET6,
1771 ip,
1772 &v6)))
1773 {
1774 GNUNET_break (GNUNET_OK ==
1775 GNUNET_DNSSTUB_add_dns_ip (
1776 ac->authority_info.dns_authority.dns_handle,
1777 ip));
1778 ac->authority_info.dns_authority.found = GNUNET_YES;
1779 GNUNET_free (ip);
1780 continue;
1781 }
1782 tld = GNS_get_tld (ip);
1783 if ((0 != strcmp (tld, "+")) &&
1784 (GNUNET_OK != GNUNET_GNSRECORD_zkey_to_pkey (tld, &zone)))
1785 {
1786 /* 'ip' is a DNS name */
1787 gp = GNUNET_new (struct Gns2DnsPending);
1788 gp->ac = ac;
1789 GNUNET_CONTAINER_DLL_insert (ac->authority_info.dns_authority.gp_head,
1790 ac->authority_info.dns_authority.gp_tail,
1791 gp);
1792 gp->dns_rh = GNUNET_RESOLVER_ip_get (ip,
1793 AF_UNSPEC,
1794 GNUNET_TIME_UNIT_FOREVER_REL,
1795 &handle_gns2dns_ip,
1796 gp);
1797 GNUNET_free (ip);
1798 continue;
1799 }
1800 /* 'ip' should be a GNS name */
1801 gp = GNUNET_new (struct Gns2DnsPending);
1802 gp->ac = ac;
1803 GNUNET_CONTAINER_DLL_insert (ac->authority_info.dns_authority.gp_head,
1804 ac->authority_info.dns_authority.gp_tail,
1805 gp);
1806 gp->rh = GNUNET_new (struct GNS_ResolverHandle);
1807 if (0 == strcmp (tld, "+"))
1808 {
1809 ip = translate_dot_plus (rh,
1810 ip);
1811 tld = GNS_get_tld (ip);
1812 if (GNUNET_OK !=
1813 GNUNET_GNSRECORD_zkey_to_pkey (tld,
1814 &zone))
1815 {
1816 GNUNET_break_op (0);
1817 GNUNET_free (ip);
1818 continue;
1819 }
1820 }
1821 gp->rh->authority_zone = zone;
1822 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1823 "Resolving `%s' to determine IP address of DNS server for GNS2DNS transition for `%s'\n",
1824 ip,
1825 ns);
1826 gp->rh->name = ip;
1827 gp->rh->name_resolution_pos = strlen (ip) - strlen (tld) - 1;
1828 gp->rh->proc = &handle_gns2dns_result;
1829 gp->rh->proc_cls = gp;
1830 gp->rh->record_type = GNUNET_GNSRECORD_TYPE_ANY;
1831 gp->rh->options = GNUNET_GNS_LO_DEFAULT;
1832 gp->rh->loop_limiter = rh->loop_limiter + 1;
1833 gp->rh->loop_threshold = rh->loop_threshold;
1834 gp->rh->task_id
1835 = GNUNET_SCHEDULER_add_now (&start_resolver_lookup,
1836 gp->rh);
1837 } /* end 'for all records' */
1838
1839 if (NULL == ns)
1840 {
1841 /* not a single GNS2DNS record found */
1842 GNUNET_free (ac);
1843 return GNUNET_SYSERR;
1844 }
1845 GNUNET_assert (strlen (ns) <= GNUNET_DNSPARSER_MAX_NAME_LENGTH);
1846 strcpy (ac->authority_info.dns_authority.name,
1847 ns);
1848 /* for DNS recursion, the label is the full DNS name,
1849 created from the remainder of the GNS name and the
1850 name in the NS record */
1851 GNUNET_asprintf (&ac->label,
1852 "%.*s%s%s",
1853 (int) rh->name_resolution_pos,
1854 rh->name,
1855 (0 != rh->name_resolution_pos) ? "." : "",
1856 ns);
1857 GNUNET_free (ns);
1858
1859 {
1860 /* the GNS name is UTF-8 and may include multibyte chars.
1861 * We have to convert the combined name to a DNS-compatible IDNA.
1862 */
1863 char *tmp = ac->label;
1864
1865 if (IDNA_SUCCESS != idna_to_ascii_8z (tmp,
1866 &ac->label,
1867 IDNA_ALLOW_UNASSIGNED))
1868 {
1869 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1870 _ ("Name `%s' cannot be converted to IDNA."),
1871 tmp);
1872 GNUNET_free (tmp);
1873 GNUNET_free (ac);
1874 return GNUNET_SYSERR;
1875 }
1876 GNUNET_free (tmp);
1877 }
1878
1879 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1880 rh->ac_tail,
1881 ac);
1882 if (strlen (ac->label) > GNUNET_DNSPARSER_MAX_NAME_LENGTH)
1883 {
1884 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1885 _ ("GNS lookup resulted in DNS name that is too long (`%s')\n"),
1886 ac->label);
1887 GNUNET_free (ac->label);
1888 GNUNET_free (ac);
1889 return GNUNET_SYSERR;
1890 }
1891 continue_with_gns2dns (ac);
1892 return GNUNET_OK;
1893}
1894
1895
1896static void
1897handle_gns_resolution_result (void *cls,
1898 unsigned int rd_count,
1899 const struct GNUNET_GNSRECORD_Data *rd)
1900{
1901 struct GNS_ResolverHandle *rh = cls;
1902 char *cname;
1903 char scratch[UINT16_MAX];
1904 size_t scratch_off;
1905 size_t scratch_start;
1906 size_t off;
1907 struct GNUNET_GNSRECORD_Data rd_new[rd_count];
1908 unsigned int rd_off;
1909
1910 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1911 "Resolution succeeded for `%s' in zone %s, got %u records\n",
1912 rh->ac_tail->label,
1913 GNUNET_GNSRECORD_z2s (&rh->ac_tail->authority_info.gns_authority),
1914 rd_count);
1915 if (0 == rd_count)
1916 {
1917 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1918 _ ("GNS lookup failed (zero records found for `%s')\n"),
1919 rh->name);
1920 fail_resolution (rh);
1921 return;
1922 }
1923
1924 if (0 == rh->name_resolution_pos)
1925 {
1926 /* top-level match, are we done yet? */
1927 if ((rd_count > 0) &&
1928 (GNUNET_DNSPARSER_TYPE_CNAME == rd[0].record_type) &&
1929 (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type))
1930 {
1931 off = 0;
1932 cname = GNUNET_DNSPARSER_parse_name (rd[0].data,
1933 rd[0].data_size,
1934 &off);
1935 if ((NULL == cname) ||
1936 (off != rd[0].data_size))
1937 {
1938 GNUNET_break_op (0);
1939 GNUNET_free (cname);
1940 fail_resolution (rh);
1941 return;
1942 }
1943 handle_gns_cname_result (rh,
1944 cname);
1945 GNUNET_free (cname);
1946 return;
1947 }
1948 if ((rd_count > 0) &&
1949 (GNUNET_GNSRECORD_TYPE_REDIRECT == rd[0].record_type) &&
1950 (GNUNET_GNSRECORD_TYPE_REDIRECT != rh->record_type))
1951 {
1952 handle_gns_redirect_result (rh,
1953 rd[0].data);
1954 return;
1955 }
1956
1957
1958 /* If A/AAAA was requested,
1959 * but we got a GNS2DNS record */
1960 if ((GNUNET_DNSPARSER_TYPE_A == rh->record_type) ||
1961 (GNUNET_DNSPARSER_TYPE_AAAA == rh->record_type))
1962 {
1963 for (unsigned int i = 0; i < rd_count; i++)
1964 {
1965 switch (rd[i].record_type)
1966 {
1967 case GNUNET_GNSRECORD_TYPE_GNS2DNS:
1968 {
1969 /* delegation to DNS */
1970 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1971 "Found GNS2DNS record, delegating to DNS!\n");
1972 if (GNUNET_OK ==
1973 recursive_gns2dns_resolution (rh,
1974 rd_count,
1975 rd))
1976 return;
1977 else
1978 goto fail;
1979 }
1980
1981 default:
1982 break;
1983 } /* end: switch */
1984 } /* end: for rd */
1985 } /* end: name_resolution_pos */
1986 /* convert relative names in record values to absolute names,
1987 using 'scratch' array for memory allocations */
1988 scratch_off = 0;
1989 rd_off = 0;
1990 for (unsigned int i = 0; i < rd_count; i++)
1991 {
1992 GNUNET_assert (rd_off <= i);
1993 if ((0 != rh->protocol) &&
1994 (0 != rh->service) &&
1995 (GNUNET_GNSRECORD_TYPE_BOX != rd[i].record_type))
1996 continue; /* we _only_ care about boxed records */
1997
1998 GNUNET_assert (rd_off < rd_count);
1999 rd_new[rd_off] = rd[i];
2000 /* Check if the embedded name(s) end in "+", and if so,
2001 replace the "+" with the zone at "ac_tail", changing the name
2002 to a ".ZONEKEY". The name is allocated on the 'scratch' array,
2003 so we can free it afterwards. */
2004 switch (rd[i].record_type)
2005 {
2006 case GNUNET_GNSRECORD_TYPE_REDIRECT:
2007 {
2008 char *rname;
2009 rname = GNUNET_strndup (rd[i].data, rd[i].data_size);
2010 rname = translate_dot_plus (rh, rname);
2011 GNUNET_break (NULL != rname);
2012 scratch_start = scratch_off;
2013 memcpy (&scratch[scratch_start], rname, strlen (rname) + 1);
2014 scratch_off += strlen (rname) + 1;
2015 GNUNET_assert (rd_off < rd_count);
2016 rd_new[rd_off].data = &scratch[scratch_start];
2017 rd_new[rd_off].data_size = scratch_off - scratch_start;
2018 rd_off++;
2019 GNUNET_free (rname);
2020 }
2021 break;
2022
2023 case GNUNET_DNSPARSER_TYPE_CNAME:
2024 {
2025 char *cname;
2026
2027 off = 0;
2028 cname = GNUNET_DNSPARSER_parse_name (rd[i].data,
2029 rd[i].data_size,
2030 &off);
2031 if ((NULL == cname) ||
2032 (off != rd[i].data_size))
2033 {
2034 GNUNET_break_op (0); /* record not well-formed */
2035 }
2036 else
2037 {
2038 cname = translate_dot_plus (rh, cname);
2039 GNUNET_break (NULL != cname);
2040 scratch_start = scratch_off;
2041 if (GNUNET_OK !=
2042 GNUNET_DNSPARSER_builder_add_name (scratch,
2043 sizeof(scratch),
2044 &scratch_off,
2045 cname))
2046 {
2047 GNUNET_break (0);
2048 }
2049 else
2050 {
2051 GNUNET_assert (rd_off < rd_count);
2052 rd_new[rd_off].data = &scratch[scratch_start];
2053 rd_new[rd_off].data_size = scratch_off - scratch_start;
2054 rd_off++;
2055 }
2056 }
2057 GNUNET_free (cname);
2058 }
2059 break;
2060
2061 case GNUNET_DNSPARSER_TYPE_SOA:
2062 {
2063 struct GNUNET_DNSPARSER_SoaRecord *soa;
2064
2065 off = 0;
2066 soa = GNUNET_DNSPARSER_parse_soa (rd[i].data,
2067 rd[i].data_size,
2068 &off);
2069 if ((NULL == soa) ||
2070 (off != rd[i].data_size))
2071 {
2072 GNUNET_break_op (0); /* record not well-formed */
2073 }
2074 else
2075 {
2076 soa->mname = translate_dot_plus (rh, soa->mname);
2077 soa->rname = translate_dot_plus (rh, soa->rname);
2078 scratch_start = scratch_off;
2079 if (GNUNET_OK !=
2080 GNUNET_DNSPARSER_builder_add_soa (scratch,
2081 sizeof(scratch),
2082 &scratch_off,
2083 soa))
2084 {
2085 GNUNET_break (0);
2086 }
2087 else
2088 {
2089 GNUNET_assert (rd_off < rd_count);
2090 rd_new[rd_off].data = &scratch[scratch_start];
2091 rd_new[rd_off].data_size = scratch_off - scratch_start;
2092 rd_off++;
2093 }
2094 }
2095 if (NULL != soa)
2096 GNUNET_DNSPARSER_free_soa (soa);
2097 }
2098 break;
2099
2100 case GNUNET_DNSPARSER_TYPE_MX:
2101 {
2102 struct GNUNET_DNSPARSER_MxRecord *mx;
2103
2104 off = 0;
2105 mx = GNUNET_DNSPARSER_parse_mx (rd[i].data,
2106 rd[i].data_size,
2107 &off);
2108 if ((NULL == mx) ||
2109 (off != rd[i].data_size))
2110 {
2111 GNUNET_break_op (0); /* record not well-formed */
2112 }
2113 else
2114 {
2115 mx->mxhost = translate_dot_plus (rh, mx->mxhost);
2116 scratch_start = scratch_off;
2117 if (GNUNET_OK !=
2118 GNUNET_DNSPARSER_builder_add_mx (scratch,
2119 sizeof(scratch),
2120 &scratch_off,
2121 mx))
2122 {
2123 GNUNET_break (0);
2124 }
2125 else
2126 {
2127 GNUNET_assert (rd_off < rd_count);
2128 rd_new[rd_off].data = &scratch[scratch_start];
2129 rd_new[rd_off].data_size = scratch_off - scratch_start;
2130 rd_off++;
2131 }
2132 }
2133 if (NULL != mx)
2134 GNUNET_DNSPARSER_free_mx (mx);
2135 }
2136 break;
2137
2138 case GNUNET_DNSPARSER_TYPE_SRV:
2139 {
2140 struct GNUNET_DNSPARSER_SrvRecord *srv;
2141
2142 off = 0;
2143 srv = GNUNET_DNSPARSER_parse_srv (rd[i].data,
2144 rd[i].data_size,
2145 &off);
2146 if ((NULL == srv) ||
2147 (off != rd[i].data_size))
2148 {
2149 GNUNET_break_op (0); /* record not well-formed */
2150 }
2151 else
2152 {
2153 srv->target = translate_dot_plus (rh, srv->target);
2154 scratch_start = scratch_off;
2155 if (GNUNET_OK !=
2156 GNUNET_DNSPARSER_builder_add_srv (scratch,
2157 sizeof(scratch),
2158 &scratch_off,
2159 srv))
2160 {
2161 GNUNET_break (0);
2162 }
2163 else
2164 {
2165 GNUNET_assert (rd_off < rd_count);
2166 rd_new[rd_off].data = &scratch[scratch_start];
2167 rd_new[rd_off].data_size = scratch_off - scratch_start;
2168 rd_off++;
2169 }
2170 }
2171 if (NULL != srv)
2172 GNUNET_DNSPARSER_free_srv (srv);
2173 }
2174 break;
2175
2176 case GNUNET_GNSRECORD_TYPE_PKEY:
2177 case GNUNET_GNSRECORD_TYPE_EDKEY:
2178 {
2179 struct GNUNET_IDENTITY_PublicKey pubkey;
2180 if (rd[i].data_size < sizeof(uint32_t))
2181 {
2182 GNUNET_break_op (0);
2183 break;
2184 }
2185 if (GNUNET_OK !=
2186 GNUNET_GNSRECORD_identity_from_data (rd[i].data,
2187 rd[i].data_size,
2188 rd[i].record_type,
2189 &pubkey))
2190 {
2191 GNUNET_break_op (0);
2192 break;
2193 }
2194 rd_off++;
2195 if (rd[i].record_type != rh->record_type)
2196 {
2197 /* try to resolve "@" */
2198 struct AuthorityChain *ac;
2199
2200 ac = GNUNET_new (struct AuthorityChain);
2201 ac->rh = rh;
2202 ac->gns_authority = GNUNET_YES;
2203 ac->authority_info.gns_authority = pubkey;
2204 ac->label = GNUNET_strdup (GNUNET_GNS_EMPTY_LABEL_AT);
2205 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
2206 rh->ac_tail,
2207 ac);
2208 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
2209 rh);
2210 return;
2211 }
2212 }
2213 break;
2214
2215 case GNUNET_GNSRECORD_TYPE_GNS2DNS:
2216 {
2217 /* delegation to DNS */
2218 if (GNUNET_GNSRECORD_TYPE_GNS2DNS == rh->record_type)
2219 {
2220 rd_off++;
2221 break; /* do not follow to DNS, we wanted the GNS2DNS record! */
2222 }
2223 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2224 "Found GNS2DNS record, delegating to DNS!\n");
2225 if (GNUNET_OK ==
2226 recursive_gns2dns_resolution (rh,
2227 rd_count,
2228 rd))
2229 return;
2230 else
2231 goto fail;
2232 }
2233
2234 case GNUNET_GNSRECORD_TYPE_BOX:
2235 {
2236 /* unbox SRV/TLSA records if a specific one was requested */
2237 if ((0 != rh->protocol) &&
2238 (0 != rh->service) &&
2239 (rd[i].data_size >= sizeof(struct GNUNET_GNSRECORD_BoxRecord)))
2240 {
2241 const struct GNUNET_GNSRECORD_BoxRecord *box;
2242
2243 box = rd[i].data;
2244 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2245 "Got BOX record, checking if parameters match... %u/%u vs %u/%u\n",
2246 ntohs (box->protocol), ntohs (box->service),
2247 rh->protocol, rh->service);
2248 if ((ntohs (box->protocol) == rh->protocol) &&
2249 (ntohs (box->service) == rh->service))
2250 {
2251 /* Box matches, unbox! */
2252 GNUNET_assert (rd_off < rd_count);
2253 rd_new[rd_off].record_type = ntohl (box->record_type);
2254 rd_new[rd_off].data_size -= sizeof(struct
2255 GNUNET_GNSRECORD_BoxRecord);
2256 rd_new[rd_off].data = &box[1];
2257 rd_off++;
2258 }
2259 }
2260 else
2261 {
2262 /* no specific protocol/service specified, preserve all BOX
2263 records (for modern, GNS-enabled applications) */
2264 rd_off++;
2265 }
2266 break;
2267 }
2268
2269 default:
2270 rd_off++;
2271 break;
2272 } /* end: switch */
2273 } /* end: for rd_count */
2274
2275 /* yes, we are done, return result */
2276 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2277 "Returning GNS response for `%s' with %u answers\n",
2278 rh->ac_tail->label,
2279 rd_off);
2280 rh->proc (rh->proc_cls,
2281 rd_off,
2282 rd_new);
2283 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2284 rh);
2285 return;
2286 }
2287
2288 switch (rd[0].record_type)
2289 {
2290 case GNUNET_GNSRECORD_TYPE_REDIRECT:
2291 GNUNET_break_op (1 == rd_count); /* REDIRECT should be unique */
2292 recursive_redirect_resolution (rh,
2293 &rd[0]);
2294 return;
2295
2296 case GNUNET_DNSPARSER_TYPE_CNAME:
2297 GNUNET_break_op (1 == rd_count); /* CNAME should be unique */
2298 recursive_cname_resolution (rh,
2299 &rd[0]);
2300 return;
2301
2302 case GNUNET_GNSRECORD_TYPE_PKEY:
2303 case GNUNET_GNSRECORD_TYPE_EDKEY:
2304 GNUNET_break_op (1 == rd_count); /* PKEY should be unique */
2305 recursive_pkey_resolution (rh,
2306 &rd[0]);
2307 return;
2308
2309 case GNUNET_GNSRECORD_TYPE_GNS2DNS:
2310 if (GNUNET_OK ==
2311 recursive_gns2dns_resolution (rh,
2312 rd_count,
2313 rd))
2314 return;
2315 break;
2316 default:
2317 if (GNUNET_YES != GNUNET_GNSRECORD_is_critical (rd[0].record_type))
2318 return;
2319 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2320 _ ("Unable to process critical delegation record\n"));
2321 break;
2322 }
2323fail:
2324 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2325 _ ("GNS lookup recursion failed (no delegation record found)\n"));
2326 fail_resolution (rh);
2327}
2328
2329
2330/**
2331 * Function called once the namestore has completed the request for
2332 * caching a block.
2333 *
2334 * @param cls closure with the `struct CacheOps`
2335 * @param success #GNUNET_OK on success
2336 * @param emsg error message
2337 */
2338static void
2339namecache_cache_continuation (void *cls,
2340 int32_t success,
2341 const char *emsg)
2342{
2343 struct CacheOps *co = cls;
2344
2345 co->namecache_qe_cache = NULL;
2346 if (GNUNET_OK != success)
2347 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2348 _ ("Failed to cache GNS resolution: %s\n"),
2349 emsg);
2350 GNUNET_CONTAINER_DLL_remove (co_head,
2351 co_tail,
2352 co);
2353 GNUNET_free (co);
2354}
2355
2356
2357/**
2358 * Iterator called on each result obtained for a DHT
2359 * operation that expects a reply
2360 *
2361 * @param cls closure with the `struct GNS_ResolverHandle`
2362 * @param exp when will this value expire
2363 * @param key key of the result
2364 * @param trunc_peer truncated peer, NULL if not truncated
2365 * @param get_path peers on reply path (or NULL if not recorded)
2366 * [0] = datastore's first neighbor, [length - 1] = local peer
2367 * @param get_path_length number of entries in @a get_path
2368 * @param put_path peers on the PUT path (or NULL if not recorded)
2369 * [0] = origin, [length - 1] = datastore
2370 * @param put_path_length number of entries in @a put_path
2371 * @param type type of the result
2372 * @param size number of bytes in data
2373 * @param data pointer to the result data
2374 */
2375static void
2376handle_dht_response (void *cls,
2377 struct GNUNET_TIME_Absolute exp,
2378 const struct GNUNET_HashCode *key,
2379 const struct GNUNET_PeerIdentity *trunc_peer,
2380 const struct GNUNET_DHT_PathElement *get_path,
2381 unsigned int get_path_length,
2382 const struct GNUNET_DHT_PathElement *put_path,
2383 unsigned int put_path_length,
2384 enum GNUNET_BLOCK_Type type,
2385 size_t size,
2386 const void *data)
2387{
2388 struct GNS_ResolverHandle *rh = cls;
2389 struct AuthorityChain *ac = rh->ac_tail;
2390 const struct GNUNET_GNSRECORD_Block *block;
2391 struct CacheOps *co;
2392
2393 (void) exp;
2394 (void) key;
2395 (void) get_path;
2396 (void) get_path_length;
2397 (void) put_path;
2398 (void) put_path_length;
2399 (void) type;
2400 GNUNET_DHT_get_stop (rh->get_handle);
2401 rh->get_handle = NULL;
2402 GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
2403 rh->dht_heap_node = NULL;
2404 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2405 "Handling response from the DHT\n");
2406 if (size < sizeof(struct GNUNET_GNSRECORD_Block))
2407 {
2408 /* how did this pass DHT block validation!? */
2409 GNUNET_break (0);
2410 fail_resolution (rh);
2411 return;
2412 }
2413 block = data;
2414 if (size != GNUNET_GNSRECORD_block_get_size (block))
2415 {
2416 /* how did this pass DHT block validation!? */
2417 GNUNET_break (0);
2418 fail_resolution (rh);
2419 return;
2420 }
2421 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2422 "Decrypting DHT block of size %lu for `%s', expires %s\n",
2423 GNUNET_GNSRECORD_block_get_size (block),
2424 rh->name,
2425 GNUNET_STRINGS_absolute_time_to_string (exp));
2426 if (GNUNET_OK !=
2427 GNUNET_GNSRECORD_block_decrypt (block,
2428 &ac->authority_info.gns_authority,
2429 ac->label,
2430 &handle_gns_resolution_result,
2431 rh))
2432 {
2433 GNUNET_break_op (0); /* block was ill-formed */
2434 fail_resolution (rh);
2435 return;
2436 }
2437 if (0 == GNUNET_TIME_absolute_get_remaining (
2438 GNUNET_GNSRECORD_block_get_expiration (block)).
2439 rel_value_us)
2440 {
2441 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2442 "Received expired block from the DHT, will not cache it.\n");
2443 return;
2444 }
2445 if (GNUNET_YES == disable_cache)
2446 return;
2447 /* Cache well-formed blocks */
2448 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2449 "Caching response from the DHT in namecache\n");
2450 co = GNUNET_new (struct CacheOps);
2451 co->namecache_qe_cache = GNUNET_NAMECACHE_block_cache (namecache_handle,
2452 block,
2453 &
2454 namecache_cache_continuation,
2455 co);
2456 GNUNET_CONTAINER_DLL_insert (co_head,
2457 co_tail,
2458 co);
2459}
2460
2461
2462/**
2463 * Initiate a DHT query for a set of GNS records.
2464 *
2465 * @param rh resolution handle
2466 * @param query key to use in the DHT lookup
2467 */
2468static void
2469start_dht_request (struct GNS_ResolverHandle *rh,
2470 const struct GNUNET_HashCode *query)
2471{
2472 struct GNS_ResolverHandle *rx;
2473
2474 GNUNET_assert (NULL == rh->get_handle);
2475 rh->get_handle = GNUNET_DHT_get_start (dht_handle,
2476 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
2477 query,
2478 DHT_GNS_REPLICATION_LEVEL,
2479 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
2480 NULL, 0,
2481 &handle_dht_response, rh);
2482 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
2483 rh,
2484 GNUNET_TIME_absolute_get ().
2485 abs_value_us);
2486 if (GNUNET_CONTAINER_heap_get_size (dht_lookup_heap) >
2487 max_allowed_background_queries)
2488 {
2489 /* fail longest-standing DHT request */
2490 rx = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
2491 rx->dht_heap_node = NULL;
2492 GNUNET_assert (NULL != rx);
2493 fail_resolution (rx);
2494 }
2495}
2496
2497
2498/**
2499 * Process a records that were decrypted from a block that we got from
2500 * the namecache. Simply calls #handle_gns_resolution_result().
2501 *
2502 * @param cls closure with the `struct GNS_ResolverHandle`
2503 * @param rd_count number of entries in @a rd array
2504 * @param rd array of records with data to store
2505 */
2506static void
2507handle_gns_namecache_resolution_result (void *cls,
2508 unsigned int rd_count,
2509 const struct GNUNET_GNSRECORD_Data *rd)
2510{
2511 struct GNS_ResolverHandle *rh = cls;
2512
2513 if (0 == rd_count)
2514 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2515 _ ("GNS namecache returned empty result for `%s'\n"),
2516 rh->name);
2517 handle_gns_resolution_result (rh,
2518 rd_count,
2519 rd);
2520}
2521
2522
2523/**
2524 * Process a record that was stored in the namecache.
2525 *
2526 * @param cls closure with the `struct GNS_ResolverHandle`
2527 * @param block block that was stored in the namecache
2528 */
2529static void
2530handle_namecache_block_response (void *cls,
2531 const struct GNUNET_GNSRECORD_Block *block)
2532{
2533 struct GNS_ResolverHandle *rh = cls;
2534 struct AuthorityChain *ac = rh->ac_tail;
2535 const char *label = ac->label;
2536 const struct GNUNET_IDENTITY_PublicKey *auth =
2537 &ac->authority_info.gns_authority;
2538 struct GNUNET_HashCode query;
2539
2540 GNUNET_assert (NULL != rh->namecache_qe);
2541 rh->namecache_qe = NULL;
2542 if (NULL == block)
2543 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2544 "No block found\n");
2545 else
2546 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2547 "Got block with expiration %s\n",
2548 GNUNET_STRINGS_absolute_time_to_string (
2549 GNUNET_GNSRECORD_block_get_expiration (block)));
2550 if (((GNUNET_GNS_LO_DEFAULT == rh->options) ||
2551 ((GNUNET_GNS_LO_LOCAL_MASTER == rh->options) &&
2552 (ac != rh->ac_head))) &&
2553 ((NULL == block) ||
2554 (0 == GNUNET_TIME_absolute_get_remaining (
2555 GNUNET_GNSRECORD_block_get_expiration (block)).
2556 rel_value_us)))
2557 {
2558 /* namecache knows nothing; try DHT lookup */
2559 GNUNET_GNSRECORD_query_from_public_key (auth,
2560 label,
2561 &query);
2562 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2563 "Starting DHT lookup for `%s' in zone `%s' under key `%s'\n",
2564 ac->label,
2565 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority),
2566 GNUNET_h2s (&query));
2567 start_dht_request (rh, &query);
2568 return;
2569 }
2570
2571 if ((NULL == block) ||
2572 (0 == GNUNET_TIME_absolute_get_remaining (
2573 GNUNET_GNSRECORD_block_get_expiration (block)).
2574 rel_value_us))
2575 {
2576 /* DHT not permitted and no local result, fail */
2577 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2578 "Resolution failed for `%s' in zone %s (DHT lookup not permitted by configuration)\n",
2579 ac->label,
2580 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2581 fail_resolution (rh);
2582 return;
2583 }
2584 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2585 "Received result from namecache for label `%s'\n",
2586 ac->label);
2587
2588 if (GNUNET_OK !=
2589 GNUNET_GNSRECORD_block_decrypt (block,
2590 auth,
2591 label,
2592 &handle_gns_namecache_resolution_result,
2593 rh))
2594 {
2595 GNUNET_break_op (0); /* block was ill-formed */
2596 /* try DHT instead */
2597 GNUNET_GNSRECORD_query_from_public_key (auth,
2598 label,
2599 &query);
2600 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2601 "Starting DHT lookup for `%s' in zone `%s' under key `%s'\n",
2602 ac->label,
2603 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority),
2604 GNUNET_h2s (&query));
2605 start_dht_request (rh, &query);
2606 return;
2607 }
2608}
2609
2610
2611/**
2612 * Lookup tail of our authority chain in the namecache.
2613 *
2614 * @param rh query we are processing
2615 */
2616static void
2617recursive_gns_resolution_namecache (struct GNS_ResolverHandle *rh)
2618{
2619 struct AuthorityChain *ac = rh->ac_tail;
2620 struct GNUNET_HashCode query;
2621
2622 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2623 "Starting GNS resolution for `%s' in zone %s\n",
2624 ac->label,
2625 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2626 GNUNET_GNSRECORD_query_from_public_key (&ac->authority_info.gns_authority,
2627 ac->label,
2628 &query);
2629 if (GNUNET_YES != disable_cache)
2630 {
2631 rh->namecache_qe
2632 = GNUNET_NAMECACHE_lookup_block (namecache_handle,
2633 &query,
2634 &handle_namecache_block_response,
2635 rh);
2636 GNUNET_assert (NULL != rh->namecache_qe);
2637 }
2638 else
2639 {
2640 start_dht_request (rh,
2641 &query);
2642 }
2643}
2644
2645
2646/**
2647 * Function called with the result from a revocation check.
2648 *
2649 * @param cls the `struct GNS_ResovlerHandle`
2650 * @param is_valid #GNUNET_YES if the zone was not yet revoked
2651 */
2652static void
2653handle_revocation_result (void *cls,
2654 int is_valid)
2655{
2656 struct GNS_ResolverHandle *rh = cls;
2657 struct AuthorityChain *ac = rh->ac_tail;
2658
2659 rh->rev_check = NULL;
2660 if (GNUNET_YES != is_valid)
2661 {
2662 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2663 _ ("Zone %s was revoked, resolution fails\n"),
2664 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2665 fail_resolution (rh);
2666 return;
2667 }
2668 recursive_gns_resolution_namecache (rh);
2669}
2670
2671
2672/**
2673 * Perform revocation check on tail of our authority chain.
2674 *
2675 * @param rh query we are processing
2676 */
2677static void
2678recursive_gns_resolution_revocation (struct GNS_ResolverHandle *rh)
2679{
2680 struct AuthorityChain *ac = rh->ac_tail;
2681
2682 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2683 "Starting revocation check for zone %s\n",
2684 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2685 rh->rev_check = GNUNET_REVOCATION_query (cfg,
2686 &ac->authority_info.gns_authority,
2687 &handle_revocation_result,
2688 rh);
2689 GNUNET_assert (NULL != rh->rev_check);
2690}
2691
2692
2693static void
2694recursive_resolution (void *cls)
2695{
2696 struct GNS_ResolverHandle *rh = cls;
2697
2698 rh->task_id = NULL;
2699 if (rh->loop_threshold < rh->loop_limiter++)
2700 {
2701 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2702 "Encountered unbounded recursion resolving `%s'\n",
2703 rh->name);
2704 fail_resolution (rh);
2705 return;
2706 }
2707 if (GNUNET_YES == rh->ac_tail->gns_authority)
2708 recursive_gns_resolution_revocation (rh);
2709 else
2710 recursive_dns_resolution (rh);
2711}
2712
2713
2714static void
2715start_resolver_lookup (void *cls)
2716{
2717 struct GNS_ResolverHandle *rh = cls;
2718 struct AuthorityChain *ac;
2719 struct in_addr v4;
2720 struct in6_addr v6;
2721
2722 rh->task_id = NULL;
2723 if (1 == inet_pton (AF_INET,
2724 rh->name,
2725 &v4))
2726 {
2727 /* name is IPv4 address, pretend it's an A record */
2728 struct GNUNET_GNSRECORD_Data rd;
2729
2730 rd.data = &v4;
2731 rd.data_size = sizeof(v4);
2732 rd.expiration_time = UINT64_MAX;
2733 rd.record_type = GNUNET_DNSPARSER_TYPE_A;
2734 rd.flags = 0;
2735 rh->proc (rh->proc_cls,
2736 1,
2737 &rd);
2738 GNUNET_assert (NULL == rh->task_id);
2739 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2740 rh);
2741 return;
2742 }
2743 if (1 == inet_pton (AF_INET6,
2744 rh->name,
2745 &v6))
2746 {
2747 /* name is IPv6 address, pretend it's an AAAA record */
2748 struct GNUNET_GNSRECORD_Data rd;
2749
2750 rd.data = &v6;
2751 rd.data_size = sizeof(v6);
2752 rd.expiration_time = UINT64_MAX;
2753 rd.record_type = GNUNET_DNSPARSER_TYPE_AAAA;
2754 rd.flags = 0;
2755 rh->proc (rh->proc_cls,
2756 1,
2757 &rd);
2758 GNUNET_assert (NULL == rh->task_id);
2759 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2760 rh);
2761 return;
2762 }
2763
2764 ac = GNUNET_new (struct AuthorityChain);
2765 ac->rh = rh;
2766 ac->label = resolver_lookup_get_next_label (rh);
2767 if (NULL == ac->label)
2768 /* name was just the "TLD", so we default to label
2769 #GNUNET_GNS_EMPTY_LABEL_AT */
2770 ac->label = GNUNET_strdup (GNUNET_GNS_EMPTY_LABEL_AT);
2771 ac->gns_authority = GNUNET_YES;
2772 ac->authority_info.gns_authority = rh->authority_zone;
2773 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
2774 rh->ac_tail,
2775 ac);
2776 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
2777 rh);
2778}
2779
2780
2781/**
2782 * Lookup of a record in a specific zone calls lookup result processor
2783 * on result.
2784 *
2785 * @param zone the zone to perform the lookup in
2786 * @param record_type the record type to look up
2787 * @param name the name to look up
2788 * @param options local options to control local lookup
2789 * @param recursion_depth_limit how many zones to traverse
2790 * at most
2791 * @param proc the processor to call on result
2792 * @param proc_cls the closure to pass to @a proc
2793 * @return handle to cancel operation
2794 */
2795struct GNS_ResolverHandle *
2796GNS_resolver_lookup (const struct GNUNET_IDENTITY_PublicKey *zone,
2797 uint32_t record_type,
2798 const char *name,
2799 enum GNUNET_GNS_LocalOptions options,
2800 uint16_t recursion_depth_limit,
2801 GNS_ResultProcessor proc,
2802 void *proc_cls)
2803{
2804 struct GNS_ResolverHandle *rh;
2805
2806 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2807 "Starting lookup for `%s'\n",
2808 name);
2809 rh = GNUNET_new (struct GNS_ResolverHandle);
2810 GNUNET_CONTAINER_DLL_insert (rlh_head,
2811 rlh_tail,
2812 rh);
2813 rh->authority_zone = *zone;
2814 rh->proc = proc;
2815 rh->proc_cls = proc_cls;
2816 rh->options = options;
2817 rh->record_type = record_type;
2818 rh->name = GNUNET_strdup (name);
2819 rh->name_resolution_pos = strlen (name);
2820 rh->loop_threshold = recursion_depth_limit;
2821 rh->task_id = GNUNET_SCHEDULER_add_now (&start_resolver_lookup,
2822 rh);
2823 return rh;
2824}
2825
2826
2827/**
2828 * Cancel active resolution (i.e. client disconnected).
2829 *
2830 * @param rh resolution to abort
2831 */
2832void
2833GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
2834{
2835 struct DnsResult *dr;
2836 struct AuthorityChain *ac;
2837
2838 GNUNET_CONTAINER_DLL_remove (rlh_head,
2839 rlh_tail,
2840 rh);
2841 if (NULL != rh->dns_request)
2842 {
2843 GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
2844 rh->dns_request = NULL;
2845 }
2846 while (NULL != (ac = rh->ac_head))
2847 {
2848 GNUNET_CONTAINER_DLL_remove (rh->ac_head,
2849 rh->ac_tail,
2850 ac);
2851 if (GNUNET_NO == ac->gns_authority)
2852 {
2853 struct Gns2DnsPending *gp;
2854
2855 while (NULL != (gp = ac->authority_info.dns_authority.gp_head))
2856 {
2857 GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
2858 ac->authority_info.dns_authority.gp_tail,
2859 gp);
2860 if (NULL != gp->rh)
2861 {
2862 /* rh->g2dc->rh is NOT in the DLL yet, so to enable us
2863 using GNS_resolver_lookup_cancel here, we need to
2864 add it first... */
2865 GNUNET_CONTAINER_DLL_insert (rlh_head,
2866 rlh_tail,
2867 gp->rh);
2868 GNUNET_assert (NULL == gp->rh->task_id);
2869 gp->rh->task_id = GNUNET_SCHEDULER_add_now (
2870 &GNS_resolver_lookup_cancel_,
2871 gp->rh);
2872 gp->rh = NULL;
2873 }
2874 if (NULL != gp->dns_rh)
2875 {
2876 GNUNET_RESOLVER_request_cancel (gp->dns_rh);
2877 gp->dns_rh = NULL;
2878 }
2879 GNUNET_free (gp);
2880 }
2881 GNUNET_DNSSTUB_stop (ac->authority_info.dns_authority.dns_handle);
2882 }
2883 GNUNET_free (ac->label);
2884 GNUNET_free (ac);
2885 }
2886 if (NULL != rh->task_id)
2887 {
2888 GNUNET_SCHEDULER_cancel (rh->task_id);
2889 rh->task_id = NULL;
2890 }
2891 if (NULL != rh->get_handle)
2892 {
2893 GNUNET_DHT_get_stop (rh->get_handle);
2894 rh->get_handle = NULL;
2895 }
2896 if (NULL != rh->dht_heap_node)
2897 {
2898 GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
2899 rh->dht_heap_node = NULL;
2900 }
2901 if (NULL != rh->namecache_qe)
2902 {
2903 GNUNET_NAMECACHE_cancel (rh->namecache_qe);
2904 rh->namecache_qe = NULL;
2905 }
2906 if (NULL != rh->rev_check)
2907 {
2908 GNUNET_REVOCATION_query_cancel (rh->rev_check);
2909 rh->rev_check = NULL;
2910 }
2911 if (NULL != rh->std_resolve)
2912 {
2913 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2914 "Canceling standard DNS resolution\n");
2915 GNUNET_RESOLVER_request_cancel (rh->std_resolve);
2916 rh->std_resolve = NULL;
2917 }
2918 while (NULL != (dr = rh->dns_result_head))
2919 {
2920 GNUNET_CONTAINER_DLL_remove (rh->dns_result_head,
2921 rh->dns_result_tail,
2922 dr);
2923 GNUNET_free (dr);
2924 }
2925 GNUNET_free (rh->leho);
2926 GNUNET_free (rh->name);
2927 GNUNET_free (rh);
2928}
2929
2930
2931/* ***************** Resolver initialization ********************* */
2932
2933
2934/**
2935 * Initialize the resolver
2936 *
2937 * @param nc the namecache handle
2938 * @param dht the dht handle
2939 * @param c configuration handle
2940 * @param max_bg_queries maximum number of parallel background queries in dht
2941 */
2942void
2943GNS_resolver_init (struct GNUNET_NAMECACHE_Handle *nc,
2944 struct GNUNET_DHT_Handle *dht,
2945 const struct GNUNET_CONFIGURATION_Handle *c,
2946 unsigned long long max_bg_queries)
2947{
2948 cfg = c;
2949 namecache_handle = nc;
2950 dht_handle = dht;
2951 dht_lookup_heap =
2952 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
2953 max_allowed_background_queries = max_bg_queries;
2954 disable_cache = GNUNET_CONFIGURATION_get_value_yesno (cfg,
2955 "namecache",
2956 "DISABLE");
2957 if (GNUNET_YES == disable_cache)
2958 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2959 "Namecache disabled\n");
2960}
2961
2962
2963/**
2964 * Shutdown resolver
2965 */
2966void
2967GNS_resolver_done ()
2968{
2969 struct GNS_ResolverHandle *rh;
2970 struct CacheOps *co;
2971
2972 /* abort active resolutions */
2973 while (NULL != (rh = rlh_head))
2974 {
2975 rh->proc (rh->proc_cls,
2976 0,
2977 NULL);
2978 GNS_resolver_lookup_cancel (rh);
2979 }
2980 while (NULL != (co = co_head))
2981 {
2982 GNUNET_CONTAINER_DLL_remove (co_head,
2983 co_tail,
2984 co);
2985 GNUNET_NAMECACHE_cancel (co->namecache_qe_cache);
2986 GNUNET_free (co);
2987 }
2988 GNUNET_CONTAINER_heap_destroy (dht_lookup_heap);
2989 dht_lookup_heap = NULL;
2990 dht_handle = NULL;
2991 namecache_handle = NULL;
2992}
2993
2994
2995/* end of gnunet-service-gns_resolver.c */