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,
797 * Initialize the given destination entry's mesh tunnel.
799 * @param de destination entry for which we need to setup a tunnel
800 * @param client client to notify on successful tunnel setup, or NULL for none
801 * @param client_af address family of the address returned to the client
802 * @param request_id request ID to send in client notification (unused if client is NULL)
803 * @return tunnel state of the tunnel that was created
805 static struct TunnelState *
806 create_tunnel_to_destination (struct DestinationEntry *de,
807 struct GNUNET_SERVER_Client *client,
811 struct TunnelState *ts;
813 GNUNET_STATISTICS_update (stats,
814 gettext_noop ("# Mesh tunnels created"),
816 GNUNET_assert (NULL == de->ts);
817 ts = GNUNET_malloc (sizeof (struct TunnelState));
821 ts->request_id = request_id;
824 ts->destination = *de;
825 ts->destination.heap_node = NULL; /* copy is NOT in destination heap */
827 ts->destination_container = de; /* we are referenced from de */
830 ts->tunnel = GNUNET_MESH_tunnel_create (mesh_handle,
832 &de->details.service_destination.target,
836 if (NULL == ts->tunnel)
838 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
839 _("Failed to setup mesh tunnel!\n"));
843 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
844 "Creating tunnel to peer %s offering service %s\n",
845 GNUNET_i2s (&de->details.service_destination.target),
846 GNUNET_h2s (&de->details.service_destination.service_descriptor));
852 switch (de->details.exit_destination.af)
856 char address[GNUNET_TUN_IPV4_REGEXLEN];
858 GNUNET_TUN_ipv4toregexsearch (&de->details.exit_destination.ip.v4,
859 "255.255.255.255", address);
860 GNUNET_asprintf (&policy, "%s%s%s",
861 GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
868 char address[GNUNET_TUN_IPV6_REGEXLEN];
870 GNUNET_TUN_ipv6toregexsearch (&de->details.exit_destination.ip.v6,
872 GNUNET_asprintf (&policy, "%s%s%s",
873 GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
883 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
884 "Requesting connect by string: %s\n",
886 ts->search = GNUNET_REGEX_search (cfg,
888 &handle_regex_result,
890 GNUNET_free (policy);
897 * We have too many active tunnels. Clean up the oldest tunnel.
899 * @param except tunnel that must NOT be cleaned up, even if it is the oldest
902 expire_tunnel (struct TunnelState *except)
904 struct TunnelState *ts;
906 ts = GNUNET_CONTAINER_heap_peek (tunnel_heap);
907 GNUNET_assert (NULL != ts);
909 return; /* can't do this */
910 free_tunnel_state (ts);
915 * Route a packet via mesh to the given destination.
917 * @param destination description of the destination
918 * @param af address family on this end (AF_INET or AF_INET6)
919 * @param protocol IPPROTO_TCP or IPPROTO_UDP or IPPROTO_ICMP or IPPROTO_ICMPV6
920 * @param source_ip source IP used by the sender (struct in_addr or struct in6_addr)
921 * @param destination_ip destination IP used by the sender (struct in_addr or struct in6_addr)
922 * @param payload payload of the packet after the IP header
923 * @param payload_length number of bytes in payload
926 route_packet (struct DestinationEntry *destination,
929 const void *source_ip,
930 const void *destination_ip,
932 size_t payload_length)
934 struct GNUNET_HashCode key;
935 struct TunnelState *ts;
936 struct TunnelMessageQueueEntry *tnq;
940 const struct GNUNET_TUN_UdpHeader *udp;
941 const struct GNUNET_TUN_TcpHeader *tcp;
942 const struct GNUNET_TUN_IcmpHeader *icmp;
943 uint16_t source_port;
944 uint16_t destination_port;
950 if (payload_length < sizeof (struct GNUNET_TUN_UdpHeader))
956 tcp = NULL; /* make compiler happy */
957 icmp = NULL; /* make compiler happy */
959 if (udp->len < sizeof (struct GNUNET_TUN_UdpHeader))
964 source_port = ntohs (udp->source_port);
965 destination_port = ntohs (udp->destination_port);
966 get_tunnel_key_from_ips (af,
977 if (payload_length < sizeof (struct GNUNET_TUN_TcpHeader))
983 udp = NULL; /* make compiler happy */
984 icmp = NULL; /* make compiler happy */
986 if (tcp->off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
991 source_port = ntohs (tcp->source_port);
992 destination_port = ntohs (tcp->destination_port);
993 get_tunnel_key_from_ips (af,
1003 case IPPROTO_ICMPV6:
1005 if ( (AF_INET == af) ^ (protocol == IPPROTO_ICMP) )
1010 if (payload_length < sizeof (struct GNUNET_TUN_IcmpHeader))
1016 tcp = NULL; /* make compiler happy */
1017 udp = NULL; /* make compiler happy */
1020 destination_port = 0;
1021 get_tunnel_key_from_ips (af,
1031 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1032 _("Protocol %u not supported, dropping\n"),
1033 (unsigned int) protocol);
1037 if (! destination->is_service)
1039 switch (destination->details.exit_destination.af)
1042 alen = sizeof (struct in_addr);
1045 alen = sizeof (struct in6_addr);
1052 char sbuf[INET6_ADDRSTRLEN];
1053 char dbuf[INET6_ADDRSTRLEN];
1054 char xbuf[INET6_ADDRSTRLEN];
1056 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1057 "Routing %s packet from %s:%u -> %s:%u to destination %s:%u\n",
1058 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
1059 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
1061 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
1063 inet_ntop (destination->details.exit_destination.af,
1064 &destination->details.exit_destination.ip,
1065 xbuf, sizeof (xbuf)),
1072 char sbuf[INET6_ADDRSTRLEN];
1073 char dbuf[INET6_ADDRSTRLEN];
1075 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1076 "Routing %s packet from %s:%u -> %s:%u to service %s at peer %s\n",
1077 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
1078 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
1080 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
1082 GNUNET_h2s (&destination->details.service_destination.service_descriptor),
1083 GNUNET_i2s (&destination->details.service_destination.target));
1088 /* see if we have an existing tunnel for this destination */
1089 ts = GNUNET_CONTAINER_multihashmap_get (tunnel_map,
1093 /* need to either use the existing tunnel from the destination (if still
1094 available) or create a fresh one */
1095 is_new = GNUNET_YES;
1096 if (NULL == destination->ts)
1097 ts = create_tunnel_to_destination (destination, NULL, af, 0);
1099 ts = destination->ts;
1102 destination->ts = NULL;
1103 ts->destination_container = NULL; /* no longer 'contained' */
1104 /* now bind existing "unbound" tunnel to our IP/port tuple */
1105 ts->protocol = protocol;
1109 ts->source_ip.v4 = * (const struct in_addr *) source_ip;
1110 ts->destination_ip.v4 = * (const struct in_addr *) destination_ip;
1114 ts->source_ip.v6 = * (const struct in6_addr *) source_ip;
1115 ts->destination_ip.v6 = * (const struct in6_addr *) destination_ip;
1117 ts->source_port = source_port;
1118 ts->destination_port = destination_port;
1119 ts->heap_node = GNUNET_CONTAINER_heap_insert (tunnel_heap,
1121 GNUNET_TIME_absolute_get ().abs_value_us);
1122 GNUNET_assert (GNUNET_YES ==
1123 GNUNET_CONTAINER_multihashmap_put (tunnel_map,
1126 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1127 GNUNET_STATISTICS_update (stats,
1128 gettext_noop ("# Active tunnels"),
1130 while (GNUNET_CONTAINER_multihashmap_size (tunnel_map) > max_tunnel_mappings)
1136 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
1138 GNUNET_TIME_absolute_get ().abs_value_us);
1140 GNUNET_assert (NULL != ts->tunnel);
1142 /* send via tunnel */
1146 if (destination->is_service)
1148 struct GNUNET_EXIT_UdpServiceMessage *usm;
1150 mlen = sizeof (struct GNUNET_EXIT_UdpServiceMessage) +
1151 payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1152 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1157 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1160 usm = (struct GNUNET_EXIT_UdpServiceMessage *) &tnq[1];
1161 usm->header.size = htons ((uint16_t) mlen);
1162 usm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE);
1163 /* if the source port is below 32000, we assume it has a special
1164 meaning; if not, we pick a random port (this is a heuristic) */
1165 usm->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1166 usm->destination_port = udp->destination_port;
1167 usm->service_descriptor = destination->details.service_destination.service_descriptor;
1170 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1174 struct GNUNET_EXIT_UdpInternetMessage *uim;
1175 struct in_addr *ip4dst;
1176 struct in6_addr *ip6dst;
1179 mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) +
1180 alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1181 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1186 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) +
1190 uim = (struct GNUNET_EXIT_UdpInternetMessage *) &tnq[1];
1191 uim->header.size = htons ((uint16_t) mlen);
1192 uim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET);
1193 uim->af = htonl (destination->details.exit_destination.af);
1194 uim->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1195 uim->destination_port = udp->destination_port;
1196 switch (destination->details.exit_destination.af)
1199 ip4dst = (struct in_addr *) &uim[1];
1200 *ip4dst = destination->details.exit_destination.ip.v4;
1201 payload = &ip4dst[1];
1204 ip6dst = (struct in6_addr *) &uim[1];
1205 *ip6dst = destination->details.exit_destination.ip.v6;
1206 payload = &ip6dst[1];
1213 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1219 if (destination->is_service)
1221 struct GNUNET_EXIT_TcpServiceStartMessage *tsm;
1223 mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) +
1224 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1225 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1230 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1233 tsm = (struct GNUNET_EXIT_TcpServiceStartMessage *) &tnq[1];
1234 tsm->header.size = htons ((uint16_t) mlen);
1235 tsm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START);
1236 tsm->reserved = htonl (0);
1237 tsm->service_descriptor = destination->details.service_destination.service_descriptor;
1238 tsm->tcp_header = *tcp;
1241 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1245 struct GNUNET_EXIT_TcpInternetStartMessage *tim;
1246 struct in_addr *ip4dst;
1247 struct in6_addr *ip6dst;
1250 mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) +
1251 alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1252 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1257 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1260 tim = (struct GNUNET_EXIT_TcpInternetStartMessage *) &tnq[1];
1261 tim->header.size = htons ((uint16_t) mlen);
1262 tim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START);
1263 tim->af = htonl (destination->details.exit_destination.af);
1264 tim->tcp_header = *tcp;
1265 switch (destination->details.exit_destination.af)
1268 ip4dst = (struct in_addr *) &tim[1];
1269 *ip4dst = destination->details.exit_destination.ip.v4;
1270 payload = &ip4dst[1];
1273 ip6dst = (struct in6_addr *) &tim[1];
1274 *ip6dst = destination->details.exit_destination.ip.v6;
1275 payload = &ip6dst[1];
1282 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1287 struct GNUNET_EXIT_TcpDataMessage *tdm;
1289 mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) +
1290 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1291 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1296 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1299 tdm = (struct GNUNET_EXIT_TcpDataMessage *) &tnq[1];
1300 tdm->header.size = htons ((uint16_t) mlen);
1301 tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT);
1302 tdm->reserved = htonl (0);
1303 tdm->tcp_header = *tcp;
1306 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1310 case IPPROTO_ICMPV6:
1311 if (destination->is_service)
1313 struct GNUNET_EXIT_IcmpServiceMessage *ism;
1315 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1316 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1317 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1322 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1324 ism = (struct GNUNET_EXIT_IcmpServiceMessage *) &tnq[1];
1325 ism->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE);
1326 ism->af = htonl (af); /* need to tell destination ICMP protocol family! */
1327 ism->service_descriptor = destination->details.service_destination.service_descriptor;
1328 ism->icmp_header = *icmp;
1329 /* ICMP protocol translation will be done by the receiver (as we don't know
1330 the target AF); however, we still need to possibly discard the payload
1331 depending on the ICMP type */
1337 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1338 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1340 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1341 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1342 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1343 /* throw away ICMP payload, won't be useful for the other side anyway */
1344 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1347 GNUNET_STATISTICS_update (stats,
1348 gettext_noop ("# ICMPv4 packets dropped (not allowed)"),
1352 /* end of AF_INET */
1357 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1358 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1359 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1360 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1361 /* throw away ICMP payload, won't be useful for the other side anyway */
1362 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1364 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1365 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1368 GNUNET_STATISTICS_update (stats,
1369 gettext_noop ("# ICMPv6 packets dropped (not allowed)"),
1373 /* end of AF_INET6 */
1380 /* update length calculations, as payload_length may have changed */
1381 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1382 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1384 ism->header.size = htons ((uint16_t) mlen);
1385 /* finally, copy payload (if there is any left...) */
1388 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1392 struct GNUNET_EXIT_IcmpInternetMessage *iim;
1393 struct in_addr *ip4dst;
1394 struct in6_addr *ip6dst;
1397 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1398 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1399 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1404 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) +
1407 iim = (struct GNUNET_EXIT_IcmpInternetMessage *) &tnq[1];
1408 iim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET);
1409 iim->icmp_header = *icmp;
1410 /* Perform ICMP protocol-translation (depending on destination AF and source AF)
1411 and throw away ICMP payload depending on ICMP message type */
1417 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1418 if (destination->details.exit_destination.af == AF_INET6)
1419 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1421 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1422 if (destination->details.exit_destination.af == AF_INET6)
1423 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1425 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1426 if (destination->details.exit_destination.af == AF_INET6)
1427 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1428 /* throw away IP-payload, exit will have to make it up anyway */
1429 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1431 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1432 if (destination->details.exit_destination.af == AF_INET6)
1433 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1434 /* throw away IP-payload, exit will have to make it up anyway */
1435 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1437 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1438 if (destination->details.exit_destination.af == AF_INET6)
1440 GNUNET_STATISTICS_update (stats,
1441 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1446 /* throw away IP-payload, exit will have to make it up anyway */
1447 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1450 GNUNET_STATISTICS_update (stats,
1451 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1456 /* end of AF_INET */
1461 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1462 if (destination->details.exit_destination.af == AF_INET6)
1463 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1464 /* throw away IP-payload, exit will have to make it up anyway */
1465 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1467 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1468 if (destination->details.exit_destination.af == AF_INET)
1469 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1470 /* throw away IP-payload, exit will have to make it up anyway */
1471 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1473 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1474 if (destination->details.exit_destination.af == AF_INET)
1476 GNUNET_STATISTICS_update (stats,
1477 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1482 /* throw away IP-payload, exit will have to make it up anyway */
1483 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1485 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1486 if (destination->details.exit_destination.af == AF_INET)
1488 GNUNET_STATISTICS_update (stats,
1489 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1494 /* throw away IP-payload, exit will have to make it up anyway */
1495 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1497 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1498 if (destination->details.exit_destination.af == AF_INET)
1499 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1501 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1502 if (destination->details.exit_destination.af == AF_INET)
1503 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1506 GNUNET_STATISTICS_update (stats,
1507 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1512 /* end of AF_INET6 */
1517 /* update length calculations, as payload_length may have changed */
1518 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1519 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1521 iim->header.size = htons ((uint16_t) mlen);
1523 /* need to tell destination ICMP protocol family! */
1524 iim->af = htonl (destination->details.exit_destination.af);
1525 switch (destination->details.exit_destination.af)
1528 ip4dst = (struct in_addr *) &iim[1];
1529 *ip4dst = destination->details.exit_destination.ip.v4;
1530 payload = &ip4dst[1];
1533 ip6dst = (struct in6_addr *) &iim[1];
1534 *ip6dst = destination->details.exit_destination.ip.v6;
1535 payload = &ip6dst[1];
1542 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1546 /* not supported above, how can we get here !? */
1550 send_to_tunnel (tnq, ts);
1555 * Receive packets from the helper-process (someone send to the local
1556 * virtual tunnel interface). Find the destination mapping, and if it
1557 * exists, identify the correct MESH tunnel (or possibly create it)
1558 * and forward the packet.
1560 * @param cls closure, NULL
1561 * @param client NULL
1562 * @param message message we got from the client (VPN tunnel interface)
1565 message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED,
1566 const struct GNUNET_MessageHeader *message)
1568 const struct GNUNET_TUN_Layer2PacketHeader *tun;
1570 struct GNUNET_HashCode key;
1571 struct DestinationEntry *de;
1573 GNUNET_STATISTICS_update (stats,
1574 gettext_noop ("# Packets received from TUN interface"),
1576 mlen = ntohs (message->size);
1577 if ( (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
1578 (mlen < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader)) )
1583 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1584 mlen -= (sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader));
1585 switch (ntohs (tun->proto))
1589 const struct GNUNET_TUN_IPv6Header *pkt6;
1591 if (mlen < sizeof (struct GNUNET_TUN_IPv6Header))
1597 pkt6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1598 get_destination_key_from_ip (AF_INET6,
1599 &pkt6->destination_address,
1601 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1602 /* FIXME: do we need to guard against hash collision?
1603 (if so, we need to also store the local destination IP in the
1604 destination entry and then compare here; however, the risk
1605 of collision seems minimal AND the impact is unlikely to be
1606 super-problematic as well... */
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);
1643 /* FIXME: do we need to guard against hash collision?
1644 (if so, we need to also store the local destination IP in the
1645 destination entry and then compare here; however, the risk
1646 of collision seems minimal AND the impact is unlikely to be
1647 super-problematic as well... */
1650 char buf[INET_ADDRSTRLEN];
1652 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1653 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1655 &pkt4->destination_address,
1660 if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header))
1662 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1663 _("Received IPv4 packet with options (dropping it)\n"));
1669 &pkt4->source_address,
1670 &pkt4->destination_address,
1672 mlen - sizeof (struct GNUNET_TUN_IPv4Header));
1676 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1677 _("Received packet of unknown protocol %d from TUN (dropping it)\n"),
1678 (unsigned int) ntohs (tun->proto));
1686 * Synthesize a plausible ICMP payload for an ICMP error
1687 * response on the given tunnel.
1689 * @param ts tunnel information
1690 * @param ipp IPv4 header to fill in (ICMP payload)
1691 * @param udp "UDP" header to fill in (ICMP payload); might actually
1692 * also be the first 8 bytes of the TCP header
1695 make_up_icmpv4_payload (struct TunnelState *ts,
1696 struct GNUNET_TUN_IPv4Header *ipp,
1697 struct GNUNET_TUN_UdpHeader *udp)
1699 GNUNET_TUN_initialize_ipv4_header (ipp,
1701 sizeof (struct GNUNET_TUN_TcpHeader),
1703 &ts->destination_ip.v4);
1704 udp->source_port = htons (ts->source_port);
1705 udp->destination_port = htons (ts->destination_port);
1706 udp->len = htons (0);
1707 udp->crc = htons (0);
1712 * Synthesize a plausible ICMP payload for an ICMP error
1713 * response on the given tunnel.
1715 * @param ts tunnel information
1716 * @param ipp IPv6 header to fill in (ICMP payload)
1717 * @param udp "UDP" header to fill in (ICMP payload); might actually
1718 * also be the first 8 bytes of the TCP header
1721 make_up_icmpv6_payload (struct TunnelState *ts,
1722 struct GNUNET_TUN_IPv6Header *ipp,
1723 struct GNUNET_TUN_UdpHeader *udp)
1725 GNUNET_TUN_initialize_ipv6_header (ipp,
1727 sizeof (struct GNUNET_TUN_TcpHeader),
1729 &ts->destination_ip.v6);
1730 udp->source_port = htons (ts->source_port);
1731 udp->destination_port = htons (ts->destination_port);
1732 udp->len = htons (0);
1733 udp->crc = htons (0);
1738 * We got an ICMP packet back from the MESH tunnel. Pass it on to the
1739 * local virtual interface via the helper.
1741 * @param cls closure, NULL
1742 * @param tunnel connection to the other end
1743 * @param tunnel_ctx pointer to our 'struct TunnelState *'
1744 * @param message the actual message
1746 * @return GNUNET_OK to keep the connection open,
1747 * GNUNET_SYSERR to close it (signal serious error)
1750 receive_icmp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1752 const struct GNUNET_MessageHeader *message)
1754 struct TunnelState *ts = *tunnel_ctx;
1755 const struct GNUNET_EXIT_IcmpToVPNMessage *i2v;
1758 GNUNET_STATISTICS_update (stats,
1759 gettext_noop ("# ICMP packets received from mesh"),
1761 mlen = ntohs (message->size);
1762 if (mlen < sizeof (struct GNUNET_EXIT_IcmpToVPNMessage))
1764 GNUNET_break_op (0);
1765 return GNUNET_SYSERR;
1767 if (NULL == ts->heap_node)
1769 GNUNET_break_op (0);
1770 return GNUNET_SYSERR;
1772 if (AF_UNSPEC == ts->af)
1774 GNUNET_break_op (0);
1775 return GNUNET_SYSERR;
1777 i2v = (const struct GNUNET_EXIT_IcmpToVPNMessage *) message;
1778 mlen -= sizeof (struct GNUNET_EXIT_IcmpToVPNMessage);
1780 char sbuf[INET6_ADDRSTRLEN];
1781 char dbuf[INET6_ADDRSTRLEN];
1783 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1784 "Received ICMP packet from mesh, sending %u bytes from %s -> %s via TUN\n",
1785 (unsigned int) mlen,
1786 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
1787 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)));
1793 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
1794 + sizeof (struct GNUNET_TUN_IcmpHeader)
1795 + sizeof (struct GNUNET_MessageHeader) +
1796 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1799 /* reserve some extra space in case we have an ICMP type here where
1800 we will need to make up the payload ourselves */
1801 char buf[size + sizeof (struct GNUNET_TUN_IPv4Header) + 8] GNUNET_ALIGN;
1802 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1803 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1804 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1805 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv4[1];
1806 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1807 tun->flags = htons (0);
1808 tun->proto = htons (ETH_P_IPV4);
1809 GNUNET_TUN_initialize_ipv4_header (ipv4,
1811 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1812 &ts->destination_ip.v4,
1814 *icmp = i2v->icmp_header;
1818 /* For some ICMP types, we need to adjust (make up) the payload here.
1819 Also, depending on the AF used on the other side, we have to
1820 do ICMP PT (translate ICMP types) */
1821 switch (ntohl (i2v->af))
1826 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1827 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1829 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1830 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1831 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1833 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1834 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1838 /* sender did not strip ICMP payload? */
1839 GNUNET_break_op (0);
1840 return GNUNET_SYSERR;
1842 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1843 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1844 make_up_icmpv4_payload (ts, ipp, udp);
1848 GNUNET_break_op (0);
1849 GNUNET_STATISTICS_update (stats,
1850 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1852 return GNUNET_SYSERR;
1857 /* ICMP PT 6-to-4 and possibly making up payloads */
1860 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1861 icmp->type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
1863 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1864 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1868 /* sender did not strip ICMP payload? */
1869 GNUNET_break_op (0);
1870 return GNUNET_SYSERR;
1872 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1873 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1874 make_up_icmpv4_payload (ts, ipp, udp);
1877 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1878 icmp->type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1880 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1881 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1885 /* sender did not strip ICMP payload? */
1886 GNUNET_break_op (0);
1887 return GNUNET_SYSERR;
1889 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1890 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1891 make_up_icmpv4_payload (ts, ipp, udp);
1894 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1895 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1896 GNUNET_STATISTICS_update (stats,
1897 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1900 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1901 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1903 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1904 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1907 GNUNET_break_op (0);
1908 GNUNET_STATISTICS_update (stats,
1909 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1911 return GNUNET_SYSERR;
1916 GNUNET_break_op (0);
1917 return GNUNET_SYSERR;
1919 msg->size = htons (size);
1920 GNUNET_TUN_calculate_icmp_checksum (icmp,
1923 (void) GNUNET_HELPER_send (helper_handle,
1932 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
1933 + sizeof (struct GNUNET_TUN_IcmpHeader)
1934 + sizeof (struct GNUNET_MessageHeader) +
1935 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1938 char buf[size + sizeof (struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN;
1939 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1940 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1941 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
1942 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv6[1];
1943 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1944 tun->flags = htons (0);
1945 tun->proto = htons (ETH_P_IPV6);
1946 GNUNET_TUN_initialize_ipv6_header (ipv6,
1948 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1949 &ts->destination_ip.v6,
1951 *icmp = i2v->icmp_header;
1956 /* For some ICMP types, we need to adjust (make up) the payload here.
1957 Also, depending on the AF used on the other side, we have to
1958 do ICMP PT (translate ICMP types) */
1959 switch (ntohl (i2v->af))
1962 /* ICMP PT 4-to-6 and possibly making up payloads */
1965 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1966 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1968 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1969 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1971 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1972 icmp->type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1974 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1975 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1979 /* sender did not strip ICMP payload? */
1980 GNUNET_break_op (0);
1981 return GNUNET_SYSERR;
1983 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1984 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1985 make_up_icmpv6_payload (ts, ipp, udp);
1988 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1989 icmp->type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1991 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1992 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1996 /* sender did not strip ICMP payload? */
1997 GNUNET_break_op (0);
1998 return GNUNET_SYSERR;
2000 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
2001 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
2002 make_up_icmpv6_payload (ts, ipp, udp);
2005 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
2006 GNUNET_STATISTICS_update (stats,
2007 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
2011 GNUNET_break_op (0);
2012 GNUNET_STATISTICS_update (stats,
2013 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
2015 return GNUNET_SYSERR;
2022 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
2023 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
2024 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
2025 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
2027 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
2028 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
2032 /* sender did not strip ICMP payload? */
2033 GNUNET_break_op (0);
2034 return GNUNET_SYSERR;
2036 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
2037 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
2038 make_up_icmpv6_payload (ts, ipp, udp);
2041 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
2044 GNUNET_break_op (0);
2045 GNUNET_STATISTICS_update (stats,
2046 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
2048 return GNUNET_SYSERR;
2053 GNUNET_break_op (0);
2054 return GNUNET_SYSERR;
2056 msg->size = htons (size);
2057 GNUNET_TUN_calculate_icmp_checksum (icmp,
2059 (void) GNUNET_HELPER_send (helper_handle,
2069 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2071 GNUNET_TIME_absolute_get ().abs_value_us);
2077 * We got a UDP packet back from the MESH tunnel. Pass it on to the
2078 * local virtual interface via the helper.
2080 * @param cls closure, NULL
2081 * @param tunnel connection to the other end
2082 * @param tunnel_ctx pointer to our 'struct TunnelState *'
2083 * @param message the actual message
2085 * @return GNUNET_OK to keep the connection open,
2086 * GNUNET_SYSERR to close it (signal serious error)
2089 receive_udp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
2091 const struct GNUNET_MessageHeader *message)
2093 struct TunnelState *ts = *tunnel_ctx;
2094 const struct GNUNET_EXIT_UdpReplyMessage *reply;
2097 GNUNET_STATISTICS_update (stats,
2098 gettext_noop ("# UDP packets received from mesh"),
2100 mlen = ntohs (message->size);
2101 if (mlen < sizeof (struct GNUNET_EXIT_UdpReplyMessage))
2103 GNUNET_break_op (0);
2104 return GNUNET_SYSERR;
2106 if (NULL == ts->heap_node)
2108 GNUNET_break_op (0);
2109 return GNUNET_SYSERR;
2111 if (AF_UNSPEC == ts->af)
2113 GNUNET_break_op (0);
2114 return GNUNET_SYSERR;
2116 reply = (const struct GNUNET_EXIT_UdpReplyMessage *) message;
2117 mlen -= sizeof (struct GNUNET_EXIT_UdpReplyMessage);
2119 char sbuf[INET6_ADDRSTRLEN];
2120 char dbuf[INET6_ADDRSTRLEN];
2122 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2123 "Received UDP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2124 (unsigned int) mlen,
2125 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2126 ts->destination_port,
2127 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2134 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2135 + sizeof (struct GNUNET_TUN_UdpHeader)
2136 + sizeof (struct GNUNET_MessageHeader) +
2137 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2140 char buf[size] GNUNET_ALIGN;
2141 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2142 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2143 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2144 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1];
2145 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2146 msg->size = htons (size);
2147 tun->flags = htons (0);
2148 tun->proto = htons (ETH_P_IPV4);
2149 GNUNET_TUN_initialize_ipv4_header (ipv4,
2151 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2152 &ts->destination_ip.v4,
2154 if (0 == ntohs (reply->source_port))
2155 udp->source_port = htons (ts->destination_port);
2157 udp->source_port = reply->source_port;
2158 if (0 == ntohs (reply->destination_port))
2159 udp->destination_port = htons (ts->source_port);
2161 udp->destination_port = reply->destination_port;
2162 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2163 GNUNET_TUN_calculate_udp4_checksum (ipv4,
2170 (void) GNUNET_HELPER_send (helper_handle,
2179 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2180 + sizeof (struct GNUNET_TUN_UdpHeader)
2181 + sizeof (struct GNUNET_MessageHeader) +
2182 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2185 char buf[size] GNUNET_ALIGN;
2186 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2187 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2188 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2189 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1];
2190 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2191 msg->size = htons (size);
2192 tun->flags = htons (0);
2193 tun->proto = htons (ETH_P_IPV6);
2194 GNUNET_TUN_initialize_ipv6_header (ipv6,
2196 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2197 &ts->destination_ip.v6,
2199 if (0 == ntohs (reply->source_port))
2200 udp->source_port = htons (ts->destination_port);
2202 udp->source_port = reply->source_port;
2203 if (0 == ntohs (reply->destination_port))
2204 udp->destination_port = htons (ts->source_port);
2206 udp->destination_port = reply->destination_port;
2207 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2208 GNUNET_TUN_calculate_udp6_checksum (ipv6,
2214 (void) GNUNET_HELPER_send (helper_handle,
2224 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2226 GNUNET_TIME_absolute_get ().abs_value_us);
2232 * We got a TCP packet back from the MESH tunnel. Pass it on to the
2233 * local virtual interface via the helper.
2235 * @param cls closure, NULL
2236 * @param tunnel connection to the other end
2237 * @param tunnel_ctx pointer to our 'struct TunnelState *'
2238 * @param message the actual message
2240 * @return GNUNET_OK to keep the connection open,
2241 * GNUNET_SYSERR to close it (signal serious error)
2244 receive_tcp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
2246 const struct GNUNET_MessageHeader *message)
2248 struct TunnelState *ts = *tunnel_ctx;
2249 const struct GNUNET_EXIT_TcpDataMessage *data;
2252 GNUNET_STATISTICS_update (stats,
2253 gettext_noop ("# TCP packets received from mesh"),
2255 mlen = ntohs (message->size);
2256 if (mlen < sizeof (struct GNUNET_EXIT_TcpDataMessage))
2258 GNUNET_break_op (0);
2259 return GNUNET_SYSERR;
2261 if (NULL == ts->heap_node)
2263 GNUNET_break_op (0);
2264 return GNUNET_SYSERR;
2266 data = (const struct GNUNET_EXIT_TcpDataMessage *) message;
2267 mlen -= sizeof (struct GNUNET_EXIT_TcpDataMessage);
2269 char sbuf[INET6_ADDRSTRLEN];
2270 char dbuf[INET6_ADDRSTRLEN];
2272 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2273 "Received TCP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2274 (unsigned int) mlen,
2275 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2276 ts->destination_port,
2277 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2280 if (data->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
2282 GNUNET_break_op (0);
2283 return GNUNET_SYSERR;
2289 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2290 + sizeof (struct GNUNET_TUN_TcpHeader)
2291 + sizeof (struct GNUNET_MessageHeader) +
2292 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2295 char buf[size] GNUNET_ALIGN;
2296 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2297 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2298 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2299 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv4[1];
2300 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2301 msg->size = htons (size);
2302 tun->flags = htons (0);
2303 tun->proto = htons (ETH_P_IPV4);
2304 GNUNET_TUN_initialize_ipv4_header (ipv4,
2306 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2307 &ts->destination_ip.v4,
2309 *tcp = data->tcp_header;
2310 tcp->source_port = htons (ts->destination_port);
2311 tcp->destination_port = htons (ts->source_port);
2312 GNUNET_TUN_calculate_tcp4_checksum (ipv4,
2319 (void) GNUNET_HELPER_send (helper_handle,
2328 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2329 + sizeof (struct GNUNET_TUN_TcpHeader)
2330 + sizeof (struct GNUNET_MessageHeader) +
2331 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2334 char buf[size] GNUNET_ALIGN;
2335 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2336 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2337 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2338 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv6[1];
2339 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2340 msg->size = htons (size);
2341 tun->flags = htons (0);
2342 tun->proto = htons (ETH_P_IPV6);
2343 GNUNET_TUN_initialize_ipv6_header (ipv6,
2345 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2346 &ts->destination_ip.v6,
2348 *tcp = data->tcp_header;
2349 tcp->source_port = htons (ts->destination_port);
2350 tcp->destination_port = htons (ts->source_port);
2351 GNUNET_TUN_calculate_tcp6_checksum (ipv6,
2358 (void) GNUNET_HELPER_send (helper_handle,
2366 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2368 GNUNET_TIME_absolute_get ().abs_value_us);
2374 * Allocate an IPv4 address from the range of the tunnel
2375 * for a new redirection.
2377 * @param v4 where to store the address
2378 * @return GNUNET_OK on success,
2379 * GNUNET_SYSERR on error
2382 allocate_v4_address (struct in_addr *v4)
2384 const char *ipv4addr = vpn_argv[4];
2385 const char *ipv4mask = vpn_argv[5];
2386 struct in_addr addr;
2387 struct in_addr mask;
2389 struct GNUNET_HashCode key;
2392 GNUNET_assert (1 == inet_pton (AF_INET, ipv4addr, &addr));
2393 GNUNET_assert (1 == inet_pton (AF_INET, ipv4mask, &mask));
2394 /* Given 192.168.0.1/255.255.0.0, we want a mask
2395 of '192.168.255.255', thus: */
2396 mask.s_addr = addr.s_addr | ~mask.s_addr;
2403 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2404 _("Failed to find unallocated IPv4 address in VPN's range\n"));
2405 return GNUNET_SYSERR;
2407 /* Pick random IPv4 address within the subnet, except 'addr' or 'mask' itself */
2408 rnd.s_addr = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2410 v4->s_addr = (addr.s_addr | rnd.s_addr) & mask.s_addr;
2411 get_destination_key_from_ip (AF_INET,
2415 while ( (GNUNET_YES ==
2416 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2418 (v4->s_addr == addr.s_addr) ||
2419 (v4->s_addr == mask.s_addr) );
2425 * Allocate an IPv6 address from the range of the tunnel
2426 * for a new redirection.
2428 * @param v6 where to store the address
2429 * @return GNUNET_OK on success,
2430 * GNUNET_SYSERR on error
2433 allocate_v6_address (struct in6_addr *v6)
2435 const char *ipv6addr = vpn_argv[2];
2436 struct in6_addr addr;
2437 struct in6_addr mask;
2438 struct in6_addr rnd;
2440 struct GNUNET_HashCode key;
2443 GNUNET_assert (1 == inet_pton (AF_INET6, ipv6addr, &addr));
2444 GNUNET_assert (ipv6prefix < 128);
2445 /* Given ABCD::/96, we want a mask of 'ABCD::FFFF:FFFF,
2448 for (i=127;i>=ipv6prefix;i--)
2449 mask.s6_addr[i / 8] |= (1 << (i % 8));
2451 /* Pick random IPv6 address within the subnet, except 'addr' or 'mask' itself */
2458 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2459 _("Failed to find unallocated IPv6 address in VPN's range\n"));
2460 return GNUNET_SYSERR;
2465 rnd.s6_addr[i] = (unsigned char) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2468 = (addr.s6_addr[i] | rnd.s6_addr[i]) & mask.s6_addr[i];
2470 get_destination_key_from_ip (AF_INET6,
2474 while ( (GNUNET_YES ==
2475 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2479 sizeof (struct in6_addr))) ||
2482 sizeof (struct in6_addr))) );
2488 * Free resources occupied by a destination entry.
2490 * @param de entry to free
2493 free_destination_entry (struct DestinationEntry *de)
2495 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2496 "Cleaning up destination entry\n");
2497 GNUNET_STATISTICS_update (stats,
2498 gettext_noop ("# Active destinations"),
2502 free_tunnel_state (de->ts);
2503 GNUNET_assert (NULL == de->ts);
2505 if (NULL != de->heap_node)
2507 GNUNET_CONTAINER_heap_remove_node (de->heap_node);
2508 de->heap_node = NULL;
2509 GNUNET_assert (GNUNET_YES ==
2510 GNUNET_CONTAINER_multihashmap_remove (destination_map,
2519 * We have too many active destinations. Clean up the oldest destination.
2521 * @param except destination that must NOT be cleaned up, even if it is the oldest
2524 expire_destination (struct DestinationEntry *except)
2526 struct DestinationEntry *de;
2528 de = GNUNET_CONTAINER_heap_peek (destination_heap);
2529 GNUNET_assert (NULL != de);
2531 return; /* can't do this */
2532 free_destination_entry (de);
2537 * Allocate an IP address for the response.
2539 * @param result_af desired address family; set to the actual
2540 * address family; can initially be AF_UNSPEC if there
2541 * is no preference; will be set to AF_UNSPEC if the
2543 * @param addr set to either v4 or v6 depending on which
2544 * storage location was used; set to NULL if allocation failed
2545 * @param v4 storage space for an IPv4 address
2546 * @param v6 storage space for an IPv6 address
2547 * @return GNUNET_OK normally, GNUNET_SYSERR if '*result_af' was
2548 * an unsupported address family (not AF_INET, AF_INET6 or AF_UNSPEC)
2551 allocate_response_ip (int *result_af,
2554 struct in6_addr *v6)
2561 allocate_v4_address (v4))
2562 *result_af = AF_UNSPEC;
2568 allocate_v6_address (v6))
2569 *result_af = AF_UNSPEC;
2575 allocate_v4_address (v4))
2578 *result_af = AF_INET;
2580 else if (GNUNET_OK ==
2581 allocate_v6_address (v6))
2584 *result_af = AF_INET6;
2589 return GNUNET_SYSERR;
2596 * A client asks us to setup a redirection via some exit
2597 * node to a particular IP. Setup the redirection and
2598 * give the client the allocated IP.
2601 * @param client requesting client
2602 * @param message redirection request (a 'struct RedirectToIpRequestMessage')
2605 service_redirect_to_ip (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
2606 const struct GNUNET_MessageHeader *message)
2610 const struct RedirectToIpRequestMessage *msg;
2616 struct DestinationEntry *de;
2617 struct GNUNET_HashCode key;
2618 struct TunnelState *ts;
2620 /* validate and parse request */
2621 mlen = ntohs (message->size);
2622 if (mlen < sizeof (struct RedirectToIpRequestMessage))
2625 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2628 alen = mlen - sizeof (struct RedirectToIpRequestMessage);
2629 msg = (const struct RedirectToIpRequestMessage *) message;
2630 addr_af = (int) htonl (msg->addr_af);
2634 if (alen != sizeof (struct in_addr))
2637 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2642 if (alen != sizeof (struct in6_addr))
2645 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2651 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2655 /* allocate response IP */
2656 result_af = (int) htonl (msg->result_af);
2657 if (GNUNET_OK != allocate_response_ip (&result_af,
2661 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2664 if ( (result_af == AF_UNSPEC) ||
2665 (GNUNET_NO == ntohl (msg->nac)) )
2667 /* send reply "instantly" */
2668 send_client_reply (client,
2673 if (result_af == AF_UNSPEC)
2675 /* failure, we're done */
2676 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2681 char sbuf[INET6_ADDRSTRLEN];
2682 char dbuf[INET6_ADDRSTRLEN];
2684 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2685 "Allocated address %s for redirection via exit to %s\n",
2686 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2688 &msg[1], dbuf, sizeof (dbuf)));
2691 /* setup destination record */
2692 de = GNUNET_malloc (sizeof (struct DestinationEntry));
2693 de->is_service = GNUNET_NO;
2694 de->details.exit_destination.af = addr_af;
2695 memcpy (&de->details.exit_destination.ip,
2698 get_destination_key_from_ip (result_af,
2702 GNUNET_assert (GNUNET_OK ==
2703 GNUNET_CONTAINER_multihashmap_put (destination_map,
2706 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2707 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2709 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value_us);
2710 GNUNET_STATISTICS_update (stats,
2711 gettext_noop ("# Active destinations"),
2713 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2714 expire_destination (de);
2716 /* setup tunnel to destination */
2717 ts = create_tunnel_to_destination (de,
2718 (GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
2724 ts->destination_ip.v4 = v4;
2727 ts->destination_ip.v6 = v6;
2733 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2738 * A client asks us to setup a redirection to a particular peer
2739 * offering a service. Setup the redirection and give the client the
2743 * @param client requesting client
2744 * @param message redirection request (a 'struct RedirectToPeerRequestMessage')
2747 service_redirect_to_service (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
2748 const struct GNUNET_MessageHeader *message)
2750 const struct RedirectToServiceRequestMessage *msg;
2755 struct DestinationEntry *de;
2756 struct GNUNET_HashCode key;
2757 struct TunnelState *ts;
2760 msg = (const struct RedirectToServiceRequestMessage *) message;
2762 /* allocate response IP */
2763 result_af = (int) htonl (msg->result_af);
2764 if (GNUNET_OK != allocate_response_ip (&result_af,
2768 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2771 if ( (result_af == AF_UNSPEC) ||
2772 (GNUNET_NO == ntohl (msg->nac)) )
2774 /* send reply "instantly" */
2775 send_client_reply (client,
2780 if (result_af == AF_UNSPEC)
2782 /* failure, we're done */
2783 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2784 _("Failed to allocate IP address for new destination\n"));
2785 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2790 char sbuf[INET6_ADDRSTRLEN];
2792 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2793 "Allocated address %s for redirection to service %s on peer %s\n",
2794 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2795 GNUNET_h2s (&msg->service_descriptor),
2796 GNUNET_i2s (&msg->target));
2799 /* setup destination record */
2800 de = GNUNET_malloc (sizeof (struct DestinationEntry));
2801 de->is_service = GNUNET_YES;
2802 de->details.service_destination.service_descriptor = msg->service_descriptor;
2803 de->details.service_destination.target = msg->target;
2804 get_destination_key_from_ip (result_af,
2808 GNUNET_assert (GNUNET_OK ==
2809 GNUNET_CONTAINER_multihashmap_put (destination_map,
2812 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2813 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2815 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value_us);
2816 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2817 expire_destination (de);
2818 ts = create_tunnel_to_destination (de,
2819 (GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
2825 ts->destination_ip.v4 = v4;
2828 ts->destination_ip.v6 = v6;
2834 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2839 * Function called whenever an inbound tunnel is destroyed. Should clean up
2840 * any associated state.
2842 * FIXME now its also user for disconnections
2844 * @param cls closure (set from GNUNET_MESH_connect)
2845 * @param tunnel connection to the other end (henceforth invalid)
2846 * @param tunnel_ctx place where local state associated
2847 * with the tunnel is stored (our 'struct TunnelState')
2850 tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel_ctx)
2852 /* we don't have inbound tunnels, so this function should never be called */
2858 * Free memory occupied by an entry in the destination map.
2862 * @param value a 'struct DestinationEntry *'
2863 * @return GNUNET_OK (continue to iterate)
2866 cleanup_destination (void *cls,
2867 const struct GNUNET_HashCode *key,
2870 struct DestinationEntry *de = value;
2872 free_destination_entry (de);
2878 * Free memory occupied by an entry in the tunnel map.
2882 * @param value a 'struct TunnelState *'
2883 * @return GNUNET_OK (continue to iterate)
2886 cleanup_tunnel (void *cls,
2887 const struct GNUNET_HashCode *key,
2890 struct TunnelState *ts = value;
2892 free_tunnel_state (ts);
2898 * Function scheduled as very last function, cleans up after us
2904 cleanup (void *cls GNUNET_UNUSED,
2905 const struct GNUNET_SCHEDULER_TaskContext *tc)
2909 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2910 "VPN is shutting down\n");
2911 if (NULL != destination_map)
2913 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
2914 &cleanup_destination,
2916 GNUNET_CONTAINER_multihashmap_destroy (destination_map);
2917 destination_map = NULL;
2919 if (NULL != destination_heap)
2921 GNUNET_CONTAINER_heap_destroy (destination_heap);
2922 destination_heap = NULL;
2924 if (NULL != tunnel_map)
2926 GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
2929 GNUNET_CONTAINER_multihashmap_destroy (tunnel_map);
2932 if (NULL != tunnel_heap)
2934 GNUNET_CONTAINER_heap_destroy (tunnel_heap);
2937 if (NULL != mesh_handle)
2939 GNUNET_MESH_disconnect (mesh_handle);
2942 if (NULL != helper_handle)
2944 GNUNET_HELPER_stop (helper_handle, GNUNET_NO);
2945 helper_handle = NULL;
2949 GNUNET_SERVER_notification_context_destroy (nc);
2954 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
2958 GNUNET_free_non_null (vpn_argv[i]);
2963 * A client disconnected, clean up all references to it.
2965 * @param cls the client that disconnected
2967 * @param value a 'struct TunnelState *'
2968 * @return GNUNET_OK (continue to iterate)
2971 cleanup_tunnel_client (void *cls,
2972 const struct GNUNET_HashCode *key,
2975 struct GNUNET_SERVER_Client *client = cls;
2976 struct TunnelState *ts = value;
2978 if (client == ts->client)
2985 * A client disconnected, clean up all references to it.
2987 * @param cls the client that disconnected
2989 * @param value a 'struct DestinationEntry *'
2990 * @return GNUNET_OK (continue to iterate)
2993 cleanup_destination_client (void *cls,
2994 const struct GNUNET_HashCode *key,
2997 struct GNUNET_SERVER_Client *client = cls;
2998 struct DestinationEntry *de = value;
2999 struct TunnelState *ts;
3001 if (NULL == (ts = de->ts))
3003 if (client == ts->client)
3010 * A client has disconnected from us. If we are currently building
3011 * a tunnel for it, cancel the operation.
3014 * @param client handle to the client that disconnected
3017 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
3019 if (NULL != tunnel_map)
3020 GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
3021 &cleanup_tunnel_client,
3023 if (NULL != destination_map)
3024 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
3025 &cleanup_destination_client,
3031 * Main function that will be run by the scheduler.
3033 * @param cls closure
3034 * @param server the initialized server
3035 * @param cfg_ configuration
3039 struct GNUNET_SERVER_Handle *server,
3040 const struct GNUNET_CONFIGURATION_Handle *cfg_)
3042 static const struct GNUNET_SERVER_MessageHandler service_handlers[] = {
3043 /* callback, cls, type, size */
3044 { &service_redirect_to_ip, NULL, GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP, 0},
3045 { &service_redirect_to_service, NULL,
3046 GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE,
3047 sizeof (struct RedirectToServiceRequestMessage) },
3050 static const struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
3051 { &receive_udp_back, GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY, 0},
3052 { &receive_tcp_back, GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN, 0},
3053 { &receive_icmp_back, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN, 0},
3065 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-vpn");
3068 GNUNET_OS_check_helper_binary (binary, GNUNET_YES, "-d gnunet-vpn - - 169.1.3.3.7 255.255.255.0")) //ipv4 only please!
3071 "`%s' is not SUID, refusing to run.\n",
3072 "gnunet-helper-vpn");
3073 GNUNET_free (binary);
3077 GNUNET_free (binary);
3079 stats = GNUNET_STATISTICS_create ("vpn", cfg);
3081 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_MAPPING",
3082 &max_destination_mappings))
3083 max_destination_mappings = 200;
3085 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_TUNNELS",
3086 &max_tunnel_mappings))
3087 max_tunnel_mappings = 200;
3089 destination_map = GNUNET_CONTAINER_multihashmap_create (max_destination_mappings * 2, GNUNET_NO);
3090 destination_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3091 tunnel_map = GNUNET_CONTAINER_multihashmap_create (max_tunnel_mappings * 2, GNUNET_NO);
3092 tunnel_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3095 vpn_argv[0] = GNUNET_strdup ("vpn-gnunet");
3096 if (GNUNET_SYSERR ==
3097 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IFNAME", &ifname))
3099 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3100 "No entry 'IFNAME' in configuration!\n");
3101 GNUNET_SCHEDULER_shutdown ();
3104 vpn_argv[1] = ifname;
3105 if (GNUNET_OK == GNUNET_NETWORK_test_pf (PF_INET6))
3107 if ( (GNUNET_SYSERR ==
3108 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6ADDR",
3110 (1 != inet_pton (AF_INET6, ipv6addr, &v6))) )
3112 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3113 "No valid entry 'IPV6ADDR' in configuration!\n");
3114 GNUNET_SCHEDULER_shutdown ();
3117 vpn_argv[2] = ipv6addr;
3118 if (GNUNET_SYSERR ==
3119 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6PREFIX",
3122 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3123 "No entry 'IPV6PREFIX' in configuration!\n");
3124 GNUNET_SCHEDULER_shutdown ();
3127 vpn_argv[3] = ipv6prefix_s;
3129 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn",
3132 (ipv6prefix >= 127) )
3134 GNUNET_SCHEDULER_shutdown ();
3140 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3141 _("IPv6 support disabled as this system does not support IPv6\n"));
3142 vpn_argv[2] = GNUNET_strdup ("-");
3143 vpn_argv[3] = GNUNET_strdup ("-");
3145 if (GNUNET_OK == GNUNET_NETWORK_test_pf (PF_INET))
3147 if ( (GNUNET_SYSERR ==
3148 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4ADDR",
3150 (1 != inet_pton (AF_INET, ipv4addr, &v4))) )
3152 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3153 "No valid entry for 'IPV4ADDR' in configuration!\n");
3154 GNUNET_SCHEDULER_shutdown ();
3157 vpn_argv[4] = ipv4addr;
3158 if ( (GNUNET_SYSERR ==
3159 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4MASK",
3161 (1 != inet_pton (AF_INET, ipv4mask, &v4))) )
3163 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3164 "No valid entry 'IPV4MASK' in configuration!\n");
3165 GNUNET_SCHEDULER_shutdown ();
3168 vpn_argv[5] = ipv4mask;
3172 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3173 _("IPv4 support disabled as this system does not support IPv4\n"));
3174 vpn_argv[4] = GNUNET_strdup ("-");
3175 vpn_argv[5] = GNUNET_strdup ("-");
3180 GNUNET_MESH_connect (cfg_, NULL,
3185 helper_handle = GNUNET_HELPER_start (GNUNET_NO,
3186 "gnunet-helper-vpn", vpn_argv,
3187 &message_token, NULL, NULL);
3188 nc = GNUNET_SERVER_notification_context_create (server, 1);
3189 GNUNET_SERVER_add_handlers (server, service_handlers);
3190 GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
3191 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls);
3196 * The main function of the VPN service.
3198 * @param argc number of arguments from the command line
3199 * @param argv command line arguments
3200 * @return 0 ok, 1 on error
3203 main (int argc, char *const *argv)
3205 return (GNUNET_OK ==
3206 GNUNET_SERVICE_run (argc, argv, "vpn",
3207 GNUNET_SERVICE_OPTION_NONE,
3208 &run, NULL)) ? global_ret : 1;
3211 /* end of gnunet-service-vpn.c */