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))
627 ts->th = GNUNET_CADET_notify_transmit_ready (ts->channel,
628 GNUNET_NO /* cork */,
629 GNUNET_TIME_UNIT_FOREVER_REL,
631 &send_to_peer_notify_callback,
634 GNUNET_STATISTICS_update (stats,
635 gettext_noop ("# Bytes given to cadet for transmission"),
642 * Add the given message to the given channel and trigger the
643 * transmission process.
645 * @param tnq message to queue
646 * @param ts channel to queue the message for
649 send_to_channel (struct ChannelMessageQueueEntry *tnq,
650 struct ChannelState *ts)
652 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
653 "Queueing %u bytes for transmission via cadet channel\n",
654 (unsigned int) tnq->len);
655 GNUNET_assert (NULL != ts->channel);
656 GNUNET_CONTAINER_DLL_insert_tail (ts->tmq_head,
660 if (ts->tmq_length > MAX_MESSAGE_QUEUE_SIZE)
662 struct ChannelMessageQueueEntry *dq;
665 GNUNET_assert (dq != tnq);
666 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
670 GNUNET_CADET_notify_transmit_ready_cancel (ts->th);
672 GNUNET_STATISTICS_update (stats,
673 gettext_noop ("# Bytes dropped in cadet queue (overflow)"),
679 ts->th = GNUNET_CADET_notify_transmit_ready (ts->channel,
680 GNUNET_NO /* cork */,
681 GNUNET_TIME_UNIT_FOREVER_REL,
683 &send_to_peer_notify_callback,
689 * Output destination of a channel for diagnostics.
691 * @param de destination to process
692 * @return diagnostic string describing destination
695 print_channel_destination (const struct DestinationEntry *de)
697 static char dest[256];
701 GNUNET_snprintf (dest,
704 GNUNET_i2s (&de->details.service_destination.target),
705 GNUNET_h2s (&de->details.service_destination.service_descriptor));
709 inet_ntop (de->details.exit_destination.af,
710 &de->details.exit_destination.ip,
719 * Regex has found a potential exit peer for us; consider using it.
721 * @param cls the `struct ChannelState`
722 * @param id Peer providing a regex that matches the string.
723 * @param get_path Path of the get request.
724 * @param get_path_length Lenght of @a get_path.
725 * @param put_path Path of the put request.
726 * @param put_path_length Length of the @a put_path.
729 handle_regex_result (void *cls,
730 const struct GNUNET_PeerIdentity *id,
731 const struct GNUNET_PeerIdentity *get_path,
732 unsigned int get_path_length,
733 const struct GNUNET_PeerIdentity *put_path,
734 unsigned int put_path_length)
736 struct ChannelState *ts = cls;
737 struct GNUNET_HashCode port;
739 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
740 "Exit %s found for destination %s!\n",
742 print_channel_destination (&ts->destination));
743 GNUNET_REGEX_search_cancel (ts->search);
748 /* these must match the strings used in gnunet-daemon-exit */
749 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_IPV4_GATEWAY,
750 strlen (GNUNET_APPLICATION_PORT_IPV4_GATEWAY),
754 /* these must match the strings used in gnunet-daemon-exit */
755 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_IPV6_GATEWAY,
756 strlen (GNUNET_APPLICATION_PORT_IPV6_GATEWAY),
763 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
764 "Creating tunnel to %s for destination %s!\n",
766 print_channel_destination (&ts->destination));
767 ts->channel = GNUNET_CADET_channel_create (cadet_handle,
771 GNUNET_CADET_OPTION_DEFAULT);
776 * Initialize the given destination entry's cadet channel.
778 * @param dt destination channel for which we need to setup a channel
779 * @param client_af address family of the address returned to the client
780 * @return channel state of the channel that was created
782 static struct ChannelState *
783 create_channel_to_destination (struct DestinationChannel *dt,
786 struct ChannelState *ts;
788 GNUNET_STATISTICS_update (stats,
789 gettext_noop ("# Cadet channels created"),
792 ts = GNUNET_new (struct ChannelState);
794 ts->destination = *dt->destination;
795 ts->destination.heap_node = NULL; /* copy is NOT in destination heap */
796 if (dt->destination->is_service)
798 ts->channel = GNUNET_CADET_channel_create (cadet_handle,
800 &dt->destination->details.service_destination.target,
801 &ts->destination.details.service_destination.service_descriptor,
802 GNUNET_CADET_OPTION_DEFAULT);
803 if (NULL == ts->channel)
809 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
810 "Creating channel %p to peer %s offering service %s\n",
812 GNUNET_i2s (&dt->destination->details.service_destination.target),
813 GNUNET_h2s (&dt->destination->details.service_destination.service_descriptor));
819 switch (dt->destination->details.exit_destination.af)
823 char address[GNUNET_TUN_IPV4_REGEXLEN];
825 GNUNET_TUN_ipv4toregexsearch (&dt->destination->details.exit_destination.ip.v4,
826 dt->destination_port,
828 GNUNET_asprintf (&policy,
830 GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
836 char address[GNUNET_TUN_IPV6_REGEXLEN];
838 GNUNET_TUN_ipv6toregexsearch (&dt->destination->details.exit_destination.ip.v6,
839 dt->destination_port,
841 GNUNET_asprintf (&policy,
843 GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
852 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
853 "Requesting connect by string: %s\n",
855 ts->search = GNUNET_REGEX_search (cfg,
857 &handle_regex_result,
859 GNUNET_free (policy);
866 * We have too many active channels. Clean up the oldest channel.
868 * @param except channel that must NOT be cleaned up, even if it is the oldest
871 expire_channel (struct ChannelState *except)
873 struct ChannelState *ts;
875 ts = GNUNET_CONTAINER_heap_peek (channel_heap);
876 GNUNET_assert (NULL != ts);
878 return; /* can't do this */
879 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
880 "Tearing down expired channel to %s\n",
881 print_channel_destination (&except->destination));
882 free_channel_state (ts);
887 * Route a packet via cadet to the given destination.
889 * @param destination description of the destination
890 * @param af address family on this end (AF_INET or AF_INET6)
891 * @param protocol IPPROTO_TCP or IPPROTO_UDP or IPPROTO_ICMP or IPPROTO_ICMPV6
892 * @param source_ip source IP used by the sender (struct in_addr or struct in6_addr)
893 * @param destination_ip destination IP used by the sender (struct in_addr or struct in6_addr)
894 * @param payload payload of the packet after the IP header
895 * @param payload_length number of bytes in @a payload
898 route_packet (struct DestinationEntry *destination,
901 const void *source_ip,
902 const void *destination_ip,
904 size_t payload_length)
906 struct GNUNET_HashCode key;
907 struct ChannelState *ts;
908 struct ChannelMessageQueueEntry *tnq;
911 const struct GNUNET_TUN_UdpHeader *udp;
912 const struct GNUNET_TUN_TcpHeader *tcp;
913 const struct GNUNET_TUN_IcmpHeader *icmp;
914 struct DestinationChannel *dt;
915 uint16_t source_port;
916 uint16_t destination_port;
922 if (payload_length < sizeof (struct GNUNET_TUN_UdpHeader))
928 tcp = NULL; /* make compiler happy */
929 icmp = NULL; /* make compiler happy */
931 if (udp->len < sizeof (struct GNUNET_TUN_UdpHeader))
936 source_port = ntohs (udp->source_port);
937 destination_port = ntohs (udp->destination_port);
938 get_channel_key_from_ips (af,
949 if (payload_length < sizeof (struct GNUNET_TUN_TcpHeader))
955 udp = NULL; /* make compiler happy */
956 icmp = NULL; /* make compiler happy */
958 if (tcp->off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
963 source_port = ntohs (tcp->source_port);
964 destination_port = ntohs (tcp->destination_port);
965 get_channel_key_from_ips (af,
977 if ( (AF_INET == af) ^ (protocol == IPPROTO_ICMP) )
982 if (payload_length < sizeof (struct GNUNET_TUN_IcmpHeader))
988 tcp = NULL; /* make compiler happy */
989 udp = NULL; /* make compiler happy */
992 destination_port = 0;
993 get_channel_key_from_ips (af,
1003 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1004 _("Protocol %u not supported, dropping\n"),
1005 (unsigned int) protocol);
1009 if (! destination->is_service)
1011 switch (destination->details.exit_destination.af)
1014 alen = sizeof (struct in_addr);
1017 alen = sizeof (struct in6_addr);
1024 char sbuf[INET6_ADDRSTRLEN];
1025 char dbuf[INET6_ADDRSTRLEN];
1026 char xbuf[INET6_ADDRSTRLEN];
1028 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1029 "Routing %s packet from [%s]:%u -> [%s]:%u to destination [%s]:%u\n",
1030 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
1041 inet_ntop (destination->details.exit_destination.af,
1042 &destination->details.exit_destination.ip,
1043 xbuf, sizeof (xbuf)),
1046 for (dt = destination->dt_head; NULL != dt; dt = dt->next)
1047 if (dt->destination_port == destination_port)
1053 char sbuf[INET6_ADDRSTRLEN];
1054 char dbuf[INET6_ADDRSTRLEN];
1056 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1057 "Routing %s packet from [%s]:%u -> [%s]:%u to service %s at peer %s\n",
1058 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
1069 GNUNET_h2s (&destination->details.service_destination.service_descriptor),
1070 GNUNET_i2s (&destination->details.service_destination.target));
1072 dt = destination->dt_head;
1076 dt = GNUNET_new (struct DestinationChannel);
1077 dt->destination = destination;
1078 GNUNET_CONTAINER_DLL_insert (destination->dt_head,
1079 destination->dt_tail,
1081 dt->destination_port = destination_port;
1084 /* see if we have an existing channel for this destination */
1085 ts = GNUNET_CONTAINER_multihashmap_get (channel_map,
1089 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1090 "Creating new channel for key %s\n",
1092 /* need to either use the existing channel from the destination (if still
1093 available) or create a fresh one */
1094 ts = create_channel_to_destination (dt, af);
1097 /* now bind existing "unbound" channel to our IP/port tuple */
1098 ts->protocol = protocol;
1102 ts->source_ip.v4 = * (const struct in_addr *) source_ip;
1103 ts->destination_ip.v4 = * (const struct in_addr *) destination_ip;
1107 ts->source_ip.v6 = * (const struct in6_addr *) source_ip;
1108 ts->destination_ip.v6 = * (const struct in6_addr *) destination_ip;
1110 ts->source_port = source_port;
1111 ts->destination_port = destination_port;
1112 ts->heap_node = GNUNET_CONTAINER_heap_insert (channel_heap,
1114 GNUNET_TIME_absolute_get ().abs_value_us);
1115 GNUNET_assert (GNUNET_YES ==
1116 GNUNET_CONTAINER_multihashmap_put (channel_map,
1119 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1120 GNUNET_STATISTICS_update (stats,
1121 gettext_noop ("# Active channels"),
1123 while (GNUNET_CONTAINER_multihashmap_size (channel_map) > max_channel_mappings)
1124 expire_channel (ts);
1128 GNUNET_CONTAINER_heap_update_cost (channel_heap,
1130 GNUNET_TIME_absolute_get ().abs_value_us);
1132 if (NULL == ts->channel)
1134 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1135 "Packet dropped, channel to %s not yet ready (%s)\n",
1136 print_channel_destination (&ts->destination),
1137 (NULL == ts->search)
1138 ? "EXIT search failed"
1139 : "EXIT search active");
1140 GNUNET_STATISTICS_update (stats,
1141 gettext_noop ("# Packets dropped (channel not yet online)"),
1147 /* send via channel */
1151 if (destination->is_service)
1153 struct GNUNET_EXIT_UdpServiceMessage *usm;
1155 mlen = sizeof (struct GNUNET_EXIT_UdpServiceMessage) +
1156 payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1157 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1162 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1165 usm = (struct GNUNET_EXIT_UdpServiceMessage *) &tnq[1];
1166 usm->header.size = htons ((uint16_t) mlen);
1167 usm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE);
1168 /* if the source port is below 32000, we assume it has a special
1169 meaning; if not, we pick a random port (this is a heuristic) */
1170 usm->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1171 usm->destination_port = udp->destination_port;
1172 usm->service_descriptor = destination->details.service_destination.service_descriptor;
1173 GNUNET_memcpy (&usm[1],
1175 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1179 struct GNUNET_EXIT_UdpInternetMessage *uim;
1180 struct in_addr *ip4dst;
1181 struct in6_addr *ip6dst;
1184 mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) +
1185 alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1186 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1191 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1194 uim = (struct GNUNET_EXIT_UdpInternetMessage *) &tnq[1];
1195 uim->header.size = htons ((uint16_t) mlen);
1196 uim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET);
1197 uim->af = htonl (destination->details.exit_destination.af);
1198 uim->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1199 uim->destination_port = udp->destination_port;
1200 switch (destination->details.exit_destination.af)
1203 ip4dst = (struct in_addr *) &uim[1];
1204 *ip4dst = destination->details.exit_destination.ip.v4;
1205 payload = &ip4dst[1];
1208 ip6dst = (struct in6_addr *) &uim[1];
1209 *ip6dst = destination->details.exit_destination.ip.v6;
1210 payload = &ip6dst[1];
1215 GNUNET_memcpy (payload,
1217 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1221 if (GNUNET_NO == ts->is_established)
1223 if (destination->is_service)
1225 struct GNUNET_EXIT_TcpServiceStartMessage *tsm;
1227 mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) +
1228 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1229 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1234 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1237 tsm = (struct GNUNET_EXIT_TcpServiceStartMessage *) &tnq[1];
1238 tsm->header.size = htons ((uint16_t) mlen);
1239 tsm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START);
1240 tsm->reserved = htonl (0);
1241 tsm->service_descriptor = destination->details.service_destination.service_descriptor;
1242 tsm->tcp_header = *tcp;
1243 GNUNET_memcpy (&tsm[1],
1245 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1249 struct GNUNET_EXIT_TcpInternetStartMessage *tim;
1250 struct in_addr *ip4dst;
1251 struct in6_addr *ip6dst;
1254 mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) +
1255 alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1256 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1261 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1264 tim = (struct GNUNET_EXIT_TcpInternetStartMessage *) &tnq[1];
1265 tim->header.size = htons ((uint16_t) mlen);
1266 tim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START);
1267 tim->af = htonl (destination->details.exit_destination.af);
1268 tim->tcp_header = *tcp;
1269 switch (destination->details.exit_destination.af)
1272 ip4dst = (struct in_addr *) &tim[1];
1273 *ip4dst = destination->details.exit_destination.ip.v4;
1274 payload = &ip4dst[1];
1277 ip6dst = (struct in6_addr *) &tim[1];
1278 *ip6dst = destination->details.exit_destination.ip.v6;
1279 payload = &ip6dst[1];
1284 GNUNET_memcpy (payload,
1286 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1291 struct GNUNET_EXIT_TcpDataMessage *tdm;
1293 mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) +
1294 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1295 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1300 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1303 tdm = (struct GNUNET_EXIT_TcpDataMessage *) &tnq[1];
1304 tdm->header.size = htons ((uint16_t) mlen);
1305 tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT);
1306 tdm->reserved = htonl (0);
1307 tdm->tcp_header = *tcp;
1308 GNUNET_memcpy (&tdm[1],
1310 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1314 case IPPROTO_ICMPV6:
1315 if (destination->is_service)
1317 struct GNUNET_EXIT_IcmpServiceMessage *ism;
1319 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1320 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1321 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1326 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1328 ism = (struct GNUNET_EXIT_IcmpServiceMessage *) &tnq[1];
1329 ism->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE);
1330 ism->af = htonl (af); /* need to tell destination ICMP protocol family! */
1331 ism->service_descriptor = destination->details.service_destination.service_descriptor;
1332 ism->icmp_header = *icmp;
1333 /* ICMP protocol translation will be done by the receiver (as we don't know
1334 the target AF); however, we still need to possibly discard the payload
1335 depending on the ICMP type */
1341 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1342 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1344 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1345 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1346 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1347 /* throw away ICMP payload, won't be useful for the other side anyway */
1348 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1351 GNUNET_STATISTICS_update (stats,
1352 gettext_noop ("# ICMPv4 packets dropped (not allowed)"),
1356 /* end of AF_INET */
1361 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1362 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1363 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1364 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1365 /* throw away ICMP payload, won't be useful for the other side anyway */
1366 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1368 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1369 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1372 GNUNET_STATISTICS_update (stats,
1373 gettext_noop ("# ICMPv6 packets dropped (not allowed)"),
1377 /* end of AF_INET6 */
1384 /* update length calculations, as payload_length may have changed */
1385 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1386 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1388 ism->header.size = htons ((uint16_t) mlen);
1389 /* finally, copy payload (if there is any left...) */
1390 GNUNET_memcpy (&ism[1],
1392 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1396 struct GNUNET_EXIT_IcmpInternetMessage *iim;
1397 struct in_addr *ip4dst;
1398 struct in6_addr *ip6dst;
1401 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1402 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1403 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1408 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1410 iim = (struct GNUNET_EXIT_IcmpInternetMessage *) &tnq[1];
1411 iim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET);
1412 iim->icmp_header = *icmp;
1413 /* Perform ICMP protocol-translation (depending on destination AF and source AF)
1414 and throw away ICMP payload depending on ICMP message type */
1420 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1421 if (destination->details.exit_destination.af == AF_INET6)
1422 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1424 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1425 if (destination->details.exit_destination.af == AF_INET6)
1426 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1428 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1429 if (destination->details.exit_destination.af == AF_INET6)
1430 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1431 /* throw away IP-payload, exit will have to make it up anyway */
1432 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1434 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1435 if (destination->details.exit_destination.af == AF_INET6)
1436 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1437 /* throw away IP-payload, exit will have to make it up anyway */
1438 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1440 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1441 if (destination->details.exit_destination.af == AF_INET6)
1443 GNUNET_STATISTICS_update (stats,
1444 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1449 /* throw away IP-payload, exit will have to make it up anyway */
1450 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1453 GNUNET_STATISTICS_update (stats,
1454 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1459 /* end of AF_INET */
1464 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1465 if (destination->details.exit_destination.af == AF_INET6)
1466 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1467 /* throw away IP-payload, exit will have to make it up anyway */
1468 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1470 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1471 if (destination->details.exit_destination.af == AF_INET)
1472 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1473 /* throw away IP-payload, exit will have to make it up anyway */
1474 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1476 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1477 if (destination->details.exit_destination.af == AF_INET)
1479 GNUNET_STATISTICS_update (stats,
1480 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1485 /* throw away IP-payload, exit will have to make it up anyway */
1486 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1488 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1489 if (destination->details.exit_destination.af == AF_INET)
1491 GNUNET_STATISTICS_update (stats,
1492 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1497 /* throw away IP-payload, exit will have to make it up anyway */
1498 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1500 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1501 if (destination->details.exit_destination.af == AF_INET)
1502 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1504 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1505 if (destination->details.exit_destination.af == AF_INET)
1506 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1509 GNUNET_STATISTICS_update (stats,
1510 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1515 /* end of AF_INET6 */
1520 /* update length calculations, as payload_length may have changed */
1521 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1522 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1524 iim->header.size = htons ((uint16_t) mlen);
1526 /* need to tell destination ICMP protocol family! */
1527 iim->af = htonl (destination->details.exit_destination.af);
1528 switch (destination->details.exit_destination.af)
1531 ip4dst = (struct in_addr *) &iim[1];
1532 *ip4dst = destination->details.exit_destination.ip.v4;
1533 payload = &ip4dst[1];
1536 ip6dst = (struct in6_addr *) &iim[1];
1537 *ip6dst = destination->details.exit_destination.ip.v6;
1538 payload = &ip6dst[1];
1543 GNUNET_memcpy (payload,
1545 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1549 /* not supported above, how can we get here !? */
1553 ts->is_established = GNUNET_YES;
1554 send_to_channel (tnq, ts);
1559 * Receive packets from the helper-process (someone send to the local
1560 * virtual channel interface). Find the destination mapping, and if it
1561 * exists, identify the correct CADET channel (or possibly create it)
1562 * and forward the packet.
1564 * @param cls closure, NULL
1565 * @param client NULL
1566 * @param message message we got from the client (VPN channel interface)
1569 message_token (void *cls,
1571 const struct GNUNET_MessageHeader *message)
1573 const struct GNUNET_TUN_Layer2PacketHeader *tun;
1575 struct GNUNET_HashCode key;
1576 struct DestinationEntry *de;
1578 GNUNET_STATISTICS_update (stats,
1579 gettext_noop ("# Packets received from TUN interface"),
1581 mlen = ntohs (message->size);
1582 if ( (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
1583 (mlen < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader)) )
1588 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1589 mlen -= (sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader));
1590 switch (ntohs (tun->proto))
1594 const struct GNUNET_TUN_IPv6Header *pkt6;
1596 if (mlen < sizeof (struct GNUNET_TUN_IPv6Header))
1602 pkt6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1603 get_destination_key_from_ip (AF_INET6,
1604 &pkt6->destination_address,
1606 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1609 char buf[INET6_ADDRSTRLEN];
1611 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1612 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1613 inet_ntop (AF_INET6,
1614 &pkt6->destination_address,
1622 &pkt6->source_address,
1623 &pkt6->destination_address,
1625 mlen - sizeof (struct GNUNET_TUN_IPv6Header));
1630 struct GNUNET_TUN_IPv4Header *pkt4;
1632 if (mlen < sizeof (struct GNUNET_TUN_IPv4Header))
1638 pkt4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1639 get_destination_key_from_ip (AF_INET,
1640 &pkt4->destination_address,
1642 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1645 char buf[INET_ADDRSTRLEN];
1647 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1648 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1650 &pkt4->destination_address,
1655 if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header))
1657 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1658 _("Received IPv4 packet with options (dropping it)\n"));
1664 &pkt4->source_address,
1665 &pkt4->destination_address,
1667 mlen - sizeof (struct GNUNET_TUN_IPv4Header));
1671 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1672 _("Received packet of unknown protocol %d from TUN (dropping it)\n"),
1673 (unsigned int) ntohs (tun->proto));
1681 * Synthesize a plausible ICMP payload for an ICMP error
1682 * response on the given channel.
1684 * @param ts channel information
1685 * @param ipp IPv4 header to fill in (ICMP payload)
1686 * @param udp "UDP" header to fill in (ICMP payload); might actually
1687 * also be the first 8 bytes of the TCP header
1690 make_up_icmpv4_payload (struct ChannelState *ts,
1691 struct GNUNET_TUN_IPv4Header *ipp,
1692 struct GNUNET_TUN_UdpHeader *udp)
1694 GNUNET_TUN_initialize_ipv4_header (ipp,
1696 sizeof (struct GNUNET_TUN_TcpHeader),
1698 &ts->destination_ip.v4);
1699 udp->source_port = htons (ts->source_port);
1700 udp->destination_port = htons (ts->destination_port);
1701 udp->len = htons (0);
1702 udp->crc = htons (0);
1707 * Synthesize a plausible ICMP payload for an ICMP error
1708 * response on the given channel.
1710 * @param ts channel information
1711 * @param ipp IPv6 header to fill in (ICMP payload)
1712 * @param udp "UDP" header to fill in (ICMP payload); might actually
1713 * also be the first 8 bytes of the TCP header
1716 make_up_icmpv6_payload (struct ChannelState *ts,
1717 struct GNUNET_TUN_IPv6Header *ipp,
1718 struct GNUNET_TUN_UdpHeader *udp)
1720 GNUNET_TUN_initialize_ipv6_header (ipp,
1722 sizeof (struct GNUNET_TUN_TcpHeader),
1724 &ts->destination_ip.v6);
1725 udp->source_port = htons (ts->source_port);
1726 udp->destination_port = htons (ts->destination_port);
1727 udp->len = htons (0);
1728 udp->crc = htons (0);
1733 * We got an ICMP packet back from the CADET channel. Pass it on to the
1734 * local virtual interface via the helper.
1736 * @param cls closure, NULL
1737 * @param channel connection to the other end
1738 * @param channel_ctx pointer to our 'struct ChannelState *'
1739 * @param message the actual message
1740 * @return #GNUNET_OK to keep the connection open,
1741 * #GNUNET_SYSERR to close it (signal serious error)
1744 receive_icmp_back (void *cls,
1745 struct GNUNET_CADET_Channel *channel,
1747 const struct GNUNET_MessageHeader *message)
1749 struct ChannelState *ts = *channel_ctx;
1750 const struct GNUNET_EXIT_IcmpToVPNMessage *i2v;
1753 GNUNET_STATISTICS_update (stats,
1754 gettext_noop ("# ICMP packets received from cadet"),
1756 mlen = ntohs (message->size);
1757 if (mlen < sizeof (struct GNUNET_EXIT_IcmpToVPNMessage))
1759 GNUNET_break_op (0);
1760 return GNUNET_SYSERR;
1762 if (NULL == ts->heap_node)
1764 GNUNET_break_op (0);
1765 return GNUNET_SYSERR;
1767 if (AF_UNSPEC == ts->af)
1769 GNUNET_break_op (0);
1770 return GNUNET_SYSERR;
1772 i2v = (const struct GNUNET_EXIT_IcmpToVPNMessage *) message;
1773 mlen -= sizeof (struct GNUNET_EXIT_IcmpToVPNMessage);
1775 char sbuf[INET6_ADDRSTRLEN];
1776 char dbuf[INET6_ADDRSTRLEN];
1778 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1779 "Received ICMP packet from cadet, sending %u bytes from %s -> %s via TUN\n",
1780 (unsigned int) mlen,
1781 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
1782 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)));
1788 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
1789 + sizeof (struct GNUNET_TUN_IcmpHeader)
1790 + sizeof (struct GNUNET_MessageHeader) +
1791 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1794 /* reserve some extra space in case we have an ICMP type here where
1795 we will need to make up the payload ourselves */
1796 char buf[size + sizeof (struct GNUNET_TUN_IPv4Header) + 8] GNUNET_ALIGN;
1797 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1798 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1799 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1800 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv4[1];
1801 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1802 tun->flags = htons (0);
1803 tun->proto = htons (ETH_P_IPV4);
1804 GNUNET_TUN_initialize_ipv4_header (ipv4,
1806 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1807 &ts->destination_ip.v4,
1809 *icmp = i2v->icmp_header;
1810 GNUNET_memcpy (&icmp[1],
1813 /* For some ICMP types, we need to adjust (make up) the payload here.
1814 Also, depending on the AF used on the other side, we have to
1815 do ICMP PT (translate ICMP types) */
1816 switch (ntohl (i2v->af))
1821 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1822 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1824 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1825 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1826 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1828 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1829 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1833 /* sender did not strip ICMP payload? */
1834 GNUNET_break_op (0);
1835 return GNUNET_SYSERR;
1837 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1838 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1839 make_up_icmpv4_payload (ts, ipp, udp);
1843 GNUNET_break_op (0);
1844 GNUNET_STATISTICS_update (stats,
1845 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1847 return GNUNET_SYSERR;
1852 /* ICMP PT 6-to-4 and possibly making up payloads */
1855 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1856 icmp->type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
1858 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1859 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1863 /* sender did not strip ICMP payload? */
1864 GNUNET_break_op (0);
1865 return GNUNET_SYSERR;
1867 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1868 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1869 make_up_icmpv4_payload (ts, ipp, udp);
1872 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1873 icmp->type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1875 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1876 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1880 /* sender did not strip ICMP payload? */
1881 GNUNET_break_op (0);
1882 return GNUNET_SYSERR;
1884 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1885 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1886 make_up_icmpv4_payload (ts, ipp, udp);
1889 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1890 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1891 GNUNET_STATISTICS_update (stats,
1892 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1895 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1896 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1898 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1899 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1902 GNUNET_break_op (0);
1903 GNUNET_STATISTICS_update (stats,
1904 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1906 return GNUNET_SYSERR;
1911 GNUNET_break_op (0);
1912 return GNUNET_SYSERR;
1914 msg->size = htons (size);
1915 GNUNET_TUN_calculate_icmp_checksum (icmp,
1918 (void) GNUNET_HELPER_send (helper_handle,
1927 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
1928 + sizeof (struct GNUNET_TUN_IcmpHeader)
1929 + sizeof (struct GNUNET_MessageHeader) +
1930 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1933 char buf[size + sizeof (struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN;
1934 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1935 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1936 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
1937 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv6[1];
1938 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1939 tun->flags = htons (0);
1940 tun->proto = htons (ETH_P_IPV6);
1941 GNUNET_TUN_initialize_ipv6_header (ipv6,
1943 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1944 &ts->destination_ip.v6,
1946 *icmp = i2v->icmp_header;
1947 GNUNET_memcpy (&icmp[1],
1951 /* For some ICMP types, we need to adjust (make up) the payload here.
1952 Also, depending on the AF used on the other side, we have to
1953 do ICMP PT (translate ICMP types) */
1954 switch (ntohl (i2v->af))
1957 /* ICMP PT 4-to-6 and possibly making up payloads */
1960 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1961 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1963 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1964 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1966 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1967 icmp->type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1969 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1970 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1974 /* sender did not strip ICMP payload? */
1975 GNUNET_break_op (0);
1976 return GNUNET_SYSERR;
1978 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1979 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1980 make_up_icmpv6_payload (ts, ipp, udp);
1983 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1984 icmp->type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1986 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1987 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1991 /* sender did not strip ICMP payload? */
1992 GNUNET_break_op (0);
1993 return GNUNET_SYSERR;
1995 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1996 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1997 make_up_icmpv6_payload (ts, ipp, udp);
2000 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
2001 GNUNET_STATISTICS_update (stats,
2002 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
2006 GNUNET_break_op (0);
2007 GNUNET_STATISTICS_update (stats,
2008 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
2010 return GNUNET_SYSERR;
2017 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
2018 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
2019 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
2020 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
2022 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
2023 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
2027 /* sender did not strip ICMP payload? */
2028 GNUNET_break_op (0);
2029 return GNUNET_SYSERR;
2031 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
2032 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
2033 make_up_icmpv6_payload (ts, ipp, udp);
2036 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
2039 GNUNET_break_op (0);
2040 GNUNET_STATISTICS_update (stats,
2041 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
2043 return GNUNET_SYSERR;
2048 GNUNET_break_op (0);
2049 return GNUNET_SYSERR;
2051 msg->size = htons (size);
2052 GNUNET_TUN_calculate_icmp_checksum (icmp,
2054 (void) GNUNET_HELPER_send (helper_handle,
2064 GNUNET_CONTAINER_heap_update_cost (channel_heap,
2066 GNUNET_TIME_absolute_get ().abs_value_us);
2067 GNUNET_CADET_receive_done (channel);
2073 * We got a UDP packet back from the CADET channel. Pass it on to the
2074 * local virtual interface via the helper.
2076 * @param cls closure, NULL
2077 * @param channel connection to the other end
2078 * @param channel_ctx pointer to our 'struct ChannelState *'
2079 * @param message the actual message
2080 * @return #GNUNET_OK to keep the connection open,
2081 * #GNUNET_SYSERR to close it (signal serious error)
2084 receive_udp_back (void *cls,
2085 struct GNUNET_CADET_Channel *channel,
2087 const struct GNUNET_MessageHeader *message)
2089 struct ChannelState *ts = *channel_ctx;
2090 const struct GNUNET_EXIT_UdpReplyMessage *reply;
2093 GNUNET_STATISTICS_update (stats,
2094 gettext_noop ("# UDP packets received from cadet"),
2096 mlen = ntohs (message->size);
2097 if (mlen < sizeof (struct GNUNET_EXIT_UdpReplyMessage))
2099 GNUNET_break_op (0);
2100 return GNUNET_SYSERR;
2102 if (NULL == ts->heap_node)
2104 GNUNET_break_op (0);
2105 return GNUNET_SYSERR;
2107 if (AF_UNSPEC == ts->af)
2109 GNUNET_break_op (0);
2110 return GNUNET_SYSERR;
2112 reply = (const struct GNUNET_EXIT_UdpReplyMessage *) message;
2113 mlen -= sizeof (struct GNUNET_EXIT_UdpReplyMessage);
2115 char sbuf[INET6_ADDRSTRLEN];
2116 char dbuf[INET6_ADDRSTRLEN];
2118 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2119 "Received UDP reply from cadet, sending %u bytes from [%s]:%u -> [%s]:%u via TUN\n",
2120 (unsigned int) mlen,
2121 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2122 ts->destination_port,
2123 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2130 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2131 + sizeof (struct GNUNET_TUN_UdpHeader)
2132 + sizeof (struct GNUNET_MessageHeader) +
2133 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2136 char buf[size] GNUNET_ALIGN;
2137 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2138 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2139 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2140 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1];
2141 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2142 msg->size = htons (size);
2143 tun->flags = htons (0);
2144 tun->proto = htons (ETH_P_IPV4);
2145 GNUNET_TUN_initialize_ipv4_header (ipv4,
2147 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2148 &ts->destination_ip.v4,
2150 if (0 == ntohs (reply->source_port))
2151 udp->source_port = htons (ts->destination_port);
2153 udp->source_port = reply->source_port;
2154 if (0 == ntohs (reply->destination_port))
2155 udp->destination_port = htons (ts->source_port);
2157 udp->destination_port = reply->destination_port;
2158 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2159 GNUNET_TUN_calculate_udp4_checksum (ipv4,
2163 GNUNET_memcpy (&udp[1],
2166 (void) GNUNET_HELPER_send (helper_handle,
2175 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2176 + sizeof (struct GNUNET_TUN_UdpHeader)
2177 + sizeof (struct GNUNET_MessageHeader) +
2178 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2181 char buf[size] GNUNET_ALIGN;
2182 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2183 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2184 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2185 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1];
2186 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2187 msg->size = htons (size);
2188 tun->flags = htons (0);
2189 tun->proto = htons (ETH_P_IPV6);
2190 GNUNET_TUN_initialize_ipv6_header (ipv6,
2192 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2193 &ts->destination_ip.v6,
2195 if (0 == ntohs (reply->source_port))
2196 udp->source_port = htons (ts->destination_port);
2198 udp->source_port = reply->source_port;
2199 if (0 == ntohs (reply->destination_port))
2200 udp->destination_port = htons (ts->source_port);
2202 udp->destination_port = reply->destination_port;
2203 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2204 GNUNET_TUN_calculate_udp6_checksum (ipv6,
2207 GNUNET_memcpy (&udp[1],
2210 (void) GNUNET_HELPER_send (helper_handle,
2220 GNUNET_CONTAINER_heap_update_cost (channel_heap,
2222 GNUNET_TIME_absolute_get ().abs_value_us);
2223 GNUNET_CADET_receive_done (channel);
2229 * We got a TCP packet back from the CADET channel. Pass it on to the
2230 * local virtual interface via the helper.
2232 * @param cls closure, NULL
2233 * @param channel connection to the other end
2234 * @param channel_ctx pointer to our `struct ChannelState *`
2235 * @param message the actual message
2236 * @return #GNUNET_OK to keep the connection open,
2237 * #GNUNET_SYSERR to close it (signal serious error)
2240 receive_tcp_back (void *cls,
2241 struct GNUNET_CADET_Channel *channel,
2243 const struct GNUNET_MessageHeader *message)
2245 struct ChannelState *ts = *channel_ctx;
2246 const struct GNUNET_EXIT_TcpDataMessage *data;
2249 GNUNET_STATISTICS_update (stats,
2250 gettext_noop ("# TCP packets received from cadet"),
2252 mlen = ntohs (message->size);
2253 if (mlen < sizeof (struct GNUNET_EXIT_TcpDataMessage))
2255 GNUNET_break_op (0);
2256 return GNUNET_SYSERR;
2258 if (NULL == ts->heap_node)
2260 GNUNET_break_op (0);
2261 return GNUNET_SYSERR;
2263 data = (const struct GNUNET_EXIT_TcpDataMessage *) message;
2264 mlen -= sizeof (struct GNUNET_EXIT_TcpDataMessage);
2266 char sbuf[INET6_ADDRSTRLEN];
2267 char dbuf[INET6_ADDRSTRLEN];
2269 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2270 "Received TCP reply from cadet, sending %u bytes from [%s]:%u -> [%s]:%u via TUN\n",
2271 (unsigned int) mlen,
2272 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2273 ts->destination_port,
2274 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2277 if (data->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
2279 GNUNET_break_op (0);
2280 return GNUNET_SYSERR;
2286 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2287 + sizeof (struct GNUNET_TUN_TcpHeader)
2288 + sizeof (struct GNUNET_MessageHeader) +
2289 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2292 char buf[size] GNUNET_ALIGN;
2293 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2294 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2295 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2296 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv4[1];
2297 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2298 msg->size = htons (size);
2299 tun->flags = htons (0);
2300 tun->proto = htons (ETH_P_IPV4);
2301 GNUNET_TUN_initialize_ipv4_header (ipv4,
2303 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2304 &ts->destination_ip.v4,
2306 *tcp = data->tcp_header;
2307 tcp->source_port = htons (ts->destination_port);
2308 tcp->destination_port = htons (ts->source_port);
2309 GNUNET_TUN_calculate_tcp4_checksum (ipv4,
2313 GNUNET_memcpy (&tcp[1],
2316 (void) GNUNET_HELPER_send (helper_handle,
2325 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2326 + sizeof (struct GNUNET_TUN_TcpHeader)
2327 + sizeof (struct GNUNET_MessageHeader) +
2328 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2331 char buf[size] GNUNET_ALIGN;
2332 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2333 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2334 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2335 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv6[1];
2336 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2337 msg->size = htons (size);
2338 tun->flags = htons (0);
2339 tun->proto = htons (ETH_P_IPV6);
2340 GNUNET_TUN_initialize_ipv6_header (ipv6,
2342 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2343 &ts->destination_ip.v6,
2345 *tcp = data->tcp_header;
2346 tcp->source_port = htons (ts->destination_port);
2347 tcp->destination_port = htons (ts->source_port);
2348 GNUNET_TUN_calculate_tcp6_checksum (ipv6,
2352 GNUNET_memcpy (&tcp[1],
2355 (void) GNUNET_HELPER_send (helper_handle,
2363 GNUNET_CONTAINER_heap_update_cost (channel_heap,
2365 GNUNET_TIME_absolute_get ().abs_value_us);
2366 GNUNET_CADET_receive_done (channel);
2372 * Allocate an IPv4 address from the range of the channel
2373 * for a new redirection.
2375 * @param v4 where to store the address
2376 * @return #GNUNET_OK on success,
2377 * #GNUNET_SYSERR on error
2380 allocate_v4_address (struct in_addr *v4)
2382 const char *ipv4addr = vpn_argv[4];
2383 const char *ipv4mask = vpn_argv[5];
2384 struct in_addr addr;
2385 struct in_addr mask;
2387 struct GNUNET_HashCode key;
2390 GNUNET_assert (1 == inet_pton (AF_INET, ipv4addr, &addr));
2391 GNUNET_assert (1 == inet_pton (AF_INET, ipv4mask, &mask));
2392 /* Given 192.168.0.1/255.255.0.0, we want a mask
2393 of '192.168.255.255', thus: */
2394 mask.s_addr = addr.s_addr | ~mask.s_addr;
2401 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2402 _("Failed to find unallocated IPv4 address in VPN's range\n"));
2403 return GNUNET_SYSERR;
2405 /* Pick random IPv4 address within the subnet, except 'addr' or 'mask' itself */
2406 rnd.s_addr = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2408 v4->s_addr = (addr.s_addr | rnd.s_addr) & mask.s_addr;
2409 get_destination_key_from_ip (AF_INET,
2413 while ( (GNUNET_YES ==
2414 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2416 (v4->s_addr == addr.s_addr) ||
2417 (v4->s_addr == mask.s_addr) );
2423 * Allocate an IPv6 address from the range of the channel
2424 * for a new redirection.
2426 * @param v6 where to store the address
2427 * @return #GNUNET_OK on success,
2428 * #GNUNET_SYSERR on error
2431 allocate_v6_address (struct in6_addr *v6)
2433 const char *ipv6addr = vpn_argv[2];
2434 struct in6_addr addr;
2435 struct in6_addr mask;
2436 struct in6_addr rnd;
2438 struct GNUNET_HashCode key;
2441 GNUNET_assert (1 == inet_pton (AF_INET6, ipv6addr, &addr));
2442 GNUNET_assert (ipv6prefix < 128);
2443 /* Given ABCD::/96, we want a mask of 'ABCD::FFFF:FFFF,
2446 for (i=127;i>=ipv6prefix;i--)
2447 mask.s6_addr[i / 8] |= (1 << (i % 8));
2449 /* Pick random IPv6 address within the subnet, except 'addr' or 'mask' itself */
2456 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2457 _("Failed to find unallocated IPv6 address in VPN's range\n"));
2458 return GNUNET_SYSERR;
2463 rnd.s6_addr[i] = (unsigned char) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2466 = (addr.s6_addr[i] | rnd.s6_addr[i]) & mask.s6_addr[i];
2468 get_destination_key_from_ip (AF_INET6,
2472 while ( (GNUNET_YES ==
2473 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2477 sizeof (struct in6_addr))) ||
2480 sizeof (struct in6_addr))) );
2486 * Free resources occupied by a destination entry.
2488 * @param de entry to free
2491 free_destination_entry (struct DestinationEntry *de)
2493 struct DestinationChannel *dt;
2495 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2496 "Cleaning up destination entry `%s'\n",
2497 print_channel_destination (de));
2498 GNUNET_STATISTICS_update (stats,
2499 gettext_noop ("# Active destinations"),
2501 while (NULL != (dt = de->dt_head))
2503 GNUNET_CONTAINER_DLL_remove (de->dt_head,
2508 if (NULL != de->heap_node)
2510 GNUNET_CONTAINER_heap_remove_node (de->heap_node);
2511 de->heap_node = NULL;
2512 GNUNET_assert (GNUNET_YES ==
2513 GNUNET_CONTAINER_multihashmap_remove (destination_map,
2522 * We have too many active destinations. Clean up the oldest destination.
2524 * @param except destination that must NOT be cleaned up, even if it is the oldest
2527 expire_destination (struct DestinationEntry *except)
2529 struct DestinationEntry *de;
2531 de = GNUNET_CONTAINER_heap_peek (destination_heap);
2532 GNUNET_assert (NULL != de);
2534 return; /* can't do this */
2535 free_destination_entry (de);
2540 * Allocate an IP address for the response.
2542 * @param result_af desired address family; set to the actual
2543 * address family; can initially be AF_UNSPEC if there
2544 * is no preference; will be set to AF_UNSPEC if the
2546 * @param addr set to either v4 or v6 depending on which
2547 * storage location was used; set to NULL if allocation failed
2548 * @param v4 storage space for an IPv4 address
2549 * @param v6 storage space for an IPv6 address
2550 * @return #GNUNET_OK normally, #GNUNET_SYSERR if `* result_af` was
2551 * an unsupported address family (not AF_INET, AF_INET6 or AF_UNSPEC)
2554 allocate_response_ip (int *result_af,
2557 struct in6_addr *v6)
2564 allocate_v4_address (v4))
2565 *result_af = AF_UNSPEC;
2571 allocate_v6_address (v6))
2572 *result_af = AF_UNSPEC;
2578 allocate_v4_address (v4))
2581 *result_af = AF_INET;
2583 else if (GNUNET_OK ==
2584 allocate_v6_address (v6))
2587 *result_af = AF_INET6;
2592 return GNUNET_SYSERR;
2599 * A client asks us to setup a redirection via some exit node to a
2600 * particular IP. Setup the redirection and give the client the
2604 * @param client requesting client
2605 * @param message redirection request (a `struct RedirectToIpRequestMessage`)
2608 service_redirect_to_ip (void *cls,
2609 struct GNUNET_SERVER_Client *client,
2610 const struct GNUNET_MessageHeader *message)
2614 const struct RedirectToIpRequestMessage *msg;
2620 struct DestinationEntry *de;
2621 struct GNUNET_HashCode key;
2623 /* validate and parse request */
2624 mlen = ntohs (message->size);
2625 if (mlen < sizeof (struct RedirectToIpRequestMessage))
2628 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2631 alen = mlen - sizeof (struct RedirectToIpRequestMessage);
2632 msg = (const struct RedirectToIpRequestMessage *) message;
2633 addr_af = (int) htonl (msg->addr_af);
2637 if (alen != sizeof (struct in_addr))
2640 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2645 if (alen != sizeof (struct in6_addr))
2648 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2654 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2658 /* allocate response IP */
2659 result_af = (int) htonl (msg->result_af);
2660 if (GNUNET_OK != allocate_response_ip (&result_af,
2664 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2667 /* send reply with our IP address */
2668 send_client_reply (client,
2672 if (result_af == AF_UNSPEC)
2674 /* failure, we're done */
2675 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2680 char sbuf[INET6_ADDRSTRLEN];
2681 char dbuf[INET6_ADDRSTRLEN];
2683 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2684 "Allocated address %s for redirection via exit to %s\n",
2685 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2687 &msg[1], dbuf, sizeof (dbuf)));
2690 /* setup destination record */
2691 de = GNUNET_new (struct DestinationEntry);
2692 de->is_service = GNUNET_NO;
2693 de->details.exit_destination.af = addr_af;
2694 GNUNET_memcpy (&de->details.exit_destination.ip,
2697 get_destination_key_from_ip (result_af,
2701 GNUNET_assert (GNUNET_OK ==
2702 GNUNET_CONTAINER_multihashmap_put (destination_map,
2705 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2706 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2708 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value_us);
2709 GNUNET_STATISTICS_update (stats,
2710 gettext_noop ("# Active destinations"),
2712 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2713 expire_destination (de);
2714 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2719 * A client asks us to setup a redirection to a particular peer
2720 * offering a service. Setup the redirection and give the client the
2724 * @param client requesting client
2725 * @param message redirection request (a `struct RedirectToPeerRequestMessage`)
2728 service_redirect_to_service (void *cls,
2729 struct GNUNET_SERVER_Client *client,
2730 const struct GNUNET_MessageHeader *message)
2732 const struct RedirectToServiceRequestMessage *msg;
2737 struct DestinationEntry *de;
2738 struct GNUNET_HashCode key;
2739 struct DestinationChannel *dt;
2742 msg = (const struct RedirectToServiceRequestMessage *) message;
2744 /* allocate response IP */
2745 result_af = (int) htonl (msg->result_af);
2746 if (GNUNET_OK != allocate_response_ip (&result_af,
2750 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2753 send_client_reply (client,
2757 if (result_af == AF_UNSPEC)
2759 /* failure, we're done */
2760 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2761 _("Failed to allocate IP address for new destination\n"));
2762 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2767 char sbuf[INET6_ADDRSTRLEN];
2769 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2770 "Allocated address %s for redirection to service %s on peer %s\n",
2771 inet_ntop (result_af,
2775 GNUNET_h2s (&msg->service_descriptor),
2776 GNUNET_i2s (&msg->target));
2779 /* setup destination record */
2780 de = GNUNET_new (struct DestinationEntry);
2781 de->is_service = GNUNET_YES;
2782 de->details.service_destination.service_descriptor = msg->service_descriptor;
2783 de->details.service_destination.target = msg->target;
2784 get_destination_key_from_ip (result_af,
2788 GNUNET_assert (GNUNET_OK ==
2789 GNUNET_CONTAINER_multihashmap_put (destination_map,
2792 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2793 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2795 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value_us);
2796 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2797 expire_destination (de);
2799 dt = GNUNET_new (struct DestinationChannel);
2800 dt->destination = de;
2801 GNUNET_CONTAINER_DLL_insert (de->dt_head,
2805 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2810 * Function called whenever a channel is destroyed. Should clean up
2811 * any associated state.
2813 * @param cls closure (set from #GNUNET_CADET_connect)
2814 * @param channel connection to the other end (henceforth invalid)
2815 * @param channel_ctx place where local state associated
2816 * with the channel is stored (our `struct ChannelState`)
2819 channel_cleaner (void *cls,
2820 const struct GNUNET_CADET_Channel *channel,
2823 struct ChannelState *ts = channel_ctx;
2825 ts->channel = NULL; /* we must not call GNUNET_CADET_channel_destroy() anymore */
2826 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2827 "CADET notified us about death of channel to `%s'\n",
2828 print_channel_destination (&ts->destination));
2829 free_channel_state (ts);
2834 * Free memory occupied by an entry in the destination map.
2838 * @param value a `struct DestinationEntry *`
2839 * @return #GNUNET_OK (continue to iterate)
2842 cleanup_destination (void *cls,
2843 const struct GNUNET_HashCode *key,
2846 struct DestinationEntry *de = value;
2848 free_destination_entry (de);
2854 * Free memory occupied by an entry in the channel map.
2858 * @param value a `struct ChannelState *`
2859 * @return #GNUNET_OK (continue to iterate)
2862 cleanup_channel (void *cls,
2863 const struct GNUNET_HashCode *key,
2866 struct ChannelState *ts = value;
2868 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2869 "Tearing down channel to `%s' during cleanup\n",
2870 print_channel_destination (&ts->destination));
2871 free_channel_state (ts);
2877 * Function scheduled as very last function, cleans up after us
2886 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2887 "VPN is shutting down\n");
2888 if (NULL != destination_map)
2890 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
2891 &cleanup_destination,
2893 GNUNET_CONTAINER_multihashmap_destroy (destination_map);
2894 destination_map = NULL;
2896 if (NULL != destination_heap)
2898 GNUNET_CONTAINER_heap_destroy (destination_heap);
2899 destination_heap = NULL;
2901 if (NULL != channel_map)
2903 GNUNET_CONTAINER_multihashmap_iterate (channel_map,
2906 GNUNET_CONTAINER_multihashmap_destroy (channel_map);
2909 if (NULL != channel_heap)
2911 GNUNET_CONTAINER_heap_destroy (channel_heap);
2912 channel_heap = NULL;
2914 if (NULL != cadet_handle)
2916 GNUNET_CADET_disconnect (cadet_handle);
2917 cadet_handle = NULL;
2919 if (NULL != helper_handle)
2921 GNUNET_HELPER_kill (helper_handle, GNUNET_NO);
2922 GNUNET_HELPER_wait (helper_handle);
2923 helper_handle = NULL;
2927 GNUNET_SERVER_notification_context_destroy (nc);
2932 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
2936 GNUNET_free_non_null (vpn_argv[i]);
2941 * Main function that will be run by the scheduler.
2943 * @param cls closure
2944 * @param server the initialized server
2945 * @param cfg_ configuration
2949 struct GNUNET_SERVER_Handle *server,
2950 const struct GNUNET_CONFIGURATION_Handle *cfg_)
2952 static const struct GNUNET_SERVER_MessageHandler service_handlers[] = {
2953 /* callback, cls, type, size */
2954 { &service_redirect_to_ip, NULL, GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP, 0},
2955 { &service_redirect_to_service, NULL,
2956 GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE,
2957 sizeof (struct RedirectToServiceRequestMessage) },
2960 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
2961 { &receive_udp_back, GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY, 0},
2962 { &receive_tcp_back, GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN, 0},
2963 { &receive_icmp_back, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN, 0},
2975 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-vpn");
2978 GNUNET_OS_check_helper_binary (binary,
2980 "-d gnunet-vpn - - 169.1.3.3.7 255.255.255.0")) //ipv4 only please!
2982 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2983 "`%s' is not SUID, refusing to run.\n",
2984 "gnunet-helper-vpn");
2985 GNUNET_free (binary);
2987 /* we won't "really" exit here, as the 'service' is still running;
2988 however, as no handlers are registered, the service won't do
2992 GNUNET_free (binary);
2994 stats = GNUNET_STATISTICS_create ("vpn", cfg);
2996 GNUNET_CONFIGURATION_get_value_number (cfg, "VPN", "MAX_MAPPING",
2997 &max_destination_mappings))
2998 max_destination_mappings = 200;
3000 GNUNET_CONFIGURATION_get_value_number (cfg, "VPN", "MAX_TUNNELS",
3001 &max_channel_mappings))
3002 max_channel_mappings = 200;
3004 destination_map = GNUNET_CONTAINER_multihashmap_create (max_destination_mappings * 2, GNUNET_NO);
3005 destination_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3006 channel_map = GNUNET_CONTAINER_multihashmap_create (max_channel_mappings * 2, GNUNET_NO);
3007 channel_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3010 vpn_argv[0] = GNUNET_strdup ("vpn-gnunet");
3011 if (GNUNET_SYSERR ==
3012 GNUNET_CONFIGURATION_get_value_string (cfg, "VPN", "IFNAME", &ifname))
3014 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "VPN", "IFNAME");
3015 GNUNET_SCHEDULER_shutdown ();
3018 vpn_argv[1] = ifname;
3020 if (GNUNET_OK == GNUNET_NETWORK_test_pf (PF_INET6))
3022 if ( (GNUNET_SYSERR ==
3023 GNUNET_CONFIGURATION_get_value_string (cfg, "VPN", "IPV6ADDR",
3025 (1 != inet_pton (AF_INET6, ipv6addr, &v6))) )
3027 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV6ADDR",
3028 _("Must specify valid IPv6 address"));
3029 GNUNET_SCHEDULER_shutdown ();
3030 GNUNET_free_non_null (ipv6addr);
3033 vpn_argv[2] = ipv6addr;
3034 ipv6prefix_s = NULL;
3035 if (GNUNET_SYSERR ==
3036 GNUNET_CONFIGURATION_get_value_string (cfg, "VPN", "IPV6PREFIX",
3039 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV6PREFIX");
3040 GNUNET_SCHEDULER_shutdown ();
3041 GNUNET_free_non_null (ipv6prefix_s);
3044 vpn_argv[3] = ipv6prefix_s;
3046 GNUNET_CONFIGURATION_get_value_number (cfg, "VPN",
3049 (ipv6prefix >= 127) )
3051 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV4MASK",
3052 _("Must specify valid IPv6 mask"));
3053 GNUNET_SCHEDULER_shutdown ();
3059 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3060 _("IPv6 support disabled as this system does not support IPv6\n"));
3061 vpn_argv[2] = GNUNET_strdup ("-");
3062 vpn_argv[3] = GNUNET_strdup ("-");
3064 if (GNUNET_OK == GNUNET_NETWORK_test_pf (PF_INET))
3067 if ( (GNUNET_SYSERR ==
3068 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4ADDR",
3070 (1 != inet_pton (AF_INET, ipv4addr, &v4))) )
3072 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV4ADDR",
3073 _("Must specify valid IPv4 address"));
3074 GNUNET_SCHEDULER_shutdown ();
3075 GNUNET_free_non_null (ipv4addr);
3078 vpn_argv[4] = ipv4addr;
3080 if ( (GNUNET_SYSERR ==
3081 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4MASK",
3083 (1 != inet_pton (AF_INET, ipv4mask, &v4))) )
3085 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV4MASK",
3086 _("Must specify valid IPv4 mask"));
3087 GNUNET_SCHEDULER_shutdown ();
3088 GNUNET_free_non_null (ipv4mask);
3091 vpn_argv[5] = ipv4mask;
3095 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3096 _("IPv4 support disabled as this system does not support IPv4\n"));
3097 vpn_argv[4] = GNUNET_strdup ("-");
3098 vpn_argv[5] = GNUNET_strdup ("-");
3103 GNUNET_CADET_connect (cfg_, NULL,
3106 // FIXME never opens ports???
3107 helper_handle = GNUNET_HELPER_start (GNUNET_NO,
3108 "gnunet-helper-vpn", vpn_argv,
3109 &message_token, NULL, NULL);
3110 nc = GNUNET_SERVER_notification_context_create (server, 1);
3111 GNUNET_SERVER_add_handlers (server, service_handlers);
3112 GNUNET_SCHEDULER_add_shutdown (&cleanup,
3118 * The main function of the VPN service.
3120 * @param argc number of arguments from the command line
3121 * @param argv command line arguments
3122 * @return 0 ok, 1 on error
3125 main (int argc, char *const *argv)
3127 return (GNUNET_OK ==
3128 GNUNET_SERVICE_run (argc, argv, "vpn",
3129 GNUNET_SERVICE_OPTION_NONE,
3130 &run, NULL)) ? global_ret : 1;
3133 /* end of gnunet-service-vpn.c */