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