diff options
Diffstat (limited to 'src/pt/gnunet-daemon-pt.c')
-rw-r--r-- | src/pt/gnunet-daemon-pt.c | 1327 |
1 files changed, 0 insertions, 1327 deletions
diff --git a/src/pt/gnunet-daemon-pt.c b/src/pt/gnunet-daemon-pt.c deleted file mode 100644 index 67227b97f..000000000 --- a/src/pt/gnunet-daemon-pt.c +++ /dev/null | |||
@@ -1,1327 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2010, 2012, 2017 Christian Grothoff | ||
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 | * @file pt/gnunet-daemon-pt.c | ||
22 | * @brief tool to manipulate DNS and VPN services to perform protocol translation (IPvX over GNUnet) | ||
23 | * @author Christian Grothoff | ||
24 | */ | ||
25 | #include "platform.h" | ||
26 | #include "gnunet_util_lib.h" | ||
27 | #include "gnunet_dns_service.h" | ||
28 | #include "gnunet_dnsparser_lib.h" | ||
29 | #include "gnunet_cadet_service.h" | ||
30 | #include "gnunet_tun_lib.h" | ||
31 | #include "gnunet_dht_service.h" | ||
32 | #include "gnunet_vpn_service.h" | ||
33 | #include "gnunet_statistics_service.h" | ||
34 | #include "gnunet_applications.h" | ||
35 | #include "block_dns.h" | ||
36 | |||
37 | |||
38 | /** | ||
39 | * After how long do we time out if we could not get an IP from VPN or CADET? | ||
40 | */ | ||
41 | #define TIMEOUT GNUNET_TIME_UNIT_MINUTES | ||
42 | |||
43 | /** | ||
44 | * How many bytes of payload do we allow at most for a DNS reply? | ||
45 | * Given that this is pretty much limited to loopback, we can be | ||
46 | * pretty high (Linux loopback defaults to 16k, most local UDP packets | ||
47 | * should survive up to 9k (NFS), so 8k should be pretty safe in | ||
48 | * general). | ||
49 | */ | ||
50 | #define MAX_DNS_SIZE (8 * 1024) | ||
51 | |||
52 | /** | ||
53 | * How many channels do we open at most at the same time? | ||
54 | */ | ||
55 | #define MAX_OPEN_TUNNELS 4 | ||
56 | |||
57 | |||
58 | /** | ||
59 | * Which group of DNS records are we currently processing? | ||
60 | */ | ||
61 | enum RequestGroup | ||
62 | { | ||
63 | /** | ||
64 | * DNS answers | ||
65 | */ | ||
66 | ANSWERS = 0, | ||
67 | |||
68 | /** | ||
69 | * DNS authority records | ||
70 | */ | ||
71 | AUTHORITY_RECORDS = 1, | ||
72 | |||
73 | /** | ||
74 | * DNS additional records | ||
75 | */ | ||
76 | ADDITIONAL_RECORDS = 2, | ||
77 | |||
78 | /** | ||
79 | * We're done processing. | ||
80 | */ | ||
81 | END = 3 | ||
82 | }; | ||
83 | |||
84 | |||
85 | /** | ||
86 | * Information tracked per DNS reply that we are processing. | ||
87 | */ | ||
88 | struct ReplyContext | ||
89 | { | ||
90 | /** | ||
91 | * Handle to submit the final result. | ||
92 | */ | ||
93 | struct GNUNET_DNS_RequestHandle *rh; | ||
94 | |||
95 | /** | ||
96 | * DNS packet that is being modified. | ||
97 | */ | ||
98 | struct GNUNET_DNSPARSER_Packet *dns; | ||
99 | |||
100 | /** | ||
101 | * Active redirection request with the VPN. | ||
102 | */ | ||
103 | struct GNUNET_VPN_RedirectionRequest *rr; | ||
104 | |||
105 | /** | ||
106 | * Record for which we have an active redirection request. | ||
107 | */ | ||
108 | struct GNUNET_DNSPARSER_Record *rec; | ||
109 | |||
110 | /** | ||
111 | * Offset in the current record group that is being modified. | ||
112 | */ | ||
113 | unsigned int offset; | ||
114 | |||
115 | /** | ||
116 | * Group that is being modified | ||
117 | */ | ||
118 | enum RequestGroup group; | ||
119 | }; | ||
120 | |||
121 | |||
122 | /** | ||
123 | * Handle to a peer that advertised that it is willing to serve | ||
124 | * as a DNS exit. We try to keep a few channels open and a few | ||
125 | * peers in reserve. | ||
126 | */ | ||
127 | struct CadetExit | ||
128 | { | ||
129 | /** | ||
130 | * Kept in a DLL. | ||
131 | */ | ||
132 | struct CadetExit *next; | ||
133 | |||
134 | /** | ||
135 | * Kept in a DLL. | ||
136 | */ | ||
137 | struct CadetExit *prev; | ||
138 | |||
139 | /** | ||
140 | * Channel we use for DNS requests over CADET, NULL if we did | ||
141 | * not initialize a channel to this peer yet. | ||
142 | */ | ||
143 | struct GNUNET_CADET_Channel *cadet_channel; | ||
144 | |||
145 | /** | ||
146 | * At what time did the peer's advertisement expire? | ||
147 | */ | ||
148 | struct GNUNET_TIME_Absolute expiration; | ||
149 | |||
150 | /** | ||
151 | * Head of DLL of requests waiting for a response. | ||
152 | */ | ||
153 | struct RequestContext *receive_queue_head; | ||
154 | |||
155 | /** | ||
156 | * Tail of DLL of requests waiting for a response. | ||
157 | */ | ||
158 | struct RequestContext *receive_queue_tail; | ||
159 | |||
160 | /** | ||
161 | * Identity of the peer that is providing the exit for us. | ||
162 | */ | ||
163 | struct GNUNET_PeerIdentity peer; | ||
164 | |||
165 | /** | ||
166 | * How many DNS requests did we transmit via this channel? | ||
167 | */ | ||
168 | unsigned int num_transmitted; | ||
169 | |||
170 | /** | ||
171 | * How many DNS requests were answered via this channel? | ||
172 | */ | ||
173 | unsigned int num_answered; | ||
174 | |||
175 | /** | ||
176 | * Size of the window, 0 if we are busy. | ||
177 | */ | ||
178 | /* unsigned */ int idle; | ||
179 | }; | ||
180 | |||
181 | |||
182 | /** | ||
183 | * State we keep for a request that is going out via CADET. | ||
184 | */ | ||
185 | struct RequestContext | ||
186 | { | ||
187 | /** | ||
188 | * We keep these in a DLL. | ||
189 | */ | ||
190 | struct RequestContext *next; | ||
191 | |||
192 | /** | ||
193 | * We keep these in a DLL. | ||
194 | */ | ||
195 | struct RequestContext *prev; | ||
196 | |||
197 | /** | ||
198 | * Exit that was chosen for this request. | ||
199 | */ | ||
200 | struct CadetExit *exit; | ||
201 | |||
202 | /** | ||
203 | * Handle for interaction with DNS service. | ||
204 | */ | ||
205 | struct GNUNET_DNS_RequestHandle *rh; | ||
206 | |||
207 | /** | ||
208 | * Envelope with the request we are transmitting. | ||
209 | */ | ||
210 | struct GNUNET_MQ_Envelope *env; | ||
211 | |||
212 | /** | ||
213 | * Task used to abort this operation with timeout. | ||
214 | */ | ||
215 | struct GNUNET_SCHEDULER_Task *timeout_task; | ||
216 | |||
217 | /** | ||
218 | * Length of the request message that follows this struct. | ||
219 | */ | ||
220 | uint16_t mlen; | ||
221 | |||
222 | /** | ||
223 | * ID of the original DNS request (used to match the reply). | ||
224 | */ | ||
225 | uint16_t dns_id; | ||
226 | }; | ||
227 | |||
228 | |||
229 | /** | ||
230 | * Head of DLL of cadet exits. Cadet exits with an open channel are | ||
231 | * always at the beginning (so we do not have to traverse the entire | ||
232 | * list to find them). | ||
233 | */ | ||
234 | static struct CadetExit *exit_head; | ||
235 | |||
236 | /** | ||
237 | * Tail of DLL of cadet exits. | ||
238 | */ | ||
239 | static struct CadetExit *exit_tail; | ||
240 | |||
241 | /** | ||
242 | * The handle to the configuration used throughout the process | ||
243 | */ | ||
244 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
245 | |||
246 | /** | ||
247 | * The handle to the VPN | ||
248 | */ | ||
249 | static struct GNUNET_VPN_Handle *vpn_handle; | ||
250 | |||
251 | /** | ||
252 | * The handle to the CADET service | ||
253 | */ | ||
254 | static struct GNUNET_CADET_Handle *cadet_handle; | ||
255 | |||
256 | /** | ||
257 | * Statistics. | ||
258 | */ | ||
259 | static struct GNUNET_STATISTICS_Handle *stats; | ||
260 | |||
261 | /** | ||
262 | * The handle to DNS post-resolution modifications. | ||
263 | */ | ||
264 | static struct GNUNET_DNS_Handle *dns_post_handle; | ||
265 | |||
266 | /** | ||
267 | * The handle to DNS pre-resolution modifications. | ||
268 | */ | ||
269 | static struct GNUNET_DNS_Handle *dns_pre_handle; | ||
270 | |||
271 | /** | ||
272 | * Handle to access the DHT. | ||
273 | */ | ||
274 | static struct GNUNET_DHT_Handle *dht; | ||
275 | |||
276 | /** | ||
277 | * Our DHT GET operation to find DNS exits. | ||
278 | */ | ||
279 | static struct GNUNET_DHT_GetHandle *dht_get; | ||
280 | |||
281 | /** | ||
282 | * Are we doing IPv4-pt? | ||
283 | */ | ||
284 | static int ipv4_pt; | ||
285 | |||
286 | /** | ||
287 | * Are we doing IPv6-pt? | ||
288 | */ | ||
289 | static int ipv6_pt; | ||
290 | |||
291 | /** | ||
292 | * Are we channeling DNS queries? | ||
293 | */ | ||
294 | static int dns_channel; | ||
295 | |||
296 | /** | ||
297 | * Number of DNS exit peers we currently have in the cadet channel. | ||
298 | * Used to see if using the cadet channel makes any sense right now, | ||
299 | * as well as to decide if we should open new channels. | ||
300 | */ | ||
301 | static unsigned int dns_exit_available; | ||
302 | |||
303 | |||
304 | /** | ||
305 | * We are short on cadet exits, try to open another one. | ||
306 | */ | ||
307 | static void | ||
308 | try_open_exit (void); | ||
309 | |||
310 | |||
311 | /** | ||
312 | * Compute the weight of the given exit. The higher the weight, | ||
313 | * the more likely it will be that the channel will be chosen. | ||
314 | * A weigt of zero means that we should close the channel as it | ||
315 | * is so bad, that we should not use it. | ||
316 | * | ||
317 | * @param exit exit to calculate the weight for | ||
318 | * @return weight of the channel | ||
319 | */ | ||
320 | static uint32_t | ||
321 | get_channel_weight (struct CadetExit *exit) | ||
322 | { | ||
323 | uint32_t dropped; | ||
324 | uint32_t drop_percent; | ||
325 | uint32_t good_percent; | ||
326 | |||
327 | GNUNET_assert (exit->num_transmitted >= exit->num_answered); | ||
328 | dropped = exit->num_transmitted - exit->num_answered; | ||
329 | if (exit->num_transmitted > 0) | ||
330 | drop_percent = (uint32_t) ((100LL * dropped) / exit->num_transmitted); | ||
331 | else | ||
332 | drop_percent = 50; /* no data */ | ||
333 | if ((exit->num_transmitted > 20) && | ||
334 | (drop_percent > 25)) | ||
335 | return 0; /* statistically significant, and > 25% loss, die */ | ||
336 | good_percent = 100 - drop_percent; | ||
337 | GNUNET_assert (0 != good_percent); | ||
338 | if (UINT32_MAX / good_percent / good_percent < exit->num_transmitted) | ||
339 | return UINT32_MAX; /* formula below would overflow */ | ||
340 | return 1 + good_percent * good_percent * exit->num_transmitted; | ||
341 | } | ||
342 | |||
343 | |||
344 | /** | ||
345 | * Choose a cadet exit for a DNS request. We try to use a channel | ||
346 | * that is reliable and currently available. All existing | ||
347 | * channels are given a base weight of 1, plus a score relating | ||
348 | * to the total number of queries answered in relation to the | ||
349 | * total number of queries we sent to that channel. That | ||
350 | * score is doubled if the channel is currently idle. | ||
351 | * | ||
352 | * @return NULL if no exit is known, otherwise the | ||
353 | * exit that we should use to queue a message with | ||
354 | */ | ||
355 | static struct CadetExit * | ||
356 | choose_exit () | ||
357 | { | ||
358 | struct CadetExit *pos; | ||
359 | uint64_t total_transmitted; | ||
360 | uint64_t selected_offset; | ||
361 | uint32_t channel_weight; | ||
362 | |||
363 | total_transmitted = 0; | ||
364 | for (pos = exit_head; NULL != pos; pos = pos->next) | ||
365 | { | ||
366 | if (NULL == pos->cadet_channel) | ||
367 | break; | ||
368 | channel_weight = get_channel_weight (pos); | ||
369 | total_transmitted += channel_weight; | ||
370 | /* double weight for idle channels */ | ||
371 | if (0 != pos->idle) | ||
372 | total_transmitted += channel_weight; | ||
373 | } | ||
374 | if (0 == total_transmitted) | ||
375 | { | ||
376 | /* no channels available, or only a very bad one... */ | ||
377 | return exit_head; | ||
378 | } | ||
379 | selected_offset = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
380 | total_transmitted); | ||
381 | total_transmitted = 0; | ||
382 | for (pos = exit_head; NULL != pos; pos = pos->next) | ||
383 | { | ||
384 | if (NULL == pos->cadet_channel) | ||
385 | break; | ||
386 | channel_weight = get_channel_weight (pos); | ||
387 | total_transmitted += channel_weight; | ||
388 | /* double weight for idle channels */ | ||
389 | if (0 != pos->idle) | ||
390 | total_transmitted += channel_weight; | ||
391 | if (total_transmitted > selected_offset) | ||
392 | return pos; | ||
393 | } | ||
394 | GNUNET_break (0); | ||
395 | return NULL; | ||
396 | } | ||
397 | |||
398 | |||
399 | /** | ||
400 | * We're done modifying all records in the response. Submit the reply | ||
401 | * and free the resources of the rc. | ||
402 | * | ||
403 | * @param rc context to process | ||
404 | */ | ||
405 | static void | ||
406 | finish_request (struct ReplyContext *rc) | ||
407 | { | ||
408 | char *buf; | ||
409 | size_t buf_len; | ||
410 | |||
411 | if (GNUNET_SYSERR == | ||
412 | GNUNET_DNSPARSER_pack (rc->dns, | ||
413 | MAX_DNS_SIZE, | ||
414 | &buf, | ||
415 | &buf_len)) | ||
416 | { | ||
417 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
418 | _ ("Failed to pack DNS request. Dropping.\n")); | ||
419 | GNUNET_DNS_request_drop (rc->rh); | ||
420 | } | ||
421 | else | ||
422 | { | ||
423 | GNUNET_STATISTICS_update (stats, | ||
424 | gettext_noop ("# DNS requests mapped to VPN"), | ||
425 | 1, GNUNET_NO); | ||
426 | GNUNET_DNS_request_answer (rc->rh, | ||
427 | buf_len, | ||
428 | buf); | ||
429 | GNUNET_free (buf); | ||
430 | } | ||
431 | GNUNET_DNSPARSER_free_packet (rc->dns); | ||
432 | GNUNET_free (rc); | ||
433 | } | ||
434 | |||
435 | |||
436 | /** | ||
437 | * Process the next record of the given request context. | ||
438 | * When done, submit the reply and free the resources of | ||
439 | * the rc. | ||
440 | * | ||
441 | * @param rc context to process | ||
442 | */ | ||
443 | static void | ||
444 | submit_request (struct ReplyContext *rc); | ||
445 | |||
446 | |||
447 | /** | ||
448 | * Callback invoked from the VPN service once a redirection is | ||
449 | * available. Provides the IP address that can now be used to | ||
450 | * reach the requested destination. We substitute the active | ||
451 | * record and then continue with 'submit_request' to look at | ||
452 | * the other records. | ||
453 | * | ||
454 | * @param cls our `struct ReplyContext` | ||
455 | * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error; | ||
456 | * will match 'result_af' from the request | ||
457 | * @param address IP address (struct in_addr or struct in_addr6, depending on 'af') | ||
458 | * that the VPN allocated for the redirection; | ||
459 | * traffic to this IP will now be redirected to the | ||
460 | * specified target peer; NULL on error | ||
461 | */ | ||
462 | static void | ||
463 | vpn_allocation_callback (void *cls, | ||
464 | int af, | ||
465 | const void *address) | ||
466 | { | ||
467 | struct ReplyContext *rc = cls; | ||
468 | |||
469 | rc->rr = NULL; | ||
470 | if (af == AF_UNSPEC) | ||
471 | { | ||
472 | GNUNET_DNS_request_drop (rc->rh); | ||
473 | GNUNET_DNSPARSER_free_packet (rc->dns); | ||
474 | GNUNET_free (rc); | ||
475 | return; | ||
476 | } | ||
477 | GNUNET_STATISTICS_update (stats, | ||
478 | gettext_noop ("# DNS records modified"), | ||
479 | 1, | ||
480 | GNUNET_NO); | ||
481 | switch (rc->rec->type) | ||
482 | { | ||
483 | case GNUNET_DNSPARSER_TYPE_A: | ||
484 | GNUNET_assert (AF_INET == af); | ||
485 | GNUNET_memcpy (rc->rec->data.raw.data, | ||
486 | address, | ||
487 | sizeof(struct in_addr)); | ||
488 | break; | ||
489 | |||
490 | case GNUNET_DNSPARSER_TYPE_AAAA: | ||
491 | GNUNET_assert (AF_INET6 == af); | ||
492 | GNUNET_memcpy (rc->rec->data.raw.data, | ||
493 | address, | ||
494 | sizeof(struct in6_addr)); | ||
495 | break; | ||
496 | |||
497 | default: | ||
498 | GNUNET_assert (0); | ||
499 | return; | ||
500 | } | ||
501 | rc->rec = NULL; | ||
502 | submit_request (rc); | ||
503 | } | ||
504 | |||
505 | |||
506 | /** | ||
507 | * Modify the given DNS record by asking VPN to create a channel | ||
508 | * to the given address. When done, continue with submitting | ||
509 | * other records from the request context ('submit_request' is | ||
510 | * our continuation). | ||
511 | * | ||
512 | * @param rc context to process | ||
513 | * @param rec record to modify | ||
514 | */ | ||
515 | static void | ||
516 | modify_address (struct ReplyContext *rc, | ||
517 | struct GNUNET_DNSPARSER_Record *rec) | ||
518 | { | ||
519 | int af; | ||
520 | |||
521 | switch (rec->type) | ||
522 | { | ||
523 | case GNUNET_DNSPARSER_TYPE_A: | ||
524 | af = AF_INET; | ||
525 | GNUNET_assert (rec->data.raw.data_len == sizeof(struct in_addr)); | ||
526 | break; | ||
527 | |||
528 | case GNUNET_DNSPARSER_TYPE_AAAA: | ||
529 | af = AF_INET6; | ||
530 | GNUNET_assert (rec->data.raw.data_len == sizeof(struct in6_addr)); | ||
531 | break; | ||
532 | |||
533 | default: | ||
534 | GNUNET_assert (0); | ||
535 | return; | ||
536 | } | ||
537 | rc->rec = rec; | ||
538 | rc->rr = GNUNET_VPN_redirect_to_ip (vpn_handle, | ||
539 | af, | ||
540 | af, | ||
541 | rec->data.raw.data, | ||
542 | GNUNET_TIME_relative_to_absolute ( | ||
543 | TIMEOUT), | ||
544 | &vpn_allocation_callback, | ||
545 | rc); | ||
546 | } | ||
547 | |||
548 | |||
549 | /** | ||
550 | * Process the next record of the given request context. | ||
551 | * When done, submit the reply and free the resources of | ||
552 | * the rc. | ||
553 | * | ||
554 | * @param rc context to process | ||
555 | */ | ||
556 | static void | ||
557 | submit_request (struct ReplyContext *rc) | ||
558 | { | ||
559 | struct GNUNET_DNSPARSER_Record *ra; | ||
560 | unsigned int ra_len; | ||
561 | unsigned int i; | ||
562 | |||
563 | while (1) | ||
564 | { | ||
565 | switch (rc->group) | ||
566 | { | ||
567 | case ANSWERS: | ||
568 | ra = rc->dns->answers; | ||
569 | ra_len = rc->dns->num_answers; | ||
570 | break; | ||
571 | |||
572 | case AUTHORITY_RECORDS: | ||
573 | ra = rc->dns->authority_records; | ||
574 | ra_len = rc->dns->num_authority_records; | ||
575 | break; | ||
576 | |||
577 | case ADDITIONAL_RECORDS: | ||
578 | ra = rc->dns->additional_records; | ||
579 | ra_len = rc->dns->num_additional_records; | ||
580 | break; | ||
581 | |||
582 | case END: | ||
583 | finish_request (rc); | ||
584 | return; | ||
585 | |||
586 | default: | ||
587 | GNUNET_assert (0); | ||
588 | } | ||
589 | for (i = rc->offset; i < ra_len; i++) | ||
590 | { | ||
591 | switch (ra[i].type) | ||
592 | { | ||
593 | case GNUNET_DNSPARSER_TYPE_A: | ||
594 | if (ipv4_pt) | ||
595 | { | ||
596 | rc->offset = i + 1; | ||
597 | modify_address (rc, | ||
598 | &ra[i]); | ||
599 | return; | ||
600 | } | ||
601 | break; | ||
602 | |||
603 | case GNUNET_DNSPARSER_TYPE_AAAA: | ||
604 | if (ipv6_pt) | ||
605 | { | ||
606 | rc->offset = i + 1; | ||
607 | modify_address (rc, | ||
608 | &ra[i]); | ||
609 | return; | ||
610 | } | ||
611 | break; | ||
612 | } | ||
613 | } | ||
614 | rc->group++; | ||
615 | } | ||
616 | } | ||
617 | |||
618 | |||
619 | /** | ||
620 | * Test if any of the given records need protocol-translation work. | ||
621 | * | ||
622 | * @param ra array of records | ||
623 | * @param ra_len number of entries in @a ra | ||
624 | * @return #GNUNET_YES if any of the given records require protocol-translation | ||
625 | */ | ||
626 | static int | ||
627 | work_test (const struct GNUNET_DNSPARSER_Record *ra, | ||
628 | unsigned int ra_len) | ||
629 | { | ||
630 | unsigned int i; | ||
631 | |||
632 | for (i = 0; i < ra_len; i++) | ||
633 | { | ||
634 | switch (ra[i].type) | ||
635 | { | ||
636 | case GNUNET_DNSPARSER_TYPE_A: | ||
637 | if (ipv4_pt) | ||
638 | return GNUNET_YES; | ||
639 | break; | ||
640 | |||
641 | case GNUNET_DNSPARSER_TYPE_AAAA: | ||
642 | if (ipv6_pt) | ||
643 | return GNUNET_YES; | ||
644 | break; | ||
645 | } | ||
646 | } | ||
647 | return GNUNET_NO; | ||
648 | } | ||
649 | |||
650 | |||
651 | /** | ||
652 | * This function is called AFTER we got an IP address for a | ||
653 | * DNS request. Now, the PT daemon has the chance to substitute | ||
654 | * the IP address with one from the VPN range to channel requests | ||
655 | * destined for this IP address via VPN and CADET. | ||
656 | * | ||
657 | * @param cls closure | ||
658 | * @param rh request handle to user for reply | ||
659 | * @param request_length number of bytes in request | ||
660 | * @param request udp payload of the DNS request | ||
661 | */ | ||
662 | static void | ||
663 | dns_post_request_handler (void *cls, | ||
664 | struct GNUNET_DNS_RequestHandle *rh, | ||
665 | size_t request_length, | ||
666 | const char *request) | ||
667 | { | ||
668 | struct GNUNET_DNSPARSER_Packet *dns; | ||
669 | struct ReplyContext *rc; | ||
670 | int work; | ||
671 | |||
672 | GNUNET_STATISTICS_update (stats, | ||
673 | gettext_noop ("# DNS replies intercepted"), | ||
674 | 1, GNUNET_NO); | ||
675 | dns = GNUNET_DNSPARSER_parse (request, | ||
676 | request_length); | ||
677 | if (NULL == dns) | ||
678 | { | ||
679 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
680 | _ ("Failed to parse DNS request. Dropping.\n")); | ||
681 | GNUNET_DNS_request_drop (rh); | ||
682 | return; | ||
683 | } | ||
684 | work = GNUNET_NO; | ||
685 | work |= work_test (dns->answers, | ||
686 | dns->num_answers); | ||
687 | work |= work_test (dns->authority_records, | ||
688 | dns->num_authority_records); | ||
689 | work |= work_test (dns->additional_records, | ||
690 | dns->num_additional_records); | ||
691 | if (! work) | ||
692 | { | ||
693 | GNUNET_DNS_request_forward (rh); | ||
694 | GNUNET_DNSPARSER_free_packet (dns); | ||
695 | return; | ||
696 | } | ||
697 | rc = GNUNET_new (struct ReplyContext); | ||
698 | rc->rh = rh; | ||
699 | rc->dns = dns; | ||
700 | rc->offset = 0; | ||
701 | rc->group = ANSWERS; | ||
702 | submit_request (rc); | ||
703 | } | ||
704 | |||
705 | |||
706 | /** | ||
707 | * Task run if the time to answer a DNS request via CADET is over. | ||
708 | * | ||
709 | * @param cls the `struct RequestContext` to abort | ||
710 | */ | ||
711 | static void | ||
712 | timeout_request (void *cls) | ||
713 | { | ||
714 | struct RequestContext *rc = cls; | ||
715 | struct CadetExit *exit = rc->exit; | ||
716 | |||
717 | GNUNET_STATISTICS_update (stats, | ||
718 | gettext_noop ("# DNS requests dropped (timeout)"), | ||
719 | 1, | ||
720 | GNUNET_NO); | ||
721 | GNUNET_DNS_request_drop (rc->rh); | ||
722 | GNUNET_free (rc); | ||
723 | if ((0 == get_channel_weight (exit)) && | ||
724 | (NULL == exit->receive_queue_head)) | ||
725 | { | ||
726 | /* this straw broke the camel's back: this channel now has | ||
727 | such a low score that it will not be used; close it! */ | ||
728 | GNUNET_CADET_channel_destroy (exit->cadet_channel); | ||
729 | exit->cadet_channel = NULL; | ||
730 | GNUNET_CONTAINER_DLL_remove (exit_head, | ||
731 | exit_tail, | ||
732 | exit); | ||
733 | GNUNET_CONTAINER_DLL_insert_tail (exit_head, | ||
734 | exit_tail, | ||
735 | exit); | ||
736 | /* go back to semi-innocent: mark as not great, but | ||
737 | avoid a prohibitively negative score (see | ||
738 | #get_channel_weight(), which checks for a certain | ||
739 | minimum number of transmissions before making | ||
740 | up an opinion) */exit->num_transmitted = 5; | ||
741 | exit->num_answered = 0; | ||
742 | dns_exit_available--; | ||
743 | /* now try to open an alternative exit */ | ||
744 | try_open_exit (); | ||
745 | } | ||
746 | } | ||
747 | |||
748 | |||
749 | /** | ||
750 | * This function is called *before* the DNS request has been | ||
751 | * given to a "local" DNS resolver. Channeling for DNS requests | ||
752 | * was enabled, so we now need to send the request via some CADET | ||
753 | * channel to a DNS EXIT for resolution. | ||
754 | * | ||
755 | * @param cls closure | ||
756 | * @param rh request handle to user for reply | ||
757 | * @param request_length number of bytes in request | ||
758 | * @param request udp payload of the DNS request | ||
759 | */ | ||
760 | static void | ||
761 | dns_pre_request_handler (void *cls, | ||
762 | struct GNUNET_DNS_RequestHandle *rh, | ||
763 | size_t request_length, | ||
764 | const char *request) | ||
765 | { | ||
766 | struct RequestContext *rc; | ||
767 | struct GNUNET_MQ_Envelope *env; | ||
768 | struct GNUNET_MessageHeader *hdr; | ||
769 | struct GNUNET_TUN_DnsHeader dns; | ||
770 | struct CadetExit *exit; | ||
771 | |||
772 | GNUNET_STATISTICS_update (stats, | ||
773 | gettext_noop ("# DNS requests intercepted"), | ||
774 | 1, GNUNET_NO); | ||
775 | if (0 == dns_exit_available) | ||
776 | { | ||
777 | GNUNET_STATISTICS_update (stats, | ||
778 | gettext_noop ( | ||
779 | "# DNS requests dropped (DNS cadet channel down)"), | ||
780 | 1, GNUNET_NO); | ||
781 | GNUNET_DNS_request_drop (rh); | ||
782 | return; | ||
783 | } | ||
784 | if (request_length < sizeof(dns)) | ||
785 | { | ||
786 | GNUNET_STATISTICS_update (stats, | ||
787 | gettext_noop ( | ||
788 | "# DNS requests dropped (malformed)"), | ||
789 | 1, GNUNET_NO); | ||
790 | GNUNET_DNS_request_drop (rh); | ||
791 | return; | ||
792 | } | ||
793 | exit = choose_exit (); | ||
794 | GNUNET_assert (NULL != exit); | ||
795 | GNUNET_assert (NULL != exit->cadet_channel); | ||
796 | |||
797 | env = GNUNET_MQ_msg_extra (hdr, | ||
798 | request_length, | ||
799 | GNUNET_MESSAGE_TYPE_VPN_DNS_TO_INTERNET); | ||
800 | GNUNET_memcpy (&hdr[1], | ||
801 | request, | ||
802 | request_length); | ||
803 | rc = GNUNET_new (struct RequestContext); | ||
804 | rc->exit = exit; | ||
805 | rc->rh = rh; | ||
806 | rc->timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, | ||
807 | &timeout_request, | ||
808 | rc); | ||
809 | GNUNET_memcpy (&dns, | ||
810 | request, | ||
811 | sizeof(dns)); | ||
812 | rc->dns_id = dns.id; | ||
813 | rc->env = env; | ||
814 | GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head, | ||
815 | exit->receive_queue_tail, | ||
816 | rc); | ||
817 | if (0 < exit->idle) | ||
818 | exit->idle--; | ||
819 | exit->num_transmitted++; | ||
820 | GNUNET_MQ_send (GNUNET_CADET_get_mq (exit->cadet_channel), | ||
821 | GNUNET_MQ_env_copy (env)); | ||
822 | } | ||
823 | |||
824 | |||
825 | GNUNET_NETWORK_STRUCT_BEGIN | ||
826 | |||
827 | /** | ||
828 | * Message with a DNS response. | ||
829 | */ | ||
830 | struct DnsResponseMessage | ||
831 | { | ||
832 | /** | ||
833 | * GNUnet header, of type #GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET | ||
834 | */ | ||
835 | struct GNUNET_MessageHeader header; | ||
836 | |||
837 | /** | ||
838 | * DNS header. | ||
839 | */ | ||
840 | struct GNUNET_TUN_DnsHeader dns; | ||
841 | |||
842 | /* Followed by more DNS payload */ | ||
843 | }; | ||
844 | |||
845 | GNUNET_NETWORK_STRUCT_END | ||
846 | |||
847 | /** | ||
848 | * Process a request via cadet to perform a DNS query. | ||
849 | * | ||
850 | * @param cls the `struct CadetExit` which got the message | ||
851 | * @param msg the actual message | ||
852 | * @return #GNUNET_OK to keep the connection open, | ||
853 | * #GNUNET_SYSERR to close it (signal serious error) | ||
854 | */ | ||
855 | static int | ||
856 | check_dns_response (void *cls, | ||
857 | const struct DnsResponseMessage *msg) | ||
858 | { | ||
859 | return GNUNET_OK; /* all OK */ | ||
860 | } | ||
861 | |||
862 | |||
863 | /** | ||
864 | * Process a request via cadet to perform a DNS query. | ||
865 | * | ||
866 | * @param cls the `struct CadetExit` which got the message | ||
867 | * @param msg the actual message | ||
868 | */ | ||
869 | static void | ||
870 | handle_dns_response (void *cls, | ||
871 | const struct DnsResponseMessage *msg) | ||
872 | { | ||
873 | struct CadetExit *exit = cls; | ||
874 | size_t mlen; | ||
875 | struct RequestContext *rc; | ||
876 | |||
877 | mlen = ntohs (msg->header.size) - sizeof(*msg); | ||
878 | for (rc = exit->receive_queue_head; NULL != rc; rc = rc->next) | ||
879 | { | ||
880 | if (msg->dns.id == rc->dns_id) | ||
881 | { | ||
882 | GNUNET_STATISTICS_update (stats, | ||
883 | gettext_noop ("# DNS replies received"), | ||
884 | 1, | ||
885 | GNUNET_NO); | ||
886 | GNUNET_DNS_request_answer (rc->rh, | ||
887 | mlen + sizeof(struct GNUNET_TUN_DnsHeader), | ||
888 | (const void *) &msg->dns); | ||
889 | GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head, | ||
890 | exit->receive_queue_tail, | ||
891 | rc); | ||
892 | GNUNET_SCHEDULER_cancel (rc->timeout_task); | ||
893 | GNUNET_MQ_discard (rc->env); | ||
894 | GNUNET_free (rc); | ||
895 | exit->num_answered++; | ||
896 | return; | ||
897 | } | ||
898 | } | ||
899 | GNUNET_STATISTICS_update (stats, | ||
900 | gettext_noop ("# DNS replies dropped (too late?)"), | ||
901 | 1, GNUNET_NO); | ||
902 | } | ||
903 | |||
904 | |||
905 | /** | ||
906 | * Abort all pending DNS requests with the given cadet exit. | ||
907 | * | ||
908 | * @param exit cadet exit to abort requests for | ||
909 | */ | ||
910 | static void | ||
911 | abort_all_requests (struct CadetExit *exit) | ||
912 | { | ||
913 | struct RequestContext *rc; | ||
914 | |||
915 | while (NULL != (rc = exit->receive_queue_head)) | ||
916 | { | ||
917 | GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head, | ||
918 | exit->receive_queue_tail, | ||
919 | rc); | ||
920 | GNUNET_DNS_request_drop (rc->rh); | ||
921 | GNUNET_SCHEDULER_cancel (rc->timeout_task); | ||
922 | GNUNET_MQ_discard (rc->env); | ||
923 | GNUNET_free (rc); | ||
924 | } | ||
925 | } | ||
926 | |||
927 | |||
928 | /** | ||
929 | * Function scheduled as very last function, cleans up after us | ||
930 | * | ||
931 | * @param cls closure, NULL | ||
932 | */ | ||
933 | static void | ||
934 | cleanup (void *cls) | ||
935 | { | ||
936 | struct CadetExit *exit; | ||
937 | |||
938 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
939 | "Protocol translation daemon is shutting down now\n"); | ||
940 | if (NULL != vpn_handle) | ||
941 | { | ||
942 | GNUNET_VPN_disconnect (vpn_handle); | ||
943 | vpn_handle = NULL; | ||
944 | } | ||
945 | while (NULL != (exit = exit_head)) | ||
946 | { | ||
947 | GNUNET_CONTAINER_DLL_remove (exit_head, | ||
948 | exit_tail, | ||
949 | exit); | ||
950 | if (NULL != exit->cadet_channel) | ||
951 | { | ||
952 | GNUNET_CADET_channel_destroy (exit->cadet_channel); | ||
953 | exit->cadet_channel = NULL; | ||
954 | } | ||
955 | abort_all_requests (exit); | ||
956 | GNUNET_free (exit); | ||
957 | } | ||
958 | if (NULL != cadet_handle) | ||
959 | { | ||
960 | GNUNET_CADET_disconnect (cadet_handle); | ||
961 | cadet_handle = NULL; | ||
962 | } | ||
963 | if (NULL != dns_post_handle) | ||
964 | { | ||
965 | GNUNET_DNS_disconnect (dns_post_handle); | ||
966 | dns_post_handle = NULL; | ||
967 | } | ||
968 | if (NULL != dns_pre_handle) | ||
969 | { | ||
970 | GNUNET_DNS_disconnect (dns_pre_handle); | ||
971 | dns_pre_handle = NULL; | ||
972 | } | ||
973 | if (NULL != stats) | ||
974 | { | ||
975 | GNUNET_STATISTICS_destroy (stats, GNUNET_YES); | ||
976 | stats = NULL; | ||
977 | } | ||
978 | if (NULL != dht_get) | ||
979 | { | ||
980 | GNUNET_DHT_get_stop (dht_get); | ||
981 | dht_get = NULL; | ||
982 | } | ||
983 | if (NULL != dht) | ||
984 | { | ||
985 | GNUNET_DHT_disconnect (dht); | ||
986 | dht = NULL; | ||
987 | } | ||
988 | } | ||
989 | |||
990 | |||
991 | /** | ||
992 | * Function called whenever a channel is destroyed. Should clean up | ||
993 | * the associated state and attempt to build a new one. | ||
994 | * | ||
995 | * It must NOT call #GNUNET_CADET_channel_destroy on the channel. | ||
996 | * | ||
997 | * @param cls closure (the `struct CadetExit` set from #GNUNET_CADET_connect) | ||
998 | * @param channel connection to the other end (henceforth invalid) | ||
999 | * @param channel_ctx place where local state associated | ||
1000 | * with the channel is stored | ||
1001 | */ | ||
1002 | static void | ||
1003 | cadet_channel_end_cb (void *cls, | ||
1004 | const struct GNUNET_CADET_Channel *channel) | ||
1005 | { | ||
1006 | struct CadetExit *exit = cls; | ||
1007 | struct CadetExit *alt; | ||
1008 | struct RequestContext *rc; | ||
1009 | |||
1010 | exit->cadet_channel = NULL; | ||
1011 | dns_exit_available--; | ||
1012 | /* open alternative channels */ | ||
1013 | /* our channel is now closed, move our requests to an alternative | ||
1014 | channel */ | ||
1015 | alt = choose_exit (); | ||
1016 | while (NULL != (rc = exit->receive_queue_head)) | ||
1017 | { | ||
1018 | GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head, | ||
1019 | exit->receive_queue_tail, | ||
1020 | rc); | ||
1021 | rc->exit = alt; | ||
1022 | GNUNET_CONTAINER_DLL_insert (alt->receive_queue_head, | ||
1023 | alt->receive_queue_tail, | ||
1024 | rc); | ||
1025 | GNUNET_MQ_send (GNUNET_CADET_get_mq (alt->cadet_channel), | ||
1026 | GNUNET_MQ_env_copy (rc->env)); | ||
1027 | } | ||
1028 | try_open_exit (); | ||
1029 | } | ||
1030 | |||
1031 | |||
1032 | /** | ||
1033 | * Function called whenever a channel has excess capacity. | ||
1034 | * | ||
1035 | * @param cls the `struct CadetExit` | ||
1036 | * @param channel connection to the other end | ||
1037 | * @param window_size how much capacity do we have | ||
1038 | */ | ||
1039 | static void | ||
1040 | channel_idle_notify_cb (void *cls, | ||
1041 | const struct GNUNET_CADET_Channel *channel, | ||
1042 | int window_size) | ||
1043 | { | ||
1044 | struct CadetExit *pos = cls; | ||
1045 | |||
1046 | pos->idle = window_size; | ||
1047 | } | ||
1048 | |||
1049 | |||
1050 | /** | ||
1051 | * We are short on cadet exits, try to open another one. | ||
1052 | */ | ||
1053 | static void | ||
1054 | try_open_exit () | ||
1055 | { | ||
1056 | struct CadetExit *pos; | ||
1057 | uint32_t candidate_count; | ||
1058 | uint32_t candidate_selected; | ||
1059 | struct GNUNET_HashCode port; | ||
1060 | |||
1061 | GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_INTERNET_RESOLVER, | ||
1062 | strlen (GNUNET_APPLICATION_PORT_INTERNET_RESOLVER), | ||
1063 | &port); | ||
1064 | candidate_count = 0; | ||
1065 | for (pos = exit_head; NULL != pos; pos = pos->next) | ||
1066 | if (NULL == pos->cadet_channel) | ||
1067 | candidate_count++; | ||
1068 | if (0 == candidate_count) | ||
1069 | { | ||
1070 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1071 | "No DNS exits available yet.\n"); | ||
1072 | return; | ||
1073 | } | ||
1074 | candidate_selected = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
1075 | candidate_count); | ||
1076 | candidate_count = 0; | ||
1077 | for (pos = exit_head; NULL != pos; pos = pos->next) | ||
1078 | if (NULL == pos->cadet_channel) | ||
1079 | { | ||
1080 | candidate_count++; | ||
1081 | if (candidate_selected < candidate_count) | ||
1082 | { | ||
1083 | struct GNUNET_MQ_MessageHandler cadet_handlers[] = { | ||
1084 | GNUNET_MQ_hd_var_size (dns_response, | ||
1085 | GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET, | ||
1086 | struct DnsResponseMessage, | ||
1087 | pos), | ||
1088 | GNUNET_MQ_handler_end () | ||
1089 | }; | ||
1090 | |||
1091 | |||
1092 | /* move to the head of the DLL */ | ||
1093 | pos->cadet_channel | ||
1094 | = GNUNET_CADET_channel_create (cadet_handle, | ||
1095 | pos, | ||
1096 | &pos->peer, | ||
1097 | &port, | ||
1098 | &channel_idle_notify_cb, | ||
1099 | &cadet_channel_end_cb, | ||
1100 | cadet_handlers); | ||
1101 | if (NULL == pos->cadet_channel) | ||
1102 | { | ||
1103 | GNUNET_break (0); | ||
1104 | continue; | ||
1105 | } | ||
1106 | GNUNET_CONTAINER_DLL_remove (exit_head, | ||
1107 | exit_tail, | ||
1108 | pos); | ||
1109 | GNUNET_CONTAINER_DLL_insert (exit_head, | ||
1110 | exit_tail, | ||
1111 | pos); | ||
1112 | dns_exit_available++; | ||
1113 | return; | ||
1114 | } | ||
1115 | } | ||
1116 | GNUNET_assert (NULL == exit_head); | ||
1117 | } | ||
1118 | |||
1119 | |||
1120 | /** | ||
1121 | * Function called whenever we find an advertisement for a | ||
1122 | * DNS exit in the DHT. If we don't have a cadet channel, | ||
1123 | * we should build one; otherwise, we should save the | ||
1124 | * advertisement for later use. | ||
1125 | * | ||
1126 | * @param cls closure | ||
1127 | * @param exp when will this value expire | ||
1128 | * @param key key of the result | ||
1129 | * @param trunc_peer peer that was truncated (or NULL if not truncated) | ||
1130 | * @param get_path peers on reply path (or NULL if not recorded) | ||
1131 | * [0] = datastore's first neighbor, [length - 1] = local peer | ||
1132 | * @param get_path_length number of entries in @a get_path | ||
1133 | * @param put_path peers on the PUT path (or NULL if not recorded) | ||
1134 | * [0] = origin, [length - 1] = datastore | ||
1135 | * @param put_path_length number of entries in @a put_path | ||
1136 | * @param type type of the result | ||
1137 | * @param size number of bytes in @a data | ||
1138 | * @param data pointer to the result data | ||
1139 | */ | ||
1140 | static void | ||
1141 | handle_dht_result (void *cls, | ||
1142 | struct GNUNET_TIME_Absolute exp, | ||
1143 | const struct GNUNET_HashCode *key, | ||
1144 | const struct GNUNET_PeerIdentity *trunc_peer, | ||
1145 | const struct GNUNET_DHT_PathElement *get_path, | ||
1146 | unsigned int get_path_length, | ||
1147 | const struct GNUNET_DHT_PathElement *put_path, | ||
1148 | unsigned int put_path_length, | ||
1149 | enum GNUNET_BLOCK_Type type, | ||
1150 | size_t size, const void *data) | ||
1151 | { | ||
1152 | const struct GNUNET_DNS_Advertisement *ad; | ||
1153 | struct CadetExit *exit; | ||
1154 | |||
1155 | if (sizeof(struct GNUNET_DNS_Advertisement) != size) | ||
1156 | { | ||
1157 | GNUNET_break (0); | ||
1158 | return; | ||
1159 | } | ||
1160 | ad = data; | ||
1161 | for (exit = exit_head; NULL != exit; exit = exit->next) | ||
1162 | if (0 == GNUNET_memcmp (&ad->peer, | ||
1163 | &exit->peer)) | ||
1164 | break; | ||
1165 | if (NULL == exit) | ||
1166 | { | ||
1167 | exit = GNUNET_new (struct CadetExit); | ||
1168 | exit->peer = ad->peer; | ||
1169 | /* channel is closed, so insert at the end */ | ||
1170 | GNUNET_CONTAINER_DLL_insert_tail (exit_head, | ||
1171 | exit_tail, | ||
1172 | exit); | ||
1173 | } | ||
1174 | exit->expiration = GNUNET_TIME_absolute_max (exit->expiration, | ||
1175 | GNUNET_TIME_absolute_ntoh ( | ||
1176 | ad->expiration_time)); | ||
1177 | if (dns_exit_available < MAX_OPEN_TUNNELS) | ||
1178 | try_open_exit (); | ||
1179 | } | ||
1180 | |||
1181 | |||
1182 | /** | ||
1183 | * @brief Main function that will be run by the scheduler. | ||
1184 | * | ||
1185 | * @param cls closure | ||
1186 | * @param args remaining command-line arguments | ||
1187 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | ||
1188 | * @param cfg_ configuration | ||
1189 | */ | ||
1190 | static void | ||
1191 | run (void *cls, char *const *args GNUNET_UNUSED, | ||
1192 | const char *cfgfile GNUNET_UNUSED, | ||
1193 | const struct GNUNET_CONFIGURATION_Handle *cfg_) | ||
1194 | { | ||
1195 | struct GNUNET_HashCode dns_key; | ||
1196 | |||
1197 | cfg = cfg_; | ||
1198 | stats = GNUNET_STATISTICS_create ("pt", | ||
1199 | cfg); | ||
1200 | ipv4_pt = GNUNET_CONFIGURATION_get_value_yesno (cfg, | ||
1201 | "pt", | ||
1202 | "TUNNEL_IPV4"); | ||
1203 | ipv6_pt = GNUNET_CONFIGURATION_get_value_yesno (cfg, | ||
1204 | "pt", | ||
1205 | "TUNNEL_IPV6"); | ||
1206 | dns_channel = GNUNET_CONFIGURATION_get_value_yesno (cfg, | ||
1207 | "pt", | ||
1208 | "TUNNEL_DNS"); | ||
1209 | if (! (ipv4_pt || ipv6_pt || dns_channel)) | ||
1210 | { | ||
1211 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1212 | _ ("No useful service enabled. Exiting.\n")); | ||
1213 | GNUNET_SCHEDULER_shutdown (); | ||
1214 | return; | ||
1215 | } | ||
1216 | GNUNET_SCHEDULER_add_shutdown (&cleanup, cls); | ||
1217 | if (ipv4_pt || ipv6_pt) | ||
1218 | { | ||
1219 | dns_post_handle | ||
1220 | = GNUNET_DNS_connect (cfg, | ||
1221 | GNUNET_DNS_FLAG_POST_RESOLUTION, | ||
1222 | &dns_post_request_handler, | ||
1223 | NULL); | ||
1224 | if (NULL == dns_post_handle) | ||
1225 | { | ||
1226 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1227 | _ ("Failed to connect to %s service. Exiting.\n"), | ||
1228 | "DNS"); | ||
1229 | GNUNET_SCHEDULER_shutdown (); | ||
1230 | return; | ||
1231 | } | ||
1232 | vpn_handle = GNUNET_VPN_connect (cfg); | ||
1233 | if (NULL == vpn_handle) | ||
1234 | { | ||
1235 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1236 | _ ("Failed to connect to %s service. Exiting.\n"), | ||
1237 | "VPN"); | ||
1238 | GNUNET_SCHEDULER_shutdown (); | ||
1239 | return; | ||
1240 | } | ||
1241 | } | ||
1242 | if (dns_channel) | ||
1243 | { | ||
1244 | dns_pre_handle | ||
1245 | = GNUNET_DNS_connect (cfg, | ||
1246 | GNUNET_DNS_FLAG_PRE_RESOLUTION, | ||
1247 | &dns_pre_request_handler, | ||
1248 | NULL); | ||
1249 | if (NULL == dns_pre_handle) | ||
1250 | { | ||
1251 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1252 | _ ("Failed to connect to %s service. Exiting.\n"), | ||
1253 | "DNS"); | ||
1254 | GNUNET_SCHEDULER_shutdown (); | ||
1255 | return; | ||
1256 | } | ||
1257 | cadet_handle = GNUNET_CADET_connect (cfg); | ||
1258 | if (NULL == cadet_handle) | ||
1259 | { | ||
1260 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1261 | _ ("Failed to connect to %s service. Exiting.\n"), | ||
1262 | "CADET"); | ||
1263 | GNUNET_SCHEDULER_shutdown (); | ||
1264 | return; | ||
1265 | } | ||
1266 | dht = GNUNET_DHT_connect (cfg, 1); | ||
1267 | if (NULL == dht) | ||
1268 | { | ||
1269 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1270 | _ ("Failed to connect to %s service. Exiting.\n"), | ||
1271 | "DHT"); | ||
1272 | GNUNET_SCHEDULER_shutdown (); | ||
1273 | return; | ||
1274 | } | ||
1275 | GNUNET_CRYPTO_hash ("dns", | ||
1276 | strlen ("dns"), | ||
1277 | &dns_key); | ||
1278 | dht_get = GNUNET_DHT_get_start (dht, | ||
1279 | GNUNET_BLOCK_TYPE_DNS, | ||
1280 | &dns_key, | ||
1281 | 1, | ||
1282 | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, | ||
1283 | NULL, 0, | ||
1284 | &handle_dht_result, | ||
1285 | NULL); | ||
1286 | } | ||
1287 | } | ||
1288 | |||
1289 | |||
1290 | /** | ||
1291 | * The main function | ||
1292 | * | ||
1293 | * @param argc number of arguments from the command line | ||
1294 | * @param argv command line arguments | ||
1295 | * @return 0 ok, 1 on error | ||
1296 | */ | ||
1297 | int | ||
1298 | main (int argc, | ||
1299 | char *const *argv) | ||
1300 | { | ||
1301 | static const struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
1302 | GNUNET_GETOPT_OPTION_END | ||
1303 | }; | ||
1304 | int ret; | ||
1305 | |||
1306 | if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, | ||
1307 | argv, | ||
1308 | &argc, | ||
1309 | &argv)) | ||
1310 | return 2; | ||
1311 | ret = (GNUNET_OK == | ||
1312 | GNUNET_PROGRAM_run (argc, | ||
1313 | argv, | ||
1314 | "gnunet-daemon-pt", | ||
1315 | gettext_noop ( | ||
1316 | "Daemon to run to perform IP protocol translation to GNUnet"), | ||
1317 | options, | ||
1318 | &run, | ||
1319 | NULL)) | ||
1320 | ? 0 | ||
1321 | : 1; | ||
1322 | GNUNET_free_nz ((void *) argv); | ||
1323 | return ret; | ||
1324 | } | ||
1325 | |||
1326 | |||
1327 | /* end of gnunet-daemon-pt.c */ | ||