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., 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 * Notification context for sending replies to clients.
382 static struct GNUNET_SERVER_NotificationContext *nc;
385 * If there are more than this number of address-mappings, old ones
388 static unsigned long long max_destination_mappings;
391 * If there are more than this number of open channels, old ones
394 static unsigned long long max_channel_mappings;
398 * Compute the key under which we would store an entry in the
399 * #destination_map for the given IP address.
401 * @param af address family (AF_INET or AF_INET6)
402 * @param address IP address, struct in_addr or struct in6_addr
403 * @param key where to store the key
406 get_destination_key_from_ip (int af,
408 struct GNUNET_HashCode *key)
413 GNUNET_CRYPTO_hash (address,
414 sizeof (struct in_addr),
418 GNUNET_CRYPTO_hash (address,
419 sizeof (struct in6_addr),
430 * Compute the key under which we would store an entry in the
431 * channel_map for the given socket address pair.
433 * @param af address family (AF_INET or AF_INET6)
434 * @param protocol IPPROTO_TCP or IPPROTO_UDP
435 * @param source_ip sender's source IP, struct in_addr or struct in6_addr
436 * @param source_port sender's source port
437 * @param destination_ip sender's destination IP, struct in_addr or struct in6_addr
438 * @param destination_port sender's destination port
439 * @param key where to store the key
442 get_channel_key_from_ips (int af,
444 const void *source_ip,
445 uint16_t source_port,
446 const void *destination_ip,
447 uint16_t destination_port,
448 struct GNUNET_HashCode *key)
452 memset (key, 0, sizeof (struct GNUNET_HashCode));
453 /* the GNUnet hashmap only uses the first sizeof(unsigned int) of the hash,
454 so we put the ports in there (and hope for few collisions) */
456 GNUNET_memcpy (off, &source_port, sizeof (uint16_t));
457 off += sizeof (uint16_t);
458 GNUNET_memcpy (off, &destination_port, sizeof (uint16_t));
459 off += sizeof (uint16_t);
463 GNUNET_memcpy (off, source_ip, sizeof (struct in_addr));
464 off += sizeof (struct in_addr);
465 GNUNET_memcpy (off, destination_ip, sizeof (struct in_addr));
466 off += sizeof (struct in_addr);
469 GNUNET_memcpy (off, source_ip, sizeof (struct in6_addr));
470 off += sizeof (struct in6_addr);
471 GNUNET_memcpy (off, destination_ip, sizeof (struct in6_addr));
472 off += sizeof (struct in6_addr);
478 GNUNET_memcpy (off, &protocol, sizeof (uint8_t));
479 /* off += sizeof (uint8_t); */
484 * Notify the client about the result of its request.
486 * @param client client to notify
487 * @param request_id original request ID to include in response
488 * @param result_af resulting address family
489 * @param addr resulting IP address
492 send_client_reply (struct GNUNET_SERVER_Client *client,
497 char buf[sizeof (struct RedirectToIpResponseMessage) + sizeof (struct in6_addr)] GNUNET_ALIGN;
498 struct RedirectToIpResponseMessage *res;
504 rlen = sizeof (struct in_addr);
507 rlen = sizeof (struct in6_addr);
516 res = (struct RedirectToIpResponseMessage *) buf;
517 res->header.size = htons (sizeof (struct RedirectToIpResponseMessage) + rlen);
518 res->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP);
519 res->result_af = htonl (result_af);
520 res->request_id = request_id;
521 GNUNET_memcpy (&res[1],
524 GNUNET_SERVER_notification_context_add (nc, client);
525 GNUNET_SERVER_notification_context_unicast (nc,
533 * Free resources associated with a channel state.
535 * @param ts state to free
538 free_channel_state (struct ChannelState *ts)
540 struct GNUNET_HashCode key;
541 struct ChannelMessageQueueEntry *tnq;
542 struct GNUNET_CADET_Channel *channel;
544 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
545 "Cleaning up channel state\n");
548 GNUNET_CADET_notify_transmit_ready_cancel (ts->th);
551 if (NULL != (channel = ts->channel))
554 GNUNET_CADET_channel_destroy (channel);
557 GNUNET_STATISTICS_update (stats,
558 gettext_noop ("# Active channels"),
560 while (NULL != (tnq = ts->tmq_head))
562 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
568 GNUNET_assert (0 == ts->tmq_length);
569 GNUNET_assert (NULL == ts->destination.heap_node);
570 if (NULL != ts->search)
572 GNUNET_REGEX_search_cancel (ts->search);
575 if (NULL != ts->heap_node)
577 GNUNET_CONTAINER_heap_remove_node (ts->heap_node);
578 ts->heap_node = NULL;
579 get_channel_key_from_ips (ts->af,
584 ts->destination_port,
586 GNUNET_assert (GNUNET_YES ==
587 GNUNET_CONTAINER_multihashmap_remove (channel_map,
596 * Send a message from the message queue via cadet.
598 * @param cls the `struct ChannelState` with the message queue
599 * @param size number of bytes available in @a buf
600 * @param buf where to copy the message
601 * @return number of bytes copied to @a buf
604 send_to_peer_notify_callback (void *cls, size_t size, void *buf)
606 struct ChannelState *ts = cls;
607 struct ChannelMessageQueueEntry *tnq;
614 GNUNET_assert (NULL != tnq);
615 GNUNET_assert (size >= tnq->len);
616 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
617 "Sending %u bytes via cadet channel\n",
618 (unsigned int) tnq->len);
619 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
623 GNUNET_memcpy (buf, tnq->msg, tnq->len);
626 if (NULL != (tnq = ts->tmq_head))
629 ts->th = GNUNET_CADET_notify_transmit_ready (ts->channel,
630 GNUNET_NO /* cork */,
631 GNUNET_TIME_UNIT_FOREVER_REL,
633 &send_to_peer_notify_callback,
636 GNUNET_STATISTICS_update (stats,
637 gettext_noop ("# Bytes given to cadet for transmission"),
644 * Add the given message to the given channel and trigger the
645 * transmission process.
647 * @param tnq message to queue
648 * @param ts channel to queue the message for
651 send_to_channel (struct ChannelMessageQueueEntry *tnq,
652 struct ChannelState *ts)
654 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
655 "Queueing %u bytes for transmission via cadet channel\n",
656 (unsigned int) tnq->len);
657 GNUNET_assert (NULL != ts->channel);
658 GNUNET_CONTAINER_DLL_insert_tail (ts->tmq_head,
662 if (ts->tmq_length > MAX_MESSAGE_QUEUE_SIZE)
664 struct ChannelMessageQueueEntry *dq;
667 GNUNET_assert (dq != tnq);
668 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
672 GNUNET_CADET_notify_transmit_ready_cancel (ts->th);
674 GNUNET_STATISTICS_update (stats,
675 gettext_noop ("# Bytes dropped in cadet queue (overflow)"),
681 ts->th = GNUNET_CADET_notify_transmit_ready (ts->channel,
682 GNUNET_NO /* cork */,
683 GNUNET_TIME_UNIT_FOREVER_REL,
685 &send_to_peer_notify_callback,
691 * Output destination of a channel for diagnostics.
693 * @param de destination to process
694 * @return diagnostic string describing destination
697 print_channel_destination (const struct DestinationEntry *de)
699 static char dest[256];
703 GNUNET_snprintf (dest,
706 GNUNET_i2s (&de->details.service_destination.target),
707 GNUNET_h2s (&de->details.service_destination.service_descriptor));
711 inet_ntop (de->details.exit_destination.af,
712 &de->details.exit_destination.ip,
721 * Regex has found a potential exit peer for us; consider using it.
723 * @param cls the `struct ChannelState`
724 * @param id Peer providing a regex that matches the string.
725 * @param get_path Path of the get request.
726 * @param get_path_length Lenght of @a get_path.
727 * @param put_path Path of the put request.
728 * @param put_path_length Length of the @a put_path.
731 handle_regex_result (void *cls,
732 const struct GNUNET_PeerIdentity *id,
733 const struct GNUNET_PeerIdentity *get_path,
734 unsigned int get_path_length,
735 const struct GNUNET_PeerIdentity *put_path,
736 unsigned int put_path_length)
738 struct ChannelState *ts = cls;
739 struct GNUNET_HashCode port;
741 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
742 "Exit %s found for destination %s!\n",
744 print_channel_destination (&ts->destination));
745 GNUNET_REGEX_search_cancel (ts->search);
750 /* these must match the strings used in gnunet-daemon-exit */
751 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_IPV4_GATEWAY,
752 strlen (GNUNET_APPLICATION_PORT_IPV4_GATEWAY),
756 /* these must match the strings used in gnunet-daemon-exit */
757 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_IPV6_GATEWAY,
758 strlen (GNUNET_APPLICATION_PORT_IPV6_GATEWAY),
765 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
766 "Creating tunnel to %s for destination %s!\n",
768 print_channel_destination (&ts->destination));
769 ts->channel = GNUNET_CADET_channel_create (cadet_handle,
773 GNUNET_CADET_OPTION_DEFAULT);
778 * Initialize the given destination entry's cadet channel.
780 * @param dt destination channel for which we need to setup a channel
781 * @param client_af address family of the address returned to the client
782 * @return channel state of the channel that was created
784 static struct ChannelState *
785 create_channel_to_destination (struct DestinationChannel *dt,
788 struct ChannelState *ts;
790 GNUNET_STATISTICS_update (stats,
791 gettext_noop ("# Cadet channels created"),
794 ts = GNUNET_new (struct ChannelState);
796 ts->destination = *dt->destination;
797 ts->destination.heap_node = NULL; /* copy is NOT in destination heap */
798 ts->destination_port = dt->destination_port;
799 if (dt->destination->is_service)
801 struct GNUNET_HashCode cadet_port;
803 GNUNET_TUN_compute_service_cadet_port (&ts->destination.details.service_destination.service_descriptor,
804 ts->destination_port,
807 = GNUNET_CADET_channel_create (cadet_handle,
809 &dt->destination->details.service_destination.target,
811 GNUNET_CADET_OPTION_DEFAULT);
812 if (NULL == ts->channel)
818 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
819 "Creating channel to peer %s offering service %s on port %u\n",
820 GNUNET_i2s (&dt->destination->details.service_destination.target),
821 GNUNET_h2s (&ts->destination.details.service_destination.service_descriptor),
822 (unsigned int) ts->destination_port);
828 switch (dt->destination->details.exit_destination.af)
832 char address[GNUNET_TUN_IPV4_REGEXLEN];
834 GNUNET_TUN_ipv4toregexsearch (&dt->destination->details.exit_destination.ip.v4,
835 dt->destination_port,
837 GNUNET_asprintf (&policy,
839 GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
845 char address[GNUNET_TUN_IPV6_REGEXLEN];
847 GNUNET_TUN_ipv6toregexsearch (&dt->destination->details.exit_destination.ip.v6,
848 dt->destination_port,
850 GNUNET_asprintf (&policy,
852 GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
861 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
862 "Requesting connect by string: %s\n",
864 ts->search = GNUNET_REGEX_search (cfg,
866 &handle_regex_result,
868 GNUNET_free (policy);
875 * We have too many active channels. Clean up the oldest channel.
877 * @param except channel that must NOT be cleaned up, even if it is the oldest
880 expire_channel (struct ChannelState *except)
882 struct ChannelState *ts;
884 ts = GNUNET_CONTAINER_heap_peek (channel_heap);
885 GNUNET_assert (NULL != ts);
887 return; /* can't do this */
888 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
889 "Tearing down expired channel to %s\n",
890 print_channel_destination (&except->destination));
891 free_channel_state (ts);
896 * Route a packet via cadet to the given destination.
898 * @param destination description of the destination
899 * @param af address family on this end (AF_INET or AF_INET6)
900 * @param protocol IPPROTO_TCP or IPPROTO_UDP or IPPROTO_ICMP or IPPROTO_ICMPV6
901 * @param source_ip source IP used by the sender (struct in_addr or struct in6_addr)
902 * @param destination_ip destination IP used by the sender (struct in_addr or struct in6_addr)
903 * @param payload payload of the packet after the IP header
904 * @param payload_length number of bytes in @a payload
907 route_packet (struct DestinationEntry *destination,
910 const void *source_ip,
911 const void *destination_ip,
913 size_t payload_length)
915 struct GNUNET_HashCode key;
916 struct ChannelState *ts;
917 struct ChannelMessageQueueEntry *tnq;
920 const struct GNUNET_TUN_UdpHeader *udp;
921 const struct GNUNET_TUN_TcpHeader *tcp;
922 const struct GNUNET_TUN_IcmpHeader *icmp;
923 struct DestinationChannel *dt;
924 uint16_t source_port;
925 uint16_t destination_port;
931 if (payload_length < sizeof (struct GNUNET_TUN_UdpHeader))
937 tcp = NULL; /* make compiler happy */
938 icmp = NULL; /* make compiler happy */
940 if (udp->len < sizeof (struct GNUNET_TUN_UdpHeader))
945 source_port = ntohs (udp->source_port);
946 destination_port = ntohs (udp->destination_port);
947 get_channel_key_from_ips (af,
958 if (payload_length < sizeof (struct GNUNET_TUN_TcpHeader))
964 udp = NULL; /* make compiler happy */
965 icmp = NULL; /* make compiler happy */
967 if (tcp->off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
972 source_port = ntohs (tcp->source_port);
973 destination_port = ntohs (tcp->destination_port);
974 get_channel_key_from_ips (af,
986 if ( (AF_INET == af) ^ (protocol == IPPROTO_ICMP) )
991 if (payload_length < sizeof (struct GNUNET_TUN_IcmpHeader))
997 tcp = NULL; /* make compiler happy */
998 udp = NULL; /* make compiler happy */
1001 destination_port = 0;
1002 get_channel_key_from_ips (af,
1012 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1013 _("Protocol %u not supported, dropping\n"),
1014 (unsigned int) protocol);
1018 if (! destination->is_service)
1020 switch (destination->details.exit_destination.af)
1023 alen = sizeof (struct in_addr);
1026 alen = sizeof (struct in6_addr);
1033 char sbuf[INET6_ADDRSTRLEN];
1034 char dbuf[INET6_ADDRSTRLEN];
1035 char xbuf[INET6_ADDRSTRLEN];
1037 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1038 "Routing %s packet from [%s]:%u -> [%s]:%u to destination [%s]:%u\n",
1039 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
1050 inet_ntop (destination->details.exit_destination.af,
1051 &destination->details.exit_destination.ip,
1052 xbuf, sizeof (xbuf)),
1055 for (dt = destination->dt_head; NULL != dt; dt = dt->next)
1056 if (dt->destination_port == destination_port)
1062 char sbuf[INET6_ADDRSTRLEN];
1063 char dbuf[INET6_ADDRSTRLEN];
1065 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1066 "Routing %s packet from [%s]:%u -> [%s]:%u to service %s at peer %s\n",
1067 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
1078 GNUNET_h2s (&destination->details.service_destination.service_descriptor),
1079 GNUNET_i2s (&destination->details.service_destination.target));
1081 for (dt = destination->dt_head; NULL != dt; dt = dt->next)
1082 if (dt->destination_port == destination_port)
1087 dt = GNUNET_new (struct DestinationChannel);
1088 dt->destination = destination;
1089 GNUNET_CONTAINER_DLL_insert (destination->dt_head,
1090 destination->dt_tail,
1092 dt->destination_port = destination_port;
1095 /* see if we have an existing channel for this destination */
1096 ts = GNUNET_CONTAINER_multihashmap_get (channel_map,
1100 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1101 "Creating new channel for key %s\n",
1103 /* need to either use the existing channel from the destination (if still
1104 available) or create a fresh one */
1105 ts = create_channel_to_destination (dt,
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 GNUNET_memcpy (&usm[1],
1186 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1190 struct GNUNET_EXIT_UdpInternetMessage *uim;
1191 struct in_addr *ip4dst;
1192 struct in6_addr *ip6dst;
1195 mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) +
1196 alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1197 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1202 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1205 uim = (struct GNUNET_EXIT_UdpInternetMessage *) &tnq[1];
1206 uim->header.size = htons ((uint16_t) mlen);
1207 uim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET);
1208 uim->af = htonl (destination->details.exit_destination.af);
1209 uim->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1210 uim->destination_port = udp->destination_port;
1211 switch (destination->details.exit_destination.af)
1214 ip4dst = (struct in_addr *) &uim[1];
1215 *ip4dst = destination->details.exit_destination.ip.v4;
1216 payload = &ip4dst[1];
1219 ip6dst = (struct in6_addr *) &uim[1];
1220 *ip6dst = destination->details.exit_destination.ip.v6;
1221 payload = &ip6dst[1];
1226 GNUNET_memcpy (payload,
1228 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1232 if (GNUNET_NO == ts->is_established)
1234 if (destination->is_service)
1236 struct GNUNET_EXIT_TcpServiceStartMessage *tsm;
1238 mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) +
1239 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1240 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1245 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1248 tsm = (struct GNUNET_EXIT_TcpServiceStartMessage *) &tnq[1];
1249 tsm->header.size = htons ((uint16_t) mlen);
1250 tsm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START);
1251 tsm->reserved = htonl (0);
1252 tsm->tcp_header = *tcp;
1253 GNUNET_memcpy (&tsm[1],
1255 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1259 struct GNUNET_EXIT_TcpInternetStartMessage *tim;
1260 struct in_addr *ip4dst;
1261 struct in6_addr *ip6dst;
1264 mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) +
1265 alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1266 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1271 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1274 tim = (struct GNUNET_EXIT_TcpInternetStartMessage *) &tnq[1];
1275 tim->header.size = htons ((uint16_t) mlen);
1276 tim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START);
1277 tim->af = htonl (destination->details.exit_destination.af);
1278 tim->tcp_header = *tcp;
1279 switch (destination->details.exit_destination.af)
1282 ip4dst = (struct in_addr *) &tim[1];
1283 *ip4dst = destination->details.exit_destination.ip.v4;
1284 payload = &ip4dst[1];
1287 ip6dst = (struct in6_addr *) &tim[1];
1288 *ip6dst = destination->details.exit_destination.ip.v6;
1289 payload = &ip6dst[1];
1294 GNUNET_memcpy (payload,
1296 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1301 struct GNUNET_EXIT_TcpDataMessage *tdm;
1303 mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) +
1304 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1305 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1310 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1313 tdm = (struct GNUNET_EXIT_TcpDataMessage *) &tnq[1];
1314 tdm->header.size = htons ((uint16_t) mlen);
1315 tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT);
1316 tdm->reserved = htonl (0);
1317 tdm->tcp_header = *tcp;
1318 GNUNET_memcpy (&tdm[1],
1320 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1324 case IPPROTO_ICMPV6:
1325 if (destination->is_service)
1327 struct GNUNET_EXIT_IcmpServiceMessage *ism;
1329 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1330 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1331 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1336 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1338 ism = (struct GNUNET_EXIT_IcmpServiceMessage *) &tnq[1];
1339 ism->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE);
1340 ism->af = htonl (af); /* need to tell destination ICMP protocol family! */
1341 ism->icmp_header = *icmp;
1342 /* ICMP protocol translation will be done by the receiver (as we don't know
1343 the target AF); however, we still need to possibly discard the payload
1344 depending on the ICMP type */
1350 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1351 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1353 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1354 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1355 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1356 /* throw away ICMP payload, won't be useful for the other side anyway */
1357 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1360 GNUNET_STATISTICS_update (stats,
1361 gettext_noop ("# ICMPv4 packets dropped (not allowed)"),
1365 /* end of AF_INET */
1370 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1371 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1372 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1373 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1374 /* throw away ICMP payload, won't be useful for the other side anyway */
1375 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1377 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1378 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1381 GNUNET_STATISTICS_update (stats,
1382 gettext_noop ("# ICMPv6 packets dropped (not allowed)"),
1386 /* end of AF_INET6 */
1393 /* update length calculations, as payload_length may have changed */
1394 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1395 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1397 ism->header.size = htons ((uint16_t) mlen);
1398 /* finally, copy payload (if there is any left...) */
1399 GNUNET_memcpy (&ism[1],
1401 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1405 struct GNUNET_EXIT_IcmpInternetMessage *iim;
1406 struct in_addr *ip4dst;
1407 struct in6_addr *ip6dst;
1410 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1411 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1412 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1417 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1419 iim = (struct GNUNET_EXIT_IcmpInternetMessage *) &tnq[1];
1420 iim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET);
1421 iim->icmp_header = *icmp;
1422 /* Perform ICMP protocol-translation (depending on destination AF and source AF)
1423 and throw away ICMP payload depending on ICMP message type */
1429 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1430 if (destination->details.exit_destination.af == AF_INET6)
1431 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1433 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1434 if (destination->details.exit_destination.af == AF_INET6)
1435 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1437 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1438 if (destination->details.exit_destination.af == AF_INET6)
1439 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1440 /* throw away IP-payload, exit will have to make it up anyway */
1441 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1443 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1444 if (destination->details.exit_destination.af == AF_INET6)
1445 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1446 /* throw away IP-payload, exit will have to make it up anyway */
1447 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1449 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1450 if (destination->details.exit_destination.af == AF_INET6)
1452 GNUNET_STATISTICS_update (stats,
1453 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1458 /* throw away IP-payload, exit will have to make it up anyway */
1459 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1462 GNUNET_STATISTICS_update (stats,
1463 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1468 /* end of AF_INET */
1473 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1474 if (destination->details.exit_destination.af == AF_INET6)
1475 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1476 /* throw away IP-payload, exit will have to make it up anyway */
1477 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1479 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1480 if (destination->details.exit_destination.af == AF_INET)
1481 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1482 /* throw away IP-payload, exit will have to make it up anyway */
1483 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1485 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1486 if (destination->details.exit_destination.af == AF_INET)
1488 GNUNET_STATISTICS_update (stats,
1489 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1494 /* throw away IP-payload, exit will have to make it up anyway */
1495 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1497 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1498 if (destination->details.exit_destination.af == AF_INET)
1500 GNUNET_STATISTICS_update (stats,
1501 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1506 /* throw away IP-payload, exit will have to make it up anyway */
1507 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1509 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1510 if (destination->details.exit_destination.af == AF_INET)
1511 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1513 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1514 if (destination->details.exit_destination.af == AF_INET)
1515 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1518 GNUNET_STATISTICS_update (stats,
1519 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1524 /* end of AF_INET6 */
1529 /* update length calculations, as payload_length may have changed */
1530 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1531 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1533 iim->header.size = htons ((uint16_t) mlen);
1535 /* need to tell destination ICMP protocol family! */
1536 iim->af = htonl (destination->details.exit_destination.af);
1537 switch (destination->details.exit_destination.af)
1540 ip4dst = (struct in_addr *) &iim[1];
1541 *ip4dst = destination->details.exit_destination.ip.v4;
1542 payload = &ip4dst[1];
1545 ip6dst = (struct in6_addr *) &iim[1];
1546 *ip6dst = destination->details.exit_destination.ip.v6;
1547 payload = &ip6dst[1];
1552 GNUNET_memcpy (payload,
1554 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1558 /* not supported above, how can we get here !? */
1562 ts->is_established = GNUNET_YES;
1563 send_to_channel (tnq, ts);
1568 * Receive packets from the helper-process (someone send to the local
1569 * virtual channel interface). Find the destination mapping, and if it
1570 * exists, identify the correct CADET channel (or possibly create it)
1571 * and forward the packet.
1573 * @param cls closure, NULL
1574 * @param client NULL
1575 * @param message message we got from the client (VPN channel interface)
1578 message_token (void *cls,
1580 const struct GNUNET_MessageHeader *message)
1582 const struct GNUNET_TUN_Layer2PacketHeader *tun;
1584 struct GNUNET_HashCode key;
1585 struct DestinationEntry *de;
1587 GNUNET_STATISTICS_update (stats,
1588 gettext_noop ("# Packets received from TUN interface"),
1590 mlen = ntohs (message->size);
1591 if ( (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
1592 (mlen < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader)) )
1597 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1598 mlen -= (sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader));
1599 switch (ntohs (tun->proto))
1603 const struct GNUNET_TUN_IPv6Header *pkt6;
1605 if (mlen < sizeof (struct GNUNET_TUN_IPv6Header))
1611 pkt6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1612 get_destination_key_from_ip (AF_INET6,
1613 &pkt6->destination_address,
1615 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1618 char buf[INET6_ADDRSTRLEN];
1620 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1621 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1622 inet_ntop (AF_INET6,
1623 &pkt6->destination_address,
1631 &pkt6->source_address,
1632 &pkt6->destination_address,
1634 mlen - sizeof (struct GNUNET_TUN_IPv6Header));
1639 struct GNUNET_TUN_IPv4Header *pkt4;
1641 if (mlen < sizeof (struct GNUNET_TUN_IPv4Header))
1647 pkt4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1648 get_destination_key_from_ip (AF_INET,
1649 &pkt4->destination_address,
1651 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1654 char buf[INET_ADDRSTRLEN];
1656 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1657 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1659 &pkt4->destination_address,
1664 if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header))
1666 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1667 _("Received IPv4 packet with options (dropping it)\n"));
1673 &pkt4->source_address,
1674 &pkt4->destination_address,
1676 mlen - sizeof (struct GNUNET_TUN_IPv4Header));
1680 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1681 _("Received packet of unknown protocol %d from TUN (dropping it)\n"),
1682 (unsigned int) ntohs (tun->proto));
1690 * Synthesize a plausible ICMP payload for an ICMP error
1691 * response on the given channel.
1693 * @param ts channel information
1694 * @param ipp IPv4 header to fill in (ICMP payload)
1695 * @param udp "UDP" header to fill in (ICMP payload); might actually
1696 * also be the first 8 bytes of the TCP header
1699 make_up_icmpv4_payload (struct ChannelState *ts,
1700 struct GNUNET_TUN_IPv4Header *ipp,
1701 struct GNUNET_TUN_UdpHeader *udp)
1703 GNUNET_TUN_initialize_ipv4_header (ipp,
1705 sizeof (struct GNUNET_TUN_TcpHeader),
1707 &ts->destination_ip.v4);
1708 udp->source_port = htons (ts->source_port);
1709 udp->destination_port = htons (ts->destination_port);
1710 udp->len = htons (0);
1711 udp->crc = htons (0);
1716 * Synthesize a plausible ICMP payload for an ICMP error
1717 * response on the given channel.
1719 * @param ts channel information
1720 * @param ipp IPv6 header to fill in (ICMP payload)
1721 * @param udp "UDP" header to fill in (ICMP payload); might actually
1722 * also be the first 8 bytes of the TCP header
1725 make_up_icmpv6_payload (struct ChannelState *ts,
1726 struct GNUNET_TUN_IPv6Header *ipp,
1727 struct GNUNET_TUN_UdpHeader *udp)
1729 GNUNET_TUN_initialize_ipv6_header (ipp,
1731 sizeof (struct GNUNET_TUN_TcpHeader),
1733 &ts->destination_ip.v6);
1734 udp->source_port = htons (ts->source_port);
1735 udp->destination_port = htons (ts->destination_port);
1736 udp->len = htons (0);
1737 udp->crc = htons (0);
1742 * We got an ICMP packet back from the CADET channel. Pass it on to the
1743 * local virtual interface via the helper.
1745 * @param cls closure, NULL
1746 * @param channel connection to the other end
1747 * @param channel_ctx pointer to our 'struct ChannelState *'
1748 * @param message the actual message
1749 * @return #GNUNET_OK to keep the connection open,
1750 * #GNUNET_SYSERR to close it (signal serious error)
1753 receive_icmp_back (void *cls,
1754 struct GNUNET_CADET_Channel *channel,
1756 const struct GNUNET_MessageHeader *message)
1758 struct ChannelState *ts = *channel_ctx;
1759 const struct GNUNET_EXIT_IcmpToVPNMessage *i2v;
1762 GNUNET_STATISTICS_update (stats,
1763 gettext_noop ("# ICMP packets received from cadet"),
1765 mlen = ntohs (message->size);
1766 if (mlen < sizeof (struct GNUNET_EXIT_IcmpToVPNMessage))
1768 GNUNET_break_op (0);
1769 return GNUNET_SYSERR;
1771 if (NULL == ts->heap_node)
1773 GNUNET_break_op (0);
1774 return GNUNET_SYSERR;
1776 if (AF_UNSPEC == ts->af)
1778 GNUNET_break_op (0);
1779 return GNUNET_SYSERR;
1781 i2v = (const struct GNUNET_EXIT_IcmpToVPNMessage *) message;
1782 mlen -= sizeof (struct GNUNET_EXIT_IcmpToVPNMessage);
1784 char sbuf[INET6_ADDRSTRLEN];
1785 char dbuf[INET6_ADDRSTRLEN];
1787 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1788 "Received ICMP packet from cadet, sending %u bytes from %s -> %s via TUN\n",
1789 (unsigned int) mlen,
1790 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
1791 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)));
1797 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
1798 + sizeof (struct GNUNET_TUN_IcmpHeader)
1799 + sizeof (struct GNUNET_MessageHeader) +
1800 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1803 /* reserve some extra space in case we have an ICMP type here where
1804 we will need to make up the payload ourselves */
1805 char buf[size + sizeof (struct GNUNET_TUN_IPv4Header) + 8] GNUNET_ALIGN;
1806 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1807 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1808 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1809 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv4[1];
1810 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1811 tun->flags = htons (0);
1812 tun->proto = htons (ETH_P_IPV4);
1813 GNUNET_TUN_initialize_ipv4_header (ipv4,
1815 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1816 &ts->destination_ip.v4,
1818 *icmp = i2v->icmp_header;
1819 GNUNET_memcpy (&icmp[1],
1822 /* For some ICMP types, we need to adjust (make up) the payload here.
1823 Also, depending on the AF used on the other side, we have to
1824 do ICMP PT (translate ICMP types) */
1825 switch (ntohl (i2v->af))
1830 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1831 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1833 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1834 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1835 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1837 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1838 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1842 /* sender did not strip ICMP payload? */
1843 GNUNET_break_op (0);
1844 return GNUNET_SYSERR;
1846 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1847 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1848 make_up_icmpv4_payload (ts, ipp, udp);
1852 GNUNET_break_op (0);
1853 GNUNET_STATISTICS_update (stats,
1854 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1856 return GNUNET_SYSERR;
1861 /* ICMP PT 6-to-4 and possibly making up payloads */
1864 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1865 icmp->type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
1867 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1868 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1872 /* sender did not strip ICMP payload? */
1873 GNUNET_break_op (0);
1874 return GNUNET_SYSERR;
1876 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1877 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1878 make_up_icmpv4_payload (ts, ipp, udp);
1881 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1882 icmp->type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1884 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1885 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1889 /* sender did not strip ICMP payload? */
1890 GNUNET_break_op (0);
1891 return GNUNET_SYSERR;
1893 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1894 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1895 make_up_icmpv4_payload (ts, ipp, udp);
1898 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1899 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1900 GNUNET_STATISTICS_update (stats,
1901 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1904 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1905 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1907 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1908 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1911 GNUNET_break_op (0);
1912 GNUNET_STATISTICS_update (stats,
1913 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1915 return GNUNET_SYSERR;
1920 GNUNET_break_op (0);
1921 return GNUNET_SYSERR;
1923 msg->size = htons (size);
1924 GNUNET_TUN_calculate_icmp_checksum (icmp,
1927 (void) GNUNET_HELPER_send (helper_handle,
1936 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
1937 + sizeof (struct GNUNET_TUN_IcmpHeader)
1938 + sizeof (struct GNUNET_MessageHeader) +
1939 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1942 char buf[size + sizeof (struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN;
1943 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1944 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1945 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
1946 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv6[1];
1947 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1948 tun->flags = htons (0);
1949 tun->proto = htons (ETH_P_IPV6);
1950 GNUNET_TUN_initialize_ipv6_header (ipv6,
1952 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1953 &ts->destination_ip.v6,
1955 *icmp = i2v->icmp_header;
1956 GNUNET_memcpy (&icmp[1],
1960 /* For some ICMP types, we need to adjust (make up) the payload here.
1961 Also, depending on the AF used on the other side, we have to
1962 do ICMP PT (translate ICMP types) */
1963 switch (ntohl (i2v->af))
1966 /* ICMP PT 4-to-6 and possibly making up payloads */
1969 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1970 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1972 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1973 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1975 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1976 icmp->type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1978 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1979 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1983 /* sender did not strip ICMP payload? */
1984 GNUNET_break_op (0);
1985 return GNUNET_SYSERR;
1987 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1988 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1989 make_up_icmpv6_payload (ts, ipp, udp);
1992 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1993 icmp->type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1995 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1996 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
2000 /* sender did not strip ICMP payload? */
2001 GNUNET_break_op (0);
2002 return GNUNET_SYSERR;
2004 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
2005 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
2006 make_up_icmpv6_payload (ts, ipp, udp);
2009 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
2010 GNUNET_STATISTICS_update (stats,
2011 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
2015 GNUNET_break_op (0);
2016 GNUNET_STATISTICS_update (stats,
2017 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
2019 return GNUNET_SYSERR;
2026 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
2027 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
2028 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
2029 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
2031 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
2032 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
2036 /* sender did not strip ICMP payload? */
2037 GNUNET_break_op (0);
2038 return GNUNET_SYSERR;
2040 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
2041 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
2042 make_up_icmpv6_payload (ts, ipp, udp);
2045 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
2048 GNUNET_break_op (0);
2049 GNUNET_STATISTICS_update (stats,
2050 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
2052 return GNUNET_SYSERR;
2057 GNUNET_break_op (0);
2058 return GNUNET_SYSERR;
2060 msg->size = htons (size);
2061 GNUNET_TUN_calculate_icmp_checksum (icmp,
2063 (void) GNUNET_HELPER_send (helper_handle,
2073 GNUNET_CONTAINER_heap_update_cost (channel_heap,
2075 GNUNET_TIME_absolute_get ().abs_value_us);
2076 GNUNET_CADET_receive_done (channel);
2082 * We got a UDP packet back from the CADET channel. Pass it on to the
2083 * local virtual interface via the helper.
2085 * @param cls closure, NULL
2086 * @param channel connection to the other end
2087 * @param channel_ctx pointer to our 'struct ChannelState *'
2088 * @param message the actual message
2089 * @return #GNUNET_OK to keep the connection open,
2090 * #GNUNET_SYSERR to close it (signal serious error)
2093 receive_udp_back (void *cls,
2094 struct GNUNET_CADET_Channel *channel,
2096 const struct GNUNET_MessageHeader *message)
2098 struct ChannelState *ts = *channel_ctx;
2099 const struct GNUNET_EXIT_UdpReplyMessage *reply;
2102 GNUNET_STATISTICS_update (stats,
2103 gettext_noop ("# UDP packets received from cadet"),
2105 mlen = ntohs (message->size);
2106 if (mlen < sizeof (struct GNUNET_EXIT_UdpReplyMessage))
2108 GNUNET_break_op (0);
2109 return GNUNET_SYSERR;
2111 if (NULL == ts->heap_node)
2113 GNUNET_break_op (0);
2114 return GNUNET_SYSERR;
2116 if (AF_UNSPEC == ts->af)
2118 GNUNET_break_op (0);
2119 return GNUNET_SYSERR;
2121 reply = (const struct GNUNET_EXIT_UdpReplyMessage *) message;
2122 mlen -= sizeof (struct GNUNET_EXIT_UdpReplyMessage);
2124 char sbuf[INET6_ADDRSTRLEN];
2125 char dbuf[INET6_ADDRSTRLEN];
2127 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2128 "Received UDP reply from cadet, sending %u bytes from [%s]:%u -> [%s]:%u via TUN\n",
2129 (unsigned int) mlen,
2130 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2131 ts->destination_port,
2132 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2139 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2140 + sizeof (struct GNUNET_TUN_UdpHeader)
2141 + sizeof (struct GNUNET_MessageHeader) +
2142 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2145 char buf[size] GNUNET_ALIGN;
2146 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2147 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2148 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2149 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1];
2150 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2151 msg->size = htons (size);
2152 tun->flags = htons (0);
2153 tun->proto = htons (ETH_P_IPV4);
2154 GNUNET_TUN_initialize_ipv4_header (ipv4,
2156 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2157 &ts->destination_ip.v4,
2159 if (0 == ntohs (reply->source_port))
2160 udp->source_port = htons (ts->destination_port);
2162 udp->source_port = reply->source_port;
2163 if (0 == ntohs (reply->destination_port))
2164 udp->destination_port = htons (ts->source_port);
2166 udp->destination_port = reply->destination_port;
2167 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2168 GNUNET_TUN_calculate_udp4_checksum (ipv4,
2172 GNUNET_memcpy (&udp[1],
2175 (void) GNUNET_HELPER_send (helper_handle,
2184 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2185 + sizeof (struct GNUNET_TUN_UdpHeader)
2186 + sizeof (struct GNUNET_MessageHeader) +
2187 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2190 char buf[size] GNUNET_ALIGN;
2191 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2192 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2193 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2194 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1];
2195 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2196 msg->size = htons (size);
2197 tun->flags = htons (0);
2198 tun->proto = htons (ETH_P_IPV6);
2199 GNUNET_TUN_initialize_ipv6_header (ipv6,
2201 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2202 &ts->destination_ip.v6,
2204 if (0 == ntohs (reply->source_port))
2205 udp->source_port = htons (ts->destination_port);
2207 udp->source_port = reply->source_port;
2208 if (0 == ntohs (reply->destination_port))
2209 udp->destination_port = htons (ts->source_port);
2211 udp->destination_port = reply->destination_port;
2212 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2213 GNUNET_TUN_calculate_udp6_checksum (ipv6,
2216 GNUNET_memcpy (&udp[1],
2219 (void) GNUNET_HELPER_send (helper_handle,
2229 GNUNET_CONTAINER_heap_update_cost (channel_heap,
2231 GNUNET_TIME_absolute_get ().abs_value_us);
2232 GNUNET_CADET_receive_done (channel);
2238 * We got a TCP packet back from the CADET channel. Pass it on to the
2239 * local virtual interface via the helper.
2241 * @param cls closure, NULL
2242 * @param channel connection to the other end
2243 * @param channel_ctx pointer to our `struct ChannelState *`
2244 * @param message the actual message
2245 * @return #GNUNET_OK to keep the connection open,
2246 * #GNUNET_SYSERR to close it (signal serious error)
2249 receive_tcp_back (void *cls,
2250 struct GNUNET_CADET_Channel *channel,
2252 const struct GNUNET_MessageHeader *message)
2254 struct ChannelState *ts = *channel_ctx;
2255 const struct GNUNET_EXIT_TcpDataMessage *data;
2258 GNUNET_STATISTICS_update (stats,
2259 gettext_noop ("# TCP packets received from cadet"),
2261 mlen = ntohs (message->size);
2262 if (mlen < sizeof (struct GNUNET_EXIT_TcpDataMessage))
2264 GNUNET_break_op (0);
2265 return GNUNET_SYSERR;
2267 if (NULL == ts->heap_node)
2269 GNUNET_break_op (0);
2270 return GNUNET_SYSERR;
2272 data = (const struct GNUNET_EXIT_TcpDataMessage *) message;
2273 mlen -= sizeof (struct GNUNET_EXIT_TcpDataMessage);
2275 char sbuf[INET6_ADDRSTRLEN];
2276 char dbuf[INET6_ADDRSTRLEN];
2278 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2279 "Received TCP reply from cadet, sending %u bytes from [%s]:%u -> [%s]:%u via TUN\n",
2280 (unsigned int) mlen,
2281 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2282 ts->destination_port,
2283 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2286 if (data->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
2288 GNUNET_break_op (0);
2289 return GNUNET_SYSERR;
2295 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2296 + sizeof (struct GNUNET_TUN_TcpHeader)
2297 + sizeof (struct GNUNET_MessageHeader) +
2298 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2301 char buf[size] GNUNET_ALIGN;
2302 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2303 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2304 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2305 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv4[1];
2306 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2307 msg->size = htons (size);
2308 tun->flags = htons (0);
2309 tun->proto = htons (ETH_P_IPV4);
2310 GNUNET_TUN_initialize_ipv4_header (ipv4,
2312 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2313 &ts->destination_ip.v4,
2315 *tcp = data->tcp_header;
2316 tcp->source_port = htons (ts->destination_port);
2317 tcp->destination_port = htons (ts->source_port);
2318 GNUNET_TUN_calculate_tcp4_checksum (ipv4,
2322 GNUNET_memcpy (&tcp[1],
2325 (void) GNUNET_HELPER_send (helper_handle,
2334 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2335 + sizeof (struct GNUNET_TUN_TcpHeader)
2336 + sizeof (struct GNUNET_MessageHeader) +
2337 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2340 char buf[size] GNUNET_ALIGN;
2341 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2342 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2343 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2344 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv6[1];
2345 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2346 msg->size = htons (size);
2347 tun->flags = htons (0);
2348 tun->proto = htons (ETH_P_IPV6);
2349 GNUNET_TUN_initialize_ipv6_header (ipv6,
2351 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2352 &ts->destination_ip.v6,
2354 *tcp = data->tcp_header;
2355 tcp->source_port = htons (ts->destination_port);
2356 tcp->destination_port = htons (ts->source_port);
2357 GNUNET_TUN_calculate_tcp6_checksum (ipv6,
2361 GNUNET_memcpy (&tcp[1],
2364 (void) GNUNET_HELPER_send (helper_handle,
2372 GNUNET_CONTAINER_heap_update_cost (channel_heap,
2374 GNUNET_TIME_absolute_get ().abs_value_us);
2375 GNUNET_CADET_receive_done (channel);
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 if (NULL != de->heap_node)
2519 GNUNET_CONTAINER_heap_remove_node (de->heap_node);
2520 de->heap_node = NULL;
2521 GNUNET_assert (GNUNET_YES ==
2522 GNUNET_CONTAINER_multihashmap_remove (destination_map,
2531 * We have too many active destinations. Clean up the oldest destination.
2533 * @param except destination that must NOT be cleaned up, even if it is the oldest
2536 expire_destination (struct DestinationEntry *except)
2538 struct DestinationEntry *de;
2540 de = GNUNET_CONTAINER_heap_peek (destination_heap);
2541 GNUNET_assert (NULL != de);
2543 return; /* can't do this */
2544 free_destination_entry (de);
2549 * Allocate an IP address for the response.
2551 * @param result_af desired address family; set to the actual
2552 * address family; can initially be AF_UNSPEC if there
2553 * is no preference; will be set to AF_UNSPEC if the
2555 * @param addr set to either v4 or v6 depending on which
2556 * storage location was used; set to NULL if allocation failed
2557 * @param v4 storage space for an IPv4 address
2558 * @param v6 storage space for an IPv6 address
2559 * @return #GNUNET_OK normally, #GNUNET_SYSERR if `* result_af` was
2560 * an unsupported address family (not AF_INET, AF_INET6 or AF_UNSPEC)
2563 allocate_response_ip (int *result_af,
2566 struct in6_addr *v6)
2573 allocate_v4_address (v4))
2574 *result_af = AF_UNSPEC;
2580 allocate_v6_address (v6))
2581 *result_af = AF_UNSPEC;
2587 allocate_v4_address (v4))
2590 *result_af = AF_INET;
2592 else if (GNUNET_OK ==
2593 allocate_v6_address (v6))
2596 *result_af = AF_INET6;
2601 return GNUNET_SYSERR;
2608 * A client asks us to setup a redirection via some exit node to a
2609 * particular IP. Setup the redirection and give the client the
2613 * @param client requesting client
2614 * @param message redirection request (a `struct RedirectToIpRequestMessage`)
2617 service_redirect_to_ip (void *cls,
2618 struct GNUNET_SERVER_Client *client,
2619 const struct GNUNET_MessageHeader *message)
2623 const struct RedirectToIpRequestMessage *msg;
2629 struct DestinationEntry *de;
2630 struct GNUNET_HashCode key;
2632 /* validate and parse request */
2633 mlen = ntohs (message->size);
2634 if (mlen < sizeof (struct RedirectToIpRequestMessage))
2637 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2640 alen = mlen - sizeof (struct RedirectToIpRequestMessage);
2641 msg = (const struct RedirectToIpRequestMessage *) message;
2642 addr_af = (int) htonl (msg->addr_af);
2646 if (alen != sizeof (struct in_addr))
2649 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2654 if (alen != sizeof (struct in6_addr))
2657 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2663 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2667 /* allocate response IP */
2668 result_af = (int) htonl (msg->result_af);
2669 if (GNUNET_OK != allocate_response_ip (&result_af,
2673 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2676 /* send reply with our IP address */
2677 send_client_reply (client,
2681 if (result_af == AF_UNSPEC)
2683 /* failure, we're done */
2684 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2689 char sbuf[INET6_ADDRSTRLEN];
2690 char dbuf[INET6_ADDRSTRLEN];
2692 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2693 "Allocated address %s for redirection via exit to %s\n",
2694 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2696 &msg[1], dbuf, sizeof (dbuf)));
2699 /* setup destination record */
2700 de = GNUNET_new (struct DestinationEntry);
2701 de->is_service = GNUNET_NO;
2702 de->details.exit_destination.af = addr_af;
2703 GNUNET_memcpy (&de->details.exit_destination.ip,
2706 get_destination_key_from_ip (result_af,
2710 GNUNET_assert (GNUNET_OK ==
2711 GNUNET_CONTAINER_multihashmap_put (destination_map,
2714 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2715 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2717 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value_us);
2718 GNUNET_STATISTICS_update (stats,
2719 gettext_noop ("# Active destinations"),
2721 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2722 expire_destination (de);
2723 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2728 * A client asks us to setup a redirection to a particular peer
2729 * offering a service. Setup the redirection and give the client the
2733 * @param client requesting client
2734 * @param message redirection request (a `struct RedirectToPeerRequestMessage`)
2737 service_redirect_to_service (void *cls,
2738 struct GNUNET_SERVER_Client *client,
2739 const struct GNUNET_MessageHeader *message)
2741 const struct RedirectToServiceRequestMessage *msg;
2746 struct DestinationEntry *de;
2747 struct GNUNET_HashCode key;
2748 struct DestinationChannel *dt;
2751 msg = (const struct RedirectToServiceRequestMessage *) message;
2753 /* allocate response IP */
2754 result_af = (int) htonl (msg->result_af);
2756 allocate_response_ip (&result_af,
2762 GNUNET_SERVER_receive_done (client,
2766 send_client_reply (client,
2770 if (result_af == AF_UNSPEC)
2772 /* failure, we're done */
2773 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2774 _("Failed to allocate IP address for new destination\n"));
2775 GNUNET_SERVER_receive_done (client,
2781 char sbuf[INET6_ADDRSTRLEN];
2783 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2784 "Allocated address %s for redirection to service %s on peer %s\n",
2785 inet_ntop (result_af,
2789 GNUNET_h2s (&msg->service_descriptor),
2790 GNUNET_i2s (&msg->target));
2793 /* setup destination record */
2794 de = GNUNET_new (struct DestinationEntry);
2795 de->is_service = GNUNET_YES;
2796 de->details.service_destination.target = msg->target;
2797 de->details.service_destination.service_descriptor = msg->service_descriptor;
2798 get_destination_key_from_ip (result_af,
2802 GNUNET_assert (GNUNET_OK ==
2803 GNUNET_CONTAINER_multihashmap_put (destination_map,
2806 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2808 = GNUNET_CONTAINER_heap_insert (destination_heap,
2810 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value_us);
2811 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2812 expire_destination (de);
2814 dt = GNUNET_new (struct DestinationChannel);
2815 dt->destination = de;
2816 GNUNET_CONTAINER_DLL_insert (de->dt_head,
2820 GNUNET_SERVER_receive_done (client,
2826 * Function called whenever a channel is destroyed. Should clean up
2827 * any associated state.
2829 * @param cls closure (set from #GNUNET_CADET_connect)
2830 * @param channel connection to the other end (henceforth invalid)
2831 * @param channel_ctx place where local state associated
2832 * with the channel is stored (our `struct ChannelState`)
2835 channel_cleaner (void *cls,
2836 const struct GNUNET_CADET_Channel *channel,
2839 struct ChannelState *ts = channel_ctx;
2841 ts->channel = NULL; /* we must not call GNUNET_CADET_channel_destroy() anymore */
2842 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2843 "CADET notified us about death of channel to `%s'\n",
2844 print_channel_destination (&ts->destination));
2845 free_channel_state (ts);
2850 * Free memory occupied by an entry in the destination map.
2854 * @param value a `struct DestinationEntry *`
2855 * @return #GNUNET_OK (continue to iterate)
2858 cleanup_destination (void *cls,
2859 const struct GNUNET_HashCode *key,
2862 struct DestinationEntry *de = value;
2864 free_destination_entry (de);
2870 * Free memory occupied by an entry in the channel map.
2874 * @param value a `struct ChannelState *`
2875 * @return #GNUNET_OK (continue to iterate)
2878 cleanup_channel (void *cls,
2879 const struct GNUNET_HashCode *key,
2882 struct ChannelState *ts = value;
2884 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2885 "Tearing down channel to `%s' during cleanup\n",
2886 print_channel_destination (&ts->destination));
2887 free_channel_state (ts);
2893 * Function scheduled as very last function, cleans up after us
2902 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2903 "VPN is shutting down\n");
2904 if (NULL != destination_map)
2906 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
2907 &cleanup_destination,
2909 GNUNET_CONTAINER_multihashmap_destroy (destination_map);
2910 destination_map = NULL;
2912 if (NULL != destination_heap)
2914 GNUNET_CONTAINER_heap_destroy (destination_heap);
2915 destination_heap = NULL;
2917 if (NULL != channel_map)
2919 GNUNET_CONTAINER_multihashmap_iterate (channel_map,
2922 GNUNET_CONTAINER_multihashmap_destroy (channel_map);
2925 if (NULL != channel_heap)
2927 GNUNET_CONTAINER_heap_destroy (channel_heap);
2928 channel_heap = NULL;
2930 if (NULL != cadet_handle)
2932 GNUNET_CADET_disconnect (cadet_handle);
2933 cadet_handle = NULL;
2935 if (NULL != helper_handle)
2937 GNUNET_HELPER_kill (helper_handle, GNUNET_NO);
2938 GNUNET_HELPER_wait (helper_handle);
2939 helper_handle = NULL;
2943 GNUNET_SERVER_notification_context_destroy (nc);
2948 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
2952 GNUNET_free_non_null (vpn_argv[i]);
2957 * Main function that will be run by the scheduler.
2959 * @param cls closure
2960 * @param server the initialized server
2961 * @param cfg_ configuration
2965 struct GNUNET_SERVER_Handle *server,
2966 const struct GNUNET_CONFIGURATION_Handle *cfg_)
2968 static const struct GNUNET_SERVER_MessageHandler service_handlers[] = {
2969 /* callback, cls, type, size */
2970 { &service_redirect_to_ip, NULL, GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP, 0},
2971 { &service_redirect_to_service, NULL,
2972 GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE,
2973 sizeof (struct RedirectToServiceRequestMessage) },
2976 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
2977 { &receive_udp_back, GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY, 0},
2978 { &receive_tcp_back, GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN, 0},
2979 { &receive_icmp_back, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN, 0},
2991 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-vpn");
2994 GNUNET_OS_check_helper_binary (binary,
2996 "-d gnunet-vpn - - 169.1.3.3.7 255.255.255.0")) //ipv4 only please!
2998 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2999 "`%s' is not SUID, refusing to run.\n",
3000 "gnunet-helper-vpn");
3001 GNUNET_free (binary);
3003 /* we won't "really" exit here, as the 'service' is still running;
3004 however, as no handlers are registered, the service won't do
3008 GNUNET_free (binary);
3010 stats = GNUNET_STATISTICS_create ("vpn", cfg);
3012 GNUNET_CONFIGURATION_get_value_number (cfg,
3015 &max_destination_mappings))
3016 max_destination_mappings = 200;
3018 GNUNET_CONFIGURATION_get_value_number (cfg,
3021 &max_channel_mappings))
3022 max_channel_mappings = 200;
3024 destination_map = GNUNET_CONTAINER_multihashmap_create (max_destination_mappings * 2, GNUNET_NO);
3025 destination_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3026 channel_map = GNUNET_CONTAINER_multihashmap_create (max_channel_mappings * 2, GNUNET_NO);
3027 channel_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3030 vpn_argv[0] = GNUNET_strdup ("vpn-gnunet");
3031 if (GNUNET_SYSERR ==
3032 GNUNET_CONFIGURATION_get_value_string (cfg, "VPN", "IFNAME", &ifname))
3034 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "VPN", "IFNAME");
3035 GNUNET_SCHEDULER_shutdown ();
3038 vpn_argv[1] = ifname;
3040 if (GNUNET_OK == GNUNET_NETWORK_test_pf (PF_INET6))
3042 if ( (GNUNET_SYSERR ==
3043 GNUNET_CONFIGURATION_get_value_string (cfg, "VPN", "IPV6ADDR",
3045 (1 != inet_pton (AF_INET6, ipv6addr, &v6))) )
3047 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV6ADDR",
3048 _("Must specify valid IPv6 address"));
3049 GNUNET_SCHEDULER_shutdown ();
3050 GNUNET_free_non_null (ipv6addr);
3053 vpn_argv[2] = ipv6addr;
3054 ipv6prefix_s = NULL;
3055 if (GNUNET_SYSERR ==
3056 GNUNET_CONFIGURATION_get_value_string (cfg, "VPN", "IPV6PREFIX",
3059 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV6PREFIX");
3060 GNUNET_SCHEDULER_shutdown ();
3061 GNUNET_free_non_null (ipv6prefix_s);
3064 vpn_argv[3] = ipv6prefix_s;
3066 GNUNET_CONFIGURATION_get_value_number (cfg, "VPN",
3069 (ipv6prefix >= 127) )
3071 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV4MASK",
3072 _("Must specify valid IPv6 mask"));
3073 GNUNET_SCHEDULER_shutdown ();
3079 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3080 _("IPv6 support disabled as this system does not support IPv6\n"));
3081 vpn_argv[2] = GNUNET_strdup ("-");
3082 vpn_argv[3] = GNUNET_strdup ("-");
3084 if (GNUNET_OK == GNUNET_NETWORK_test_pf (PF_INET))
3087 if ( (GNUNET_SYSERR ==
3088 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4ADDR",
3090 (1 != inet_pton (AF_INET, ipv4addr, &v4))) )
3092 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV4ADDR",
3093 _("Must specify valid IPv4 address"));
3094 GNUNET_SCHEDULER_shutdown ();
3095 GNUNET_free_non_null (ipv4addr);
3098 vpn_argv[4] = ipv4addr;
3100 if ( (GNUNET_SYSERR ==
3101 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4MASK",
3103 (1 != inet_pton (AF_INET, ipv4mask, &v4))) )
3105 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV4MASK",
3106 _("Must specify valid IPv4 mask"));
3107 GNUNET_SCHEDULER_shutdown ();
3108 GNUNET_free_non_null (ipv4mask);
3111 vpn_argv[5] = ipv4mask;
3115 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3116 _("IPv4 support disabled as this system does not support IPv4\n"));
3117 vpn_argv[4] = GNUNET_strdup ("-");
3118 vpn_argv[5] = GNUNET_strdup ("-");
3123 = GNUNET_CADET_connect (cfg_,
3127 // FIXME never opens ports???
3128 helper_handle = GNUNET_HELPER_start (GNUNET_NO,
3129 "gnunet-helper-vpn", vpn_argv,
3130 &message_token, NULL, NULL);
3131 nc = GNUNET_SERVER_notification_context_create (server, 1);
3132 GNUNET_SERVER_add_handlers (server, service_handlers);
3133 GNUNET_SCHEDULER_add_shutdown (&cleanup,
3139 * The main function of the VPN service.
3141 * @param argc number of arguments from the command line
3142 * @param argv command line arguments
3143 * @return 0 ok, 1 on error
3146 main (int argc, char *const *argv)
3148 return (GNUNET_OK ==
3149 GNUNET_SERVICE_run (argc, argv, "vpn",
3150 GNUNET_SERVICE_OPTION_NONE,
3151 &run, NULL)) ? global_ret : 1;
3154 /* end of gnunet-service-vpn.c */