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 '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], addr, rlen);
522 GNUNET_SERVER_notification_context_add (nc, client);
523 GNUNET_SERVER_notification_context_unicast (nc,
531 * Free resources associated with a channel state.
533 * @param ts state to free
536 free_channel_state (struct ChannelState *ts)
538 struct GNUNET_HashCode key;
539 struct ChannelMessageQueueEntry *tnq;
540 struct GNUNET_CADET_Channel *channel;
542 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
543 "Cleaning up channel state\n");
546 GNUNET_CADET_notify_transmit_ready_cancel (ts->th);
549 if (NULL != (channel = ts->channel))
552 GNUNET_CADET_channel_destroy (channel);
555 GNUNET_STATISTICS_update (stats,
556 gettext_noop ("# Active channels"),
558 while (NULL != (tnq = ts->tmq_head))
560 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
566 GNUNET_assert (0 == ts->tmq_length);
567 GNUNET_assert (NULL == ts->destination.heap_node);
568 if (NULL != ts->search)
570 GNUNET_REGEX_search_cancel (ts->search);
573 if (NULL != ts->heap_node)
575 GNUNET_CONTAINER_heap_remove_node (ts->heap_node);
576 ts->heap_node = NULL;
577 get_channel_key_from_ips (ts->af,
582 ts->destination_port,
584 GNUNET_assert (GNUNET_YES ==
585 GNUNET_CONTAINER_multihashmap_remove (channel_map,
594 * Send a message from the message queue via cadet.
596 * @param cls the `struct ChannelState` with the message queue
597 * @param size number of bytes available in @a buf
598 * @param buf where to copy the message
599 * @return number of bytes copied to @a buf
602 send_to_peer_notify_callback (void *cls, size_t size, void *buf)
604 struct ChannelState *ts = cls;
605 struct ChannelMessageQueueEntry *tnq;
612 GNUNET_assert (NULL != tnq);
613 GNUNET_assert (size >= tnq->len);
614 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
615 "Sending %u bytes via cadet channel\n",
616 (unsigned int) tnq->len);
617 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
621 GNUNET_memcpy (buf, tnq->msg, tnq->len);
624 if (NULL != (tnq = ts->tmq_head))
625 ts->th = GNUNET_CADET_notify_transmit_ready (ts->channel,
626 GNUNET_NO /* cork */,
627 GNUNET_TIME_UNIT_FOREVER_REL,
629 &send_to_peer_notify_callback,
631 GNUNET_STATISTICS_update (stats,
632 gettext_noop ("# Bytes given to cadet for transmission"),
639 * Add the given message to the given channel and trigger the
640 * transmission process.
642 * @param tnq message to queue
643 * @param ts channel to queue the message for
646 send_to_channel (struct ChannelMessageQueueEntry *tnq,
647 struct ChannelState *ts)
649 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
650 "Queueing %u bytes for transmission via cadet channel\n",
651 (unsigned int) tnq->len);
652 GNUNET_assert (NULL != ts->channel);
653 GNUNET_CONTAINER_DLL_insert_tail (ts->tmq_head,
657 if (ts->tmq_length > MAX_MESSAGE_QUEUE_SIZE)
659 struct ChannelMessageQueueEntry *dq;
662 GNUNET_assert (dq != tnq);
663 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
667 GNUNET_CADET_notify_transmit_ready_cancel (ts->th);
669 GNUNET_STATISTICS_update (stats,
670 gettext_noop ("# Bytes dropped in cadet queue (overflow)"),
676 ts->th = GNUNET_CADET_notify_transmit_ready (ts->channel,
677 GNUNET_NO /* cork */,
678 GNUNET_TIME_UNIT_FOREVER_REL,
680 &send_to_peer_notify_callback,
686 * Output destination of a channel for diagnostics.
688 * @param de destination to process
689 * @return diagnostic string describing destination
692 print_channel_destination (const struct DestinationEntry *de)
694 static char dest[256];
698 GNUNET_snprintf (dest,
701 GNUNET_i2s (&de->details.service_destination.target),
702 GNUNET_h2s (&de->details.service_destination.service_descriptor));
706 inet_ntop (de->details.exit_destination.af,
707 &de->details.exit_destination.ip,
716 * Regex has found a potential exit peer for us; consider using it.
718 * @param cls the `struct ChannelState`
719 * @param id Peer providing a regex that matches the string.
720 * @param get_path Path of the get request.
721 * @param get_path_length Lenght of @a get_path.
722 * @param put_path Path of the put request.
723 * @param put_path_length Length of the @a put_path.
726 handle_regex_result (void *cls,
727 const struct GNUNET_PeerIdentity *id,
728 const struct GNUNET_PeerIdentity *get_path,
729 unsigned int get_path_length,
730 const struct GNUNET_PeerIdentity *put_path,
731 unsigned int put_path_length)
733 struct ChannelState *ts = cls;
734 unsigned int apptype;
736 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
737 "Exit %s found for destination %s!\n",
739 print_channel_destination (&ts->destination));
740 GNUNET_REGEX_search_cancel (ts->search);
745 apptype = GNUNET_APPLICATION_TYPE_IPV4_GATEWAY;
748 apptype = GNUNET_APPLICATION_TYPE_IPV6_GATEWAY;
754 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
755 "Creating tunnel to %s for destination %s!\n",
757 print_channel_destination (&ts->destination));
758 ts->channel = GNUNET_CADET_channel_create (cadet_handle,
762 GNUNET_CADET_OPTION_DEFAULT);
767 * Initialize the given destination entry's cadet channel.
769 * @param dt destination channel for which we need to setup a channel
770 * @param client_af address family of the address returned to the client
771 * @return channel state of the channel that was created
773 static struct ChannelState *
774 create_channel_to_destination (struct DestinationChannel *dt,
777 struct ChannelState *ts;
778 unsigned int apptype;
780 GNUNET_STATISTICS_update (stats,
781 gettext_noop ("# Cadet channels created"),
786 apptype = GNUNET_APPLICATION_TYPE_IPV4_GATEWAY;
789 apptype = GNUNET_APPLICATION_TYPE_IPV6_GATEWAY;
795 ts = GNUNET_new (struct ChannelState);
797 ts->destination = *dt->destination;
798 ts->destination.heap_node = NULL; /* copy is NOT in destination heap */
799 if (dt->destination->is_service)
801 ts->channel = GNUNET_CADET_channel_create (cadet_handle,
803 &dt->destination->details.service_destination.target,
805 GNUNET_CADET_OPTION_DEFAULT);
806 if (NULL == ts->channel)
808 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
809 _("Failed to setup cadet channel!\n"));
813 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
814 "Creating channel %p to peer %s offering service %s\n",
816 GNUNET_i2s (&dt->destination->details.service_destination.target),
817 GNUNET_h2s (&dt->destination->details.service_destination.service_descriptor));
823 switch (dt->destination->details.exit_destination.af)
827 char address[GNUNET_TUN_IPV4_REGEXLEN];
829 GNUNET_TUN_ipv4toregexsearch (&dt->destination->details.exit_destination.ip.v4,
830 dt->destination_port,
832 GNUNET_asprintf (&policy,
834 GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
840 char address[GNUNET_TUN_IPV6_REGEXLEN];
842 GNUNET_TUN_ipv6toregexsearch (&dt->destination->details.exit_destination.ip.v6,
843 dt->destination_port,
845 GNUNET_asprintf (&policy,
847 GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
856 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
857 "Requesting connect by string: %s\n",
859 ts->search = GNUNET_REGEX_search (cfg,
861 &handle_regex_result,
863 GNUNET_free (policy);
870 * We have too many active channels. Clean up the oldest channel.
872 * @param except channel that must NOT be cleaned up, even if it is the oldest
875 expire_channel (struct ChannelState *except)
877 struct ChannelState *ts;
879 ts = GNUNET_CONTAINER_heap_peek (channel_heap);
880 GNUNET_assert (NULL != ts);
882 return; /* can't do this */
883 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
884 "Tearing down expired channel to %s\n",
885 print_channel_destination (&except->destination));
886 free_channel_state (ts);
891 * Route a packet via cadet to the given destination.
893 * @param destination description of the destination
894 * @param af address family on this end (AF_INET or AF_INET6)
895 * @param protocol IPPROTO_TCP or IPPROTO_UDP or IPPROTO_ICMP or IPPROTO_ICMPV6
896 * @param source_ip source IP used by the sender (struct in_addr or struct in6_addr)
897 * @param destination_ip destination IP used by the sender (struct in_addr or struct in6_addr)
898 * @param payload payload of the packet after the IP header
899 * @param payload_length number of bytes in @a payload
902 route_packet (struct DestinationEntry *destination,
905 const void *source_ip,
906 const void *destination_ip,
908 size_t payload_length)
910 struct GNUNET_HashCode key;
911 struct ChannelState *ts;
912 struct ChannelMessageQueueEntry *tnq;
915 const struct GNUNET_TUN_UdpHeader *udp;
916 const struct GNUNET_TUN_TcpHeader *tcp;
917 const struct GNUNET_TUN_IcmpHeader *icmp;
918 struct DestinationChannel *dt;
919 uint16_t source_port;
920 uint16_t destination_port;
926 if (payload_length < sizeof (struct GNUNET_TUN_UdpHeader))
932 tcp = NULL; /* make compiler happy */
933 icmp = NULL; /* make compiler happy */
935 if (udp->len < sizeof (struct GNUNET_TUN_UdpHeader))
940 source_port = ntohs (udp->source_port);
941 destination_port = ntohs (udp->destination_port);
942 get_channel_key_from_ips (af,
953 if (payload_length < sizeof (struct GNUNET_TUN_TcpHeader))
959 udp = NULL; /* make compiler happy */
960 icmp = NULL; /* make compiler happy */
962 if (tcp->off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
967 source_port = ntohs (tcp->source_port);
968 destination_port = ntohs (tcp->destination_port);
969 get_channel_key_from_ips (af,
981 if ( (AF_INET == af) ^ (protocol == IPPROTO_ICMP) )
986 if (payload_length < sizeof (struct GNUNET_TUN_IcmpHeader))
992 tcp = NULL; /* make compiler happy */
993 udp = NULL; /* make compiler happy */
996 destination_port = 0;
997 get_channel_key_from_ips (af,
1007 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1008 _("Protocol %u not supported, dropping\n"),
1009 (unsigned int) protocol);
1013 if (! destination->is_service)
1015 switch (destination->details.exit_destination.af)
1018 alen = sizeof (struct in_addr);
1021 alen = sizeof (struct in6_addr);
1028 char sbuf[INET6_ADDRSTRLEN];
1029 char dbuf[INET6_ADDRSTRLEN];
1030 char xbuf[INET6_ADDRSTRLEN];
1032 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1033 "Routing %s packet from [%s]:%u -> [%s]:%u to destination [%s]:%u\n",
1034 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
1035 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
1037 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
1039 inet_ntop (destination->details.exit_destination.af,
1040 &destination->details.exit_destination.ip,
1041 xbuf, sizeof (xbuf)),
1044 for (dt = destination->dt_head; NULL != dt; dt = dt->next)
1045 if (dt->destination_port == destination_port)
1051 char sbuf[INET6_ADDRSTRLEN];
1052 char dbuf[INET6_ADDRSTRLEN];
1054 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1055 "Routing %s packet from [%s]:%u -> [%s]:%u to service %s at peer %s\n",
1056 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
1057 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
1059 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
1061 GNUNET_h2s (&destination->details.service_destination.service_descriptor),
1062 GNUNET_i2s (&destination->details.service_destination.target));
1064 dt = destination->dt_head;
1068 dt = GNUNET_new (struct DestinationChannel);
1069 dt->destination = destination;
1070 GNUNET_CONTAINER_DLL_insert (destination->dt_head,
1071 destination->dt_tail,
1073 dt->destination_port = destination_port;
1076 /* see if we have an existing channel for this destination */
1077 ts = GNUNET_CONTAINER_multihashmap_get (channel_map,
1081 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1082 "Creating new channel for key %s\n",
1084 /* need to either use the existing channel from the destination (if still
1085 available) or create a fresh one */
1086 ts = create_channel_to_destination (dt, af);
1089 /* now bind existing "unbound" channel to our IP/port tuple */
1090 ts->protocol = protocol;
1094 ts->source_ip.v4 = * (const struct in_addr *) source_ip;
1095 ts->destination_ip.v4 = * (const struct in_addr *) destination_ip;
1099 ts->source_ip.v6 = * (const struct in6_addr *) source_ip;
1100 ts->destination_ip.v6 = * (const struct in6_addr *) destination_ip;
1102 ts->source_port = source_port;
1103 ts->destination_port = destination_port;
1104 ts->heap_node = GNUNET_CONTAINER_heap_insert (channel_heap,
1106 GNUNET_TIME_absolute_get ().abs_value_us);
1107 GNUNET_assert (GNUNET_YES ==
1108 GNUNET_CONTAINER_multihashmap_put (channel_map,
1111 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1112 GNUNET_STATISTICS_update (stats,
1113 gettext_noop ("# Active channels"),
1115 while (GNUNET_CONTAINER_multihashmap_size (channel_map) > max_channel_mappings)
1116 expire_channel (ts);
1120 GNUNET_CONTAINER_heap_update_cost (channel_heap,
1122 GNUNET_TIME_absolute_get ().abs_value_us);
1124 if (NULL == ts->channel)
1126 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1127 "Packet dropped, channel to %s not yet ready (%s)\n",
1128 print_channel_destination (&ts->destination),
1129 (NULL == ts->search)
1130 ? "EXIT search failed"
1131 : "EXIT search active");
1132 GNUNET_STATISTICS_update (stats,
1133 gettext_noop ("# Packets dropped (channel not yet online)"),
1139 /* send via channel */
1143 if (destination->is_service)
1145 struct GNUNET_EXIT_UdpServiceMessage *usm;
1147 mlen = sizeof (struct GNUNET_EXIT_UdpServiceMessage) +
1148 payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1149 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1154 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1157 usm = (struct GNUNET_EXIT_UdpServiceMessage *) &tnq[1];
1158 usm->header.size = htons ((uint16_t) mlen);
1159 usm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE);
1160 /* if the source port is below 32000, we assume it has a special
1161 meaning; if not, we pick a random port (this is a heuristic) */
1162 usm->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1163 usm->destination_port = udp->destination_port;
1164 usm->service_descriptor = destination->details.service_destination.service_descriptor;
1165 GNUNET_memcpy (&usm[1],
1167 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1171 struct GNUNET_EXIT_UdpInternetMessage *uim;
1172 struct in_addr *ip4dst;
1173 struct in6_addr *ip6dst;
1176 mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) +
1177 alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1178 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1183 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1186 uim = (struct GNUNET_EXIT_UdpInternetMessage *) &tnq[1];
1187 uim->header.size = htons ((uint16_t) mlen);
1188 uim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET);
1189 uim->af = htonl (destination->details.exit_destination.af);
1190 uim->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1191 uim->destination_port = udp->destination_port;
1192 switch (destination->details.exit_destination.af)
1195 ip4dst = (struct in_addr *) &uim[1];
1196 *ip4dst = destination->details.exit_destination.ip.v4;
1197 payload = &ip4dst[1];
1200 ip6dst = (struct in6_addr *) &uim[1];
1201 *ip6dst = destination->details.exit_destination.ip.v6;
1202 payload = &ip6dst[1];
1207 GNUNET_memcpy (payload,
1209 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1213 if (GNUNET_NO == ts->is_established)
1215 if (destination->is_service)
1217 struct GNUNET_EXIT_TcpServiceStartMessage *tsm;
1219 mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) +
1220 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1221 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1226 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1229 tsm = (struct GNUNET_EXIT_TcpServiceStartMessage *) &tnq[1];
1230 tsm->header.size = htons ((uint16_t) mlen);
1231 tsm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START);
1232 tsm->reserved = htonl (0);
1233 tsm->service_descriptor = destination->details.service_destination.service_descriptor;
1234 tsm->tcp_header = *tcp;
1235 GNUNET_memcpy (&tsm[1],
1237 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1241 struct GNUNET_EXIT_TcpInternetStartMessage *tim;
1242 struct in_addr *ip4dst;
1243 struct in6_addr *ip6dst;
1246 mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) +
1247 alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1248 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1253 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1256 tim = (struct GNUNET_EXIT_TcpInternetStartMessage *) &tnq[1];
1257 tim->header.size = htons ((uint16_t) mlen);
1258 tim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START);
1259 tim->af = htonl (destination->details.exit_destination.af);
1260 tim->tcp_header = *tcp;
1261 switch (destination->details.exit_destination.af)
1264 ip4dst = (struct in_addr *) &tim[1];
1265 *ip4dst = destination->details.exit_destination.ip.v4;
1266 payload = &ip4dst[1];
1269 ip6dst = (struct in6_addr *) &tim[1];
1270 *ip6dst = destination->details.exit_destination.ip.v6;
1271 payload = &ip6dst[1];
1276 GNUNET_memcpy (payload,
1278 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1283 struct GNUNET_EXIT_TcpDataMessage *tdm;
1285 mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) +
1286 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1287 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1292 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1295 tdm = (struct GNUNET_EXIT_TcpDataMessage *) &tnq[1];
1296 tdm->header.size = htons ((uint16_t) mlen);
1297 tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT);
1298 tdm->reserved = htonl (0);
1299 tdm->tcp_header = *tcp;
1300 GNUNET_memcpy (&tdm[1],
1302 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1306 case IPPROTO_ICMPV6:
1307 if (destination->is_service)
1309 struct GNUNET_EXIT_IcmpServiceMessage *ism;
1311 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1312 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1313 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1318 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1320 ism = (struct GNUNET_EXIT_IcmpServiceMessage *) &tnq[1];
1321 ism->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE);
1322 ism->af = htonl (af); /* need to tell destination ICMP protocol family! */
1323 ism->service_descriptor = destination->details.service_destination.service_descriptor;
1324 ism->icmp_header = *icmp;
1325 /* ICMP protocol translation will be done by the receiver (as we don't know
1326 the target AF); however, we still need to possibly discard the payload
1327 depending on the ICMP type */
1333 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1334 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1336 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1337 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1338 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1339 /* throw away ICMP payload, won't be useful for the other side anyway */
1340 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1343 GNUNET_STATISTICS_update (stats,
1344 gettext_noop ("# ICMPv4 packets dropped (not allowed)"),
1348 /* end of AF_INET */
1353 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1354 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1355 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1356 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1357 /* throw away ICMP payload, won't be useful for the other side anyway */
1358 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1360 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1361 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1364 GNUNET_STATISTICS_update (stats,
1365 gettext_noop ("# ICMPv6 packets dropped (not allowed)"),
1369 /* end of AF_INET6 */
1376 /* update length calculations, as payload_length may have changed */
1377 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1378 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1380 ism->header.size = htons ((uint16_t) mlen);
1381 /* finally, copy payload (if there is any left...) */
1382 GNUNET_memcpy (&ism[1],
1384 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1388 struct GNUNET_EXIT_IcmpInternetMessage *iim;
1389 struct in_addr *ip4dst;
1390 struct in6_addr *ip6dst;
1393 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1394 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1395 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1400 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1402 iim = (struct GNUNET_EXIT_IcmpInternetMessage *) &tnq[1];
1403 iim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET);
1404 iim->icmp_header = *icmp;
1405 /* Perform ICMP protocol-translation (depending on destination AF and source AF)
1406 and throw away ICMP payload depending on ICMP message type */
1412 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1413 if (destination->details.exit_destination.af == AF_INET6)
1414 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1416 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1417 if (destination->details.exit_destination.af == AF_INET6)
1418 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1420 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1421 if (destination->details.exit_destination.af == AF_INET6)
1422 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1423 /* throw away IP-payload, exit will have to make it up anyway */
1424 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1426 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1427 if (destination->details.exit_destination.af == AF_INET6)
1428 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1429 /* throw away IP-payload, exit will have to make it up anyway */
1430 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1432 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1433 if (destination->details.exit_destination.af == AF_INET6)
1435 GNUNET_STATISTICS_update (stats,
1436 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1441 /* throw away IP-payload, exit will have to make it up anyway */
1442 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1445 GNUNET_STATISTICS_update (stats,
1446 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1451 /* end of AF_INET */
1456 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1457 if (destination->details.exit_destination.af == AF_INET6)
1458 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1459 /* throw away IP-payload, exit will have to make it up anyway */
1460 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1462 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1463 if (destination->details.exit_destination.af == AF_INET)
1464 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1465 /* throw away IP-payload, exit will have to make it up anyway */
1466 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1468 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1469 if (destination->details.exit_destination.af == AF_INET)
1471 GNUNET_STATISTICS_update (stats,
1472 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1477 /* throw away IP-payload, exit will have to make it up anyway */
1478 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1480 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1481 if (destination->details.exit_destination.af == AF_INET)
1483 GNUNET_STATISTICS_update (stats,
1484 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1489 /* throw away IP-payload, exit will have to make it up anyway */
1490 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1492 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1493 if (destination->details.exit_destination.af == AF_INET)
1494 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1496 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1497 if (destination->details.exit_destination.af == AF_INET)
1498 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1501 GNUNET_STATISTICS_update (stats,
1502 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1507 /* end of AF_INET6 */
1512 /* update length calculations, as payload_length may have changed */
1513 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1514 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1516 iim->header.size = htons ((uint16_t) mlen);
1518 /* need to tell destination ICMP protocol family! */
1519 iim->af = htonl (destination->details.exit_destination.af);
1520 switch (destination->details.exit_destination.af)
1523 ip4dst = (struct in_addr *) &iim[1];
1524 *ip4dst = destination->details.exit_destination.ip.v4;
1525 payload = &ip4dst[1];
1528 ip6dst = (struct in6_addr *) &iim[1];
1529 *ip6dst = destination->details.exit_destination.ip.v6;
1530 payload = &ip6dst[1];
1535 GNUNET_memcpy (payload,
1537 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1541 /* not supported above, how can we get here !? */
1545 ts->is_established = GNUNET_YES;
1546 send_to_channel (tnq, ts);
1551 * Receive packets from the helper-process (someone send to the local
1552 * virtual channel interface). Find the destination mapping, and if it
1553 * exists, identify the correct CADET channel (or possibly create it)
1554 * and forward the packet.
1556 * @param cls closure, NULL
1557 * @param client NULL
1558 * @param message message we got from the client (VPN channel interface)
1561 message_token (void *cls,
1563 const struct GNUNET_MessageHeader *message)
1565 const struct GNUNET_TUN_Layer2PacketHeader *tun;
1567 struct GNUNET_HashCode key;
1568 struct DestinationEntry *de;
1570 GNUNET_STATISTICS_update (stats,
1571 gettext_noop ("# Packets received from TUN interface"),
1573 mlen = ntohs (message->size);
1574 if ( (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
1575 (mlen < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader)) )
1580 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1581 mlen -= (sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader));
1582 switch (ntohs (tun->proto))
1586 const struct GNUNET_TUN_IPv6Header *pkt6;
1588 if (mlen < sizeof (struct GNUNET_TUN_IPv6Header))
1594 pkt6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1595 get_destination_key_from_ip (AF_INET6,
1596 &pkt6->destination_address,
1598 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1601 char buf[INET6_ADDRSTRLEN];
1603 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1604 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1605 inet_ntop (AF_INET6,
1606 &pkt6->destination_address,
1614 &pkt6->source_address,
1615 &pkt6->destination_address,
1617 mlen - sizeof (struct GNUNET_TUN_IPv6Header));
1622 struct GNUNET_TUN_IPv4Header *pkt4;
1624 if (mlen < sizeof (struct GNUNET_TUN_IPv4Header))
1630 pkt4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1631 get_destination_key_from_ip (AF_INET,
1632 &pkt4->destination_address,
1634 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1637 char buf[INET_ADDRSTRLEN];
1639 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1640 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1642 &pkt4->destination_address,
1647 if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header))
1649 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1650 _("Received IPv4 packet with options (dropping it)\n"));
1656 &pkt4->source_address,
1657 &pkt4->destination_address,
1659 mlen - sizeof (struct GNUNET_TUN_IPv4Header));
1663 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1664 _("Received packet of unknown protocol %d from TUN (dropping it)\n"),
1665 (unsigned int) ntohs (tun->proto));
1673 * Synthesize a plausible ICMP payload for an ICMP error
1674 * response on the given channel.
1676 * @param ts channel information
1677 * @param ipp IPv4 header to fill in (ICMP payload)
1678 * @param udp "UDP" header to fill in (ICMP payload); might actually
1679 * also be the first 8 bytes of the TCP header
1682 make_up_icmpv4_payload (struct ChannelState *ts,
1683 struct GNUNET_TUN_IPv4Header *ipp,
1684 struct GNUNET_TUN_UdpHeader *udp)
1686 GNUNET_TUN_initialize_ipv4_header (ipp,
1688 sizeof (struct GNUNET_TUN_TcpHeader),
1690 &ts->destination_ip.v4);
1691 udp->source_port = htons (ts->source_port);
1692 udp->destination_port = htons (ts->destination_port);
1693 udp->len = htons (0);
1694 udp->crc = htons (0);
1699 * Synthesize a plausible ICMP payload for an ICMP error
1700 * response on the given channel.
1702 * @param ts channel information
1703 * @param ipp IPv6 header to fill in (ICMP payload)
1704 * @param udp "UDP" header to fill in (ICMP payload); might actually
1705 * also be the first 8 bytes of the TCP header
1708 make_up_icmpv6_payload (struct ChannelState *ts,
1709 struct GNUNET_TUN_IPv6Header *ipp,
1710 struct GNUNET_TUN_UdpHeader *udp)
1712 GNUNET_TUN_initialize_ipv6_header (ipp,
1714 sizeof (struct GNUNET_TUN_TcpHeader),
1716 &ts->destination_ip.v6);
1717 udp->source_port = htons (ts->source_port);
1718 udp->destination_port = htons (ts->destination_port);
1719 udp->len = htons (0);
1720 udp->crc = htons (0);
1725 * We got an ICMP packet back from the CADET channel. Pass it on to the
1726 * local virtual interface via the helper.
1728 * @param cls closure, NULL
1729 * @param channel connection to the other end
1730 * @param channel_ctx pointer to our 'struct ChannelState *'
1731 * @param message the actual message
1732 * @return #GNUNET_OK to keep the connection open,
1733 * #GNUNET_SYSERR to close it (signal serious error)
1736 receive_icmp_back (void *cls,
1737 struct GNUNET_CADET_Channel *channel,
1739 const struct GNUNET_MessageHeader *message)
1741 struct ChannelState *ts = *channel_ctx;
1742 const struct GNUNET_EXIT_IcmpToVPNMessage *i2v;
1745 GNUNET_STATISTICS_update (stats,
1746 gettext_noop ("# ICMP packets received from cadet"),
1748 mlen = ntohs (message->size);
1749 if (mlen < sizeof (struct GNUNET_EXIT_IcmpToVPNMessage))
1751 GNUNET_break_op (0);
1752 return GNUNET_SYSERR;
1754 if (NULL == ts->heap_node)
1756 GNUNET_break_op (0);
1757 return GNUNET_SYSERR;
1759 if (AF_UNSPEC == ts->af)
1761 GNUNET_break_op (0);
1762 return GNUNET_SYSERR;
1764 i2v = (const struct GNUNET_EXIT_IcmpToVPNMessage *) message;
1765 mlen -= sizeof (struct GNUNET_EXIT_IcmpToVPNMessage);
1767 char sbuf[INET6_ADDRSTRLEN];
1768 char dbuf[INET6_ADDRSTRLEN];
1770 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1771 "Received ICMP packet from cadet, sending %u bytes from %s -> %s via TUN\n",
1772 (unsigned int) mlen,
1773 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
1774 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)));
1780 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
1781 + sizeof (struct GNUNET_TUN_IcmpHeader)
1782 + sizeof (struct GNUNET_MessageHeader) +
1783 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1786 /* reserve some extra space in case we have an ICMP type here where
1787 we will need to make up the payload ourselves */
1788 char buf[size + sizeof (struct GNUNET_TUN_IPv4Header) + 8] GNUNET_ALIGN;
1789 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1790 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1791 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1792 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv4[1];
1793 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1794 tun->flags = htons (0);
1795 tun->proto = htons (ETH_P_IPV4);
1796 GNUNET_TUN_initialize_ipv4_header (ipv4,
1798 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1799 &ts->destination_ip.v4,
1801 *icmp = i2v->icmp_header;
1802 GNUNET_memcpy (&icmp[1],
1805 /* For some ICMP types, we need to adjust (make up) the payload here.
1806 Also, depending on the AF used on the other side, we have to
1807 do ICMP PT (translate ICMP types) */
1808 switch (ntohl (i2v->af))
1813 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1814 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1816 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1817 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1818 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1820 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1821 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1825 /* sender did not strip ICMP payload? */
1826 GNUNET_break_op (0);
1827 return GNUNET_SYSERR;
1829 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1830 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1831 make_up_icmpv4_payload (ts, ipp, udp);
1835 GNUNET_break_op (0);
1836 GNUNET_STATISTICS_update (stats,
1837 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1839 return GNUNET_SYSERR;
1844 /* ICMP PT 6-to-4 and possibly making up payloads */
1847 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1848 icmp->type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
1850 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1851 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1855 /* sender did not strip ICMP payload? */
1856 GNUNET_break_op (0);
1857 return GNUNET_SYSERR;
1859 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1860 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1861 make_up_icmpv4_payload (ts, ipp, udp);
1864 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1865 icmp->type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
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_PACKET_TOO_BIG:
1882 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1883 GNUNET_STATISTICS_update (stats,
1884 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1887 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1888 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1890 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1891 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1894 GNUNET_break_op (0);
1895 GNUNET_STATISTICS_update (stats,
1896 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1898 return GNUNET_SYSERR;
1903 GNUNET_break_op (0);
1904 return GNUNET_SYSERR;
1906 msg->size = htons (size);
1907 GNUNET_TUN_calculate_icmp_checksum (icmp,
1910 (void) GNUNET_HELPER_send (helper_handle,
1919 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
1920 + sizeof (struct GNUNET_TUN_IcmpHeader)
1921 + sizeof (struct GNUNET_MessageHeader) +
1922 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1925 char buf[size + sizeof (struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN;
1926 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1927 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1928 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
1929 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv6[1];
1930 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1931 tun->flags = htons (0);
1932 tun->proto = htons (ETH_P_IPV6);
1933 GNUNET_TUN_initialize_ipv6_header (ipv6,
1935 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1936 &ts->destination_ip.v6,
1938 *icmp = i2v->icmp_header;
1939 GNUNET_memcpy (&icmp[1],
1943 /* For some ICMP types, we need to adjust (make up) the payload here.
1944 Also, depending on the AF used on the other side, we have to
1945 do ICMP PT (translate ICMP types) */
1946 switch (ntohl (i2v->af))
1949 /* ICMP PT 4-to-6 and possibly making up payloads */
1952 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1953 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1955 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1956 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1958 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1959 icmp->type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1961 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1962 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1966 /* sender did not strip ICMP payload? */
1967 GNUNET_break_op (0);
1968 return GNUNET_SYSERR;
1970 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1971 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1972 make_up_icmpv6_payload (ts, ipp, udp);
1975 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1976 icmp->type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
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_SOURCE_QUENCH:
1993 GNUNET_STATISTICS_update (stats,
1994 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1998 GNUNET_break_op (0);
1999 GNUNET_STATISTICS_update (stats,
2000 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
2002 return GNUNET_SYSERR;
2009 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
2010 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
2011 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
2012 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
2014 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
2015 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
2019 /* sender did not strip ICMP payload? */
2020 GNUNET_break_op (0);
2021 return GNUNET_SYSERR;
2023 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
2024 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
2025 make_up_icmpv6_payload (ts, ipp, udp);
2028 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
2031 GNUNET_break_op (0);
2032 GNUNET_STATISTICS_update (stats,
2033 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
2035 return GNUNET_SYSERR;
2040 GNUNET_break_op (0);
2041 return GNUNET_SYSERR;
2043 msg->size = htons (size);
2044 GNUNET_TUN_calculate_icmp_checksum (icmp,
2046 (void) GNUNET_HELPER_send (helper_handle,
2056 GNUNET_CONTAINER_heap_update_cost (channel_heap,
2058 GNUNET_TIME_absolute_get ().abs_value_us);
2059 GNUNET_CADET_receive_done (channel);
2065 * We got a UDP packet back from the CADET channel. Pass it on to the
2066 * local virtual interface via the helper.
2068 * @param cls closure, NULL
2069 * @param channel connection to the other end
2070 * @param channel_ctx pointer to our 'struct ChannelState *'
2071 * @param message the actual message
2072 * @return #GNUNET_OK to keep the connection open,
2073 * #GNUNET_SYSERR to close it (signal serious error)
2076 receive_udp_back (void *cls,
2077 struct GNUNET_CADET_Channel *channel,
2079 const struct GNUNET_MessageHeader *message)
2081 struct ChannelState *ts = *channel_ctx;
2082 const struct GNUNET_EXIT_UdpReplyMessage *reply;
2085 GNUNET_STATISTICS_update (stats,
2086 gettext_noop ("# UDP packets received from cadet"),
2088 mlen = ntohs (message->size);
2089 if (mlen < sizeof (struct GNUNET_EXIT_UdpReplyMessage))
2091 GNUNET_break_op (0);
2092 return GNUNET_SYSERR;
2094 if (NULL == ts->heap_node)
2096 GNUNET_break_op (0);
2097 return GNUNET_SYSERR;
2099 if (AF_UNSPEC == ts->af)
2101 GNUNET_break_op (0);
2102 return GNUNET_SYSERR;
2104 reply = (const struct GNUNET_EXIT_UdpReplyMessage *) message;
2105 mlen -= sizeof (struct GNUNET_EXIT_UdpReplyMessage);
2107 char sbuf[INET6_ADDRSTRLEN];
2108 char dbuf[INET6_ADDRSTRLEN];
2110 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2111 "Received UDP reply from cadet, sending %u bytes from [%s]:%u -> [%s]:%u via TUN\n",
2112 (unsigned int) mlen,
2113 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2114 ts->destination_port,
2115 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2122 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2123 + sizeof (struct GNUNET_TUN_UdpHeader)
2124 + sizeof (struct GNUNET_MessageHeader) +
2125 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2128 char buf[size] GNUNET_ALIGN;
2129 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2130 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2131 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2132 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1];
2133 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2134 msg->size = htons (size);
2135 tun->flags = htons (0);
2136 tun->proto = htons (ETH_P_IPV4);
2137 GNUNET_TUN_initialize_ipv4_header (ipv4,
2139 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2140 &ts->destination_ip.v4,
2142 if (0 == ntohs (reply->source_port))
2143 udp->source_port = htons (ts->destination_port);
2145 udp->source_port = reply->source_port;
2146 if (0 == ntohs (reply->destination_port))
2147 udp->destination_port = htons (ts->source_port);
2149 udp->destination_port = reply->destination_port;
2150 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2151 GNUNET_TUN_calculate_udp4_checksum (ipv4,
2155 GNUNET_memcpy (&udp[1],
2158 (void) GNUNET_HELPER_send (helper_handle,
2167 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2168 + sizeof (struct GNUNET_TUN_UdpHeader)
2169 + sizeof (struct GNUNET_MessageHeader) +
2170 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2173 char buf[size] GNUNET_ALIGN;
2174 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2175 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2176 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2177 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1];
2178 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2179 msg->size = htons (size);
2180 tun->flags = htons (0);
2181 tun->proto = htons (ETH_P_IPV6);
2182 GNUNET_TUN_initialize_ipv6_header (ipv6,
2184 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2185 &ts->destination_ip.v6,
2187 if (0 == ntohs (reply->source_port))
2188 udp->source_port = htons (ts->destination_port);
2190 udp->source_port = reply->source_port;
2191 if (0 == ntohs (reply->destination_port))
2192 udp->destination_port = htons (ts->source_port);
2194 udp->destination_port = reply->destination_port;
2195 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2196 GNUNET_TUN_calculate_udp6_checksum (ipv6,
2199 GNUNET_memcpy (&udp[1],
2202 (void) GNUNET_HELPER_send (helper_handle,
2212 GNUNET_CONTAINER_heap_update_cost (channel_heap,
2214 GNUNET_TIME_absolute_get ().abs_value_us);
2215 GNUNET_CADET_receive_done (channel);
2221 * We got a TCP packet back from the CADET channel. Pass it on to the
2222 * local virtual interface via the helper.
2224 * @param cls closure, NULL
2225 * @param channel connection to the other end
2226 * @param channel_ctx pointer to our `struct ChannelState *`
2227 * @param message the actual message
2228 * @return #GNUNET_OK to keep the connection open,
2229 * #GNUNET_SYSERR to close it (signal serious error)
2232 receive_tcp_back (void *cls,
2233 struct GNUNET_CADET_Channel *channel,
2235 const struct GNUNET_MessageHeader *message)
2237 struct ChannelState *ts = *channel_ctx;
2238 const struct GNUNET_EXIT_TcpDataMessage *data;
2241 GNUNET_STATISTICS_update (stats,
2242 gettext_noop ("# TCP packets received from cadet"),
2244 mlen = ntohs (message->size);
2245 if (mlen < sizeof (struct GNUNET_EXIT_TcpDataMessage))
2247 GNUNET_break_op (0);
2248 return GNUNET_SYSERR;
2250 if (NULL == ts->heap_node)
2252 GNUNET_break_op (0);
2253 return GNUNET_SYSERR;
2255 data = (const struct GNUNET_EXIT_TcpDataMessage *) message;
2256 mlen -= sizeof (struct GNUNET_EXIT_TcpDataMessage);
2258 char sbuf[INET6_ADDRSTRLEN];
2259 char dbuf[INET6_ADDRSTRLEN];
2261 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2262 "Received TCP reply from cadet, sending %u bytes from [%s]:%u -> [%s]:%u via TUN\n",
2263 (unsigned int) mlen,
2264 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2265 ts->destination_port,
2266 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2269 if (data->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
2271 GNUNET_break_op (0);
2272 return GNUNET_SYSERR;
2278 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2279 + sizeof (struct GNUNET_TUN_TcpHeader)
2280 + sizeof (struct GNUNET_MessageHeader) +
2281 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2284 char buf[size] GNUNET_ALIGN;
2285 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2286 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2287 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2288 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv4[1];
2289 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2290 msg->size = htons (size);
2291 tun->flags = htons (0);
2292 tun->proto = htons (ETH_P_IPV4);
2293 GNUNET_TUN_initialize_ipv4_header (ipv4,
2295 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2296 &ts->destination_ip.v4,
2298 *tcp = data->tcp_header;
2299 tcp->source_port = htons (ts->destination_port);
2300 tcp->destination_port = htons (ts->source_port);
2301 GNUNET_TUN_calculate_tcp4_checksum (ipv4,
2305 GNUNET_memcpy (&tcp[1],
2308 (void) GNUNET_HELPER_send (helper_handle,
2317 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2318 + sizeof (struct GNUNET_TUN_TcpHeader)
2319 + sizeof (struct GNUNET_MessageHeader) +
2320 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2323 char buf[size] GNUNET_ALIGN;
2324 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2325 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2326 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2327 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv6[1];
2328 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2329 msg->size = htons (size);
2330 tun->flags = htons (0);
2331 tun->proto = htons (ETH_P_IPV6);
2332 GNUNET_TUN_initialize_ipv6_header (ipv6,
2334 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2335 &ts->destination_ip.v6,
2337 *tcp = data->tcp_header;
2338 tcp->source_port = htons (ts->destination_port);
2339 tcp->destination_port = htons (ts->source_port);
2340 GNUNET_TUN_calculate_tcp6_checksum (ipv6,
2344 GNUNET_memcpy (&tcp[1],
2347 (void) GNUNET_HELPER_send (helper_handle,
2355 GNUNET_CONTAINER_heap_update_cost (channel_heap,
2357 GNUNET_TIME_absolute_get ().abs_value_us);
2358 GNUNET_CADET_receive_done (channel);
2364 * Allocate an IPv4 address from the range of the channel
2365 * for a new redirection.
2367 * @param v4 where to store the address
2368 * @return #GNUNET_OK on success,
2369 * #GNUNET_SYSERR on error
2372 allocate_v4_address (struct in_addr *v4)
2374 const char *ipv4addr = vpn_argv[4];
2375 const char *ipv4mask = vpn_argv[5];
2376 struct in_addr addr;
2377 struct in_addr mask;
2379 struct GNUNET_HashCode key;
2382 GNUNET_assert (1 == inet_pton (AF_INET, ipv4addr, &addr));
2383 GNUNET_assert (1 == inet_pton (AF_INET, ipv4mask, &mask));
2384 /* Given 192.168.0.1/255.255.0.0, we want a mask
2385 of '192.168.255.255', thus: */
2386 mask.s_addr = addr.s_addr | ~mask.s_addr;
2393 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2394 _("Failed to find unallocated IPv4 address in VPN's range\n"));
2395 return GNUNET_SYSERR;
2397 /* Pick random IPv4 address within the subnet, except 'addr' or 'mask' itself */
2398 rnd.s_addr = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2400 v4->s_addr = (addr.s_addr | rnd.s_addr) & mask.s_addr;
2401 get_destination_key_from_ip (AF_INET,
2405 while ( (GNUNET_YES ==
2406 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2408 (v4->s_addr == addr.s_addr) ||
2409 (v4->s_addr == mask.s_addr) );
2415 * Allocate an IPv6 address from the range of the channel
2416 * for a new redirection.
2418 * @param v6 where to store the address
2419 * @return #GNUNET_OK on success,
2420 * #GNUNET_SYSERR on error
2423 allocate_v6_address (struct in6_addr *v6)
2425 const char *ipv6addr = vpn_argv[2];
2426 struct in6_addr addr;
2427 struct in6_addr mask;
2428 struct in6_addr rnd;
2430 struct GNUNET_HashCode key;
2433 GNUNET_assert (1 == inet_pton (AF_INET6, ipv6addr, &addr));
2434 GNUNET_assert (ipv6prefix < 128);
2435 /* Given ABCD::/96, we want a mask of 'ABCD::FFFF:FFFF,
2438 for (i=127;i>=ipv6prefix;i--)
2439 mask.s6_addr[i / 8] |= (1 << (i % 8));
2441 /* Pick random IPv6 address within the subnet, except 'addr' or 'mask' itself */
2448 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2449 _("Failed to find unallocated IPv6 address in VPN's range\n"));
2450 return GNUNET_SYSERR;
2455 rnd.s6_addr[i] = (unsigned char) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2458 = (addr.s6_addr[i] | rnd.s6_addr[i]) & mask.s6_addr[i];
2460 get_destination_key_from_ip (AF_INET6,
2464 while ( (GNUNET_YES ==
2465 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2469 sizeof (struct in6_addr))) ||
2472 sizeof (struct in6_addr))) );
2478 * Free resources occupied by a destination entry.
2480 * @param de entry to free
2483 free_destination_entry (struct DestinationEntry *de)
2485 struct DestinationChannel *dt;
2487 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2488 "Cleaning up destination entry `%s'\n",
2489 print_channel_destination (de));
2490 GNUNET_STATISTICS_update (stats,
2491 gettext_noop ("# Active destinations"),
2493 while (NULL != (dt = de->dt_head))
2495 GNUNET_CONTAINER_DLL_remove (de->dt_head,
2500 if (NULL != de->heap_node)
2502 GNUNET_CONTAINER_heap_remove_node (de->heap_node);
2503 de->heap_node = NULL;
2504 GNUNET_assert (GNUNET_YES ==
2505 GNUNET_CONTAINER_multihashmap_remove (destination_map,
2514 * We have too many active destinations. Clean up the oldest destination.
2516 * @param except destination that must NOT be cleaned up, even if it is the oldest
2519 expire_destination (struct DestinationEntry *except)
2521 struct DestinationEntry *de;
2523 de = GNUNET_CONTAINER_heap_peek (destination_heap);
2524 GNUNET_assert (NULL != de);
2526 return; /* can't do this */
2527 free_destination_entry (de);
2532 * Allocate an IP address for the response.
2534 * @param result_af desired address family; set to the actual
2535 * address family; can initially be AF_UNSPEC if there
2536 * is no preference; will be set to AF_UNSPEC if the
2538 * @param addr set to either v4 or v6 depending on which
2539 * storage location was used; set to NULL if allocation failed
2540 * @param v4 storage space for an IPv4 address
2541 * @param v6 storage space for an IPv6 address
2542 * @return #GNUNET_OK normally, #GNUNET_SYSERR if `* result_af` was
2543 * an unsupported address family (not AF_INET, AF_INET6 or AF_UNSPEC)
2546 allocate_response_ip (int *result_af,
2549 struct in6_addr *v6)
2556 allocate_v4_address (v4))
2557 *result_af = AF_UNSPEC;
2563 allocate_v6_address (v6))
2564 *result_af = AF_UNSPEC;
2570 allocate_v4_address (v4))
2573 *result_af = AF_INET;
2575 else if (GNUNET_OK ==
2576 allocate_v6_address (v6))
2579 *result_af = AF_INET6;
2584 return GNUNET_SYSERR;
2591 * A client asks us to setup a redirection via some exit node to a
2592 * particular IP. Setup the redirection and give the client the
2596 * @param client requesting client
2597 * @param message redirection request (a `struct RedirectToIpRequestMessage`)
2600 service_redirect_to_ip (void *cls,
2601 struct GNUNET_SERVER_Client *client,
2602 const struct GNUNET_MessageHeader *message)
2606 const struct RedirectToIpRequestMessage *msg;
2612 struct DestinationEntry *de;
2613 struct GNUNET_HashCode key;
2615 /* validate and parse request */
2616 mlen = ntohs (message->size);
2617 if (mlen < sizeof (struct RedirectToIpRequestMessage))
2620 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2623 alen = mlen - sizeof (struct RedirectToIpRequestMessage);
2624 msg = (const struct RedirectToIpRequestMessage *) message;
2625 addr_af = (int) htonl (msg->addr_af);
2629 if (alen != sizeof (struct in_addr))
2632 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2637 if (alen != sizeof (struct in6_addr))
2640 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2646 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2650 /* allocate response IP */
2651 result_af = (int) htonl (msg->result_af);
2652 if (GNUNET_OK != allocate_response_ip (&result_af,
2656 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2659 /* send reply with our IP address */
2660 send_client_reply (client,
2664 if (result_af == AF_UNSPEC)
2666 /* failure, we're done */
2667 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2672 char sbuf[INET6_ADDRSTRLEN];
2673 char dbuf[INET6_ADDRSTRLEN];
2675 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2676 "Allocated address %s for redirection via exit to %s\n",
2677 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2679 &msg[1], dbuf, sizeof (dbuf)));
2682 /* setup destination record */
2683 de = GNUNET_new (struct DestinationEntry);
2684 de->is_service = GNUNET_NO;
2685 de->details.exit_destination.af = addr_af;
2686 GNUNET_memcpy (&de->details.exit_destination.ip,
2689 get_destination_key_from_ip (result_af,
2693 GNUNET_assert (GNUNET_OK ==
2694 GNUNET_CONTAINER_multihashmap_put (destination_map,
2697 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2698 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2700 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value_us);
2701 GNUNET_STATISTICS_update (stats,
2702 gettext_noop ("# Active destinations"),
2704 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2705 expire_destination (de);
2706 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2711 * A client asks us to setup a redirection to a particular peer
2712 * offering a service. Setup the redirection and give the client the
2716 * @param client requesting client
2717 * @param message redirection request (a `struct RedirectToPeerRequestMessage`)
2720 service_redirect_to_service (void *cls,
2721 struct GNUNET_SERVER_Client *client,
2722 const struct GNUNET_MessageHeader *message)
2724 const struct RedirectToServiceRequestMessage *msg;
2729 struct DestinationEntry *de;
2730 struct GNUNET_HashCode key;
2731 struct DestinationChannel *dt;
2734 msg = (const struct RedirectToServiceRequestMessage *) message;
2736 /* allocate response IP */
2737 result_af = (int) htonl (msg->result_af);
2738 if (GNUNET_OK != allocate_response_ip (&result_af,
2742 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2745 send_client_reply (client,
2749 if (result_af == AF_UNSPEC)
2751 /* failure, we're done */
2752 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2753 _("Failed to allocate IP address for new destination\n"));
2754 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2759 char sbuf[INET6_ADDRSTRLEN];
2761 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2762 "Allocated address %s for redirection to service %s on peer %s\n",
2763 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2764 GNUNET_h2s (&msg->service_descriptor),
2765 GNUNET_i2s (&msg->target));
2768 /* setup destination record */
2769 de = GNUNET_new (struct DestinationEntry);
2770 de->is_service = GNUNET_YES;
2771 de->details.service_destination.service_descriptor = msg->service_descriptor;
2772 de->details.service_destination.target = msg->target;
2773 get_destination_key_from_ip (result_af,
2777 GNUNET_assert (GNUNET_OK ==
2778 GNUNET_CONTAINER_multihashmap_put (destination_map,
2781 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2782 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2784 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value_us);
2785 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2786 expire_destination (de);
2788 dt = GNUNET_new (struct DestinationChannel);
2789 dt->destination = de;
2790 GNUNET_CONTAINER_DLL_insert (de->dt_head,
2794 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2799 * Function called whenever a channel is destroyed. Should clean up
2800 * any associated state.
2802 * @param cls closure (set from #GNUNET_CADET_connect)
2803 * @param channel connection to the other end (henceforth invalid)
2804 * @param channel_ctx place where local state associated
2805 * with the channel is stored (our `struct ChannelState`)
2808 channel_cleaner (void *cls,
2809 const struct GNUNET_CADET_Channel *channel,
2812 struct ChannelState *ts = channel_ctx;
2814 ts->channel = NULL; /* we must not call GNUNET_CADET_channel_destroy() anymore */
2815 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2816 "CADET notified us about death of channel to `%s'\n",
2817 print_channel_destination (&ts->destination));
2818 free_channel_state (ts);
2823 * Free memory occupied by an entry in the destination map.
2827 * @param value a `struct DestinationEntry *`
2828 * @return #GNUNET_OK (continue to iterate)
2831 cleanup_destination (void *cls,
2832 const struct GNUNET_HashCode *key,
2835 struct DestinationEntry *de = value;
2837 free_destination_entry (de);
2843 * Free memory occupied by an entry in the channel map.
2847 * @param value a `struct ChannelState *`
2848 * @return #GNUNET_OK (continue to iterate)
2851 cleanup_channel (void *cls,
2852 const struct GNUNET_HashCode *key,
2855 struct ChannelState *ts = value;
2857 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2858 "Tearing down channel to `%s' during cleanup\n",
2859 print_channel_destination (&ts->destination));
2860 free_channel_state (ts);
2866 * Function scheduled as very last function, cleans up after us
2875 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2876 "VPN is shutting down\n");
2877 if (NULL != destination_map)
2879 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
2880 &cleanup_destination,
2882 GNUNET_CONTAINER_multihashmap_destroy (destination_map);
2883 destination_map = NULL;
2885 if (NULL != destination_heap)
2887 GNUNET_CONTAINER_heap_destroy (destination_heap);
2888 destination_heap = NULL;
2890 if (NULL != channel_map)
2892 GNUNET_CONTAINER_multihashmap_iterate (channel_map,
2895 GNUNET_CONTAINER_multihashmap_destroy (channel_map);
2898 if (NULL != channel_heap)
2900 GNUNET_CONTAINER_heap_destroy (channel_heap);
2901 channel_heap = NULL;
2903 if (NULL != cadet_handle)
2905 GNUNET_CADET_disconnect (cadet_handle);
2906 cadet_handle = NULL;
2908 if (NULL != helper_handle)
2910 GNUNET_HELPER_kill (helper_handle, GNUNET_NO);
2911 GNUNET_HELPER_wait (helper_handle);
2912 helper_handle = NULL;
2916 GNUNET_SERVER_notification_context_destroy (nc);
2921 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
2925 GNUNET_free_non_null (vpn_argv[i]);
2930 * Main function that will be run by the scheduler.
2932 * @param cls closure
2933 * @param server the initialized server
2934 * @param cfg_ configuration
2938 struct GNUNET_SERVER_Handle *server,
2939 const struct GNUNET_CONFIGURATION_Handle *cfg_)
2941 static const struct GNUNET_SERVER_MessageHandler service_handlers[] = {
2942 /* callback, cls, type, size */
2943 { &service_redirect_to_ip, NULL, GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP, 0},
2944 { &service_redirect_to_service, NULL,
2945 GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE,
2946 sizeof (struct RedirectToServiceRequestMessage) },
2949 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
2950 { &receive_udp_back, GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY, 0},
2951 { &receive_tcp_back, GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN, 0},
2952 { &receive_icmp_back, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN, 0},
2964 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-vpn");
2967 GNUNET_OS_check_helper_binary (binary,
2969 "-d gnunet-vpn - - 169.1.3.3.7 255.255.255.0")) //ipv4 only please!
2971 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2972 "`%s' is not SUID, refusing to run.\n",
2973 "gnunet-helper-vpn");
2974 GNUNET_free (binary);
2976 /* we won't "really" exit here, as the 'service' is still running;
2977 however, as no handlers are registered, the service won't do
2981 GNUNET_free (binary);
2983 stats = GNUNET_STATISTICS_create ("vpn", cfg);
2985 GNUNET_CONFIGURATION_get_value_number (cfg, "VPN", "MAX_MAPPING",
2986 &max_destination_mappings))
2987 max_destination_mappings = 200;
2989 GNUNET_CONFIGURATION_get_value_number (cfg, "VPN", "MAX_TUNNELS",
2990 &max_channel_mappings))
2991 max_channel_mappings = 200;
2993 destination_map = GNUNET_CONTAINER_multihashmap_create (max_destination_mappings * 2, GNUNET_NO);
2994 destination_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
2995 channel_map = GNUNET_CONTAINER_multihashmap_create (max_channel_mappings * 2, GNUNET_NO);
2996 channel_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
2999 vpn_argv[0] = GNUNET_strdup ("vpn-gnunet");
3000 if (GNUNET_SYSERR ==
3001 GNUNET_CONFIGURATION_get_value_string (cfg, "VPN", "IFNAME", &ifname))
3003 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "VPN", "IFNAME");
3004 GNUNET_SCHEDULER_shutdown ();
3007 vpn_argv[1] = ifname;
3009 if (GNUNET_OK == GNUNET_NETWORK_test_pf (PF_INET6))
3011 if ( (GNUNET_SYSERR ==
3012 GNUNET_CONFIGURATION_get_value_string (cfg, "VPN", "IPV6ADDR",
3014 (1 != inet_pton (AF_INET6, ipv6addr, &v6))) )
3016 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV6ADDR",
3017 _("Must specify valid IPv6 address"));
3018 GNUNET_SCHEDULER_shutdown ();
3019 GNUNET_free_non_null (ipv6addr);
3022 vpn_argv[2] = ipv6addr;
3023 ipv6prefix_s = NULL;
3024 if (GNUNET_SYSERR ==
3025 GNUNET_CONFIGURATION_get_value_string (cfg, "VPN", "IPV6PREFIX",
3028 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV6PREFIX");
3029 GNUNET_SCHEDULER_shutdown ();
3030 GNUNET_free_non_null (ipv6prefix_s);
3033 vpn_argv[3] = ipv6prefix_s;
3035 GNUNET_CONFIGURATION_get_value_number (cfg, "VPN",
3038 (ipv6prefix >= 127) )
3040 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV4MASK",
3041 _("Must specify valid IPv6 mask"));
3042 GNUNET_SCHEDULER_shutdown ();
3048 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3049 _("IPv6 support disabled as this system does not support IPv6\n"));
3050 vpn_argv[2] = GNUNET_strdup ("-");
3051 vpn_argv[3] = GNUNET_strdup ("-");
3053 if (GNUNET_OK == GNUNET_NETWORK_test_pf (PF_INET))
3056 if ( (GNUNET_SYSERR ==
3057 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4ADDR",
3059 (1 != inet_pton (AF_INET, ipv4addr, &v4))) )
3061 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV4ADDR",
3062 _("Must specify valid IPv4 address"));
3063 GNUNET_SCHEDULER_shutdown ();
3064 GNUNET_free_non_null (ipv4addr);
3067 vpn_argv[4] = ipv4addr;
3069 if ( (GNUNET_SYSERR ==
3070 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4MASK",
3072 (1 != inet_pton (AF_INET, ipv4mask, &v4))) )
3074 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV4MASK",
3075 _("Must specify valid IPv4 mask"));
3076 GNUNET_SCHEDULER_shutdown ();
3077 GNUNET_free_non_null (ipv4mask);
3080 vpn_argv[5] = ipv4mask;
3084 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3085 _("IPv4 support disabled as this system does not support IPv4\n"));
3086 vpn_argv[4] = GNUNET_strdup ("-");
3087 vpn_argv[5] = GNUNET_strdup ("-");
3092 GNUNET_CADET_connect (cfg_, NULL,
3097 helper_handle = GNUNET_HELPER_start (GNUNET_NO,
3098 "gnunet-helper-vpn", vpn_argv,
3099 &message_token, NULL, NULL);
3100 nc = GNUNET_SERVER_notification_context_create (server, 1);
3101 GNUNET_SERVER_add_handlers (server, service_handlers);
3102 GNUNET_SCHEDULER_add_shutdown (&cleanup,
3108 * The main function of the VPN service.
3110 * @param argc number of arguments from the command line
3111 * @param argv command line arguments
3112 * @return 0 ok, 1 on error
3115 main (int argc, char *const *argv)
3117 return (GNUNET_OK ==
3118 GNUNET_SERVICE_run (argc, argv, "vpn",
3119 GNUNET_SERVICE_OPTION_NONE,
3120 &run, NULL)) ? global_ret : 1;
3123 /* end of gnunet-service-vpn.c */