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 to peer %s offering service %s\n",
834 GNUNET_i2s (&dt->destination->details.service_destination.target),
835 GNUNET_h2s (&dt->destination->details.service_destination.service_descriptor));
841 switch (dt->destination->details.exit_destination.af)
845 char address[GNUNET_TUN_IPV4_REGEXLEN];
847 GNUNET_TUN_ipv4toregexsearch (&dt->destination->details.exit_destination.ip.v4,
848 dt->destination_port,
850 GNUNET_asprintf (&policy,
852 GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
858 char address[GNUNET_TUN_IPV6_REGEXLEN];
860 GNUNET_TUN_ipv6toregexsearch (&dt->destination->details.exit_destination.ip.v6,
861 dt->destination_port,
863 GNUNET_asprintf (&policy,
865 GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
874 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
875 "Requesting connect by string: %s\n",
877 ts->search = GNUNET_REGEX_search (cfg,
879 &handle_regex_result,
881 GNUNET_free (policy);
888 * We have too many active channels. Clean up the oldest channel.
890 * @param except channel that must NOT be cleaned up, even if it is the oldest
893 expire_channel (struct ChannelState *except)
895 struct ChannelState *ts;
897 ts = GNUNET_CONTAINER_heap_peek (channel_heap);
898 GNUNET_assert (NULL != ts);
900 return; /* can't do this */
901 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
902 "Tearing down expired channel to %s\n",
903 print_channel_destination (&except->destination));
904 free_channel_state (ts);
909 * Route a packet via cadet to the given destination.
911 * @param destination description of the destination
912 * @param af address family on this end (AF_INET or AF_INET6)
913 * @param protocol IPPROTO_TCP or IPPROTO_UDP or IPPROTO_ICMP or IPPROTO_ICMPV6
914 * @param source_ip source IP used by the sender (struct in_addr or struct in6_addr)
915 * @param destination_ip destination IP used by the sender (struct in_addr or struct in6_addr)
916 * @param payload payload of the packet after the IP header
917 * @param payload_length number of bytes in @a payload
920 route_packet (struct DestinationEntry *destination,
923 const void *source_ip,
924 const void *destination_ip,
926 size_t payload_length)
928 struct GNUNET_HashCode key;
929 struct ChannelState *ts;
930 struct ChannelMessageQueueEntry *tnq;
933 const struct GNUNET_TUN_UdpHeader *udp;
934 const struct GNUNET_TUN_TcpHeader *tcp;
935 const struct GNUNET_TUN_IcmpHeader *icmp;
936 struct DestinationChannel *dt;
937 uint16_t source_port;
938 uint16_t destination_port;
944 if (payload_length < sizeof (struct GNUNET_TUN_UdpHeader))
950 tcp = NULL; /* make compiler happy */
951 icmp = NULL; /* make compiler happy */
953 if (udp->len < sizeof (struct GNUNET_TUN_UdpHeader))
958 source_port = ntohs (udp->source_port);
959 destination_port = ntohs (udp->destination_port);
960 get_channel_key_from_ips (af,
971 if (payload_length < sizeof (struct GNUNET_TUN_TcpHeader))
977 udp = NULL; /* make compiler happy */
978 icmp = NULL; /* make compiler happy */
980 if (tcp->off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
985 source_port = ntohs (tcp->source_port);
986 destination_port = ntohs (tcp->destination_port);
987 get_channel_key_from_ips (af,
999 if ( (AF_INET == af) ^ (protocol == IPPROTO_ICMP) )
1004 if (payload_length < sizeof (struct GNUNET_TUN_IcmpHeader))
1010 tcp = NULL; /* make compiler happy */
1011 udp = NULL; /* make compiler happy */
1014 destination_port = 0;
1015 get_channel_key_from_ips (af,
1025 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1026 _("Protocol %u not supported, dropping\n"),
1027 (unsigned int) protocol);
1031 if (! destination->is_service)
1033 switch (destination->details.exit_destination.af)
1036 alen = sizeof (struct in_addr);
1039 alen = sizeof (struct in6_addr);
1046 char sbuf[INET6_ADDRSTRLEN];
1047 char dbuf[INET6_ADDRSTRLEN];
1048 char xbuf[INET6_ADDRSTRLEN];
1050 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1051 "Routing %s packet from %s:%u -> %s:%u to destination %s:%u\n",
1052 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
1053 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
1055 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
1057 inet_ntop (destination->details.exit_destination.af,
1058 &destination->details.exit_destination.ip,
1059 xbuf, sizeof (xbuf)),
1062 for (dt = destination->dt_head; NULL != dt; dt = dt->next)
1063 if (dt->destination_port == destination_port)
1069 char sbuf[INET6_ADDRSTRLEN];
1070 char dbuf[INET6_ADDRSTRLEN];
1072 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1073 "Routing %s packet from %s:%u -> %s:%u to service %s at peer %s\n",
1074 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
1075 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
1077 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
1079 GNUNET_h2s (&destination->details.service_destination.service_descriptor),
1080 GNUNET_i2s (&destination->details.service_destination.target));
1082 dt = destination->dt_head;
1086 dt = GNUNET_new (struct DestinationChannel);
1087 dt->destination = destination;
1088 GNUNET_CONTAINER_DLL_insert (destination->dt_head,
1089 destination->dt_tail,
1091 dt->destination_port = destination_port;
1094 /* see if we have an existing channel for this destination */
1095 ts = GNUNET_CONTAINER_multihashmap_get (channel_map,
1099 /* need to either use the existing channel from the destination (if still
1100 available) or create a fresh one */
1102 ts = create_channel_to_destination (dt, af);
1108 ts->destination_container = NULL; /* no longer 'contained' */
1109 /* now bind existing "unbound" channel to our IP/port tuple */
1110 ts->protocol = protocol;
1114 ts->source_ip.v4 = * (const struct in_addr *) source_ip;
1115 ts->destination_ip.v4 = * (const struct in_addr *) destination_ip;
1119 ts->source_ip.v6 = * (const struct in6_addr *) source_ip;
1120 ts->destination_ip.v6 = * (const struct in6_addr *) destination_ip;
1122 ts->source_port = source_port;
1123 ts->destination_port = destination_port;
1124 ts->heap_node = GNUNET_CONTAINER_heap_insert (channel_heap,
1126 GNUNET_TIME_absolute_get ().abs_value_us);
1127 GNUNET_assert (GNUNET_YES ==
1128 GNUNET_CONTAINER_multihashmap_put (channel_map,
1131 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1132 GNUNET_STATISTICS_update (stats,
1133 gettext_noop ("# Active channels"),
1135 while (GNUNET_CONTAINER_multihashmap_size (channel_map) > max_channel_mappings)
1136 expire_channel (ts);
1140 GNUNET_CONTAINER_heap_update_cost (channel_heap,
1142 GNUNET_TIME_absolute_get ().abs_value_us);
1144 if (NULL == ts->channel)
1146 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1147 "Packet dropped, channel to %s not yet ready (%s)\n",
1148 print_channel_destination (&ts->destination),
1149 (NULL == ts->search)
1150 ? "EXIT search failed"
1151 : "EXIT search active");
1152 GNUNET_STATISTICS_update (stats,
1153 gettext_noop ("# Packets dropped (channel not yet online)"),
1159 /* send via channel */
1163 if (destination->is_service)
1165 struct GNUNET_EXIT_UdpServiceMessage *usm;
1167 mlen = sizeof (struct GNUNET_EXIT_UdpServiceMessage) +
1168 payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1169 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1174 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1177 usm = (struct GNUNET_EXIT_UdpServiceMessage *) &tnq[1];
1178 usm->header.size = htons ((uint16_t) mlen);
1179 usm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE);
1180 /* if the source port is below 32000, we assume it has a special
1181 meaning; if not, we pick a random port (this is a heuristic) */
1182 usm->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1183 usm->destination_port = udp->destination_port;
1184 usm->service_descriptor = destination->details.service_destination.service_descriptor;
1187 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1191 struct GNUNET_EXIT_UdpInternetMessage *uim;
1192 struct in_addr *ip4dst;
1193 struct in6_addr *ip6dst;
1196 mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) +
1197 alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1198 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1203 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1206 uim = (struct GNUNET_EXIT_UdpInternetMessage *) &tnq[1];
1207 uim->header.size = htons ((uint16_t) mlen);
1208 uim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET);
1209 uim->af = htonl (destination->details.exit_destination.af);
1210 uim->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1211 uim->destination_port = udp->destination_port;
1212 switch (destination->details.exit_destination.af)
1215 ip4dst = (struct in_addr *) &uim[1];
1216 *ip4dst = destination->details.exit_destination.ip.v4;
1217 payload = &ip4dst[1];
1220 ip6dst = (struct in6_addr *) &uim[1];
1221 *ip6dst = destination->details.exit_destination.ip.v6;
1222 payload = &ip6dst[1];
1229 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1233 if (GNUNET_NO == ts->is_established)
1235 if (destination->is_service)
1237 struct GNUNET_EXIT_TcpServiceStartMessage *tsm;
1239 mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) +
1240 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1241 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1246 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1249 tsm = (struct GNUNET_EXIT_TcpServiceStartMessage *) &tnq[1];
1250 tsm->header.size = htons ((uint16_t) mlen);
1251 tsm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START);
1252 tsm->reserved = htonl (0);
1253 tsm->service_descriptor = destination->details.service_destination.service_descriptor;
1254 tsm->tcp_header = *tcp;
1257 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1261 struct GNUNET_EXIT_TcpInternetStartMessage *tim;
1262 struct in_addr *ip4dst;
1263 struct in6_addr *ip6dst;
1266 mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) +
1267 alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1268 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1273 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1276 tim = (struct GNUNET_EXIT_TcpInternetStartMessage *) &tnq[1];
1277 tim->header.size = htons ((uint16_t) mlen);
1278 tim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START);
1279 tim->af = htonl (destination->details.exit_destination.af);
1280 tim->tcp_header = *tcp;
1281 switch (destination->details.exit_destination.af)
1284 ip4dst = (struct in_addr *) &tim[1];
1285 *ip4dst = destination->details.exit_destination.ip.v4;
1286 payload = &ip4dst[1];
1289 ip6dst = (struct in6_addr *) &tim[1];
1290 *ip6dst = destination->details.exit_destination.ip.v6;
1291 payload = &ip6dst[1];
1298 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1303 struct GNUNET_EXIT_TcpDataMessage *tdm;
1305 mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) +
1306 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1307 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1312 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1315 tdm = (struct GNUNET_EXIT_TcpDataMessage *) &tnq[1];
1316 tdm->header.size = htons ((uint16_t) mlen);
1317 tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT);
1318 tdm->reserved = htonl (0);
1319 tdm->tcp_header = *tcp;
1322 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1326 case IPPROTO_ICMPV6:
1327 if (destination->is_service)
1329 struct GNUNET_EXIT_IcmpServiceMessage *ism;
1331 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1332 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1333 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1338 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1340 ism = (struct GNUNET_EXIT_IcmpServiceMessage *) &tnq[1];
1341 ism->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE);
1342 ism->af = htonl (af); /* need to tell destination ICMP protocol family! */
1343 ism->service_descriptor = destination->details.service_destination.service_descriptor;
1344 ism->icmp_header = *icmp;
1345 /* ICMP protocol translation will be done by the receiver (as we don't know
1346 the target AF); however, we still need to possibly discard the payload
1347 depending on the ICMP type */
1353 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1354 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1356 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1357 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1358 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1359 /* throw away ICMP payload, won't be useful for the other side anyway */
1360 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1363 GNUNET_STATISTICS_update (stats,
1364 gettext_noop ("# ICMPv4 packets dropped (not allowed)"),
1368 /* end of AF_INET */
1373 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1374 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1375 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1376 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1377 /* throw away ICMP payload, won't be useful for the other side anyway */
1378 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1380 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1381 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1384 GNUNET_STATISTICS_update (stats,
1385 gettext_noop ("# ICMPv6 packets dropped (not allowed)"),
1389 /* end of AF_INET6 */
1396 /* update length calculations, as payload_length may have changed */
1397 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1398 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1400 ism->header.size = htons ((uint16_t) mlen);
1401 /* finally, copy payload (if there is any left...) */
1404 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1408 struct GNUNET_EXIT_IcmpInternetMessage *iim;
1409 struct in_addr *ip4dst;
1410 struct in6_addr *ip6dst;
1413 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1414 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1415 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1420 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1422 iim = (struct GNUNET_EXIT_IcmpInternetMessage *) &tnq[1];
1423 iim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET);
1424 iim->icmp_header = *icmp;
1425 /* Perform ICMP protocol-translation (depending on destination AF and source AF)
1426 and throw away ICMP payload depending on ICMP message type */
1432 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1433 if (destination->details.exit_destination.af == AF_INET6)
1434 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1436 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1437 if (destination->details.exit_destination.af == AF_INET6)
1438 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1440 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1441 if (destination->details.exit_destination.af == AF_INET6)
1442 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1443 /* throw away IP-payload, exit will have to make it up anyway */
1444 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1446 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1447 if (destination->details.exit_destination.af == AF_INET6)
1448 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1449 /* throw away IP-payload, exit will have to make it up anyway */
1450 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1452 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1453 if (destination->details.exit_destination.af == AF_INET6)
1455 GNUNET_STATISTICS_update (stats,
1456 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1461 /* throw away IP-payload, exit will have to make it up anyway */
1462 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1465 GNUNET_STATISTICS_update (stats,
1466 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1471 /* end of AF_INET */
1476 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1477 if (destination->details.exit_destination.af == AF_INET6)
1478 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1479 /* throw away IP-payload, exit will have to make it up anyway */
1480 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1482 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1483 if (destination->details.exit_destination.af == AF_INET)
1484 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1485 /* throw away IP-payload, exit will have to make it up anyway */
1486 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1488 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1489 if (destination->details.exit_destination.af == AF_INET)
1491 GNUNET_STATISTICS_update (stats,
1492 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1497 /* throw away IP-payload, exit will have to make it up anyway */
1498 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1500 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1501 if (destination->details.exit_destination.af == AF_INET)
1503 GNUNET_STATISTICS_update (stats,
1504 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1509 /* throw away IP-payload, exit will have to make it up anyway */
1510 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1512 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1513 if (destination->details.exit_destination.af == AF_INET)
1514 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1516 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1517 if (destination->details.exit_destination.af == AF_INET)
1518 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1521 GNUNET_STATISTICS_update (stats,
1522 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1527 /* end of AF_INET6 */
1532 /* update length calculations, as payload_length may have changed */
1533 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1534 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1536 iim->header.size = htons ((uint16_t) mlen);
1538 /* need to tell destination ICMP protocol family! */
1539 iim->af = htonl (destination->details.exit_destination.af);
1540 switch (destination->details.exit_destination.af)
1543 ip4dst = (struct in_addr *) &iim[1];
1544 *ip4dst = destination->details.exit_destination.ip.v4;
1545 payload = &ip4dst[1];
1548 ip6dst = (struct in6_addr *) &iim[1];
1549 *ip6dst = destination->details.exit_destination.ip.v6;
1550 payload = &ip6dst[1];
1557 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1561 /* not supported above, how can we get here !? */
1565 ts->is_established = GNUNET_YES;
1566 send_to_channel (tnq, ts);
1571 * Receive packets from the helper-process (someone send to the local
1572 * virtual channel interface). Find the destination mapping, and if it
1573 * exists, identify the correct CADET channel (or possibly create it)
1574 * and forward the packet.
1576 * @param cls closure, NULL
1577 * @param client NULL
1578 * @param message message we got from the client (VPN channel interface)
1581 message_token (void *cls,
1583 const struct GNUNET_MessageHeader *message)
1585 const struct GNUNET_TUN_Layer2PacketHeader *tun;
1587 struct GNUNET_HashCode key;
1588 struct DestinationEntry *de;
1590 GNUNET_STATISTICS_update (stats,
1591 gettext_noop ("# Packets received from TUN interface"),
1593 mlen = ntohs (message->size);
1594 if ( (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
1595 (mlen < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader)) )
1600 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1601 mlen -= (sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader));
1602 switch (ntohs (tun->proto))
1606 const struct GNUNET_TUN_IPv6Header *pkt6;
1608 if (mlen < sizeof (struct GNUNET_TUN_IPv6Header))
1614 pkt6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1615 get_destination_key_from_ip (AF_INET6,
1616 &pkt6->destination_address,
1618 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1621 char buf[INET6_ADDRSTRLEN];
1623 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1624 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1625 inet_ntop (AF_INET6,
1626 &pkt6->destination_address,
1634 &pkt6->source_address,
1635 &pkt6->destination_address,
1637 mlen - sizeof (struct GNUNET_TUN_IPv6Header));
1642 struct GNUNET_TUN_IPv4Header *pkt4;
1644 if (mlen < sizeof (struct GNUNET_TUN_IPv4Header))
1650 pkt4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1651 get_destination_key_from_ip (AF_INET,
1652 &pkt4->destination_address,
1654 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1657 char buf[INET_ADDRSTRLEN];
1659 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1660 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1662 &pkt4->destination_address,
1667 if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header))
1669 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1670 _("Received IPv4 packet with options (dropping it)\n"));
1676 &pkt4->source_address,
1677 &pkt4->destination_address,
1679 mlen - sizeof (struct GNUNET_TUN_IPv4Header));
1683 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1684 _("Received packet of unknown protocol %d from TUN (dropping it)\n"),
1685 (unsigned int) ntohs (tun->proto));
1693 * Synthesize a plausible ICMP payload for an ICMP error
1694 * response on the given channel.
1696 * @param ts channel information
1697 * @param ipp IPv4 header to fill in (ICMP payload)
1698 * @param udp "UDP" header to fill in (ICMP payload); might actually
1699 * also be the first 8 bytes of the TCP header
1702 make_up_icmpv4_payload (struct ChannelState *ts,
1703 struct GNUNET_TUN_IPv4Header *ipp,
1704 struct GNUNET_TUN_UdpHeader *udp)
1706 GNUNET_TUN_initialize_ipv4_header (ipp,
1708 sizeof (struct GNUNET_TUN_TcpHeader),
1710 &ts->destination_ip.v4);
1711 udp->source_port = htons (ts->source_port);
1712 udp->destination_port = htons (ts->destination_port);
1713 udp->len = htons (0);
1714 udp->crc = htons (0);
1719 * Synthesize a plausible ICMP payload for an ICMP error
1720 * response on the given channel.
1722 * @param ts channel information
1723 * @param ipp IPv6 header to fill in (ICMP payload)
1724 * @param udp "UDP" header to fill in (ICMP payload); might actually
1725 * also be the first 8 bytes of the TCP header
1728 make_up_icmpv6_payload (struct ChannelState *ts,
1729 struct GNUNET_TUN_IPv6Header *ipp,
1730 struct GNUNET_TUN_UdpHeader *udp)
1732 GNUNET_TUN_initialize_ipv6_header (ipp,
1734 sizeof (struct GNUNET_TUN_TcpHeader),
1736 &ts->destination_ip.v6);
1737 udp->source_port = htons (ts->source_port);
1738 udp->destination_port = htons (ts->destination_port);
1739 udp->len = htons (0);
1740 udp->crc = htons (0);
1745 * We got an ICMP packet back from the CADET channel. Pass it on to the
1746 * local virtual interface via the helper.
1748 * @param cls closure, NULL
1749 * @param channel connection to the other end
1750 * @param channel_ctx pointer to our 'struct ChannelState *'
1751 * @param message the actual message
1752 * @return #GNUNET_OK to keep the connection open,
1753 * #GNUNET_SYSERR to close it (signal serious error)
1756 receive_icmp_back (void *cls,
1757 struct GNUNET_CADET_Channel *channel,
1759 const struct GNUNET_MessageHeader *message)
1761 struct ChannelState *ts = *channel_ctx;
1762 const struct GNUNET_EXIT_IcmpToVPNMessage *i2v;
1765 GNUNET_STATISTICS_update (stats,
1766 gettext_noop ("# ICMP packets received from cadet"),
1768 mlen = ntohs (message->size);
1769 if (mlen < sizeof (struct GNUNET_EXIT_IcmpToVPNMessage))
1771 GNUNET_break_op (0);
1772 return GNUNET_SYSERR;
1774 if (NULL == ts->heap_node)
1776 GNUNET_break_op (0);
1777 return GNUNET_SYSERR;
1779 if (AF_UNSPEC == ts->af)
1781 GNUNET_break_op (0);
1782 return GNUNET_SYSERR;
1784 i2v = (const struct GNUNET_EXIT_IcmpToVPNMessage *) message;
1785 mlen -= sizeof (struct GNUNET_EXIT_IcmpToVPNMessage);
1787 char sbuf[INET6_ADDRSTRLEN];
1788 char dbuf[INET6_ADDRSTRLEN];
1790 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1791 "Received ICMP packet from cadet, sending %u bytes from %s -> %s via TUN\n",
1792 (unsigned int) mlen,
1793 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
1794 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)));
1800 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
1801 + sizeof (struct GNUNET_TUN_IcmpHeader)
1802 + sizeof (struct GNUNET_MessageHeader) +
1803 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1806 /* reserve some extra space in case we have an ICMP type here where
1807 we will need to make up the payload ourselves */
1808 char buf[size + sizeof (struct GNUNET_TUN_IPv4Header) + 8] GNUNET_ALIGN;
1809 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1810 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1811 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1812 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv4[1];
1813 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1814 tun->flags = htons (0);
1815 tun->proto = htons (ETH_P_IPV4);
1816 GNUNET_TUN_initialize_ipv4_header (ipv4,
1818 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1819 &ts->destination_ip.v4,
1821 *icmp = i2v->icmp_header;
1825 /* For some ICMP types, we need to adjust (make up) the payload here.
1826 Also, depending on the AF used on the other side, we have to
1827 do ICMP PT (translate ICMP types) */
1828 switch (ntohl (i2v->af))
1833 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1834 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1836 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1837 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1838 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1840 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1841 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1845 /* sender did not strip ICMP payload? */
1846 GNUNET_break_op (0);
1847 return GNUNET_SYSERR;
1849 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1850 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1851 make_up_icmpv4_payload (ts, ipp, udp);
1855 GNUNET_break_op (0);
1856 GNUNET_STATISTICS_update (stats,
1857 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1859 return GNUNET_SYSERR;
1864 /* ICMP PT 6-to-4 and possibly making up payloads */
1867 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1868 icmp->type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
1870 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1871 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1875 /* sender did not strip ICMP payload? */
1876 GNUNET_break_op (0);
1877 return GNUNET_SYSERR;
1879 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1880 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1881 make_up_icmpv4_payload (ts, ipp, udp);
1884 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1885 icmp->type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1887 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1888 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1892 /* sender did not strip ICMP payload? */
1893 GNUNET_break_op (0);
1894 return GNUNET_SYSERR;
1896 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1897 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1898 make_up_icmpv4_payload (ts, ipp, udp);
1901 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1902 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1903 GNUNET_STATISTICS_update (stats,
1904 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1907 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1908 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1910 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1911 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1914 GNUNET_break_op (0);
1915 GNUNET_STATISTICS_update (stats,
1916 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1918 return GNUNET_SYSERR;
1923 GNUNET_break_op (0);
1924 return GNUNET_SYSERR;
1926 msg->size = htons (size);
1927 GNUNET_TUN_calculate_icmp_checksum (icmp,
1930 (void) GNUNET_HELPER_send (helper_handle,
1939 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
1940 + sizeof (struct GNUNET_TUN_IcmpHeader)
1941 + sizeof (struct GNUNET_MessageHeader) +
1942 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1945 char buf[size + sizeof (struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN;
1946 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1947 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1948 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
1949 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv6[1];
1950 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1951 tun->flags = htons (0);
1952 tun->proto = htons (ETH_P_IPV6);
1953 GNUNET_TUN_initialize_ipv6_header (ipv6,
1955 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1956 &ts->destination_ip.v6,
1958 *icmp = i2v->icmp_header;
1963 /* For some ICMP types, we need to adjust (make up) the payload here.
1964 Also, depending on the AF used on the other side, we have to
1965 do ICMP PT (translate ICMP types) */
1966 switch (ntohl (i2v->af))
1969 /* ICMP PT 4-to-6 and possibly making up payloads */
1972 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1973 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1975 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1976 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1978 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1979 icmp->type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1981 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1982 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1986 /* sender did not strip ICMP payload? */
1987 GNUNET_break_op (0);
1988 return GNUNET_SYSERR;
1990 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1991 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1992 make_up_icmpv6_payload (ts, ipp, udp);
1995 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1996 icmp->type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1998 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1999 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
2003 /* sender did not strip ICMP payload? */
2004 GNUNET_break_op (0);
2005 return GNUNET_SYSERR;
2007 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
2008 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
2009 make_up_icmpv6_payload (ts, ipp, udp);
2012 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
2013 GNUNET_STATISTICS_update (stats,
2014 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
2018 GNUNET_break_op (0);
2019 GNUNET_STATISTICS_update (stats,
2020 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
2022 return GNUNET_SYSERR;
2029 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
2030 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
2031 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
2032 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
2034 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
2035 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
2039 /* sender did not strip ICMP payload? */
2040 GNUNET_break_op (0);
2041 return GNUNET_SYSERR;
2043 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
2044 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
2045 make_up_icmpv6_payload (ts, ipp, udp);
2048 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
2051 GNUNET_break_op (0);
2052 GNUNET_STATISTICS_update (stats,
2053 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
2055 return GNUNET_SYSERR;
2060 GNUNET_break_op (0);
2061 return GNUNET_SYSERR;
2063 msg->size = htons (size);
2064 GNUNET_TUN_calculate_icmp_checksum (icmp,
2066 (void) GNUNET_HELPER_send (helper_handle,
2076 GNUNET_CONTAINER_heap_update_cost (channel_heap,
2078 GNUNET_TIME_absolute_get ().abs_value_us);
2084 * We got a UDP packet back from the CADET channel. Pass it on to the
2085 * local virtual interface via the helper.
2087 * @param cls closure, NULL
2088 * @param channel connection to the other end
2089 * @param channel_ctx pointer to our 'struct ChannelState *'
2090 * @param message the actual message
2091 * @return #GNUNET_OK to keep the connection open,
2092 * #GNUNET_SYSERR to close it (signal serious error)
2095 receive_udp_back (void *cls,
2096 struct GNUNET_CADET_Channel *channel,
2098 const struct GNUNET_MessageHeader *message)
2100 struct ChannelState *ts = *channel_ctx;
2101 const struct GNUNET_EXIT_UdpReplyMessage *reply;
2104 GNUNET_STATISTICS_update (stats,
2105 gettext_noop ("# UDP packets received from cadet"),
2107 mlen = ntohs (message->size);
2108 if (mlen < sizeof (struct GNUNET_EXIT_UdpReplyMessage))
2110 GNUNET_break_op (0);
2111 return GNUNET_SYSERR;
2113 if (NULL == ts->heap_node)
2115 GNUNET_break_op (0);
2116 return GNUNET_SYSERR;
2118 if (AF_UNSPEC == ts->af)
2120 GNUNET_break_op (0);
2121 return GNUNET_SYSERR;
2123 reply = (const struct GNUNET_EXIT_UdpReplyMessage *) message;
2124 mlen -= sizeof (struct GNUNET_EXIT_UdpReplyMessage);
2126 char sbuf[INET6_ADDRSTRLEN];
2127 char dbuf[INET6_ADDRSTRLEN];
2129 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2130 "Received UDP reply from cadet, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2131 (unsigned int) mlen,
2132 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2133 ts->destination_port,
2134 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2141 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2142 + sizeof (struct GNUNET_TUN_UdpHeader)
2143 + sizeof (struct GNUNET_MessageHeader) +
2144 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2147 char buf[size] GNUNET_ALIGN;
2148 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2149 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2150 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2151 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1];
2152 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2153 msg->size = htons (size);
2154 tun->flags = htons (0);
2155 tun->proto = htons (ETH_P_IPV4);
2156 GNUNET_TUN_initialize_ipv4_header (ipv4,
2158 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2159 &ts->destination_ip.v4,
2161 if (0 == ntohs (reply->source_port))
2162 udp->source_port = htons (ts->destination_port);
2164 udp->source_port = reply->source_port;
2165 if (0 == ntohs (reply->destination_port))
2166 udp->destination_port = htons (ts->source_port);
2168 udp->destination_port = reply->destination_port;
2169 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2170 GNUNET_TUN_calculate_udp4_checksum (ipv4,
2177 (void) GNUNET_HELPER_send (helper_handle,
2186 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2187 + sizeof (struct GNUNET_TUN_UdpHeader)
2188 + sizeof (struct GNUNET_MessageHeader) +
2189 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2192 char buf[size] GNUNET_ALIGN;
2193 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2194 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2195 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2196 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1];
2197 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2198 msg->size = htons (size);
2199 tun->flags = htons (0);
2200 tun->proto = htons (ETH_P_IPV6);
2201 GNUNET_TUN_initialize_ipv6_header (ipv6,
2203 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2204 &ts->destination_ip.v6,
2206 if (0 == ntohs (reply->source_port))
2207 udp->source_port = htons (ts->destination_port);
2209 udp->source_port = reply->source_port;
2210 if (0 == ntohs (reply->destination_port))
2211 udp->destination_port = htons (ts->source_port);
2213 udp->destination_port = reply->destination_port;
2214 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2215 GNUNET_TUN_calculate_udp6_checksum (ipv6,
2221 (void) GNUNET_HELPER_send (helper_handle,
2231 GNUNET_CONTAINER_heap_update_cost (channel_heap,
2233 GNUNET_TIME_absolute_get ().abs_value_us);
2239 * We got a TCP packet back from the CADET channel. Pass it on to the
2240 * local virtual interface via the helper.
2242 * @param cls closure, NULL
2243 * @param channel connection to the other end
2244 * @param channel_ctx pointer to our `struct ChannelState *`
2245 * @param message the actual message
2246 * @return #GNUNET_OK to keep the connection open,
2247 * #GNUNET_SYSERR to close it (signal serious error)
2250 receive_tcp_back (void *cls,
2251 struct GNUNET_CADET_Channel *channel,
2253 const struct GNUNET_MessageHeader *message)
2255 struct ChannelState *ts = *channel_ctx;
2256 const struct GNUNET_EXIT_TcpDataMessage *data;
2259 GNUNET_STATISTICS_update (stats,
2260 gettext_noop ("# TCP packets received from cadet"),
2262 mlen = ntohs (message->size);
2263 if (mlen < sizeof (struct GNUNET_EXIT_TcpDataMessage))
2265 GNUNET_break_op (0);
2266 return GNUNET_SYSERR;
2268 if (NULL == ts->heap_node)
2270 GNUNET_break_op (0);
2271 return GNUNET_SYSERR;
2273 data = (const struct GNUNET_EXIT_TcpDataMessage *) message;
2274 mlen -= sizeof (struct GNUNET_EXIT_TcpDataMessage);
2276 char sbuf[INET6_ADDRSTRLEN];
2277 char dbuf[INET6_ADDRSTRLEN];
2279 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2280 "Received TCP reply from cadet, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2281 (unsigned int) mlen,
2282 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2283 ts->destination_port,
2284 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2287 if (data->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
2289 GNUNET_break_op (0);
2290 return GNUNET_SYSERR;
2296 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2297 + sizeof (struct GNUNET_TUN_TcpHeader)
2298 + sizeof (struct GNUNET_MessageHeader) +
2299 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2302 char buf[size] GNUNET_ALIGN;
2303 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2304 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2305 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2306 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv4[1];
2307 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2308 msg->size = htons (size);
2309 tun->flags = htons (0);
2310 tun->proto = htons (ETH_P_IPV4);
2311 GNUNET_TUN_initialize_ipv4_header (ipv4,
2313 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2314 &ts->destination_ip.v4,
2316 *tcp = data->tcp_header;
2317 tcp->source_port = htons (ts->destination_port);
2318 tcp->destination_port = htons (ts->source_port);
2319 GNUNET_TUN_calculate_tcp4_checksum (ipv4,
2326 (void) GNUNET_HELPER_send (helper_handle,
2335 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2336 + sizeof (struct GNUNET_TUN_TcpHeader)
2337 + sizeof (struct GNUNET_MessageHeader) +
2338 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2341 char buf[size] GNUNET_ALIGN;
2342 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2343 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2344 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2345 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv6[1];
2346 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2347 msg->size = htons (size);
2348 tun->flags = htons (0);
2349 tun->proto = htons (ETH_P_IPV6);
2350 GNUNET_TUN_initialize_ipv6_header (ipv6,
2352 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2353 &ts->destination_ip.v6,
2355 *tcp = data->tcp_header;
2356 tcp->source_port = htons (ts->destination_port);
2357 tcp->destination_port = htons (ts->source_port);
2358 GNUNET_TUN_calculate_tcp6_checksum (ipv6,
2365 (void) GNUNET_HELPER_send (helper_handle,
2373 GNUNET_CONTAINER_heap_update_cost (channel_heap,
2375 GNUNET_TIME_absolute_get ().abs_value_us);
2381 * Allocate an IPv4 address from the range of the channel
2382 * for a new redirection.
2384 * @param v4 where to store the address
2385 * @return #GNUNET_OK on success,
2386 * #GNUNET_SYSERR on error
2389 allocate_v4_address (struct in_addr *v4)
2391 const char *ipv4addr = vpn_argv[4];
2392 const char *ipv4mask = vpn_argv[5];
2393 struct in_addr addr;
2394 struct in_addr mask;
2396 struct GNUNET_HashCode key;
2399 GNUNET_assert (1 == inet_pton (AF_INET, ipv4addr, &addr));
2400 GNUNET_assert (1 == inet_pton (AF_INET, ipv4mask, &mask));
2401 /* Given 192.168.0.1/255.255.0.0, we want a mask
2402 of '192.168.255.255', thus: */
2403 mask.s_addr = addr.s_addr | ~mask.s_addr;
2410 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2411 _("Failed to find unallocated IPv4 address in VPN's range\n"));
2412 return GNUNET_SYSERR;
2414 /* Pick random IPv4 address within the subnet, except 'addr' or 'mask' itself */
2415 rnd.s_addr = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2417 v4->s_addr = (addr.s_addr | rnd.s_addr) & mask.s_addr;
2418 get_destination_key_from_ip (AF_INET,
2422 while ( (GNUNET_YES ==
2423 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2425 (v4->s_addr == addr.s_addr) ||
2426 (v4->s_addr == mask.s_addr) );
2432 * Allocate an IPv6 address from the range of the channel
2433 * for a new redirection.
2435 * @param v6 where to store the address
2436 * @return #GNUNET_OK on success,
2437 * #GNUNET_SYSERR on error
2440 allocate_v6_address (struct in6_addr *v6)
2442 const char *ipv6addr = vpn_argv[2];
2443 struct in6_addr addr;
2444 struct in6_addr mask;
2445 struct in6_addr rnd;
2447 struct GNUNET_HashCode key;
2450 GNUNET_assert (1 == inet_pton (AF_INET6, ipv6addr, &addr));
2451 GNUNET_assert (ipv6prefix < 128);
2452 /* Given ABCD::/96, we want a mask of 'ABCD::FFFF:FFFF,
2455 for (i=127;i>=ipv6prefix;i--)
2456 mask.s6_addr[i / 8] |= (1 << (i % 8));
2458 /* Pick random IPv6 address within the subnet, except 'addr' or 'mask' itself */
2465 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2466 _("Failed to find unallocated IPv6 address in VPN's range\n"));
2467 return GNUNET_SYSERR;
2472 rnd.s6_addr[i] = (unsigned char) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2475 = (addr.s6_addr[i] | rnd.s6_addr[i]) & mask.s6_addr[i];
2477 get_destination_key_from_ip (AF_INET6,
2481 while ( (GNUNET_YES ==
2482 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2486 sizeof (struct in6_addr))) ||
2489 sizeof (struct in6_addr))) );
2495 * Free resources occupied by a destination entry.
2497 * @param de entry to free
2500 free_destination_entry (struct DestinationEntry *de)
2502 struct DestinationChannel *dt;
2504 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2505 "Cleaning up destination entry `%s'\n",
2506 print_channel_destination (de));
2507 GNUNET_STATISTICS_update (stats,
2508 gettext_noop ("# Active destinations"),
2510 while (NULL != (dt = de->dt_head))
2512 GNUNET_CONTAINER_DLL_remove (de->dt_head,
2517 free_channel_state (dt->ts);
2518 GNUNET_assert (NULL == dt->ts);
2522 if (NULL != de->heap_node)
2524 GNUNET_CONTAINER_heap_remove_node (de->heap_node);
2525 de->heap_node = NULL;
2526 GNUNET_assert (GNUNET_YES ==
2527 GNUNET_CONTAINER_multihashmap_remove (destination_map,
2536 * We have too many active destinations. Clean up the oldest destination.
2538 * @param except destination that must NOT be cleaned up, even if it is the oldest
2541 expire_destination (struct DestinationEntry *except)
2543 struct DestinationEntry *de;
2545 de = GNUNET_CONTAINER_heap_peek (destination_heap);
2546 GNUNET_assert (NULL != de);
2548 return; /* can't do this */
2549 free_destination_entry (de);
2554 * Allocate an IP address for the response.
2556 * @param result_af desired address family; set to the actual
2557 * address family; can initially be AF_UNSPEC if there
2558 * is no preference; will be set to AF_UNSPEC if the
2560 * @param addr set to either v4 or v6 depending on which
2561 * storage location was used; set to NULL if allocation failed
2562 * @param v4 storage space for an IPv4 address
2563 * @param v6 storage space for an IPv6 address
2564 * @return #GNUNET_OK normally, #GNUNET_SYSERR if `* result_af` was
2565 * an unsupported address family (not AF_INET, AF_INET6 or AF_UNSPEC)
2568 allocate_response_ip (int *result_af,
2571 struct in6_addr *v6)
2578 allocate_v4_address (v4))
2579 *result_af = AF_UNSPEC;
2585 allocate_v6_address (v6))
2586 *result_af = AF_UNSPEC;
2592 allocate_v4_address (v4))
2595 *result_af = AF_INET;
2597 else if (GNUNET_OK ==
2598 allocate_v6_address (v6))
2601 *result_af = AF_INET6;
2606 return GNUNET_SYSERR;
2613 * A client asks us to setup a redirection via some exit node to a
2614 * particular IP. Setup the redirection and give the client the
2618 * @param client requesting client
2619 * @param message redirection request (a `struct RedirectToIpRequestMessage`)
2622 service_redirect_to_ip (void *cls,
2623 struct GNUNET_SERVER_Client *client,
2624 const struct GNUNET_MessageHeader *message)
2628 const struct RedirectToIpRequestMessage *msg;
2634 struct DestinationEntry *de;
2635 struct GNUNET_HashCode key;
2637 /* validate and parse request */
2638 mlen = ntohs (message->size);
2639 if (mlen < sizeof (struct RedirectToIpRequestMessage))
2642 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2645 alen = mlen - sizeof (struct RedirectToIpRequestMessage);
2646 msg = (const struct RedirectToIpRequestMessage *) message;
2647 addr_af = (int) htonl (msg->addr_af);
2651 if (alen != sizeof (struct in_addr))
2654 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2659 if (alen != sizeof (struct in6_addr))
2662 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2668 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2672 /* allocate response IP */
2673 result_af = (int) htonl (msg->result_af);
2674 if (GNUNET_OK != allocate_response_ip (&result_af,
2678 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2681 /* send reply with our IP address */
2682 send_client_reply (client,
2686 if (result_af == AF_UNSPEC)
2688 /* failure, we're done */
2689 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2694 char sbuf[INET6_ADDRSTRLEN];
2695 char dbuf[INET6_ADDRSTRLEN];
2697 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2698 "Allocated address %s for redirection via exit to %s\n",
2699 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2701 &msg[1], dbuf, sizeof (dbuf)));
2704 /* setup destination record */
2705 de = GNUNET_new (struct DestinationEntry);
2706 de->is_service = GNUNET_NO;
2707 de->details.exit_destination.af = addr_af;
2708 memcpy (&de->details.exit_destination.ip,
2711 get_destination_key_from_ip (result_af,
2715 GNUNET_assert (GNUNET_OK ==
2716 GNUNET_CONTAINER_multihashmap_put (destination_map,
2719 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2720 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2722 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value_us);
2723 GNUNET_STATISTICS_update (stats,
2724 gettext_noop ("# Active destinations"),
2726 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2727 expire_destination (de);
2728 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2733 * A client asks us to setup a redirection to a particular peer
2734 * offering a service. Setup the redirection and give the client the
2738 * @param client requesting client
2739 * @param message redirection request (a `struct RedirectToPeerRequestMessage`)
2742 service_redirect_to_service (void *cls,
2743 struct GNUNET_SERVER_Client *client,
2744 const struct GNUNET_MessageHeader *message)
2746 const struct RedirectToServiceRequestMessage *msg;
2751 struct DestinationEntry *de;
2752 struct GNUNET_HashCode key;
2753 struct ChannelState *ts;
2754 struct DestinationChannel *dt;
2757 msg = (const struct RedirectToServiceRequestMessage *) message;
2759 /* allocate response IP */
2760 result_af = (int) htonl (msg->result_af);
2761 if (GNUNET_OK != allocate_response_ip (&result_af,
2765 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2768 send_client_reply (client,
2772 if (result_af == AF_UNSPEC)
2774 /* failure, we're done */
2775 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2776 _("Failed to allocate IP address for new destination\n"));
2777 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2782 char sbuf[INET6_ADDRSTRLEN];
2784 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2785 "Allocated address %s for redirection to service %s on peer %s\n",
2786 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2787 GNUNET_h2s (&msg->service_descriptor),
2788 GNUNET_i2s (&msg->target));
2791 /* setup destination record */
2792 de = GNUNET_new (struct DestinationEntry);
2793 de->is_service = GNUNET_YES;
2794 de->details.service_destination.service_descriptor = msg->service_descriptor;
2795 de->details.service_destination.target = msg->target;
2796 get_destination_key_from_ip (result_af,
2800 GNUNET_assert (GNUNET_OK ==
2801 GNUNET_CONTAINER_multihashmap_put (destination_map,
2804 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2805 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2807 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value_us);
2808 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2809 expire_destination (de);
2811 dt = GNUNET_new (struct DestinationChannel);
2812 dt->destination = de;
2813 GNUNET_CONTAINER_DLL_insert (de->dt_head,
2816 ts = create_channel_to_destination (dt,
2821 ts->destination_ip.v4 = v4;
2824 ts->destination_ip.v6 = v6;
2830 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2835 * Function called whenever a channel is destroyed. Should clean up
2836 * any associated state.
2838 * @param cls closure (set from #GNUNET_CADET_connect)
2839 * @param channel connection to the other end (henceforth invalid)
2840 * @param channel_ctx place where local state associated
2841 * with the channel is stored (our `struct ChannelState`)
2844 channel_cleaner (void *cls,
2845 const struct GNUNET_CADET_Channel *channel,
2848 struct ChannelState *ts = channel_ctx;
2850 ts->channel = NULL; /* we must not call GNUNET_CADET_channel_destroy() anymore */
2851 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2852 "CADET notified us about death of channel to `%s'\n",
2853 print_channel_destination (&ts->destination));
2854 free_channel_state (ts);
2859 * Free memory occupied by an entry in the destination map.
2863 * @param value a `struct DestinationEntry *`
2864 * @return #GNUNET_OK (continue to iterate)
2867 cleanup_destination (void *cls,
2868 const struct GNUNET_HashCode *key,
2871 struct DestinationEntry *de = value;
2873 free_destination_entry (de);
2879 * Free memory occupied by an entry in the channel map.
2883 * @param value a `struct ChannelState *`
2884 * @return #GNUNET_OK (continue to iterate)
2887 cleanup_channel (void *cls,
2888 const struct GNUNET_HashCode *key,
2891 struct ChannelState *ts = value;
2893 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2894 "Tearing down channel to `%s' during cleanup\n",
2895 print_channel_destination (&ts->destination));
2896 free_channel_state (ts);
2902 * Function scheduled as very last function, cleans up after us
2909 const struct GNUNET_SCHEDULER_TaskContext *tc)
2913 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2914 "VPN is shutting down\n");
2915 if (NULL != destination_map)
2917 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
2918 &cleanup_destination,
2920 GNUNET_CONTAINER_multihashmap_destroy (destination_map);
2921 destination_map = NULL;
2923 if (NULL != destination_heap)
2925 GNUNET_CONTAINER_heap_destroy (destination_heap);
2926 destination_heap = NULL;
2928 if (NULL != channel_map)
2930 GNUNET_CONTAINER_multihashmap_iterate (channel_map,
2933 GNUNET_CONTAINER_multihashmap_destroy (channel_map);
2936 if (NULL != channel_heap)
2938 GNUNET_CONTAINER_heap_destroy (channel_heap);
2939 channel_heap = NULL;
2941 if (NULL != cadet_handle)
2943 GNUNET_CADET_disconnect (cadet_handle);
2944 cadet_handle = NULL;
2946 if (NULL != helper_handle)
2948 GNUNET_HELPER_stop (helper_handle, GNUNET_NO);
2949 helper_handle = NULL;
2953 GNUNET_SERVER_notification_context_destroy (nc);
2958 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
2962 GNUNET_free_non_null (vpn_argv[i]);
2967 * Main function that will be run by the scheduler.
2969 * @param cls closure
2970 * @param server the initialized server
2971 * @param cfg_ configuration
2975 struct GNUNET_SERVER_Handle *server,
2976 const struct GNUNET_CONFIGURATION_Handle *cfg_)
2978 static const struct GNUNET_SERVER_MessageHandler service_handlers[] = {
2979 /* callback, cls, type, size */
2980 { &service_redirect_to_ip, NULL, GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP, 0},
2981 { &service_redirect_to_service, NULL,
2982 GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE,
2983 sizeof (struct RedirectToServiceRequestMessage) },
2986 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
2987 { &receive_udp_back, GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY, 0},
2988 { &receive_tcp_back, GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN, 0},
2989 { &receive_icmp_back, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN, 0},
3001 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-vpn");
3004 GNUNET_OS_check_helper_binary (binary,
3006 "-d gnunet-vpn - - 169.1.3.3.7 255.255.255.0")) //ipv4 only please!
3008 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3009 "`%s' is not SUID, refusing to run.\n",
3010 "gnunet-helper-vpn");
3011 GNUNET_free (binary);
3013 /* we won't "really" exit here, as the 'service' is still running;
3014 however, as no handlers are registered, the service won't do
3018 GNUNET_free (binary);
3020 stats = GNUNET_STATISTICS_create ("vpn", cfg);
3022 GNUNET_CONFIGURATION_get_value_number (cfg, "VPN", "MAX_MAPPING",
3023 &max_destination_mappings))
3024 max_destination_mappings = 200;
3026 GNUNET_CONFIGURATION_get_value_number (cfg, "VPN", "MAX_TUNNELS",
3027 &max_channel_mappings))
3028 max_channel_mappings = 200;
3030 destination_map = GNUNET_CONTAINER_multihashmap_create (max_destination_mappings * 2, GNUNET_NO);
3031 destination_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3032 channel_map = GNUNET_CONTAINER_multihashmap_create (max_channel_mappings * 2, GNUNET_NO);
3033 channel_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3036 vpn_argv[0] = GNUNET_strdup ("vpn-gnunet");
3037 if (GNUNET_SYSERR ==
3038 GNUNET_CONFIGURATION_get_value_string (cfg, "VPN", "IFNAME", &ifname))
3040 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "VPN", "IFNAME");
3041 GNUNET_SCHEDULER_shutdown ();
3044 vpn_argv[1] = ifname;
3046 if (GNUNET_OK == GNUNET_NETWORK_test_pf (PF_INET6))
3048 if ( (GNUNET_SYSERR ==
3049 GNUNET_CONFIGURATION_get_value_string (cfg, "VPN", "IPV6ADDR",
3051 (1 != inet_pton (AF_INET6, ipv6addr, &v6))) )
3053 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV6ADDR",
3054 _("Must specify valid IPv6 address"));
3055 GNUNET_SCHEDULER_shutdown ();
3056 GNUNET_free_non_null (ipv6addr);
3059 vpn_argv[2] = ipv6addr;
3060 ipv6prefix_s = NULL;
3061 if (GNUNET_SYSERR ==
3062 GNUNET_CONFIGURATION_get_value_string (cfg, "VPN", "IPV6PREFIX",
3065 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV6PREFIX");
3066 GNUNET_SCHEDULER_shutdown ();
3067 GNUNET_free_non_null (ipv6prefix_s);
3070 vpn_argv[3] = ipv6prefix_s;
3072 GNUNET_CONFIGURATION_get_value_number (cfg, "VPN",
3075 (ipv6prefix >= 127) )
3077 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV4MASK",
3078 _("Must specify valid IPv6 mask"));
3079 GNUNET_SCHEDULER_shutdown ();
3085 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3086 _("IPv6 support disabled as this system does not support IPv6\n"));
3087 vpn_argv[2] = GNUNET_strdup ("-");
3088 vpn_argv[3] = GNUNET_strdup ("-");
3090 if (GNUNET_OK == GNUNET_NETWORK_test_pf (PF_INET))
3093 if ( (GNUNET_SYSERR ==
3094 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4ADDR",
3096 (1 != inet_pton (AF_INET, ipv4addr, &v4))) )
3098 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV4ADDR",
3099 _("Must specify valid IPv4 address"));
3100 GNUNET_SCHEDULER_shutdown ();
3101 GNUNET_free_non_null (ipv4addr);
3104 vpn_argv[4] = ipv4addr;
3106 if ( (GNUNET_SYSERR ==
3107 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4MASK",
3109 (1 != inet_pton (AF_INET, ipv4mask, &v4))) )
3111 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV4MASK",
3112 _("Must specify valid IPv4 mask"));
3113 GNUNET_SCHEDULER_shutdown ();
3114 GNUNET_free_non_null (ipv4mask);
3117 vpn_argv[5] = ipv4mask;
3121 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3122 _("IPv4 support disabled as this system does not support IPv4\n"));
3123 vpn_argv[4] = GNUNET_strdup ("-");
3124 vpn_argv[5] = GNUNET_strdup ("-");
3129 GNUNET_CADET_connect (cfg_, NULL,
3134 helper_handle = GNUNET_HELPER_start (GNUNET_NO,
3135 "gnunet-helper-vpn", vpn_argv,
3136 &message_token, NULL, NULL);
3137 nc = GNUNET_SERVER_notification_context_create (server, 1);
3138 GNUNET_SERVER_add_handlers (server, service_handlers);
3139 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
3146 * The main function of the VPN service.
3148 * @param argc number of arguments from the command line
3149 * @param argv command line arguments
3150 * @return 0 ok, 1 on error
3153 main (int argc, char *const *argv)
3155 return (GNUNET_OK ==
3156 GNUNET_SERVICE_run (argc, argv, "vpn",
3157 GNUNET_SERVICE_OPTION_NONE,
3158 &run, NULL)) ? global_ret : 1;
3161 /* end of gnunet-service-vpn.c */