2 This file is part of GNUnet.
3 (C) 2010, 2011, 2012 Christian Grothoff
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file vpn/gnunet-service-vpn.c
23 * @brief service that opens a virtual interface and allows its clients
24 * to allocate IPs on the virtual interface and to then redirect
25 * IP traffic received on those IPs via the GNUnet mesh
26 * @author Philipp Toelke
27 * @author Christian Grothoff
30 * - keep multiple peers/mesh tunnels ready as alternative exits /
31 * recover from tunnel-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_mesh_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 mesh.
50 #define MAX_MESSAGE_QUEUE_SIZE 4
56 * State we keep for each of our tunnels.
62 * Information we track for each IP address to determine which tunnel
63 * to send the traffic over to the destination.
65 struct DestinationEntry
69 * Key under which this entry is in the 'destination_map' (only valid
70 * if 'heap_node != NULL').
72 struct GNUNET_HashCode key;
75 * Pre-allocated tunnel for this destination, or NULL for none.
77 struct TunnelState *ts;
80 * Entry for this entry in the destination_heap.
82 struct GNUNET_CONTAINER_HeapNode *heap_node;
85 * GNUNET_NO if this is a tunnel to an Internet-exit,
86 * GNUNET_YES if this tunnel is to a service.
91 * Details about the connection (depending on is_service).
99 * The description of the service (only used for service tunnels).
101 struct GNUNET_HashCode service_descriptor;
104 * Peer offering the service.
106 struct GNUNET_PeerIdentity target;
108 } service_destination;
114 * Address family used (AF_INET or AF_INET6).
119 * IP address of the ultimate destination (only used for exit tunnels).
124 * Address if af is AF_INET.
129 * Address if af is AF_INET6.
142 * A messages we have in queue for a particular tunnel.
144 struct TunnelMessageQueueEntry
147 * This is a doubly-linked list.
149 struct TunnelMessageQueueEntry *next;
152 * This is a doubly-linked list.
154 struct TunnelMessageQueueEntry *prev;
157 * Number of bytes in 'msg'.
162 * Message to transmit, allocated at the end of this struct.
169 * State we keep for each of our tunnels.
175 * Information about the tunnel to use, NULL if no tunnel
176 * is available right now.
178 struct GNUNET_MESH_Tunnel *tunnel;
181 * Active query with REGEX to locate exit.
183 struct GNUNET_REGEX_Search *search;
186 * Active transmission handle, NULL for none.
188 struct GNUNET_MESH_TransmitHandle *th;
191 * Entry for this entry in the tunnel_heap, NULL as long as this
192 * tunnel state is not fully bound.
194 struct GNUNET_CONTAINER_HeapNode *heap_node;
197 * Head of list of messages scheduled for transmission.
199 struct TunnelMessageQueueEntry *tmq_head;
202 * Tail of list of messages scheduled for transmission.
204 struct TunnelMessageQueueEntry *tmq_tail;
207 * Client that needs to be notified about the tunnel being
208 * up as soon as a peer is connected; NULL for none.
210 struct GNUNET_SERVER_Client *client;
213 * Destination entry that has a pointer to this tunnel state;
214 * NULL if this tunnel state is in the tunnel map.
216 struct DestinationEntry *destination_container;
219 * ID of the client request that caused us to setup this entry.
224 * Destination to which this tunnel leads. Note that
225 * this struct is NOT in the destination_map (but a
226 * local copy) and that the 'heap_node' should always
229 struct DestinationEntry destination;
232 * Task scheduled to destroy the tunnel (or NO_TASK).
234 GNUNET_SCHEDULER_TaskIdentifier destroy_task;
237 * Addess family used for this tunnel on the local TUN interface.
242 * Length of the doubly linked 'tmq_head/tmq_tail' list.
244 unsigned int tmq_length;
247 * IPPROTO_TCP or IPPROTO_UDP once bound.
252 * IP address of the source on our end, initially uninitialized.
257 * Address if af is AF_INET.
262 * Address if af is AF_INET6.
269 * Destination IP address used by the source on our end (this is the IP
270 * that we pick freely within the VPN's tunnel IP range).
275 * Address if af is AF_INET.
280 * Address if af is AF_INET6.
287 * Source port used by the sender on our end; 0 for uninitialized.
289 uint16_t source_port;
292 * Destination port used by the sender on our end; 0 for uninitialized.
294 uint16_t destination_port;
300 * Return value from 'main'.
302 static int global_ret;
305 * Configuration we use.
307 static const struct GNUNET_CONFIGURATION_Handle *cfg;
310 * Handle to the mesh service.
312 static struct GNUNET_MESH_Handle *mesh_handle;
315 * Map from IP address to destination information (possibly with a
316 * MESH tunnel handle for fast setup).
318 static struct GNUNET_CONTAINER_MultiHashMap *destination_map;
321 * Min-Heap sorted by activity time to expire old mappings.
323 static struct GNUNET_CONTAINER_Heap *destination_heap;
326 * Map from source and destination address (IP+port) to connection
327 * information (mostly with the respective MESH tunnel handle).
329 static struct GNUNET_CONTAINER_MultiHashMap *tunnel_map;
332 * Min-Heap sorted by activity time to expire old mappings; values are
333 * of type 'struct TunnelState'.
335 static struct GNUNET_CONTAINER_Heap *tunnel_heap;
340 static struct GNUNET_STATISTICS_Handle *stats;
343 * The handle to the VPN helper process "gnunet-helper-vpn".
345 static struct GNUNET_HELPER_Handle *helper_handle;
348 * Arguments to the vpn helper.
350 static char *vpn_argv[7];
353 * Length of the prefix of the VPN's IPv6 network.
355 static unsigned long long ipv6prefix;
358 * Notification context for sending replies to clients.
360 static struct GNUNET_SERVER_NotificationContext *nc;
363 * If there are more than this number of address-mappings, old ones
366 static unsigned long long max_destination_mappings;
369 * If there are more than this number of open tunnels, old ones
372 static unsigned long long max_tunnel_mappings;
376 * Compute the key under which we would store an entry in the
377 * destination_map for the given IP address.
379 * @param af address family (AF_INET or AF_INET6)
380 * @param address IP address, struct in_addr or struct in6_addr
381 * @param key where to store the key
384 get_destination_key_from_ip (int af,
386 struct GNUNET_HashCode *key)
391 GNUNET_CRYPTO_hash (address,
392 sizeof (struct in_addr),
396 GNUNET_CRYPTO_hash (address,
397 sizeof (struct in6_addr),
408 * Compute the key under which we would store an entry in the
409 * tunnel_map for the given socket address pair.
411 * @param af address family (AF_INET or AF_INET6)
412 * @param protocol IPPROTO_TCP or IPPROTO_UDP
413 * @param source_ip sender's source IP, struct in_addr or struct in6_addr
414 * @param source_port sender's source port
415 * @param destination_ip sender's destination IP, struct in_addr or struct in6_addr
416 * @param destination_port sender's destination port
417 * @param key where to store the key
420 get_tunnel_key_from_ips (int af,
422 const void *source_ip,
423 uint16_t source_port,
424 const void *destination_ip,
425 uint16_t destination_port,
426 struct GNUNET_HashCode *key)
430 memset (key, 0, sizeof (struct GNUNET_HashCode));
431 /* the GNUnet hashmap only uses the first sizeof(unsigned int) of the hash,
432 so we put the ports in there (and hope for few collisions) */
434 memcpy (off, &source_port, sizeof (uint16_t));
435 off += sizeof (uint16_t);
436 memcpy (off, &destination_port, sizeof (uint16_t));
437 off += sizeof (uint16_t);
441 memcpy (off, source_ip, sizeof (struct in_addr));
442 off += sizeof (struct in_addr);
443 memcpy (off, destination_ip, sizeof (struct in_addr));
444 off += sizeof (struct in_addr);
447 memcpy (off, source_ip, sizeof (struct in6_addr));
448 off += sizeof (struct in6_addr);
449 memcpy (off, destination_ip, sizeof (struct in6_addr));
450 off += sizeof (struct in6_addr);
456 memcpy (off, &protocol, sizeof (uint8_t));
457 off += sizeof (uint8_t);
462 * Notify the client about the result of its request.
464 * @param client client to notify
465 * @param request_id original request ID to include in response
466 * @param result_af resulting address family
467 * @param addr resulting IP address
470 send_client_reply (struct GNUNET_SERVER_Client *client,
475 char buf[sizeof (struct RedirectToIpResponseMessage) + sizeof (struct in6_addr)] GNUNET_ALIGN;
476 struct RedirectToIpResponseMessage *res;
482 rlen = sizeof (struct in_addr);
485 rlen = sizeof (struct in6_addr);
494 res = (struct RedirectToIpResponseMessage *) buf;
495 res->header.size = htons (sizeof (struct RedirectToIpResponseMessage) + rlen);
496 res->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP);
497 res->result_af = htonl (result_af);
498 res->request_id = request_id;
499 memcpy (&res[1], addr, rlen);
500 GNUNET_SERVER_notification_context_add (nc, client);
501 GNUNET_SERVER_notification_context_unicast (nc,
509 * Free resources associated with a tunnel state.
511 * @param ts state to free
514 free_tunnel_state (struct TunnelState *ts)
516 struct GNUNET_HashCode key;
517 struct TunnelMessageQueueEntry *tnq;
518 struct GNUNET_MESH_Tunnel *tunnel;
520 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
521 "Cleaning up tunnel state\n");
522 GNUNET_STATISTICS_update (stats,
523 gettext_noop ("# Active tunnels"),
525 while (NULL != (tnq = ts->tmq_head))
527 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
533 GNUNET_assert (0 == ts->tmq_length);
536 GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
539 GNUNET_assert (NULL == ts->destination.heap_node);
540 if (NULL != (tunnel = ts->tunnel))
543 GNUNET_MESH_tunnel_destroy (tunnel);
545 if (NULL != ts->search)
547 GNUNET_REGEX_search_cancel (ts->search);
550 if (GNUNET_SCHEDULER_NO_TASK != ts->destroy_task)
552 GNUNET_SCHEDULER_cancel (ts->destroy_task);
553 ts->destroy_task = GNUNET_SCHEDULER_NO_TASK;
555 if (NULL != ts->heap_node)
557 GNUNET_CONTAINER_heap_remove_node (ts->heap_node);
558 ts->heap_node = NULL;
559 get_tunnel_key_from_ips (ts->af,
564 ts->destination_port,
566 GNUNET_assert (GNUNET_YES ==
567 GNUNET_CONTAINER_multihashmap_remove (tunnel_map,
571 if (NULL != ts->destination_container)
573 GNUNET_assert (ts == ts->destination_container->ts);
574 ts->destination_container->ts = NULL;
575 ts->destination_container = NULL;
582 * Destroy the mesh tunnel.
584 * @param cls the 'struct TunnelState' with the tunnel to destroy
585 * @param tc scheduler context
588 destroy_tunnel_task (void *cls,
589 const struct GNUNET_SCHEDULER_TaskContext *tc)
591 struct TunnelState *ts = cls;
592 struct GNUNET_MESH_Tunnel *tunnel;
594 ts->destroy_task = GNUNET_SCHEDULER_NO_TASK;
595 GNUNET_assert (NULL != ts->tunnel);
598 GNUNET_MESH_tunnel_destroy (tunnel);
599 free_tunnel_state (ts);
604 * Method called whenever a peer has disconnected from the tunnel.
606 * FIXME merge with inbound_cleaner
609 * @param peer peer identity the tunnel stopped working with
612 tunnel_peer_disconnect_handler (void *cls,
614 GNUNET_PeerIdentity * peer)
616 struct TunnelState *ts = cls;
618 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
619 "Peer %s disconnected from tunnel.\n",
621 GNUNET_STATISTICS_update (stats,
622 gettext_noop ("# peers connected to mesh tunnels"),
626 GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
629 if (ts->destination.is_service)
630 return; /* hope for reconnect eventually */
631 /* as we are most likely going to change the exit node now,
632 we should just destroy the tunnel entirely... */
633 if (GNUNET_SCHEDULER_NO_TASK == ts->destroy_task)
634 ts->destroy_task = GNUNET_SCHEDULER_add_now (&destroy_tunnel_task, ts);
639 * Method called whenever a peer has connected to the tunnel. Notifies
640 * the waiting client that the tunnel is now up.
642 * FIXME merge with tunnel_create
645 * @param peer peer identity the tunnel was created to, NULL on timeout
646 * @param atsi performance data for the connection
649 tunnel_peer_connect_handler (void *cls,
650 const struct GNUNET_PeerIdentity
653 GNUNET_ATS_Information * atsi)
655 struct TunnelState *ts = cls;
657 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
658 "Peer %s connected to tunnel.\n",
660 GNUNET_STATISTICS_update (stats,
661 gettext_noop ("# peers connected to mesh tunnels"),
663 if (NULL == ts->client)
664 return; /* nothing to do */
665 send_client_reply (ts->client,
668 &ts->destination_ip);
674 * Send a message from the message queue via mesh.
676 * @param cls the 'struct TunnelState' with the message queue
677 * @param size number of bytes available in buf
678 * @param buf where to copy the message
679 * @return number of bytes copied to buf
682 send_to_peer_notify_callback (void *cls, size_t size, void *buf)
684 struct TunnelState *ts = cls;
685 struct TunnelMessageQueueEntry *tnq;
692 GNUNET_assert (NULL != tnq);
693 GNUNET_assert (size >= tnq->len);
694 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
695 "Sending %u bytes via mesh tunnel\n",
697 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
701 memcpy (buf, tnq->msg, tnq->len);
704 if (NULL != (tnq = ts->tmq_head))
705 ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel,
706 GNUNET_NO /* cork */,
707 GNUNET_TIME_UNIT_FOREVER_REL,
709 &send_to_peer_notify_callback,
711 GNUNET_STATISTICS_update (stats,
712 gettext_noop ("# Bytes given to mesh for transmission"),
719 * Add the given message to the given tunnel and trigger the
720 * transmission process.
722 * @param tnq message to queue
723 * @param ts tunnel to queue the message for
726 send_to_tunnel (struct TunnelMessageQueueEntry *tnq,
727 struct TunnelState *ts)
729 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
730 "Queueing %u bytes for transmission via mesh tunnel\n",
732 GNUNET_assert (NULL != ts->tunnel);
733 GNUNET_CONTAINER_DLL_insert_tail (ts->tmq_head,
737 if (ts->tmq_length > MAX_MESSAGE_QUEUE_SIZE)
739 struct TunnelMessageQueueEntry *dq;
742 GNUNET_assert (dq != tnq);
743 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
747 GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
749 GNUNET_STATISTICS_update (stats,
750 gettext_noop ("# Bytes dropped in mesh queue (overflow)"),
756 ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel,
757 GNUNET_NO /* cork */,
758 GNUNET_TIME_UNIT_FOREVER_REL,
760 &send_to_peer_notify_callback,
766 * Regex has found a potential exit peer for us; consider using it.
768 * @param cls the 'struct TunnelState'
769 * @param id Peer providing a regex that matches the string.
770 * @param get_path Path of the get request.
771 * @param get_path_length Lenght of get_path.
772 * @param put_path Path of the put request.
773 * @param put_path_length Length of the put_path.
776 handle_regex_result (void *cls,
777 const struct GNUNET_PeerIdentity *id,
778 const struct GNUNET_PeerIdentity *get_path,
779 unsigned int get_path_length,
780 const struct GNUNET_PeerIdentity *put_path,
781 unsigned int put_path_length)
783 struct TunnelState *ts = cls;
785 GNUNET_REGEX_search_cancel (ts->search);
787 ts->tunnel = GNUNET_MESH_tunnel_create (mesh_handle,
795 * Initialize the given destination entry's mesh tunnel.
797 * @param de destination entry for which we need to setup a tunnel
798 * @param client client to notify on successful tunnel setup, or NULL for none
799 * @param client_af address family of the address returned to the client
800 * @param request_id request ID to send in client notification (unused if client is NULL)
801 * @return tunnel state of the tunnel that was created
803 static struct TunnelState *
804 create_tunnel_to_destination (struct DestinationEntry *de,
805 struct GNUNET_SERVER_Client *client,
809 struct TunnelState *ts;
811 GNUNET_STATISTICS_update (stats,
812 gettext_noop ("# Mesh tunnels created"),
814 GNUNET_assert (NULL == de->ts);
815 ts = GNUNET_malloc (sizeof (struct TunnelState));
819 ts->request_id = request_id;
822 ts->destination = *de;
823 ts->destination.heap_node = NULL; /* copy is NOT in destination heap */
825 ts->destination_container = de; /* we are referenced from de */
828 ts->tunnel = GNUNET_MESH_tunnel_create (mesh_handle,
830 &de->details.service_destination.target,
832 if (NULL == ts->tunnel)
834 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
835 _("Failed to setup mesh tunnel!\n"));
839 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
840 "Creating tunnel to peer %s offering service %s\n",
841 GNUNET_i2s (&de->details.service_destination.target),
842 GNUNET_h2s (&de->details.service_destination.service_descriptor));
848 switch (de->details.exit_destination.af)
852 char address[GNUNET_TUN_IPV4_REGEXLEN];
854 GNUNET_TUN_ipv4toregex (&de->details.exit_destination.ip.v4,
855 "255.255.255.255", address);
856 GNUNET_asprintf (&policy, "%s%s%s",
857 GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
864 char address[GNUNET_TUN_IPV6_REGEXLEN];
866 GNUNET_TUN_ipv6toregex (&de->details.exit_destination.ip.v6,
868 GNUNET_asprintf (&policy, "%s%s%s",
869 GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
879 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
880 "Requesting connect by string: %s\n",
882 ts->search = GNUNET_REGEX_search (cfg,
884 &handle_regex_result,
886 GNUNET_free (policy);
893 * We have too many active tunnels. Clean up the oldest tunnel.
895 * @param except tunnel that must NOT be cleaned up, even if it is the oldest
898 expire_tunnel (struct TunnelState *except)
900 struct TunnelState *ts;
902 ts = GNUNET_CONTAINER_heap_peek (tunnel_heap);
903 GNUNET_assert (NULL != ts);
905 return; /* can't do this */
906 free_tunnel_state (ts);
911 * Route a packet via mesh to the given destination.
913 * @param destination description of the destination
914 * @param af address family on this end (AF_INET or AF_INET6)
915 * @param protocol IPPROTO_TCP or IPPROTO_UDP or IPPROTO_ICMP or IPPROTO_ICMPV6
916 * @param source_ip source IP used by the sender (struct in_addr or struct in6_addr)
917 * @param destination_ip destination IP used by the sender (struct in_addr or struct in6_addr)
918 * @param payload payload of the packet after the IP header
919 * @param payload_length number of bytes in payload
922 route_packet (struct DestinationEntry *destination,
925 const void *source_ip,
926 const void *destination_ip,
928 size_t payload_length)
930 struct GNUNET_HashCode key;
931 struct TunnelState *ts;
932 struct TunnelMessageQueueEntry *tnq;
936 const struct GNUNET_TUN_UdpHeader *udp;
937 const struct GNUNET_TUN_TcpHeader *tcp;
938 const struct GNUNET_TUN_IcmpHeader *icmp;
939 uint16_t source_port;
940 uint16_t destination_port;
946 if (payload_length < sizeof (struct GNUNET_TUN_UdpHeader))
952 tcp = NULL; /* make compiler happy */
953 icmp = NULL; /* make compiler happy */
955 if (udp->len < sizeof (struct GNUNET_TUN_UdpHeader))
960 source_port = ntohs (udp->source_port);
961 destination_port = ntohs (udp->destination_port);
962 get_tunnel_key_from_ips (af,
973 if (payload_length < sizeof (struct GNUNET_TUN_TcpHeader))
979 udp = NULL; /* make compiler happy */
980 icmp = NULL; /* make compiler happy */
982 if (tcp->off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
987 source_port = ntohs (tcp->source_port);
988 destination_port = ntohs (tcp->destination_port);
989 get_tunnel_key_from_ips (af,
1001 if ( (AF_INET == af) ^ (protocol == IPPROTO_ICMP) )
1006 if (payload_length < sizeof (struct GNUNET_TUN_IcmpHeader))
1012 tcp = NULL; /* make compiler happy */
1013 udp = NULL; /* make compiler happy */
1016 destination_port = 0;
1017 get_tunnel_key_from_ips (af,
1027 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1028 _("Protocol %u not supported, dropping\n"),
1029 (unsigned int) protocol);
1032 if (! destination->is_service)
1034 switch (destination->details.exit_destination.af)
1037 alen = sizeof (struct in_addr);
1040 alen = sizeof (struct in6_addr);
1048 char sbuf[INET6_ADDRSTRLEN];
1049 char dbuf[INET6_ADDRSTRLEN];
1050 char xbuf[INET6_ADDRSTRLEN];
1052 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1053 "Routing %s packet from %s:%u -> %s:%u to destination %s:%u\n",
1054 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
1055 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
1057 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
1059 inet_ntop (destination->details.exit_destination.af,
1060 &destination->details.exit_destination.ip,
1061 xbuf, sizeof (xbuf)),
1067 /* make compiler happy */
1070 char sbuf[INET6_ADDRSTRLEN];
1071 char dbuf[INET6_ADDRSTRLEN];
1073 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1074 "Routing %s packet from %s:%u -> %s:%u to service %s at peer %s\n",
1075 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
1076 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
1078 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
1080 GNUNET_h2s (&destination->details.service_destination.service_descriptor),
1081 GNUNET_i2s (&destination->details.service_destination.target));
1086 /* see if we have an existing tunnel for this destination */
1087 ts = GNUNET_CONTAINER_multihashmap_get (tunnel_map,
1091 /* need to either use the existing tunnel from the destination (if still
1092 available) or create a fresh one */
1093 is_new = GNUNET_YES;
1094 if (NULL == destination->ts)
1095 ts = create_tunnel_to_destination (destination, NULL, af, 0);
1097 ts = destination->ts;
1100 destination->ts = NULL;
1101 ts->destination_container = NULL; /* no longer 'contained' */
1102 /* now bind existing "unbound" tunnel to our IP/port tuple */
1103 ts->protocol = protocol;
1107 ts->source_ip.v4 = * (const struct in_addr *) source_ip;
1108 ts->destination_ip.v4 = * (const struct in_addr *) destination_ip;
1112 ts->source_ip.v6 = * (const struct in6_addr *) source_ip;
1113 ts->destination_ip.v6 = * (const struct in6_addr *) destination_ip;
1115 ts->source_port = source_port;
1116 ts->destination_port = destination_port;
1117 ts->heap_node = GNUNET_CONTAINER_heap_insert (tunnel_heap,
1119 GNUNET_TIME_absolute_get ().abs_value);
1120 GNUNET_assert (GNUNET_YES ==
1121 GNUNET_CONTAINER_multihashmap_put (tunnel_map,
1124 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1125 GNUNET_STATISTICS_update (stats,
1126 gettext_noop ("# Active tunnels"),
1128 while (GNUNET_CONTAINER_multihashmap_size (tunnel_map) > max_tunnel_mappings)
1134 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
1136 GNUNET_TIME_absolute_get ().abs_value);
1138 GNUNET_assert (NULL != ts->tunnel);
1140 /* send via tunnel */
1144 if (destination->is_service)
1146 struct GNUNET_EXIT_UdpServiceMessage *usm;
1148 mlen = sizeof (struct GNUNET_EXIT_UdpServiceMessage) +
1149 payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1150 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1155 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1158 usm = (struct GNUNET_EXIT_UdpServiceMessage *) &tnq[1];
1159 usm->header.size = htons ((uint16_t) mlen);
1160 usm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE);
1161 /* if the source port is below 32000, we assume it has a special
1162 meaning; if not, we pick a random port (this is a heuristic) */
1163 usm->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1164 usm->destination_port = udp->destination_port;
1165 usm->service_descriptor = destination->details.service_destination.service_descriptor;
1168 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1172 struct GNUNET_EXIT_UdpInternetMessage *uim;
1173 struct in_addr *ip4dst;
1174 struct in6_addr *ip6dst;
1177 mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) +
1178 alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1179 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1184 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) +
1188 uim = (struct GNUNET_EXIT_UdpInternetMessage *) &tnq[1];
1189 uim->header.size = htons ((uint16_t) mlen);
1190 uim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET);
1191 uim->af = htonl (destination->details.exit_destination.af);
1192 uim->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1193 uim->destination_port = udp->destination_port;
1194 switch (destination->details.exit_destination.af)
1197 ip4dst = (struct in_addr *) &uim[1];
1198 *ip4dst = destination->details.exit_destination.ip.v4;
1199 payload = &ip4dst[1];
1202 ip6dst = (struct in6_addr *) &uim[1];
1203 *ip6dst = destination->details.exit_destination.ip.v6;
1204 payload = &ip6dst[1];
1211 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1217 if (destination->is_service)
1219 struct GNUNET_EXIT_TcpServiceStartMessage *tsm;
1221 mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) +
1222 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1223 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1228 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1231 tsm = (struct GNUNET_EXIT_TcpServiceStartMessage *) &tnq[1];
1232 tsm->header.size = htons ((uint16_t) mlen);
1233 tsm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START);
1234 tsm->reserved = htonl (0);
1235 tsm->service_descriptor = destination->details.service_destination.service_descriptor;
1236 tsm->tcp_header = *tcp;
1239 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1243 struct GNUNET_EXIT_TcpInternetStartMessage *tim;
1244 struct in_addr *ip4dst;
1245 struct in6_addr *ip6dst;
1248 mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) +
1249 alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1250 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1255 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1258 tim = (struct GNUNET_EXIT_TcpInternetStartMessage *) &tnq[1];
1259 tim->header.size = htons ((uint16_t) mlen);
1260 tim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START);
1261 tim->af = htonl (destination->details.exit_destination.af);
1262 tim->tcp_header = *tcp;
1263 switch (destination->details.exit_destination.af)
1266 ip4dst = (struct in_addr *) &tim[1];
1267 *ip4dst = destination->details.exit_destination.ip.v4;
1268 payload = &ip4dst[1];
1271 ip6dst = (struct in6_addr *) &tim[1];
1272 *ip6dst = destination->details.exit_destination.ip.v6;
1273 payload = &ip6dst[1];
1280 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1285 struct GNUNET_EXIT_TcpDataMessage *tdm;
1287 mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) +
1288 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1289 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1294 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1297 tdm = (struct GNUNET_EXIT_TcpDataMessage *) &tnq[1];
1298 tdm->header.size = htons ((uint16_t) mlen);
1299 tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT);
1300 tdm->reserved = htonl (0);
1301 tdm->tcp_header = *tcp;
1304 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1308 case IPPROTO_ICMPV6:
1309 if (destination->is_service)
1311 struct GNUNET_EXIT_IcmpServiceMessage *ism;
1313 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1314 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1315 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1320 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1322 ism = (struct GNUNET_EXIT_IcmpServiceMessage *) &tnq[1];
1323 ism->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE);
1324 ism->af = htonl (af); /* need to tell destination ICMP protocol family! */
1325 ism->service_descriptor = destination->details.service_destination.service_descriptor;
1326 ism->icmp_header = *icmp;
1327 /* ICMP protocol translation will be done by the receiver (as we don't know
1328 the target AF); however, we still need to possibly discard the payload
1329 depending on the ICMP type */
1335 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1336 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1338 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1339 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1340 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1341 /* throw away ICMP payload, won't be useful for the other side anyway */
1342 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1345 GNUNET_STATISTICS_update (stats,
1346 gettext_noop ("# ICMPv4 packets dropped (not allowed)"),
1350 /* end of AF_INET */
1355 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1356 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1357 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1358 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1359 /* throw away ICMP payload, won't be useful for the other side anyway */
1360 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1362 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1363 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1366 GNUNET_STATISTICS_update (stats,
1367 gettext_noop ("# ICMPv6 packets dropped (not allowed)"),
1371 /* end of AF_INET6 */
1378 /* update length calculations, as payload_length may have changed */
1379 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1380 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1382 ism->header.size = htons ((uint16_t) mlen);
1383 /* finally, copy payload (if there is any left...) */
1386 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1390 struct GNUNET_EXIT_IcmpInternetMessage *iim;
1391 struct in_addr *ip4dst;
1392 struct in6_addr *ip6dst;
1395 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1396 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1397 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1402 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) +
1405 iim = (struct GNUNET_EXIT_IcmpInternetMessage *) &tnq[1];
1406 iim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET);
1407 iim->icmp_header = *icmp;
1408 /* Perform ICMP protocol-translation (depending on destination AF and source AF)
1409 and throw away ICMP payload depending on ICMP message type */
1415 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1416 if (destination->details.exit_destination.af == AF_INET6)
1417 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1419 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1420 if (destination->details.exit_destination.af == AF_INET6)
1421 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1423 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1424 if (destination->details.exit_destination.af == AF_INET6)
1425 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1426 /* throw away IP-payload, exit will have to make it up anyway */
1427 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1429 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1430 if (destination->details.exit_destination.af == AF_INET6)
1431 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1432 /* throw away IP-payload, exit will have to make it up anyway */
1433 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1435 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1436 if (destination->details.exit_destination.af == AF_INET6)
1438 GNUNET_STATISTICS_update (stats,
1439 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1444 /* throw away IP-payload, exit will have to make it up anyway */
1445 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1448 GNUNET_STATISTICS_update (stats,
1449 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1454 /* end of AF_INET */
1459 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1460 if (destination->details.exit_destination.af == AF_INET6)
1461 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1462 /* throw away IP-payload, exit will have to make it up anyway */
1463 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1465 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1466 if (destination->details.exit_destination.af == AF_INET)
1467 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1468 /* throw away IP-payload, exit will have to make it up anyway */
1469 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1471 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1472 if (destination->details.exit_destination.af == AF_INET)
1474 GNUNET_STATISTICS_update (stats,
1475 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1480 /* throw away IP-payload, exit will have to make it up anyway */
1481 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1483 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1484 if (destination->details.exit_destination.af == AF_INET)
1486 GNUNET_STATISTICS_update (stats,
1487 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1492 /* throw away IP-payload, exit will have to make it up anyway */
1493 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1495 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1496 if (destination->details.exit_destination.af == AF_INET)
1497 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1499 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1500 if (destination->details.exit_destination.af == AF_INET)
1501 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1504 GNUNET_STATISTICS_update (stats,
1505 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1510 /* end of AF_INET6 */
1515 /* update length calculations, as payload_length may have changed */
1516 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1517 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1519 iim->header.size = htons ((uint16_t) mlen);
1521 /* need to tell destination ICMP protocol family! */
1522 iim->af = htonl (destination->details.exit_destination.af);
1523 switch (destination->details.exit_destination.af)
1526 ip4dst = (struct in_addr *) &iim[1];
1527 *ip4dst = destination->details.exit_destination.ip.v4;
1528 payload = &ip4dst[1];
1531 ip6dst = (struct in6_addr *) &iim[1];
1532 *ip6dst = destination->details.exit_destination.ip.v6;
1533 payload = &ip6dst[1];
1540 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1544 /* not supported above, how can we get here !? */
1548 send_to_tunnel (tnq, ts);
1553 * Receive packets from the helper-process (someone send to the local
1554 * virtual tunnel interface). Find the destination mapping, and if it
1555 * exists, identify the correct MESH tunnel (or possibly create it)
1556 * and forward the packet.
1558 * @param cls closure, NULL
1559 * @param client NULL
1560 * @param message message we got from the client (VPN tunnel interface)
1563 message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED,
1564 const struct GNUNET_MessageHeader *message)
1566 const struct GNUNET_TUN_Layer2PacketHeader *tun;
1568 struct GNUNET_HashCode key;
1569 struct DestinationEntry *de;
1571 GNUNET_STATISTICS_update (stats,
1572 gettext_noop ("# Packets received from TUN interface"),
1574 mlen = ntohs (message->size);
1575 if ( (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
1576 (mlen < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader)) )
1581 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1582 mlen -= (sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader));
1583 switch (ntohs (tun->proto))
1587 const struct GNUNET_TUN_IPv6Header *pkt6;
1589 if (mlen < sizeof (struct GNUNET_TUN_IPv6Header))
1595 pkt6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1596 get_destination_key_from_ip (AF_INET6,
1597 &pkt6->destination_address,
1599 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1600 /* FIXME: do we need to guard against hash collision?
1601 (if so, we need to also store the local destination IP in the
1602 destination entry and then compare here; however, the risk
1603 of collision seems minimal AND the impact is unlikely to be
1604 super-problematic as well... */
1607 char buf[INET6_ADDRSTRLEN];
1609 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1610 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1611 inet_ntop (AF_INET6,
1612 &pkt6->destination_address,
1620 &pkt6->source_address,
1621 &pkt6->destination_address,
1623 mlen - sizeof (struct GNUNET_TUN_IPv6Header));
1628 struct GNUNET_TUN_IPv4Header *pkt4;
1630 if (mlen < sizeof (struct GNUNET_TUN_IPv4Header))
1636 pkt4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1637 get_destination_key_from_ip (AF_INET,
1638 &pkt4->destination_address,
1640 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1641 /* FIXME: do we need to guard against hash collision?
1642 (if so, we need to also store the local destination IP in the
1643 destination entry and then compare here; however, the risk
1644 of collision seems minimal AND the impact is unlikely to be
1645 super-problematic as well... */
1648 char buf[INET_ADDRSTRLEN];
1650 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1651 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1653 &pkt4->destination_address,
1658 if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header))
1660 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1661 _("Received IPv4 packet with options (dropping it)\n"));
1667 &pkt4->source_address,
1668 &pkt4->destination_address,
1670 mlen - sizeof (struct GNUNET_TUN_IPv4Header));
1674 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1675 _("Received packet of unknown protocol %d from TUN (dropping it)\n"),
1676 (unsigned int) ntohs (tun->proto));
1684 * Synthesize a plausible ICMP payload for an ICMP error
1685 * response on the given tunnel.
1687 * @param ts tunnel information
1688 * @param ipp IPv4 header to fill in (ICMP payload)
1689 * @param udp "UDP" header to fill in (ICMP payload); might actually
1690 * also be the first 8 bytes of the TCP header
1693 make_up_icmpv4_payload (struct TunnelState *ts,
1694 struct GNUNET_TUN_IPv4Header *ipp,
1695 struct GNUNET_TUN_UdpHeader *udp)
1697 GNUNET_TUN_initialize_ipv4_header (ipp,
1699 sizeof (struct GNUNET_TUN_TcpHeader),
1701 &ts->destination_ip.v4);
1702 udp->source_port = htons (ts->source_port);
1703 udp->destination_port = htons (ts->destination_port);
1704 udp->len = htons (0);
1705 udp->crc = htons (0);
1710 * Synthesize a plausible ICMP payload for an ICMP error
1711 * response on the given tunnel.
1713 * @param ts tunnel information
1714 * @param ipp IPv6 header to fill in (ICMP payload)
1715 * @param udp "UDP" header to fill in (ICMP payload); might actually
1716 * also be the first 8 bytes of the TCP header
1719 make_up_icmpv6_payload (struct TunnelState *ts,
1720 struct GNUNET_TUN_IPv6Header *ipp,
1721 struct GNUNET_TUN_UdpHeader *udp)
1723 GNUNET_TUN_initialize_ipv6_header (ipp,
1725 sizeof (struct GNUNET_TUN_TcpHeader),
1727 &ts->destination_ip.v6);
1728 udp->source_port = htons (ts->source_port);
1729 udp->destination_port = htons (ts->destination_port);
1730 udp->len = htons (0);
1731 udp->crc = htons (0);
1736 * We got an ICMP packet back from the MESH tunnel. Pass it on to the
1737 * local virtual interface via the helper.
1739 * @param cls closure, NULL
1740 * @param tunnel connection to the other end
1741 * @param tunnel_ctx pointer to our 'struct TunnelState *'
1742 * @param message the actual message
1744 * @return GNUNET_OK to keep the connection open,
1745 * GNUNET_SYSERR to close it (signal serious error)
1748 receive_icmp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1750 const struct GNUNET_MessageHeader *message)
1752 struct TunnelState *ts = *tunnel_ctx;
1753 const struct GNUNET_EXIT_IcmpToVPNMessage *i2v;
1756 GNUNET_STATISTICS_update (stats,
1757 gettext_noop ("# ICMP packets received from mesh"),
1759 mlen = ntohs (message->size);
1760 if (mlen < sizeof (struct GNUNET_EXIT_IcmpToVPNMessage))
1762 GNUNET_break_op (0);
1763 return GNUNET_SYSERR;
1765 if (NULL == ts->heap_node)
1767 GNUNET_break_op (0);
1768 return GNUNET_SYSERR;
1770 if (AF_UNSPEC == ts->af)
1772 GNUNET_break_op (0);
1773 return GNUNET_SYSERR;
1775 i2v = (const struct GNUNET_EXIT_IcmpToVPNMessage *) message;
1776 mlen -= sizeof (struct GNUNET_EXIT_IcmpToVPNMessage);
1778 char sbuf[INET6_ADDRSTRLEN];
1779 char dbuf[INET6_ADDRSTRLEN];
1781 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1782 "Received ICMP packet from mesh, sending %u bytes from %s -> %s via TUN\n",
1783 (unsigned int) mlen,
1784 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
1785 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)));
1791 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
1792 + sizeof (struct GNUNET_TUN_IcmpHeader)
1793 + sizeof (struct GNUNET_MessageHeader) +
1794 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1797 /* reserve some extra space in case we have an ICMP type here where
1798 we will need to make up the payload ourselves */
1799 char buf[size + sizeof (struct GNUNET_TUN_IPv4Header) + 8] GNUNET_ALIGN;
1800 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1801 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1802 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1803 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv4[1];
1804 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1805 tun->flags = htons (0);
1806 tun->proto = htons (ETH_P_IPV4);
1807 GNUNET_TUN_initialize_ipv4_header (ipv4,
1809 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1810 &ts->destination_ip.v4,
1812 *icmp = i2v->icmp_header;
1816 /* For some ICMP types, we need to adjust (make up) the payload here.
1817 Also, depending on the AF used on the other side, we have to
1818 do ICMP PT (translate ICMP types) */
1819 switch (ntohl (i2v->af))
1824 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1825 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1827 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1828 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1829 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1831 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1832 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1836 /* sender did not strip ICMP payload? */
1837 GNUNET_break_op (0);
1838 return GNUNET_SYSERR;
1840 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1841 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1842 make_up_icmpv4_payload (ts, ipp, udp);
1846 GNUNET_break_op (0);
1847 GNUNET_STATISTICS_update (stats,
1848 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1850 return GNUNET_SYSERR;
1855 /* ICMP PT 6-to-4 and possibly making up payloads */
1858 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1859 icmp->type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
1861 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1862 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1866 /* sender did not strip ICMP payload? */
1867 GNUNET_break_op (0);
1868 return GNUNET_SYSERR;
1870 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1871 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1872 make_up_icmpv4_payload (ts, ipp, udp);
1875 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1876 icmp->type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1878 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1879 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1883 /* sender did not strip ICMP payload? */
1884 GNUNET_break_op (0);
1885 return GNUNET_SYSERR;
1887 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1888 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1889 make_up_icmpv4_payload (ts, ipp, udp);
1892 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1893 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1894 GNUNET_STATISTICS_update (stats,
1895 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1898 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1899 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1901 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1902 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1905 GNUNET_break_op (0);
1906 GNUNET_STATISTICS_update (stats,
1907 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1909 return GNUNET_SYSERR;
1914 GNUNET_break_op (0);
1915 return GNUNET_SYSERR;
1917 msg->size = htons (size);
1918 GNUNET_TUN_calculate_icmp_checksum (icmp,
1921 (void) GNUNET_HELPER_send (helper_handle,
1930 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
1931 + sizeof (struct GNUNET_TUN_IcmpHeader)
1932 + sizeof (struct GNUNET_MessageHeader) +
1933 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1936 char buf[size + sizeof (struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN;
1937 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1938 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1939 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
1940 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv6[1];
1941 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1942 tun->flags = htons (0);
1943 tun->proto = htons (ETH_P_IPV6);
1944 GNUNET_TUN_initialize_ipv6_header (ipv6,
1946 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1947 &ts->destination_ip.v6,
1949 *icmp = i2v->icmp_header;
1954 /* For some ICMP types, we need to adjust (make up) the payload here.
1955 Also, depending on the AF used on the other side, we have to
1956 do ICMP PT (translate ICMP types) */
1957 switch (ntohl (i2v->af))
1960 /* ICMP PT 4-to-6 and possibly making up payloads */
1963 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1964 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1966 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1967 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1969 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1970 icmp->type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1972 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1973 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1977 /* sender did not strip ICMP payload? */
1978 GNUNET_break_op (0);
1979 return GNUNET_SYSERR;
1981 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1982 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1983 make_up_icmpv6_payload (ts, ipp, udp);
1986 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1987 icmp->type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1989 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1990 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1994 /* sender did not strip ICMP payload? */
1995 GNUNET_break_op (0);
1996 return GNUNET_SYSERR;
1998 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1999 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
2000 make_up_icmpv6_payload (ts, ipp, udp);
2003 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
2004 GNUNET_STATISTICS_update (stats,
2005 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
2009 GNUNET_break_op (0);
2010 GNUNET_STATISTICS_update (stats,
2011 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
2013 return GNUNET_SYSERR;
2020 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
2021 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
2022 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
2023 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
2025 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
2026 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
2030 /* sender did not strip ICMP payload? */
2031 GNUNET_break_op (0);
2032 return GNUNET_SYSERR;
2034 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
2035 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
2036 make_up_icmpv6_payload (ts, ipp, udp);
2039 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
2042 GNUNET_break_op (0);
2043 GNUNET_STATISTICS_update (stats,
2044 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
2046 return GNUNET_SYSERR;
2051 GNUNET_break_op (0);
2052 return GNUNET_SYSERR;
2054 msg->size = htons (size);
2055 GNUNET_TUN_calculate_icmp_checksum (icmp,
2057 (void) GNUNET_HELPER_send (helper_handle,
2067 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2069 GNUNET_TIME_absolute_get ().abs_value);
2075 * We got a UDP packet back from the MESH tunnel. Pass it on to the
2076 * local virtual interface via the helper.
2078 * @param cls closure, NULL
2079 * @param tunnel connection to the other end
2080 * @param tunnel_ctx pointer to our 'struct TunnelState *'
2081 * @param message the actual message
2083 * @return GNUNET_OK to keep the connection open,
2084 * GNUNET_SYSERR to close it (signal serious error)
2087 receive_udp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
2089 const struct GNUNET_MessageHeader *message)
2091 struct TunnelState *ts = *tunnel_ctx;
2092 const struct GNUNET_EXIT_UdpReplyMessage *reply;
2095 GNUNET_STATISTICS_update (stats,
2096 gettext_noop ("# UDP packets received from mesh"),
2098 mlen = ntohs (message->size);
2099 if (mlen < sizeof (struct GNUNET_EXIT_UdpReplyMessage))
2101 GNUNET_break_op (0);
2102 return GNUNET_SYSERR;
2104 if (NULL == ts->heap_node)
2106 GNUNET_break_op (0);
2107 return GNUNET_SYSERR;
2109 if (AF_UNSPEC == ts->af)
2111 GNUNET_break_op (0);
2112 return GNUNET_SYSERR;
2114 reply = (const struct GNUNET_EXIT_UdpReplyMessage *) message;
2115 mlen -= sizeof (struct GNUNET_EXIT_UdpReplyMessage);
2117 char sbuf[INET6_ADDRSTRLEN];
2118 char dbuf[INET6_ADDRSTRLEN];
2120 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2121 "Received UDP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2122 (unsigned int) mlen,
2123 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2124 ts->destination_port,
2125 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2132 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2133 + sizeof (struct GNUNET_TUN_UdpHeader)
2134 + sizeof (struct GNUNET_MessageHeader) +
2135 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2138 char buf[size] GNUNET_ALIGN;
2139 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2140 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2141 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2142 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1];
2143 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2144 msg->size = htons (size);
2145 tun->flags = htons (0);
2146 tun->proto = htons (ETH_P_IPV4);
2147 GNUNET_TUN_initialize_ipv4_header (ipv4,
2149 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2150 &ts->destination_ip.v4,
2152 if (0 == ntohs (reply->source_port))
2153 udp->source_port = htons (ts->destination_port);
2155 udp->source_port = reply->source_port;
2156 if (0 == ntohs (reply->destination_port))
2157 udp->destination_port = htons (ts->source_port);
2159 udp->destination_port = reply->destination_port;
2160 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2161 GNUNET_TUN_calculate_udp4_checksum (ipv4,
2168 (void) GNUNET_HELPER_send (helper_handle,
2177 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2178 + sizeof (struct GNUNET_TUN_UdpHeader)
2179 + sizeof (struct GNUNET_MessageHeader) +
2180 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2183 char buf[size] GNUNET_ALIGN;
2184 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2185 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2186 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2187 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1];
2188 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2189 msg->size = htons (size);
2190 tun->flags = htons (0);
2191 tun->proto = htons (ETH_P_IPV6);
2192 GNUNET_TUN_initialize_ipv6_header (ipv6,
2194 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2195 &ts->destination_ip.v6,
2197 if (0 == ntohs (reply->source_port))
2198 udp->source_port = htons (ts->destination_port);
2200 udp->source_port = reply->source_port;
2201 if (0 == ntohs (reply->destination_port))
2202 udp->destination_port = htons (ts->source_port);
2204 udp->destination_port = reply->destination_port;
2205 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2206 GNUNET_TUN_calculate_udp6_checksum (ipv6,
2212 (void) GNUNET_HELPER_send (helper_handle,
2222 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2224 GNUNET_TIME_absolute_get ().abs_value);
2230 * We got a TCP packet back from the MESH tunnel. Pass it on to the
2231 * local virtual interface via the helper.
2233 * @param cls closure, NULL
2234 * @param tunnel connection to the other end
2235 * @param tunnel_ctx pointer to our 'struct TunnelState *'
2236 * @param message the actual message
2238 * @return GNUNET_OK to keep the connection open,
2239 * GNUNET_SYSERR to close it (signal serious error)
2242 receive_tcp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
2244 const struct GNUNET_MessageHeader *message)
2246 struct TunnelState *ts = *tunnel_ctx;
2247 const struct GNUNET_EXIT_TcpDataMessage *data;
2250 GNUNET_STATISTICS_update (stats,
2251 gettext_noop ("# TCP packets received from mesh"),
2253 mlen = ntohs (message->size);
2254 if (mlen < sizeof (struct GNUNET_EXIT_TcpDataMessage))
2256 GNUNET_break_op (0);
2257 return GNUNET_SYSERR;
2259 if (NULL == ts->heap_node)
2261 GNUNET_break_op (0);
2262 return GNUNET_SYSERR;
2264 data = (const struct GNUNET_EXIT_TcpDataMessage *) message;
2265 mlen -= sizeof (struct GNUNET_EXIT_TcpDataMessage);
2267 char sbuf[INET6_ADDRSTRLEN];
2268 char dbuf[INET6_ADDRSTRLEN];
2270 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2271 "Received TCP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2272 (unsigned int) mlen,
2273 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2274 ts->destination_port,
2275 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2278 if (data->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
2280 GNUNET_break_op (0);
2281 return GNUNET_SYSERR;
2287 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2288 + sizeof (struct GNUNET_TUN_TcpHeader)
2289 + sizeof (struct GNUNET_MessageHeader) +
2290 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2293 char buf[size] GNUNET_ALIGN;
2294 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2295 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2296 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2297 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv4[1];
2298 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2299 msg->size = htons (size);
2300 tun->flags = htons (0);
2301 tun->proto = htons (ETH_P_IPV4);
2302 GNUNET_TUN_initialize_ipv4_header (ipv4,
2304 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2305 &ts->destination_ip.v4,
2307 *tcp = data->tcp_header;
2308 tcp->source_port = htons (ts->destination_port);
2309 tcp->destination_port = htons (ts->source_port);
2310 GNUNET_TUN_calculate_tcp4_checksum (ipv4,
2317 (void) GNUNET_HELPER_send (helper_handle,
2326 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2327 + sizeof (struct GNUNET_TUN_TcpHeader)
2328 + sizeof (struct GNUNET_MessageHeader) +
2329 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2332 char buf[size] GNUNET_ALIGN;
2333 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2334 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2335 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2336 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv6[1];
2337 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2338 msg->size = htons (size);
2339 tun->flags = htons (0);
2340 tun->proto = htons (ETH_P_IPV6);
2341 GNUNET_TUN_initialize_ipv6_header (ipv6,
2343 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2344 &ts->destination_ip.v6,
2346 *tcp = data->tcp_header;
2347 tcp->source_port = htons (ts->destination_port);
2348 tcp->destination_port = htons (ts->source_port);
2349 GNUNET_TUN_calculate_tcp6_checksum (ipv6,
2356 (void) GNUNET_HELPER_send (helper_handle,
2364 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2366 GNUNET_TIME_absolute_get ().abs_value);
2372 * Allocate an IPv4 address from the range of the tunnel
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 tunnel
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 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2494 "Cleaning up destination entry\n");
2495 GNUNET_STATISTICS_update (stats,
2496 gettext_noop ("# Active destinations"),
2500 free_tunnel_state (de->ts);
2501 GNUNET_assert (NULL == de->ts);
2503 if (NULL != de->heap_node)
2505 GNUNET_CONTAINER_heap_remove_node (de->heap_node);
2506 de->heap_node = NULL;
2507 GNUNET_assert (GNUNET_YES ==
2508 GNUNET_CONTAINER_multihashmap_remove (destination_map,
2517 * We have too many active destinations. Clean up the oldest destination.
2519 * @param except destination that must NOT be cleaned up, even if it is the oldest
2522 expire_destination (struct DestinationEntry *except)
2524 struct DestinationEntry *de;
2526 de = GNUNET_CONTAINER_heap_peek (destination_heap);
2527 GNUNET_assert (NULL != de);
2529 return; /* can't do this */
2530 free_destination_entry (de);
2535 * Allocate an IP address for the response.
2537 * @param result_af desired address family; set to the actual
2538 * address family; can initially be AF_UNSPEC if there
2539 * is no preference; will be set to AF_UNSPEC if the
2541 * @param addr set to either v4 or v6 depending on which
2542 * storage location was used; set to NULL if allocation failed
2543 * @param v4 storage space for an IPv4 address
2544 * @param v6 storage space for an IPv6 address
2545 * @return GNUNET_OK normally, GNUNET_SYSERR if '*result_af' was
2546 * an unsupported address family (not AF_INET, AF_INET6 or AF_UNSPEC)
2549 allocate_response_ip (int *result_af,
2552 struct in6_addr *v6)
2559 allocate_v4_address (v4))
2560 *result_af = AF_UNSPEC;
2566 allocate_v6_address (v6))
2567 *result_af = AF_UNSPEC;
2573 allocate_v4_address (v4))
2576 *result_af = AF_INET;
2578 else if (GNUNET_OK ==
2579 allocate_v6_address (v6))
2582 *result_af = AF_INET6;
2587 return GNUNET_SYSERR;
2594 * A client asks us to setup a redirection via some exit
2595 * node to a particular IP. Setup the redirection and
2596 * give the client the allocated IP.
2599 * @param client requesting client
2600 * @param message redirection request (a 'struct RedirectToIpRequestMessage')
2603 service_redirect_to_ip (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
2604 const struct GNUNET_MessageHeader *message)
2608 const struct RedirectToIpRequestMessage *msg;
2614 struct DestinationEntry *de;
2615 struct GNUNET_HashCode key;
2616 struct TunnelState *ts;
2618 /* validate and parse request */
2619 mlen = ntohs (message->size);
2620 if (mlen < sizeof (struct RedirectToIpRequestMessage))
2623 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2626 alen = mlen - sizeof (struct RedirectToIpRequestMessage);
2627 msg = (const struct RedirectToIpRequestMessage *) message;
2628 addr_af = (int) htonl (msg->addr_af);
2632 if (alen != sizeof (struct in_addr))
2635 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2640 if (alen != sizeof (struct in6_addr))
2643 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2649 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2653 /* allocate response IP */
2654 result_af = (int) htonl (msg->result_af);
2655 if (GNUNET_OK != allocate_response_ip (&result_af,
2659 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2662 if ( (result_af == AF_UNSPEC) ||
2663 (GNUNET_NO == ntohl (msg->nac)) )
2665 /* send reply "instantly" */
2666 send_client_reply (client,
2671 if (result_af == AF_UNSPEC)
2673 /* failure, we're done */
2674 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2679 char sbuf[INET6_ADDRSTRLEN];
2680 char dbuf[INET6_ADDRSTRLEN];
2682 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2683 "Allocated address %s for redirection via exit to %s\n",
2684 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2686 &msg[1], dbuf, sizeof (dbuf)));
2689 /* setup destination record */
2690 de = GNUNET_malloc (sizeof (struct DestinationEntry));
2691 de->is_service = GNUNET_NO;
2692 de->details.exit_destination.af = addr_af;
2693 memcpy (&de->details.exit_destination.ip,
2696 get_destination_key_from_ip (result_af,
2700 GNUNET_assert (GNUNET_OK ==
2701 GNUNET_CONTAINER_multihashmap_put (destination_map,
2704 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2705 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2707 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
2708 GNUNET_STATISTICS_update (stats,
2709 gettext_noop ("# Active destinations"),
2711 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2712 expire_destination (de);
2714 /* setup tunnel to destination */
2715 ts = create_tunnel_to_destination (de,
2716 (GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
2722 ts->destination_ip.v4 = v4;
2725 ts->destination_ip.v6 = v6;
2731 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2736 * A client asks us to setup a redirection to a particular peer
2737 * offering a service. Setup the redirection and give the client the
2741 * @param client requesting client
2742 * @param message redirection request (a 'struct RedirectToPeerRequestMessage')
2745 service_redirect_to_service (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
2746 const struct GNUNET_MessageHeader *message)
2748 const struct RedirectToServiceRequestMessage *msg;
2753 struct DestinationEntry *de;
2754 struct GNUNET_HashCode key;
2755 struct TunnelState *ts;
2758 msg = (const struct RedirectToServiceRequestMessage *) message;
2760 /* allocate response IP */
2761 result_af = (int) htonl (msg->result_af);
2762 if (GNUNET_OK != allocate_response_ip (&result_af,
2766 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2769 if ( (result_af == AF_UNSPEC) ||
2770 (GNUNET_NO == ntohl (msg->nac)) )
2772 /* send reply "instantly" */
2773 send_client_reply (client,
2778 if (result_af == AF_UNSPEC)
2780 /* failure, we're done */
2781 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2782 _("Failed to allocate IP address for new destination\n"));
2783 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2788 char sbuf[INET6_ADDRSTRLEN];
2790 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2791 "Allocated address %s for redirection to service %s on peer %s\n",
2792 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2793 GNUNET_h2s (&msg->service_descriptor),
2794 GNUNET_i2s (&msg->target));
2797 /* setup destination record */
2798 de = GNUNET_malloc (sizeof (struct DestinationEntry));
2799 de->is_service = GNUNET_YES;
2800 de->details.service_destination.service_descriptor = msg->service_descriptor;
2801 de->details.service_destination.target = msg->target;
2802 get_destination_key_from_ip (result_af,
2806 GNUNET_assert (GNUNET_OK ==
2807 GNUNET_CONTAINER_multihashmap_put (destination_map,
2810 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2811 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2813 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
2814 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2815 expire_destination (de);
2816 ts = create_tunnel_to_destination (de,
2817 (GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
2823 ts->destination_ip.v4 = v4;
2826 ts->destination_ip.v6 = v6;
2832 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2837 * Function called whenever an inbound tunnel is destroyed. Should clean up
2838 * any associated state.
2840 * FIXME now its also user for disconnections
2842 * @param cls closure (set from GNUNET_MESH_connect)
2843 * @param tunnel connection to the other end (henceforth invalid)
2844 * @param tunnel_ctx place where local state associated
2845 * with the tunnel is stored (our 'struct TunnelState')
2848 tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel_ctx)
2850 /* we don't have inbound tunnels, so this function should never be called */
2856 * Free memory occupied by an entry in the destination map.
2860 * @param value a 'struct DestinationEntry *'
2861 * @return GNUNET_OK (continue to iterate)
2864 cleanup_destination (void *cls,
2865 const struct GNUNET_HashCode *key,
2868 struct DestinationEntry *de = value;
2870 free_destination_entry (de);
2876 * Free memory occupied by an entry in the tunnel map.
2880 * @param value a 'struct TunnelState *'
2881 * @return GNUNET_OK (continue to iterate)
2884 cleanup_tunnel (void *cls,
2885 const struct GNUNET_HashCode *key,
2888 struct TunnelState *ts = value;
2890 free_tunnel_state (ts);
2896 * Function scheduled as very last function, cleans up after us
2902 cleanup (void *cls GNUNET_UNUSED,
2903 const struct GNUNET_SCHEDULER_TaskContext *tc)
2907 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2908 "VPN is shutting down\n");
2909 if (NULL != destination_map)
2911 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
2912 &cleanup_destination,
2914 GNUNET_CONTAINER_multihashmap_destroy (destination_map);
2915 destination_map = NULL;
2917 if (NULL != destination_heap)
2919 GNUNET_CONTAINER_heap_destroy (destination_heap);
2920 destination_heap = NULL;
2922 if (NULL != tunnel_map)
2924 GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
2927 GNUNET_CONTAINER_multihashmap_destroy (tunnel_map);
2930 if (NULL != tunnel_heap)
2932 GNUNET_CONTAINER_heap_destroy (tunnel_heap);
2935 if (NULL != mesh_handle)
2937 GNUNET_MESH_disconnect (mesh_handle);
2940 if (NULL != helper_handle)
2942 GNUNET_HELPER_stop (helper_handle, GNUNET_NO);
2943 helper_handle = NULL;
2947 GNUNET_SERVER_notification_context_destroy (nc);
2952 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
2956 GNUNET_free_non_null (vpn_argv[i]);
2961 * A client disconnected, clean up all references to it.
2963 * @param cls the client that disconnected
2965 * @param value a 'struct TunnelState *'
2966 * @return GNUNET_OK (continue to iterate)
2969 cleanup_tunnel_client (void *cls,
2970 const struct GNUNET_HashCode *key,
2973 struct GNUNET_SERVER_Client *client = cls;
2974 struct TunnelState *ts = value;
2976 if (client == ts->client)
2983 * A client disconnected, clean up all references to it.
2985 * @param cls the client that disconnected
2987 * @param value a 'struct DestinationEntry *'
2988 * @return GNUNET_OK (continue to iterate)
2991 cleanup_destination_client (void *cls,
2992 const struct GNUNET_HashCode *key,
2995 struct GNUNET_SERVER_Client *client = cls;
2996 struct DestinationEntry *de = value;
2997 struct TunnelState *ts;
2999 if (NULL == (ts = de->ts))
3001 if (client == ts->client)
3008 * A client has disconnected from us. If we are currently building
3009 * a tunnel for it, cancel the operation.
3012 * @param client handle to the client that disconnected
3015 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
3017 if (NULL != tunnel_map)
3018 GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
3019 &cleanup_tunnel_client,
3021 if (NULL != destination_map)
3022 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
3023 &cleanup_destination_client,
3029 * Main function that will be run by the scheduler.
3031 * @param cls closure
3032 * @param server the initialized server
3033 * @param cfg_ configuration
3037 struct GNUNET_SERVER_Handle *server,
3038 const struct GNUNET_CONFIGURATION_Handle *cfg_)
3040 static const struct GNUNET_SERVER_MessageHandler service_handlers[] = {
3041 /* callback, cls, type, size */
3042 { &service_redirect_to_ip, NULL, GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP, 0},
3043 { &service_redirect_to_service, NULL,
3044 GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE,
3045 sizeof (struct RedirectToServiceRequestMessage) },
3048 static const struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
3049 { &receive_udp_back, GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY, 0},
3050 { &receive_tcp_back, GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN, 0},
3051 { &receive_icmp_back, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN, 0},
3063 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-vpn");
3066 GNUNET_OS_check_helper_binary (binary, GNUNET_YES, "-d gnunet-vpn - - 169.1.3.3.7 255.255.255.0")) //ipv4 only please!
3069 "`%s' is not SUID, refusing to run.\n",
3070 "gnunet-helper-vpn");
3071 GNUNET_free (binary);
3075 GNUNET_free (binary);
3077 stats = GNUNET_STATISTICS_create ("vpn", cfg);
3079 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_MAPPING",
3080 &max_destination_mappings))
3081 max_destination_mappings = 200;
3083 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_TUNNELS",
3084 &max_tunnel_mappings))
3085 max_tunnel_mappings = 200;
3087 destination_map = GNUNET_CONTAINER_multihashmap_create (max_destination_mappings * 2, GNUNET_NO);
3088 destination_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3089 tunnel_map = GNUNET_CONTAINER_multihashmap_create (max_tunnel_mappings * 2, GNUNET_NO);
3090 tunnel_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3093 vpn_argv[0] = GNUNET_strdup ("vpn-gnunet");
3094 if (GNUNET_SYSERR ==
3095 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IFNAME", &ifname))
3097 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3098 "No entry 'IFNAME' in configuration!\n");
3099 GNUNET_SCHEDULER_shutdown ();
3102 vpn_argv[1] = ifname;
3103 if (GNUNET_OK == GNUNET_NETWORK_test_pf (PF_INET6))
3105 if ( (GNUNET_SYSERR ==
3106 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6ADDR",
3108 (1 != inet_pton (AF_INET6, ipv6addr, &v6))) )
3110 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3111 "No valid entry 'IPV6ADDR' in configuration!\n");
3112 GNUNET_SCHEDULER_shutdown ();
3115 vpn_argv[2] = ipv6addr;
3116 if (GNUNET_SYSERR ==
3117 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6PREFIX",
3120 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3121 "No entry 'IPV6PREFIX' in configuration!\n");
3122 GNUNET_SCHEDULER_shutdown ();
3125 vpn_argv[3] = ipv6prefix_s;
3127 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn",
3130 (ipv6prefix >= 127) )
3132 GNUNET_SCHEDULER_shutdown ();
3138 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3139 _("IPv6 support disabled as this system does not support IPv6\n"));
3140 vpn_argv[2] = GNUNET_strdup ("-");
3141 vpn_argv[3] = GNUNET_strdup ("-");
3143 if (GNUNET_OK == GNUNET_NETWORK_test_pf (PF_INET))
3145 if ( (GNUNET_SYSERR ==
3146 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4ADDR",
3148 (1 != inet_pton (AF_INET, ipv4addr, &v4))) )
3150 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3151 "No valid entry for 'IPV4ADDR' in configuration!\n");
3152 GNUNET_SCHEDULER_shutdown ();
3155 vpn_argv[4] = ipv4addr;
3156 if ( (GNUNET_SYSERR ==
3157 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4MASK",
3159 (1 != inet_pton (AF_INET, ipv4mask, &v4))) )
3161 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3162 "No valid entry 'IPV4MASK' in configuration!\n");
3163 GNUNET_SCHEDULER_shutdown ();
3166 vpn_argv[5] = ipv4mask;
3170 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3171 _("IPv4 support disabled as this system does not support IPv4\n"));
3172 vpn_argv[4] = GNUNET_strdup ("-");
3173 vpn_argv[5] = GNUNET_strdup ("-");
3178 GNUNET_MESH_connect (cfg_, NULL,
3183 helper_handle = GNUNET_HELPER_start (GNUNET_NO,
3184 "gnunet-helper-vpn", vpn_argv,
3185 &message_token, NULL, NULL);
3186 nc = GNUNET_SERVER_notification_context_create (server, 1);
3187 GNUNET_SERVER_add_handlers (server, service_handlers);
3188 GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
3189 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls);
3194 * The main function of the VPN service.
3196 * @param argc number of arguments from the command line
3197 * @param argv command line arguments
3198 * @return 0 ok, 1 on error
3201 main (int argc, char *const *argv)
3203 return (GNUNET_OK ==
3204 GNUNET_SERVICE_run (argc, argv, "vpn",
3205 GNUNET_SERVICE_OPTION_NONE,
3206 &run, NULL)) ? global_ret : 1;
3209 /* end of gnunet-service-vpn.c */