2 This file is part of GNUnet.
3 Copyright (C) 2010, 2012 Christian Grothoff
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
22 * @file pt/gnunet-daemon-pt.c
23 * @brief tool to manipulate DNS and VPN services to perform protocol translation (IPvX over GNUnet)
24 * @author Christian Grothoff
27 #include "gnunet_util_lib.h"
28 #include "gnunet_dns_service.h"
29 #include "gnunet_dnsparser_lib.h"
30 #include "gnunet_cadet_service.h"
31 #include "gnunet_tun_lib.h"
32 #include "gnunet_dht_service.h"
33 #include "gnunet_vpn_service.h"
34 #include "gnunet_statistics_service.h"
35 #include "gnunet_applications.h"
36 #include "block_dns.h"
40 * After how long do we time out if we could not get an IP from VPN or CADET?
42 #define TIMEOUT GNUNET_TIME_UNIT_MINUTES
45 * How many bytes of payload do we allow at most for a DNS reply?
46 * Given that this is pretty much limited to loopback, we can be
47 * pretty high (Linux loopback defaults to 16k, most local UDP packets
48 * should survive up to 9k (NFS), so 8k should be pretty safe in
51 #define MAX_DNS_SIZE (8 * 1024)
54 * How many channels do we open at most at the same time?
56 #define MAX_OPEN_TUNNELS 4
60 * Which group of DNS records are we currently processing?
70 * DNS authority records
72 AUTHORITY_RECORDS = 1,
75 * DNS additional records
77 ADDITIONAL_RECORDS = 2,
80 * We're done processing.
87 * Information tracked per DNS reply that we are processing.
92 * Handle to submit the final result.
94 struct GNUNET_DNS_RequestHandle *rh;
97 * DNS packet that is being modified.
99 struct GNUNET_DNSPARSER_Packet *dns;
102 * Active redirection request with the VPN.
104 struct GNUNET_VPN_RedirectionRequest *rr;
107 * Record for which we have an active redirection request.
109 struct GNUNET_DNSPARSER_Record *rec;
112 * Offset in the current record group that is being modified.
117 * Group that is being modified
119 enum RequestGroup group;
125 * Handle to a peer that advertised that it is willing to serve
126 * as a DNS exit. We try to keep a few channels open and a few
135 struct CadetExit *next;
140 struct CadetExit *prev;
143 * Channel we use for DNS requests over CADET, NULL if we did
144 * not initialze a channel to this peer yet.
146 struct GNUNET_CADET_Channel *cadet_channel;
149 * At what time did the peer's advertisement expire?
151 struct GNUNET_TIME_Absolute expiration;
154 * Head of DLL of requests waiting for a response.
156 struct RequestContext *receive_queue_head;
159 * Tail of DLL of requests waiting for a response.
161 struct RequestContext *receive_queue_tail;
164 * Head of DLL of requests to be transmitted to a cadet_channel.
166 struct RequestContext *transmit_queue_head;
169 * Tail of DLL of requests to be transmitted to a cadet_channel.
171 struct RequestContext *transmit_queue_tail;
174 * Active transmission request for this channel (or NULL).
176 struct GNUNET_CADET_TransmitHandle *cadet_th;
179 * Identity of the peer that is providing the exit for us.
181 struct GNUNET_PeerIdentity peer;
184 * How many DNS requests did we transmit via this channel?
186 unsigned int num_transmitted;
189 * How many DNS requests were answered via this channel?
191 unsigned int num_answered;
198 * State we keep for a request that is going out via CADET.
200 struct RequestContext
203 * We keep these in a DLL.
205 struct RequestContext *next;
208 * We keep these in a DLL.
210 struct RequestContext *prev;
213 * Exit that was chosen for this request.
215 struct CadetExit *exit;
218 * Handle for interaction with DNS service.
220 struct GNUNET_DNS_RequestHandle *rh;
223 * Message we're sending out via CADET, allocated at the
224 * end of this struct.
226 const struct GNUNET_MessageHeader *cadet_message;
229 * Task used to abort this operation with timeout.
231 struct GNUNET_SCHEDULER_Task *timeout_task;
234 * Length of the request message that follows this struct.
239 * ID of the original DNS request (used to match the reply).
244 * #GNUNET_NO if this request is still in the transmit_queue,
245 * #GNUNET_YES if we are in the receive_queue.
247 int16_t was_transmitted;
253 * Head of DLL of cadet exits. Cadet exits with an open channel are
254 * always at the beginning (so we do not have to traverse the entire
255 * list to find them).
257 static struct CadetExit *exit_head;
260 * Tail of DLL of cadet exits.
262 static struct CadetExit *exit_tail;
265 * The handle to the configuration used throughout the process
267 static const struct GNUNET_CONFIGURATION_Handle *cfg;
270 * The handle to the VPN
272 static struct GNUNET_VPN_Handle *vpn_handle;
275 * The handle to the CADET service
277 static struct GNUNET_CADET_Handle *cadet_handle;
282 static struct GNUNET_STATISTICS_Handle *stats;
285 * The handle to DNS post-resolution modifications.
287 static struct GNUNET_DNS_Handle *dns_post_handle;
290 * The handle to DNS pre-resolution modifications.
292 static struct GNUNET_DNS_Handle *dns_pre_handle;
295 * Handle to access the DHT.
297 static struct GNUNET_DHT_Handle *dht;
300 * Our DHT GET operation to find DNS exits.
302 static struct GNUNET_DHT_GetHandle *dht_get;
305 * Are we doing IPv4-pt?
310 * Are we doing IPv6-pt?
315 * Are we channeling DNS queries?
317 static int dns_channel;
320 * Number of DNS exit peers we currently have in the cadet channel.
321 * Used to see if using the cadet channel makes any sense right now,
322 * as well as to decide if we should open new channels.
324 static unsigned int dns_exit_available;
328 * We are short on cadet exits, try to open another one.
333 struct CadetExit *pos;
334 uint32_t candidate_count;
335 uint32_t candidate_selected;
336 struct GNUNET_HashCode port;
338 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_INTERNET_RESOLVER,
339 strlen (GNUNET_APPLICATION_PORT_INTERNET_RESOLVER),
342 for (pos = exit_head; NULL != pos; pos = pos->next)
343 if (NULL == pos->cadet_channel)
345 if (0 == candidate_count)
347 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
348 "No DNS exits available yet.\n");
351 candidate_selected = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
354 for (pos = exit_head; NULL != pos; pos = pos->next)
355 if (NULL == pos->cadet_channel)
358 if (candidate_selected < candidate_count)
360 /* move to the head of the DLL */
362 = GNUNET_CADET_channel_create (cadet_handle,
366 GNUNET_CADET_OPTION_DEFAULT);
367 if (NULL == pos->cadet_channel)
372 GNUNET_CONTAINER_DLL_remove (exit_head,
375 GNUNET_CONTAINER_DLL_insert (exit_head,
378 dns_exit_available++;
382 GNUNET_assert (NULL == exit_head);
387 * Compute the weight of the given exit. The higher the weight,
388 * the more likely it will be that the channel will be chosen.
389 * A weigt of zero means that we should close the channel as it
390 * is so bad, that we should not use it.
392 * @param exit exit to calculate the weight for
393 * @return weight of the channel
396 get_channel_weight (struct CadetExit *exit)
399 uint32_t drop_percent;
400 uint32_t good_percent;
402 GNUNET_assert (exit->num_transmitted >= exit->num_answered);
403 dropped = exit->num_transmitted - exit->num_answered;
404 if (exit->num_transmitted > 0)
405 drop_percent = (uint32_t) ((100LL * dropped) / exit->num_transmitted);
407 drop_percent = 50; /* no data */
408 if ( (exit->num_transmitted > 20) &&
409 (drop_percent > 25) )
410 return 0; /* statistically significant, and > 25% loss, die */
411 good_percent = 100 - drop_percent;
412 GNUNET_assert (0 != good_percent);
413 if ( UINT32_MAX / good_percent / good_percent < exit->num_transmitted)
414 return UINT32_MAX; /* formula below would overflow */
415 return 1 + good_percent * good_percent * exit->num_transmitted;
420 * Choose a cadet exit for a DNS request. We try to use a channel
421 * that is reliable and currently available. All existing
422 * channels are given a base weight of 1, plus a score relating
423 * to the total number of queries answered in relation to the
424 * total number of queries we sent to that channel. That
425 * score is doubled if the channel is currently idle.
427 * @return NULL if no exit is known, otherwise the
428 * exit that we should use to queue a message with
430 static struct CadetExit *
433 struct CadetExit *pos;
434 uint64_t total_transmitted;
435 uint64_t selected_offset;
436 uint32_t channel_weight;
438 total_transmitted = 0;
439 for (pos = exit_head; NULL != pos; pos = pos->next)
441 if (NULL == pos->cadet_channel)
443 channel_weight = get_channel_weight (pos);
444 total_transmitted += channel_weight;
445 /* double weight for idle channels */
446 if (NULL == pos->cadet_th)
447 total_transmitted += channel_weight;
449 if (0 == total_transmitted)
451 /* no channels available, or only a very bad one... */
454 selected_offset = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
456 total_transmitted = 0;
457 for (pos = exit_head; NULL != pos; pos = pos->next)
459 if (NULL == pos->cadet_channel)
461 channel_weight = get_channel_weight (pos);
462 total_transmitted += channel_weight;
463 /* double weight for idle channels */
464 if (NULL == pos->cadet_th)
465 total_transmitted += channel_weight;
466 if (total_transmitted > selected_offset)
475 * We're done modifying all records in the response. Submit the reply
476 * and free the resources of the rc.
478 * @param rc context to process
481 finish_request (struct ReplyContext *rc)
487 GNUNET_DNSPARSER_pack (rc->dns,
492 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
493 _("Failed to pack DNS request. Dropping.\n"));
494 GNUNET_DNS_request_drop (rc->rh);
498 GNUNET_STATISTICS_update (stats,
499 gettext_noop ("# DNS requests mapped to VPN"),
501 GNUNET_DNS_request_answer (rc->rh,
506 GNUNET_DNSPARSER_free_packet (rc->dns);
512 * Process the next record of the given request context.
513 * When done, submit the reply and free the resources of
516 * @param rc context to process
519 submit_request (struct ReplyContext *rc);
523 * Callback invoked from the VPN service once a redirection is
524 * available. Provides the IP address that can now be used to
525 * reach the requested destination. We substitute the active
526 * record and then continue with 'submit_request' to look at
529 * @param cls our `struct ReplyContext`
530 * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error;
531 * will match 'result_af' from the request
532 * @param address IP address (struct in_addr or struct in_addr6, depending on 'af')
533 * that the VPN allocated for the redirection;
534 * traffic to this IP will now be redirected to the
535 * specified target peer; NULL on error
538 vpn_allocation_callback (void *cls,
542 struct ReplyContext *rc = cls;
547 GNUNET_DNS_request_drop (rc->rh);
548 GNUNET_DNSPARSER_free_packet (rc->dns);
552 GNUNET_STATISTICS_update (stats,
553 gettext_noop ("# DNS records modified"),
556 switch (rc->rec->type)
558 case GNUNET_DNSPARSER_TYPE_A:
559 GNUNET_assert (AF_INET == af);
560 GNUNET_memcpy (rc->rec->data.raw.data,
562 sizeof (struct in_addr));
564 case GNUNET_DNSPARSER_TYPE_AAAA:
565 GNUNET_assert (AF_INET6 == af);
566 GNUNET_memcpy (rc->rec->data.raw.data,
568 sizeof (struct in6_addr));
580 * Modify the given DNS record by asking VPN to create a channel
581 * to the given address. When done, continue with submitting
582 * other records from the request context ('submit_request' is
585 * @param rc context to process
586 * @param rec record to modify
589 modify_address (struct ReplyContext *rc,
590 struct GNUNET_DNSPARSER_Record *rec)
596 case GNUNET_DNSPARSER_TYPE_A:
598 GNUNET_assert (rec->data.raw.data_len == sizeof (struct in_addr));
600 case GNUNET_DNSPARSER_TYPE_AAAA:
602 GNUNET_assert (rec->data.raw.data_len == sizeof (struct in6_addr));
609 rc->rr = GNUNET_VPN_redirect_to_ip (vpn_handle,
613 GNUNET_TIME_relative_to_absolute (TIMEOUT),
614 &vpn_allocation_callback,
620 * Process the next record of the given request context.
621 * When done, submit the reply and free the resources of
624 * @param rc context to process
627 submit_request (struct ReplyContext *rc)
629 struct GNUNET_DNSPARSER_Record *ra;
638 ra = rc->dns->answers;
639 ra_len = rc->dns->num_answers;
641 case AUTHORITY_RECORDS:
642 ra = rc->dns->authority_records;
643 ra_len = rc->dns->num_authority_records;
645 case ADDITIONAL_RECORDS:
646 ra = rc->dns->additional_records;
647 ra_len = rc->dns->num_additional_records;
655 for (i=rc->offset;i<ra_len;i++)
659 case GNUNET_DNSPARSER_TYPE_A:
668 case GNUNET_DNSPARSER_TYPE_AAAA:
685 * Test if any of the given records need protocol-translation work.
687 * @param ra array of records
688 * @param ra_len number of entries in @a ra
689 * @return #GNUNET_YES if any of the given records require protocol-translation
692 work_test (const struct GNUNET_DNSPARSER_Record *ra,
697 for (i=0;i<ra_len;i++)
701 case GNUNET_DNSPARSER_TYPE_A:
705 case GNUNET_DNSPARSER_TYPE_AAAA:
716 * This function is called AFTER we got an IP address for a
717 * DNS request. Now, the PT daemon has the chance to substitute
718 * the IP address with one from the VPN range to channel requests
719 * destined for this IP address via VPN and CADET.
722 * @param rh request handle to user for reply
723 * @param request_length number of bytes in request
724 * @param request udp payload of the DNS request
727 dns_post_request_handler (void *cls,
728 struct GNUNET_DNS_RequestHandle *rh,
729 size_t request_length,
732 struct GNUNET_DNSPARSER_Packet *dns;
733 struct ReplyContext *rc;
736 GNUNET_STATISTICS_update (stats,
737 gettext_noop ("# DNS replies intercepted"),
739 dns = GNUNET_DNSPARSER_parse (request,
743 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
744 _("Failed to parse DNS request. Dropping.\n"));
745 GNUNET_DNS_request_drop (rh);
749 work |= work_test (dns->answers,
751 work |= work_test (dns->authority_records,
752 dns->num_authority_records);
753 work |= work_test (dns->additional_records,
754 dns->num_additional_records);
757 GNUNET_DNS_request_forward (rh);
758 GNUNET_DNSPARSER_free_packet (dns);
761 rc = GNUNET_new (struct ReplyContext);
771 * Transmit a DNS request via CADET and move the request
772 * handle to the receive queue.
774 * @param cls the `struct CadetExit`
775 * @param size number of bytes available in buf
776 * @param buf where to copy the message
777 * @return number of bytes written to buf
780 transmit_dns_request_to_cadet (void *cls,
784 struct CadetExit *exit = cls;
785 struct RequestContext *rc;
788 exit->cadet_th = NULL;
789 if (NULL == (rc = exit->transmit_queue_head))
795 = GNUNET_CADET_notify_transmit_ready (exit->cadet_channel,
799 &transmit_dns_request_to_cadet,
803 GNUNET_assert (GNUNET_NO == rc->was_transmitted);
807 GNUNET_CONTAINER_DLL_remove (exit->transmit_queue_head,
808 exit->transmit_queue_tail,
810 rc->was_transmitted = GNUNET_YES;
811 GNUNET_CONTAINER_DLL_insert (exit->receive_queue_head,
812 exit->receive_queue_tail,
814 rc = exit->transmit_queue_head;
816 exit->cadet_th = GNUNET_CADET_notify_transmit_ready (exit->cadet_channel,
820 &transmit_dns_request_to_cadet,
827 * Task run if the time to answer a DNS request via CADET is over.
829 * @param cls the `struct RequestContext` to abort
832 timeout_request (void *cls)
834 struct RequestContext *rc = cls;
835 struct CadetExit *exit = rc->exit;
837 if (rc->was_transmitted)
839 exit->num_transmitted++;
840 GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head,
841 exit->receive_queue_tail,
846 GNUNET_CONTAINER_DLL_remove (exit->transmit_queue_head,
847 exit->transmit_queue_tail,
850 GNUNET_STATISTICS_update (stats,
851 gettext_noop ("# DNS requests dropped (timeout)"),
854 GNUNET_DNS_request_drop (rc->rh);
856 if ( (0 == get_channel_weight (exit)) &&
857 (NULL == exit->receive_queue_head) &&
858 (NULL == exit->transmit_queue_head) )
860 /* this straw broke the camel's back: this channel now has
861 such a low score that it will not be used; close it! */
862 GNUNET_assert (NULL == exit->cadet_th);
863 GNUNET_CADET_channel_destroy (exit->cadet_channel);
864 exit->cadet_channel = NULL;
865 GNUNET_CONTAINER_DLL_remove (exit_head,
868 GNUNET_CONTAINER_DLL_insert_tail (exit_head,
871 /* go back to semi-innocent: mark as not great, but
872 avoid a prohibitively negative score (see
873 #get_channel_weight, which checks for a certain
874 minimum number of transmissions before making
876 exit->num_transmitted = 5;
877 exit->num_answered = 0;
878 dns_exit_available--;
879 /* now try to open an alternative exit */
886 * This function is called *before* the DNS request has been
887 * given to a "local" DNS resolver. Channeling for DNS requests
888 * was enabled, so we now need to send the request via some CADET
889 * channel to a DNS EXIT for resolution.
892 * @param rh request handle to user for reply
893 * @param request_length number of bytes in request
894 * @param request udp payload of the DNS request
897 dns_pre_request_handler (void *cls,
898 struct GNUNET_DNS_RequestHandle *rh,
899 size_t request_length,
902 struct RequestContext *rc;
904 struct GNUNET_MessageHeader hdr;
905 struct GNUNET_TUN_DnsHeader dns;
906 struct CadetExit *exit;
908 GNUNET_STATISTICS_update (stats,
909 gettext_noop ("# DNS requests intercepted"),
911 if (0 == dns_exit_available)
913 GNUNET_STATISTICS_update (stats,
914 gettext_noop ("# DNS requests dropped (DNS cadet channel down)"),
916 GNUNET_DNS_request_drop (rh);
919 if (request_length < sizeof (dns))
921 GNUNET_STATISTICS_update (stats,
922 gettext_noop ("# DNS requests dropped (malformed)"),
924 GNUNET_DNS_request_drop (rh);
927 GNUNET_memcpy (&dns, request, sizeof (dns));
928 mlen = sizeof (struct GNUNET_MessageHeader) + request_length;
929 exit = choose_exit ();
930 GNUNET_assert (NULL != exit);
931 GNUNET_assert (NULL != exit->cadet_channel);
932 rc = GNUNET_malloc (sizeof (struct RequestContext) + mlen);
935 rc->cadet_message = (const struct GNUNET_MessageHeader*) &rc[1];
936 rc->timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
941 hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_TO_INTERNET);
942 hdr.size = htons (mlen);
943 GNUNET_memcpy (&rc[1], &hdr, sizeof (struct GNUNET_MessageHeader));
944 GNUNET_memcpy (&(((char*)&rc[1])[sizeof (struct GNUNET_MessageHeader)]),
947 GNUNET_CONTAINER_DLL_insert_tail (exit->transmit_queue_head,
948 exit->transmit_queue_tail,
950 if (NULL == exit->cadet_th)
951 exit->cadet_th = GNUNET_CADET_notify_transmit_ready (exit->cadet_channel,
955 &transmit_dns_request_to_cadet,
961 * Process a request via cadet to perform a DNS query.
964 * @param channel connection to the other end
965 * @param channel_ctx pointer to our `struct CadetExit`
966 * @param message the actual message
967 * @return #GNUNET_OK to keep the connection open,
968 * #GNUNET_SYSERR to close it (signal serious error)
971 receive_dns_response (void *cls,
972 struct GNUNET_CADET_Channel *channel,
974 const struct GNUNET_MessageHeader *message)
976 struct CadetExit *exit = *channel_ctx;
977 struct GNUNET_TUN_DnsHeader dns;
979 struct RequestContext *rc;
981 mlen = ntohs (message->size);
982 mlen -= sizeof (struct GNUNET_MessageHeader);
983 if (mlen < sizeof (struct GNUNET_TUN_DnsHeader))
986 return GNUNET_SYSERR;
988 GNUNET_memcpy (&dns, &message[1], sizeof (dns));
989 for (rc = exit->receive_queue_head; NULL != rc; rc = rc->next)
991 GNUNET_assert (GNUNET_YES == rc->was_transmitted);
992 if (dns.id == rc->dns_id)
994 GNUNET_STATISTICS_update (stats,
995 gettext_noop ("# DNS replies received"),
997 GNUNET_DNS_request_answer (rc->rh,
999 (const void*) &message[1]);
1000 GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head,
1001 exit->receive_queue_tail,
1003 GNUNET_SCHEDULER_cancel (rc->timeout_task);
1005 exit->num_answered++;
1006 exit->num_transmitted++;
1010 GNUNET_STATISTICS_update (stats,
1011 gettext_noop ("# DNS replies dropped (too late?)"),
1018 * Abort all pending DNS requests with the given cadet exit.
1020 * @param exit cadet exit to abort requests for
1023 abort_all_requests (struct CadetExit *exit)
1025 struct RequestContext *rc;
1027 while (NULL != (rc = exit->receive_queue_head))
1029 GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head,
1030 exit->receive_queue_tail,
1032 GNUNET_DNS_request_drop (rc->rh);
1033 GNUNET_SCHEDULER_cancel (rc->timeout_task);
1036 while (NULL != (rc = exit->transmit_queue_head))
1038 GNUNET_CONTAINER_DLL_remove (exit->transmit_queue_head,
1039 exit->transmit_queue_tail,
1041 GNUNET_DNS_request_drop (rc->rh);
1042 GNUNET_SCHEDULER_cancel (rc->timeout_task);
1049 * Function scheduled as very last function, cleans up after us
1051 * @param cls closure, NULL
1056 struct CadetExit *exit;
1058 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1059 "Protocol translation daemon is shutting down now\n");
1060 if (NULL != vpn_handle)
1062 GNUNET_VPN_disconnect (vpn_handle);
1065 while (NULL != (exit = exit_head))
1067 GNUNET_CONTAINER_DLL_remove (exit_head,
1070 if (NULL != exit->cadet_th)
1072 GNUNET_CADET_notify_transmit_ready_cancel (exit->cadet_th);
1073 exit->cadet_th = NULL;
1075 if (NULL != exit->cadet_channel)
1077 GNUNET_CADET_channel_destroy (exit->cadet_channel);
1078 exit->cadet_channel = NULL;
1080 abort_all_requests (exit);
1083 if (NULL != cadet_handle)
1085 GNUNET_CADET_disconnect (cadet_handle);
1086 cadet_handle = NULL;
1088 if (NULL != dns_post_handle)
1090 GNUNET_DNS_disconnect (dns_post_handle);
1091 dns_post_handle = NULL;
1093 if (NULL != dns_pre_handle)
1095 GNUNET_DNS_disconnect (dns_pre_handle);
1096 dns_pre_handle = NULL;
1100 GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
1103 if (NULL != dht_get)
1105 GNUNET_DHT_get_stop (dht_get);
1110 GNUNET_DHT_disconnect (dht);
1117 * Function called whenever a channel is destroyed. Should clean up
1118 * the associated state and attempt to build a new one.
1120 * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
1122 * @param cls closure (the `struct CadetExit` set from #GNUNET_CADET_connect)
1123 * @param channel connection to the other end (henceforth invalid)
1124 * @param channel_ctx place where local state associated
1125 * with the channel is stored
1128 cadet_channel_end_cb (void *cls,
1129 const struct GNUNET_CADET_Channel *channel,
1132 struct CadetExit *exit = channel_ctx;
1133 struct CadetExit *alt;
1134 struct RequestContext *rc;
1136 if (NULL != exit->cadet_th)
1138 GNUNET_CADET_notify_transmit_ready_cancel (exit->cadet_th);
1139 exit->cadet_th = NULL;
1141 exit->cadet_channel = NULL;
1142 dns_exit_available--;
1143 /* open alternative channels */
1145 if (NULL == exit->cadet_channel)
1147 /* our channel is now closed, move our requests to an alternative
1149 alt = choose_exit ();
1150 while (NULL != (rc = exit->transmit_queue_head))
1152 GNUNET_CONTAINER_DLL_remove (exit->transmit_queue_head,
1153 exit->transmit_queue_tail,
1156 GNUNET_CONTAINER_DLL_insert (alt->transmit_queue_head,
1157 alt->transmit_queue_tail,
1160 while (NULL != (rc = exit->receive_queue_head))
1162 GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head,
1163 exit->receive_queue_tail,
1165 rc->was_transmitted = GNUNET_NO;
1167 GNUNET_CONTAINER_DLL_insert (alt->transmit_queue_head,
1168 alt->transmit_queue_tail,
1174 /* the same peer was chosen, just make sure the queue processing is restarted */
1177 if ( (NULL == alt->cadet_th) &&
1178 (NULL != (rc = alt->transmit_queue_head)) )
1180 = GNUNET_CADET_notify_transmit_ready (alt->cadet_channel,
1184 &transmit_dns_request_to_cadet,
1190 * Function called whenever we find an advertisement for a
1191 * DNS exit in the DHT. If we don't have a cadet channel,
1192 * we should build one; otherwise, we should save the
1193 * advertisement for later use.
1195 * @param cls closure
1196 * @param exp when will this value expire
1197 * @param key key of the result
1198 * @param get_path peers on reply path (or NULL if not recorded)
1199 * [0] = datastore's first neighbor, [length - 1] = local peer
1200 * @param get_path_length number of entries in @a get_path
1201 * @param put_path peers on the PUT path (or NULL if not recorded)
1202 * [0] = origin, [length - 1] = datastore
1203 * @param put_path_length number of entries in @a put_path
1204 * @param type type of the result
1205 * @param size number of bytes in @a data
1206 * @param data pointer to the result data
1209 handle_dht_result (void *cls,
1210 struct GNUNET_TIME_Absolute exp,
1211 const struct GNUNET_HashCode *key,
1212 const struct GNUNET_PeerIdentity *get_path,
1213 unsigned int get_path_length,
1214 const struct GNUNET_PeerIdentity *put_path,
1215 unsigned int put_path_length,
1216 enum GNUNET_BLOCK_Type type,
1217 size_t size, const void *data)
1219 const struct GNUNET_DNS_Advertisement *ad;
1220 struct CadetExit *exit;
1222 if (sizeof (struct GNUNET_DNS_Advertisement) != size)
1228 for (exit = exit_head; NULL != exit; exit = exit->next)
1229 if (0 == memcmp (&ad->peer,
1231 sizeof (struct GNUNET_PeerIdentity)))
1235 exit = GNUNET_new (struct CadetExit);
1236 exit->peer = ad->peer;
1237 /* channel is closed, so insert at the end */
1238 GNUNET_CONTAINER_DLL_insert_tail (exit_head,
1242 exit->expiration = GNUNET_TIME_absolute_max (exit->expiration,
1243 GNUNET_TIME_absolute_ntoh (ad->expiration_time));
1244 if (dns_exit_available < MAX_OPEN_TUNNELS)
1250 * @brief Main function that will be run by the scheduler.
1252 * @param cls closure
1253 * @param args remaining command-line arguments
1254 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1255 * @param cfg_ configuration
1258 run (void *cls, char *const *args GNUNET_UNUSED,
1259 const char *cfgfile GNUNET_UNUSED,
1260 const struct GNUNET_CONFIGURATION_Handle *cfg_)
1262 struct GNUNET_HashCode dns_key;
1265 stats = GNUNET_STATISTICS_create ("pt",
1267 ipv4_pt = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1270 ipv6_pt = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1273 dns_channel = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1276 if (! (ipv4_pt || ipv6_pt || dns_channel))
1278 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1279 _("No useful service enabled. Exiting.\n"));
1280 GNUNET_SCHEDULER_shutdown ();
1283 GNUNET_SCHEDULER_add_shutdown (&cleanup, cls);
1284 if (ipv4_pt || ipv6_pt)
1287 = GNUNET_DNS_connect (cfg,
1288 GNUNET_DNS_FLAG_POST_RESOLUTION,
1289 &dns_post_request_handler,
1291 if (NULL == dns_post_handle)
1293 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1294 _("Failed to connect to %s service. Exiting.\n"),
1296 GNUNET_SCHEDULER_shutdown ();
1299 vpn_handle = GNUNET_VPN_connect (cfg);
1300 if (NULL == vpn_handle)
1302 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1303 _("Failed to connect to %s service. Exiting.\n"),
1305 GNUNET_SCHEDULER_shutdown ();
1311 static struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1312 {&receive_dns_response, GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET, 0},
1317 = GNUNET_DNS_connect (cfg,
1318 GNUNET_DNS_FLAG_PRE_RESOLUTION,
1319 &dns_pre_request_handler,
1321 if (NULL == dns_pre_handle)
1323 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1324 _("Failed to connect to %s service. Exiting.\n"),
1326 GNUNET_SCHEDULER_shutdown ();
1329 cadet_handle = GNUNET_CADET_connect (cfg,
1331 &cadet_channel_end_cb,
1333 if (NULL == cadet_handle)
1335 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1336 _("Failed to connect to %s service. Exiting.\n"),
1338 GNUNET_SCHEDULER_shutdown ();
1341 dht = GNUNET_DHT_connect (cfg, 1);
1344 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1345 _("Failed to connect to %s service. Exiting.\n"),
1347 GNUNET_SCHEDULER_shutdown ();
1350 GNUNET_CRYPTO_hash ("dns",
1353 dht_get = GNUNET_DHT_get_start (dht,
1354 GNUNET_BLOCK_TYPE_DNS,
1357 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
1368 * @param argc number of arguments from the command line
1369 * @param argv command line arguments
1370 * @return 0 ok, 1 on error
1376 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1377 GNUNET_GETOPT_OPTION_END
1381 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc,
1387 GNUNET_PROGRAM_run (argc,
1390 gettext_noop ("Daemon to run to perform IP protocol translation to GNUnet"),
1396 GNUNET_free ((void*) argv);
1401 /* end of gnunet-daemon-pt.c */