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