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