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').
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 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 * Configuration we use.
290 static const struct GNUNET_CONFIGURATION_Handle *cfg;
293 * Handle to the mesh service.
295 static struct GNUNET_MESH_Handle *mesh_handle;
298 * Map from IP address to destination information (possibly with a
299 * MESH tunnel handle for fast setup).
301 static struct GNUNET_CONTAINER_MultiHashMap *destination_map;
304 * Min-Heap sorted by activity time to expire old mappings.
306 static struct GNUNET_CONTAINER_Heap *destination_heap;
309 * Map from source and destination address (IP+port) to connection
310 * information (mostly with the respective MESH tunnel handle).
312 static struct GNUNET_CONTAINER_MultiHashMap *tunnel_map;
315 * Min-Heap sorted by activity time to expire old mappings; values are
316 * of type 'struct TunnelState'.
318 static struct GNUNET_CONTAINER_Heap *tunnel_heap;
323 static struct GNUNET_STATISTICS_Handle *stats;
326 * The handle to the VPN helper process "gnunet-helper-vpn".
328 static struct GNUNET_HELPER_Handle *helper_handle;
331 * Arguments to the vpn helper.
333 static char *vpn_argv[7];
336 * Length of the prefix of the VPN's IPv6 network.
338 static unsigned long long ipv6prefix;
341 * Notification context for sending replies to clients.
343 static struct GNUNET_SERVER_NotificationContext *nc;
346 * If there are more than this number of address-mappings, old ones
349 static unsigned long long max_destination_mappings;
352 * If there are more than this number of open tunnels, old ones
355 static unsigned long long max_tunnel_mappings;
359 * Compute the key under which we would store an entry in the
360 * destination_map for the given IP address.
362 * @param af address family (AF_INET or AF_INET6)
363 * @param address IP address, struct in_addr or struct in6_addr
364 * @param key where to store the key
367 get_destination_key_from_ip (int af,
369 GNUNET_HashCode *key)
374 GNUNET_CRYPTO_hash (address,
375 sizeof (struct in_addr),
379 GNUNET_CRYPTO_hash (address,
380 sizeof (struct in6_addr),
391 * Compute the key under which we would store an entry in the
392 * tunnel_map for the given socket address pair.
394 * @param af address family (AF_INET or AF_INET6)
395 * @param protocol IPPROTO_TCP or IPPROTO_UDP
396 * @param source_ip sender's source IP, struct in_addr or struct in6_addr
397 * @param source_port sender's source port
398 * @param destination_ip sender's destination IP, struct in_addr or struct in6_addr
399 * @param destination_port sender's destination port
400 * @param key where to store the key
403 get_tunnel_key_from_ips (int af,
405 const void *source_ip,
406 uint16_t source_port,
407 const void *destination_ip,
408 uint16_t destination_port,
409 GNUNET_HashCode *key)
413 memset (key, 0, sizeof (GNUNET_HashCode));
414 /* the GNUnet hashmap only uses the first sizeof(unsigned int) of the hash,
415 so we put the ports in there (and hope for few collisions) */
417 memcpy (off, &source_port, sizeof (uint16_t));
418 off += sizeof (uint16_t);
419 memcpy (off, &destination_port, sizeof (uint16_t));
420 off += sizeof (uint16_t);
424 memcpy (off, source_ip, sizeof (struct in_addr));
425 off += sizeof (struct in_addr);
426 memcpy (off, destination_ip, sizeof (struct in_addr));
427 off += sizeof (struct in_addr);
430 memcpy (off, source_ip, sizeof (struct in6_addr));
431 off += sizeof (struct in6_addr);
432 memcpy (off, destination_ip, sizeof (struct in6_addr));
433 off += sizeof (struct in6_addr);
439 memcpy (off, &protocol, sizeof (uint8_t));
440 off += sizeof (uint8_t);
445 * Notify the client about the result of its request.
447 * @param client client to notify
448 * @param request_id original request ID to include in response
449 * @param result_af resulting address family
450 * @param addr resulting IP address
453 send_client_reply (struct GNUNET_SERVER_Client *client,
458 char buf[sizeof (struct RedirectToIpResponseMessage) + sizeof (struct in6_addr)];
459 struct RedirectToIpResponseMessage *res;
465 rlen = sizeof (struct in_addr);
468 rlen = sizeof (struct in6_addr);
477 res = (struct RedirectToIpResponseMessage *) buf;
478 res->header.size = htons (sizeof (struct RedirectToIpResponseMessage) + rlen);
479 res->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP);
480 res->result_af = htonl (result_af);
481 res->request_id = request_id;
482 memcpy (&res[1], addr, rlen);
483 GNUNET_SERVER_notification_context_add (nc, client);
484 GNUNET_SERVER_notification_context_unicast (nc,
492 * Free resources associated with a tunnel state.
494 * @param ts state to free
497 free_tunnel_state (struct TunnelState *ts)
500 struct TunnelMessageQueueEntry *tnq;
501 struct GNUNET_MESH_Tunnel *tunnel;
503 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
504 "Cleaning up tunnel state\n");
505 GNUNET_STATISTICS_update (stats,
506 gettext_noop ("# Active tunnels"),
508 while (NULL != (tnq = ts->tmq_head))
510 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
516 GNUNET_assert (0 == ts->tmq_length);
517 if (NULL != ts->client)
519 GNUNET_SERVER_client_drop (ts->client);
524 GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
527 GNUNET_assert (NULL == ts->destination.heap_node);
528 if (NULL != (tunnel = ts->tunnel))
531 GNUNET_MESH_tunnel_destroy (tunnel);
533 if (GNUNET_SCHEDULER_NO_TASK != ts->destroy_task)
535 GNUNET_SCHEDULER_cancel (ts->destroy_task);
536 ts->destroy_task = GNUNET_SCHEDULER_NO_TASK;
538 if (NULL != ts->heap_node)
540 GNUNET_CONTAINER_heap_remove_node (ts->heap_node);
541 ts->heap_node = NULL;
542 get_tunnel_key_from_ips (ts->af,
547 ts->destination_port,
549 GNUNET_assert (GNUNET_YES ==
550 GNUNET_CONTAINER_multihashmap_remove (tunnel_map,
554 if (NULL != ts->destination_container)
556 GNUNET_assert (ts == ts->destination_container->ts);
557 ts->destination_container->ts = NULL;
558 ts->destination_container = NULL;
565 * Destroy the mesh tunnel.
567 * @param cls the 'struct TunnelState' with the tunnel to destroy
568 * @param ts schedule context
571 destroy_tunnel_task (void *cls,
572 const struct GNUNET_SCHEDULER_TaskContext *tc)
574 struct TunnelState *ts = cls;
575 struct GNUNET_MESH_Tunnel *tunnel;
577 ts->destroy_task = GNUNET_SCHEDULER_NO_TASK;
578 GNUNET_assert (NULL != ts->tunnel);
581 GNUNET_MESH_tunnel_destroy (tunnel);
582 free_tunnel_state (ts);
587 * Method called whenever a peer has disconnected from the tunnel.
590 * @param peer peer identity the tunnel stopped working with
593 tunnel_peer_disconnect_handler (void *cls,
595 GNUNET_PeerIdentity * peer)
597 struct TunnelState *ts = cls;
599 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
600 "Peer %s disconnected from tunnel.\n",
602 GNUNET_STATISTICS_update (stats,
603 gettext_noop ("# Peers connected to mesh tunnels"),
607 GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
610 if (ts->destination.is_service)
611 return; /* hope for reconnect eventually */
612 /* as we are most likely going to change the exit node now,
613 we should just destroy the tunnel entirely... */
614 if (GNUNET_SCHEDULER_NO_TASK == ts->destroy_task)
615 ts->destroy_task = GNUNET_SCHEDULER_add_now (&destroy_tunnel_task, ts);
620 * Method called whenever a peer has connected to the tunnel. Notifies
621 * the waiting client that the tunnel is now up.
624 * @param peer peer identity the tunnel was created to, NULL on timeout
625 * @param atsi performance data for the connection
628 tunnel_peer_connect_handler (void *cls,
629 const struct GNUNET_PeerIdentity
632 GNUNET_ATS_Information * atsi)
634 struct TunnelState *ts = cls;
636 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
637 "Peer %s connected to tunnel.\n",
639 GNUNET_STATISTICS_update (stats,
640 gettext_noop ("# Peers connected to mesh tunnels"),
642 if (NULL == ts->client)
643 return; /* nothing to do */
644 send_client_reply (ts->client,
647 &ts->destination_ip);
648 GNUNET_SERVER_client_drop (ts->client);
654 * Send a message from the message queue via mesh.
656 * @param cls the 'struct TunnelState' with the message queue
657 * @param size number of bytes available in buf
658 * @param buf where to copy the message
659 * @return number of bytes copied to buf
662 send_to_peer_notify_callback (void *cls, size_t size, void *buf)
664 struct TunnelState *ts = cls;
665 struct TunnelMessageQueueEntry *tnq;
672 GNUNET_assert (NULL != tnq);
673 GNUNET_assert (size >= tnq->len);
674 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
675 "Sending %u bytes via mesh tunnel\n",
677 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
681 memcpy (buf, tnq->msg, tnq->len);
684 if (NULL != (tnq = ts->tmq_head))
685 ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel,
686 GNUNET_NO /* cork */,
688 GNUNET_TIME_UNIT_FOREVER_REL,
691 &send_to_peer_notify_callback,
693 GNUNET_STATISTICS_update (stats,
694 gettext_noop ("# Bytes given to mesh for transmission"),
701 * Add the given message to the given tunnel and trigger the
702 * transmission process.
704 * @param tnq message to queue
705 * @param ts tunnel to queue the message for
708 send_to_tunnel (struct TunnelMessageQueueEntry *tnq,
709 struct TunnelState *ts)
711 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
712 "Queueing %u bytes for transmission via mesh tunnel\n",
714 GNUNET_assert (NULL != ts->tunnel);
715 GNUNET_CONTAINER_DLL_insert_tail (ts->tmq_head,
719 if (ts->tmq_length > MAX_MESSAGE_QUEUE_SIZE)
721 struct TunnelMessageQueueEntry *dq;
724 GNUNET_assert (dq != tnq);
725 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
729 GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
731 GNUNET_STATISTICS_update (stats,
732 gettext_noop ("# Bytes dropped in mesh queue (overflow)"),
738 ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel,
739 GNUNET_NO /* cork */,
741 GNUNET_TIME_UNIT_FOREVER_REL,
744 &send_to_peer_notify_callback,
750 * Initialize the given destination entry's mesh tunnel.
752 * @param de destination entry for which we need to setup a tunnel
753 * @param client client to notify on successful tunnel setup, or NULL for none
754 * @param request_id request ID to send in client notification (unused if client is NULL)
755 * @return tunnel state of the tunnel that was created
757 static struct TunnelState *
758 create_tunnel_to_destination (struct DestinationEntry *de,
759 struct GNUNET_SERVER_Client *client,
763 struct TunnelState *ts;
765 GNUNET_STATISTICS_update (stats,
766 gettext_noop ("# Mesh tunnels created"),
768 GNUNET_assert (NULL == de->ts);
769 ts = GNUNET_malloc (sizeof (struct TunnelState));
773 ts->request_id = request_id;
775 GNUNET_SERVER_client_keep (client);
777 ts->destination = *de;
778 ts->destination.heap_node = NULL; /* copy is NOT in destination heap */
780 ts->destination_container = de; /* we are referenced from de */
781 ts->tunnel = GNUNET_MESH_tunnel_create (mesh_handle,
783 &tunnel_peer_connect_handler,
784 &tunnel_peer_disconnect_handler,
786 if (NULL == ts->tunnel)
788 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
789 _("Failed to setup mesh tunnel!\n"));
791 GNUNET_SERVER_client_drop (client);
797 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
798 "Creating tunnel to peer %s offering service %s\n",
799 GNUNET_i2s (&de->details.service_destination.target),
800 GNUNET_h2s (&de->details.service_destination.service_descriptor));
801 GNUNET_MESH_peer_request_connect_add (ts->tunnel,
802 &de->details.service_destination.target);
806 switch (de->details.exit_destination.af)
809 GNUNET_MESH_peer_request_connect_by_type (ts->tunnel,
810 GNUNET_APPLICATION_TYPE_IPV4_GATEWAY);
811 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
812 "Creating tunnel to exit peer for %s\n",
816 GNUNET_MESH_peer_request_connect_by_type (ts->tunnel,
817 GNUNET_APPLICATION_TYPE_IPV6_GATEWAY);
818 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
819 "Creating tunnel to exit peer for %s\n",
832 * We have too many active tunnels. Clean up the oldest tunnel.
834 * @param except tunnel that must NOT be cleaned up, even if it is the oldest
837 expire_tunnel (struct TunnelState *except)
839 struct TunnelState *ts;
841 ts = GNUNET_CONTAINER_heap_peek (tunnel_heap);
843 return; /* can't do this */
844 free_tunnel_state (ts);
849 * Route a packet via mesh to the given destination.
851 * @param destination description of the destination
852 * @param af address family on this end (AF_INET or AF_INET6)
853 * @param protocol IPPROTO_TCP or IPPROTO_UDP
854 * @param source_ip source IP used by the sender (struct in_addr or struct in6_addr)
855 * @param destination_ip destination IP used by the sender (struct in_addr or struct in6_addr)
856 * @param payload payload of the packet after the IP header
857 * @param payload_length number of bytes in payload
860 route_packet (struct DestinationEntry *destination,
863 const void *source_ip,
864 const void *destination_ip,
866 size_t payload_length)
869 struct TunnelState *ts;
870 struct TunnelMessageQueueEntry *tnq;
874 const struct GNUNET_TUN_UdpHeader *udp;
875 const struct GNUNET_TUN_TcpHeader *tcp;
876 const struct GNUNET_TUN_IcmpHeader *icmp;
884 if (payload_length < sizeof (struct GNUNET_TUN_UdpHeader))
891 spt = ntohs (udp->spt);
892 dpt = ntohs (udp->dpt);
893 get_tunnel_key_from_ips (af,
904 if (payload_length < sizeof (struct GNUNET_TUN_TcpHeader))
911 spt = ntohs (tcp->spt);
912 dpt = ntohs (tcp->dpt);
913 get_tunnel_key_from_ips (af,
924 if (payload_length < sizeof (struct GNUNET_TUN_IcmpHeader))
933 get_tunnel_key_from_ips (af,
943 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
944 _("Protocol %u not supported, dropping\n"),
945 (unsigned int) protocol);
948 if (! destination->is_service)
950 switch (destination->details.exit_destination.af)
953 alen = sizeof (struct in_addr);
956 alen = sizeof (struct in6_addr);
964 char sbuf[INET6_ADDRSTRLEN];
965 char dbuf[INET6_ADDRSTRLEN];
966 char xbuf[INET6_ADDRSTRLEN];
968 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
969 "Routing %s packet from %s:%u -> %s:%u to destination %s:%u\n",
970 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
971 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
973 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
975 inet_ntop (destination->details.exit_destination.af,
976 &destination->details.exit_destination.ip,
977 xbuf, sizeof (xbuf)),
983 /* make compiler happy */
986 char sbuf[INET6_ADDRSTRLEN];
987 char dbuf[INET6_ADDRSTRLEN];
989 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
990 "Routing %s packet from %s:%u -> %s:%u to service %s at peer %s\n",
991 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
992 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
994 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
996 GNUNET_h2s (&destination->details.service_destination.service_descriptor),
997 GNUNET_i2s (&destination->details.service_destination.target));
1002 /* see if we have an existing tunnel for this destination */
1003 ts = GNUNET_CONTAINER_multihashmap_get (tunnel_map,
1007 /* need to either use the existing tunnel from the destination (if still
1008 available) or create a fresh one */
1009 is_new = GNUNET_YES;
1010 if (NULL == destination->ts)
1011 ts = create_tunnel_to_destination (destination, NULL, af, 0);
1013 ts = destination->ts;
1016 destination->ts = NULL;
1017 ts->destination_container = NULL; /* no longer 'contained' */
1018 /* now bind existing "unbound" tunnel to our IP/port tuple */
1019 ts->protocol = protocol;
1023 ts->source_ip.v4 = * (const struct in_addr *) source_ip;
1024 ts->destination_ip.v4 = * (const struct in_addr *) destination_ip;
1028 ts->source_ip.v6 = * (const struct in6_addr *) source_ip;
1029 ts->destination_ip.v6 = * (const struct in6_addr *) destination_ip;
1031 ts->source_port = spt;
1032 ts->destination_port = dpt;
1033 ts->heap_node = GNUNET_CONTAINER_heap_insert (tunnel_heap,
1035 GNUNET_TIME_absolute_get ().abs_value);
1036 GNUNET_assert (GNUNET_YES ==
1037 GNUNET_CONTAINER_multihashmap_put (tunnel_map,
1040 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1041 GNUNET_STATISTICS_update (stats,
1042 gettext_noop ("# Active tunnels"),
1044 while (GNUNET_CONTAINER_multihashmap_size (tunnel_map) > max_tunnel_mappings)
1050 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
1052 GNUNET_TIME_absolute_get ().abs_value);
1054 GNUNET_assert (NULL != ts->tunnel);
1056 /* send via tunnel */
1060 if (destination->is_service)
1062 struct GNUNET_EXIT_UdpServiceMessage *usm;
1064 mlen = sizeof (struct GNUNET_EXIT_UdpServiceMessage) +
1065 payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1066 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1071 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1074 usm = (struct GNUNET_EXIT_UdpServiceMessage *) &tnq[1];
1075 usm->header.size = htons ((uint16_t) mlen);
1076 usm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE);
1077 /* if the source port is below 32000, we assume it has a special
1078 meaning; if not, we pick a random port (this is a heuristic) */
1079 usm->source_port = (ntohs (udp->spt) < 32000) ? udp->spt : 0;
1080 usm->destination_port = udp->dpt;
1081 usm->service_descriptor = destination->details.service_destination.service_descriptor;
1084 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1088 struct GNUNET_EXIT_UdpInternetMessage *uim;
1089 struct in_addr *ip4dst;
1090 struct in6_addr *ip6dst;
1093 mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) +
1094 alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1095 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1100 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) +
1104 uim = (struct GNUNET_EXIT_UdpInternetMessage *) &tnq[1];
1105 uim->header.size = htons ((uint16_t) mlen);
1106 uim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET);
1107 uim->af = htonl (destination->details.exit_destination.af);
1108 uim->source_port = (ntohs (udp->spt) < 32000) ? udp->spt : 0;
1109 uim->destination_port = udp->dpt;
1110 switch (destination->details.exit_destination.af)
1113 ip4dst = (struct in_addr *) &uim[1];
1114 *ip4dst = destination->details.exit_destination.ip.v4;
1115 payload = &ip4dst[1];
1118 ip6dst = (struct in6_addr *) &uim[1];
1119 *ip6dst = destination->details.exit_destination.ip.v6;
1120 payload = &ip6dst[1];
1127 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1133 if (destination->is_service)
1135 struct GNUNET_EXIT_TcpServiceStartMessage *tsm;
1137 mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) +
1138 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1139 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1144 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1147 tsm = (struct GNUNET_EXIT_TcpServiceStartMessage *) &tnq[1];
1148 tsm->header.size = htons ((uint16_t) mlen);
1149 tsm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START);
1150 tsm->reserved = htonl (0);
1151 tsm->service_descriptor = destination->details.service_destination.service_descriptor;
1152 tsm->tcp_header = *tcp;
1155 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1159 struct GNUNET_EXIT_TcpInternetStartMessage *tim;
1160 struct in_addr *ip4dst;
1161 struct in6_addr *ip6dst;
1164 mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) +
1165 alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1166 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1171 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1174 tim = (struct GNUNET_EXIT_TcpInternetStartMessage *) &tnq[1];
1175 tim->header.size = htons ((uint16_t) mlen);
1176 tim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START);
1177 tim->af = htonl (destination->details.exit_destination.af);
1178 tim->tcp_header = *tcp;
1179 switch (destination->details.exit_destination.af)
1182 ip4dst = (struct in_addr *) &tim[1];
1183 *ip4dst = destination->details.exit_destination.ip.v4;
1184 payload = &ip4dst[1];
1187 ip6dst = (struct in6_addr *) &tim[1];
1188 *ip6dst = destination->details.exit_destination.ip.v6;
1189 payload = &ip6dst[1];
1196 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1201 struct GNUNET_EXIT_TcpDataMessage *tdm;
1203 mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) +
1204 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1205 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1210 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1213 tdm = (struct GNUNET_EXIT_TcpDataMessage *) &tnq[1];
1214 tdm->header.size = htons ((uint16_t) mlen);
1215 tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT);
1216 tdm->reserved = htonl (0);
1217 tdm->tcp_header = *tcp;
1220 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1224 if (destination->is_service)
1226 struct GNUNET_EXIT_IcmpServiceMessage *ism;
1228 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1229 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1230 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1235 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1237 ism = (struct GNUNET_EXIT_IcmpServiceMessage *) &tnq[1];
1238 ism->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE);
1239 ism->af = htonl (af); /* need to tell destination ICMP protocol family! */
1240 ism->service_descriptor = destination->details.service_destination.service_descriptor;
1241 ism->icmp_header = *icmp;
1242 /* ICMP protocol translation will be done by the receiver (as we don't know
1243 the target AF); however, we still need to possibly discard the payload
1244 depending on the ICMP type */
1250 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1251 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1253 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1254 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1255 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1256 /* throw away ICMP payload, won't be useful for the other side anyway */
1257 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1260 GNUNET_STATISTICS_update (stats,
1261 gettext_noop ("# ICMPv4 packets dropped (not allowed)"),
1265 /* end of AF_INET */
1270 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1271 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1272 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1273 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1274 /* throw away ICMP payload, won't be useful for the other side anyway */
1275 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1277 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1278 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1281 GNUNET_STATISTICS_update (stats,
1282 gettext_noop ("# ICMPv6 packets dropped (not allowed)"),
1286 /* end of AF_INET6 */
1293 /* update length calculations, as payload_length may have changed */
1294 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1295 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1297 ism->header.size = htons ((uint16_t) mlen);
1298 /* finally, copy payload (if there is any left...) */
1301 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1305 struct GNUNET_EXIT_IcmpInternetMessage *iim;
1306 struct in_addr *ip4dst;
1307 struct in6_addr *ip6dst;
1310 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1311 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1312 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1317 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) +
1320 iim = (struct GNUNET_EXIT_IcmpInternetMessage *) &tnq[1];
1321 iim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET);
1322 iim->icmp_header = *icmp;
1323 /* Perform ICMP protocol-translation (depending on destination AF and source AF)
1324 and throw away ICMP payload depending on ICMP message type */
1330 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1331 if (destination->details.exit_destination.af == AF_INET6)
1332 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1334 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1335 if (destination->details.exit_destination.af == AF_INET6)
1336 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1338 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1339 if (destination->details.exit_destination.af == AF_INET6)
1340 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1341 /* throw away IP-payload, exit will have to make it up anyway */
1342 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1344 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1345 if (destination->details.exit_destination.af == AF_INET6)
1346 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1347 /* throw away IP-payload, exit will have to make it up anyway */
1348 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1350 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1351 if (destination->details.exit_destination.af == AF_INET6)
1353 GNUNET_STATISTICS_update (stats,
1354 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1359 /* throw away IP-payload, exit will have to make it up anyway */
1360 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1363 GNUNET_STATISTICS_update (stats,
1364 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1369 /* end of AF_INET */
1374 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1375 if (destination->details.exit_destination.af == AF_INET6)
1376 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1377 /* throw away IP-payload, exit will have to make it up anyway */
1378 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1380 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1381 if (destination->details.exit_destination.af == AF_INET)
1382 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1383 /* throw away IP-payload, exit will have to make it up anyway */
1384 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1386 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1387 if (destination->details.exit_destination.af == AF_INET)
1389 GNUNET_STATISTICS_update (stats,
1390 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1395 /* throw away IP-payload, exit will have to make it up anyway */
1396 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1398 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1399 if (destination->details.exit_destination.af == AF_INET)
1401 GNUNET_STATISTICS_update (stats,
1402 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1407 /* throw away IP-payload, exit will have to make it up anyway */
1408 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1410 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1411 if (destination->details.exit_destination.af == AF_INET)
1412 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1414 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1415 if (destination->details.exit_destination.af == AF_INET)
1416 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1419 GNUNET_STATISTICS_update (stats,
1420 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1425 /* end of AF_INET6 */
1430 /* update length calculations, as payload_length may have changed */
1431 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1432 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1434 iim->header.size = htons ((uint16_t) mlen);
1436 /* need to tell destination ICMP protocol family! */
1437 iim->af = htonl (destination->details.exit_destination.af);
1438 switch (destination->details.exit_destination.af)
1441 ip4dst = (struct in_addr *) &iim[1];
1442 *ip4dst = destination->details.exit_destination.ip.v4;
1443 payload = &ip4dst[1];
1446 ip6dst = (struct in6_addr *) &iim[1];
1447 *ip6dst = destination->details.exit_destination.ip.v6;
1448 payload = &ip6dst[1];
1455 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1459 /* not supported above, how can we get here !? */
1463 send_to_tunnel (tnq, ts);
1468 * Receive packets from the helper-process (someone send to the local
1469 * virtual tunnel interface). Find the destination mapping, and if it
1470 * exists, identify the correct MESH tunnel (or possibly create it)
1471 * and forward the packet.
1473 * @param cls closure, NULL
1474 * @param client NULL
1475 * @param message message we got from the client (VPN tunnel interface)
1478 message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED,
1479 const struct GNUNET_MessageHeader *message)
1481 const struct GNUNET_TUN_Layer2PacketHeader *tun;
1483 GNUNET_HashCode key;
1484 struct DestinationEntry *de;
1486 GNUNET_STATISTICS_update (stats,
1487 gettext_noop ("# Packets received from TUN interface"),
1489 mlen = ntohs (message->size);
1490 if ( (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
1491 (mlen < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader)) )
1496 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1497 mlen -= (sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader));
1498 switch (ntohs (tun->proto))
1502 const struct GNUNET_TUN_IPv6Header *pkt6;
1504 if (mlen < sizeof (struct GNUNET_TUN_IPv6Header))
1510 pkt6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1511 get_destination_key_from_ip (AF_INET6,
1512 &pkt6->destination_address,
1514 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1515 /* FIXME: do we need to guard against hash collision?
1516 (if so, we need to also store the local destination IP in the
1517 destination entry and then compare here; however, the risk
1518 of collision seems minimal AND the impact is unlikely to be
1519 super-problematic as well... */
1522 char buf[INET6_ADDRSTRLEN];
1524 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1525 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1526 inet_ntop (AF_INET6,
1527 &pkt6->destination_address,
1535 &pkt6->source_address,
1536 &pkt6->destination_address,
1538 mlen - sizeof (struct GNUNET_TUN_IPv6Header));
1543 struct GNUNET_TUN_IPv4Header *pkt4;
1545 if (mlen < sizeof (struct GNUNET_TUN_IPv4Header))
1551 pkt4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1552 get_destination_key_from_ip (AF_INET,
1553 &pkt4->destination_address,
1555 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1556 /* FIXME: do we need to guard against hash collision?
1557 (if so, we need to also store the local destination IP in the
1558 destination entry and then compare here; however, the risk
1559 of collision seems minimal AND the impact is unlikely to be
1560 super-problematic as well... */
1563 char buf[INET_ADDRSTRLEN];
1565 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1566 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1568 &pkt4->destination_address,
1573 if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header))
1575 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1576 _("Received IPv4 packet with options (dropping it)\n"));
1582 &pkt4->source_address,
1583 &pkt4->destination_address,
1585 mlen - sizeof (struct GNUNET_TUN_IPv4Header));
1589 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1590 _("Received packet of unknown protocol %d from TUN (dropping it)\n"),
1591 (unsigned int) ntohs (tun->proto));
1598 * Synthesize a plausible ICMP payload for an ICMP error
1599 * response on the given tunnel.
1601 * @param ts tunnel information
1602 * @param ipp IPv4 header to fill in (ICMP payload)
1603 * @param udp "UDP" header to fill in (ICMP payload); might actually
1604 * also be the first 8 bytes of the TCP header
1607 make_up_icmpv4_payload (struct TunnelState *ts,
1608 struct GNUNET_TUN_IPv4Header *ipp,
1609 struct GNUNET_TUN_UdpHeader *udp)
1611 GNUNET_TUN_initialize_ipv4_header (ipp,
1613 sizeof (struct GNUNET_TUN_TcpHeader),
1615 &ts->destination_ip.v4);
1616 udp->spt = htons (ts->source_port);
1617 udp->dpt = htons (ts->destination_port);
1618 udp->len = htons (0);
1619 udp->crc = htons (0);
1624 * Synthesize a plausible ICMP payload for an ICMP error
1625 * response on the given tunnel.
1627 * @param ts tunnel information
1628 * @param ipp IPv6 header to fill in (ICMP payload)
1629 * @param udp "UDP" header to fill in (ICMP payload); might actually
1630 * also be the first 8 bytes of the TCP header
1633 make_up_icmpv6_payload (struct TunnelState *ts,
1634 struct GNUNET_TUN_IPv6Header *ipp,
1635 struct GNUNET_TUN_UdpHeader *udp)
1637 GNUNET_TUN_initialize_ipv6_header (ipp,
1639 sizeof (struct GNUNET_TUN_TcpHeader),
1641 &ts->destination_ip.v6);
1642 udp->spt = htons (ts->source_port);
1643 udp->dpt = htons (ts->destination_port);
1644 udp->len = htons (0);
1645 udp->crc = htons (0);
1650 * We got an ICMP packet back from the MESH tunnel. Pass it on to the
1651 * local virtual interface via the helper.
1653 * @param cls closure, NULL
1654 * @param tunnel connection to the other end
1655 * @param tunnel_ctx pointer to our 'struct TunnelState *'
1656 * @param sender who sent the message
1657 * @param message the actual message
1658 * @param atsi performance data for the connection
1659 * @return GNUNET_OK to keep the connection open,
1660 * GNUNET_SYSERR to close it (signal serious error)
1663 receive_icmp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1664 void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender,
1665 const struct GNUNET_MessageHeader *message,
1666 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
1668 struct TunnelState *ts = *tunnel_ctx;
1669 const struct GNUNET_EXIT_IcmpToVPNMessage *i2v;
1672 GNUNET_STATISTICS_update (stats,
1673 gettext_noop ("# ICMP packets received from mesh"),
1675 mlen = ntohs (message->size);
1676 if (mlen < sizeof (struct GNUNET_EXIT_IcmpToVPNMessage))
1678 GNUNET_break_op (0);
1679 return GNUNET_SYSERR;
1681 if (NULL == ts->heap_node)
1683 GNUNET_break_op (0);
1684 return GNUNET_SYSERR;
1686 if (AF_UNSPEC == ts->af)
1688 GNUNET_break_op (0);
1689 return GNUNET_SYSERR;
1691 i2v = (const struct GNUNET_EXIT_IcmpToVPNMessage *) message;
1692 mlen -= sizeof (struct GNUNET_EXIT_IcmpToVPNMessage);
1694 char sbuf[INET6_ADDRSTRLEN];
1695 char dbuf[INET6_ADDRSTRLEN];
1697 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1698 "Received ICMP packet from mesh, sending %u bytes from %s -> %s via TUN\n",
1699 (unsigned int) mlen,
1700 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
1701 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)));
1707 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
1708 + sizeof (struct GNUNET_TUN_IcmpHeader)
1709 + sizeof (struct GNUNET_MessageHeader) +
1710 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1713 /* reserve some extra space in case we have an ICMP type here where
1714 we will need to make up the payload ourselves */
1715 char buf[size + sizeof (struct GNUNET_TUN_IPv4Header) + 8];
1716 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1717 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1718 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1719 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv4[1];
1720 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1721 tun->flags = htons (0);
1722 tun->proto = htons (ETH_P_IPV4);
1723 GNUNET_TUN_initialize_ipv4_header (ipv4,
1725 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1726 &ts->destination_ip.v4,
1728 *icmp = i2v->icmp_header;
1732 /* For some ICMP types, we need to adjust (make up) the payload here.
1733 Also, depending on the AF used on the other side, we have to
1734 do ICMP PT (translate ICMP types) */
1735 switch (ntohl (i2v->af))
1740 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1741 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1743 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1744 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1745 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1747 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1748 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1752 /* sender did not strip ICMP payload? */
1753 GNUNET_break_op (0);
1754 return GNUNET_SYSERR;
1756 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1757 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1758 make_up_icmpv4_payload (ts, ipp, udp);
1762 GNUNET_break_op (0);
1763 GNUNET_STATISTICS_update (stats,
1764 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1766 return GNUNET_SYSERR;
1771 /* ICMP PT 6-to-4 and possibly making up payloads */
1774 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1775 icmp->type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
1777 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1778 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1782 /* sender did not strip ICMP payload? */
1783 GNUNET_break_op (0);
1784 return GNUNET_SYSERR;
1786 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1787 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1788 make_up_icmpv4_payload (ts, ipp, udp);
1791 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1792 icmp->type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1794 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1795 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1799 /* sender did not strip ICMP payload? */
1800 GNUNET_break_op (0);
1801 return GNUNET_SYSERR;
1803 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1804 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1805 make_up_icmpv4_payload (ts, ipp, udp);
1808 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1809 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1810 GNUNET_STATISTICS_update (stats,
1811 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1814 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1815 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1817 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1818 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1821 GNUNET_break_op (0);
1822 GNUNET_STATISTICS_update (stats,
1823 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1825 return GNUNET_SYSERR;
1830 GNUNET_break_op (0);
1831 return GNUNET_SYSERR;
1833 msg->size = htons (size);
1834 GNUNET_TUN_calculate_icmp_checksum (icmp,
1837 (void) GNUNET_HELPER_send (helper_handle,
1846 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
1847 + sizeof (struct GNUNET_TUN_IcmpHeader)
1848 + sizeof (struct GNUNET_MessageHeader) +
1849 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1852 char buf[size + sizeof (struct GNUNET_TUN_IPv6Header) + 8];
1853 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1854 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1855 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
1856 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv6[1];
1857 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1858 tun->flags = htons (0);
1859 tun->proto = htons (ETH_P_IPV6);
1860 GNUNET_TUN_initialize_ipv6_header (ipv6,
1862 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1863 &ts->destination_ip.v6,
1865 *icmp = i2v->icmp_header;
1870 /* For some ICMP types, we need to adjust (make up) the payload here.
1871 Also, depending on the AF used on the other side, we have to
1872 do ICMP PT (translate ICMP types) */
1873 switch (ntohl (i2v->af))
1876 /* ICMP PT 4-to-6 and possibly making up payloads */
1879 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1880 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1882 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1883 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1885 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1886 icmp->type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1888 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1889 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1893 /* sender did not strip ICMP payload? */
1894 GNUNET_break_op (0);
1895 return GNUNET_SYSERR;
1897 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1898 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1899 make_up_icmpv6_payload (ts, ipp, udp);
1902 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1903 icmp->type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1905 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1906 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1910 /* sender did not strip ICMP payload? */
1911 GNUNET_break_op (0);
1912 return GNUNET_SYSERR;
1914 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1915 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1916 make_up_icmpv6_payload (ts, ipp, udp);
1919 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1920 GNUNET_STATISTICS_update (stats,
1921 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1925 GNUNET_break_op (0);
1926 GNUNET_STATISTICS_update (stats,
1927 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1929 return GNUNET_SYSERR;
1936 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1937 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1938 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1939 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1941 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1942 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1946 /* sender did not strip ICMP payload? */
1947 GNUNET_break_op (0);
1948 return GNUNET_SYSERR;
1950 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1951 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1952 make_up_icmpv6_payload (ts, ipp, udp);
1955 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1958 GNUNET_break_op (0);
1959 GNUNET_STATISTICS_update (stats,
1960 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1962 return GNUNET_SYSERR;
1967 GNUNET_break_op (0);
1968 return GNUNET_SYSERR;
1970 msg->size = htons (size);
1971 GNUNET_TUN_calculate_icmp_checksum (icmp,
1973 (void) GNUNET_HELPER_send (helper_handle,
1983 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
1985 GNUNET_TIME_absolute_get ().abs_value);
1991 * We got a UDP packet back from the MESH tunnel. Pass it on to the
1992 * local virtual interface via the helper.
1994 * @param cls closure, NULL
1995 * @param tunnel connection to the other end
1996 * @param tunnel_ctx pointer to our 'struct TunnelState *'
1997 * @param sender who sent the message
1998 * @param message the actual message
1999 * @param atsi performance data for the connection
2000 * @return GNUNET_OK to keep the connection open,
2001 * GNUNET_SYSERR to close it (signal serious error)
2004 receive_udp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
2005 void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender,
2006 const struct GNUNET_MessageHeader *message,
2007 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
2009 struct TunnelState *ts = *tunnel_ctx;
2010 const struct GNUNET_EXIT_UdpReplyMessage *reply;
2013 GNUNET_STATISTICS_update (stats,
2014 gettext_noop ("# UDP packets received from mesh"),
2016 mlen = ntohs (message->size);
2017 if (mlen < sizeof (struct GNUNET_EXIT_UdpReplyMessage))
2019 GNUNET_break_op (0);
2020 return GNUNET_SYSERR;
2022 if (NULL == ts->heap_node)
2024 GNUNET_break_op (0);
2025 return GNUNET_SYSERR;
2027 if (AF_UNSPEC == ts->af)
2029 GNUNET_break_op (0);
2030 return GNUNET_SYSERR;
2032 reply = (const struct GNUNET_EXIT_UdpReplyMessage *) message;
2033 mlen -= sizeof (struct GNUNET_EXIT_UdpReplyMessage);
2035 char sbuf[INET6_ADDRSTRLEN];
2036 char dbuf[INET6_ADDRSTRLEN];
2038 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2039 "Received UDP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2040 (unsigned int) mlen,
2041 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2042 ts->destination_port,
2043 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2050 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2051 + sizeof (struct GNUNET_TUN_UdpHeader)
2052 + sizeof (struct GNUNET_MessageHeader) +
2053 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2057 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2058 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2059 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2060 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1];
2061 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2062 msg->size = htons (size);
2063 tun->flags = htons (0);
2064 tun->proto = htons (ETH_P_IPV4);
2065 GNUNET_TUN_initialize_ipv4_header (ipv4,
2067 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2068 &ts->destination_ip.v4,
2070 if (0 == ntohs (reply->source_port))
2071 udp->spt = htons (ts->destination_port);
2073 udp->spt = reply->source_port;
2074 if (0 == ntohs (reply->destination_port))
2075 udp->dpt = htons (ts->source_port);
2077 udp->dpt = reply->destination_port;
2078 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2079 GNUNET_TUN_calculate_udp4_checksum (ipv4,
2086 (void) GNUNET_HELPER_send (helper_handle,
2095 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2096 + sizeof (struct GNUNET_TUN_UdpHeader)
2097 + sizeof (struct GNUNET_MessageHeader) +
2098 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2102 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2103 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2104 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2105 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1];
2106 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2107 msg->size = htons (size);
2108 tun->flags = htons (0);
2109 tun->proto = htons (ETH_P_IPV6);
2110 GNUNET_TUN_initialize_ipv6_header (ipv6,
2112 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2113 &ts->destination_ip.v6,
2115 if (0 == ntohs (reply->source_port))
2116 udp->spt = htons (ts->destination_port);
2118 udp->spt = reply->source_port;
2119 if (0 == ntohs (reply->destination_port))
2120 udp->dpt = htons (ts->source_port);
2122 udp->dpt = reply->destination_port;
2123 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2124 GNUNET_TUN_calculate_udp6_checksum (ipv6,
2130 (void) GNUNET_HELPER_send (helper_handle,
2140 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2142 GNUNET_TIME_absolute_get ().abs_value);
2148 * We got a TCP packet back from the MESH tunnel. Pass it on to the
2149 * local virtual interface via the helper.
2151 * @param cls closure, NULL
2152 * @param tunnel connection to the other end
2153 * @param tunnel_ctx pointer to our 'struct TunnelState *'
2154 * @param sender who sent the message
2155 * @param message the actual message
2156 * @param atsi performance data for the connection
2157 * @return GNUNET_OK to keep the connection open,
2158 * GNUNET_SYSERR to close it (signal serious error)
2161 receive_tcp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
2163 const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED,
2164 const struct GNUNET_MessageHeader *message,
2165 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
2167 struct TunnelState *ts = *tunnel_ctx;
2168 const struct GNUNET_EXIT_TcpDataMessage *data;
2171 GNUNET_STATISTICS_update (stats,
2172 gettext_noop ("# TCP packets received from mesh"),
2174 mlen = ntohs (message->size);
2175 if (mlen < sizeof (struct GNUNET_EXIT_TcpDataMessage))
2177 GNUNET_break_op (0);
2178 return GNUNET_SYSERR;
2180 if (NULL == ts->heap_node)
2182 GNUNET_break_op (0);
2183 return GNUNET_SYSERR;
2185 data = (const struct GNUNET_EXIT_TcpDataMessage *) message;
2186 mlen -= sizeof (struct GNUNET_EXIT_TcpDataMessage);
2188 char sbuf[INET6_ADDRSTRLEN];
2189 char dbuf[INET6_ADDRSTRLEN];
2191 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2192 "Received TCP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2193 (unsigned int) mlen,
2194 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2195 ts->destination_port,
2196 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2203 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2204 + sizeof (struct GNUNET_TUN_TcpHeader)
2205 + sizeof (struct GNUNET_MessageHeader) +
2206 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2210 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2211 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2212 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2213 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv4[1];
2214 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2215 msg->size = htons (size);
2216 tun->flags = htons (0);
2217 tun->proto = htons (ETH_P_IPV4);
2218 GNUNET_TUN_initialize_ipv4_header (ipv4,
2220 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2221 &ts->destination_ip.v4,
2223 *tcp = data->tcp_header;
2224 tcp->spt = htons (ts->destination_port);
2225 tcp->dpt = htons (ts->source_port);
2226 GNUNET_TUN_calculate_tcp4_checksum (ipv4,
2233 (void) GNUNET_HELPER_send (helper_handle,
2242 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2243 + sizeof (struct GNUNET_TUN_TcpHeader)
2244 + sizeof (struct GNUNET_MessageHeader) +
2245 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2249 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2250 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2251 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2252 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv6[1];
2253 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2254 msg->size = htons (size);
2255 tun->flags = htons (0);
2256 tun->proto = htons (ETH_P_IPV6);
2257 GNUNET_TUN_initialize_ipv6_header (ipv6,
2259 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2260 &ts->destination_ip.v6,
2262 tcp->spt = htons (ts->destination_port);
2263 tcp->dpt = htons (ts->source_port);
2264 GNUNET_TUN_calculate_tcp6_checksum (ipv6,
2268 (void) GNUNET_HELPER_send (helper_handle,
2276 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2278 GNUNET_TIME_absolute_get ().abs_value);
2284 * Allocate an IPv4 address from the range of the tunnel
2285 * for a new redirection.
2287 * @param v4 where to store the address
2288 * @return GNUNET_OK on success,
2289 * GNUNET_SYSERR on error
2292 allocate_v4_address (struct in_addr *v4)
2294 const char *ipv4addr = vpn_argv[4];
2295 const char *ipv4mask = vpn_argv[5];
2296 struct in_addr addr;
2297 struct in_addr mask;
2299 GNUNET_HashCode key;
2302 GNUNET_assert (1 == inet_pton (AF_INET, ipv4addr, &addr));
2303 GNUNET_assert (1 == inet_pton (AF_INET, ipv4mask, &mask));
2304 /* Given 192.168.0.1/255.255.0.0, we want a mask
2305 of '192.168.255.255', thus: */
2306 mask.s_addr = addr.s_addr | ~mask.s_addr;
2313 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2314 _("Failed to find unallocated IPv4 address in VPN's range\n"));
2315 return GNUNET_SYSERR;
2317 /* Pick random IPv4 address within the subnet, except 'addr' or 'mask' itself */
2318 rnd.s_addr = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2320 v4->s_addr = (addr.s_addr | rnd.s_addr) & mask.s_addr;
2321 get_destination_key_from_ip (AF_INET,
2325 while ( (GNUNET_YES ==
2326 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2328 (v4->s_addr == addr.s_addr) ||
2329 (v4->s_addr == mask.s_addr) );
2335 * Allocate an IPv6 address from the range of the tunnel
2336 * for a new redirection.
2338 * @param v6 where to store the address
2339 * @return GNUNET_OK on success,
2340 * GNUNET_SYSERR on error
2343 allocate_v6_address (struct in6_addr *v6)
2345 const char *ipv6addr = vpn_argv[2];
2346 struct in6_addr addr;
2347 struct in6_addr mask;
2348 struct in6_addr rnd;
2350 GNUNET_HashCode key;
2353 GNUNET_assert (1 == inet_pton (AF_INET6, ipv6addr, &addr));
2354 GNUNET_assert (ipv6prefix < 128);
2355 /* Given ABCD::/96, we want a mask of 'ABCD::FFFF:FFFF,
2358 for (i=127;i>=128-ipv6prefix;i--)
2359 mask.s6_addr[i / 8] |= (1 << (i % 8));
2361 /* Pick random IPv6 address within the subnet, except 'addr' or 'mask' itself */
2368 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2369 _("Failed to find unallocated IPv6 address in VPN's range\n"));
2370 return GNUNET_SYSERR;
2375 rnd.s6_addr[i] = (unsigned char) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2378 = (addr.s6_addr[i] | rnd.s6_addr[i]) & mask.s6_addr[i];
2380 get_destination_key_from_ip (AF_INET6,
2384 while ( (GNUNET_YES ==
2385 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2389 sizeof (struct in6_addr))) ||
2392 sizeof (struct in6_addr))) );
2398 * Free resources occupied by a destination entry.
2400 * @param de entry to free
2403 free_destination_entry (struct DestinationEntry *de)
2405 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2406 "Cleaning up destination entry\n");
2407 GNUNET_STATISTICS_update (stats,
2408 gettext_noop ("# Active destinations"),
2412 free_tunnel_state (de->ts);
2413 GNUNET_assert (NULL == de->ts);
2415 if (NULL != de->heap_node)
2417 GNUNET_CONTAINER_heap_remove_node (de->heap_node);
2418 de->heap_node = NULL;
2419 GNUNET_assert (GNUNET_YES ==
2420 GNUNET_CONTAINER_multihashmap_remove (destination_map,
2429 * We have too many active destinations. Clean up the oldest destination.
2431 * @param except destination that must NOT be cleaned up, even if it is the oldest
2434 expire_destination (struct DestinationEntry *except)
2436 struct DestinationEntry *de;
2438 de = GNUNET_CONTAINER_heap_peek (destination_heap);
2440 return; /* can't do this */
2441 free_destination_entry (de);
2446 * A client asks us to setup a redirection via some exit
2447 * node to a particular IP. Setup the redirection and
2448 * give the client the allocated IP.
2451 * @param client requesting client
2452 * @param message redirection request (a 'struct RedirectToIpRequestMessage')
2455 service_redirect_to_ip (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
2456 const struct GNUNET_MessageHeader *message)
2460 const struct RedirectToIpRequestMessage *msg;
2466 struct DestinationEntry *de;
2467 GNUNET_HashCode key;
2468 struct TunnelState *ts;
2470 /* validate and parse request */
2471 mlen = ntohs (message->size);
2472 if (mlen < sizeof (struct RedirectToIpRequestMessage))
2475 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2478 alen = mlen - sizeof (struct RedirectToIpRequestMessage);
2479 msg = (const struct RedirectToIpRequestMessage *) message;
2480 addr_af = (int) htonl (msg->addr_af);
2484 if (alen != sizeof (struct in_addr))
2487 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2492 if (alen != sizeof (struct in6_addr))
2495 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2501 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2505 /* allocate response IP */
2507 result_af = (int) htonl (msg->result_af);
2512 allocate_v4_address (&v4))
2513 result_af = AF_UNSPEC;
2519 allocate_v6_address (&v6))
2520 result_af = AF_UNSPEC;
2526 allocate_v4_address (&v4))
2529 result_af = AF_INET;
2531 else if (GNUNET_OK ==
2532 allocate_v6_address (&v6))
2535 result_af = AF_INET6;
2540 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2543 if ( (result_af == AF_UNSPEC) ||
2544 (GNUNET_NO == ntohl (msg->nac)) )
2546 /* send reply "instantly" */
2547 send_client_reply (client,
2552 if (result_af == AF_UNSPEC)
2554 /* failure, we're done */
2555 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2560 char sbuf[INET6_ADDRSTRLEN];
2561 char dbuf[INET6_ADDRSTRLEN];
2563 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2564 "Allocated address %s for redirection via exit to %s\n",
2565 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2567 &msg[1], dbuf, sizeof (dbuf)));
2570 /* setup destination record */
2571 de = GNUNET_malloc (sizeof (struct DestinationEntry));
2572 de->is_service = GNUNET_NO;
2573 de->details.exit_destination.af = addr_af;
2574 memcpy (&de->details.exit_destination.ip,
2577 get_destination_key_from_ip (result_af,
2581 GNUNET_assert (GNUNET_OK ==
2582 GNUNET_CONTAINER_multihashmap_put (destination_map,
2585 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2586 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2588 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
2589 GNUNET_STATISTICS_update (stats,
2590 gettext_noop ("# Active destinations"),
2592 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2593 expire_destination (de);
2595 /* setup tunnel to destination */
2596 ts = create_tunnel_to_destination (de,
2597 (GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
2603 ts->destination_ip.v4 = v4;
2606 ts->destination_ip.v6 = v6;
2612 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2617 * A client asks us to setup a redirection to a particular peer
2618 * offering a service. Setup the redirection and give the client the
2622 * @param client requesting client
2623 * @param message redirection request (a 'struct RedirectToPeerRequestMessage')
2626 service_redirect_to_service (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
2627 const struct GNUNET_MessageHeader *message)
2629 const struct RedirectToServiceRequestMessage *msg;
2634 struct DestinationEntry *de;
2635 GNUNET_HashCode key;
2636 struct TunnelState *ts;
2639 msg = (const struct RedirectToServiceRequestMessage *) message;
2641 /* allocate response IP */
2643 result_af = (int) htonl (msg->result_af);
2648 allocate_v4_address (&v4))
2649 result_af = AF_UNSPEC;
2655 allocate_v6_address (&v6))
2656 result_af = AF_UNSPEC;
2662 allocate_v4_address (&v4))
2665 result_af = AF_INET;
2667 else if (GNUNET_OK ==
2668 allocate_v6_address (&v6))
2671 result_af = AF_INET6;
2676 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2679 if ( (result_af == AF_UNSPEC) ||
2680 (GNUNET_NO == ntohl (msg->nac)) )
2682 /* send reply "instantly" */
2683 send_client_reply (client,
2688 if (result_af == AF_UNSPEC)
2690 /* failure, we're done */
2691 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2692 _("Failed to allocate IP address for new destination\n"));
2693 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2698 char sbuf[INET6_ADDRSTRLEN];
2700 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2701 "Allocated address %s for redirection to service %s on peer %s\n",
2702 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2703 GNUNET_h2s (&msg->service_descriptor),
2704 GNUNET_i2s (&msg->target));
2707 /* setup destination record */
2708 de = GNUNET_malloc (sizeof (struct DestinationEntry));
2709 de->is_service = GNUNET_YES;
2710 de->details.service_destination.service_descriptor = msg->service_descriptor;
2711 de->details.service_destination.target = msg->target;
2712 get_destination_key_from_ip (result_af,
2716 GNUNET_assert (GNUNET_OK ==
2717 GNUNET_CONTAINER_multihashmap_put (destination_map,
2720 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2721 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2723 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
2724 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2725 expire_destination (de);
2726 ts = create_tunnel_to_destination (de,
2727 (GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
2733 ts->destination_ip.v4 = v4;
2736 ts->destination_ip.v6 = v6;
2742 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2748 * Function called for inbound tunnels. As we don't offer
2749 * any mesh services, this function should never be called.
2751 * @param cls closure
2752 * @param tunnel new handle to the tunnel
2753 * @param initiator peer that started the tunnel
2754 * @param atsi performance information for the tunnel
2755 * @return initial tunnel context for the tunnel
2756 * (can be NULL -- that's not an error)
2759 inbound_tunnel_cb (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
2760 const struct GNUNET_PeerIdentity *initiator,
2761 const struct GNUNET_ATS_Information *atsi)
2763 /* How can and why should anyone open an inbound tunnel to vpn? */
2770 * Function called whenever an inbound tunnel is destroyed. Should clean up
2771 * any associated state.
2773 * @param cls closure (set from GNUNET_MESH_connect)
2774 * @param tunnel connection to the other end (henceforth invalid)
2775 * @param tunnel_ctx place where local state associated
2776 * with the tunnel is stored (our 'struct TunnelState')
2779 tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel_ctx)
2781 /* we don't have inbound tunnels, so this function should never be called */
2787 * Free memory occupied by an entry in the destination map.
2791 * @param value a 'struct DestinationEntry *'
2792 * @return GNUNET_OK (continue to iterate)
2795 cleanup_destination (void *cls,
2796 const GNUNET_HashCode *key,
2799 struct DestinationEntry *de = value;
2801 free_destination_entry (de);
2807 * Free memory occupied by an entry in the tunnel map.
2811 * @param value a 'struct TunnelState *'
2812 * @return GNUNET_OK (continue to iterate)
2815 cleanup_tunnel (void *cls,
2816 const GNUNET_HashCode *key,
2819 struct TunnelState *ts = value;
2821 free_tunnel_state (ts);
2827 * Function scheduled as very last function, cleans up after us
2833 cleanup (void *cls GNUNET_UNUSED,
2834 const struct GNUNET_SCHEDULER_TaskContext *tc)
2838 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2839 "VPN is shutting down\n");
2840 if (NULL != destination_map)
2842 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
2843 &cleanup_destination,
2845 GNUNET_CONTAINER_multihashmap_destroy (destination_map);
2846 destination_map = NULL;
2848 if (NULL != destination_heap)
2850 GNUNET_CONTAINER_heap_destroy (destination_heap);
2851 destination_heap = NULL;
2853 if (NULL != tunnel_map)
2855 GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
2858 GNUNET_CONTAINER_multihashmap_destroy (tunnel_map);
2861 if (NULL != tunnel_heap)
2863 GNUNET_CONTAINER_heap_destroy (tunnel_heap);
2866 if (NULL != mesh_handle)
2868 GNUNET_MESH_disconnect (mesh_handle);
2871 if (NULL != helper_handle)
2873 GNUNET_HELPER_stop (helper_handle);
2874 helper_handle = NULL;
2878 GNUNET_SERVER_notification_context_destroy (nc);
2883 GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
2887 GNUNET_free_non_null (vpn_argv[i]);
2892 * A client disconnected, clean up all references to it.
2894 * @param cls the client that disconnected
2896 * @param value a 'struct TunnelState *'
2897 * @return GNUNET_OK (continue to iterate)
2900 cleanup_tunnel_client (void *cls,
2901 const GNUNET_HashCode *key,
2904 struct GNUNET_SERVER_Client *client = cls;
2905 struct TunnelState *ts = value;
2907 if (client == ts->client)
2909 GNUNET_SERVER_client_drop (ts->client);
2917 * A client disconnected, clean up all references to it.
2919 * @param cls the client that disconnected
2921 * @param value a 'struct DestinationEntry *'
2922 * @return GNUNET_OK (continue to iterate)
2925 cleanup_destination_client (void *cls,
2926 const GNUNET_HashCode *key,
2929 struct GNUNET_SERVER_Client *client = cls;
2930 struct DestinationEntry *de = value;
2931 struct TunnelState *ts;
2933 if (NULL == (ts = de->ts))
2935 if (client == ts->client)
2937 GNUNET_SERVER_client_drop (ts->client);
2945 * A client has disconnected from us. If we are currently building
2946 * a tunnel for it, cancel the operation.
2949 * @param client handle to the client that disconnected
2952 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
2954 if (NULL != tunnel_map)
2955 GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
2956 &cleanup_tunnel_client,
2958 if (NULL != destination_map)
2959 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
2960 &cleanup_destination_client,
2966 * Main function that will be run by the scheduler.
2968 * @param cls closure
2969 * @param server the initialized server
2970 * @param cfg_ configuration
2974 struct GNUNET_SERVER_Handle *server,
2975 const struct GNUNET_CONFIGURATION_Handle *cfg_)
2977 static const struct GNUNET_SERVER_MessageHandler service_handlers[] = {
2978 /* callback, cls, type, size */
2979 { &service_redirect_to_ip, NULL, GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP, 0},
2980 { &service_redirect_to_service, NULL,
2981 GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE,
2982 sizeof (struct RedirectToServiceRequestMessage) },
2985 static const struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
2986 { &receive_udp_back, GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY, 0},
2987 { &receive_tcp_back, GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN, 0},
2988 { &receive_icmp_back, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN, 0},
2991 static const GNUNET_MESH_ApplicationType types[] = {
2992 GNUNET_APPLICATION_TYPE_END
3003 stats = GNUNET_STATISTICS_create ("vpn", cfg);
3005 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_MAPPING",
3006 &max_destination_mappings))
3007 max_destination_mappings = 200;
3009 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_TUNNELS",
3010 &max_tunnel_mappings))
3011 max_tunnel_mappings = 200;
3013 destination_map = GNUNET_CONTAINER_multihashmap_create (max_destination_mappings * 2);
3014 destination_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3015 tunnel_map = GNUNET_CONTAINER_multihashmap_create (max_tunnel_mappings * 2);
3016 tunnel_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3019 vpn_argv[0] = GNUNET_strdup ("vpn-gnunet");
3020 if (GNUNET_SYSERR ==
3021 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IFNAME", &ifname))
3023 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3024 "No entry 'IFNAME' in configuration!\n");
3025 GNUNET_SCHEDULER_shutdown ();
3028 vpn_argv[1] = ifname;
3029 if ( (GNUNET_SYSERR ==
3030 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6ADDR",
3032 (1 != inet_pton (AF_INET6, ipv6addr, &v6))) )
3034 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3035 "No valid entry 'IPV6ADDR' in configuration!\n");
3036 GNUNET_SCHEDULER_shutdown ();
3039 vpn_argv[2] = ipv6addr;
3040 if (GNUNET_SYSERR ==
3041 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6PREFIX",
3044 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3045 "No entry 'IPV6PREFIX' in configuration!\n");
3046 GNUNET_SCHEDULER_shutdown ();
3049 vpn_argv[3] = ipv6prefix_s;
3051 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn",
3054 (ipv6prefix >= 127) )
3056 GNUNET_SCHEDULER_shutdown ();
3060 if ( (GNUNET_SYSERR ==
3061 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4ADDR",
3063 (1 != inet_pton (AF_INET, ipv4addr, &v4))) )
3065 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3066 "No valid entry for 'IPV4ADDR' in configuration!\n");
3067 GNUNET_SCHEDULER_shutdown ();
3070 vpn_argv[4] = ipv4addr;
3071 if ( (GNUNET_SYSERR ==
3072 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4MASK",
3074 (1 != inet_pton (AF_INET, ipv4mask, &v4))) )
3076 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3077 "No valid entry 'IPV4MASK' in configuration!\n");
3078 GNUNET_SCHEDULER_shutdown ();
3081 vpn_argv[5] = ipv4mask;
3085 GNUNET_MESH_connect (cfg_, 42 /* queue length */, NULL,
3090 helper_handle = GNUNET_HELPER_start ("gnunet-helper-vpn", vpn_argv,
3091 &message_token, NULL);
3092 nc = GNUNET_SERVER_notification_context_create (server, 1);
3093 GNUNET_SERVER_add_handlers (server, service_handlers);
3094 GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
3095 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls);
3100 * The main function of the VPN service.
3102 * @param argc number of arguments from the command line
3103 * @param argv command line arguments
3104 * @return 0 ok, 1 on error
3107 main (int argc, char *const *argv)
3109 return (GNUNET_OK ==
3110 GNUNET_SERVICE_run (argc, argv, "vpn",
3111 GNUNET_SERVICE_OPTION_NONE,
3112 &run, NULL)) ? 0 : 1;
3115 /* end of gnunet-service-vpn.c */