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);
1036 if (! destination->is_service)
1038 switch (destination->details.exit_destination.af)
1041 alen = sizeof (struct in_addr);
1044 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)),
1071 /* make compiler happy */
1074 char sbuf[INET6_ADDRSTRLEN];
1075 char dbuf[INET6_ADDRSTRLEN];
1077 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1078 "Routing %s packet from %s:%u -> %s:%u to service %s at peer %s\n",
1079 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
1080 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
1082 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
1084 GNUNET_h2s (&destination->details.service_destination.service_descriptor),
1085 GNUNET_i2s (&destination->details.service_destination.target));
1090 /* see if we have an existing tunnel for this destination */
1091 ts = GNUNET_CONTAINER_multihashmap_get (tunnel_map,
1095 /* need to either use the existing tunnel from the destination (if still
1096 available) or create a fresh one */
1097 is_new = GNUNET_YES;
1098 if (NULL == destination->ts)
1099 ts = create_tunnel_to_destination (destination, NULL, af, 0);
1101 ts = destination->ts;
1104 destination->ts = NULL;
1105 ts->destination_container = NULL; /* no longer 'contained' */
1106 /* now bind existing "unbound" tunnel to our IP/port tuple */
1107 ts->protocol = protocol;
1111 ts->source_ip.v4 = * (const struct in_addr *) source_ip;
1112 ts->destination_ip.v4 = * (const struct in_addr *) destination_ip;
1116 ts->source_ip.v6 = * (const struct in6_addr *) source_ip;
1117 ts->destination_ip.v6 = * (const struct in6_addr *) destination_ip;
1119 ts->source_port = source_port;
1120 ts->destination_port = destination_port;
1121 ts->heap_node = GNUNET_CONTAINER_heap_insert (tunnel_heap,
1123 GNUNET_TIME_absolute_get ().abs_value_us);
1124 GNUNET_assert (GNUNET_YES ==
1125 GNUNET_CONTAINER_multihashmap_put (tunnel_map,
1128 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1129 GNUNET_STATISTICS_update (stats,
1130 gettext_noop ("# Active tunnels"),
1132 while (GNUNET_CONTAINER_multihashmap_size (tunnel_map) > max_tunnel_mappings)
1138 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
1140 GNUNET_TIME_absolute_get ().abs_value_us);
1142 GNUNET_assert (NULL != ts->tunnel);
1144 /* send via tunnel */
1148 if (destination->is_service)
1150 struct GNUNET_EXIT_UdpServiceMessage *usm;
1152 mlen = sizeof (struct GNUNET_EXIT_UdpServiceMessage) +
1153 payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1154 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1159 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1162 usm = (struct GNUNET_EXIT_UdpServiceMessage *) &tnq[1];
1163 usm->header.size = htons ((uint16_t) mlen);
1164 usm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE);
1165 /* if the source port is below 32000, we assume it has a special
1166 meaning; if not, we pick a random port (this is a heuristic) */
1167 usm->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1168 usm->destination_port = udp->destination_port;
1169 usm->service_descriptor = destination->details.service_destination.service_descriptor;
1172 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1176 struct GNUNET_EXIT_UdpInternetMessage *uim;
1177 struct in_addr *ip4dst;
1178 struct in6_addr *ip6dst;
1181 mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) +
1182 alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1183 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1188 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) +
1192 uim = (struct GNUNET_EXIT_UdpInternetMessage *) &tnq[1];
1193 uim->header.size = htons ((uint16_t) mlen);
1194 uim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET);
1195 uim->af = htonl (destination->details.exit_destination.af);
1196 uim->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1197 uim->destination_port = udp->destination_port;
1198 switch (destination->details.exit_destination.af)
1201 ip4dst = (struct in_addr *) &uim[1];
1202 *ip4dst = destination->details.exit_destination.ip.v4;
1203 payload = &ip4dst[1];
1206 ip6dst = (struct in6_addr *) &uim[1];
1207 *ip6dst = destination->details.exit_destination.ip.v6;
1208 payload = &ip6dst[1];
1215 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1221 if (destination->is_service)
1223 struct GNUNET_EXIT_TcpServiceStartMessage *tsm;
1225 mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) +
1226 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1227 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1232 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1235 tsm = (struct GNUNET_EXIT_TcpServiceStartMessage *) &tnq[1];
1236 tsm->header.size = htons ((uint16_t) mlen);
1237 tsm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START);
1238 tsm->reserved = htonl (0);
1239 tsm->service_descriptor = destination->details.service_destination.service_descriptor;
1240 tsm->tcp_header = *tcp;
1243 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1247 struct GNUNET_EXIT_TcpInternetStartMessage *tim;
1248 struct in_addr *ip4dst;
1249 struct in6_addr *ip6dst;
1252 mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) +
1253 alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1254 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1259 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1262 tim = (struct GNUNET_EXIT_TcpInternetStartMessage *) &tnq[1];
1263 tim->header.size = htons ((uint16_t) mlen);
1264 tim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START);
1265 tim->af = htonl (destination->details.exit_destination.af);
1266 tim->tcp_header = *tcp;
1267 switch (destination->details.exit_destination.af)
1270 ip4dst = (struct in_addr *) &tim[1];
1271 *ip4dst = destination->details.exit_destination.ip.v4;
1272 payload = &ip4dst[1];
1275 ip6dst = (struct in6_addr *) &tim[1];
1276 *ip6dst = destination->details.exit_destination.ip.v6;
1277 payload = &ip6dst[1];
1284 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1289 struct GNUNET_EXIT_TcpDataMessage *tdm;
1291 mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) +
1292 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1293 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1298 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1301 tdm = (struct GNUNET_EXIT_TcpDataMessage *) &tnq[1];
1302 tdm->header.size = htons ((uint16_t) mlen);
1303 tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT);
1304 tdm->reserved = htonl (0);
1305 tdm->tcp_header = *tcp;
1308 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1312 case IPPROTO_ICMPV6:
1313 if (destination->is_service)
1315 struct GNUNET_EXIT_IcmpServiceMessage *ism;
1317 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1318 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1319 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1324 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1326 ism = (struct GNUNET_EXIT_IcmpServiceMessage *) &tnq[1];
1327 ism->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE);
1328 ism->af = htonl (af); /* need to tell destination ICMP protocol family! */
1329 ism->service_descriptor = destination->details.service_destination.service_descriptor;
1330 ism->icmp_header = *icmp;
1331 /* ICMP protocol translation will be done by the receiver (as we don't know
1332 the target AF); however, we still need to possibly discard the payload
1333 depending on the ICMP type */
1339 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1340 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1342 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1343 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1344 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1345 /* throw away ICMP payload, won't be useful for the other side anyway */
1346 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1349 GNUNET_STATISTICS_update (stats,
1350 gettext_noop ("# ICMPv4 packets dropped (not allowed)"),
1354 /* end of AF_INET */
1359 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1360 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1361 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1362 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1363 /* throw away ICMP payload, won't be useful for the other side anyway */
1364 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1366 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1367 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1370 GNUNET_STATISTICS_update (stats,
1371 gettext_noop ("# ICMPv6 packets dropped (not allowed)"),
1375 /* end of AF_INET6 */
1382 /* update length calculations, as payload_length may have changed */
1383 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1384 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1386 ism->header.size = htons ((uint16_t) mlen);
1387 /* finally, copy payload (if there is any left...) */
1390 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1394 struct GNUNET_EXIT_IcmpInternetMessage *iim;
1395 struct in_addr *ip4dst;
1396 struct in6_addr *ip6dst;
1399 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1400 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1401 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1406 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) +
1409 iim = (struct GNUNET_EXIT_IcmpInternetMessage *) &tnq[1];
1410 iim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET);
1411 iim->icmp_header = *icmp;
1412 /* Perform ICMP protocol-translation (depending on destination AF and source AF)
1413 and throw away ICMP payload depending on ICMP message type */
1419 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1420 if (destination->details.exit_destination.af == AF_INET6)
1421 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1423 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1424 if (destination->details.exit_destination.af == AF_INET6)
1425 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1427 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1428 if (destination->details.exit_destination.af == AF_INET6)
1429 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1430 /* throw away IP-payload, exit will have to make it up anyway */
1431 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1433 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1434 if (destination->details.exit_destination.af == AF_INET6)
1435 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1436 /* throw away IP-payload, exit will have to make it up anyway */
1437 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1439 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1440 if (destination->details.exit_destination.af == AF_INET6)
1442 GNUNET_STATISTICS_update (stats,
1443 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1448 /* throw away IP-payload, exit will have to make it up anyway */
1449 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1452 GNUNET_STATISTICS_update (stats,
1453 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1458 /* end of AF_INET */
1463 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1464 if (destination->details.exit_destination.af == AF_INET6)
1465 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1466 /* throw away IP-payload, exit will have to make it up anyway */
1467 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1469 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1470 if (destination->details.exit_destination.af == AF_INET)
1471 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1472 /* throw away IP-payload, exit will have to make it up anyway */
1473 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1475 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1476 if (destination->details.exit_destination.af == AF_INET)
1478 GNUNET_STATISTICS_update (stats,
1479 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1484 /* throw away IP-payload, exit will have to make it up anyway */
1485 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1487 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1488 if (destination->details.exit_destination.af == AF_INET)
1490 GNUNET_STATISTICS_update (stats,
1491 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1496 /* throw away IP-payload, exit will have to make it up anyway */
1497 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1499 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1500 if (destination->details.exit_destination.af == AF_INET)
1501 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1503 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1504 if (destination->details.exit_destination.af == AF_INET)
1505 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1508 GNUNET_STATISTICS_update (stats,
1509 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1514 /* end of AF_INET6 */
1519 /* update length calculations, as payload_length may have changed */
1520 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1521 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1523 iim->header.size = htons ((uint16_t) mlen);
1525 /* need to tell destination ICMP protocol family! */
1526 iim->af = htonl (destination->details.exit_destination.af);
1527 switch (destination->details.exit_destination.af)
1530 ip4dst = (struct in_addr *) &iim[1];
1531 *ip4dst = destination->details.exit_destination.ip.v4;
1532 payload = &ip4dst[1];
1535 ip6dst = (struct in6_addr *) &iim[1];
1536 *ip6dst = destination->details.exit_destination.ip.v6;
1537 payload = &ip6dst[1];
1544 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1548 /* not supported above, how can we get here !? */
1552 send_to_tunnel (tnq, ts);
1557 * Receive packets from the helper-process (someone send to the local
1558 * virtual tunnel interface). Find the destination mapping, and if it
1559 * exists, identify the correct MESH tunnel (or possibly create it)
1560 * and forward the packet.
1562 * @param cls closure, NULL
1563 * @param client NULL
1564 * @param message message we got from the client (VPN tunnel interface)
1567 message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED,
1568 const struct GNUNET_MessageHeader *message)
1570 const struct GNUNET_TUN_Layer2PacketHeader *tun;
1572 struct GNUNET_HashCode key;
1573 struct DestinationEntry *de;
1575 GNUNET_STATISTICS_update (stats,
1576 gettext_noop ("# Packets received from TUN interface"),
1578 mlen = ntohs (message->size);
1579 if ( (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
1580 (mlen < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader)) )
1585 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1586 mlen -= (sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader));
1587 switch (ntohs (tun->proto))
1591 const struct GNUNET_TUN_IPv6Header *pkt6;
1593 if (mlen < sizeof (struct GNUNET_TUN_IPv6Header))
1599 pkt6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1600 get_destination_key_from_ip (AF_INET6,
1601 &pkt6->destination_address,
1603 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1604 /* FIXME: do we need to guard against hash collision?
1605 (if so, we need to also store the local destination IP in the
1606 destination entry and then compare here; however, the risk
1607 of collision seems minimal AND the impact is unlikely to be
1608 super-problematic as well... */
1611 char buf[INET6_ADDRSTRLEN];
1613 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1614 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1615 inet_ntop (AF_INET6,
1616 &pkt6->destination_address,
1624 &pkt6->source_address,
1625 &pkt6->destination_address,
1627 mlen - sizeof (struct GNUNET_TUN_IPv6Header));
1632 struct GNUNET_TUN_IPv4Header *pkt4;
1634 if (mlen < sizeof (struct GNUNET_TUN_IPv4Header))
1640 pkt4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1641 get_destination_key_from_ip (AF_INET,
1642 &pkt4->destination_address,
1644 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1645 /* FIXME: do we need to guard against hash collision?
1646 (if so, we need to also store the local destination IP in the
1647 destination entry and then compare here; however, the risk
1648 of collision seems minimal AND the impact is unlikely to be
1649 super-problematic as well... */
1652 char buf[INET_ADDRSTRLEN];
1654 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1655 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1657 &pkt4->destination_address,
1662 if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header))
1664 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1665 _("Received IPv4 packet with options (dropping it)\n"));
1671 &pkt4->source_address,
1672 &pkt4->destination_address,
1674 mlen - sizeof (struct GNUNET_TUN_IPv4Header));
1678 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1679 _("Received packet of unknown protocol %d from TUN (dropping it)\n"),
1680 (unsigned int) ntohs (tun->proto));
1688 * Synthesize a plausible ICMP payload for an ICMP error
1689 * response on the given tunnel.
1691 * @param ts tunnel information
1692 * @param ipp IPv4 header to fill in (ICMP payload)
1693 * @param udp "UDP" header to fill in (ICMP payload); might actually
1694 * also be the first 8 bytes of the TCP header
1697 make_up_icmpv4_payload (struct TunnelState *ts,
1698 struct GNUNET_TUN_IPv4Header *ipp,
1699 struct GNUNET_TUN_UdpHeader *udp)
1701 GNUNET_TUN_initialize_ipv4_header (ipp,
1703 sizeof (struct GNUNET_TUN_TcpHeader),
1705 &ts->destination_ip.v4);
1706 udp->source_port = htons (ts->source_port);
1707 udp->destination_port = htons (ts->destination_port);
1708 udp->len = htons (0);
1709 udp->crc = htons (0);
1714 * Synthesize a plausible ICMP payload for an ICMP error
1715 * response on the given tunnel.
1717 * @param ts tunnel information
1718 * @param ipp IPv6 header to fill in (ICMP payload)
1719 * @param udp "UDP" header to fill in (ICMP payload); might actually
1720 * also be the first 8 bytes of the TCP header
1723 make_up_icmpv6_payload (struct TunnelState *ts,
1724 struct GNUNET_TUN_IPv6Header *ipp,
1725 struct GNUNET_TUN_UdpHeader *udp)
1727 GNUNET_TUN_initialize_ipv6_header (ipp,
1729 sizeof (struct GNUNET_TUN_TcpHeader),
1731 &ts->destination_ip.v6);
1732 udp->source_port = htons (ts->source_port);
1733 udp->destination_port = htons (ts->destination_port);
1734 udp->len = htons (0);
1735 udp->crc = htons (0);
1740 * We got an ICMP packet back from the MESH tunnel. Pass it on to the
1741 * local virtual interface via the helper.
1743 * @param cls closure, NULL
1744 * @param tunnel connection to the other end
1745 * @param tunnel_ctx pointer to our 'struct TunnelState *'
1746 * @param message the actual message
1748 * @return GNUNET_OK to keep the connection open,
1749 * GNUNET_SYSERR to close it (signal serious error)
1752 receive_icmp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1754 const struct GNUNET_MessageHeader *message)
1756 struct TunnelState *ts = *tunnel_ctx;
1757 const struct GNUNET_EXIT_IcmpToVPNMessage *i2v;
1760 GNUNET_STATISTICS_update (stats,
1761 gettext_noop ("# ICMP packets received from mesh"),
1763 mlen = ntohs (message->size);
1764 if (mlen < sizeof (struct GNUNET_EXIT_IcmpToVPNMessage))
1766 GNUNET_break_op (0);
1767 return GNUNET_SYSERR;
1769 if (NULL == ts->heap_node)
1771 GNUNET_break_op (0);
1772 return GNUNET_SYSERR;
1774 if (AF_UNSPEC == ts->af)
1776 GNUNET_break_op (0);
1777 return GNUNET_SYSERR;
1779 i2v = (const struct GNUNET_EXIT_IcmpToVPNMessage *) message;
1780 mlen -= sizeof (struct GNUNET_EXIT_IcmpToVPNMessage);
1782 char sbuf[INET6_ADDRSTRLEN];
1783 char dbuf[INET6_ADDRSTRLEN];
1785 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1786 "Received ICMP packet from mesh, sending %u bytes from %s -> %s via TUN\n",
1787 (unsigned int) mlen,
1788 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
1789 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)));
1795 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
1796 + sizeof (struct GNUNET_TUN_IcmpHeader)
1797 + sizeof (struct GNUNET_MessageHeader) +
1798 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1801 /* reserve some extra space in case we have an ICMP type here where
1802 we will need to make up the payload ourselves */
1803 char buf[size + sizeof (struct GNUNET_TUN_IPv4Header) + 8] GNUNET_ALIGN;
1804 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1805 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1806 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1807 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv4[1];
1808 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1809 tun->flags = htons (0);
1810 tun->proto = htons (ETH_P_IPV4);
1811 GNUNET_TUN_initialize_ipv4_header (ipv4,
1813 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1814 &ts->destination_ip.v4,
1816 *icmp = i2v->icmp_header;
1820 /* For some ICMP types, we need to adjust (make up) the payload here.
1821 Also, depending on the AF used on the other side, we have to
1822 do ICMP PT (translate ICMP types) */
1823 switch (ntohl (i2v->af))
1828 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1829 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1831 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1832 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1833 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1835 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1836 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1840 /* sender did not strip ICMP payload? */
1841 GNUNET_break_op (0);
1842 return GNUNET_SYSERR;
1844 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1845 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1846 make_up_icmpv4_payload (ts, ipp, udp);
1850 GNUNET_break_op (0);
1851 GNUNET_STATISTICS_update (stats,
1852 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1854 return GNUNET_SYSERR;
1859 /* ICMP PT 6-to-4 and possibly making up payloads */
1862 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1863 icmp->type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
1865 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1866 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1870 /* sender did not strip ICMP payload? */
1871 GNUNET_break_op (0);
1872 return GNUNET_SYSERR;
1874 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1875 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1876 make_up_icmpv4_payload (ts, ipp, udp);
1879 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1880 icmp->type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1882 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1883 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1887 /* sender did not strip ICMP payload? */
1888 GNUNET_break_op (0);
1889 return GNUNET_SYSERR;
1891 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1892 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1893 make_up_icmpv4_payload (ts, ipp, udp);
1896 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1897 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1898 GNUNET_STATISTICS_update (stats,
1899 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1902 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1903 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1905 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1906 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1909 GNUNET_break_op (0);
1910 GNUNET_STATISTICS_update (stats,
1911 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1913 return GNUNET_SYSERR;
1918 GNUNET_break_op (0);
1919 return GNUNET_SYSERR;
1921 msg->size = htons (size);
1922 GNUNET_TUN_calculate_icmp_checksum (icmp,
1925 (void) GNUNET_HELPER_send (helper_handle,
1934 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
1935 + sizeof (struct GNUNET_TUN_IcmpHeader)
1936 + sizeof (struct GNUNET_MessageHeader) +
1937 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1940 char buf[size + sizeof (struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN;
1941 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1942 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1943 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
1944 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv6[1];
1945 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1946 tun->flags = htons (0);
1947 tun->proto = htons (ETH_P_IPV6);
1948 GNUNET_TUN_initialize_ipv6_header (ipv6,
1950 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1951 &ts->destination_ip.v6,
1953 *icmp = i2v->icmp_header;
1958 /* For some ICMP types, we need to adjust (make up) the payload here.
1959 Also, depending on the AF used on the other side, we have to
1960 do ICMP PT (translate ICMP types) */
1961 switch (ntohl (i2v->af))
1964 /* ICMP PT 4-to-6 and possibly making up payloads */
1967 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1968 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1970 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1971 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1973 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1974 icmp->type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1976 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1977 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1981 /* sender did not strip ICMP payload? */
1982 GNUNET_break_op (0);
1983 return GNUNET_SYSERR;
1985 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1986 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1987 make_up_icmpv6_payload (ts, ipp, udp);
1990 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1991 icmp->type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1993 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1994 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1998 /* sender did not strip ICMP payload? */
1999 GNUNET_break_op (0);
2000 return GNUNET_SYSERR;
2002 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
2003 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
2004 make_up_icmpv6_payload (ts, ipp, udp);
2007 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
2008 GNUNET_STATISTICS_update (stats,
2009 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
2013 GNUNET_break_op (0);
2014 GNUNET_STATISTICS_update (stats,
2015 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
2017 return GNUNET_SYSERR;
2024 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
2025 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
2026 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
2027 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
2029 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
2030 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
2034 /* sender did not strip ICMP payload? */
2035 GNUNET_break_op (0);
2036 return GNUNET_SYSERR;
2038 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
2039 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
2040 make_up_icmpv6_payload (ts, ipp, udp);
2043 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
2046 GNUNET_break_op (0);
2047 GNUNET_STATISTICS_update (stats,
2048 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
2050 return GNUNET_SYSERR;
2055 GNUNET_break_op (0);
2056 return GNUNET_SYSERR;
2058 msg->size = htons (size);
2059 GNUNET_TUN_calculate_icmp_checksum (icmp,
2061 (void) GNUNET_HELPER_send (helper_handle,
2071 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2073 GNUNET_TIME_absolute_get ().abs_value_us);
2079 * We got a UDP packet back from the MESH tunnel. Pass it on to the
2080 * local virtual interface via the helper.
2082 * @param cls closure, NULL
2083 * @param tunnel connection to the other end
2084 * @param tunnel_ctx pointer to our 'struct TunnelState *'
2085 * @param message the actual message
2087 * @return GNUNET_OK to keep the connection open,
2088 * GNUNET_SYSERR to close it (signal serious error)
2091 receive_udp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
2093 const struct GNUNET_MessageHeader *message)
2095 struct TunnelState *ts = *tunnel_ctx;
2096 const struct GNUNET_EXIT_UdpReplyMessage *reply;
2099 GNUNET_STATISTICS_update (stats,
2100 gettext_noop ("# UDP packets received from mesh"),
2102 mlen = ntohs (message->size);
2103 if (mlen < sizeof (struct GNUNET_EXIT_UdpReplyMessage))
2105 GNUNET_break_op (0);
2106 return GNUNET_SYSERR;
2108 if (NULL == ts->heap_node)
2110 GNUNET_break_op (0);
2111 return GNUNET_SYSERR;
2113 if (AF_UNSPEC == ts->af)
2115 GNUNET_break_op (0);
2116 return GNUNET_SYSERR;
2118 reply = (const struct GNUNET_EXIT_UdpReplyMessage *) message;
2119 mlen -= sizeof (struct GNUNET_EXIT_UdpReplyMessage);
2121 char sbuf[INET6_ADDRSTRLEN];
2122 char dbuf[INET6_ADDRSTRLEN];
2124 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2125 "Received UDP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2126 (unsigned int) mlen,
2127 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2128 ts->destination_port,
2129 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2136 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2137 + sizeof (struct GNUNET_TUN_UdpHeader)
2138 + sizeof (struct GNUNET_MessageHeader) +
2139 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2142 char buf[size] GNUNET_ALIGN;
2143 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2144 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2145 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2146 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1];
2147 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2148 msg->size = htons (size);
2149 tun->flags = htons (0);
2150 tun->proto = htons (ETH_P_IPV4);
2151 GNUNET_TUN_initialize_ipv4_header (ipv4,
2153 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2154 &ts->destination_ip.v4,
2156 if (0 == ntohs (reply->source_port))
2157 udp->source_port = htons (ts->destination_port);
2159 udp->source_port = reply->source_port;
2160 if (0 == ntohs (reply->destination_port))
2161 udp->destination_port = htons (ts->source_port);
2163 udp->destination_port = reply->destination_port;
2164 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2165 GNUNET_TUN_calculate_udp4_checksum (ipv4,
2172 (void) GNUNET_HELPER_send (helper_handle,
2181 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2182 + sizeof (struct GNUNET_TUN_UdpHeader)
2183 + sizeof (struct GNUNET_MessageHeader) +
2184 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2187 char buf[size] GNUNET_ALIGN;
2188 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2189 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2190 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2191 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1];
2192 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2193 msg->size = htons (size);
2194 tun->flags = htons (0);
2195 tun->proto = htons (ETH_P_IPV6);
2196 GNUNET_TUN_initialize_ipv6_header (ipv6,
2198 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2199 &ts->destination_ip.v6,
2201 if (0 == ntohs (reply->source_port))
2202 udp->source_port = htons (ts->destination_port);
2204 udp->source_port = reply->source_port;
2205 if (0 == ntohs (reply->destination_port))
2206 udp->destination_port = htons (ts->source_port);
2208 udp->destination_port = reply->destination_port;
2209 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2210 GNUNET_TUN_calculate_udp6_checksum (ipv6,
2216 (void) GNUNET_HELPER_send (helper_handle,
2226 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2228 GNUNET_TIME_absolute_get ().abs_value_us);
2234 * We got a TCP packet back from the MESH tunnel. Pass it on to the
2235 * local virtual interface via the helper.
2237 * @param cls closure, NULL
2238 * @param tunnel connection to the other end
2239 * @param tunnel_ctx pointer to our 'struct TunnelState *'
2240 * @param message the actual message
2242 * @return GNUNET_OK to keep the connection open,
2243 * GNUNET_SYSERR to close it (signal serious error)
2246 receive_tcp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
2248 const struct GNUNET_MessageHeader *message)
2250 struct TunnelState *ts = *tunnel_ctx;
2251 const struct GNUNET_EXIT_TcpDataMessage *data;
2254 GNUNET_STATISTICS_update (stats,
2255 gettext_noop ("# TCP packets received from mesh"),
2257 mlen = ntohs (message->size);
2258 if (mlen < sizeof (struct GNUNET_EXIT_TcpDataMessage))
2260 GNUNET_break_op (0);
2261 return GNUNET_SYSERR;
2263 if (NULL == ts->heap_node)
2265 GNUNET_break_op (0);
2266 return GNUNET_SYSERR;
2268 data = (const struct GNUNET_EXIT_TcpDataMessage *) message;
2269 mlen -= sizeof (struct GNUNET_EXIT_TcpDataMessage);
2271 char sbuf[INET6_ADDRSTRLEN];
2272 char dbuf[INET6_ADDRSTRLEN];
2274 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2275 "Received TCP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2276 (unsigned int) mlen,
2277 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2278 ts->destination_port,
2279 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2282 if (data->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
2284 GNUNET_break_op (0);
2285 return GNUNET_SYSERR;
2291 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2292 + sizeof (struct GNUNET_TUN_TcpHeader)
2293 + sizeof (struct GNUNET_MessageHeader) +
2294 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2297 char buf[size] GNUNET_ALIGN;
2298 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2299 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2300 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2301 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv4[1];
2302 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2303 msg->size = htons (size);
2304 tun->flags = htons (0);
2305 tun->proto = htons (ETH_P_IPV4);
2306 GNUNET_TUN_initialize_ipv4_header (ipv4,
2308 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2309 &ts->destination_ip.v4,
2311 *tcp = data->tcp_header;
2312 tcp->source_port = htons (ts->destination_port);
2313 tcp->destination_port = htons (ts->source_port);
2314 GNUNET_TUN_calculate_tcp4_checksum (ipv4,
2321 (void) GNUNET_HELPER_send (helper_handle,
2330 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2331 + sizeof (struct GNUNET_TUN_TcpHeader)
2332 + sizeof (struct GNUNET_MessageHeader) +
2333 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2336 char buf[size] GNUNET_ALIGN;
2337 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2338 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2339 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2340 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv6[1];
2341 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2342 msg->size = htons (size);
2343 tun->flags = htons (0);
2344 tun->proto = htons (ETH_P_IPV6);
2345 GNUNET_TUN_initialize_ipv6_header (ipv6,
2347 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2348 &ts->destination_ip.v6,
2350 *tcp = data->tcp_header;
2351 tcp->source_port = htons (ts->destination_port);
2352 tcp->destination_port = htons (ts->source_port);
2353 GNUNET_TUN_calculate_tcp6_checksum (ipv6,
2360 (void) GNUNET_HELPER_send (helper_handle,
2368 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2370 GNUNET_TIME_absolute_get ().abs_value_us);
2376 * Allocate an IPv4 address from the range of the tunnel
2377 * for a new redirection.
2379 * @param v4 where to store the address
2380 * @return GNUNET_OK on success,
2381 * GNUNET_SYSERR on error
2384 allocate_v4_address (struct in_addr *v4)
2386 const char *ipv4addr = vpn_argv[4];
2387 const char *ipv4mask = vpn_argv[5];
2388 struct in_addr addr;
2389 struct in_addr mask;
2391 struct GNUNET_HashCode key;
2394 GNUNET_assert (1 == inet_pton (AF_INET, ipv4addr, &addr));
2395 GNUNET_assert (1 == inet_pton (AF_INET, ipv4mask, &mask));
2396 /* Given 192.168.0.1/255.255.0.0, we want a mask
2397 of '192.168.255.255', thus: */
2398 mask.s_addr = addr.s_addr | ~mask.s_addr;
2405 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2406 _("Failed to find unallocated IPv4 address in VPN's range\n"));
2407 return GNUNET_SYSERR;
2409 /* Pick random IPv4 address within the subnet, except 'addr' or 'mask' itself */
2410 rnd.s_addr = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2412 v4->s_addr = (addr.s_addr | rnd.s_addr) & mask.s_addr;
2413 get_destination_key_from_ip (AF_INET,
2417 while ( (GNUNET_YES ==
2418 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2420 (v4->s_addr == addr.s_addr) ||
2421 (v4->s_addr == mask.s_addr) );
2427 * Allocate an IPv6 address from the range of the tunnel
2428 * for a new redirection.
2430 * @param v6 where to store the address
2431 * @return GNUNET_OK on success,
2432 * GNUNET_SYSERR on error
2435 allocate_v6_address (struct in6_addr *v6)
2437 const char *ipv6addr = vpn_argv[2];
2438 struct in6_addr addr;
2439 struct in6_addr mask;
2440 struct in6_addr rnd;
2442 struct GNUNET_HashCode key;
2445 GNUNET_assert (1 == inet_pton (AF_INET6, ipv6addr, &addr));
2446 GNUNET_assert (ipv6prefix < 128);
2447 /* Given ABCD::/96, we want a mask of 'ABCD::FFFF:FFFF,
2450 for (i=127;i>=ipv6prefix;i--)
2451 mask.s6_addr[i / 8] |= (1 << (i % 8));
2453 /* Pick random IPv6 address within the subnet, except 'addr' or 'mask' itself */
2460 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2461 _("Failed to find unallocated IPv6 address in VPN's range\n"));
2462 return GNUNET_SYSERR;
2467 rnd.s6_addr[i] = (unsigned char) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2470 = (addr.s6_addr[i] | rnd.s6_addr[i]) & mask.s6_addr[i];
2472 get_destination_key_from_ip (AF_INET6,
2476 while ( (GNUNET_YES ==
2477 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2481 sizeof (struct in6_addr))) ||
2484 sizeof (struct in6_addr))) );
2490 * Free resources occupied by a destination entry.
2492 * @param de entry to free
2495 free_destination_entry (struct DestinationEntry *de)
2497 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2498 "Cleaning up destination entry\n");
2499 GNUNET_STATISTICS_update (stats,
2500 gettext_noop ("# Active destinations"),
2504 free_tunnel_state (de->ts);
2505 GNUNET_assert (NULL == de->ts);
2507 if (NULL != de->heap_node)
2509 GNUNET_CONTAINER_heap_remove_node (de->heap_node);
2510 de->heap_node = NULL;
2511 GNUNET_assert (GNUNET_YES ==
2512 GNUNET_CONTAINER_multihashmap_remove (destination_map,
2521 * We have too many active destinations. Clean up the oldest destination.
2523 * @param except destination that must NOT be cleaned up, even if it is the oldest
2526 expire_destination (struct DestinationEntry *except)
2528 struct DestinationEntry *de;
2530 de = GNUNET_CONTAINER_heap_peek (destination_heap);
2531 GNUNET_assert (NULL != de);
2533 return; /* can't do this */
2534 free_destination_entry (de);
2539 * Allocate an IP address for the response.
2541 * @param result_af desired address family; set to the actual
2542 * address family; can initially be AF_UNSPEC if there
2543 * is no preference; will be set to AF_UNSPEC if the
2545 * @param addr set to either v4 or v6 depending on which
2546 * storage location was used; set to NULL if allocation failed
2547 * @param v4 storage space for an IPv4 address
2548 * @param v6 storage space for an IPv6 address
2549 * @return GNUNET_OK normally, GNUNET_SYSERR if '*result_af' was
2550 * an unsupported address family (not AF_INET, AF_INET6 or AF_UNSPEC)
2553 allocate_response_ip (int *result_af,
2556 struct in6_addr *v6)
2563 allocate_v4_address (v4))
2564 *result_af = AF_UNSPEC;
2570 allocate_v6_address (v6))
2571 *result_af = AF_UNSPEC;
2577 allocate_v4_address (v4))
2580 *result_af = AF_INET;
2582 else if (GNUNET_OK ==
2583 allocate_v6_address (v6))
2586 *result_af = AF_INET6;
2591 return GNUNET_SYSERR;
2598 * A client asks us to setup a redirection via some exit
2599 * node to a particular IP. Setup the redirection and
2600 * give the client the allocated IP.
2603 * @param client requesting client
2604 * @param message redirection request (a 'struct RedirectToIpRequestMessage')
2607 service_redirect_to_ip (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
2608 const struct GNUNET_MessageHeader *message)
2612 const struct RedirectToIpRequestMessage *msg;
2618 struct DestinationEntry *de;
2619 struct GNUNET_HashCode key;
2620 struct TunnelState *ts;
2622 /* validate and parse request */
2623 mlen = ntohs (message->size);
2624 if (mlen < sizeof (struct RedirectToIpRequestMessage))
2627 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2630 alen = mlen - sizeof (struct RedirectToIpRequestMessage);
2631 msg = (const struct RedirectToIpRequestMessage *) message;
2632 addr_af = (int) htonl (msg->addr_af);
2636 if (alen != sizeof (struct in_addr))
2639 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2644 if (alen != sizeof (struct in6_addr))
2647 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2653 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2657 /* allocate response IP */
2658 result_af = (int) htonl (msg->result_af);
2659 if (GNUNET_OK != allocate_response_ip (&result_af,
2663 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2666 if ( (result_af == AF_UNSPEC) ||
2667 (GNUNET_NO == ntohl (msg->nac)) )
2669 /* send reply "instantly" */
2670 send_client_reply (client,
2675 if (result_af == AF_UNSPEC)
2677 /* failure, we're done */
2678 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2683 char sbuf[INET6_ADDRSTRLEN];
2684 char dbuf[INET6_ADDRSTRLEN];
2686 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2687 "Allocated address %s for redirection via exit to %s\n",
2688 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2690 &msg[1], dbuf, sizeof (dbuf)));
2693 /* setup destination record */
2694 de = GNUNET_malloc (sizeof (struct DestinationEntry));
2695 de->is_service = GNUNET_NO;
2696 de->details.exit_destination.af = addr_af;
2697 memcpy (&de->details.exit_destination.ip,
2700 get_destination_key_from_ip (result_af,
2704 GNUNET_assert (GNUNET_OK ==
2705 GNUNET_CONTAINER_multihashmap_put (destination_map,
2708 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2709 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2711 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value_us);
2712 GNUNET_STATISTICS_update (stats,
2713 gettext_noop ("# Active destinations"),
2715 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2716 expire_destination (de);
2718 /* setup tunnel to destination */
2719 ts = create_tunnel_to_destination (de,
2720 (GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
2726 ts->destination_ip.v4 = v4;
2729 ts->destination_ip.v6 = v6;
2735 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2740 * A client asks us to setup a redirection to a particular peer
2741 * offering a service. Setup the redirection and give the client the
2745 * @param client requesting client
2746 * @param message redirection request (a 'struct RedirectToPeerRequestMessage')
2749 service_redirect_to_service (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
2750 const struct GNUNET_MessageHeader *message)
2752 const struct RedirectToServiceRequestMessage *msg;
2757 struct DestinationEntry *de;
2758 struct GNUNET_HashCode key;
2759 struct TunnelState *ts;
2762 msg = (const struct RedirectToServiceRequestMessage *) message;
2764 /* allocate response IP */
2765 result_af = (int) htonl (msg->result_af);
2766 if (GNUNET_OK != allocate_response_ip (&result_af,
2770 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2773 if ( (result_af == AF_UNSPEC) ||
2774 (GNUNET_NO == ntohl (msg->nac)) )
2776 /* send reply "instantly" */
2777 send_client_reply (client,
2782 if (result_af == AF_UNSPEC)
2784 /* failure, we're done */
2785 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2786 _("Failed to allocate IP address for new destination\n"));
2787 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2792 char sbuf[INET6_ADDRSTRLEN];
2794 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2795 "Allocated address %s for redirection to service %s on peer %s\n",
2796 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2797 GNUNET_h2s (&msg->service_descriptor),
2798 GNUNET_i2s (&msg->target));
2801 /* setup destination record */
2802 de = GNUNET_malloc (sizeof (struct DestinationEntry));
2803 de->is_service = GNUNET_YES;
2804 de->details.service_destination.service_descriptor = msg->service_descriptor;
2805 de->details.service_destination.target = msg->target;
2806 get_destination_key_from_ip (result_af,
2810 GNUNET_assert (GNUNET_OK ==
2811 GNUNET_CONTAINER_multihashmap_put (destination_map,
2814 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2815 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2817 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value_us);
2818 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2819 expire_destination (de);
2820 ts = create_tunnel_to_destination (de,
2821 (GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
2827 ts->destination_ip.v4 = v4;
2830 ts->destination_ip.v6 = v6;
2836 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2841 * Function called whenever an inbound tunnel is destroyed. Should clean up
2842 * any associated state.
2844 * FIXME now its also user for disconnections
2846 * @param cls closure (set from GNUNET_MESH_connect)
2847 * @param tunnel connection to the other end (henceforth invalid)
2848 * @param tunnel_ctx place where local state associated
2849 * with the tunnel is stored (our 'struct TunnelState')
2852 tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel_ctx)
2854 /* we don't have inbound tunnels, so this function should never be called */
2860 * Free memory occupied by an entry in the destination map.
2864 * @param value a 'struct DestinationEntry *'
2865 * @return GNUNET_OK (continue to iterate)
2868 cleanup_destination (void *cls,
2869 const struct GNUNET_HashCode *key,
2872 struct DestinationEntry *de = value;
2874 free_destination_entry (de);
2880 * Free memory occupied by an entry in the tunnel map.
2884 * @param value a 'struct TunnelState *'
2885 * @return GNUNET_OK (continue to iterate)
2888 cleanup_tunnel (void *cls,
2889 const struct GNUNET_HashCode *key,
2892 struct TunnelState *ts = value;
2894 free_tunnel_state (ts);
2900 * Function scheduled as very last function, cleans up after us
2906 cleanup (void *cls GNUNET_UNUSED,
2907 const struct GNUNET_SCHEDULER_TaskContext *tc)
2911 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2912 "VPN is shutting down\n");
2913 if (NULL != destination_map)
2915 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
2916 &cleanup_destination,
2918 GNUNET_CONTAINER_multihashmap_destroy (destination_map);
2919 destination_map = NULL;
2921 if (NULL != destination_heap)
2923 GNUNET_CONTAINER_heap_destroy (destination_heap);
2924 destination_heap = NULL;
2926 if (NULL != tunnel_map)
2928 GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
2931 GNUNET_CONTAINER_multihashmap_destroy (tunnel_map);
2934 if (NULL != tunnel_heap)
2936 GNUNET_CONTAINER_heap_destroy (tunnel_heap);
2939 if (NULL != mesh_handle)
2941 GNUNET_MESH_disconnect (mesh_handle);
2944 if (NULL != helper_handle)
2946 GNUNET_HELPER_stop (helper_handle, GNUNET_NO);
2947 helper_handle = NULL;
2951 GNUNET_SERVER_notification_context_destroy (nc);
2956 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
2960 GNUNET_free_non_null (vpn_argv[i]);
2965 * A client disconnected, clean up all references to it.
2967 * @param cls the client that disconnected
2969 * @param value a 'struct TunnelState *'
2970 * @return GNUNET_OK (continue to iterate)
2973 cleanup_tunnel_client (void *cls,
2974 const struct GNUNET_HashCode *key,
2977 struct GNUNET_SERVER_Client *client = cls;
2978 struct TunnelState *ts = value;
2980 if (client == ts->client)
2987 * A client disconnected, clean up all references to it.
2989 * @param cls the client that disconnected
2991 * @param value a 'struct DestinationEntry *'
2992 * @return GNUNET_OK (continue to iterate)
2995 cleanup_destination_client (void *cls,
2996 const struct GNUNET_HashCode *key,
2999 struct GNUNET_SERVER_Client *client = cls;
3000 struct DestinationEntry *de = value;
3001 struct TunnelState *ts;
3003 if (NULL == (ts = de->ts))
3005 if (client == ts->client)
3012 * A client has disconnected from us. If we are currently building
3013 * a tunnel for it, cancel the operation.
3016 * @param client handle to the client that disconnected
3019 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
3021 if (NULL != tunnel_map)
3022 GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
3023 &cleanup_tunnel_client,
3025 if (NULL != destination_map)
3026 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
3027 &cleanup_destination_client,
3033 * Main function that will be run by the scheduler.
3035 * @param cls closure
3036 * @param server the initialized server
3037 * @param cfg_ configuration
3041 struct GNUNET_SERVER_Handle *server,
3042 const struct GNUNET_CONFIGURATION_Handle *cfg_)
3044 static const struct GNUNET_SERVER_MessageHandler service_handlers[] = {
3045 /* callback, cls, type, size */
3046 { &service_redirect_to_ip, NULL, GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP, 0},
3047 { &service_redirect_to_service, NULL,
3048 GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE,
3049 sizeof (struct RedirectToServiceRequestMessage) },
3052 static const struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
3053 { &receive_udp_back, GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY, 0},
3054 { &receive_tcp_back, GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN, 0},
3055 { &receive_icmp_back, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN, 0},
3067 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-vpn");
3070 GNUNET_OS_check_helper_binary (binary, GNUNET_YES, "-d gnunet-vpn - - 169.1.3.3.7 255.255.255.0")) //ipv4 only please!
3073 "`%s' is not SUID, refusing to run.\n",
3074 "gnunet-helper-vpn");
3075 GNUNET_free (binary);
3079 GNUNET_free (binary);
3081 stats = GNUNET_STATISTICS_create ("vpn", cfg);
3083 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_MAPPING",
3084 &max_destination_mappings))
3085 max_destination_mappings = 200;
3087 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_TUNNELS",
3088 &max_tunnel_mappings))
3089 max_tunnel_mappings = 200;
3091 destination_map = GNUNET_CONTAINER_multihashmap_create (max_destination_mappings * 2, GNUNET_NO);
3092 destination_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3093 tunnel_map = GNUNET_CONTAINER_multihashmap_create (max_tunnel_mappings * 2, GNUNET_NO);
3094 tunnel_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3097 vpn_argv[0] = GNUNET_strdup ("vpn-gnunet");
3098 if (GNUNET_SYSERR ==
3099 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IFNAME", &ifname))
3101 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3102 "No entry 'IFNAME' in configuration!\n");
3103 GNUNET_SCHEDULER_shutdown ();
3106 vpn_argv[1] = ifname;
3107 if (GNUNET_OK == GNUNET_NETWORK_test_pf (PF_INET6))
3109 if ( (GNUNET_SYSERR ==
3110 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6ADDR",
3112 (1 != inet_pton (AF_INET6, ipv6addr, &v6))) )
3114 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3115 "No valid entry 'IPV6ADDR' in configuration!\n");
3116 GNUNET_SCHEDULER_shutdown ();
3119 vpn_argv[2] = ipv6addr;
3120 if (GNUNET_SYSERR ==
3121 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6PREFIX",
3124 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3125 "No entry 'IPV6PREFIX' in configuration!\n");
3126 GNUNET_SCHEDULER_shutdown ();
3129 vpn_argv[3] = ipv6prefix_s;
3131 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn",
3134 (ipv6prefix >= 127) )
3136 GNUNET_SCHEDULER_shutdown ();
3142 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3143 _("IPv6 support disabled as this system does not support IPv6\n"));
3144 vpn_argv[2] = GNUNET_strdup ("-");
3145 vpn_argv[3] = GNUNET_strdup ("-");
3147 if (GNUNET_OK == GNUNET_NETWORK_test_pf (PF_INET))
3149 if ( (GNUNET_SYSERR ==
3150 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4ADDR",
3152 (1 != inet_pton (AF_INET, ipv4addr, &v4))) )
3154 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3155 "No valid entry for 'IPV4ADDR' in configuration!\n");
3156 GNUNET_SCHEDULER_shutdown ();
3159 vpn_argv[4] = ipv4addr;
3160 if ( (GNUNET_SYSERR ==
3161 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4MASK",
3163 (1 != inet_pton (AF_INET, ipv4mask, &v4))) )
3165 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3166 "No valid entry 'IPV4MASK' in configuration!\n");
3167 GNUNET_SCHEDULER_shutdown ();
3170 vpn_argv[5] = ipv4mask;
3174 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3175 _("IPv4 support disabled as this system does not support IPv4\n"));
3176 vpn_argv[4] = GNUNET_strdup ("-");
3177 vpn_argv[5] = GNUNET_strdup ("-");
3182 GNUNET_MESH_connect (cfg_, NULL,
3187 helper_handle = GNUNET_HELPER_start (GNUNET_NO,
3188 "gnunet-helper-vpn", vpn_argv,
3189 &message_token, NULL, NULL);
3190 nc = GNUNET_SERVER_notification_context_create (server, 1);
3191 GNUNET_SERVER_add_handlers (server, service_handlers);
3192 GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
3193 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls);
3198 * The main function of the VPN service.
3200 * @param argc number of arguments from the command line
3201 * @param argv command line arguments
3202 * @return 0 ok, 1 on error
3205 main (int argc, char *const *argv)
3207 return (GNUNET_OK ==
3208 GNUNET_SERVICE_run (argc, argv, "vpn",
3209 GNUNET_SERVICE_OPTION_NONE,
3210 &run, NULL)) ? global_ret : 1;
3213 /* end of gnunet-service-vpn.c */