2 This file is part of GNUnet.
3 Copyright (C) 2010, 2011, 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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file vpn/gnunet-service-vpn.c
23 * @brief service that opens a virtual interface and allows its clients
24 * to allocate IPs on the virtual interface and to then redirect
25 * IP traffic received on those IPs via the GNUnet cadet
26 * @author Philipp Toelke
27 * @author Christian Grothoff
30 * - keep multiple peers/cadet channels ready as alternative exits /
31 * detect & recover from channel-to-exit failure gracefully
34 #include "gnunet_util_lib.h"
35 #include "gnunet_common.h"
36 #include "gnunet_protocols.h"
37 #include "gnunet_applications.h"
38 #include "gnunet_cadet_service.h"
39 #include "gnunet_statistics_service.h"
40 #include "gnunet_constants.h"
41 #include "gnunet_tun_lib.h"
42 #include "gnunet_regex_service.h"
48 * Maximum number of messages we allow in the queue for cadet.
50 #define MAX_MESSAGE_QUEUE_SIZE 4
54 * State we keep for each of our channels.
59 * Information we track for each IP address to determine which channel
60 * to send the traffic over to the destination.
62 struct DestinationEntry;
65 * List of channels we keep for each destination port for a given
68 struct DestinationChannel
74 struct DestinationChannel *next;
79 struct DestinationChannel *prev;
82 * Destination entry list this `struct DestinationChannel` belongs with.
84 struct DestinationEntry *destination;
87 * Pre-allocated channel for this destination, or NULL for none.
89 struct ChannelState *ts;
92 * Destination port this channel state is used for.
94 uint16_t destination_port;
100 * Information we track for each IP address to determine which channel
101 * to send the traffic over to the destination.
103 struct DestinationEntry
107 * Key under which this entry is in the 'destination_map' (only valid
108 * if 'heap_node != NULL').
110 struct GNUNET_HashCode key;
113 * Head of DLL of channels associated with this destination.
115 struct DestinationChannel *dt_head;
118 * Tail of DLL of channels associated with this destination.
120 struct DestinationChannel *dt_tail;
123 * Entry for this entry in the destination_heap.
125 struct GNUNET_CONTAINER_HeapNode *heap_node;
128 * #GNUNET_NO if this is a channel to an Internet-exit,
129 * #GNUNET_YES if this channel is to a service.
134 * Details about the connection (depending on is_service).
142 * The description of the service (only used for service channels).
144 struct GNUNET_HashCode service_descriptor;
147 * Peer offering the service.
149 struct GNUNET_PeerIdentity target;
151 } service_destination;
157 * Address family used (AF_INET or AF_INET6).
162 * IP address of the ultimate destination (only used for exit channels).
167 * Address if af is AF_INET.
172 * Address if af is AF_INET6.
185 * A messages we have in queue for a particular channel.
187 struct ChannelMessageQueueEntry
190 * This is a doubly-linked list.
192 struct ChannelMessageQueueEntry *next;
195 * This is a doubly-linked list.
197 struct ChannelMessageQueueEntry *prev;
200 * Number of bytes in 'msg'.
205 * Message to transmit, allocated at the end of this struct.
212 * State we keep for each of our channels.
218 * Information about the channel to use, NULL if no channel
219 * is available right now.
221 struct GNUNET_CADET_Channel *channel;
224 * Active query with REGEX to locate exit.
226 struct GNUNET_REGEX_Search *search;
229 * Active transmission handle, NULL for none.
231 struct GNUNET_CADET_TransmitHandle *th;
234 * Entry for this entry in the channel_heap, NULL as long as this
235 * channel state is not fully bound.
237 struct GNUNET_CONTAINER_HeapNode *heap_node;
240 * Head of list of messages scheduled for transmission.
242 struct ChannelMessageQueueEntry *tmq_head;
245 * Tail of list of messages scheduled for transmission.
247 struct ChannelMessageQueueEntry *tmq_tail;
250 * Destination entry that has a pointer to this channel state;
251 * NULL if this channel state is in the channel map.
253 struct DestinationChannel *destination_container;
256 * Destination to which this channel leads. Note that
257 * this struct is NOT in the destination_map (but a
258 * local copy) and that the 'heap_node' should always
261 struct DestinationEntry destination;
264 * Addess family used for this channel on the local TUN interface.
269 * Is this channel new (#GNUNET_NO), or did we exchange messages with the
270 * other side already (#GNUNET_YES)?
275 * Length of the doubly linked 'tmq_head/tmq_tail' list.
277 unsigned int tmq_length;
280 * IPPROTO_TCP or IPPROTO_UDP once bound.
285 * IP address of the source on our end, initially uninitialized.
290 * Address if af is AF_INET.
295 * Address if af is AF_INET6.
302 * Destination IP address used by the source on our end (this is the IP
303 * that we pick freely within the VPN's channel IP range).
308 * Address if af is AF_INET.
313 * Address if af is AF_INET6.
320 * Source port used by the sender on our end; 0 for uninitialized.
322 uint16_t source_port;
325 * Destination port used by the sender on our end; 0 for uninitialized.
327 uint16_t destination_port;
333 * Return value from #main().
335 static int global_ret;
338 * Configuration we use.
340 static const struct GNUNET_CONFIGURATION_Handle *cfg;
343 * Handle to the cadet service.
345 static struct GNUNET_CADET_Handle *cadet_handle;
348 * Map from IP address to destination information (possibly with a
349 * CADET channel handle for fast setup).
351 static struct GNUNET_CONTAINER_MultiHashMap *destination_map;
354 * Min-Heap sorted by activity time to expire old mappings.
356 static struct GNUNET_CONTAINER_Heap *destination_heap;
359 * Map from source and destination address (IP+port) to connection
360 * information (mostly with the respective CADET channel handle).
362 static struct GNUNET_CONTAINER_MultiHashMap *channel_map;
365 * Min-Heap sorted by activity time to expire old mappings; values are
366 * of type 'struct ChannelState'.
368 static struct GNUNET_CONTAINER_Heap *channel_heap;
373 static struct GNUNET_STATISTICS_Handle *stats;
376 * The handle to the VPN helper process "gnunet-helper-vpn".
378 static struct GNUNET_HELPER_Handle *helper_handle;
381 * Arguments to the vpn helper.
383 static char *vpn_argv[7];
386 * Length of the prefix of the VPN's IPv6 network.
388 static unsigned long long ipv6prefix;
391 * Notification context for sending replies to clients.
393 static struct GNUNET_SERVER_NotificationContext *nc;
396 * If there are more than this number of address-mappings, old ones
399 static unsigned long long max_destination_mappings;
402 * If there are more than this number of open channels, old ones
405 static unsigned long long max_channel_mappings;
409 * Compute the key under which we would store an entry in the
410 * destination_map for the given IP address.
412 * @param af address family (AF_INET or AF_INET6)
413 * @param address IP address, struct in_addr or struct in6_addr
414 * @param key where to store the key
417 get_destination_key_from_ip (int af,
419 struct GNUNET_HashCode *key)
424 GNUNET_CRYPTO_hash (address,
425 sizeof (struct in_addr),
429 GNUNET_CRYPTO_hash (address,
430 sizeof (struct in6_addr),
441 * Compute the key under which we would store an entry in the
442 * channel_map for the given socket address pair.
444 * @param af address family (AF_INET or AF_INET6)
445 * @param protocol IPPROTO_TCP or IPPROTO_UDP
446 * @param source_ip sender's source IP, struct in_addr or struct in6_addr
447 * @param source_port sender's source port
448 * @param destination_ip sender's destination IP, struct in_addr or struct in6_addr
449 * @param destination_port sender's destination port
450 * @param key where to store the key
453 get_channel_key_from_ips (int af,
455 const void *source_ip,
456 uint16_t source_port,
457 const void *destination_ip,
458 uint16_t destination_port,
459 struct GNUNET_HashCode *key)
463 memset (key, 0, sizeof (struct GNUNET_HashCode));
464 /* the GNUnet hashmap only uses the first sizeof(unsigned int) of the hash,
465 so we put the ports in there (and hope for few collisions) */
467 memcpy (off, &source_port, sizeof (uint16_t));
468 off += sizeof (uint16_t);
469 memcpy (off, &destination_port, sizeof (uint16_t));
470 off += sizeof (uint16_t);
474 memcpy (off, source_ip, sizeof (struct in_addr));
475 off += sizeof (struct in_addr);
476 memcpy (off, destination_ip, sizeof (struct in_addr));
477 off += sizeof (struct in_addr);
480 memcpy (off, source_ip, sizeof (struct in6_addr));
481 off += sizeof (struct in6_addr);
482 memcpy (off, destination_ip, sizeof (struct in6_addr));
483 off += sizeof (struct in6_addr);
489 memcpy (off, &protocol, sizeof (uint8_t));
490 /* off += sizeof (uint8_t); */
495 * Notify the client about the result of its request.
497 * @param client client to notify
498 * @param request_id original request ID to include in response
499 * @param result_af resulting address family
500 * @param addr resulting IP address
503 send_client_reply (struct GNUNET_SERVER_Client *client,
508 char buf[sizeof (struct RedirectToIpResponseMessage) + sizeof (struct in6_addr)] GNUNET_ALIGN;
509 struct RedirectToIpResponseMessage *res;
515 rlen = sizeof (struct in_addr);
518 rlen = sizeof (struct in6_addr);
527 res = (struct RedirectToIpResponseMessage *) buf;
528 res->header.size = htons (sizeof (struct RedirectToIpResponseMessage) + rlen);
529 res->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP);
530 res->result_af = htonl (result_af);
531 res->request_id = request_id;
532 memcpy (&res[1], addr, rlen);
533 GNUNET_SERVER_notification_context_add (nc, client);
534 GNUNET_SERVER_notification_context_unicast (nc,
542 * Free resources associated with a channel state.
544 * @param ts state to free
547 free_channel_state (struct ChannelState *ts)
549 struct GNUNET_HashCode key;
550 struct ChannelMessageQueueEntry *tnq;
551 struct GNUNET_CADET_Channel *channel;
553 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
554 "Cleaning up channel state\n");
555 GNUNET_STATISTICS_update (stats,
556 gettext_noop ("# Active channels"),
558 while (NULL != (tnq = ts->tmq_head))
560 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
566 GNUNET_assert (0 == ts->tmq_length);
569 GNUNET_CADET_notify_transmit_ready_cancel (ts->th);
572 GNUNET_assert (NULL == ts->destination.heap_node);
573 if (NULL != (channel = ts->channel))
576 GNUNET_CADET_channel_destroy (channel);
578 if (NULL != ts->search)
580 GNUNET_REGEX_search_cancel (ts->search);
583 if (NULL != ts->heap_node)
585 GNUNET_CONTAINER_heap_remove_node (ts->heap_node);
586 ts->heap_node = NULL;
587 get_channel_key_from_ips (ts->af,
592 ts->destination_port,
594 GNUNET_assert (GNUNET_YES ==
595 GNUNET_CONTAINER_multihashmap_remove (channel_map,
599 if (NULL != ts->destination_container)
601 GNUNET_assert (ts == ts->destination_container->ts);
602 ts->destination_container->ts = NULL;
603 ts->destination_container = NULL;
610 * Send a message from the message queue via cadet.
612 * @param cls the `struct ChannelState` with the message queue
613 * @param size number of bytes available in @a buf
614 * @param buf where to copy the message
615 * @return number of bytes copied to @a buf
618 send_to_peer_notify_callback (void *cls, size_t size, void *buf)
620 struct ChannelState *ts = cls;
621 struct ChannelMessageQueueEntry *tnq;
628 GNUNET_assert (NULL != tnq);
629 GNUNET_assert (size >= tnq->len);
630 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
631 "Sending %u bytes via cadet channel\n",
633 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
637 memcpy (buf, tnq->msg, tnq->len);
640 if (NULL != (tnq = ts->tmq_head))
641 ts->th = GNUNET_CADET_notify_transmit_ready (ts->channel,
642 GNUNET_NO /* cork */,
643 GNUNET_TIME_UNIT_FOREVER_REL,
645 &send_to_peer_notify_callback,
647 GNUNET_STATISTICS_update (stats,
648 gettext_noop ("# Bytes given to cadet for transmission"),
655 * Add the given message to the given channel and trigger the
656 * transmission process.
658 * @param tnq message to queue
659 * @param ts channel to queue the message for
662 send_to_channel (struct ChannelMessageQueueEntry *tnq,
663 struct ChannelState *ts)
665 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
666 "Queueing %u bytes for transmission via cadet channel\n",
668 GNUNET_assert (NULL != ts->channel);
669 GNUNET_CONTAINER_DLL_insert_tail (ts->tmq_head,
673 if (ts->tmq_length > MAX_MESSAGE_QUEUE_SIZE)
675 struct ChannelMessageQueueEntry *dq;
678 GNUNET_assert (dq != tnq);
679 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
683 GNUNET_CADET_notify_transmit_ready_cancel (ts->th);
685 GNUNET_STATISTICS_update (stats,
686 gettext_noop ("# Bytes dropped in cadet queue (overflow)"),
692 ts->th = GNUNET_CADET_notify_transmit_ready (ts->channel,
693 GNUNET_NO /* cork */,
694 GNUNET_TIME_UNIT_FOREVER_REL,
696 &send_to_peer_notify_callback,
702 * Output destination of a channel for diagnostics.
704 * @param de destination to process
705 * @return diagnostic string describing destination
708 print_channel_destination (const struct DestinationEntry *de)
710 static char dest[256];
714 GNUNET_snprintf (dest,
717 GNUNET_i2s (&de->details.service_destination.target),
718 GNUNET_h2s (&de->details.service_destination.service_descriptor));
722 inet_ntop (de->details.exit_destination.af,
723 &de->details.exit_destination.ip,
732 * Regex has found a potential exit peer for us; consider using it.
734 * @param cls the `struct ChannelState`
735 * @param id Peer providing a regex that matches the string.
736 * @param get_path Path of the get request.
737 * @param get_path_length Lenght of @a get_path.
738 * @param put_path Path of the put request.
739 * @param put_path_length Length of the @a put_path.
742 handle_regex_result (void *cls,
743 const struct GNUNET_PeerIdentity *id,
744 const struct GNUNET_PeerIdentity *get_path,
745 unsigned int get_path_length,
746 const struct GNUNET_PeerIdentity *put_path,
747 unsigned int put_path_length)
749 struct ChannelState *ts = cls;
750 unsigned int apptype;
752 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
753 "Exit %s found for destination %s!\n",
755 print_channel_destination (&ts->destination));
756 GNUNET_REGEX_search_cancel (ts->search);
761 apptype = GNUNET_APPLICATION_TYPE_IPV4_GATEWAY;
764 apptype = GNUNET_APPLICATION_TYPE_IPV6_GATEWAY;
770 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
771 "Creating tunnel to %s for destination %s!\n",
773 print_channel_destination (&ts->destination));
774 ts->channel = GNUNET_CADET_channel_create (cadet_handle,
778 GNUNET_CADET_OPTION_DEFAULT);
783 * Initialize the given destination entry's cadet channel.
785 * @param dt destination channel for which we need to setup a channel
786 * @param client_af address family of the address returned to the client
787 * @return channel state of the channel that was created
789 static struct ChannelState *
790 create_channel_to_destination (struct DestinationChannel *dt,
793 struct ChannelState *ts;
794 unsigned int apptype;
796 GNUNET_STATISTICS_update (stats,
797 gettext_noop ("# Cadet channels created"),
799 GNUNET_assert (NULL == dt->ts);
803 apptype = GNUNET_APPLICATION_TYPE_IPV4_GATEWAY;
806 apptype = GNUNET_APPLICATION_TYPE_IPV6_GATEWAY;
812 ts = GNUNET_new (struct ChannelState);
814 ts->destination = *dt->destination;
815 ts->destination.heap_node = NULL; /* copy is NOT in destination heap */
817 ts->destination_container = dt; /* we are referenced from dt */
818 if (dt->destination->is_service)
820 ts->channel = GNUNET_CADET_channel_create (cadet_handle,
822 &dt->destination->details.service_destination.target,
824 GNUNET_CADET_OPTION_DEFAULT);
825 if (NULL == ts->channel)
827 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
828 _("Failed to setup cadet channel!\n"));
832 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
833 "Creating channel %p to peer %s offering service %s\n",
835 GNUNET_i2s (&dt->destination->details.service_destination.target),
836 GNUNET_h2s (&dt->destination->details.service_destination.service_descriptor));
842 switch (dt->destination->details.exit_destination.af)
846 char address[GNUNET_TUN_IPV4_REGEXLEN];
848 GNUNET_TUN_ipv4toregexsearch (&dt->destination->details.exit_destination.ip.v4,
849 dt->destination_port,
851 GNUNET_asprintf (&policy,
853 GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
859 char address[GNUNET_TUN_IPV6_REGEXLEN];
861 GNUNET_TUN_ipv6toregexsearch (&dt->destination->details.exit_destination.ip.v6,
862 dt->destination_port,
864 GNUNET_asprintf (&policy,
866 GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
875 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
876 "Requesting connect by string: %s\n",
878 ts->search = GNUNET_REGEX_search (cfg,
880 &handle_regex_result,
882 GNUNET_free (policy);
889 * We have too many active channels. Clean up the oldest channel.
891 * @param except channel that must NOT be cleaned up, even if it is the oldest
894 expire_channel (struct ChannelState *except)
896 struct ChannelState *ts;
898 ts = GNUNET_CONTAINER_heap_peek (channel_heap);
899 GNUNET_assert (NULL != ts);
901 return; /* can't do this */
902 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
903 "Tearing down expired channel to %s\n",
904 print_channel_destination (&except->destination));
905 free_channel_state (ts);
910 * Route a packet via cadet to the given destination.
912 * @param destination description of the destination
913 * @param af address family on this end (AF_INET or AF_INET6)
914 * @param protocol IPPROTO_TCP or IPPROTO_UDP or IPPROTO_ICMP or IPPROTO_ICMPV6
915 * @param source_ip source IP used by the sender (struct in_addr or struct in6_addr)
916 * @param destination_ip destination IP used by the sender (struct in_addr or struct in6_addr)
917 * @param payload payload of the packet after the IP header
918 * @param payload_length number of bytes in @a payload
921 route_packet (struct DestinationEntry *destination,
924 const void *source_ip,
925 const void *destination_ip,
927 size_t payload_length)
929 struct GNUNET_HashCode key;
930 struct ChannelState *ts;
931 struct ChannelMessageQueueEntry *tnq;
934 const struct GNUNET_TUN_UdpHeader *udp;
935 const struct GNUNET_TUN_TcpHeader *tcp;
936 const struct GNUNET_TUN_IcmpHeader *icmp;
937 struct DestinationChannel *dt;
938 uint16_t source_port;
939 uint16_t destination_port;
945 if (payload_length < sizeof (struct GNUNET_TUN_UdpHeader))
951 tcp = NULL; /* make compiler happy */
952 icmp = NULL; /* make compiler happy */
954 if (udp->len < sizeof (struct GNUNET_TUN_UdpHeader))
959 source_port = ntohs (udp->source_port);
960 destination_port = ntohs (udp->destination_port);
961 get_channel_key_from_ips (af,
972 if (payload_length < sizeof (struct GNUNET_TUN_TcpHeader))
978 udp = NULL; /* make compiler happy */
979 icmp = NULL; /* make compiler happy */
981 if (tcp->off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
986 source_port = ntohs (tcp->source_port);
987 destination_port = ntohs (tcp->destination_port);
988 get_channel_key_from_ips (af,
1000 if ( (AF_INET == af) ^ (protocol == IPPROTO_ICMP) )
1005 if (payload_length < sizeof (struct GNUNET_TUN_IcmpHeader))
1011 tcp = NULL; /* make compiler happy */
1012 udp = NULL; /* make compiler happy */
1015 destination_port = 0;
1016 get_channel_key_from_ips (af,
1026 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1027 _("Protocol %u not supported, dropping\n"),
1028 (unsigned int) protocol);
1032 if (! destination->is_service)
1034 switch (destination->details.exit_destination.af)
1037 alen = sizeof (struct in_addr);
1040 alen = sizeof (struct in6_addr);
1047 char sbuf[INET6_ADDRSTRLEN];
1048 char dbuf[INET6_ADDRSTRLEN];
1049 char xbuf[INET6_ADDRSTRLEN];
1051 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1052 "Routing %s packet from [%s]:%u -> [%s]:%u to destination [%s]:%u\n",
1053 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
1054 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
1056 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
1058 inet_ntop (destination->details.exit_destination.af,
1059 &destination->details.exit_destination.ip,
1060 xbuf, sizeof (xbuf)),
1063 for (dt = destination->dt_head; NULL != dt; dt = dt->next)
1064 if (dt->destination_port == destination_port)
1070 char sbuf[INET6_ADDRSTRLEN];
1071 char dbuf[INET6_ADDRSTRLEN];
1073 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1074 "Routing %s packet from [%s]:%u -> [%s]:%u to service %s at peer %s\n",
1075 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
1076 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
1078 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
1080 GNUNET_h2s (&destination->details.service_destination.service_descriptor),
1081 GNUNET_i2s (&destination->details.service_destination.target));
1083 dt = destination->dt_head;
1087 dt = GNUNET_new (struct DestinationChannel);
1088 dt->destination = destination;
1089 GNUNET_CONTAINER_DLL_insert (destination->dt_head,
1090 destination->dt_tail,
1092 dt->destination_port = destination_port;
1095 /* see if we have an existing channel for this destination */
1096 ts = GNUNET_CONTAINER_multihashmap_get (channel_map,
1100 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1101 "Creating new channel for key %s\n",
1103 /* need to either use the existing channel from the destination (if still
1104 available) or create a fresh one */
1106 ts = create_channel_to_destination (dt, af);
1112 ts->destination_container = NULL; /* no longer 'contained' */
1113 /* now bind existing "unbound" channel to our IP/port tuple */
1114 ts->protocol = protocol;
1118 ts->source_ip.v4 = * (const struct in_addr *) source_ip;
1119 ts->destination_ip.v4 = * (const struct in_addr *) destination_ip;
1123 ts->source_ip.v6 = * (const struct in6_addr *) source_ip;
1124 ts->destination_ip.v6 = * (const struct in6_addr *) destination_ip;
1126 ts->source_port = source_port;
1127 ts->destination_port = destination_port;
1128 ts->heap_node = GNUNET_CONTAINER_heap_insert (channel_heap,
1130 GNUNET_TIME_absolute_get ().abs_value_us);
1131 GNUNET_assert (GNUNET_YES ==
1132 GNUNET_CONTAINER_multihashmap_put (channel_map,
1135 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1136 GNUNET_STATISTICS_update (stats,
1137 gettext_noop ("# Active channels"),
1139 while (GNUNET_CONTAINER_multihashmap_size (channel_map) > max_channel_mappings)
1140 expire_channel (ts);
1144 GNUNET_CONTAINER_heap_update_cost (channel_heap,
1146 GNUNET_TIME_absolute_get ().abs_value_us);
1148 if (NULL == ts->channel)
1150 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1151 "Packet dropped, channel to %s not yet ready (%s)\n",
1152 print_channel_destination (&ts->destination),
1153 (NULL == ts->search)
1154 ? "EXIT search failed"
1155 : "EXIT search active");
1156 GNUNET_STATISTICS_update (stats,
1157 gettext_noop ("# Packets dropped (channel not yet online)"),
1163 /* send via channel */
1167 if (destination->is_service)
1169 struct GNUNET_EXIT_UdpServiceMessage *usm;
1171 mlen = sizeof (struct GNUNET_EXIT_UdpServiceMessage) +
1172 payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1173 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1178 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1181 usm = (struct GNUNET_EXIT_UdpServiceMessage *) &tnq[1];
1182 usm->header.size = htons ((uint16_t) mlen);
1183 usm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE);
1184 /* if the source port is below 32000, we assume it has a special
1185 meaning; if not, we pick a random port (this is a heuristic) */
1186 usm->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1187 usm->destination_port = udp->destination_port;
1188 usm->service_descriptor = destination->details.service_destination.service_descriptor;
1191 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1195 struct GNUNET_EXIT_UdpInternetMessage *uim;
1196 struct in_addr *ip4dst;
1197 struct in6_addr *ip6dst;
1200 mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) +
1201 alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1202 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1207 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1210 uim = (struct GNUNET_EXIT_UdpInternetMessage *) &tnq[1];
1211 uim->header.size = htons ((uint16_t) mlen);
1212 uim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET);
1213 uim->af = htonl (destination->details.exit_destination.af);
1214 uim->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1215 uim->destination_port = udp->destination_port;
1216 switch (destination->details.exit_destination.af)
1219 ip4dst = (struct in_addr *) &uim[1];
1220 *ip4dst = destination->details.exit_destination.ip.v4;
1221 payload = &ip4dst[1];
1224 ip6dst = (struct in6_addr *) &uim[1];
1225 *ip6dst = destination->details.exit_destination.ip.v6;
1226 payload = &ip6dst[1];
1233 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1237 if (GNUNET_NO == ts->is_established)
1239 if (destination->is_service)
1241 struct GNUNET_EXIT_TcpServiceStartMessage *tsm;
1243 mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) +
1244 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1245 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1250 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1253 tsm = (struct GNUNET_EXIT_TcpServiceStartMessage *) &tnq[1];
1254 tsm->header.size = htons ((uint16_t) mlen);
1255 tsm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START);
1256 tsm->reserved = htonl (0);
1257 tsm->service_descriptor = destination->details.service_destination.service_descriptor;
1258 tsm->tcp_header = *tcp;
1261 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1265 struct GNUNET_EXIT_TcpInternetStartMessage *tim;
1266 struct in_addr *ip4dst;
1267 struct in6_addr *ip6dst;
1270 mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) +
1271 alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1272 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1277 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1280 tim = (struct GNUNET_EXIT_TcpInternetStartMessage *) &tnq[1];
1281 tim->header.size = htons ((uint16_t) mlen);
1282 tim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START);
1283 tim->af = htonl (destination->details.exit_destination.af);
1284 tim->tcp_header = *tcp;
1285 switch (destination->details.exit_destination.af)
1288 ip4dst = (struct in_addr *) &tim[1];
1289 *ip4dst = destination->details.exit_destination.ip.v4;
1290 payload = &ip4dst[1];
1293 ip6dst = (struct in6_addr *) &tim[1];
1294 *ip6dst = destination->details.exit_destination.ip.v6;
1295 payload = &ip6dst[1];
1302 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1307 struct GNUNET_EXIT_TcpDataMessage *tdm;
1309 mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) +
1310 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1311 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1316 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1319 tdm = (struct GNUNET_EXIT_TcpDataMessage *) &tnq[1];
1320 tdm->header.size = htons ((uint16_t) mlen);
1321 tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT);
1322 tdm->reserved = htonl (0);
1323 tdm->tcp_header = *tcp;
1326 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1330 case IPPROTO_ICMPV6:
1331 if (destination->is_service)
1333 struct GNUNET_EXIT_IcmpServiceMessage *ism;
1335 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1336 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1337 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1342 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1344 ism = (struct GNUNET_EXIT_IcmpServiceMessage *) &tnq[1];
1345 ism->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE);
1346 ism->af = htonl (af); /* need to tell destination ICMP protocol family! */
1347 ism->service_descriptor = destination->details.service_destination.service_descriptor;
1348 ism->icmp_header = *icmp;
1349 /* ICMP protocol translation will be done by the receiver (as we don't know
1350 the target AF); however, we still need to possibly discard the payload
1351 depending on the ICMP type */
1357 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1358 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1360 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1361 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1362 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1363 /* throw away ICMP payload, won't be useful for the other side anyway */
1364 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1367 GNUNET_STATISTICS_update (stats,
1368 gettext_noop ("# ICMPv4 packets dropped (not allowed)"),
1372 /* end of AF_INET */
1377 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1378 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1379 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1380 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1381 /* throw away ICMP payload, won't be useful for the other side anyway */
1382 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1384 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1385 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1388 GNUNET_STATISTICS_update (stats,
1389 gettext_noop ("# ICMPv6 packets dropped (not allowed)"),
1393 /* end of AF_INET6 */
1400 /* update length calculations, as payload_length may have changed */
1401 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1402 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1404 ism->header.size = htons ((uint16_t) mlen);
1405 /* finally, copy payload (if there is any left...) */
1408 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1412 struct GNUNET_EXIT_IcmpInternetMessage *iim;
1413 struct in_addr *ip4dst;
1414 struct in6_addr *ip6dst;
1417 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1418 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1419 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1424 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1426 iim = (struct GNUNET_EXIT_IcmpInternetMessage *) &tnq[1];
1427 iim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET);
1428 iim->icmp_header = *icmp;
1429 /* Perform ICMP protocol-translation (depending on destination AF and source AF)
1430 and throw away ICMP payload depending on ICMP message type */
1436 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1437 if (destination->details.exit_destination.af == AF_INET6)
1438 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1440 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1441 if (destination->details.exit_destination.af == AF_INET6)
1442 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1444 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1445 if (destination->details.exit_destination.af == AF_INET6)
1446 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1447 /* throw away IP-payload, exit will have to make it up anyway */
1448 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1450 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1451 if (destination->details.exit_destination.af == AF_INET6)
1452 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1453 /* throw away IP-payload, exit will have to make it up anyway */
1454 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1456 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1457 if (destination->details.exit_destination.af == AF_INET6)
1459 GNUNET_STATISTICS_update (stats,
1460 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1465 /* throw away IP-payload, exit will have to make it up anyway */
1466 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1469 GNUNET_STATISTICS_update (stats,
1470 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1475 /* end of AF_INET */
1480 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1481 if (destination->details.exit_destination.af == AF_INET6)
1482 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1483 /* throw away IP-payload, exit will have to make it up anyway */
1484 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1486 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1487 if (destination->details.exit_destination.af == AF_INET)
1488 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1489 /* throw away IP-payload, exit will have to make it up anyway */
1490 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1492 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1493 if (destination->details.exit_destination.af == AF_INET)
1495 GNUNET_STATISTICS_update (stats,
1496 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1501 /* throw away IP-payload, exit will have to make it up anyway */
1502 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1504 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1505 if (destination->details.exit_destination.af == AF_INET)
1507 GNUNET_STATISTICS_update (stats,
1508 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1513 /* throw away IP-payload, exit will have to make it up anyway */
1514 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1516 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1517 if (destination->details.exit_destination.af == AF_INET)
1518 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1520 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1521 if (destination->details.exit_destination.af == AF_INET)
1522 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1525 GNUNET_STATISTICS_update (stats,
1526 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1531 /* end of AF_INET6 */
1536 /* update length calculations, as payload_length may have changed */
1537 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1538 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1540 iim->header.size = htons ((uint16_t) mlen);
1542 /* need to tell destination ICMP protocol family! */
1543 iim->af = htonl (destination->details.exit_destination.af);
1544 switch (destination->details.exit_destination.af)
1547 ip4dst = (struct in_addr *) &iim[1];
1548 *ip4dst = destination->details.exit_destination.ip.v4;
1549 payload = &ip4dst[1];
1552 ip6dst = (struct in6_addr *) &iim[1];
1553 *ip6dst = destination->details.exit_destination.ip.v6;
1554 payload = &ip6dst[1];
1561 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1565 /* not supported above, how can we get here !? */
1569 ts->is_established = GNUNET_YES;
1570 send_to_channel (tnq, ts);
1575 * Receive packets from the helper-process (someone send to the local
1576 * virtual channel interface). Find the destination mapping, and if it
1577 * exists, identify the correct CADET channel (or possibly create it)
1578 * and forward the packet.
1580 * @param cls closure, NULL
1581 * @param client NULL
1582 * @param message message we got from the client (VPN channel interface)
1585 message_token (void *cls,
1587 const struct GNUNET_MessageHeader *message)
1589 const struct GNUNET_TUN_Layer2PacketHeader *tun;
1591 struct GNUNET_HashCode key;
1592 struct DestinationEntry *de;
1594 GNUNET_STATISTICS_update (stats,
1595 gettext_noop ("# Packets received from TUN interface"),
1597 mlen = ntohs (message->size);
1598 if ( (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
1599 (mlen < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader)) )
1604 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1605 mlen -= (sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader));
1606 switch (ntohs (tun->proto))
1610 const struct GNUNET_TUN_IPv6Header *pkt6;
1612 if (mlen < sizeof (struct GNUNET_TUN_IPv6Header))
1618 pkt6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1619 get_destination_key_from_ip (AF_INET6,
1620 &pkt6->destination_address,
1622 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1625 char buf[INET6_ADDRSTRLEN];
1627 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1628 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1629 inet_ntop (AF_INET6,
1630 &pkt6->destination_address,
1638 &pkt6->source_address,
1639 &pkt6->destination_address,
1641 mlen - sizeof (struct GNUNET_TUN_IPv6Header));
1646 struct GNUNET_TUN_IPv4Header *pkt4;
1648 if (mlen < sizeof (struct GNUNET_TUN_IPv4Header))
1654 pkt4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1655 get_destination_key_from_ip (AF_INET,
1656 &pkt4->destination_address,
1658 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1661 char buf[INET_ADDRSTRLEN];
1663 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1664 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1666 &pkt4->destination_address,
1671 if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header))
1673 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1674 _("Received IPv4 packet with options (dropping it)\n"));
1680 &pkt4->source_address,
1681 &pkt4->destination_address,
1683 mlen - sizeof (struct GNUNET_TUN_IPv4Header));
1687 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1688 _("Received packet of unknown protocol %d from TUN (dropping it)\n"),
1689 (unsigned int) ntohs (tun->proto));
1697 * Synthesize a plausible ICMP payload for an ICMP error
1698 * response on the given channel.
1700 * @param ts channel information
1701 * @param ipp IPv4 header to fill in (ICMP payload)
1702 * @param udp "UDP" header to fill in (ICMP payload); might actually
1703 * also be the first 8 bytes of the TCP header
1706 make_up_icmpv4_payload (struct ChannelState *ts,
1707 struct GNUNET_TUN_IPv4Header *ipp,
1708 struct GNUNET_TUN_UdpHeader *udp)
1710 GNUNET_TUN_initialize_ipv4_header (ipp,
1712 sizeof (struct GNUNET_TUN_TcpHeader),
1714 &ts->destination_ip.v4);
1715 udp->source_port = htons (ts->source_port);
1716 udp->destination_port = htons (ts->destination_port);
1717 udp->len = htons (0);
1718 udp->crc = htons (0);
1723 * Synthesize a plausible ICMP payload for an ICMP error
1724 * response on the given channel.
1726 * @param ts channel information
1727 * @param ipp IPv6 header to fill in (ICMP payload)
1728 * @param udp "UDP" header to fill in (ICMP payload); might actually
1729 * also be the first 8 bytes of the TCP header
1732 make_up_icmpv6_payload (struct ChannelState *ts,
1733 struct GNUNET_TUN_IPv6Header *ipp,
1734 struct GNUNET_TUN_UdpHeader *udp)
1736 GNUNET_TUN_initialize_ipv6_header (ipp,
1738 sizeof (struct GNUNET_TUN_TcpHeader),
1740 &ts->destination_ip.v6);
1741 udp->source_port = htons (ts->source_port);
1742 udp->destination_port = htons (ts->destination_port);
1743 udp->len = htons (0);
1744 udp->crc = htons (0);
1749 * We got an ICMP packet back from the CADET channel. Pass it on to the
1750 * local virtual interface via the helper.
1752 * @param cls closure, NULL
1753 * @param channel connection to the other end
1754 * @param channel_ctx pointer to our 'struct ChannelState *'
1755 * @param message the actual message
1756 * @return #GNUNET_OK to keep the connection open,
1757 * #GNUNET_SYSERR to close it (signal serious error)
1760 receive_icmp_back (void *cls,
1761 struct GNUNET_CADET_Channel *channel,
1763 const struct GNUNET_MessageHeader *message)
1765 struct ChannelState *ts = *channel_ctx;
1766 const struct GNUNET_EXIT_IcmpToVPNMessage *i2v;
1769 GNUNET_STATISTICS_update (stats,
1770 gettext_noop ("# ICMP packets received from cadet"),
1772 mlen = ntohs (message->size);
1773 if (mlen < sizeof (struct GNUNET_EXIT_IcmpToVPNMessage))
1775 GNUNET_break_op (0);
1776 return GNUNET_SYSERR;
1778 if (NULL == ts->heap_node)
1780 GNUNET_break_op (0);
1781 return GNUNET_SYSERR;
1783 if (AF_UNSPEC == ts->af)
1785 GNUNET_break_op (0);
1786 return GNUNET_SYSERR;
1788 i2v = (const struct GNUNET_EXIT_IcmpToVPNMessage *) message;
1789 mlen -= sizeof (struct GNUNET_EXIT_IcmpToVPNMessage);
1791 char sbuf[INET6_ADDRSTRLEN];
1792 char dbuf[INET6_ADDRSTRLEN];
1794 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1795 "Received ICMP packet from cadet, sending %u bytes from %s -> %s via TUN\n",
1796 (unsigned int) mlen,
1797 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
1798 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)));
1804 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
1805 + sizeof (struct GNUNET_TUN_IcmpHeader)
1806 + sizeof (struct GNUNET_MessageHeader) +
1807 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1810 /* reserve some extra space in case we have an ICMP type here where
1811 we will need to make up the payload ourselves */
1812 char buf[size + sizeof (struct GNUNET_TUN_IPv4Header) + 8] GNUNET_ALIGN;
1813 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1814 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1815 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1816 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv4[1];
1817 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1818 tun->flags = htons (0);
1819 tun->proto = htons (ETH_P_IPV4);
1820 GNUNET_TUN_initialize_ipv4_header (ipv4,
1822 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1823 &ts->destination_ip.v4,
1825 *icmp = i2v->icmp_header;
1829 /* For some ICMP types, we need to adjust (make up) the payload here.
1830 Also, depending on the AF used on the other side, we have to
1831 do ICMP PT (translate ICMP types) */
1832 switch (ntohl (i2v->af))
1837 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1838 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1840 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1841 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1842 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1844 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1845 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1849 /* sender did not strip ICMP payload? */
1850 GNUNET_break_op (0);
1851 return GNUNET_SYSERR;
1853 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1854 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1855 make_up_icmpv4_payload (ts, ipp, udp);
1859 GNUNET_break_op (0);
1860 GNUNET_STATISTICS_update (stats,
1861 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1863 return GNUNET_SYSERR;
1868 /* ICMP PT 6-to-4 and possibly making up payloads */
1871 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1872 icmp->type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
1874 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1875 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1879 /* sender did not strip ICMP payload? */
1880 GNUNET_break_op (0);
1881 return GNUNET_SYSERR;
1883 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1884 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1885 make_up_icmpv4_payload (ts, ipp, udp);
1888 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1889 icmp->type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1891 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1892 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1896 /* sender did not strip ICMP payload? */
1897 GNUNET_break_op (0);
1898 return GNUNET_SYSERR;
1900 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1901 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1902 make_up_icmpv4_payload (ts, ipp, udp);
1905 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1906 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1907 GNUNET_STATISTICS_update (stats,
1908 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1911 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1912 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1914 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1915 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1918 GNUNET_break_op (0);
1919 GNUNET_STATISTICS_update (stats,
1920 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1922 return GNUNET_SYSERR;
1927 GNUNET_break_op (0);
1928 return GNUNET_SYSERR;
1930 msg->size = htons (size);
1931 GNUNET_TUN_calculate_icmp_checksum (icmp,
1934 (void) GNUNET_HELPER_send (helper_handle,
1943 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
1944 + sizeof (struct GNUNET_TUN_IcmpHeader)
1945 + sizeof (struct GNUNET_MessageHeader) +
1946 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1949 char buf[size + sizeof (struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN;
1950 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1951 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1952 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
1953 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv6[1];
1954 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1955 tun->flags = htons (0);
1956 tun->proto = htons (ETH_P_IPV6);
1957 GNUNET_TUN_initialize_ipv6_header (ipv6,
1959 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1960 &ts->destination_ip.v6,
1962 *icmp = i2v->icmp_header;
1967 /* For some ICMP types, we need to adjust (make up) the payload here.
1968 Also, depending on the AF used on the other side, we have to
1969 do ICMP PT (translate ICMP types) */
1970 switch (ntohl (i2v->af))
1973 /* ICMP PT 4-to-6 and possibly making up payloads */
1976 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1977 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1979 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1980 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1982 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1983 icmp->type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1985 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1986 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1990 /* sender did not strip ICMP payload? */
1991 GNUNET_break_op (0);
1992 return GNUNET_SYSERR;
1994 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1995 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1996 make_up_icmpv6_payload (ts, ipp, udp);
1999 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
2000 icmp->type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
2002 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
2003 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
2007 /* sender did not strip ICMP payload? */
2008 GNUNET_break_op (0);
2009 return GNUNET_SYSERR;
2011 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
2012 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
2013 make_up_icmpv6_payload (ts, ipp, udp);
2016 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
2017 GNUNET_STATISTICS_update (stats,
2018 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
2022 GNUNET_break_op (0);
2023 GNUNET_STATISTICS_update (stats,
2024 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
2026 return GNUNET_SYSERR;
2033 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
2034 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
2035 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
2036 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
2038 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
2039 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
2043 /* sender did not strip ICMP payload? */
2044 GNUNET_break_op (0);
2045 return GNUNET_SYSERR;
2047 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
2048 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
2049 make_up_icmpv6_payload (ts, ipp, udp);
2052 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
2055 GNUNET_break_op (0);
2056 GNUNET_STATISTICS_update (stats,
2057 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
2059 return GNUNET_SYSERR;
2064 GNUNET_break_op (0);
2065 return GNUNET_SYSERR;
2067 msg->size = htons (size);
2068 GNUNET_TUN_calculate_icmp_checksum (icmp,
2070 (void) GNUNET_HELPER_send (helper_handle,
2080 GNUNET_CONTAINER_heap_update_cost (channel_heap,
2082 GNUNET_TIME_absolute_get ().abs_value_us);
2083 GNUNET_CADET_receive_done (channel);
2089 * We got a UDP packet back from the CADET channel. Pass it on to the
2090 * local virtual interface via the helper.
2092 * @param cls closure, NULL
2093 * @param channel connection to the other end
2094 * @param channel_ctx pointer to our 'struct ChannelState *'
2095 * @param message the actual message
2096 * @return #GNUNET_OK to keep the connection open,
2097 * #GNUNET_SYSERR to close it (signal serious error)
2100 receive_udp_back (void *cls,
2101 struct GNUNET_CADET_Channel *channel,
2103 const struct GNUNET_MessageHeader *message)
2105 struct ChannelState *ts = *channel_ctx;
2106 const struct GNUNET_EXIT_UdpReplyMessage *reply;
2109 GNUNET_STATISTICS_update (stats,
2110 gettext_noop ("# UDP packets received from cadet"),
2112 mlen = ntohs (message->size);
2113 if (mlen < sizeof (struct GNUNET_EXIT_UdpReplyMessage))
2115 GNUNET_break_op (0);
2116 return GNUNET_SYSERR;
2118 if (NULL == ts->heap_node)
2120 GNUNET_break_op (0);
2121 return GNUNET_SYSERR;
2123 if (AF_UNSPEC == ts->af)
2125 GNUNET_break_op (0);
2126 return GNUNET_SYSERR;
2128 reply = (const struct GNUNET_EXIT_UdpReplyMessage *) message;
2129 mlen -= sizeof (struct GNUNET_EXIT_UdpReplyMessage);
2131 char sbuf[INET6_ADDRSTRLEN];
2132 char dbuf[INET6_ADDRSTRLEN];
2134 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2135 "Received UDP reply from cadet, sending %u bytes from [%s]:%u -> [%s]:%u via TUN\n",
2136 (unsigned int) mlen,
2137 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2138 ts->destination_port,
2139 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2146 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2147 + sizeof (struct GNUNET_TUN_UdpHeader)
2148 + sizeof (struct GNUNET_MessageHeader) +
2149 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2152 char buf[size] GNUNET_ALIGN;
2153 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2154 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2155 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2156 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1];
2157 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2158 msg->size = htons (size);
2159 tun->flags = htons (0);
2160 tun->proto = htons (ETH_P_IPV4);
2161 GNUNET_TUN_initialize_ipv4_header (ipv4,
2163 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2164 &ts->destination_ip.v4,
2166 if (0 == ntohs (reply->source_port))
2167 udp->source_port = htons (ts->destination_port);
2169 udp->source_port = reply->source_port;
2170 if (0 == ntohs (reply->destination_port))
2171 udp->destination_port = htons (ts->source_port);
2173 udp->destination_port = reply->destination_port;
2174 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2175 GNUNET_TUN_calculate_udp4_checksum (ipv4,
2182 (void) GNUNET_HELPER_send (helper_handle,
2191 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2192 + sizeof (struct GNUNET_TUN_UdpHeader)
2193 + sizeof (struct GNUNET_MessageHeader) +
2194 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2197 char buf[size] GNUNET_ALIGN;
2198 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2199 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2200 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2201 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1];
2202 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2203 msg->size = htons (size);
2204 tun->flags = htons (0);
2205 tun->proto = htons (ETH_P_IPV6);
2206 GNUNET_TUN_initialize_ipv6_header (ipv6,
2208 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2209 &ts->destination_ip.v6,
2211 if (0 == ntohs (reply->source_port))
2212 udp->source_port = htons (ts->destination_port);
2214 udp->source_port = reply->source_port;
2215 if (0 == ntohs (reply->destination_port))
2216 udp->destination_port = htons (ts->source_port);
2218 udp->destination_port = reply->destination_port;
2219 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2220 GNUNET_TUN_calculate_udp6_checksum (ipv6,
2226 (void) GNUNET_HELPER_send (helper_handle,
2236 GNUNET_CONTAINER_heap_update_cost (channel_heap,
2238 GNUNET_TIME_absolute_get ().abs_value_us);
2239 GNUNET_CADET_receive_done (channel);
2245 * We got a TCP packet back from the CADET channel. Pass it on to the
2246 * local virtual interface via the helper.
2248 * @param cls closure, NULL
2249 * @param channel connection to the other end
2250 * @param channel_ctx pointer to our `struct ChannelState *`
2251 * @param message the actual message
2252 * @return #GNUNET_OK to keep the connection open,
2253 * #GNUNET_SYSERR to close it (signal serious error)
2256 receive_tcp_back (void *cls,
2257 struct GNUNET_CADET_Channel *channel,
2259 const struct GNUNET_MessageHeader *message)
2261 struct ChannelState *ts = *channel_ctx;
2262 const struct GNUNET_EXIT_TcpDataMessage *data;
2265 GNUNET_STATISTICS_update (stats,
2266 gettext_noop ("# TCP packets received from cadet"),
2268 mlen = ntohs (message->size);
2269 if (mlen < sizeof (struct GNUNET_EXIT_TcpDataMessage))
2271 GNUNET_break_op (0);
2272 return GNUNET_SYSERR;
2274 if (NULL == ts->heap_node)
2276 GNUNET_break_op (0);
2277 return GNUNET_SYSERR;
2279 data = (const struct GNUNET_EXIT_TcpDataMessage *) message;
2280 mlen -= sizeof (struct GNUNET_EXIT_TcpDataMessage);
2282 char sbuf[INET6_ADDRSTRLEN];
2283 char dbuf[INET6_ADDRSTRLEN];
2285 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2286 "Received TCP reply from cadet, sending %u bytes from [%s]:%u -> [%s]:%u via TUN\n",
2287 (unsigned int) mlen,
2288 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2289 ts->destination_port,
2290 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2293 if (data->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
2295 GNUNET_break_op (0);
2296 return GNUNET_SYSERR;
2302 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2303 + sizeof (struct GNUNET_TUN_TcpHeader)
2304 + sizeof (struct GNUNET_MessageHeader) +
2305 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2308 char buf[size] GNUNET_ALIGN;
2309 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2310 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2311 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2312 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv4[1];
2313 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2314 msg->size = htons (size);
2315 tun->flags = htons (0);
2316 tun->proto = htons (ETH_P_IPV4);
2317 GNUNET_TUN_initialize_ipv4_header (ipv4,
2319 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2320 &ts->destination_ip.v4,
2322 *tcp = data->tcp_header;
2323 tcp->source_port = htons (ts->destination_port);
2324 tcp->destination_port = htons (ts->source_port);
2325 GNUNET_TUN_calculate_tcp4_checksum (ipv4,
2332 (void) GNUNET_HELPER_send (helper_handle,
2341 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2342 + sizeof (struct GNUNET_TUN_TcpHeader)
2343 + sizeof (struct GNUNET_MessageHeader) +
2344 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2347 char buf[size] GNUNET_ALIGN;
2348 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2349 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2350 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2351 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv6[1];
2352 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2353 msg->size = htons (size);
2354 tun->flags = htons (0);
2355 tun->proto = htons (ETH_P_IPV6);
2356 GNUNET_TUN_initialize_ipv6_header (ipv6,
2358 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2359 &ts->destination_ip.v6,
2361 *tcp = data->tcp_header;
2362 tcp->source_port = htons (ts->destination_port);
2363 tcp->destination_port = htons (ts->source_port);
2364 GNUNET_TUN_calculate_tcp6_checksum (ipv6,
2371 (void) GNUNET_HELPER_send (helper_handle,
2379 GNUNET_CONTAINER_heap_update_cost (channel_heap,
2381 GNUNET_TIME_absolute_get ().abs_value_us);
2382 GNUNET_CADET_receive_done (channel);
2388 * Allocate an IPv4 address from the range of the channel
2389 * for a new redirection.
2391 * @param v4 where to store the address
2392 * @return #GNUNET_OK on success,
2393 * #GNUNET_SYSERR on error
2396 allocate_v4_address (struct in_addr *v4)
2398 const char *ipv4addr = vpn_argv[4];
2399 const char *ipv4mask = vpn_argv[5];
2400 struct in_addr addr;
2401 struct in_addr mask;
2403 struct GNUNET_HashCode key;
2406 GNUNET_assert (1 == inet_pton (AF_INET, ipv4addr, &addr));
2407 GNUNET_assert (1 == inet_pton (AF_INET, ipv4mask, &mask));
2408 /* Given 192.168.0.1/255.255.0.0, we want a mask
2409 of '192.168.255.255', thus: */
2410 mask.s_addr = addr.s_addr | ~mask.s_addr;
2417 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2418 _("Failed to find unallocated IPv4 address in VPN's range\n"));
2419 return GNUNET_SYSERR;
2421 /* Pick random IPv4 address within the subnet, except 'addr' or 'mask' itself */
2422 rnd.s_addr = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2424 v4->s_addr = (addr.s_addr | rnd.s_addr) & mask.s_addr;
2425 get_destination_key_from_ip (AF_INET,
2429 while ( (GNUNET_YES ==
2430 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2432 (v4->s_addr == addr.s_addr) ||
2433 (v4->s_addr == mask.s_addr) );
2439 * Allocate an IPv6 address from the range of the channel
2440 * for a new redirection.
2442 * @param v6 where to store the address
2443 * @return #GNUNET_OK on success,
2444 * #GNUNET_SYSERR on error
2447 allocate_v6_address (struct in6_addr *v6)
2449 const char *ipv6addr = vpn_argv[2];
2450 struct in6_addr addr;
2451 struct in6_addr mask;
2452 struct in6_addr rnd;
2454 struct GNUNET_HashCode key;
2457 GNUNET_assert (1 == inet_pton (AF_INET6, ipv6addr, &addr));
2458 GNUNET_assert (ipv6prefix < 128);
2459 /* Given ABCD::/96, we want a mask of 'ABCD::FFFF:FFFF,
2462 for (i=127;i>=ipv6prefix;i--)
2463 mask.s6_addr[i / 8] |= (1 << (i % 8));
2465 /* Pick random IPv6 address within the subnet, except 'addr' or 'mask' itself */
2472 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2473 _("Failed to find unallocated IPv6 address in VPN's range\n"));
2474 return GNUNET_SYSERR;
2479 rnd.s6_addr[i] = (unsigned char) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2482 = (addr.s6_addr[i] | rnd.s6_addr[i]) & mask.s6_addr[i];
2484 get_destination_key_from_ip (AF_INET6,
2488 while ( (GNUNET_YES ==
2489 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2493 sizeof (struct in6_addr))) ||
2496 sizeof (struct in6_addr))) );
2502 * Free resources occupied by a destination entry.
2504 * @param de entry to free
2507 free_destination_entry (struct DestinationEntry *de)
2509 struct DestinationChannel *dt;
2511 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2512 "Cleaning up destination entry `%s'\n",
2513 print_channel_destination (de));
2514 GNUNET_STATISTICS_update (stats,
2515 gettext_noop ("# Active destinations"),
2517 while (NULL != (dt = de->dt_head))
2519 GNUNET_CONTAINER_DLL_remove (de->dt_head,
2524 free_channel_state (dt->ts);
2525 GNUNET_assert (NULL == dt->ts);
2529 if (NULL != de->heap_node)
2531 GNUNET_CONTAINER_heap_remove_node (de->heap_node);
2532 de->heap_node = NULL;
2533 GNUNET_assert (GNUNET_YES ==
2534 GNUNET_CONTAINER_multihashmap_remove (destination_map,
2543 * We have too many active destinations. Clean up the oldest destination.
2545 * @param except destination that must NOT be cleaned up, even if it is the oldest
2548 expire_destination (struct DestinationEntry *except)
2550 struct DestinationEntry *de;
2552 de = GNUNET_CONTAINER_heap_peek (destination_heap);
2553 GNUNET_assert (NULL != de);
2555 return; /* can't do this */
2556 free_destination_entry (de);
2561 * Allocate an IP address for the response.
2563 * @param result_af desired address family; set to the actual
2564 * address family; can initially be AF_UNSPEC if there
2565 * is no preference; will be set to AF_UNSPEC if the
2567 * @param addr set to either v4 or v6 depending on which
2568 * storage location was used; set to NULL if allocation failed
2569 * @param v4 storage space for an IPv4 address
2570 * @param v6 storage space for an IPv6 address
2571 * @return #GNUNET_OK normally, #GNUNET_SYSERR if `* result_af` was
2572 * an unsupported address family (not AF_INET, AF_INET6 or AF_UNSPEC)
2575 allocate_response_ip (int *result_af,
2578 struct in6_addr *v6)
2585 allocate_v4_address (v4))
2586 *result_af = AF_UNSPEC;
2592 allocate_v6_address (v6))
2593 *result_af = AF_UNSPEC;
2599 allocate_v4_address (v4))
2602 *result_af = AF_INET;
2604 else if (GNUNET_OK ==
2605 allocate_v6_address (v6))
2608 *result_af = AF_INET6;
2613 return GNUNET_SYSERR;
2620 * A client asks us to setup a redirection via some exit node to a
2621 * particular IP. Setup the redirection and give the client the
2625 * @param client requesting client
2626 * @param message redirection request (a `struct RedirectToIpRequestMessage`)
2629 service_redirect_to_ip (void *cls,
2630 struct GNUNET_SERVER_Client *client,
2631 const struct GNUNET_MessageHeader *message)
2635 const struct RedirectToIpRequestMessage *msg;
2641 struct DestinationEntry *de;
2642 struct GNUNET_HashCode key;
2644 /* validate and parse request */
2645 mlen = ntohs (message->size);
2646 if (mlen < sizeof (struct RedirectToIpRequestMessage))
2649 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2652 alen = mlen - sizeof (struct RedirectToIpRequestMessage);
2653 msg = (const struct RedirectToIpRequestMessage *) message;
2654 addr_af = (int) htonl (msg->addr_af);
2658 if (alen != sizeof (struct in_addr))
2661 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2666 if (alen != sizeof (struct in6_addr))
2669 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2675 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2679 /* allocate response IP */
2680 result_af = (int) htonl (msg->result_af);
2681 if (GNUNET_OK != allocate_response_ip (&result_af,
2685 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2688 /* send reply with our IP address */
2689 send_client_reply (client,
2693 if (result_af == AF_UNSPEC)
2695 /* failure, we're done */
2696 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2701 char sbuf[INET6_ADDRSTRLEN];
2702 char dbuf[INET6_ADDRSTRLEN];
2704 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2705 "Allocated address %s for redirection via exit to %s\n",
2706 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2708 &msg[1], dbuf, sizeof (dbuf)));
2711 /* setup destination record */
2712 de = GNUNET_new (struct DestinationEntry);
2713 de->is_service = GNUNET_NO;
2714 de->details.exit_destination.af = addr_af;
2715 memcpy (&de->details.exit_destination.ip,
2718 get_destination_key_from_ip (result_af,
2722 GNUNET_assert (GNUNET_OK ==
2723 GNUNET_CONTAINER_multihashmap_put (destination_map,
2726 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2727 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2729 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value_us);
2730 GNUNET_STATISTICS_update (stats,
2731 gettext_noop ("# Active destinations"),
2733 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2734 expire_destination (de);
2735 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2740 * A client asks us to setup a redirection to a particular peer
2741 * offering a service. Setup the redirection and give the client the
2745 * @param client requesting client
2746 * @param message redirection request (a `struct RedirectToPeerRequestMessage`)
2749 service_redirect_to_service (void *cls,
2750 struct GNUNET_SERVER_Client *client,
2751 const struct GNUNET_MessageHeader *message)
2753 const struct RedirectToServiceRequestMessage *msg;
2758 struct DestinationEntry *de;
2759 struct GNUNET_HashCode key;
2760 struct DestinationChannel *dt;
2763 msg = (const struct RedirectToServiceRequestMessage *) message;
2765 /* allocate response IP */
2766 result_af = (int) htonl (msg->result_af);
2767 if (GNUNET_OK != allocate_response_ip (&result_af,
2771 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2774 send_client_reply (client,
2778 if (result_af == AF_UNSPEC)
2780 /* failure, we're done */
2781 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2782 _("Failed to allocate IP address for new destination\n"));
2783 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2788 char sbuf[INET6_ADDRSTRLEN];
2790 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2791 "Allocated address %s for redirection to service %s on peer %s\n",
2792 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2793 GNUNET_h2s (&msg->service_descriptor),
2794 GNUNET_i2s (&msg->target));
2797 /* setup destination record */
2798 de = GNUNET_new (struct DestinationEntry);
2799 de->is_service = GNUNET_YES;
2800 de->details.service_destination.service_descriptor = msg->service_descriptor;
2801 de->details.service_destination.target = msg->target;
2802 get_destination_key_from_ip (result_af,
2806 GNUNET_assert (GNUNET_OK ==
2807 GNUNET_CONTAINER_multihashmap_put (destination_map,
2810 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2811 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2813 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value_us);
2814 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2815 expire_destination (de);
2817 dt = GNUNET_new (struct DestinationChannel);
2818 dt->destination = de;
2819 GNUNET_CONTAINER_DLL_insert (de->dt_head,
2823 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2828 * Function called whenever a channel is destroyed. Should clean up
2829 * any associated state.
2831 * @param cls closure (set from #GNUNET_CADET_connect)
2832 * @param channel connection to the other end (henceforth invalid)
2833 * @param channel_ctx place where local state associated
2834 * with the channel is stored (our `struct ChannelState`)
2837 channel_cleaner (void *cls,
2838 const struct GNUNET_CADET_Channel *channel,
2841 struct ChannelState *ts = channel_ctx;
2843 ts->channel = NULL; /* we must not call GNUNET_CADET_channel_destroy() anymore */
2844 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2845 "CADET notified us about death of channel to `%s'\n",
2846 print_channel_destination (&ts->destination));
2847 free_channel_state (ts);
2852 * Free memory occupied by an entry in the destination map.
2856 * @param value a `struct DestinationEntry *`
2857 * @return #GNUNET_OK (continue to iterate)
2860 cleanup_destination (void *cls,
2861 const struct GNUNET_HashCode *key,
2864 struct DestinationEntry *de = value;
2866 free_destination_entry (de);
2872 * Free memory occupied by an entry in the channel map.
2876 * @param value a `struct ChannelState *`
2877 * @return #GNUNET_OK (continue to iterate)
2880 cleanup_channel (void *cls,
2881 const struct GNUNET_HashCode *key,
2884 struct ChannelState *ts = value;
2886 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2887 "Tearing down channel to `%s' during cleanup\n",
2888 print_channel_destination (&ts->destination));
2889 free_channel_state (ts);
2895 * Function scheduled as very last function, cleans up after us
2902 const struct GNUNET_SCHEDULER_TaskContext *tc)
2906 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2907 "VPN is shutting down\n");
2908 if (NULL != destination_map)
2910 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
2911 &cleanup_destination,
2913 GNUNET_CONTAINER_multihashmap_destroy (destination_map);
2914 destination_map = NULL;
2916 if (NULL != destination_heap)
2918 GNUNET_CONTAINER_heap_destroy (destination_heap);
2919 destination_heap = NULL;
2921 if (NULL != channel_map)
2923 GNUNET_CONTAINER_multihashmap_iterate (channel_map,
2926 GNUNET_CONTAINER_multihashmap_destroy (channel_map);
2929 if (NULL != channel_heap)
2931 GNUNET_CONTAINER_heap_destroy (channel_heap);
2932 channel_heap = NULL;
2934 if (NULL != cadet_handle)
2936 GNUNET_CADET_disconnect (cadet_handle);
2937 cadet_handle = NULL;
2939 if (NULL != helper_handle)
2941 GNUNET_HELPER_kill (helper_handle, GNUNET_NO);
2942 GNUNET_HELPER_wait (helper_handle);
2943 helper_handle = NULL;
2947 GNUNET_SERVER_notification_context_destroy (nc);
2952 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
2956 GNUNET_free_non_null (vpn_argv[i]);
2961 * Main function that will be run by the scheduler.
2963 * @param cls closure
2964 * @param server the initialized server
2965 * @param cfg_ configuration
2969 struct GNUNET_SERVER_Handle *server,
2970 const struct GNUNET_CONFIGURATION_Handle *cfg_)
2972 static const struct GNUNET_SERVER_MessageHandler service_handlers[] = {
2973 /* callback, cls, type, size */
2974 { &service_redirect_to_ip, NULL, GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP, 0},
2975 { &service_redirect_to_service, NULL,
2976 GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE,
2977 sizeof (struct RedirectToServiceRequestMessage) },
2980 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
2981 { &receive_udp_back, GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY, 0},
2982 { &receive_tcp_back, GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN, 0},
2983 { &receive_icmp_back, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN, 0},
2995 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-vpn");
2998 GNUNET_OS_check_helper_binary (binary,
3000 "-d gnunet-vpn - - 169.1.3.3.7 255.255.255.0")) //ipv4 only please!
3002 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3003 "`%s' is not SUID, refusing to run.\n",
3004 "gnunet-helper-vpn");
3005 GNUNET_free (binary);
3007 /* we won't "really" exit here, as the 'service' is still running;
3008 however, as no handlers are registered, the service won't do
3012 GNUNET_free (binary);
3014 stats = GNUNET_STATISTICS_create ("vpn", cfg);
3016 GNUNET_CONFIGURATION_get_value_number (cfg, "VPN", "MAX_MAPPING",
3017 &max_destination_mappings))
3018 max_destination_mappings = 200;
3020 GNUNET_CONFIGURATION_get_value_number (cfg, "VPN", "MAX_TUNNELS",
3021 &max_channel_mappings))
3022 max_channel_mappings = 200;
3024 destination_map = GNUNET_CONTAINER_multihashmap_create (max_destination_mappings * 2, GNUNET_NO);
3025 destination_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3026 channel_map = GNUNET_CONTAINER_multihashmap_create (max_channel_mappings * 2, GNUNET_NO);
3027 channel_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3030 vpn_argv[0] = GNUNET_strdup ("vpn-gnunet");
3031 if (GNUNET_SYSERR ==
3032 GNUNET_CONFIGURATION_get_value_string (cfg, "VPN", "IFNAME", &ifname))
3034 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "VPN", "IFNAME");
3035 GNUNET_SCHEDULER_shutdown ();
3038 vpn_argv[1] = ifname;
3040 if (GNUNET_OK == GNUNET_NETWORK_test_pf (PF_INET6))
3042 if ( (GNUNET_SYSERR ==
3043 GNUNET_CONFIGURATION_get_value_string (cfg, "VPN", "IPV6ADDR",
3045 (1 != inet_pton (AF_INET6, ipv6addr, &v6))) )
3047 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV6ADDR",
3048 _("Must specify valid IPv6 address"));
3049 GNUNET_SCHEDULER_shutdown ();
3050 GNUNET_free_non_null (ipv6addr);
3053 vpn_argv[2] = ipv6addr;
3054 ipv6prefix_s = NULL;
3055 if (GNUNET_SYSERR ==
3056 GNUNET_CONFIGURATION_get_value_string (cfg, "VPN", "IPV6PREFIX",
3059 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV6PREFIX");
3060 GNUNET_SCHEDULER_shutdown ();
3061 GNUNET_free_non_null (ipv6prefix_s);
3064 vpn_argv[3] = ipv6prefix_s;
3066 GNUNET_CONFIGURATION_get_value_number (cfg, "VPN",
3069 (ipv6prefix >= 127) )
3071 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV4MASK",
3072 _("Must specify valid IPv6 mask"));
3073 GNUNET_SCHEDULER_shutdown ();
3079 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3080 _("IPv6 support disabled as this system does not support IPv6\n"));
3081 vpn_argv[2] = GNUNET_strdup ("-");
3082 vpn_argv[3] = GNUNET_strdup ("-");
3084 if (GNUNET_OK == GNUNET_NETWORK_test_pf (PF_INET))
3087 if ( (GNUNET_SYSERR ==
3088 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4ADDR",
3090 (1 != inet_pton (AF_INET, ipv4addr, &v4))) )
3092 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV4ADDR",
3093 _("Must specify valid IPv4 address"));
3094 GNUNET_SCHEDULER_shutdown ();
3095 GNUNET_free_non_null (ipv4addr);
3098 vpn_argv[4] = ipv4addr;
3100 if ( (GNUNET_SYSERR ==
3101 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4MASK",
3103 (1 != inet_pton (AF_INET, ipv4mask, &v4))) )
3105 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV4MASK",
3106 _("Must specify valid IPv4 mask"));
3107 GNUNET_SCHEDULER_shutdown ();
3108 GNUNET_free_non_null (ipv4mask);
3111 vpn_argv[5] = ipv4mask;
3115 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3116 _("IPv4 support disabled as this system does not support IPv4\n"));
3117 vpn_argv[4] = GNUNET_strdup ("-");
3118 vpn_argv[5] = GNUNET_strdup ("-");
3123 GNUNET_CADET_connect (cfg_, NULL,
3128 helper_handle = GNUNET_HELPER_start (GNUNET_NO,
3129 "gnunet-helper-vpn", vpn_argv,
3130 &message_token, NULL, NULL);
3131 nc = GNUNET_SERVER_notification_context_create (server, 1);
3132 GNUNET_SERVER_add_handlers (server, service_handlers);
3133 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
3140 * The main function of the VPN service.
3142 * @param argc number of arguments from the command line
3143 * @param argv command line arguments
3144 * @return 0 ok, 1 on error
3147 main (int argc, char *const *argv)
3149 return (GNUNET_OK ==
3150 GNUNET_SERVICE_run (argc, argv, "vpn",
3151 GNUNET_SERVICE_OPTION_NONE,
3152 &run, NULL)) ? global_ret : 1;
3155 /* end of gnunet-service-vpn.c */