2 This file is part of GNUnet.
3 Copyright (C) 2010, 2011, 2012, 2016 Christian Grothoff
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
22 * @file 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 * Destination port this channel state is used for.
89 uint16_t destination_port;
95 * Information we track for each IP address to determine which channel
96 * to send the traffic over to the destination.
98 struct DestinationEntry
102 * Key under which this entry is in the 'destination_map' (only valid
103 * if 'heap_node != NULL').
105 struct GNUNET_HashCode key;
108 * Head of DLL of channels associated with this destination.
110 struct DestinationChannel *dt_head;
113 * Tail of DLL of channels associated with this destination.
115 struct DestinationChannel *dt_tail;
118 * Entry for this entry in the destination_heap.
120 struct GNUNET_CONTAINER_HeapNode *heap_node;
123 * #GNUNET_NO if this is a channel to an Internet-exit,
124 * #GNUNET_YES if this channel is to a service.
129 * Details about the connection (depending on is_service).
137 * The description of the service (only used for service channels).
139 struct GNUNET_HashCode service_descriptor;
142 * Peer offering the service.
144 struct GNUNET_PeerIdentity target;
146 } service_destination;
152 * Address family used (AF_INET or AF_INET6).
157 * IP address of the ultimate destination (only used for exit channels).
162 * Address if af is AF_INET.
167 * Address if af is AF_INET6.
180 * A messages we have in queue for a particular channel.
182 struct ChannelMessageQueueEntry
185 * This is a doubly-linked list.
187 struct ChannelMessageQueueEntry *next;
190 * This is a doubly-linked list.
192 struct ChannelMessageQueueEntry *prev;
195 * Number of bytes in @e msg.
200 * Message to transmit, allocated at the end of this struct.
207 * State we keep for each of our channels.
213 * Information about the channel to use, NULL if no channel
214 * is available right now.
216 struct GNUNET_CADET_Channel *channel;
219 * Active query with REGEX to locate exit.
221 struct GNUNET_REGEX_Search *search;
224 * Active transmission handle, NULL for none.
226 struct GNUNET_CADET_TransmitHandle *th;
229 * Entry for this entry in the channel_heap, NULL as long as this
230 * channel state is not fully bound.
232 struct GNUNET_CONTAINER_HeapNode *heap_node;
235 * Head of list of messages scheduled for transmission.
237 struct ChannelMessageQueueEntry *tmq_head;
240 * Tail of list of messages scheduled for transmission.
242 struct ChannelMessageQueueEntry *tmq_tail;
245 * Destination to which this channel leads. Note that
246 * this struct is NOT in the destination_map (but a
247 * local copy) and that the 'heap_node' should always
250 struct DestinationEntry destination;
253 * Addess family used for this channel on the local TUN interface.
258 * Is this channel new (#GNUNET_NO), or did we exchange messages with the
259 * other side already (#GNUNET_YES)?
264 * Length of the doubly linked 'tmq_head/tmq_tail' list.
266 unsigned int tmq_length;
269 * IPPROTO_TCP or IPPROTO_UDP once bound.
274 * IP address of the source on our end, initially uninitialized.
279 * Address if af is AF_INET.
284 * Address if af is AF_INET6.
291 * Destination IP address used by the source on our end (this is the IP
292 * that we pick freely within the VPN's channel IP range).
297 * Address if af is AF_INET.
302 * Address if af is AF_INET6.
309 * Source port used by the sender on our end; 0 for uninitialized.
311 uint16_t source_port;
314 * Destination port used by the sender on our end; 0 for uninitialized.
316 uint16_t destination_port;
322 * Return value from #main().
324 static int global_ret;
327 * Configuration we use.
329 static const struct GNUNET_CONFIGURATION_Handle *cfg;
332 * Handle to the cadet service.
334 static struct GNUNET_CADET_Handle *cadet_handle;
337 * Map from IP address to destination information (possibly with a
338 * CADET channel handle for fast setup).
340 static struct GNUNET_CONTAINER_MultiHashMap *destination_map;
343 * Min-Heap sorted by activity time to expire old mappings.
345 static struct GNUNET_CONTAINER_Heap *destination_heap;
348 * Map from source and destination address (IP+port) to connection
349 * information (mostly with the respective CADET channel handle).
351 static struct GNUNET_CONTAINER_MultiHashMap *channel_map;
354 * Min-Heap sorted by activity time to expire old mappings; values are
355 * of type 'struct ChannelState'.
357 static struct GNUNET_CONTAINER_Heap *channel_heap;
362 static struct GNUNET_STATISTICS_Handle *stats;
365 * The handle to the VPN helper process "gnunet-helper-vpn".
367 static struct GNUNET_HELPER_Handle *helper_handle;
370 * Arguments to the vpn helper.
372 static char *vpn_argv[7];
375 * Length of the prefix of the VPN's IPv6 network.
377 static unsigned long long ipv6prefix;
380 * If there are more than this number of address-mappings, old ones
383 static unsigned long long max_destination_mappings;
386 * If there are more than this number of open channels, old ones
389 static unsigned long long max_channel_mappings;
393 * Compute the key under which we would store an entry in the
394 * #destination_map for the given IP address.
396 * @param af address family (AF_INET or AF_INET6)
397 * @param address IP address, struct in_addr or struct in6_addr
398 * @param key where to store the key
401 get_destination_key_from_ip (int af,
403 struct GNUNET_HashCode *key)
408 GNUNET_CRYPTO_hash (address,
409 sizeof (struct in_addr),
413 GNUNET_CRYPTO_hash (address,
414 sizeof (struct in6_addr),
425 * Compute the key under which we would store an entry in the
426 * channel_map for the given socket address pair.
428 * @param af address family (AF_INET or AF_INET6)
429 * @param protocol IPPROTO_TCP or IPPROTO_UDP
430 * @param source_ip sender's source IP, struct in_addr or struct in6_addr
431 * @param source_port sender's source port
432 * @param destination_ip sender's destination IP, struct in_addr or struct in6_addr
433 * @param destination_port sender's destination port
434 * @param key where to store the key
437 get_channel_key_from_ips (int af,
439 const void *source_ip,
440 uint16_t source_port,
441 const void *destination_ip,
442 uint16_t destination_port,
443 struct GNUNET_HashCode *key)
447 memset (key, 0, sizeof (struct GNUNET_HashCode));
448 /* the GNUnet hashmap only uses the first sizeof(unsigned int) of the hash,
449 so we put the ports in there (and hope for few collisions) */
451 GNUNET_memcpy (off, &source_port, sizeof (uint16_t));
452 off += sizeof (uint16_t);
453 GNUNET_memcpy (off, &destination_port, sizeof (uint16_t));
454 off += sizeof (uint16_t);
458 GNUNET_memcpy (off, source_ip, sizeof (struct in_addr));
459 off += sizeof (struct in_addr);
460 GNUNET_memcpy (off, destination_ip, sizeof (struct in_addr));
461 off += sizeof (struct in_addr);
464 GNUNET_memcpy (off, source_ip, sizeof (struct in6_addr));
465 off += sizeof (struct in6_addr);
466 GNUNET_memcpy (off, destination_ip, sizeof (struct in6_addr));
467 off += sizeof (struct in6_addr);
473 GNUNET_memcpy (off, &protocol, sizeof (uint8_t));
474 /* off += sizeof (uint8_t); */
479 * Notify the client about the result of its request.
481 * @param client client to notify
482 * @param request_id original request ID to include in response
483 * @param result_af resulting address family
484 * @param addr resulting IP address
487 send_client_reply (struct GNUNET_SERVICE_Client *client,
492 struct GNUNET_MQ_Envelope *env;
493 struct RedirectToIpResponseMessage *res;
499 rlen = sizeof (struct in_addr);
502 rlen = sizeof (struct in6_addr);
511 env = GNUNET_MQ_msg_extra (res,
513 GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP);
514 res->result_af = htonl (result_af);
515 res->request_id = request_id;
516 GNUNET_memcpy (&res[1],
519 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
525 * Free resources associated with a channel state.
527 * @param ts state to free
530 free_channel_state (struct ChannelState *ts)
532 struct GNUNET_HashCode key;
533 struct ChannelMessageQueueEntry *tnq;
534 struct GNUNET_CADET_Channel *channel;
536 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
537 "Cleaning up channel state\n");
540 GNUNET_CADET_notify_transmit_ready_cancel (ts->th);
543 if (NULL != (channel = ts->channel))
546 GNUNET_CADET_channel_destroy (channel);
549 GNUNET_STATISTICS_update (stats,
550 gettext_noop ("# Active channels"),
552 while (NULL != (tnq = ts->tmq_head))
554 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
560 GNUNET_assert (0 == ts->tmq_length);
561 GNUNET_assert (NULL == ts->destination.heap_node);
562 if (NULL != ts->search)
564 GNUNET_REGEX_search_cancel (ts->search);
567 if (NULL != ts->heap_node)
569 GNUNET_CONTAINER_heap_remove_node (ts->heap_node);
570 ts->heap_node = NULL;
571 get_channel_key_from_ips (ts->af,
576 ts->destination_port,
578 GNUNET_assert (GNUNET_YES ==
579 GNUNET_CONTAINER_multihashmap_remove (channel_map,
588 * Send a message from the message queue via cadet.
590 * @param cls the `struct ChannelState` with the message queue
591 * @param size number of bytes available in @a buf
592 * @param buf where to copy the message
593 * @return number of bytes copied to @a buf
596 send_to_peer_notify_callback (void *cls, size_t size, void *buf)
598 struct ChannelState *ts = cls;
599 struct ChannelMessageQueueEntry *tnq;
606 GNUNET_assert (NULL != tnq);
607 GNUNET_assert (size >= tnq->len);
608 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
609 "Sending %u bytes via cadet channel\n",
610 (unsigned int) tnq->len);
611 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
615 GNUNET_memcpy (buf, tnq->msg, tnq->len);
618 if (NULL != (tnq = ts->tmq_head))
621 ts->th = GNUNET_CADET_notify_transmit_ready (ts->channel,
622 GNUNET_NO /* cork */,
623 GNUNET_TIME_UNIT_FOREVER_REL,
625 &send_to_peer_notify_callback,
628 GNUNET_STATISTICS_update (stats,
629 gettext_noop ("# Bytes given to cadet for transmission"),
636 * Add the given message to the given channel and trigger the
637 * transmission process.
639 * @param tnq message to queue
640 * @param ts channel to queue the message for
643 send_to_channel (struct ChannelMessageQueueEntry *tnq,
644 struct ChannelState *ts)
646 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
647 "Queueing %u bytes for transmission via cadet channel\n",
648 (unsigned int) tnq->len);
649 GNUNET_assert (NULL != ts->channel);
650 GNUNET_CONTAINER_DLL_insert_tail (ts->tmq_head,
654 if (ts->tmq_length > MAX_MESSAGE_QUEUE_SIZE)
656 struct ChannelMessageQueueEntry *dq;
659 GNUNET_assert (dq != tnq);
660 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
664 GNUNET_CADET_notify_transmit_ready_cancel (ts->th);
666 GNUNET_STATISTICS_update (stats,
667 gettext_noop ("# Bytes dropped in cadet queue (overflow)"),
673 ts->th = GNUNET_CADET_notify_transmit_ready (ts->channel,
674 GNUNET_NO /* cork */,
675 GNUNET_TIME_UNIT_FOREVER_REL,
677 &send_to_peer_notify_callback,
683 * Output destination of a channel for diagnostics.
685 * @param de destination to process
686 * @return diagnostic string describing destination
689 print_channel_destination (const struct DestinationEntry *de)
691 static char dest[256];
695 GNUNET_snprintf (dest,
698 GNUNET_i2s (&de->details.service_destination.target),
699 GNUNET_h2s (&de->details.service_destination.service_descriptor));
703 inet_ntop (de->details.exit_destination.af,
704 &de->details.exit_destination.ip,
713 * Regex has found a potential exit peer for us; consider using it.
715 * @param cls the `struct ChannelState`
716 * @param id Peer providing a regex that matches the string.
717 * @param get_path Path of the get request.
718 * @param get_path_length Lenght of @a get_path.
719 * @param put_path Path of the put request.
720 * @param put_path_length Length of the @a put_path.
723 handle_regex_result (void *cls,
724 const struct GNUNET_PeerIdentity *id,
725 const struct GNUNET_PeerIdentity *get_path,
726 unsigned int get_path_length,
727 const struct GNUNET_PeerIdentity *put_path,
728 unsigned int put_path_length)
730 struct ChannelState *ts = cls;
731 struct GNUNET_HashCode port;
733 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
734 "Exit %s found for destination %s!\n",
736 print_channel_destination (&ts->destination));
737 GNUNET_REGEX_search_cancel (ts->search);
742 /* these must match the strings used in gnunet-daemon-exit */
743 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_IPV4_GATEWAY,
744 strlen (GNUNET_APPLICATION_PORT_IPV4_GATEWAY),
748 /* these must match the strings used in gnunet-daemon-exit */
749 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_IPV6_GATEWAY,
750 strlen (GNUNET_APPLICATION_PORT_IPV6_GATEWAY),
757 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
758 "Creating tunnel to %s for destination %s!\n",
760 print_channel_destination (&ts->destination));
761 ts->channel = GNUNET_CADET_channel_create (cadet_handle,
765 GNUNET_CADET_OPTION_DEFAULT);
770 * Initialize the given destination entry's cadet channel.
772 * @param dt destination channel for which we need to setup a channel
773 * @param client_af address family of the address returned to the client
774 * @return channel state of the channel that was created
776 static struct ChannelState *
777 create_channel_to_destination (struct DestinationChannel *dt,
780 struct ChannelState *ts;
782 GNUNET_STATISTICS_update (stats,
783 gettext_noop ("# Cadet channels created"),
786 ts = GNUNET_new (struct ChannelState);
788 ts->destination = *dt->destination;
789 ts->destination.heap_node = NULL; /* copy is NOT in destination heap */
790 ts->destination_port = dt->destination_port;
791 if (dt->destination->is_service)
793 struct GNUNET_HashCode cadet_port;
795 GNUNET_TUN_compute_service_cadet_port (&ts->destination.details.service_destination.service_descriptor,
796 ts->destination_port,
799 = GNUNET_CADET_channel_create (cadet_handle,
801 &dt->destination->details.service_destination.target,
803 GNUNET_CADET_OPTION_DEFAULT);
804 if (NULL == ts->channel)
810 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
811 "Creating channel to peer %s offering service %s on port %u\n",
812 GNUNET_i2s (&dt->destination->details.service_destination.target),
813 GNUNET_h2s (&ts->destination.details.service_destination.service_descriptor),
814 (unsigned int) ts->destination_port);
820 switch (dt->destination->details.exit_destination.af)
824 char address[GNUNET_TUN_IPV4_REGEXLEN];
826 GNUNET_TUN_ipv4toregexsearch (&dt->destination->details.exit_destination.ip.v4,
827 dt->destination_port,
829 GNUNET_asprintf (&policy,
831 GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
837 char address[GNUNET_TUN_IPV6_REGEXLEN];
839 GNUNET_TUN_ipv6toregexsearch (&dt->destination->details.exit_destination.ip.v6,
840 dt->destination_port,
842 GNUNET_asprintf (&policy,
844 GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
853 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
854 "Requesting connect by string: %s\n",
856 ts->search = GNUNET_REGEX_search (cfg,
858 &handle_regex_result,
860 GNUNET_free (policy);
867 * We have too many active channels. Clean up the oldest channel.
869 * @param except channel that must NOT be cleaned up, even if it is the oldest
872 expire_channel (struct ChannelState *except)
874 struct ChannelState *ts;
876 ts = GNUNET_CONTAINER_heap_peek (channel_heap);
877 GNUNET_assert (NULL != ts);
879 return; /* can't do this */
880 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
881 "Tearing down expired channel to %s\n",
882 print_channel_destination (&except->destination));
883 free_channel_state (ts);
888 * Route a packet via cadet to the given destination.
890 * @param destination description of the destination
891 * @param af address family on this end (AF_INET or AF_INET6)
892 * @param protocol IPPROTO_TCP or IPPROTO_UDP or IPPROTO_ICMP or IPPROTO_ICMPV6
893 * @param source_ip source IP used by the sender (struct in_addr or struct in6_addr)
894 * @param destination_ip destination IP used by the sender (struct in_addr or struct in6_addr)
895 * @param payload payload of the packet after the IP header
896 * @param payload_length number of bytes in @a payload
899 route_packet (struct DestinationEntry *destination,
902 const void *source_ip,
903 const void *destination_ip,
905 size_t payload_length)
907 struct GNUNET_HashCode key;
908 struct ChannelState *ts;
909 struct ChannelMessageQueueEntry *tnq;
912 const struct GNUNET_TUN_UdpHeader *udp;
913 const struct GNUNET_TUN_TcpHeader *tcp;
914 const struct GNUNET_TUN_IcmpHeader *icmp;
915 struct DestinationChannel *dt;
916 uint16_t source_port;
917 uint16_t destination_port;
923 if (payload_length < sizeof (struct GNUNET_TUN_UdpHeader))
929 tcp = NULL; /* make compiler happy */
930 icmp = NULL; /* make compiler happy */
932 if (udp->len < sizeof (struct GNUNET_TUN_UdpHeader))
937 source_port = ntohs (udp->source_port);
938 destination_port = ntohs (udp->destination_port);
939 get_channel_key_from_ips (af,
950 if (payload_length < sizeof (struct GNUNET_TUN_TcpHeader))
956 udp = NULL; /* make compiler happy */
957 icmp = NULL; /* make compiler happy */
959 if (tcp->off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
964 source_port = ntohs (tcp->source_port);
965 destination_port = ntohs (tcp->destination_port);
966 get_channel_key_from_ips (af,
978 if ( (AF_INET == af) ^ (protocol == IPPROTO_ICMP) )
983 if (payload_length < sizeof (struct GNUNET_TUN_IcmpHeader))
989 tcp = NULL; /* make compiler happy */
990 udp = NULL; /* make compiler happy */
993 destination_port = 0;
994 get_channel_key_from_ips (af,
1004 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1005 _("Protocol %u not supported, dropping\n"),
1006 (unsigned int) protocol);
1010 if (! destination->is_service)
1012 switch (destination->details.exit_destination.af)
1015 alen = sizeof (struct in_addr);
1018 alen = sizeof (struct in6_addr);
1025 char sbuf[INET6_ADDRSTRLEN];
1026 char dbuf[INET6_ADDRSTRLEN];
1027 char xbuf[INET6_ADDRSTRLEN];
1029 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1030 "Routing %s packet from [%s]:%u -> [%s]:%u to destination [%s]:%u\n",
1031 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
1042 inet_ntop (destination->details.exit_destination.af,
1043 &destination->details.exit_destination.ip,
1044 xbuf, sizeof (xbuf)),
1047 for (dt = destination->dt_head; NULL != dt; dt = dt->next)
1048 if (dt->destination_port == destination_port)
1054 char sbuf[INET6_ADDRSTRLEN];
1055 char dbuf[INET6_ADDRSTRLEN];
1057 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1058 "Routing %s packet from [%s]:%u -> [%s]:%u to service %s at peer %s\n",
1059 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
1070 GNUNET_h2s (&destination->details.service_destination.service_descriptor),
1071 GNUNET_i2s (&destination->details.service_destination.target));
1073 for (dt = destination->dt_head; NULL != dt; dt = dt->next)
1074 if (dt->destination_port == destination_port)
1079 dt = GNUNET_new (struct DestinationChannel);
1080 dt->destination = destination;
1081 GNUNET_CONTAINER_DLL_insert (destination->dt_head,
1082 destination->dt_tail,
1084 dt->destination_port = destination_port;
1087 /* see if we have an existing channel for this destination */
1088 ts = GNUNET_CONTAINER_multihashmap_get (channel_map,
1092 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1093 "Creating new channel for key %s\n",
1095 /* need to either use the existing channel from the destination (if still
1096 available) or create a fresh one */
1097 ts = create_channel_to_destination (dt,
1101 /* now bind existing "unbound" channel to our IP/port tuple */
1102 ts->protocol = protocol;
1106 ts->source_ip.v4 = * (const struct in_addr *) source_ip;
1107 ts->destination_ip.v4 = * (const struct in_addr *) destination_ip;
1111 ts->source_ip.v6 = * (const struct in6_addr *) source_ip;
1112 ts->destination_ip.v6 = * (const struct in6_addr *) destination_ip;
1114 ts->source_port = source_port;
1115 ts->destination_port = destination_port;
1116 ts->heap_node = GNUNET_CONTAINER_heap_insert (channel_heap,
1118 GNUNET_TIME_absolute_get ().abs_value_us);
1119 GNUNET_assert (GNUNET_YES ==
1120 GNUNET_CONTAINER_multihashmap_put (channel_map,
1123 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1124 GNUNET_STATISTICS_update (stats,
1125 gettext_noop ("# Active channels"),
1127 while (GNUNET_CONTAINER_multihashmap_size (channel_map) > max_channel_mappings)
1128 expire_channel (ts);
1132 GNUNET_CONTAINER_heap_update_cost (channel_heap,
1134 GNUNET_TIME_absolute_get ().abs_value_us);
1136 if (NULL == ts->channel)
1138 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1139 "Packet dropped, channel to %s not yet ready (%s)\n",
1140 print_channel_destination (&ts->destination),
1141 (NULL == ts->search)
1142 ? "EXIT search failed"
1143 : "EXIT search active");
1144 GNUNET_STATISTICS_update (stats,
1145 gettext_noop ("# Packets dropped (channel not yet online)"),
1151 /* send via channel */
1155 if (destination->is_service)
1157 struct GNUNET_EXIT_UdpServiceMessage *usm;
1159 mlen = sizeof (struct GNUNET_EXIT_UdpServiceMessage) +
1160 payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1161 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1166 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1169 usm = (struct GNUNET_EXIT_UdpServiceMessage *) &tnq[1];
1170 usm->header.size = htons ((uint16_t) mlen);
1171 usm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE);
1172 /* if the source port is below 32000, we assume it has a special
1173 meaning; if not, we pick a random port (this is a heuristic) */
1174 usm->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1175 usm->destination_port = udp->destination_port;
1176 GNUNET_memcpy (&usm[1],
1178 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1182 struct GNUNET_EXIT_UdpInternetMessage *uim;
1183 struct in_addr *ip4dst;
1184 struct in6_addr *ip6dst;
1187 mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) +
1188 alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1189 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1194 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1197 uim = (struct GNUNET_EXIT_UdpInternetMessage *) &tnq[1];
1198 uim->header.size = htons ((uint16_t) mlen);
1199 uim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET);
1200 uim->af = htonl (destination->details.exit_destination.af);
1201 uim->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1202 uim->destination_port = udp->destination_port;
1203 switch (destination->details.exit_destination.af)
1206 ip4dst = (struct in_addr *) &uim[1];
1207 *ip4dst = destination->details.exit_destination.ip.v4;
1208 payload = &ip4dst[1];
1211 ip6dst = (struct in6_addr *) &uim[1];
1212 *ip6dst = destination->details.exit_destination.ip.v6;
1213 payload = &ip6dst[1];
1218 GNUNET_memcpy (payload,
1220 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1224 if (GNUNET_NO == ts->is_established)
1226 if (destination->is_service)
1228 struct GNUNET_EXIT_TcpServiceStartMessage *tsm;
1230 mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) +
1231 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1232 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1237 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1240 tsm = (struct GNUNET_EXIT_TcpServiceStartMessage *) &tnq[1];
1241 tsm->header.size = htons ((uint16_t) mlen);
1242 tsm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START);
1243 tsm->reserved = htonl (0);
1244 tsm->tcp_header = *tcp;
1245 GNUNET_memcpy (&tsm[1],
1247 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1251 struct GNUNET_EXIT_TcpInternetStartMessage *tim;
1252 struct in_addr *ip4dst;
1253 struct in6_addr *ip6dst;
1256 mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) +
1257 alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1258 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1263 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1266 tim = (struct GNUNET_EXIT_TcpInternetStartMessage *) &tnq[1];
1267 tim->header.size = htons ((uint16_t) mlen);
1268 tim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START);
1269 tim->af = htonl (destination->details.exit_destination.af);
1270 tim->tcp_header = *tcp;
1271 switch (destination->details.exit_destination.af)
1274 ip4dst = (struct in_addr *) &tim[1];
1275 *ip4dst = destination->details.exit_destination.ip.v4;
1276 payload = &ip4dst[1];
1279 ip6dst = (struct in6_addr *) &tim[1];
1280 *ip6dst = destination->details.exit_destination.ip.v6;
1281 payload = &ip6dst[1];
1286 GNUNET_memcpy (payload,
1288 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1293 struct GNUNET_EXIT_TcpDataMessage *tdm;
1295 mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) +
1296 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1297 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1302 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1305 tdm = (struct GNUNET_EXIT_TcpDataMessage *) &tnq[1];
1306 tdm->header.size = htons ((uint16_t) mlen);
1307 tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT);
1308 tdm->reserved = htonl (0);
1309 tdm->tcp_header = *tcp;
1310 GNUNET_memcpy (&tdm[1],
1312 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1316 case IPPROTO_ICMPV6:
1317 if (destination->is_service)
1319 struct GNUNET_EXIT_IcmpServiceMessage *ism;
1321 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1322 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1323 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1328 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1330 ism = (struct GNUNET_EXIT_IcmpServiceMessage *) &tnq[1];
1331 ism->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE);
1332 ism->af = htonl (af); /* need to tell destination ICMP protocol family! */
1333 ism->icmp_header = *icmp;
1334 /* ICMP protocol translation will be done by the receiver (as we don't know
1335 the target AF); however, we still need to possibly discard the payload
1336 depending on the ICMP type */
1342 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1343 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1345 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1346 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1347 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1348 /* throw away ICMP payload, won't be useful for the other side anyway */
1349 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1352 GNUNET_STATISTICS_update (stats,
1353 gettext_noop ("# ICMPv4 packets dropped (not allowed)"),
1357 /* end of AF_INET */
1362 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1363 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1364 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1365 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1366 /* throw away ICMP payload, won't be useful for the other side anyway */
1367 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1369 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1370 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1373 GNUNET_STATISTICS_update (stats,
1374 gettext_noop ("# ICMPv6 packets dropped (not allowed)"),
1378 /* end of AF_INET6 */
1385 /* update length calculations, as payload_length may have changed */
1386 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1387 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1389 ism->header.size = htons ((uint16_t) mlen);
1390 /* finally, copy payload (if there is any left...) */
1391 GNUNET_memcpy (&ism[1],
1393 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1397 struct GNUNET_EXIT_IcmpInternetMessage *iim;
1398 struct in_addr *ip4dst;
1399 struct in6_addr *ip6dst;
1402 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1403 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1404 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1409 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1411 iim = (struct GNUNET_EXIT_IcmpInternetMessage *) &tnq[1];
1412 iim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET);
1413 iim->icmp_header = *icmp;
1414 /* Perform ICMP protocol-translation (depending on destination AF and source AF)
1415 and throw away ICMP payload depending on ICMP message type */
1421 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1422 if (destination->details.exit_destination.af == AF_INET6)
1423 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1425 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1426 if (destination->details.exit_destination.af == AF_INET6)
1427 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1429 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1430 if (destination->details.exit_destination.af == AF_INET6)
1431 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1432 /* throw away IP-payload, exit will have to make it up anyway */
1433 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1435 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1436 if (destination->details.exit_destination.af == AF_INET6)
1437 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1438 /* throw away IP-payload, exit will have to make it up anyway */
1439 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1441 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1442 if (destination->details.exit_destination.af == AF_INET6)
1444 GNUNET_STATISTICS_update (stats,
1445 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1450 /* throw away IP-payload, exit will have to make it up anyway */
1451 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1454 GNUNET_STATISTICS_update (stats,
1455 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1460 /* end of AF_INET */
1465 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1466 if (destination->details.exit_destination.af == AF_INET6)
1467 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1468 /* throw away IP-payload, exit will have to make it up anyway */
1469 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1471 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1472 if (destination->details.exit_destination.af == AF_INET)
1473 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1474 /* throw away IP-payload, exit will have to make it up anyway */
1475 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1477 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1478 if (destination->details.exit_destination.af == AF_INET)
1480 GNUNET_STATISTICS_update (stats,
1481 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1486 /* throw away IP-payload, exit will have to make it up anyway */
1487 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1489 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1490 if (destination->details.exit_destination.af == AF_INET)
1492 GNUNET_STATISTICS_update (stats,
1493 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1498 /* throw away IP-payload, exit will have to make it up anyway */
1499 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1501 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1502 if (destination->details.exit_destination.af == AF_INET)
1503 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1505 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1506 if (destination->details.exit_destination.af == AF_INET)
1507 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1510 GNUNET_STATISTICS_update (stats,
1511 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1516 /* end of AF_INET6 */
1521 /* update length calculations, as payload_length may have changed */
1522 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1523 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1525 iim->header.size = htons ((uint16_t) mlen);
1527 /* need to tell destination ICMP protocol family! */
1528 iim->af = htonl (destination->details.exit_destination.af);
1529 switch (destination->details.exit_destination.af)
1532 ip4dst = (struct in_addr *) &iim[1];
1533 *ip4dst = destination->details.exit_destination.ip.v4;
1534 payload = &ip4dst[1];
1537 ip6dst = (struct in6_addr *) &iim[1];
1538 *ip6dst = destination->details.exit_destination.ip.v6;
1539 payload = &ip6dst[1];
1544 GNUNET_memcpy (payload,
1546 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1550 /* not supported above, how can we get here !? */
1554 ts->is_established = GNUNET_YES;
1555 send_to_channel (tnq, ts);
1560 * Receive packets from the helper-process (someone send to the local
1561 * virtual channel interface). Find the destination mapping, and if it
1562 * exists, identify the correct CADET channel (or possibly create it)
1563 * and forward the packet.
1565 * @param cls closure, NULL
1566 * @param client NULL
1567 * @param message message we got from the client (VPN channel interface)
1570 message_token (void *cls,
1572 const struct GNUNET_MessageHeader *message)
1574 const struct GNUNET_TUN_Layer2PacketHeader *tun;
1576 struct GNUNET_HashCode key;
1577 struct DestinationEntry *de;
1579 GNUNET_STATISTICS_update (stats,
1580 gettext_noop ("# Packets received from TUN interface"),
1582 mlen = ntohs (message->size);
1583 if ( (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
1584 (mlen < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader)) )
1589 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1590 mlen -= (sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader));
1591 switch (ntohs (tun->proto))
1595 const struct GNUNET_TUN_IPv6Header *pkt6;
1597 if (mlen < sizeof (struct GNUNET_TUN_IPv6Header))
1603 pkt6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1604 get_destination_key_from_ip (AF_INET6,
1605 &pkt6->destination_address,
1607 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1610 char buf[INET6_ADDRSTRLEN];
1612 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1613 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1614 inet_ntop (AF_INET6,
1615 &pkt6->destination_address,
1623 &pkt6->source_address,
1624 &pkt6->destination_address,
1626 mlen - sizeof (struct GNUNET_TUN_IPv6Header));
1631 struct GNUNET_TUN_IPv4Header *pkt4;
1633 if (mlen < sizeof (struct GNUNET_TUN_IPv4Header))
1639 pkt4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1640 get_destination_key_from_ip (AF_INET,
1641 &pkt4->destination_address,
1643 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1646 char buf[INET_ADDRSTRLEN];
1648 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1649 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1651 &pkt4->destination_address,
1656 if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header))
1658 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1659 _("Received IPv4 packet with options (dropping it)\n"));
1665 &pkt4->source_address,
1666 &pkt4->destination_address,
1668 mlen - sizeof (struct GNUNET_TUN_IPv4Header));
1672 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1673 _("Received packet of unknown protocol %d from TUN (dropping it)\n"),
1674 (unsigned int) ntohs (tun->proto));
1682 * Synthesize a plausible ICMP payload for an ICMP error
1683 * response on the given channel.
1685 * @param ts channel information
1686 * @param ipp IPv4 header to fill in (ICMP payload)
1687 * @param udp "UDP" header to fill in (ICMP payload); might actually
1688 * also be the first 8 bytes of the TCP header
1691 make_up_icmpv4_payload (struct ChannelState *ts,
1692 struct GNUNET_TUN_IPv4Header *ipp,
1693 struct GNUNET_TUN_UdpHeader *udp)
1695 GNUNET_TUN_initialize_ipv4_header (ipp,
1697 sizeof (struct GNUNET_TUN_TcpHeader),
1699 &ts->destination_ip.v4);
1700 udp->source_port = htons (ts->source_port);
1701 udp->destination_port = htons (ts->destination_port);
1702 udp->len = htons (0);
1703 udp->crc = htons (0);
1708 * Synthesize a plausible ICMP payload for an ICMP error
1709 * response on the given channel.
1711 * @param ts channel information
1712 * @param ipp IPv6 header to fill in (ICMP payload)
1713 * @param udp "UDP" header to fill in (ICMP payload); might actually
1714 * also be the first 8 bytes of the TCP header
1717 make_up_icmpv6_payload (struct ChannelState *ts,
1718 struct GNUNET_TUN_IPv6Header *ipp,
1719 struct GNUNET_TUN_UdpHeader *udp)
1721 GNUNET_TUN_initialize_ipv6_header (ipp,
1723 sizeof (struct GNUNET_TUN_TcpHeader),
1725 &ts->destination_ip.v6);
1726 udp->source_port = htons (ts->source_port);
1727 udp->destination_port = htons (ts->destination_port);
1728 udp->len = htons (0);
1729 udp->crc = htons (0);
1734 * We got an ICMP packet back from the CADET channel. Pass it on to the
1735 * local virtual interface via the helper.
1737 * @param cls closure, NULL
1738 * @param channel connection to the other end
1739 * @param channel_ctx pointer to our 'struct ChannelState *'
1740 * @param message the actual message
1741 * @return #GNUNET_OK to keep the connection open,
1742 * #GNUNET_SYSERR to close it (signal serious error)
1745 receive_icmp_back (void *cls,
1746 struct GNUNET_CADET_Channel *channel,
1748 const struct GNUNET_MessageHeader *message)
1750 struct ChannelState *ts = *channel_ctx;
1751 const struct GNUNET_EXIT_IcmpToVPNMessage *i2v;
1754 GNUNET_STATISTICS_update (stats,
1755 gettext_noop ("# ICMP packets received from cadet"),
1757 mlen = ntohs (message->size);
1758 if (mlen < sizeof (struct GNUNET_EXIT_IcmpToVPNMessage))
1760 GNUNET_break_op (0);
1761 return GNUNET_SYSERR;
1763 if (NULL == ts->heap_node)
1765 GNUNET_break_op (0);
1766 return GNUNET_SYSERR;
1768 if (AF_UNSPEC == ts->af)
1770 GNUNET_break_op (0);
1771 return GNUNET_SYSERR;
1773 i2v = (const struct GNUNET_EXIT_IcmpToVPNMessage *) message;
1774 mlen -= sizeof (struct GNUNET_EXIT_IcmpToVPNMessage);
1776 char sbuf[INET6_ADDRSTRLEN];
1777 char dbuf[INET6_ADDRSTRLEN];
1779 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1780 "Received ICMP packet from cadet, sending %u bytes from %s -> %s via TUN\n",
1781 (unsigned int) mlen,
1782 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
1783 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)));
1789 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
1790 + sizeof (struct GNUNET_TUN_IcmpHeader)
1791 + sizeof (struct GNUNET_MessageHeader) +
1792 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1795 /* reserve some extra space in case we have an ICMP type here where
1796 we will need to make up the payload ourselves */
1797 char buf[size + sizeof (struct GNUNET_TUN_IPv4Header) + 8] GNUNET_ALIGN;
1798 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1799 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1800 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1801 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv4[1];
1802 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1803 tun->flags = htons (0);
1804 tun->proto = htons (ETH_P_IPV4);
1805 GNUNET_TUN_initialize_ipv4_header (ipv4,
1807 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1808 &ts->destination_ip.v4,
1810 *icmp = i2v->icmp_header;
1811 GNUNET_memcpy (&icmp[1],
1814 /* For some ICMP types, we need to adjust (make up) the payload here.
1815 Also, depending on the AF used on the other side, we have to
1816 do ICMP PT (translate ICMP types) */
1817 switch (ntohl (i2v->af))
1822 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1823 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1825 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1826 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1827 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1829 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1830 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1834 /* sender did not strip ICMP payload? */
1835 GNUNET_break_op (0);
1836 return GNUNET_SYSERR;
1838 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1839 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1840 make_up_icmpv4_payload (ts, ipp, udp);
1844 GNUNET_break_op (0);
1845 GNUNET_STATISTICS_update (stats,
1846 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1848 return GNUNET_SYSERR;
1853 /* ICMP PT 6-to-4 and possibly making up payloads */
1856 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1857 icmp->type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
1859 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1860 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1864 /* sender did not strip ICMP payload? */
1865 GNUNET_break_op (0);
1866 return GNUNET_SYSERR;
1868 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1869 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1870 make_up_icmpv4_payload (ts, ipp, udp);
1873 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1874 icmp->type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1876 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1877 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1881 /* sender did not strip ICMP payload? */
1882 GNUNET_break_op (0);
1883 return GNUNET_SYSERR;
1885 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1886 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1887 make_up_icmpv4_payload (ts, ipp, udp);
1890 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1891 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1892 GNUNET_STATISTICS_update (stats,
1893 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1896 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1897 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1899 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1900 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1903 GNUNET_break_op (0);
1904 GNUNET_STATISTICS_update (stats,
1905 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1907 return GNUNET_SYSERR;
1912 GNUNET_break_op (0);
1913 return GNUNET_SYSERR;
1915 msg->size = htons (size);
1916 GNUNET_TUN_calculate_icmp_checksum (icmp,
1919 (void) GNUNET_HELPER_send (helper_handle,
1928 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
1929 + sizeof (struct GNUNET_TUN_IcmpHeader)
1930 + sizeof (struct GNUNET_MessageHeader) +
1931 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1934 char buf[size + sizeof (struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN;
1935 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1936 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1937 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
1938 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv6[1];
1939 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1940 tun->flags = htons (0);
1941 tun->proto = htons (ETH_P_IPV6);
1942 GNUNET_TUN_initialize_ipv6_header (ipv6,
1944 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1945 &ts->destination_ip.v6,
1947 *icmp = i2v->icmp_header;
1948 GNUNET_memcpy (&icmp[1],
1952 /* For some ICMP types, we need to adjust (make up) the payload here.
1953 Also, depending on the AF used on the other side, we have to
1954 do ICMP PT (translate ICMP types) */
1955 switch (ntohl (i2v->af))
1958 /* ICMP PT 4-to-6 and possibly making up payloads */
1961 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1962 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1964 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1965 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1967 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1968 icmp->type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1970 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1971 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1975 /* sender did not strip ICMP payload? */
1976 GNUNET_break_op (0);
1977 return GNUNET_SYSERR;
1979 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1980 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1981 make_up_icmpv6_payload (ts, ipp, udp);
1984 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1985 icmp->type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1987 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1988 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1992 /* sender did not strip ICMP payload? */
1993 GNUNET_break_op (0);
1994 return GNUNET_SYSERR;
1996 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1997 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1998 make_up_icmpv6_payload (ts, ipp, udp);
2001 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
2002 GNUNET_STATISTICS_update (stats,
2003 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
2007 GNUNET_break_op (0);
2008 GNUNET_STATISTICS_update (stats,
2009 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
2011 return GNUNET_SYSERR;
2018 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
2019 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
2020 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
2021 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
2023 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
2024 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
2028 /* sender did not strip ICMP payload? */
2029 GNUNET_break_op (0);
2030 return GNUNET_SYSERR;
2032 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
2033 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
2034 make_up_icmpv6_payload (ts, ipp, udp);
2037 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
2040 GNUNET_break_op (0);
2041 GNUNET_STATISTICS_update (stats,
2042 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
2044 return GNUNET_SYSERR;
2049 GNUNET_break_op (0);
2050 return GNUNET_SYSERR;
2052 msg->size = htons (size);
2053 GNUNET_TUN_calculate_icmp_checksum (icmp,
2055 (void) GNUNET_HELPER_send (helper_handle,
2065 GNUNET_CONTAINER_heap_update_cost (channel_heap,
2067 GNUNET_TIME_absolute_get ().abs_value_us);
2068 GNUNET_CADET_receive_done (channel);
2074 * We got a UDP packet back from the CADET channel. Pass it on to the
2075 * local virtual interface via the helper.
2077 * @param cls closure, NULL
2078 * @param channel connection to the other end
2079 * @param channel_ctx pointer to our 'struct ChannelState *'
2080 * @param message the actual message
2081 * @return #GNUNET_OK to keep the connection open,
2082 * #GNUNET_SYSERR to close it (signal serious error)
2085 receive_udp_back (void *cls,
2086 struct GNUNET_CADET_Channel *channel,
2088 const struct GNUNET_MessageHeader *message)
2090 struct ChannelState *ts = *channel_ctx;
2091 const struct GNUNET_EXIT_UdpReplyMessage *reply;
2094 GNUNET_STATISTICS_update (stats,
2095 gettext_noop ("# UDP packets received from cadet"),
2097 mlen = ntohs (message->size);
2098 if (mlen < sizeof (struct GNUNET_EXIT_UdpReplyMessage))
2100 GNUNET_break_op (0);
2101 return GNUNET_SYSERR;
2103 if (NULL == ts->heap_node)
2105 GNUNET_break_op (0);
2106 return GNUNET_SYSERR;
2108 if (AF_UNSPEC == ts->af)
2110 GNUNET_break_op (0);
2111 return GNUNET_SYSERR;
2113 reply = (const struct GNUNET_EXIT_UdpReplyMessage *) message;
2114 mlen -= sizeof (struct GNUNET_EXIT_UdpReplyMessage);
2116 char sbuf[INET6_ADDRSTRLEN];
2117 char dbuf[INET6_ADDRSTRLEN];
2119 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2120 "Received UDP reply from cadet, sending %u bytes from [%s]:%u -> [%s]:%u via TUN\n",
2121 (unsigned int) mlen,
2122 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2123 ts->destination_port,
2124 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2131 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2132 + sizeof (struct GNUNET_TUN_UdpHeader)
2133 + sizeof (struct GNUNET_MessageHeader) +
2134 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2137 char buf[size] GNUNET_ALIGN;
2138 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2139 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2140 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2141 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1];
2142 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2143 msg->size = htons (size);
2144 tun->flags = htons (0);
2145 tun->proto = htons (ETH_P_IPV4);
2146 GNUNET_TUN_initialize_ipv4_header (ipv4,
2148 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2149 &ts->destination_ip.v4,
2151 if (0 == ntohs (reply->source_port))
2152 udp->source_port = htons (ts->destination_port);
2154 udp->source_port = reply->source_port;
2155 if (0 == ntohs (reply->destination_port))
2156 udp->destination_port = htons (ts->source_port);
2158 udp->destination_port = reply->destination_port;
2159 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2160 GNUNET_TUN_calculate_udp4_checksum (ipv4,
2164 GNUNET_memcpy (&udp[1],
2167 (void) GNUNET_HELPER_send (helper_handle,
2176 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2177 + sizeof (struct GNUNET_TUN_UdpHeader)
2178 + sizeof (struct GNUNET_MessageHeader) +
2179 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2182 char buf[size] GNUNET_ALIGN;
2183 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2184 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2185 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2186 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1];
2187 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2188 msg->size = htons (size);
2189 tun->flags = htons (0);
2190 tun->proto = htons (ETH_P_IPV6);
2191 GNUNET_TUN_initialize_ipv6_header (ipv6,
2193 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2194 &ts->destination_ip.v6,
2196 if (0 == ntohs (reply->source_port))
2197 udp->source_port = htons (ts->destination_port);
2199 udp->source_port = reply->source_port;
2200 if (0 == ntohs (reply->destination_port))
2201 udp->destination_port = htons (ts->source_port);
2203 udp->destination_port = reply->destination_port;
2204 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2205 GNUNET_TUN_calculate_udp6_checksum (ipv6,
2208 GNUNET_memcpy (&udp[1],
2211 (void) GNUNET_HELPER_send (helper_handle,
2221 GNUNET_CONTAINER_heap_update_cost (channel_heap,
2223 GNUNET_TIME_absolute_get ().abs_value_us);
2224 GNUNET_CADET_receive_done (channel);
2230 * We got a TCP packet back from the CADET channel. Pass it on to the
2231 * local virtual interface via the helper.
2233 * @param cls closure, NULL
2234 * @param channel connection to the other end
2235 * @param channel_ctx pointer to our `struct ChannelState *`
2236 * @param message the actual message
2237 * @return #GNUNET_OK to keep the connection open,
2238 * #GNUNET_SYSERR to close it (signal serious error)
2241 receive_tcp_back (void *cls,
2242 struct GNUNET_CADET_Channel *channel,
2244 const struct GNUNET_MessageHeader *message)
2246 struct ChannelState *ts = *channel_ctx;
2247 const struct GNUNET_EXIT_TcpDataMessage *data;
2250 GNUNET_STATISTICS_update (stats,
2251 gettext_noop ("# TCP packets received from cadet"),
2253 mlen = ntohs (message->size);
2254 if (mlen < sizeof (struct GNUNET_EXIT_TcpDataMessage))
2256 GNUNET_break_op (0);
2257 return GNUNET_SYSERR;
2259 if (NULL == ts->heap_node)
2261 GNUNET_break_op (0);
2262 return GNUNET_SYSERR;
2264 data = (const struct GNUNET_EXIT_TcpDataMessage *) message;
2265 mlen -= sizeof (struct GNUNET_EXIT_TcpDataMessage);
2267 char sbuf[INET6_ADDRSTRLEN];
2268 char dbuf[INET6_ADDRSTRLEN];
2270 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2271 "Received TCP reply from cadet, sending %u bytes from [%s]:%u -> [%s]:%u via TUN\n",
2272 (unsigned int) mlen,
2273 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2274 ts->destination_port,
2275 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2278 if (data->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
2280 GNUNET_break_op (0);
2281 return GNUNET_SYSERR;
2287 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2288 + sizeof (struct GNUNET_TUN_TcpHeader)
2289 + sizeof (struct GNUNET_MessageHeader) +
2290 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2293 char buf[size] GNUNET_ALIGN;
2294 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2295 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2296 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2297 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv4[1];
2298 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2299 msg->size = htons (size);
2300 tun->flags = htons (0);
2301 tun->proto = htons (ETH_P_IPV4);
2302 GNUNET_TUN_initialize_ipv4_header (ipv4,
2304 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2305 &ts->destination_ip.v4,
2307 *tcp = data->tcp_header;
2308 tcp->source_port = htons (ts->destination_port);
2309 tcp->destination_port = htons (ts->source_port);
2310 GNUNET_TUN_calculate_tcp4_checksum (ipv4,
2314 GNUNET_memcpy (&tcp[1],
2317 (void) GNUNET_HELPER_send (helper_handle,
2326 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2327 + sizeof (struct GNUNET_TUN_TcpHeader)
2328 + sizeof (struct GNUNET_MessageHeader) +
2329 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2332 char buf[size] GNUNET_ALIGN;
2333 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2334 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2335 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2336 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv6[1];
2337 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2338 msg->size = htons (size);
2339 tun->flags = htons (0);
2340 tun->proto = htons (ETH_P_IPV6);
2341 GNUNET_TUN_initialize_ipv6_header (ipv6,
2343 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2344 &ts->destination_ip.v6,
2346 *tcp = data->tcp_header;
2347 tcp->source_port = htons (ts->destination_port);
2348 tcp->destination_port = htons (ts->source_port);
2349 GNUNET_TUN_calculate_tcp6_checksum (ipv6,
2353 GNUNET_memcpy (&tcp[1],
2356 (void) GNUNET_HELPER_send (helper_handle,
2364 GNUNET_CONTAINER_heap_update_cost (channel_heap,
2366 GNUNET_TIME_absolute_get ().abs_value_us);
2367 GNUNET_CADET_receive_done (channel);
2373 * Allocate an IPv4 address from the range of the channel
2374 * for a new redirection.
2376 * @param v4 where to store the address
2377 * @return #GNUNET_OK on success,
2378 * #GNUNET_SYSERR on error
2381 allocate_v4_address (struct in_addr *v4)
2383 const char *ipv4addr = vpn_argv[4];
2384 const char *ipv4mask = vpn_argv[5];
2385 struct in_addr addr;
2386 struct in_addr mask;
2388 struct GNUNET_HashCode key;
2391 GNUNET_assert (1 == inet_pton (AF_INET, ipv4addr, &addr));
2392 GNUNET_assert (1 == inet_pton (AF_INET, ipv4mask, &mask));
2393 /* Given 192.168.0.1/255.255.0.0, we want a mask
2394 of '192.168.255.255', thus: */
2395 mask.s_addr = addr.s_addr | ~mask.s_addr;
2402 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2403 _("Failed to find unallocated IPv4 address in VPN's range\n"));
2404 return GNUNET_SYSERR;
2406 /* Pick random IPv4 address within the subnet, except 'addr' or 'mask' itself */
2407 rnd.s_addr = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2409 v4->s_addr = (addr.s_addr | rnd.s_addr) & mask.s_addr;
2410 get_destination_key_from_ip (AF_INET,
2414 while ( (GNUNET_YES ==
2415 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2417 (v4->s_addr == addr.s_addr) ||
2418 (v4->s_addr == mask.s_addr) );
2424 * Allocate an IPv6 address from the range of the channel
2425 * for a new redirection.
2427 * @param v6 where to store the address
2428 * @return #GNUNET_OK on success,
2429 * #GNUNET_SYSERR on error
2432 allocate_v6_address (struct in6_addr *v6)
2434 const char *ipv6addr = vpn_argv[2];
2435 struct in6_addr addr;
2436 struct in6_addr mask;
2437 struct in6_addr rnd;
2439 struct GNUNET_HashCode key;
2442 GNUNET_assert (1 == inet_pton (AF_INET6, ipv6addr, &addr));
2443 GNUNET_assert (ipv6prefix < 128);
2444 /* Given ABCD::/96, we want a mask of 'ABCD::FFFF:FFFF,
2447 for (i=127;i>=ipv6prefix;i--)
2448 mask.s6_addr[i / 8] |= (1 << (i % 8));
2450 /* Pick random IPv6 address within the subnet, except 'addr' or 'mask' itself */
2457 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2458 _("Failed to find unallocated IPv6 address in VPN's range\n"));
2459 return GNUNET_SYSERR;
2464 rnd.s6_addr[i] = (unsigned char) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2467 = (addr.s6_addr[i] | rnd.s6_addr[i]) & mask.s6_addr[i];
2469 get_destination_key_from_ip (AF_INET6,
2473 while ( (GNUNET_YES ==
2474 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2478 sizeof (struct in6_addr))) ||
2481 sizeof (struct in6_addr))) );
2487 * Free resources occupied by a destination entry.
2489 * @param de entry to free
2492 free_destination_entry (struct DestinationEntry *de)
2494 struct DestinationChannel *dt;
2496 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2497 "Cleaning up destination entry `%s'\n",
2498 print_channel_destination (de));
2499 GNUNET_STATISTICS_update (stats,
2500 gettext_noop ("# Active destinations"),
2502 while (NULL != (dt = de->dt_head))
2504 GNUNET_CONTAINER_DLL_remove (de->dt_head,
2509 if (NULL != de->heap_node)
2511 GNUNET_CONTAINER_heap_remove_node (de->heap_node);
2512 de->heap_node = NULL;
2513 GNUNET_assert (GNUNET_YES ==
2514 GNUNET_CONTAINER_multihashmap_remove (destination_map,
2523 * We have too many active destinations. Clean up the oldest destination.
2525 * @param except destination that must NOT be cleaned up, even if it is the oldest
2528 expire_destination (struct DestinationEntry *except)
2530 struct DestinationEntry *de;
2532 de = GNUNET_CONTAINER_heap_peek (destination_heap);
2533 GNUNET_assert (NULL != de);
2535 return; /* can't do this */
2536 free_destination_entry (de);
2541 * Allocate an IP address for the response.
2543 * @param result_af desired address family; set to the actual
2544 * address family; can initially be AF_UNSPEC if there
2545 * is no preference; will be set to AF_UNSPEC if the
2547 * @param addr set to either v4 or v6 depending on which
2548 * storage location was used; set to NULL if allocation failed
2549 * @param v4 storage space for an IPv4 address
2550 * @param v6 storage space for an IPv6 address
2551 * @return #GNUNET_OK normally, #GNUNET_SYSERR if `* result_af` was
2552 * an unsupported address family (not AF_INET, AF_INET6 or AF_UNSPEC)
2555 allocate_response_ip (int *result_af,
2558 struct in6_addr *v6)
2565 allocate_v4_address (v4))
2566 *result_af = AF_UNSPEC;
2572 allocate_v6_address (v6))
2573 *result_af = AF_UNSPEC;
2579 allocate_v4_address (v4))
2582 *result_af = AF_INET;
2584 else if (GNUNET_OK ==
2585 allocate_v6_address (v6))
2588 *result_af = AF_INET6;
2593 return GNUNET_SYSERR;
2600 * A client asks us to setup a redirection via some exit node to a
2601 * particular IP. Check if @a msg is well-formed.
2604 * @param cls client requesting client
2605 * @param msg redirection request
2606 * @return #GNUNET_OK if @a msg is well-formed
2609 check_client_redirect_to_ip (void *cls,
2610 const struct RedirectToIpRequestMessage *msg)
2615 alen = ntohs (msg->header.size) - sizeof (struct RedirectToIpRequestMessage);
2616 addr_af = (int) htonl (msg->addr_af);
2620 if (alen != sizeof (struct in_addr))
2623 return GNUNET_SYSERR;
2627 if (alen != sizeof (struct in6_addr))
2630 return GNUNET_SYSERR;
2635 return GNUNET_SYSERR;
2642 * A client asks us to setup a redirection via some exit node to a
2643 * particular IP. Setup the redirection and give the client the
2646 * @param cls client requesting client
2647 * @param msg redirection request
2650 handle_client_redirect_to_ip (void *cls,
2651 const struct RedirectToIpRequestMessage *msg)
2653 struct GNUNET_SERVICE_Client *client = cls;
2660 struct DestinationEntry *de;
2661 struct GNUNET_HashCode key;
2663 alen = ntohs (msg->header.size) - sizeof (struct RedirectToIpRequestMessage);
2664 addr_af = (int) htonl (msg->addr_af);
2665 /* allocate response IP */
2666 result_af = (int) htonl (msg->result_af);
2667 if (GNUNET_OK != allocate_response_ip (&result_af,
2671 GNUNET_SERVICE_client_drop (client);
2674 /* send reply with our IP address */
2675 send_client_reply (client,
2679 if (result_af == AF_UNSPEC)
2681 /* failure, we're done */
2682 GNUNET_SERVICE_client_continue (client);
2687 char sbuf[INET6_ADDRSTRLEN];
2688 char dbuf[INET6_ADDRSTRLEN];
2690 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2691 "Allocated address %s for redirection via exit to %s\n",
2692 inet_ntop (result_af,
2702 /* setup destination record */
2703 de = GNUNET_new (struct DestinationEntry);
2704 de->is_service = GNUNET_NO;
2705 de->details.exit_destination.af = addr_af;
2706 GNUNET_memcpy (&de->details.exit_destination.ip,
2709 get_destination_key_from_ip (result_af,
2713 GNUNET_assert (GNUNET_OK ==
2714 GNUNET_CONTAINER_multihashmap_put (destination_map,
2717 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2718 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2720 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value_us);
2721 GNUNET_STATISTICS_update (stats,
2722 gettext_noop ("# Active destinations"),
2724 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2725 expire_destination (de);
2726 GNUNET_SERVICE_client_continue (client);
2731 * A client asks us to setup a redirection to a particular peer
2732 * offering a service. Setup the redirection and give the client the
2735 * @param cls requesting client
2736 * @param msg redirection request
2739 handle_client_redirect_to_service (void *cls,
2740 const struct RedirectToServiceRequestMessage *msg)
2742 struct GNUNET_SERVICE_Client *client = cls;
2747 struct DestinationEntry *de;
2748 struct GNUNET_HashCode key;
2749 struct DestinationChannel *dt;
2751 /* allocate response IP */
2752 result_af = (int) htonl (msg->result_af);
2754 allocate_response_ip (&result_af,
2760 GNUNET_SERVICE_client_drop (client);
2763 send_client_reply (client,
2767 if (result_af == AF_UNSPEC)
2769 /* failure, we're done */
2770 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2771 _("Failed to allocate IP address for new destination\n"));
2772 GNUNET_SERVICE_client_continue (client);
2777 char sbuf[INET6_ADDRSTRLEN];
2779 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2780 "Allocated address %s for redirection to service %s on peer %s\n",
2781 inet_ntop (result_af,
2785 GNUNET_h2s (&msg->service_descriptor),
2786 GNUNET_i2s (&msg->target));
2789 /* setup destination record */
2790 de = GNUNET_new (struct DestinationEntry);
2791 de->is_service = GNUNET_YES;
2792 de->details.service_destination.target = msg->target;
2793 de->details.service_destination.service_descriptor = msg->service_descriptor;
2794 get_destination_key_from_ip (result_af,
2798 GNUNET_assert (GNUNET_OK ==
2799 GNUNET_CONTAINER_multihashmap_put (destination_map,
2802 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2804 = GNUNET_CONTAINER_heap_insert (destination_heap,
2806 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value_us);
2807 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2808 expire_destination (de);
2810 dt = GNUNET_new (struct DestinationChannel);
2811 dt->destination = de;
2812 GNUNET_CONTAINER_DLL_insert (de->dt_head,
2816 GNUNET_SERVICE_client_continue (client);
2821 * Function called whenever a channel is destroyed. Should clean up
2822 * any associated state.
2824 * @param cls closure (set from #GNUNET_CADET_connect)
2825 * @param channel connection to the other end (henceforth invalid)
2826 * @param channel_ctx place where local state associated
2827 * with the channel is stored (our `struct ChannelState`)
2830 channel_cleaner (void *cls,
2831 const struct GNUNET_CADET_Channel *channel,
2834 struct ChannelState *ts = channel_ctx;
2836 ts->channel = NULL; /* we must not call GNUNET_CADET_channel_destroy() anymore */
2837 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2838 "CADET notified us about death of channel to `%s'\n",
2839 print_channel_destination (&ts->destination));
2840 free_channel_state (ts);
2845 * Free memory occupied by an entry in the destination map.
2849 * @param value a `struct DestinationEntry *`
2850 * @return #GNUNET_OK (continue to iterate)
2853 cleanup_destination (void *cls,
2854 const struct GNUNET_HashCode *key,
2857 struct DestinationEntry *de = value;
2859 free_destination_entry (de);
2865 * Free memory occupied by an entry in the channel map.
2869 * @param value a `struct ChannelState *`
2870 * @return #GNUNET_OK (continue to iterate)
2873 cleanup_channel (void *cls,
2874 const struct GNUNET_HashCode *key,
2877 struct ChannelState *ts = value;
2879 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2880 "Tearing down channel to `%s' during cleanup\n",
2881 print_channel_destination (&ts->destination));
2882 free_channel_state (ts);
2888 * Function scheduled as very last function, cleans up after us
2897 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2898 "VPN is shutting down\n");
2899 if (NULL != destination_map)
2901 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
2902 &cleanup_destination,
2904 GNUNET_CONTAINER_multihashmap_destroy (destination_map);
2905 destination_map = NULL;
2907 if (NULL != destination_heap)
2909 GNUNET_CONTAINER_heap_destroy (destination_heap);
2910 destination_heap = NULL;
2912 if (NULL != channel_map)
2914 GNUNET_CONTAINER_multihashmap_iterate (channel_map,
2917 GNUNET_CONTAINER_multihashmap_destroy (channel_map);
2920 if (NULL != channel_heap)
2922 GNUNET_CONTAINER_heap_destroy (channel_heap);
2923 channel_heap = NULL;
2925 if (NULL != cadet_handle)
2927 GNUNET_CADET_disconnect (cadet_handle);
2928 cadet_handle = NULL;
2930 if (NULL != helper_handle)
2932 GNUNET_HELPER_kill (helper_handle, GNUNET_NO);
2933 GNUNET_HELPER_wait (helper_handle);
2934 helper_handle = NULL;
2938 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
2942 GNUNET_free_non_null (vpn_argv[i]);
2947 * Callback called when a client connects to the service.
2949 * @param cls closure for the service
2950 * @param c the new client that connected to the service
2951 * @param mq the message queue used to send messages to the client
2955 client_connect_cb (void *cls,
2956 struct GNUNET_SERVICE_Client *c,
2957 struct GNUNET_MQ_Handle *mq)
2964 * Callback called when a client disconnected from the service
2966 * @param cls closure for the service
2967 * @param c the client that disconnected
2968 * @param internal_cls should be equal to @a c
2971 client_disconnect_cb (void *cls,
2972 struct GNUNET_SERVICE_Client *c,
2975 GNUNET_assert (c == internal_cls);
2980 * Main function that will be run by the scheduler.
2982 * @param cls closure
2983 * @param cfg_ configuration
2984 * @param service the initialized service
2988 const struct GNUNET_CONFIGURATION_Handle *cfg_,
2989 struct GNUNET_SERVICE_Handle *service)
2991 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
2992 { &receive_udp_back, GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY, 0},
2993 { &receive_tcp_back, GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN, 0},
2994 { &receive_icmp_back, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN, 0},
3006 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-vpn");
3009 GNUNET_OS_check_helper_binary (binary,
3011 "-d gnunet-vpn - - 169.1.3.3.7 255.255.255.0")) //ipv4 only please!
3013 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3014 "`%s' is not SUID, refusing to run.\n",
3015 "gnunet-helper-vpn");
3016 GNUNET_free (binary);
3018 /* we won't "really" exit here, as the 'service' is still running;
3019 however, as no handlers are registered, the service won't do
3023 GNUNET_free (binary);
3025 stats = GNUNET_STATISTICS_create ("vpn", cfg);
3027 GNUNET_CONFIGURATION_get_value_number (cfg,
3030 &max_destination_mappings))
3031 max_destination_mappings = 200;
3033 GNUNET_CONFIGURATION_get_value_number (cfg,
3036 &max_channel_mappings))
3037 max_channel_mappings = 200;
3039 destination_map = GNUNET_CONTAINER_multihashmap_create (max_destination_mappings * 2, GNUNET_NO);
3040 destination_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3041 channel_map = GNUNET_CONTAINER_multihashmap_create (max_channel_mappings * 2, GNUNET_NO);
3042 channel_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3045 vpn_argv[0] = GNUNET_strdup ("vpn-gnunet");
3046 if (GNUNET_SYSERR ==
3047 GNUNET_CONFIGURATION_get_value_string (cfg, "VPN", "IFNAME", &ifname))
3049 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "VPN", "IFNAME");
3050 GNUNET_SCHEDULER_shutdown ();
3053 vpn_argv[1] = ifname;
3055 if (GNUNET_OK == GNUNET_NETWORK_test_pf (PF_INET6))
3057 if ( (GNUNET_SYSERR ==
3058 GNUNET_CONFIGURATION_get_value_string (cfg, "VPN", "IPV6ADDR",
3060 (1 != inet_pton (AF_INET6, ipv6addr, &v6))) )
3062 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV6ADDR",
3063 _("Must specify valid IPv6 address"));
3064 GNUNET_SCHEDULER_shutdown ();
3065 GNUNET_free_non_null (ipv6addr);
3068 vpn_argv[2] = ipv6addr;
3069 ipv6prefix_s = NULL;
3070 if (GNUNET_SYSERR ==
3071 GNUNET_CONFIGURATION_get_value_string (cfg, "VPN", "IPV6PREFIX",
3074 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV6PREFIX");
3075 GNUNET_SCHEDULER_shutdown ();
3076 GNUNET_free_non_null (ipv6prefix_s);
3079 vpn_argv[3] = ipv6prefix_s;
3081 GNUNET_CONFIGURATION_get_value_number (cfg, "VPN",
3084 (ipv6prefix >= 127) )
3086 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV4MASK",
3087 _("Must specify valid IPv6 mask"));
3088 GNUNET_SCHEDULER_shutdown ();
3094 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3095 _("IPv6 support disabled as this system does not support IPv6\n"));
3096 vpn_argv[2] = GNUNET_strdup ("-");
3097 vpn_argv[3] = GNUNET_strdup ("-");
3099 if (GNUNET_OK == GNUNET_NETWORK_test_pf (PF_INET))
3102 if ( (GNUNET_SYSERR ==
3103 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4ADDR",
3105 (1 != inet_pton (AF_INET, ipv4addr, &v4))) )
3107 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV4ADDR",
3108 _("Must specify valid IPv4 address"));
3109 GNUNET_SCHEDULER_shutdown ();
3110 GNUNET_free_non_null (ipv4addr);
3113 vpn_argv[4] = ipv4addr;
3115 if ( (GNUNET_SYSERR ==
3116 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4MASK",
3118 (1 != inet_pton (AF_INET, ipv4mask, &v4))) )
3120 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV4MASK",
3121 _("Must specify valid IPv4 mask"));
3122 GNUNET_SCHEDULER_shutdown ();
3123 GNUNET_free_non_null (ipv4mask);
3126 vpn_argv[5] = ipv4mask;
3130 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3131 _("IPv4 support disabled as this system does not support IPv4\n"));
3132 vpn_argv[4] = GNUNET_strdup ("-");
3133 vpn_argv[5] = GNUNET_strdup ("-");
3138 = GNUNET_CADET_connect (cfg_,
3142 // FIXME never opens ports???
3143 helper_handle = GNUNET_HELPER_start (GNUNET_NO,
3144 "gnunet-helper-vpn", vpn_argv,
3145 &message_token, NULL, NULL);
3146 GNUNET_SCHEDULER_add_shutdown (&cleanup,
3152 * Define "main" method using service macro.
3156 GNUNET_SERVICE_OPTION_NONE,
3159 &client_disconnect_cb,
3161 GNUNET_MQ_hd_var_size (client_redirect_to_ip,
3162 GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP,
3163 struct RedirectToIpRequestMessage,
3165 GNUNET_MQ_hd_fixed_size (client_redirect_to_service,
3166 GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE,
3167 struct RedirectToServiceRequestMessage,
3169 GNUNET_MQ_handler_end ());
3172 /* end of gnunet-service-vpn.c */