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;
338 for (pos = exit_head; NULL != pos; pos = pos->next)
339 if (NULL == pos->cadet_channel)
341 candidate_selected = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
344 for (pos = exit_head; NULL != pos; pos = pos->next)
345 if (NULL == pos->cadet_channel)
348 if (candidate_selected < candidate_count)
350 /* move to the head of the DLL */
351 pos->cadet_channel = GNUNET_CADET_channel_create (cadet_handle,
354 GNUNET_APPLICATION_TYPE_INTERNET_RESOLVER,
355 GNUNET_CADET_OPTION_DEFAULT);
356 if (NULL == pos->cadet_channel)
361 GNUNET_CONTAINER_DLL_remove (exit_head,
364 GNUNET_CONTAINER_DLL_insert (exit_head,
367 dns_exit_available++;
371 GNUNET_assert (NULL == exit_head);
376 * Compute the weight of the given exit. The higher the weight,
377 * the more likely it will be that the channel will be chosen.
378 * A weigt of zero means that we should close the channel as it
379 * is so bad, that we should not use it.
381 * @param exit exit to calculate the weight for
382 * @return weight of the channel
385 get_channel_weight (struct CadetExit *exit)
388 uint32_t drop_percent;
389 uint32_t good_percent;
391 GNUNET_assert (exit->num_transmitted >= exit->num_answered);
392 dropped = exit->num_transmitted - exit->num_answered;
393 if (exit->num_transmitted > 0)
394 drop_percent = (uint32_t) ((100LL * dropped) / exit->num_transmitted);
396 drop_percent = 50; /* no data */
397 if ( (exit->num_transmitted > 20) &&
398 (drop_percent > 25) )
399 return 0; /* statistically significant, and > 25% loss, die */
400 good_percent = 100 - drop_percent;
401 GNUNET_assert (0 != good_percent);
402 if ( UINT32_MAX / good_percent / good_percent < exit->num_transmitted)
403 return UINT32_MAX; /* formula below would overflow */
404 return 1 + good_percent * good_percent * exit->num_transmitted;
409 * Choose a cadet exit for a DNS request. We try to use a channel
410 * that is reliable and currently available. All existing
411 * channels are given a base weight of 1, plus a score relating
412 * to the total number of queries answered in relation to the
413 * total number of queries we sent to that channel. That
414 * score is doubled if the channel is currently idle.
416 * @return NULL if no exit is known, otherwise the
417 * exit that we should use to queue a message with
419 static struct CadetExit *
422 struct CadetExit *pos;
423 uint64_t total_transmitted;
424 uint64_t selected_offset;
425 uint32_t channel_weight;
427 total_transmitted = 0;
428 for (pos = exit_head; NULL != pos; pos = pos->next)
430 if (NULL == pos->cadet_channel)
432 channel_weight = get_channel_weight (pos);
433 total_transmitted += channel_weight;
434 /* double weight for idle channels */
435 if (NULL == pos->cadet_th)
436 total_transmitted += channel_weight;
438 if (0 == total_transmitted)
440 /* no channels available, or only a very bad one... */
443 selected_offset = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
445 total_transmitted = 0;
446 for (pos = exit_head; NULL != pos; pos = pos->next)
448 if (NULL == pos->cadet_channel)
450 channel_weight = get_channel_weight (pos);
451 total_transmitted += channel_weight;
452 /* double weight for idle channels */
453 if (NULL == pos->cadet_th)
454 total_transmitted += channel_weight;
455 if (total_transmitted > selected_offset)
464 * We're done modifying all records in the response. Submit the reply
465 * and free the resources of the rc.
467 * @param rc context to process
470 finish_request (struct ReplyContext *rc)
476 GNUNET_DNSPARSER_pack (rc->dns,
481 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
482 _("Failed to pack DNS request. Dropping.\n"));
483 GNUNET_DNS_request_drop (rc->rh);
487 GNUNET_STATISTICS_update (stats,
488 gettext_noop ("# DNS requests mapped to VPN"),
490 GNUNET_DNS_request_answer (rc->rh,
494 GNUNET_DNSPARSER_free_packet (rc->dns);
500 * Process the next record of the given request context.
501 * When done, submit the reply and free the resources of
504 * @param rc context to process
507 submit_request (struct ReplyContext *rc);
511 * Callback invoked from the VPN service once a redirection is
512 * available. Provides the IP address that can now be used to
513 * reach the requested destination. We substitute the active
514 * record and then continue with 'submit_request' to look at
517 * @param cls our `struct ReplyContext`
518 * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error;
519 * will match 'result_af' from the request
520 * @param address IP address (struct in_addr or struct in_addr6, depending on 'af')
521 * that the VPN allocated for the redirection;
522 * traffic to this IP will now be redirected to the
523 * specified target peer; NULL on error
526 vpn_allocation_callback (void *cls,
530 struct ReplyContext *rc = cls;
535 GNUNET_DNS_request_drop (rc->rh);
536 GNUNET_DNSPARSER_free_packet (rc->dns);
540 GNUNET_STATISTICS_update (stats,
541 gettext_noop ("# DNS records modified"),
543 switch (rc->rec->type)
545 case GNUNET_DNSPARSER_TYPE_A:
546 GNUNET_assert (AF_INET == af);
547 memcpy (rc->rec->data.raw.data, address, sizeof (struct in_addr));
549 case GNUNET_DNSPARSER_TYPE_AAAA:
550 GNUNET_assert (AF_INET6 == af);
551 memcpy (rc->rec->data.raw.data, address, sizeof (struct in6_addr));
563 * Modify the given DNS record by asking VPN to create a channel
564 * to the given address. When done, continue with submitting
565 * other records from the request context ('submit_request' is
568 * @param rc context to process
569 * @param rec record to modify
572 modify_address (struct ReplyContext *rc,
573 struct GNUNET_DNSPARSER_Record *rec)
579 case GNUNET_DNSPARSER_TYPE_A:
581 GNUNET_assert (rec->data.raw.data_len == sizeof (struct in_addr));
583 case GNUNET_DNSPARSER_TYPE_AAAA:
585 GNUNET_assert (rec->data.raw.data_len == sizeof (struct in6_addr));
592 rc->rr = GNUNET_VPN_redirect_to_ip (vpn_handle,
595 GNUNET_TIME_relative_to_absolute (TIMEOUT),
596 &vpn_allocation_callback,
602 * Process the next record of the given request context.
603 * When done, submit the reply and free the resources of
606 * @param rc context to process
609 submit_request (struct ReplyContext *rc)
611 struct GNUNET_DNSPARSER_Record *ra;
620 ra = rc->dns->answers;
621 ra_len = rc->dns->num_answers;
623 case AUTHORITY_RECORDS:
624 ra = rc->dns->authority_records;
625 ra_len = rc->dns->num_authority_records;
627 case ADDITIONAL_RECORDS:
628 ra = rc->dns->additional_records;
629 ra_len = rc->dns->num_additional_records;
637 for (i=rc->offset;i<ra_len;i++)
641 case GNUNET_DNSPARSER_TYPE_A:
645 modify_address (rc, &ra[i]);
649 case GNUNET_DNSPARSER_TYPE_AAAA:
653 modify_address (rc, &ra[i]);
665 * Test if any of the given records need protocol-translation work.
667 * @param ra array of records
668 * @param ra_len number of entries in @a ra
669 * @return #GNUNET_YES if any of the given records require protocol-translation
672 work_test (const struct GNUNET_DNSPARSER_Record *ra,
677 for (i=0;i<ra_len;i++)
681 case GNUNET_DNSPARSER_TYPE_A:
685 case GNUNET_DNSPARSER_TYPE_AAAA:
696 * This function is called AFTER we got an IP address for a
697 * DNS request. Now, the PT daemon has the chance to substitute
698 * the IP address with one from the VPN range to channel requests
699 * destined for this IP address via VPN and CADET.
702 * @param rh request handle to user for reply
703 * @param request_length number of bytes in request
704 * @param request udp payload of the DNS request
707 dns_post_request_handler (void *cls,
708 struct GNUNET_DNS_RequestHandle *rh,
709 size_t request_length,
712 struct GNUNET_DNSPARSER_Packet *dns;
713 struct ReplyContext *rc;
716 GNUNET_STATISTICS_update (stats,
717 gettext_noop ("# DNS replies intercepted"),
719 dns = GNUNET_DNSPARSER_parse (request, request_length);
722 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
723 _("Failed to parse DNS request. Dropping.\n"));
724 GNUNET_DNS_request_drop (rh);
728 work |= work_test (dns->answers, dns->num_answers);
729 work |= work_test (dns->authority_records, dns->num_authority_records);
730 work |= work_test (dns->additional_records, dns->num_additional_records);
733 GNUNET_DNS_request_forward (rh);
734 GNUNET_DNSPARSER_free_packet (dns);
737 rc = GNUNET_new (struct ReplyContext);
747 * Transmit a DNS request via CADET and move the request
748 * handle to the receive queue.
750 * @param cls the `struct CadetExit`
751 * @param size number of bytes available in buf
752 * @param buf where to copy the message
753 * @return number of bytes written to buf
756 transmit_dns_request_to_cadet (void *cls,
760 struct CadetExit *exit = cls;
761 struct RequestContext *rc;
764 exit->cadet_th = NULL;
765 if (NULL == (rc = exit->transmit_queue_head))
770 exit->cadet_th = GNUNET_CADET_notify_transmit_ready (exit->cadet_channel,
774 &transmit_dns_request_to_cadet,
778 GNUNET_assert (GNUNET_NO == rc->was_transmitted);
779 memcpy (buf, rc->cadet_message, mlen);
780 GNUNET_CONTAINER_DLL_remove (exit->transmit_queue_head,
781 exit->transmit_queue_tail,
783 rc->was_transmitted = GNUNET_YES;
784 GNUNET_CONTAINER_DLL_insert (exit->receive_queue_head,
785 exit->receive_queue_tail,
787 rc = exit->transmit_queue_head;
789 exit->cadet_th = GNUNET_CADET_notify_transmit_ready (exit->cadet_channel,
793 &transmit_dns_request_to_cadet,
800 * Task run if the time to answer a DNS request via CADET is over.
802 * @param cls the `struct RequestContext` to abort
805 timeout_request (void *cls)
807 struct RequestContext *rc = cls;
808 struct CadetExit *exit = rc->exit;
810 if (rc->was_transmitted)
812 exit->num_transmitted++;
813 GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head,
814 exit->receive_queue_tail,
819 GNUNET_CONTAINER_DLL_remove (exit->transmit_queue_head,
820 exit->transmit_queue_tail,
823 GNUNET_STATISTICS_update (stats,
824 gettext_noop ("# DNS requests dropped (timeout)"),
826 GNUNET_DNS_request_drop (rc->rh);
828 if ( (0 == get_channel_weight (exit)) &&
829 (NULL == exit->receive_queue_head) &&
830 (NULL == exit->transmit_queue_head) )
832 /* this straw broke the camel's back: this channel now has
833 such a low score that it will not be used; close it! */
834 GNUNET_assert (NULL == exit->cadet_th);
835 GNUNET_CADET_channel_destroy (exit->cadet_channel);
836 exit->cadet_channel = NULL;
837 GNUNET_CONTAINER_DLL_remove (exit_head,
840 GNUNET_CONTAINER_DLL_insert_tail (exit_head,
843 /* go back to semi-innocent: mark as not great, but
844 avoid a prohibitively negative score (see
845 #get_channel_weight, which checks for a certain
846 minimum number of transmissions before making
848 exit->num_transmitted = 5;
849 exit->num_answered = 0;
850 dns_exit_available--;
851 /* now try to open an alternative exit */
858 * This function is called *before* the DNS request has been
859 * given to a "local" DNS resolver. Channeling for DNS requests
860 * was enabled, so we now need to send the request via some CADET
861 * channel to a DNS EXIT for resolution.
864 * @param rh request handle to user for reply
865 * @param request_length number of bytes in request
866 * @param request udp payload of the DNS request
869 dns_pre_request_handler (void *cls,
870 struct GNUNET_DNS_RequestHandle *rh,
871 size_t request_length,
874 struct RequestContext *rc;
876 struct GNUNET_MessageHeader hdr;
877 struct GNUNET_TUN_DnsHeader dns;
878 struct CadetExit *exit;
880 GNUNET_STATISTICS_update (stats,
881 gettext_noop ("# DNS requests intercepted"),
883 if (0 == dns_exit_available)
885 GNUNET_STATISTICS_update (stats,
886 gettext_noop ("# DNS requests dropped (DNS cadet channel down)"),
888 GNUNET_DNS_request_drop (rh);
891 if (request_length < sizeof (dns))
893 GNUNET_STATISTICS_update (stats,
894 gettext_noop ("# DNS requests dropped (malformed)"),
896 GNUNET_DNS_request_drop (rh);
899 memcpy (&dns, request, sizeof (dns));
900 mlen = sizeof (struct GNUNET_MessageHeader) + request_length;
901 exit = choose_exit ();
902 GNUNET_assert (NULL != exit);
903 GNUNET_assert (NULL != exit->cadet_channel);
904 rc = GNUNET_malloc (sizeof (struct RequestContext) + mlen);
907 rc->cadet_message = (const struct GNUNET_MessageHeader*) &rc[1];
908 rc->timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
913 hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_TO_INTERNET);
914 hdr.size = htons (mlen);
915 memcpy (&rc[1], &hdr, sizeof (struct GNUNET_MessageHeader));
916 memcpy (&(((char*)&rc[1])[sizeof (struct GNUNET_MessageHeader)]),
919 GNUNET_CONTAINER_DLL_insert_tail (exit->transmit_queue_head,
920 exit->transmit_queue_tail,
922 if (NULL == exit->cadet_th)
923 exit->cadet_th = GNUNET_CADET_notify_transmit_ready (exit->cadet_channel,
927 &transmit_dns_request_to_cadet,
933 * Process a request via cadet to perform a DNS query.
936 * @param channel connection to the other end
937 * @param channel_ctx pointer to our `struct CadetExit`
938 * @param message the actual message
939 * @return #GNUNET_OK to keep the connection open,
940 * #GNUNET_SYSERR to close it (signal serious error)
943 receive_dns_response (void *cls,
944 struct GNUNET_CADET_Channel *channel,
946 const struct GNUNET_MessageHeader *message)
948 struct CadetExit *exit = *channel_ctx;
949 struct GNUNET_TUN_DnsHeader dns;
951 struct RequestContext *rc;
953 mlen = ntohs (message->size);
954 mlen -= sizeof (struct GNUNET_MessageHeader);
955 if (mlen < sizeof (struct GNUNET_TUN_DnsHeader))
958 return GNUNET_SYSERR;
960 memcpy (&dns, &message[1], sizeof (dns));
961 for (rc = exit->receive_queue_head; NULL != rc; rc = rc->next)
963 GNUNET_assert (GNUNET_YES == rc->was_transmitted);
964 if (dns.id == rc->dns_id)
966 GNUNET_STATISTICS_update (stats,
967 gettext_noop ("# DNS replies received"),
969 GNUNET_DNS_request_answer (rc->rh,
971 (const void*) &message[1]);
972 GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head,
973 exit->receive_queue_tail,
975 GNUNET_SCHEDULER_cancel (rc->timeout_task);
977 exit->num_answered++;
978 exit->num_transmitted++;
982 GNUNET_STATISTICS_update (stats,
983 gettext_noop ("# DNS replies dropped (too late?)"),
990 * Abort all pending DNS requests with the given cadet exit.
992 * @param exit cadet exit to abort requests for
995 abort_all_requests (struct CadetExit *exit)
997 struct RequestContext *rc;
999 while (NULL != (rc = exit->receive_queue_head))
1001 GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head,
1002 exit->receive_queue_tail,
1004 GNUNET_DNS_request_drop (rc->rh);
1005 GNUNET_SCHEDULER_cancel (rc->timeout_task);
1008 while (NULL != (rc = exit->transmit_queue_head))
1010 GNUNET_CONTAINER_DLL_remove (exit->transmit_queue_head,
1011 exit->transmit_queue_tail,
1013 GNUNET_DNS_request_drop (rc->rh);
1014 GNUNET_SCHEDULER_cancel (rc->timeout_task);
1021 * Function scheduled as very last function, cleans up after us
1023 * @param cls closure, NULL
1028 struct CadetExit *exit;
1030 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1031 "Protocol translation daemon is shutting down now\n");
1032 if (NULL != vpn_handle)
1034 GNUNET_VPN_disconnect (vpn_handle);
1037 while (NULL != (exit = exit_head))
1039 GNUNET_CONTAINER_DLL_remove (exit_head,
1042 if (NULL != exit->cadet_th)
1044 GNUNET_CADET_notify_transmit_ready_cancel (exit->cadet_th);
1045 exit->cadet_th = NULL;
1047 if (NULL != exit->cadet_channel)
1049 GNUNET_CADET_channel_destroy (exit->cadet_channel);
1050 exit->cadet_channel = NULL;
1052 abort_all_requests (exit);
1055 if (NULL != cadet_handle)
1057 GNUNET_CADET_disconnect (cadet_handle);
1058 cadet_handle = NULL;
1060 if (NULL != dns_post_handle)
1062 GNUNET_DNS_disconnect (dns_post_handle);
1063 dns_post_handle = NULL;
1065 if (NULL != dns_pre_handle)
1067 GNUNET_DNS_disconnect (dns_pre_handle);
1068 dns_pre_handle = NULL;
1072 GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
1075 if (NULL != dht_get)
1077 GNUNET_DHT_get_stop (dht_get);
1082 GNUNET_DHT_disconnect (dht);
1089 * Function called whenever a channel is destroyed. Should clean up
1090 * the associated state and attempt to build a new one.
1092 * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
1094 * @param cls closure (the `struct CadetExit` set from #GNUNET_CADET_connect)
1095 * @param channel connection to the other end (henceforth invalid)
1096 * @param channel_ctx place where local state associated
1097 * with the channel is stored
1100 cadet_channel_end_cb (void *cls,
1101 const struct GNUNET_CADET_Channel *channel,
1104 struct CadetExit *exit = channel_ctx;
1105 struct CadetExit *alt;
1106 struct RequestContext *rc;
1108 if (NULL != exit->cadet_th)
1110 GNUNET_CADET_notify_transmit_ready_cancel (exit->cadet_th);
1111 exit->cadet_th = NULL;
1113 exit->cadet_channel = NULL;
1114 dns_exit_available--;
1115 /* open alternative channels */
1117 if (NULL == exit->cadet_channel)
1119 /* our channel is now closed, move our requests to an alternative
1121 alt = choose_exit ();
1122 while (NULL != (rc = exit->transmit_queue_head))
1124 GNUNET_CONTAINER_DLL_remove (exit->transmit_queue_head,
1125 exit->transmit_queue_tail,
1128 GNUNET_CONTAINER_DLL_insert (alt->transmit_queue_head,
1129 alt->transmit_queue_tail,
1132 while (NULL != (rc = exit->receive_queue_head))
1134 GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head,
1135 exit->receive_queue_tail,
1137 rc->was_transmitted = GNUNET_NO;
1139 GNUNET_CONTAINER_DLL_insert (alt->transmit_queue_head,
1140 alt->transmit_queue_tail,
1146 /* the same peer was chosen, just make sure the queue processing is restarted */
1149 if ( (NULL == alt->cadet_th) &&
1150 (NULL != (rc = alt->transmit_queue_head)) )
1151 alt->cadet_th = GNUNET_CADET_notify_transmit_ready (alt->cadet_channel,
1155 &transmit_dns_request_to_cadet,
1161 * Function called whenever we find an advertisement for a
1162 * DNS exit in the DHT. If we don't have a cadet channel,
1163 * we should build one; otherwise, we should save the
1164 * advertisement for later use.
1166 * @param cls closure
1167 * @param exp when will this value expire
1168 * @param key key of the result
1169 * @param get_path peers on reply path (or NULL if not recorded)
1170 * [0] = datastore's first neighbor, [length - 1] = local peer
1171 * @param get_path_length number of entries in @a get_path
1172 * @param put_path peers on the PUT path (or NULL if not recorded)
1173 * [0] = origin, [length - 1] = datastore
1174 * @param put_path_length number of entries in @a put_path
1175 * @param type type of the result
1176 * @param size number of bytes in @a data
1177 * @param data pointer to the result data
1180 handle_dht_result (void *cls,
1181 struct GNUNET_TIME_Absolute exp,
1182 const struct GNUNET_HashCode *key,
1183 const struct GNUNET_PeerIdentity *get_path,
1184 unsigned int get_path_length,
1185 const struct GNUNET_PeerIdentity *put_path,
1186 unsigned int put_path_length,
1187 enum GNUNET_BLOCK_Type type,
1188 size_t size, const void *data)
1190 const struct GNUNET_DNS_Advertisement *ad;
1191 struct CadetExit *exit;
1193 if (sizeof (struct GNUNET_DNS_Advertisement) != size)
1199 for (exit = exit_head; NULL != exit; exit = exit->next)
1200 if (0 == memcmp (&ad->peer,
1202 sizeof (struct GNUNET_PeerIdentity)))
1206 exit = GNUNET_new (struct CadetExit);
1207 exit->peer = ad->peer;
1208 /* channel is closed, so insert at the end */
1209 GNUNET_CONTAINER_DLL_insert_tail (exit_head,
1213 exit->expiration = GNUNET_TIME_absolute_max (exit->expiration,
1214 GNUNET_TIME_absolute_ntoh (ad->expiration_time));
1215 if (dns_exit_available < MAX_OPEN_TUNNELS)
1221 * @brief Main function that will be run by the scheduler.
1223 * @param cls closure
1224 * @param args remaining command-line arguments
1225 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1226 * @param cfg_ configuration
1229 run (void *cls, char *const *args GNUNET_UNUSED,
1230 const char *cfgfile GNUNET_UNUSED,
1231 const struct GNUNET_CONFIGURATION_Handle *cfg_)
1233 struct GNUNET_HashCode dns_key;
1236 stats = GNUNET_STATISTICS_create ("pt", cfg);
1237 ipv4_pt = GNUNET_CONFIGURATION_get_value_yesno (cfg, "pt", "TUNNEL_IPV4");
1238 ipv6_pt = GNUNET_CONFIGURATION_get_value_yesno (cfg, "pt", "TUNNEL_IPV6");
1239 dns_channel = GNUNET_CONFIGURATION_get_value_yesno (cfg, "pt", "TUNNEL_DNS");
1240 if (! (ipv4_pt || ipv6_pt || dns_channel))
1242 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1243 _("No useful service enabled. Exiting.\n"));
1244 GNUNET_SCHEDULER_shutdown ();
1247 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls);
1248 if (ipv4_pt || ipv6_pt)
1251 = GNUNET_DNS_connect (cfg,
1252 GNUNET_DNS_FLAG_POST_RESOLUTION,
1253 &dns_post_request_handler, NULL);
1254 if (NULL == dns_post_handle)
1256 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1257 _("Failed to connect to %s service. Exiting.\n"),
1259 GNUNET_SCHEDULER_shutdown ();
1262 vpn_handle = GNUNET_VPN_connect (cfg);
1263 if (NULL == vpn_handle)
1265 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1266 _("Failed to connect to %s service. Exiting.\n"),
1268 GNUNET_SCHEDULER_shutdown ();
1274 static struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1275 {&receive_dns_response, GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET, 0},
1280 = GNUNET_DNS_connect (cfg,
1281 GNUNET_DNS_FLAG_PRE_RESOLUTION,
1282 &dns_pre_request_handler, NULL);
1283 if (NULL == dns_pre_handle)
1285 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1286 _("Failed to connect to %s service. Exiting.\n"),
1288 GNUNET_SCHEDULER_shutdown ();
1291 cadet_handle = GNUNET_CADET_connect (cfg, NULL, NULL,
1292 &cadet_channel_end_cb,
1293 cadet_handlers, NULL);
1294 if (NULL == cadet_handle)
1296 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1297 _("Failed to connect to %s service. Exiting.\n"),
1299 GNUNET_SCHEDULER_shutdown ();
1302 dht = GNUNET_DHT_connect (cfg, 1);
1305 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1306 _("Failed to connect to %s service. Exiting.\n"),
1308 GNUNET_SCHEDULER_shutdown ();
1311 GNUNET_CRYPTO_hash ("dns", strlen ("dns"), &dns_key);
1312 dht_get = GNUNET_DHT_get_start (dht,
1313 GNUNET_BLOCK_TYPE_DNS,
1316 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
1318 &handle_dht_result, NULL);
1326 * @param argc number of arguments from the command line
1327 * @param argv command line arguments
1328 * @return 0 ok, 1 on error
1331 main (int argc, char *const *argv)
1333 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1334 GNUNET_GETOPT_OPTION_END
1338 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1341 GNUNET_PROGRAM_run (argc, argv, "gnunet-daemon-pt",
1343 ("Daemon to run to perform IP protocol translation to GNUnet"),
1344 options, &run, NULL)) ? 0 : 1;
1345 GNUNET_free ((void*) argv);
1350 /* end of gnunet-daemon-pt.c */