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 candidate_selected = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
348 for (pos = exit_head; NULL != pos; pos = pos->next)
349 if (NULL == pos->cadet_channel)
352 if (candidate_selected < candidate_count)
354 /* move to the head of the DLL */
356 = GNUNET_CADET_channel_create (cadet_handle,
360 GNUNET_CADET_OPTION_DEFAULT);
361 if (NULL == pos->cadet_channel)
366 GNUNET_CONTAINER_DLL_remove (exit_head,
369 GNUNET_CONTAINER_DLL_insert (exit_head,
372 dns_exit_available++;
376 GNUNET_assert (NULL == exit_head);
381 * Compute the weight of the given exit. The higher the weight,
382 * the more likely it will be that the channel will be chosen.
383 * A weigt of zero means that we should close the channel as it
384 * is so bad, that we should not use it.
386 * @param exit exit to calculate the weight for
387 * @return weight of the channel
390 get_channel_weight (struct CadetExit *exit)
393 uint32_t drop_percent;
394 uint32_t good_percent;
396 GNUNET_assert (exit->num_transmitted >= exit->num_answered);
397 dropped = exit->num_transmitted - exit->num_answered;
398 if (exit->num_transmitted > 0)
399 drop_percent = (uint32_t) ((100LL * dropped) / exit->num_transmitted);
401 drop_percent = 50; /* no data */
402 if ( (exit->num_transmitted > 20) &&
403 (drop_percent > 25) )
404 return 0; /* statistically significant, and > 25% loss, die */
405 good_percent = 100 - drop_percent;
406 GNUNET_assert (0 != good_percent);
407 if ( UINT32_MAX / good_percent / good_percent < exit->num_transmitted)
408 return UINT32_MAX; /* formula below would overflow */
409 return 1 + good_percent * good_percent * exit->num_transmitted;
414 * Choose a cadet exit for a DNS request. We try to use a channel
415 * that is reliable and currently available. All existing
416 * channels are given a base weight of 1, plus a score relating
417 * to the total number of queries answered in relation to the
418 * total number of queries we sent to that channel. That
419 * score is doubled if the channel is currently idle.
421 * @return NULL if no exit is known, otherwise the
422 * exit that we should use to queue a message with
424 static struct CadetExit *
427 struct CadetExit *pos;
428 uint64_t total_transmitted;
429 uint64_t selected_offset;
430 uint32_t channel_weight;
432 total_transmitted = 0;
433 for (pos = exit_head; NULL != pos; pos = pos->next)
435 if (NULL == pos->cadet_channel)
437 channel_weight = get_channel_weight (pos);
438 total_transmitted += channel_weight;
439 /* double weight for idle channels */
440 if (NULL == pos->cadet_th)
441 total_transmitted += channel_weight;
443 if (0 == total_transmitted)
445 /* no channels available, or only a very bad one... */
448 selected_offset = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
450 total_transmitted = 0;
451 for (pos = exit_head; NULL != pos; pos = pos->next)
453 if (NULL == pos->cadet_channel)
455 channel_weight = get_channel_weight (pos);
456 total_transmitted += channel_weight;
457 /* double weight for idle channels */
458 if (NULL == pos->cadet_th)
459 total_transmitted += channel_weight;
460 if (total_transmitted > selected_offset)
469 * We're done modifying all records in the response. Submit the reply
470 * and free the resources of the rc.
472 * @param rc context to process
475 finish_request (struct ReplyContext *rc)
481 GNUNET_DNSPARSER_pack (rc->dns,
486 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
487 _("Failed to pack DNS request. Dropping.\n"));
488 GNUNET_DNS_request_drop (rc->rh);
492 GNUNET_STATISTICS_update (stats,
493 gettext_noop ("# DNS requests mapped to VPN"),
495 GNUNET_DNS_request_answer (rc->rh,
500 GNUNET_DNSPARSER_free_packet (rc->dns);
506 * Process the next record of the given request context.
507 * When done, submit the reply and free the resources of
510 * @param rc context to process
513 submit_request (struct ReplyContext *rc);
517 * Callback invoked from the VPN service once a redirection is
518 * available. Provides the IP address that can now be used to
519 * reach the requested destination. We substitute the active
520 * record and then continue with 'submit_request' to look at
523 * @param cls our `struct ReplyContext`
524 * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error;
525 * will match 'result_af' from the request
526 * @param address IP address (struct in_addr or struct in_addr6, depending on 'af')
527 * that the VPN allocated for the redirection;
528 * traffic to this IP will now be redirected to the
529 * specified target peer; NULL on error
532 vpn_allocation_callback (void *cls,
536 struct ReplyContext *rc = cls;
541 GNUNET_DNS_request_drop (rc->rh);
542 GNUNET_DNSPARSER_free_packet (rc->dns);
546 GNUNET_STATISTICS_update (stats,
547 gettext_noop ("# DNS records modified"),
550 switch (rc->rec->type)
552 case GNUNET_DNSPARSER_TYPE_A:
553 GNUNET_assert (AF_INET == af);
554 GNUNET_memcpy (rc->rec->data.raw.data,
556 sizeof (struct in_addr));
558 case GNUNET_DNSPARSER_TYPE_AAAA:
559 GNUNET_assert (AF_INET6 == af);
560 GNUNET_memcpy (rc->rec->data.raw.data,
562 sizeof (struct in6_addr));
574 * Modify the given DNS record by asking VPN to create a channel
575 * to the given address. When done, continue with submitting
576 * other records from the request context ('submit_request' is
579 * @param rc context to process
580 * @param rec record to modify
583 modify_address (struct ReplyContext *rc,
584 struct GNUNET_DNSPARSER_Record *rec)
590 case GNUNET_DNSPARSER_TYPE_A:
592 GNUNET_assert (rec->data.raw.data_len == sizeof (struct in_addr));
594 case GNUNET_DNSPARSER_TYPE_AAAA:
596 GNUNET_assert (rec->data.raw.data_len == sizeof (struct in6_addr));
603 rc->rr = GNUNET_VPN_redirect_to_ip (vpn_handle,
607 GNUNET_TIME_relative_to_absolute (TIMEOUT),
608 &vpn_allocation_callback,
614 * Process the next record of the given request context.
615 * When done, submit the reply and free the resources of
618 * @param rc context to process
621 submit_request (struct ReplyContext *rc)
623 struct GNUNET_DNSPARSER_Record *ra;
632 ra = rc->dns->answers;
633 ra_len = rc->dns->num_answers;
635 case AUTHORITY_RECORDS:
636 ra = rc->dns->authority_records;
637 ra_len = rc->dns->num_authority_records;
639 case ADDITIONAL_RECORDS:
640 ra = rc->dns->additional_records;
641 ra_len = rc->dns->num_additional_records;
649 for (i=rc->offset;i<ra_len;i++)
653 case GNUNET_DNSPARSER_TYPE_A:
662 case GNUNET_DNSPARSER_TYPE_AAAA:
679 * Test if any of the given records need protocol-translation work.
681 * @param ra array of records
682 * @param ra_len number of entries in @a ra
683 * @return #GNUNET_YES if any of the given records require protocol-translation
686 work_test (const struct GNUNET_DNSPARSER_Record *ra,
691 for (i=0;i<ra_len;i++)
695 case GNUNET_DNSPARSER_TYPE_A:
699 case GNUNET_DNSPARSER_TYPE_AAAA:
710 * This function is called AFTER we got an IP address for a
711 * DNS request. Now, the PT daemon has the chance to substitute
712 * the IP address with one from the VPN range to channel requests
713 * destined for this IP address via VPN and CADET.
716 * @param rh request handle to user for reply
717 * @param request_length number of bytes in request
718 * @param request udp payload of the DNS request
721 dns_post_request_handler (void *cls,
722 struct GNUNET_DNS_RequestHandle *rh,
723 size_t request_length,
726 struct GNUNET_DNSPARSER_Packet *dns;
727 struct ReplyContext *rc;
730 GNUNET_STATISTICS_update (stats,
731 gettext_noop ("# DNS replies intercepted"),
733 dns = GNUNET_DNSPARSER_parse (request,
737 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
738 _("Failed to parse DNS request. Dropping.\n"));
739 GNUNET_DNS_request_drop (rh);
743 work |= work_test (dns->answers,
745 work |= work_test (dns->authority_records,
746 dns->num_authority_records);
747 work |= work_test (dns->additional_records,
748 dns->num_additional_records);
751 GNUNET_DNS_request_forward (rh);
752 GNUNET_DNSPARSER_free_packet (dns);
755 rc = GNUNET_new (struct ReplyContext);
765 * Transmit a DNS request via CADET and move the request
766 * handle to the receive queue.
768 * @param cls the `struct CadetExit`
769 * @param size number of bytes available in buf
770 * @param buf where to copy the message
771 * @return number of bytes written to buf
774 transmit_dns_request_to_cadet (void *cls,
778 struct CadetExit *exit = cls;
779 struct RequestContext *rc;
782 exit->cadet_th = NULL;
783 if (NULL == (rc = exit->transmit_queue_head))
789 = GNUNET_CADET_notify_transmit_ready (exit->cadet_channel,
793 &transmit_dns_request_to_cadet,
797 GNUNET_assert (GNUNET_NO == rc->was_transmitted);
801 GNUNET_CONTAINER_DLL_remove (exit->transmit_queue_head,
802 exit->transmit_queue_tail,
804 rc->was_transmitted = GNUNET_YES;
805 GNUNET_CONTAINER_DLL_insert (exit->receive_queue_head,
806 exit->receive_queue_tail,
808 rc = exit->transmit_queue_head;
810 exit->cadet_th = GNUNET_CADET_notify_transmit_ready (exit->cadet_channel,
814 &transmit_dns_request_to_cadet,
821 * Task run if the time to answer a DNS request via CADET is over.
823 * @param cls the `struct RequestContext` to abort
826 timeout_request (void *cls)
828 struct RequestContext *rc = cls;
829 struct CadetExit *exit = rc->exit;
831 if (rc->was_transmitted)
833 exit->num_transmitted++;
834 GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head,
835 exit->receive_queue_tail,
840 GNUNET_CONTAINER_DLL_remove (exit->transmit_queue_head,
841 exit->transmit_queue_tail,
844 GNUNET_STATISTICS_update (stats,
845 gettext_noop ("# DNS requests dropped (timeout)"),
848 GNUNET_DNS_request_drop (rc->rh);
850 if ( (0 == get_channel_weight (exit)) &&
851 (NULL == exit->receive_queue_head) &&
852 (NULL == exit->transmit_queue_head) )
854 /* this straw broke the camel's back: this channel now has
855 such a low score that it will not be used; close it! */
856 GNUNET_assert (NULL == exit->cadet_th);
857 GNUNET_CADET_channel_destroy (exit->cadet_channel);
858 exit->cadet_channel = NULL;
859 GNUNET_CONTAINER_DLL_remove (exit_head,
862 GNUNET_CONTAINER_DLL_insert_tail (exit_head,
865 /* go back to semi-innocent: mark as not great, but
866 avoid a prohibitively negative score (see
867 #get_channel_weight, which checks for a certain
868 minimum number of transmissions before making
870 exit->num_transmitted = 5;
871 exit->num_answered = 0;
872 dns_exit_available--;
873 /* now try to open an alternative exit */
880 * This function is called *before* the DNS request has been
881 * given to a "local" DNS resolver. Channeling for DNS requests
882 * was enabled, so we now need to send the request via some CADET
883 * channel to a DNS EXIT for resolution.
886 * @param rh request handle to user for reply
887 * @param request_length number of bytes in request
888 * @param request udp payload of the DNS request
891 dns_pre_request_handler (void *cls,
892 struct GNUNET_DNS_RequestHandle *rh,
893 size_t request_length,
896 struct RequestContext *rc;
898 struct GNUNET_MessageHeader hdr;
899 struct GNUNET_TUN_DnsHeader dns;
900 struct CadetExit *exit;
902 GNUNET_STATISTICS_update (stats,
903 gettext_noop ("# DNS requests intercepted"),
905 if (0 == dns_exit_available)
907 GNUNET_STATISTICS_update (stats,
908 gettext_noop ("# DNS requests dropped (DNS cadet channel down)"),
910 GNUNET_DNS_request_drop (rh);
913 if (request_length < sizeof (dns))
915 GNUNET_STATISTICS_update (stats,
916 gettext_noop ("# DNS requests dropped (malformed)"),
918 GNUNET_DNS_request_drop (rh);
921 GNUNET_memcpy (&dns, request, sizeof (dns));
922 mlen = sizeof (struct GNUNET_MessageHeader) + request_length;
923 exit = choose_exit ();
924 GNUNET_assert (NULL != exit);
925 GNUNET_assert (NULL != exit->cadet_channel);
926 rc = GNUNET_malloc (sizeof (struct RequestContext) + mlen);
929 rc->cadet_message = (const struct GNUNET_MessageHeader*) &rc[1];
930 rc->timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
935 hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_TO_INTERNET);
936 hdr.size = htons (mlen);
937 GNUNET_memcpy (&rc[1], &hdr, sizeof (struct GNUNET_MessageHeader));
938 GNUNET_memcpy (&(((char*)&rc[1])[sizeof (struct GNUNET_MessageHeader)]),
941 GNUNET_CONTAINER_DLL_insert_tail (exit->transmit_queue_head,
942 exit->transmit_queue_tail,
944 if (NULL == exit->cadet_th)
945 exit->cadet_th = GNUNET_CADET_notify_transmit_ready (exit->cadet_channel,
949 &transmit_dns_request_to_cadet,
955 * Process a request via cadet to perform a DNS query.
958 * @param channel connection to the other end
959 * @param channel_ctx pointer to our `struct CadetExit`
960 * @param message the actual message
961 * @return #GNUNET_OK to keep the connection open,
962 * #GNUNET_SYSERR to close it (signal serious error)
965 receive_dns_response (void *cls,
966 struct GNUNET_CADET_Channel *channel,
968 const struct GNUNET_MessageHeader *message)
970 struct CadetExit *exit = *channel_ctx;
971 struct GNUNET_TUN_DnsHeader dns;
973 struct RequestContext *rc;
975 mlen = ntohs (message->size);
976 mlen -= sizeof (struct GNUNET_MessageHeader);
977 if (mlen < sizeof (struct GNUNET_TUN_DnsHeader))
980 return GNUNET_SYSERR;
982 GNUNET_memcpy (&dns, &message[1], sizeof (dns));
983 for (rc = exit->receive_queue_head; NULL != rc; rc = rc->next)
985 GNUNET_assert (GNUNET_YES == rc->was_transmitted);
986 if (dns.id == rc->dns_id)
988 GNUNET_STATISTICS_update (stats,
989 gettext_noop ("# DNS replies received"),
991 GNUNET_DNS_request_answer (rc->rh,
993 (const void*) &message[1]);
994 GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head,
995 exit->receive_queue_tail,
997 GNUNET_SCHEDULER_cancel (rc->timeout_task);
999 exit->num_answered++;
1000 exit->num_transmitted++;
1004 GNUNET_STATISTICS_update (stats,
1005 gettext_noop ("# DNS replies dropped (too late?)"),
1012 * Abort all pending DNS requests with the given cadet exit.
1014 * @param exit cadet exit to abort requests for
1017 abort_all_requests (struct CadetExit *exit)
1019 struct RequestContext *rc;
1021 while (NULL != (rc = exit->receive_queue_head))
1023 GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head,
1024 exit->receive_queue_tail,
1026 GNUNET_DNS_request_drop (rc->rh);
1027 GNUNET_SCHEDULER_cancel (rc->timeout_task);
1030 while (NULL != (rc = exit->transmit_queue_head))
1032 GNUNET_CONTAINER_DLL_remove (exit->transmit_queue_head,
1033 exit->transmit_queue_tail,
1035 GNUNET_DNS_request_drop (rc->rh);
1036 GNUNET_SCHEDULER_cancel (rc->timeout_task);
1043 * Function scheduled as very last function, cleans up after us
1045 * @param cls closure, NULL
1050 struct CadetExit *exit;
1052 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1053 "Protocol translation daemon is shutting down now\n");
1054 if (NULL != vpn_handle)
1056 GNUNET_VPN_disconnect (vpn_handle);
1059 while (NULL != (exit = exit_head))
1061 GNUNET_CONTAINER_DLL_remove (exit_head,
1064 if (NULL != exit->cadet_th)
1066 GNUNET_CADET_notify_transmit_ready_cancel (exit->cadet_th);
1067 exit->cadet_th = NULL;
1069 if (NULL != exit->cadet_channel)
1071 GNUNET_CADET_channel_destroy (exit->cadet_channel);
1072 exit->cadet_channel = NULL;
1074 abort_all_requests (exit);
1077 if (NULL != cadet_handle)
1079 GNUNET_CADET_disconnect (cadet_handle);
1080 cadet_handle = NULL;
1082 if (NULL != dns_post_handle)
1084 GNUNET_DNS_disconnect (dns_post_handle);
1085 dns_post_handle = NULL;
1087 if (NULL != dns_pre_handle)
1089 GNUNET_DNS_disconnect (dns_pre_handle);
1090 dns_pre_handle = NULL;
1094 GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
1097 if (NULL != dht_get)
1099 GNUNET_DHT_get_stop (dht_get);
1104 GNUNET_DHT_disconnect (dht);
1111 * Function called whenever a channel is destroyed. Should clean up
1112 * the associated state and attempt to build a new one.
1114 * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
1116 * @param cls closure (the `struct CadetExit` set from #GNUNET_CADET_connect)
1117 * @param channel connection to the other end (henceforth invalid)
1118 * @param channel_ctx place where local state associated
1119 * with the channel is stored
1122 cadet_channel_end_cb (void *cls,
1123 const struct GNUNET_CADET_Channel *channel,
1126 struct CadetExit *exit = channel_ctx;
1127 struct CadetExit *alt;
1128 struct RequestContext *rc;
1130 if (NULL != exit->cadet_th)
1132 GNUNET_CADET_notify_transmit_ready_cancel (exit->cadet_th);
1133 exit->cadet_th = NULL;
1135 exit->cadet_channel = NULL;
1136 dns_exit_available--;
1137 /* open alternative channels */
1139 if (NULL == exit->cadet_channel)
1141 /* our channel is now closed, move our requests to an alternative
1143 alt = choose_exit ();
1144 while (NULL != (rc = exit->transmit_queue_head))
1146 GNUNET_CONTAINER_DLL_remove (exit->transmit_queue_head,
1147 exit->transmit_queue_tail,
1150 GNUNET_CONTAINER_DLL_insert (alt->transmit_queue_head,
1151 alt->transmit_queue_tail,
1154 while (NULL != (rc = exit->receive_queue_head))
1156 GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head,
1157 exit->receive_queue_tail,
1159 rc->was_transmitted = GNUNET_NO;
1161 GNUNET_CONTAINER_DLL_insert (alt->transmit_queue_head,
1162 alt->transmit_queue_tail,
1168 /* the same peer was chosen, just make sure the queue processing is restarted */
1171 if ( (NULL == alt->cadet_th) &&
1172 (NULL != (rc = alt->transmit_queue_head)) )
1174 = GNUNET_CADET_notify_transmit_ready (alt->cadet_channel,
1178 &transmit_dns_request_to_cadet,
1184 * Function called whenever we find an advertisement for a
1185 * DNS exit in the DHT. If we don't have a cadet channel,
1186 * we should build one; otherwise, we should save the
1187 * advertisement for later use.
1189 * @param cls closure
1190 * @param exp when will this value expire
1191 * @param key key of the result
1192 * @param get_path peers on reply path (or NULL if not recorded)
1193 * [0] = datastore's first neighbor, [length - 1] = local peer
1194 * @param get_path_length number of entries in @a get_path
1195 * @param put_path peers on the PUT path (or NULL if not recorded)
1196 * [0] = origin, [length - 1] = datastore
1197 * @param put_path_length number of entries in @a put_path
1198 * @param type type of the result
1199 * @param size number of bytes in @a data
1200 * @param data pointer to the result data
1203 handle_dht_result (void *cls,
1204 struct GNUNET_TIME_Absolute exp,
1205 const struct GNUNET_HashCode *key,
1206 const struct GNUNET_PeerIdentity *get_path,
1207 unsigned int get_path_length,
1208 const struct GNUNET_PeerIdentity *put_path,
1209 unsigned int put_path_length,
1210 enum GNUNET_BLOCK_Type type,
1211 size_t size, const void *data)
1213 const struct GNUNET_DNS_Advertisement *ad;
1214 struct CadetExit *exit;
1216 if (sizeof (struct GNUNET_DNS_Advertisement) != size)
1222 for (exit = exit_head; NULL != exit; exit = exit->next)
1223 if (0 == memcmp (&ad->peer,
1225 sizeof (struct GNUNET_PeerIdentity)))
1229 exit = GNUNET_new (struct CadetExit);
1230 exit->peer = ad->peer;
1231 /* channel is closed, so insert at the end */
1232 GNUNET_CONTAINER_DLL_insert_tail (exit_head,
1236 exit->expiration = GNUNET_TIME_absolute_max (exit->expiration,
1237 GNUNET_TIME_absolute_ntoh (ad->expiration_time));
1238 if (dns_exit_available < MAX_OPEN_TUNNELS)
1244 * @brief Main function that will be run by the scheduler.
1246 * @param cls closure
1247 * @param args remaining command-line arguments
1248 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1249 * @param cfg_ configuration
1252 run (void *cls, char *const *args GNUNET_UNUSED,
1253 const char *cfgfile GNUNET_UNUSED,
1254 const struct GNUNET_CONFIGURATION_Handle *cfg_)
1256 struct GNUNET_HashCode dns_key;
1259 stats = GNUNET_STATISTICS_create ("pt",
1261 ipv4_pt = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1264 ipv6_pt = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1267 dns_channel = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1270 if (! (ipv4_pt || ipv6_pt || dns_channel))
1272 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1273 _("No useful service enabled. Exiting.\n"));
1274 GNUNET_SCHEDULER_shutdown ();
1277 GNUNET_SCHEDULER_add_shutdown (&cleanup, cls);
1278 if (ipv4_pt || ipv6_pt)
1281 = GNUNET_DNS_connect (cfg,
1282 GNUNET_DNS_FLAG_POST_RESOLUTION,
1283 &dns_post_request_handler,
1285 if (NULL == dns_post_handle)
1287 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1288 _("Failed to connect to %s service. Exiting.\n"),
1290 GNUNET_SCHEDULER_shutdown ();
1293 vpn_handle = GNUNET_VPN_connect (cfg);
1294 if (NULL == vpn_handle)
1296 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1297 _("Failed to connect to %s service. Exiting.\n"),
1299 GNUNET_SCHEDULER_shutdown ();
1305 static struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1306 {&receive_dns_response, GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET, 0},
1311 = GNUNET_DNS_connect (cfg,
1312 GNUNET_DNS_FLAG_PRE_RESOLUTION,
1313 &dns_pre_request_handler,
1315 if (NULL == dns_pre_handle)
1317 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1318 _("Failed to connect to %s service. Exiting.\n"),
1320 GNUNET_SCHEDULER_shutdown ();
1323 cadet_handle = GNUNET_CADET_connect (cfg,
1325 &cadet_channel_end_cb,
1327 if (NULL == cadet_handle)
1329 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1330 _("Failed to connect to %s service. Exiting.\n"),
1332 GNUNET_SCHEDULER_shutdown ();
1335 dht = GNUNET_DHT_connect (cfg, 1);
1338 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1339 _("Failed to connect to %s service. Exiting.\n"),
1341 GNUNET_SCHEDULER_shutdown ();
1344 GNUNET_CRYPTO_hash ("dns",
1347 dht_get = GNUNET_DHT_get_start (dht,
1348 GNUNET_BLOCK_TYPE_DNS,
1351 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
1362 * @param argc number of arguments from the command line
1363 * @param argv command line arguments
1364 * @return 0 ok, 1 on error
1370 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1371 GNUNET_GETOPT_OPTION_END
1375 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc,
1381 GNUNET_PROGRAM_run (argc,
1384 gettext_noop ("Daemon to run to perform IP protocol translation to GNUnet"),
1390 GNUNET_free ((void*) argv);
1395 /* end of gnunet-daemon-pt.c */