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 #include "gnunet_util_lib.h"
31 #include "gnunet_common.h"
32 #include "gnunet_protocols.h"
33 #include "gnunet_applications.h"
34 #include "gnunet_mesh_service.h"
35 #include "gnunet_statistics_service.h"
36 #include "gnunet_constants.h"
37 #include "gnunet_tun_lib.h"
43 * Maximum number of messages we allow in the queue for mesh.
45 #define MAX_MESSAGE_QUEUE_SIZE 4
49 * State we keep for each of our tunnels.
55 * Information we track for each IP address to determine which tunnel
56 * to send the traffic over to the destination.
58 struct DestinationEntry
62 * Key under which this entry is in the 'destination_map' (only valid
63 * if 'heap_node != NULL').
65 struct GNUNET_HashCode key;
68 * Pre-allocated tunnel for this destination, or NULL for none.
70 struct TunnelState *ts;
73 * Entry for this entry in the destination_heap.
75 struct GNUNET_CONTAINER_HeapNode *heap_node;
78 * GNUNET_NO if this is a tunnel to an Internet-exit,
79 * GNUNET_YES if this tunnel is to a service.
84 * Details about the connection (depending on is_service).
92 * The description of the service (only used for service tunnels).
94 struct GNUNET_HashCode service_descriptor;
97 * Peer offering the service.
99 struct GNUNET_PeerIdentity target;
101 } service_destination;
107 * Address family used (AF_INET or AF_INET6).
112 * IP address of the ultimate destination (only used for exit tunnels).
117 * Address if af is AF_INET.
122 * Address if af is AF_INET6.
135 * A messages we have in queue for a particular tunnel.
137 struct TunnelMessageQueueEntry
140 * This is a doubly-linked list.
142 struct TunnelMessageQueueEntry *next;
145 * This is a doubly-linked list.
147 struct TunnelMessageQueueEntry *prev;
150 * Number of bytes in 'msg'.
155 * Message to transmit, allocated at the end of this struct.
162 * State we keep for each of our tunnels.
168 * Information about the tunnel to use, NULL if no tunnel
169 * is available right now.
171 struct GNUNET_MESH_Tunnel *tunnel;
174 * Active transmission handle, NULL for none.
176 struct GNUNET_MESH_TransmitHandle *th;
179 * Entry for this entry in the tunnel_heap, NULL as long as this
180 * tunnel state is not fully bound.
182 struct GNUNET_CONTAINER_HeapNode *heap_node;
185 * Head of list of messages scheduled for transmission.
187 struct TunnelMessageQueueEntry *tmq_head;
190 * Tail of list of messages scheduled for transmission.
192 struct TunnelMessageQueueEntry *tmq_tail;
195 * Client that needs to be notified about the tunnel being
196 * up as soon as a peer is connected; NULL for none.
198 struct GNUNET_SERVER_Client *client;
201 * Destination entry that has a pointer to this tunnel state;
202 * NULL if this tunnel state is in the tunnel map.
204 struct DestinationEntry *destination_container;
207 * ID of the client request that caused us to setup this entry.
212 * Destination to which this tunnel leads. Note that
213 * this struct is NOT in the destination_map (but a
214 * local copy) and that the 'heap_node' should always
217 struct DestinationEntry destination;
220 * Task scheduled to destroy the tunnel (or NO_TASK).
222 GNUNET_SCHEDULER_TaskIdentifier destroy_task;
225 * Addess family used for this tunnel on the local TUN interface.
230 * Length of the doubly linked 'tmq_head/tmq_tail' list.
232 unsigned int tmq_length;
235 * IPPROTO_TCP or IPPROTO_UDP once bound.
240 * IP address of the source on our end, initially uninitialized.
245 * Address if af is AF_INET.
250 * Address if af is AF_INET6.
257 * Destination IP address used by the source on our end (this is the IP
258 * that we pick freely within the VPN's tunnel IP range).
263 * Address if af is AF_INET.
268 * Address if af is AF_INET6.
275 * Source port used by the sender on our end; 0 for uninitialized.
277 uint16_t source_port;
280 * Destination port used by the sender on our end; 0 for uninitialized.
282 uint16_t destination_port;
288 * Return value from 'main'.
290 static int global_ret;
293 * Configuration we use.
295 static const struct GNUNET_CONFIGURATION_Handle *cfg;
298 * Handle to the mesh service.
300 static struct GNUNET_MESH_Handle *mesh_handle;
303 * Map from IP address to destination information (possibly with a
304 * MESH tunnel handle for fast setup).
306 static struct GNUNET_CONTAINER_MultiHashMap *destination_map;
309 * Min-Heap sorted by activity time to expire old mappings.
311 static struct GNUNET_CONTAINER_Heap *destination_heap;
314 * Map from source and destination address (IP+port) to connection
315 * information (mostly with the respective MESH tunnel handle).
317 static struct GNUNET_CONTAINER_MultiHashMap *tunnel_map;
320 * Min-Heap sorted by activity time to expire old mappings; values are
321 * of type 'struct TunnelState'.
323 static struct GNUNET_CONTAINER_Heap *tunnel_heap;
328 static struct GNUNET_STATISTICS_Handle *stats;
331 * The handle to the VPN helper process "gnunet-helper-vpn".
333 static struct GNUNET_HELPER_Handle *helper_handle;
336 * Arguments to the vpn helper.
338 static char *vpn_argv[7];
341 * Length of the prefix of the VPN's IPv6 network.
343 static unsigned long long ipv6prefix;
346 * Notification context for sending replies to clients.
348 static struct GNUNET_SERVER_NotificationContext *nc;
351 * If there are more than this number of address-mappings, old ones
354 static unsigned long long max_destination_mappings;
357 * If there are more than this number of open tunnels, old ones
360 static unsigned long long max_tunnel_mappings;
364 * Compute the key under which we would store an entry in the
365 * destination_map for the given IP address.
367 * @param af address family (AF_INET or AF_INET6)
368 * @param address IP address, struct in_addr or struct in6_addr
369 * @param key where to store the key
372 get_destination_key_from_ip (int af,
374 struct GNUNET_HashCode *key)
379 GNUNET_CRYPTO_hash (address,
380 sizeof (struct in_addr),
384 GNUNET_CRYPTO_hash (address,
385 sizeof (struct in6_addr),
396 * Compute the key under which we would store an entry in the
397 * tunnel_map for the given socket address pair.
399 * @param af address family (AF_INET or AF_INET6)
400 * @param protocol IPPROTO_TCP or IPPROTO_UDP
401 * @param source_ip sender's source IP, struct in_addr or struct in6_addr
402 * @param source_port sender's source port
403 * @param destination_ip sender's destination IP, struct in_addr or struct in6_addr
404 * @param destination_port sender's destination port
405 * @param key where to store the key
408 get_tunnel_key_from_ips (int af,
410 const void *source_ip,
411 uint16_t source_port,
412 const void *destination_ip,
413 uint16_t destination_port,
414 struct GNUNET_HashCode *key)
418 memset (key, 0, sizeof (struct GNUNET_HashCode));
419 /* the GNUnet hashmap only uses the first sizeof(unsigned int) of the hash,
420 so we put the ports in there (and hope for few collisions) */
422 memcpy (off, &source_port, sizeof (uint16_t));
423 off += sizeof (uint16_t);
424 memcpy (off, &destination_port, sizeof (uint16_t));
425 off += sizeof (uint16_t);
429 memcpy (off, source_ip, sizeof (struct in_addr));
430 off += sizeof (struct in_addr);
431 memcpy (off, destination_ip, sizeof (struct in_addr));
432 off += sizeof (struct in_addr);
435 memcpy (off, source_ip, sizeof (struct in6_addr));
436 off += sizeof (struct in6_addr);
437 memcpy (off, destination_ip, sizeof (struct in6_addr));
438 off += sizeof (struct in6_addr);
444 memcpy (off, &protocol, sizeof (uint8_t));
445 off += sizeof (uint8_t);
450 * Notify the client about the result of its request.
452 * @param client client to notify
453 * @param request_id original request ID to include in response
454 * @param result_af resulting address family
455 * @param addr resulting IP address
458 send_client_reply (struct GNUNET_SERVER_Client *client,
463 char buf[sizeof (struct RedirectToIpResponseMessage) + sizeof (struct in6_addr)] GNUNET_ALIGN;
464 struct RedirectToIpResponseMessage *res;
470 rlen = sizeof (struct in_addr);
473 rlen = sizeof (struct in6_addr);
482 res = (struct RedirectToIpResponseMessage *) buf;
483 res->header.size = htons (sizeof (struct RedirectToIpResponseMessage) + rlen);
484 res->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP);
485 res->result_af = htonl (result_af);
486 res->request_id = request_id;
487 memcpy (&res[1], addr, rlen);
488 GNUNET_SERVER_notification_context_add (nc, client);
489 GNUNET_SERVER_notification_context_unicast (nc,
497 * Free resources associated with a tunnel state.
499 * @param ts state to free
502 free_tunnel_state (struct TunnelState *ts)
504 struct GNUNET_HashCode key;
505 struct TunnelMessageQueueEntry *tnq;
506 struct GNUNET_MESH_Tunnel *tunnel;
508 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
509 "Cleaning up tunnel state\n");
510 GNUNET_STATISTICS_update (stats,
511 gettext_noop ("# Active tunnels"),
513 while (NULL != (tnq = ts->tmq_head))
515 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
521 GNUNET_assert (0 == ts->tmq_length);
522 if (NULL != ts->client)
524 GNUNET_SERVER_client_drop (ts->client);
529 GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
532 GNUNET_assert (NULL == ts->destination.heap_node);
533 if (NULL != (tunnel = ts->tunnel))
536 GNUNET_MESH_tunnel_destroy (tunnel);
538 if (GNUNET_SCHEDULER_NO_TASK != ts->destroy_task)
540 GNUNET_SCHEDULER_cancel (ts->destroy_task);
541 ts->destroy_task = GNUNET_SCHEDULER_NO_TASK;
543 if (NULL != ts->heap_node)
545 GNUNET_CONTAINER_heap_remove_node (ts->heap_node);
546 ts->heap_node = NULL;
547 get_tunnel_key_from_ips (ts->af,
552 ts->destination_port,
554 GNUNET_assert (GNUNET_YES ==
555 GNUNET_CONTAINER_multihashmap_remove (tunnel_map,
559 if (NULL != ts->destination_container)
561 GNUNET_assert (ts == ts->destination_container->ts);
562 ts->destination_container->ts = NULL;
563 ts->destination_container = NULL;
570 * Destroy the mesh tunnel.
572 * @param cls the 'struct TunnelState' with the tunnel to destroy
573 * @param tc scheduler context
576 destroy_tunnel_task (void *cls,
577 const struct GNUNET_SCHEDULER_TaskContext *tc)
579 struct TunnelState *ts = cls;
580 struct GNUNET_MESH_Tunnel *tunnel;
582 ts->destroy_task = GNUNET_SCHEDULER_NO_TASK;
583 GNUNET_assert (NULL != ts->tunnel);
586 GNUNET_MESH_tunnel_destroy (tunnel);
587 free_tunnel_state (ts);
592 * Method called whenever a peer has disconnected from the tunnel.
595 * @param peer peer identity the tunnel stopped working with
598 tunnel_peer_disconnect_handler (void *cls,
600 GNUNET_PeerIdentity * peer)
602 struct TunnelState *ts = cls;
604 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
605 "Peer %s disconnected from tunnel.\n",
607 GNUNET_STATISTICS_update (stats,
608 gettext_noop ("# peers connected to mesh tunnels"),
612 GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
615 if (ts->destination.is_service)
616 return; /* hope for reconnect eventually */
617 /* as we are most likely going to change the exit node now,
618 we should just destroy the tunnel entirely... */
619 if (GNUNET_SCHEDULER_NO_TASK == ts->destroy_task)
620 ts->destroy_task = GNUNET_SCHEDULER_add_now (&destroy_tunnel_task, ts);
625 * Method called whenever a peer has connected to the tunnel. Notifies
626 * the waiting client that the tunnel is now up.
629 * @param peer peer identity the tunnel was created to, NULL on timeout
630 * @param atsi performance data for the connection
633 tunnel_peer_connect_handler (void *cls,
634 const struct GNUNET_PeerIdentity
637 GNUNET_ATS_Information * atsi)
639 struct TunnelState *ts = cls;
641 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
642 "Peer %s connected to tunnel.\n",
644 GNUNET_STATISTICS_update (stats,
645 gettext_noop ("# peers connected to mesh tunnels"),
647 if (NULL == ts->client)
648 return; /* nothing to do */
649 send_client_reply (ts->client,
652 &ts->destination_ip);
653 GNUNET_SERVER_client_drop (ts->client);
659 * Send a message from the message queue via mesh.
661 * @param cls the 'struct TunnelState' with the message queue
662 * @param size number of bytes available in buf
663 * @param buf where to copy the message
664 * @return number of bytes copied to buf
667 send_to_peer_notify_callback (void *cls, size_t size, void *buf)
669 struct TunnelState *ts = cls;
670 struct TunnelMessageQueueEntry *tnq;
677 GNUNET_assert (NULL != tnq);
678 GNUNET_assert (size >= tnq->len);
679 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
680 "Sending %u bytes via mesh tunnel\n",
682 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
686 memcpy (buf, tnq->msg, tnq->len);
689 if (NULL != (tnq = ts->tmq_head))
690 ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel,
691 GNUNET_NO /* cork */,
692 GNUNET_TIME_UNIT_FOREVER_REL,
695 &send_to_peer_notify_callback,
697 GNUNET_STATISTICS_update (stats,
698 gettext_noop ("# Bytes given to mesh for transmission"),
705 * Add the given message to the given tunnel and trigger the
706 * transmission process.
708 * @param tnq message to queue
709 * @param ts tunnel to queue the message for
712 send_to_tunnel (struct TunnelMessageQueueEntry *tnq,
713 struct TunnelState *ts)
715 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
716 "Queueing %u bytes for transmission via mesh tunnel\n",
718 GNUNET_assert (NULL != ts->tunnel);
719 GNUNET_CONTAINER_DLL_insert_tail (ts->tmq_head,
723 if (ts->tmq_length > MAX_MESSAGE_QUEUE_SIZE)
725 struct TunnelMessageQueueEntry *dq;
728 GNUNET_assert (dq != tnq);
729 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
733 GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
735 GNUNET_STATISTICS_update (stats,
736 gettext_noop ("# Bytes dropped in mesh queue (overflow)"),
742 ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel,
743 GNUNET_NO /* cork */,
744 GNUNET_TIME_UNIT_FOREVER_REL,
747 &send_to_peer_notify_callback,
753 * Initialize the given destination entry's mesh tunnel.
755 * @param de destination entry for which we need to setup a tunnel
756 * @param client client to notify on successful tunnel setup, or NULL for none
757 * @param client_af address family of the address returned to the client
758 * @param request_id request ID to send in client notification (unused if client is NULL)
759 * @return tunnel state of the tunnel that was created
761 static struct TunnelState *
762 create_tunnel_to_destination (struct DestinationEntry *de,
763 struct GNUNET_SERVER_Client *client,
767 struct TunnelState *ts;
769 GNUNET_STATISTICS_update (stats,
770 gettext_noop ("# Mesh tunnels created"),
772 GNUNET_assert (NULL == de->ts);
773 ts = GNUNET_malloc (sizeof (struct TunnelState));
777 ts->request_id = request_id;
779 GNUNET_SERVER_client_keep (client);
781 ts->destination = *de;
782 ts->destination.heap_node = NULL; /* copy is NOT in destination heap */
784 ts->destination_container = de; /* we are referenced from de */
785 ts->tunnel = GNUNET_MESH_tunnel_create (mesh_handle,
787 &tunnel_peer_connect_handler,
788 &tunnel_peer_disconnect_handler,
790 if (NULL == ts->tunnel)
792 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
793 _("Failed to setup mesh tunnel!\n"));
795 GNUNET_SERVER_client_drop (client);
801 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
802 "Creating tunnel to peer %s offering service %s\n",
803 GNUNET_i2s (&de->details.service_destination.target),
804 GNUNET_h2s (&de->details.service_destination.service_descriptor));
805 GNUNET_MESH_peer_request_connect_add (ts->tunnel,
806 &de->details.service_destination.target);
810 switch (de->details.exit_destination.af)
813 GNUNET_MESH_peer_request_connect_by_type (ts->tunnel,
814 GNUNET_APPLICATION_TYPE_IPV4_GATEWAY);
815 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
816 "Creating tunnel to exit peer for %s\n",
820 GNUNET_MESH_peer_request_connect_by_type (ts->tunnel,
821 GNUNET_APPLICATION_TYPE_IPV6_GATEWAY);
822 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
823 "Creating tunnel to exit peer for %s\n",
836 * We have too many active tunnels. Clean up the oldest tunnel.
838 * @param except tunnel that must NOT be cleaned up, even if it is the oldest
841 expire_tunnel (struct TunnelState *except)
843 struct TunnelState *ts;
845 ts = GNUNET_CONTAINER_heap_peek (tunnel_heap);
846 GNUNET_assert (NULL != ts);
848 return; /* can't do this */
849 free_tunnel_state (ts);
854 * Route a packet via mesh to the given destination.
856 * @param destination description of the destination
857 * @param af address family on this end (AF_INET or AF_INET6)
858 * @param protocol IPPROTO_TCP or IPPROTO_UDP or IPPROTO_ICMP or IPPROTO_ICMPV6
859 * @param source_ip source IP used by the sender (struct in_addr or struct in6_addr)
860 * @param destination_ip destination IP used by the sender (struct in_addr or struct in6_addr)
861 * @param payload payload of the packet after the IP header
862 * @param payload_length number of bytes in payload
865 route_packet (struct DestinationEntry *destination,
868 const void *source_ip,
869 const void *destination_ip,
871 size_t payload_length)
873 struct GNUNET_HashCode key;
874 struct TunnelState *ts;
875 struct TunnelMessageQueueEntry *tnq;
879 const struct GNUNET_TUN_UdpHeader *udp;
880 const struct GNUNET_TUN_TcpHeader *tcp;
881 const struct GNUNET_TUN_IcmpHeader *icmp;
882 uint16_t source_port;
883 uint16_t destination_port;
889 if (payload_length < sizeof (struct GNUNET_TUN_UdpHeader))
895 tcp = NULL; /* make compiler happy */
896 icmp = NULL; /* make compiler happy */
898 if (udp->len < sizeof (struct GNUNET_TUN_UdpHeader))
903 source_port = ntohs (udp->source_port);
904 destination_port = ntohs (udp->destination_port);
905 get_tunnel_key_from_ips (af,
916 if (payload_length < sizeof (struct GNUNET_TUN_TcpHeader))
922 udp = NULL; /* make compiler happy */
923 icmp = NULL; /* make compiler happy */
925 if (tcp->off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
930 source_port = ntohs (tcp->source_port);
931 destination_port = ntohs (tcp->destination_port);
932 get_tunnel_key_from_ips (af,
944 if ( (AF_INET == af) ^ (protocol == IPPROTO_ICMP) )
949 if (payload_length < sizeof (struct GNUNET_TUN_IcmpHeader))
955 tcp = NULL; /* make compiler happy */
956 udp = NULL; /* make compiler happy */
959 destination_port = 0;
960 get_tunnel_key_from_ips (af,
970 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
971 _("Protocol %u not supported, dropping\n"),
972 (unsigned int) protocol);
975 if (! destination->is_service)
977 switch (destination->details.exit_destination.af)
980 alen = sizeof (struct in_addr);
983 alen = sizeof (struct in6_addr);
991 char sbuf[INET6_ADDRSTRLEN];
992 char dbuf[INET6_ADDRSTRLEN];
993 char xbuf[INET6_ADDRSTRLEN];
995 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
996 "Routing %s packet from %s:%u -> %s:%u to destination %s:%u\n",
997 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
998 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
1000 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
1002 inet_ntop (destination->details.exit_destination.af,
1003 &destination->details.exit_destination.ip,
1004 xbuf, sizeof (xbuf)),
1010 /* make compiler happy */
1013 char sbuf[INET6_ADDRSTRLEN];
1014 char dbuf[INET6_ADDRSTRLEN];
1016 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1017 "Routing %s packet from %s:%u -> %s:%u to service %s at peer %s\n",
1018 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
1019 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
1021 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
1023 GNUNET_h2s (&destination->details.service_destination.service_descriptor),
1024 GNUNET_i2s (&destination->details.service_destination.target));
1029 /* see if we have an existing tunnel for this destination */
1030 ts = GNUNET_CONTAINER_multihashmap_get (tunnel_map,
1034 /* need to either use the existing tunnel from the destination (if still
1035 available) or create a fresh one */
1036 is_new = GNUNET_YES;
1037 if (NULL == destination->ts)
1038 ts = create_tunnel_to_destination (destination, NULL, af, 0);
1040 ts = destination->ts;
1043 destination->ts = NULL;
1044 ts->destination_container = NULL; /* no longer 'contained' */
1045 /* now bind existing "unbound" tunnel to our IP/port tuple */
1046 ts->protocol = protocol;
1050 ts->source_ip.v4 = * (const struct in_addr *) source_ip;
1051 ts->destination_ip.v4 = * (const struct in_addr *) destination_ip;
1055 ts->source_ip.v6 = * (const struct in6_addr *) source_ip;
1056 ts->destination_ip.v6 = * (const struct in6_addr *) destination_ip;
1058 ts->source_port = source_port;
1059 ts->destination_port = destination_port;
1060 ts->heap_node = GNUNET_CONTAINER_heap_insert (tunnel_heap,
1062 GNUNET_TIME_absolute_get ().abs_value);
1063 GNUNET_assert (GNUNET_YES ==
1064 GNUNET_CONTAINER_multihashmap_put (tunnel_map,
1067 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1068 GNUNET_STATISTICS_update (stats,
1069 gettext_noop ("# Active tunnels"),
1071 while (GNUNET_CONTAINER_multihashmap_size (tunnel_map) > max_tunnel_mappings)
1077 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
1079 GNUNET_TIME_absolute_get ().abs_value);
1081 GNUNET_assert (NULL != ts->tunnel);
1083 /* send via tunnel */
1087 if (destination->is_service)
1089 struct GNUNET_EXIT_UdpServiceMessage *usm;
1091 mlen = sizeof (struct GNUNET_EXIT_UdpServiceMessage) +
1092 payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1093 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1098 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1101 usm = (struct GNUNET_EXIT_UdpServiceMessage *) &tnq[1];
1102 usm->header.size = htons ((uint16_t) mlen);
1103 usm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE);
1104 /* if the source port is below 32000, we assume it has a special
1105 meaning; if not, we pick a random port (this is a heuristic) */
1106 usm->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1107 usm->destination_port = udp->destination_port;
1108 usm->service_descriptor = destination->details.service_destination.service_descriptor;
1111 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1115 struct GNUNET_EXIT_UdpInternetMessage *uim;
1116 struct in_addr *ip4dst;
1117 struct in6_addr *ip6dst;
1120 mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) +
1121 alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1122 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1127 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) +
1131 uim = (struct GNUNET_EXIT_UdpInternetMessage *) &tnq[1];
1132 uim->header.size = htons ((uint16_t) mlen);
1133 uim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET);
1134 uim->af = htonl (destination->details.exit_destination.af);
1135 uim->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1136 uim->destination_port = udp->destination_port;
1137 switch (destination->details.exit_destination.af)
1140 ip4dst = (struct in_addr *) &uim[1];
1141 *ip4dst = destination->details.exit_destination.ip.v4;
1142 payload = &ip4dst[1];
1145 ip6dst = (struct in6_addr *) &uim[1];
1146 *ip6dst = destination->details.exit_destination.ip.v6;
1147 payload = &ip6dst[1];
1154 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1160 if (destination->is_service)
1162 struct GNUNET_EXIT_TcpServiceStartMessage *tsm;
1164 mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) +
1165 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1166 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1171 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1174 tsm = (struct GNUNET_EXIT_TcpServiceStartMessage *) &tnq[1];
1175 tsm->header.size = htons ((uint16_t) mlen);
1176 tsm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START);
1177 tsm->reserved = htonl (0);
1178 tsm->service_descriptor = destination->details.service_destination.service_descriptor;
1179 tsm->tcp_header = *tcp;
1182 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1186 struct GNUNET_EXIT_TcpInternetStartMessage *tim;
1187 struct in_addr *ip4dst;
1188 struct in6_addr *ip6dst;
1191 mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) +
1192 alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1193 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1198 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1201 tim = (struct GNUNET_EXIT_TcpInternetStartMessage *) &tnq[1];
1202 tim->header.size = htons ((uint16_t) mlen);
1203 tim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START);
1204 tim->af = htonl (destination->details.exit_destination.af);
1205 tim->tcp_header = *tcp;
1206 switch (destination->details.exit_destination.af)
1209 ip4dst = (struct in_addr *) &tim[1];
1210 *ip4dst = destination->details.exit_destination.ip.v4;
1211 payload = &ip4dst[1];
1214 ip6dst = (struct in6_addr *) &tim[1];
1215 *ip6dst = destination->details.exit_destination.ip.v6;
1216 payload = &ip6dst[1];
1223 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1228 struct GNUNET_EXIT_TcpDataMessage *tdm;
1230 mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) +
1231 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1232 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1237 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1240 tdm = (struct GNUNET_EXIT_TcpDataMessage *) &tnq[1];
1241 tdm->header.size = htons ((uint16_t) mlen);
1242 tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT);
1243 tdm->reserved = htonl (0);
1244 tdm->tcp_header = *tcp;
1247 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1251 case IPPROTO_ICMPV6:
1252 if (destination->is_service)
1254 struct GNUNET_EXIT_IcmpServiceMessage *ism;
1256 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1257 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1258 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1263 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1265 ism = (struct GNUNET_EXIT_IcmpServiceMessage *) &tnq[1];
1266 ism->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE);
1267 ism->af = htonl (af); /* need to tell destination ICMP protocol family! */
1268 ism->service_descriptor = destination->details.service_destination.service_descriptor;
1269 ism->icmp_header = *icmp;
1270 /* ICMP protocol translation will be done by the receiver (as we don't know
1271 the target AF); however, we still need to possibly discard the payload
1272 depending on the ICMP type */
1278 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1279 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1281 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1282 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1283 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1284 /* throw away ICMP payload, won't be useful for the other side anyway */
1285 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1288 GNUNET_STATISTICS_update (stats,
1289 gettext_noop ("# ICMPv4 packets dropped (not allowed)"),
1293 /* end of AF_INET */
1298 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1299 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1300 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1301 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1302 /* throw away ICMP payload, won't be useful for the other side anyway */
1303 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1305 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1306 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1309 GNUNET_STATISTICS_update (stats,
1310 gettext_noop ("# ICMPv6 packets dropped (not allowed)"),
1314 /* end of AF_INET6 */
1321 /* update length calculations, as payload_length may have changed */
1322 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1323 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1325 ism->header.size = htons ((uint16_t) mlen);
1326 /* finally, copy payload (if there is any left...) */
1329 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1333 struct GNUNET_EXIT_IcmpInternetMessage *iim;
1334 struct in_addr *ip4dst;
1335 struct in6_addr *ip6dst;
1338 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1339 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1340 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1345 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) +
1348 iim = (struct GNUNET_EXIT_IcmpInternetMessage *) &tnq[1];
1349 iim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET);
1350 iim->icmp_header = *icmp;
1351 /* Perform ICMP protocol-translation (depending on destination AF and source AF)
1352 and throw away ICMP payload depending on ICMP message type */
1358 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1359 if (destination->details.exit_destination.af == AF_INET6)
1360 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1362 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1363 if (destination->details.exit_destination.af == AF_INET6)
1364 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1366 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1367 if (destination->details.exit_destination.af == AF_INET6)
1368 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1369 /* throw away IP-payload, exit will have to make it up anyway */
1370 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1372 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1373 if (destination->details.exit_destination.af == AF_INET6)
1374 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1375 /* throw away IP-payload, exit will have to make it up anyway */
1376 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1378 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1379 if (destination->details.exit_destination.af == AF_INET6)
1381 GNUNET_STATISTICS_update (stats,
1382 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1387 /* throw away IP-payload, exit will have to make it up anyway */
1388 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1391 GNUNET_STATISTICS_update (stats,
1392 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1397 /* end of AF_INET */
1402 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1403 if (destination->details.exit_destination.af == AF_INET6)
1404 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1405 /* throw away IP-payload, exit will have to make it up anyway */
1406 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1408 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1409 if (destination->details.exit_destination.af == AF_INET)
1410 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1411 /* throw away IP-payload, exit will have to make it up anyway */
1412 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1414 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1415 if (destination->details.exit_destination.af == AF_INET)
1417 GNUNET_STATISTICS_update (stats,
1418 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1423 /* throw away IP-payload, exit will have to make it up anyway */
1424 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1426 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1427 if (destination->details.exit_destination.af == AF_INET)
1429 GNUNET_STATISTICS_update (stats,
1430 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1435 /* throw away IP-payload, exit will have to make it up anyway */
1436 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1438 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1439 if (destination->details.exit_destination.af == AF_INET)
1440 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1442 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1443 if (destination->details.exit_destination.af == AF_INET)
1444 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1447 GNUNET_STATISTICS_update (stats,
1448 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1453 /* end of AF_INET6 */
1458 /* update length calculations, as payload_length may have changed */
1459 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1460 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1462 iim->header.size = htons ((uint16_t) mlen);
1464 /* need to tell destination ICMP protocol family! */
1465 iim->af = htonl (destination->details.exit_destination.af);
1466 switch (destination->details.exit_destination.af)
1469 ip4dst = (struct in_addr *) &iim[1];
1470 *ip4dst = destination->details.exit_destination.ip.v4;
1471 payload = &ip4dst[1];
1474 ip6dst = (struct in6_addr *) &iim[1];
1475 *ip6dst = destination->details.exit_destination.ip.v6;
1476 payload = &ip6dst[1];
1483 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1487 /* not supported above, how can we get here !? */
1491 send_to_tunnel (tnq, ts);
1496 * Receive packets from the helper-process (someone send to the local
1497 * virtual tunnel interface). Find the destination mapping, and if it
1498 * exists, identify the correct MESH tunnel (or possibly create it)
1499 * and forward the packet.
1501 * @param cls closure, NULL
1502 * @param client NULL
1503 * @param message message we got from the client (VPN tunnel interface)
1506 message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED,
1507 const struct GNUNET_MessageHeader *message)
1509 const struct GNUNET_TUN_Layer2PacketHeader *tun;
1511 struct GNUNET_HashCode key;
1512 struct DestinationEntry *de;
1514 GNUNET_STATISTICS_update (stats,
1515 gettext_noop ("# Packets received from TUN interface"),
1517 mlen = ntohs (message->size);
1518 if ( (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
1519 (mlen < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader)) )
1524 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1525 mlen -= (sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader));
1526 switch (ntohs (tun->proto))
1530 const struct GNUNET_TUN_IPv6Header *pkt6;
1532 if (mlen < sizeof (struct GNUNET_TUN_IPv6Header))
1538 pkt6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1539 get_destination_key_from_ip (AF_INET6,
1540 &pkt6->destination_address,
1542 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1543 /* FIXME: do we need to guard against hash collision?
1544 (if so, we need to also store the local destination IP in the
1545 destination entry and then compare here; however, the risk
1546 of collision seems minimal AND the impact is unlikely to be
1547 super-problematic as well... */
1550 char buf[INET6_ADDRSTRLEN];
1552 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1553 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1554 inet_ntop (AF_INET6,
1555 &pkt6->destination_address,
1563 &pkt6->source_address,
1564 &pkt6->destination_address,
1566 mlen - sizeof (struct GNUNET_TUN_IPv6Header));
1571 struct GNUNET_TUN_IPv4Header *pkt4;
1573 if (mlen < sizeof (struct GNUNET_TUN_IPv4Header))
1579 pkt4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1580 get_destination_key_from_ip (AF_INET,
1581 &pkt4->destination_address,
1583 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1584 /* FIXME: do we need to guard against hash collision?
1585 (if so, we need to also store the local destination IP in the
1586 destination entry and then compare here; however, the risk
1587 of collision seems minimal AND the impact is unlikely to be
1588 super-problematic as well... */
1591 char buf[INET_ADDRSTRLEN];
1593 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1594 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1596 &pkt4->destination_address,
1601 if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header))
1603 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1604 _("Received IPv4 packet with options (dropping it)\n"));
1610 &pkt4->source_address,
1611 &pkt4->destination_address,
1613 mlen - sizeof (struct GNUNET_TUN_IPv4Header));
1617 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1618 _("Received packet of unknown protocol %d from TUN (dropping it)\n"),
1619 (unsigned int) ntohs (tun->proto));
1627 * Synthesize a plausible ICMP payload for an ICMP error
1628 * response on the given tunnel.
1630 * @param ts tunnel information
1631 * @param ipp IPv4 header to fill in (ICMP payload)
1632 * @param udp "UDP" header to fill in (ICMP payload); might actually
1633 * also be the first 8 bytes of the TCP header
1636 make_up_icmpv4_payload (struct TunnelState *ts,
1637 struct GNUNET_TUN_IPv4Header *ipp,
1638 struct GNUNET_TUN_UdpHeader *udp)
1640 GNUNET_TUN_initialize_ipv4_header (ipp,
1642 sizeof (struct GNUNET_TUN_TcpHeader),
1644 &ts->destination_ip.v4);
1645 udp->source_port = htons (ts->source_port);
1646 udp->destination_port = htons (ts->destination_port);
1647 udp->len = htons (0);
1648 udp->crc = htons (0);
1653 * Synthesize a plausible ICMP payload for an ICMP error
1654 * response on the given tunnel.
1656 * @param ts tunnel information
1657 * @param ipp IPv6 header to fill in (ICMP payload)
1658 * @param udp "UDP" header to fill in (ICMP payload); might actually
1659 * also be the first 8 bytes of the TCP header
1662 make_up_icmpv6_payload (struct TunnelState *ts,
1663 struct GNUNET_TUN_IPv6Header *ipp,
1664 struct GNUNET_TUN_UdpHeader *udp)
1666 GNUNET_TUN_initialize_ipv6_header (ipp,
1668 sizeof (struct GNUNET_TUN_TcpHeader),
1670 &ts->destination_ip.v6);
1671 udp->source_port = htons (ts->source_port);
1672 udp->destination_port = htons (ts->destination_port);
1673 udp->len = htons (0);
1674 udp->crc = htons (0);
1679 * We got an ICMP packet back from the MESH tunnel. Pass it on to the
1680 * local virtual interface via the helper.
1682 * @param cls closure, NULL
1683 * @param tunnel connection to the other end
1684 * @param tunnel_ctx pointer to our 'struct TunnelState *'
1685 * @param sender who sent the message
1686 * @param message the actual message
1687 * @param atsi performance data for the connection
1688 * @return GNUNET_OK to keep the connection open,
1689 * GNUNET_SYSERR to close it (signal serious error)
1692 receive_icmp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1693 void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender,
1694 const struct GNUNET_MessageHeader *message,
1695 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
1697 struct TunnelState *ts = *tunnel_ctx;
1698 const struct GNUNET_EXIT_IcmpToVPNMessage *i2v;
1701 GNUNET_STATISTICS_update (stats,
1702 gettext_noop ("# ICMP packets received from mesh"),
1704 mlen = ntohs (message->size);
1705 if (mlen < sizeof (struct GNUNET_EXIT_IcmpToVPNMessage))
1707 GNUNET_break_op (0);
1708 return GNUNET_SYSERR;
1710 if (NULL == ts->heap_node)
1712 GNUNET_break_op (0);
1713 return GNUNET_SYSERR;
1715 if (AF_UNSPEC == ts->af)
1717 GNUNET_break_op (0);
1718 return GNUNET_SYSERR;
1720 i2v = (const struct GNUNET_EXIT_IcmpToVPNMessage *) message;
1721 mlen -= sizeof (struct GNUNET_EXIT_IcmpToVPNMessage);
1723 char sbuf[INET6_ADDRSTRLEN];
1724 char dbuf[INET6_ADDRSTRLEN];
1726 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1727 "Received ICMP packet from mesh, sending %u bytes from %s -> %s via TUN\n",
1728 (unsigned int) mlen,
1729 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
1730 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)));
1736 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
1737 + sizeof (struct GNUNET_TUN_IcmpHeader)
1738 + sizeof (struct GNUNET_MessageHeader) +
1739 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1742 /* reserve some extra space in case we have an ICMP type here where
1743 we will need to make up the payload ourselves */
1744 char buf[size + sizeof (struct GNUNET_TUN_IPv4Header) + 8] GNUNET_ALIGN;
1745 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1746 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1747 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1748 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv4[1];
1749 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1750 tun->flags = htons (0);
1751 tun->proto = htons (ETH_P_IPV4);
1752 GNUNET_TUN_initialize_ipv4_header (ipv4,
1754 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1755 &ts->destination_ip.v4,
1757 *icmp = i2v->icmp_header;
1761 /* For some ICMP types, we need to adjust (make up) the payload here.
1762 Also, depending on the AF used on the other side, we have to
1763 do ICMP PT (translate ICMP types) */
1764 switch (ntohl (i2v->af))
1769 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1770 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1772 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1773 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1774 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1776 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1777 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1781 /* sender did not strip ICMP payload? */
1782 GNUNET_break_op (0);
1783 return GNUNET_SYSERR;
1785 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1786 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1787 make_up_icmpv4_payload (ts, ipp, udp);
1791 GNUNET_break_op (0);
1792 GNUNET_STATISTICS_update (stats,
1793 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1795 return GNUNET_SYSERR;
1800 /* ICMP PT 6-to-4 and possibly making up payloads */
1803 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1804 icmp->type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
1806 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1807 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1811 /* sender did not strip ICMP payload? */
1812 GNUNET_break_op (0);
1813 return GNUNET_SYSERR;
1815 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1816 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1817 make_up_icmpv4_payload (ts, ipp, udp);
1820 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1821 icmp->type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1823 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1824 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1828 /* sender did not strip ICMP payload? */
1829 GNUNET_break_op (0);
1830 return GNUNET_SYSERR;
1832 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1833 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1834 make_up_icmpv4_payload (ts, ipp, udp);
1837 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1838 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1839 GNUNET_STATISTICS_update (stats,
1840 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1843 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1844 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1846 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1847 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1850 GNUNET_break_op (0);
1851 GNUNET_STATISTICS_update (stats,
1852 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1854 return GNUNET_SYSERR;
1859 GNUNET_break_op (0);
1860 return GNUNET_SYSERR;
1862 msg->size = htons (size);
1863 GNUNET_TUN_calculate_icmp_checksum (icmp,
1866 (void) GNUNET_HELPER_send (helper_handle,
1875 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
1876 + sizeof (struct GNUNET_TUN_IcmpHeader)
1877 + sizeof (struct GNUNET_MessageHeader) +
1878 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1881 char buf[size + sizeof (struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN;
1882 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1883 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1884 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
1885 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv6[1];
1886 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1887 tun->flags = htons (0);
1888 tun->proto = htons (ETH_P_IPV6);
1889 GNUNET_TUN_initialize_ipv6_header (ipv6,
1891 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1892 &ts->destination_ip.v6,
1894 *icmp = i2v->icmp_header;
1899 /* For some ICMP types, we need to adjust (make up) the payload here.
1900 Also, depending on the AF used on the other side, we have to
1901 do ICMP PT (translate ICMP types) */
1902 switch (ntohl (i2v->af))
1905 /* ICMP PT 4-to-6 and possibly making up payloads */
1908 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1909 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1911 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1912 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1914 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1915 icmp->type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1917 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1918 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1922 /* sender did not strip ICMP payload? */
1923 GNUNET_break_op (0);
1924 return GNUNET_SYSERR;
1926 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1927 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1928 make_up_icmpv6_payload (ts, ipp, udp);
1931 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1932 icmp->type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1934 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1935 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1939 /* sender did not strip ICMP payload? */
1940 GNUNET_break_op (0);
1941 return GNUNET_SYSERR;
1943 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1944 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1945 make_up_icmpv6_payload (ts, ipp, udp);
1948 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1949 GNUNET_STATISTICS_update (stats,
1950 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1954 GNUNET_break_op (0);
1955 GNUNET_STATISTICS_update (stats,
1956 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1958 return GNUNET_SYSERR;
1965 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1966 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1967 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1968 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1970 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1971 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1975 /* sender did not strip ICMP payload? */
1976 GNUNET_break_op (0);
1977 return GNUNET_SYSERR;
1979 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1980 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1981 make_up_icmpv6_payload (ts, ipp, udp);
1984 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1987 GNUNET_break_op (0);
1988 GNUNET_STATISTICS_update (stats,
1989 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1991 return GNUNET_SYSERR;
1996 GNUNET_break_op (0);
1997 return GNUNET_SYSERR;
1999 msg->size = htons (size);
2000 GNUNET_TUN_calculate_icmp_checksum (icmp,
2002 (void) GNUNET_HELPER_send (helper_handle,
2012 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2014 GNUNET_TIME_absolute_get ().abs_value);
2020 * We got a UDP packet back from the MESH tunnel. Pass it on to the
2021 * local virtual interface via the helper.
2023 * @param cls closure, NULL
2024 * @param tunnel connection to the other end
2025 * @param tunnel_ctx pointer to our 'struct TunnelState *'
2026 * @param sender who sent the message
2027 * @param message the actual message
2028 * @param atsi performance data for the connection
2029 * @return GNUNET_OK to keep the connection open,
2030 * GNUNET_SYSERR to close it (signal serious error)
2033 receive_udp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
2034 void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender,
2035 const struct GNUNET_MessageHeader *message,
2036 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
2038 struct TunnelState *ts = *tunnel_ctx;
2039 const struct GNUNET_EXIT_UdpReplyMessage *reply;
2042 GNUNET_STATISTICS_update (stats,
2043 gettext_noop ("# UDP packets received from mesh"),
2045 mlen = ntohs (message->size);
2046 if (mlen < sizeof (struct GNUNET_EXIT_UdpReplyMessage))
2048 GNUNET_break_op (0);
2049 return GNUNET_SYSERR;
2051 if (NULL == ts->heap_node)
2053 GNUNET_break_op (0);
2054 return GNUNET_SYSERR;
2056 if (AF_UNSPEC == ts->af)
2058 GNUNET_break_op (0);
2059 return GNUNET_SYSERR;
2061 reply = (const struct GNUNET_EXIT_UdpReplyMessage *) message;
2062 mlen -= sizeof (struct GNUNET_EXIT_UdpReplyMessage);
2064 char sbuf[INET6_ADDRSTRLEN];
2065 char dbuf[INET6_ADDRSTRLEN];
2067 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2068 "Received UDP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2069 (unsigned int) mlen,
2070 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2071 ts->destination_port,
2072 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2079 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2080 + sizeof (struct GNUNET_TUN_UdpHeader)
2081 + sizeof (struct GNUNET_MessageHeader) +
2082 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2085 char buf[size] GNUNET_ALIGN;
2086 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2087 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2088 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2089 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1];
2090 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2091 msg->size = htons (size);
2092 tun->flags = htons (0);
2093 tun->proto = htons (ETH_P_IPV4);
2094 GNUNET_TUN_initialize_ipv4_header (ipv4,
2096 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2097 &ts->destination_ip.v4,
2099 if (0 == ntohs (reply->source_port))
2100 udp->source_port = htons (ts->destination_port);
2102 udp->source_port = reply->source_port;
2103 if (0 == ntohs (reply->destination_port))
2104 udp->destination_port = htons (ts->source_port);
2106 udp->destination_port = reply->destination_port;
2107 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2108 GNUNET_TUN_calculate_udp4_checksum (ipv4,
2115 (void) GNUNET_HELPER_send (helper_handle,
2124 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2125 + sizeof (struct GNUNET_TUN_UdpHeader)
2126 + sizeof (struct GNUNET_MessageHeader) +
2127 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2130 char buf[size] GNUNET_ALIGN;
2131 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2132 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2133 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2134 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1];
2135 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2136 msg->size = htons (size);
2137 tun->flags = htons (0);
2138 tun->proto = htons (ETH_P_IPV6);
2139 GNUNET_TUN_initialize_ipv6_header (ipv6,
2141 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2142 &ts->destination_ip.v6,
2144 if (0 == ntohs (reply->source_port))
2145 udp->source_port = htons (ts->destination_port);
2147 udp->source_port = reply->source_port;
2148 if (0 == ntohs (reply->destination_port))
2149 udp->destination_port = htons (ts->source_port);
2151 udp->destination_port = reply->destination_port;
2152 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2153 GNUNET_TUN_calculate_udp6_checksum (ipv6,
2159 (void) GNUNET_HELPER_send (helper_handle,
2169 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2171 GNUNET_TIME_absolute_get ().abs_value);
2177 * We got a TCP packet back from the MESH tunnel. Pass it on to the
2178 * local virtual interface via the helper.
2180 * @param cls closure, NULL
2181 * @param tunnel connection to the other end
2182 * @param tunnel_ctx pointer to our 'struct TunnelState *'
2183 * @param sender who sent the message
2184 * @param message the actual message
2185 * @param atsi performance data for the connection
2186 * @return GNUNET_OK to keep the connection open,
2187 * GNUNET_SYSERR to close it (signal serious error)
2190 receive_tcp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
2192 const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED,
2193 const struct GNUNET_MessageHeader *message,
2194 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
2196 struct TunnelState *ts = *tunnel_ctx;
2197 const struct GNUNET_EXIT_TcpDataMessage *data;
2200 GNUNET_STATISTICS_update (stats,
2201 gettext_noop ("# TCP packets received from mesh"),
2203 mlen = ntohs (message->size);
2204 if (mlen < sizeof (struct GNUNET_EXIT_TcpDataMessage))
2206 GNUNET_break_op (0);
2207 return GNUNET_SYSERR;
2209 if (NULL == ts->heap_node)
2211 GNUNET_break_op (0);
2212 return GNUNET_SYSERR;
2214 data = (const struct GNUNET_EXIT_TcpDataMessage *) message;
2215 mlen -= sizeof (struct GNUNET_EXIT_TcpDataMessage);
2217 char sbuf[INET6_ADDRSTRLEN];
2218 char dbuf[INET6_ADDRSTRLEN];
2220 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2221 "Received TCP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2222 (unsigned int) mlen,
2223 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2224 ts->destination_port,
2225 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2228 if (data->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
2230 GNUNET_break_op (0);
2231 return GNUNET_SYSERR;
2237 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2238 + sizeof (struct GNUNET_TUN_TcpHeader)
2239 + sizeof (struct GNUNET_MessageHeader) +
2240 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2243 char buf[size] GNUNET_ALIGN;
2244 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2245 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2246 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2247 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv4[1];
2248 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2249 msg->size = htons (size);
2250 tun->flags = htons (0);
2251 tun->proto = htons (ETH_P_IPV4);
2252 GNUNET_TUN_initialize_ipv4_header (ipv4,
2254 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2255 &ts->destination_ip.v4,
2257 *tcp = data->tcp_header;
2258 tcp->source_port = htons (ts->destination_port);
2259 tcp->destination_port = htons (ts->source_port);
2260 GNUNET_TUN_calculate_tcp4_checksum (ipv4,
2267 (void) GNUNET_HELPER_send (helper_handle,
2276 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2277 + sizeof (struct GNUNET_TUN_TcpHeader)
2278 + sizeof (struct GNUNET_MessageHeader) +
2279 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2282 char buf[size] GNUNET_ALIGN;
2283 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2284 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2285 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2286 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv6[1];
2287 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2288 msg->size = htons (size);
2289 tun->flags = htons (0);
2290 tun->proto = htons (ETH_P_IPV6);
2291 GNUNET_TUN_initialize_ipv6_header (ipv6,
2293 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2294 &ts->destination_ip.v6,
2296 *tcp = data->tcp_header;
2297 tcp->source_port = htons (ts->destination_port);
2298 tcp->destination_port = htons (ts->source_port);
2299 GNUNET_TUN_calculate_tcp6_checksum (ipv6,
2306 (void) GNUNET_HELPER_send (helper_handle,
2314 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2316 GNUNET_TIME_absolute_get ().abs_value);
2322 * Allocate an IPv4 address from the range of the tunnel
2323 * for a new redirection.
2325 * @param v4 where to store the address
2326 * @return GNUNET_OK on success,
2327 * GNUNET_SYSERR on error
2330 allocate_v4_address (struct in_addr *v4)
2332 const char *ipv4addr = vpn_argv[4];
2333 const char *ipv4mask = vpn_argv[5];
2334 struct in_addr addr;
2335 struct in_addr mask;
2337 struct GNUNET_HashCode key;
2340 GNUNET_assert (1 == inet_pton (AF_INET, ipv4addr, &addr));
2341 GNUNET_assert (1 == inet_pton (AF_INET, ipv4mask, &mask));
2342 /* Given 192.168.0.1/255.255.0.0, we want a mask
2343 of '192.168.255.255', thus: */
2344 mask.s_addr = addr.s_addr | ~mask.s_addr;
2351 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2352 _("Failed to find unallocated IPv4 address in VPN's range\n"));
2353 return GNUNET_SYSERR;
2355 /* Pick random IPv4 address within the subnet, except 'addr' or 'mask' itself */
2356 rnd.s_addr = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2358 v4->s_addr = (addr.s_addr | rnd.s_addr) & mask.s_addr;
2359 get_destination_key_from_ip (AF_INET,
2363 while ( (GNUNET_YES ==
2364 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2366 (v4->s_addr == addr.s_addr) ||
2367 (v4->s_addr == mask.s_addr) );
2373 * Allocate an IPv6 address from the range of the tunnel
2374 * for a new redirection.
2376 * @param v6 where to store the address
2377 * @return GNUNET_OK on success,
2378 * GNUNET_SYSERR on error
2381 allocate_v6_address (struct in6_addr *v6)
2383 const char *ipv6addr = vpn_argv[2];
2384 struct in6_addr addr;
2385 struct in6_addr mask;
2386 struct in6_addr rnd;
2388 struct GNUNET_HashCode key;
2391 GNUNET_assert (1 == inet_pton (AF_INET6, ipv6addr, &addr));
2392 GNUNET_assert (ipv6prefix < 128);
2393 /* Given ABCD::/96, we want a mask of 'ABCD::FFFF:FFFF,
2396 for (i=127;i>=ipv6prefix;i--)
2397 mask.s6_addr[i / 8] |= (1 << (i % 8));
2399 /* Pick random IPv6 address within the subnet, except 'addr' or 'mask' itself */
2406 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2407 _("Failed to find unallocated IPv6 address in VPN's range\n"));
2408 return GNUNET_SYSERR;
2413 rnd.s6_addr[i] = (unsigned char) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2416 = (addr.s6_addr[i] | rnd.s6_addr[i]) & mask.s6_addr[i];
2418 get_destination_key_from_ip (AF_INET6,
2422 while ( (GNUNET_YES ==
2423 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2427 sizeof (struct in6_addr))) ||
2430 sizeof (struct in6_addr))) );
2436 * Free resources occupied by a destination entry.
2438 * @param de entry to free
2441 free_destination_entry (struct DestinationEntry *de)
2443 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2444 "Cleaning up destination entry\n");
2445 GNUNET_STATISTICS_update (stats,
2446 gettext_noop ("# Active destinations"),
2450 free_tunnel_state (de->ts);
2451 GNUNET_assert (NULL == de->ts);
2453 if (NULL != de->heap_node)
2455 GNUNET_CONTAINER_heap_remove_node (de->heap_node);
2456 de->heap_node = NULL;
2457 GNUNET_assert (GNUNET_YES ==
2458 GNUNET_CONTAINER_multihashmap_remove (destination_map,
2467 * We have too many active destinations. Clean up the oldest destination.
2469 * @param except destination that must NOT be cleaned up, even if it is the oldest
2472 expire_destination (struct DestinationEntry *except)
2474 struct DestinationEntry *de;
2476 de = GNUNET_CONTAINER_heap_peek (destination_heap);
2477 GNUNET_assert (NULL != de);
2479 return; /* can't do this */
2480 free_destination_entry (de);
2485 * Allocate an IP address for the response.
2487 * @param result_af desired address family; set to the actual
2488 * address family; can initially be AF_UNSPEC if there
2489 * is no preference; will be set to AF_UNSPEC if the
2491 * @param addr set to either v4 or v6 depending on which
2492 * storage location was used; set to NULL if allocation failed
2493 * @param v4 storage space for an IPv4 address
2494 * @param v6 storage space for an IPv6 address
2495 * @return GNUNET_OK normally, GNUNET_SYSERR if '*result_af' was
2496 * an unsupported address family (not AF_INET, AF_INET6 or AF_UNSPEC)
2499 allocate_response_ip (int *result_af,
2502 struct in6_addr *v6)
2509 allocate_v4_address (v4))
2510 *result_af = AF_UNSPEC;
2516 allocate_v6_address (v6))
2517 *result_af = AF_UNSPEC;
2523 allocate_v4_address (v4))
2526 *result_af = AF_INET;
2528 else if (GNUNET_OK ==
2529 allocate_v6_address (v6))
2532 *result_af = AF_INET6;
2537 return GNUNET_SYSERR;
2544 * A client asks us to setup a redirection via some exit
2545 * node to a particular IP. Setup the redirection and
2546 * give the client the allocated IP.
2549 * @param client requesting client
2550 * @param message redirection request (a 'struct RedirectToIpRequestMessage')
2553 service_redirect_to_ip (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
2554 const struct GNUNET_MessageHeader *message)
2558 const struct RedirectToIpRequestMessage *msg;
2564 struct DestinationEntry *de;
2565 struct GNUNET_HashCode key;
2566 struct TunnelState *ts;
2568 /* validate and parse request */
2569 mlen = ntohs (message->size);
2570 if (mlen < sizeof (struct RedirectToIpRequestMessage))
2573 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2576 alen = mlen - sizeof (struct RedirectToIpRequestMessage);
2577 msg = (const struct RedirectToIpRequestMessage *) message;
2578 addr_af = (int) htonl (msg->addr_af);
2582 if (alen != sizeof (struct in_addr))
2585 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2590 if (alen != sizeof (struct in6_addr))
2593 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2599 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2603 /* allocate response IP */
2604 result_af = (int) htonl (msg->result_af);
2605 if (GNUNET_OK != allocate_response_ip (&result_af,
2609 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2612 if ( (result_af == AF_UNSPEC) ||
2613 (GNUNET_NO == ntohl (msg->nac)) )
2615 /* send reply "instantly" */
2616 send_client_reply (client,
2621 if (result_af == AF_UNSPEC)
2623 /* failure, we're done */
2624 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2629 char sbuf[INET6_ADDRSTRLEN];
2630 char dbuf[INET6_ADDRSTRLEN];
2632 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2633 "Allocated address %s for redirection via exit to %s\n",
2634 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2636 &msg[1], dbuf, sizeof (dbuf)));
2639 /* setup destination record */
2640 de = GNUNET_malloc (sizeof (struct DestinationEntry));
2641 de->is_service = GNUNET_NO;
2642 de->details.exit_destination.af = addr_af;
2643 memcpy (&de->details.exit_destination.ip,
2646 get_destination_key_from_ip (result_af,
2650 GNUNET_assert (GNUNET_OK ==
2651 GNUNET_CONTAINER_multihashmap_put (destination_map,
2654 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2655 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2657 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
2658 GNUNET_STATISTICS_update (stats,
2659 gettext_noop ("# Active destinations"),
2661 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2662 expire_destination (de);
2664 /* setup tunnel to destination */
2665 ts = create_tunnel_to_destination (de,
2666 (GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
2672 ts->destination_ip.v4 = v4;
2675 ts->destination_ip.v6 = v6;
2681 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2686 * A client asks us to setup a redirection to a particular peer
2687 * offering a service. Setup the redirection and give the client the
2691 * @param client requesting client
2692 * @param message redirection request (a 'struct RedirectToPeerRequestMessage')
2695 service_redirect_to_service (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
2696 const struct GNUNET_MessageHeader *message)
2698 const struct RedirectToServiceRequestMessage *msg;
2703 struct DestinationEntry *de;
2704 struct GNUNET_HashCode key;
2705 struct TunnelState *ts;
2708 msg = (const struct RedirectToServiceRequestMessage *) message;
2710 /* allocate response IP */
2711 result_af = (int) htonl (msg->result_af);
2712 if (GNUNET_OK != allocate_response_ip (&result_af,
2716 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2719 if ( (result_af == AF_UNSPEC) ||
2720 (GNUNET_NO == ntohl (msg->nac)) )
2722 /* send reply "instantly" */
2723 send_client_reply (client,
2728 if (result_af == AF_UNSPEC)
2730 /* failure, we're done */
2731 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2732 _("Failed to allocate IP address for new destination\n"));
2733 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2738 char sbuf[INET6_ADDRSTRLEN];
2740 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2741 "Allocated address %s for redirection to service %s on peer %s\n",
2742 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2743 GNUNET_h2s (&msg->service_descriptor),
2744 GNUNET_i2s (&msg->target));
2747 /* setup destination record */
2748 de = GNUNET_malloc (sizeof (struct DestinationEntry));
2749 de->is_service = GNUNET_YES;
2750 de->details.service_destination.service_descriptor = msg->service_descriptor;
2751 de->details.service_destination.target = msg->target;
2752 get_destination_key_from_ip (result_af,
2756 GNUNET_assert (GNUNET_OK ==
2757 GNUNET_CONTAINER_multihashmap_put (destination_map,
2760 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2761 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2763 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
2764 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2765 expire_destination (de);
2766 ts = create_tunnel_to_destination (de,
2767 (GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
2773 ts->destination_ip.v4 = v4;
2776 ts->destination_ip.v6 = v6;
2782 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2788 * Function called for inbound tunnels. As we don't offer
2789 * any mesh services, this function should never be called.
2791 * @param cls closure
2792 * @param tunnel new handle to the tunnel
2793 * @param initiator peer that started the tunnel
2794 * @param atsi performance information for the tunnel
2795 * @return initial tunnel context for the tunnel
2796 * (can be NULL -- that's not an error)
2799 inbound_tunnel_cb (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
2800 const struct GNUNET_PeerIdentity *initiator,
2801 const struct GNUNET_ATS_Information *atsi)
2803 /* How can and why should anyone open an inbound tunnel to vpn? */
2810 * Function called whenever an inbound tunnel is destroyed. Should clean up
2811 * any associated state.
2813 * @param cls closure (set from GNUNET_MESH_connect)
2814 * @param tunnel connection to the other end (henceforth invalid)
2815 * @param tunnel_ctx place where local state associated
2816 * with the tunnel is stored (our 'struct TunnelState')
2819 tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel_ctx)
2821 /* we don't have inbound tunnels, so this function should never be called */
2827 * Free memory occupied by an entry in the destination map.
2831 * @param value a 'struct DestinationEntry *'
2832 * @return GNUNET_OK (continue to iterate)
2835 cleanup_destination (void *cls,
2836 const struct GNUNET_HashCode *key,
2839 struct DestinationEntry *de = value;
2841 free_destination_entry (de);
2847 * Free memory occupied by an entry in the tunnel map.
2851 * @param value a 'struct TunnelState *'
2852 * @return GNUNET_OK (continue to iterate)
2855 cleanup_tunnel (void *cls,
2856 const struct GNUNET_HashCode *key,
2859 struct TunnelState *ts = value;
2861 free_tunnel_state (ts);
2867 * Function scheduled as very last function, cleans up after us
2873 cleanup (void *cls GNUNET_UNUSED,
2874 const struct GNUNET_SCHEDULER_TaskContext *tc)
2878 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2879 "VPN is shutting down\n");
2880 if (NULL != destination_map)
2882 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
2883 &cleanup_destination,
2885 GNUNET_CONTAINER_multihashmap_destroy (destination_map);
2886 destination_map = NULL;
2888 if (NULL != destination_heap)
2890 GNUNET_CONTAINER_heap_destroy (destination_heap);
2891 destination_heap = NULL;
2893 if (NULL != tunnel_map)
2895 GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
2898 GNUNET_CONTAINER_multihashmap_destroy (tunnel_map);
2901 if (NULL != tunnel_heap)
2903 GNUNET_CONTAINER_heap_destroy (tunnel_heap);
2906 if (NULL != mesh_handle)
2908 GNUNET_MESH_disconnect (mesh_handle);
2911 if (NULL != helper_handle)
2913 GNUNET_HELPER_stop (helper_handle);
2914 helper_handle = NULL;
2918 GNUNET_SERVER_notification_context_destroy (nc);
2923 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
2927 GNUNET_free_non_null (vpn_argv[i]);
2932 * A client disconnected, clean up all references to it.
2934 * @param cls the client that disconnected
2936 * @param value a 'struct TunnelState *'
2937 * @return GNUNET_OK (continue to iterate)
2940 cleanup_tunnel_client (void *cls,
2941 const struct GNUNET_HashCode *key,
2944 struct GNUNET_SERVER_Client *client = cls;
2945 struct TunnelState *ts = value;
2947 if (client == ts->client)
2949 GNUNET_SERVER_client_drop (ts->client);
2957 * A client disconnected, clean up all references to it.
2959 * @param cls the client that disconnected
2961 * @param value a 'struct DestinationEntry *'
2962 * @return GNUNET_OK (continue to iterate)
2965 cleanup_destination_client (void *cls,
2966 const struct GNUNET_HashCode *key,
2969 struct GNUNET_SERVER_Client *client = cls;
2970 struct DestinationEntry *de = value;
2971 struct TunnelState *ts;
2973 if (NULL == (ts = de->ts))
2975 if (client == ts->client)
2977 GNUNET_SERVER_client_drop (ts->client);
2985 * A client has disconnected from us. If we are currently building
2986 * a tunnel for it, cancel the operation.
2989 * @param client handle to the client that disconnected
2992 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
2994 if (NULL != tunnel_map)
2995 GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
2996 &cleanup_tunnel_client,
2998 if (NULL != destination_map)
2999 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
3000 &cleanup_destination_client,
3006 * Test if the given AF is supported by this system.
3009 * @return GNUNET_OK if the AF is supported
3016 s = socket (af, SOCK_STREAM, 0);
3019 if (EAFNOSUPPORT == errno)
3021 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
3023 return GNUNET_SYSERR;
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},
3056 static const GNUNET_MESH_ApplicationType types[] = {
3057 GNUNET_APPLICATION_TYPE_END
3068 GNUNET_OS_check_helper_binary ("gnunet-helper-vpn"))
3071 "`%s' is not SUID, refusing to run.\n",
3072 "gnunet-helper-vpn");
3077 stats = GNUNET_STATISTICS_create ("vpn", cfg);
3079 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_MAPPING",
3080 &max_destination_mappings))
3081 max_destination_mappings = 200;
3083 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_TUNNELS",
3084 &max_tunnel_mappings))
3085 max_tunnel_mappings = 200;
3087 destination_map = GNUNET_CONTAINER_multihashmap_create (max_destination_mappings * 2);
3088 destination_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3089 tunnel_map = GNUNET_CONTAINER_multihashmap_create (max_tunnel_mappings * 2);
3090 tunnel_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3093 vpn_argv[0] = GNUNET_strdup ("vpn-gnunet");
3094 if (GNUNET_SYSERR ==
3095 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IFNAME", &ifname))
3097 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3098 "No entry 'IFNAME' in configuration!\n");
3099 GNUNET_SCHEDULER_shutdown ();
3102 vpn_argv[1] = ifname;
3103 if (GNUNET_OK == test_af (AF_INET6))
3105 if ( (GNUNET_SYSERR ==
3106 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6ADDR",
3108 (1 != inet_pton (AF_INET6, ipv6addr, &v6))) )
3110 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3111 "No valid entry 'IPV6ADDR' in configuration!\n");
3112 GNUNET_SCHEDULER_shutdown ();
3115 vpn_argv[2] = ipv6addr;
3116 if (GNUNET_SYSERR ==
3117 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6PREFIX",
3120 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3121 "No entry 'IPV6PREFIX' in configuration!\n");
3122 GNUNET_SCHEDULER_shutdown ();
3125 vpn_argv[3] = ipv6prefix_s;
3127 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn",
3130 (ipv6prefix >= 127) )
3132 GNUNET_SCHEDULER_shutdown ();
3138 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3139 _("IPv6 support disabled as this system does not support IPv6\n"));
3140 vpn_argv[2] = GNUNET_strdup ("-");
3141 vpn_argv[3] = GNUNET_strdup ("-");
3143 if (GNUNET_OK == test_af (AF_INET))
3145 if ( (GNUNET_SYSERR ==
3146 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4ADDR",
3148 (1 != inet_pton (AF_INET, ipv4addr, &v4))) )
3150 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3151 "No valid entry for 'IPV4ADDR' in configuration!\n");
3152 GNUNET_SCHEDULER_shutdown ();
3155 vpn_argv[4] = ipv4addr;
3156 if ( (GNUNET_SYSERR ==
3157 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4MASK",
3159 (1 != inet_pton (AF_INET, ipv4mask, &v4))) )
3161 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3162 "No valid entry 'IPV4MASK' in configuration!\n");
3163 GNUNET_SCHEDULER_shutdown ();
3166 vpn_argv[5] = ipv4mask;
3170 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3171 _("IPv4 support disabled as this system does not support IPv4\n"));
3172 vpn_argv[4] = GNUNET_strdup ("-");
3173 vpn_argv[5] = GNUNET_strdup ("-");
3178 GNUNET_MESH_connect (cfg_, NULL,
3183 helper_handle = GNUNET_HELPER_start (GNUNET_NO,
3184 "gnunet-helper-vpn", vpn_argv,
3185 &message_token, NULL, NULL);
3186 nc = GNUNET_SERVER_notification_context_create (server, 1);
3187 GNUNET_SERVER_add_handlers (server, service_handlers);
3188 GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
3189 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls);
3194 * The main function of the VPN service.
3196 * @param argc number of arguments from the command line
3197 * @param argv command line arguments
3198 * @return 0 ok, 1 on error
3201 main (int argc, char *const *argv)
3203 return (GNUNET_OK ==
3204 GNUNET_SERVICE_run (argc, argv, "vpn",
3205 GNUNET_SERVICE_OPTION_NONE,
3206 &run, NULL)) ? global_ret : 1;
3209 /* end of gnunet-service-vpn.c */