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);
842 GNUNET_assert (NULL != ts);
844 return; /* can't do this */
845 free_tunnel_state (ts);
850 * Route a packet via mesh to the given destination.
852 * @param destination description of the destination
853 * @param af address family on this end (AF_INET or AF_INET6)
854 * @param protocol IPPROTO_TCP or IPPROTO_UDP
855 * @param source_ip source IP used by the sender (struct in_addr or struct in6_addr)
856 * @param destination_ip destination IP used by the sender (struct in_addr or struct in6_addr)
857 * @param payload payload of the packet after the IP header
858 * @param payload_length number of bytes in payload
861 route_packet (struct DestinationEntry *destination,
864 const void *source_ip,
865 const void *destination_ip,
867 size_t payload_length)
870 struct TunnelState *ts;
871 struct TunnelMessageQueueEntry *tnq;
875 const struct GNUNET_TUN_UdpHeader *udp;
876 const struct GNUNET_TUN_TcpHeader *tcp;
877 const struct GNUNET_TUN_IcmpHeader *icmp;
885 if (payload_length < sizeof (struct GNUNET_TUN_UdpHeader))
892 spt = ntohs (udp->spt);
893 dpt = ntohs (udp->dpt);
894 get_tunnel_key_from_ips (af,
905 if (payload_length < sizeof (struct GNUNET_TUN_TcpHeader))
912 spt = ntohs (tcp->spt);
913 dpt = ntohs (tcp->dpt);
914 get_tunnel_key_from_ips (af,
925 if (payload_length < sizeof (struct GNUNET_TUN_IcmpHeader))
934 get_tunnel_key_from_ips (af,
944 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
945 _("Protocol %u not supported, dropping\n"),
946 (unsigned int) protocol);
949 if (! destination->is_service)
951 switch (destination->details.exit_destination.af)
954 alen = sizeof (struct in_addr);
957 alen = sizeof (struct in6_addr);
965 char sbuf[INET6_ADDRSTRLEN];
966 char dbuf[INET6_ADDRSTRLEN];
967 char xbuf[INET6_ADDRSTRLEN];
969 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
970 "Routing %s packet from %s:%u -> %s:%u to destination %s:%u\n",
971 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
972 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
974 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
976 inet_ntop (destination->details.exit_destination.af,
977 &destination->details.exit_destination.ip,
978 xbuf, sizeof (xbuf)),
984 /* make compiler happy */
987 char sbuf[INET6_ADDRSTRLEN];
988 char dbuf[INET6_ADDRSTRLEN];
990 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
991 "Routing %s packet from %s:%u -> %s:%u to service %s at peer %s\n",
992 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
993 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
995 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
997 GNUNET_h2s (&destination->details.service_destination.service_descriptor),
998 GNUNET_i2s (&destination->details.service_destination.target));
1003 /* see if we have an existing tunnel for this destination */
1004 ts = GNUNET_CONTAINER_multihashmap_get (tunnel_map,
1008 /* need to either use the existing tunnel from the destination (if still
1009 available) or create a fresh one */
1010 is_new = GNUNET_YES;
1011 if (NULL == destination->ts)
1012 ts = create_tunnel_to_destination (destination, NULL, af, 0);
1014 ts = destination->ts;
1017 destination->ts = NULL;
1018 ts->destination_container = NULL; /* no longer 'contained' */
1019 /* now bind existing "unbound" tunnel to our IP/port tuple */
1020 ts->protocol = protocol;
1024 ts->source_ip.v4 = * (const struct in_addr *) source_ip;
1025 ts->destination_ip.v4 = * (const struct in_addr *) destination_ip;
1029 ts->source_ip.v6 = * (const struct in6_addr *) source_ip;
1030 ts->destination_ip.v6 = * (const struct in6_addr *) destination_ip;
1032 ts->source_port = spt;
1033 ts->destination_port = dpt;
1034 ts->heap_node = GNUNET_CONTAINER_heap_insert (tunnel_heap,
1036 GNUNET_TIME_absolute_get ().abs_value);
1037 GNUNET_assert (GNUNET_YES ==
1038 GNUNET_CONTAINER_multihashmap_put (tunnel_map,
1041 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1042 GNUNET_STATISTICS_update (stats,
1043 gettext_noop ("# Active tunnels"),
1045 while (GNUNET_CONTAINER_multihashmap_size (tunnel_map) > max_tunnel_mappings)
1051 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
1053 GNUNET_TIME_absolute_get ().abs_value);
1055 GNUNET_assert (NULL != ts->tunnel);
1057 /* send via tunnel */
1061 if (destination->is_service)
1063 struct GNUNET_EXIT_UdpServiceMessage *usm;
1065 mlen = sizeof (struct GNUNET_EXIT_UdpServiceMessage) +
1066 payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1067 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1072 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1075 usm = (struct GNUNET_EXIT_UdpServiceMessage *) &tnq[1];
1076 usm->header.size = htons ((uint16_t) mlen);
1077 usm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE);
1078 /* if the source port is below 32000, we assume it has a special
1079 meaning; if not, we pick a random port (this is a heuristic) */
1080 usm->source_port = (ntohs (udp->spt) < 32000) ? udp->spt : 0;
1081 usm->destination_port = udp->dpt;
1082 usm->service_descriptor = destination->details.service_destination.service_descriptor;
1085 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1089 struct GNUNET_EXIT_UdpInternetMessage *uim;
1090 struct in_addr *ip4dst;
1091 struct in6_addr *ip6dst;
1094 mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) +
1095 alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1096 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1101 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) +
1105 uim = (struct GNUNET_EXIT_UdpInternetMessage *) &tnq[1];
1106 uim->header.size = htons ((uint16_t) mlen);
1107 uim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET);
1108 uim->af = htonl (destination->details.exit_destination.af);
1109 uim->source_port = (ntohs (udp->spt) < 32000) ? udp->spt : 0;
1110 uim->destination_port = udp->dpt;
1111 switch (destination->details.exit_destination.af)
1114 ip4dst = (struct in_addr *) &uim[1];
1115 *ip4dst = destination->details.exit_destination.ip.v4;
1116 payload = &ip4dst[1];
1119 ip6dst = (struct in6_addr *) &uim[1];
1120 *ip6dst = destination->details.exit_destination.ip.v6;
1121 payload = &ip6dst[1];
1128 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1134 if (destination->is_service)
1136 struct GNUNET_EXIT_TcpServiceStartMessage *tsm;
1138 mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) +
1139 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1140 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1145 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1148 tsm = (struct GNUNET_EXIT_TcpServiceStartMessage *) &tnq[1];
1149 tsm->header.size = htons ((uint16_t) mlen);
1150 tsm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START);
1151 tsm->reserved = htonl (0);
1152 tsm->service_descriptor = destination->details.service_destination.service_descriptor;
1153 tsm->tcp_header = *tcp;
1156 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1160 struct GNUNET_EXIT_TcpInternetStartMessage *tim;
1161 struct in_addr *ip4dst;
1162 struct in6_addr *ip6dst;
1165 mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) +
1166 alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1167 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1172 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1175 tim = (struct GNUNET_EXIT_TcpInternetStartMessage *) &tnq[1];
1176 tim->header.size = htons ((uint16_t) mlen);
1177 tim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START);
1178 tim->af = htonl (destination->details.exit_destination.af);
1179 tim->tcp_header = *tcp;
1180 switch (destination->details.exit_destination.af)
1183 ip4dst = (struct in_addr *) &tim[1];
1184 *ip4dst = destination->details.exit_destination.ip.v4;
1185 payload = &ip4dst[1];
1188 ip6dst = (struct in6_addr *) &tim[1];
1189 *ip6dst = destination->details.exit_destination.ip.v6;
1190 payload = &ip6dst[1];
1197 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1202 struct GNUNET_EXIT_TcpDataMessage *tdm;
1204 mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) +
1205 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1206 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1211 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1214 tdm = (struct GNUNET_EXIT_TcpDataMessage *) &tnq[1];
1215 tdm->header.size = htons ((uint16_t) mlen);
1216 tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT);
1217 tdm->reserved = htonl (0);
1218 tdm->tcp_header = *tcp;
1221 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1225 if (destination->is_service)
1227 struct GNUNET_EXIT_IcmpServiceMessage *ism;
1229 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1230 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1231 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1236 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1238 ism = (struct GNUNET_EXIT_IcmpServiceMessage *) &tnq[1];
1239 ism->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE);
1240 ism->af = htonl (af); /* need to tell destination ICMP protocol family! */
1241 ism->service_descriptor = destination->details.service_destination.service_descriptor;
1242 ism->icmp_header = *icmp;
1243 /* ICMP protocol translation will be done by the receiver (as we don't know
1244 the target AF); however, we still need to possibly discard the payload
1245 depending on the ICMP type */
1251 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1252 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1254 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1255 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1256 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1257 /* throw away ICMP payload, won't be useful for the other side anyway */
1258 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1261 GNUNET_STATISTICS_update (stats,
1262 gettext_noop ("# ICMPv4 packets dropped (not allowed)"),
1266 /* end of AF_INET */
1271 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1272 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1273 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1274 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1275 /* throw away ICMP payload, won't be useful for the other side anyway */
1276 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1278 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1279 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1282 GNUNET_STATISTICS_update (stats,
1283 gettext_noop ("# ICMPv6 packets dropped (not allowed)"),
1287 /* end of AF_INET6 */
1294 /* update length calculations, as payload_length may have changed */
1295 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1296 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1298 ism->header.size = htons ((uint16_t) mlen);
1299 /* finally, copy payload (if there is any left...) */
1302 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1306 struct GNUNET_EXIT_IcmpInternetMessage *iim;
1307 struct in_addr *ip4dst;
1308 struct in6_addr *ip6dst;
1311 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1312 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1313 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1318 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) +
1321 iim = (struct GNUNET_EXIT_IcmpInternetMessage *) &tnq[1];
1322 iim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET);
1323 iim->icmp_header = *icmp;
1324 /* Perform ICMP protocol-translation (depending on destination AF and source AF)
1325 and throw away ICMP payload depending on ICMP message type */
1331 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1332 if (destination->details.exit_destination.af == AF_INET6)
1333 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1335 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1336 if (destination->details.exit_destination.af == AF_INET6)
1337 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1339 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1340 if (destination->details.exit_destination.af == AF_INET6)
1341 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1342 /* throw away IP-payload, exit will have to make it up anyway */
1343 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1345 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1346 if (destination->details.exit_destination.af == AF_INET6)
1347 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1348 /* throw away IP-payload, exit will have to make it up anyway */
1349 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1351 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1352 if (destination->details.exit_destination.af == AF_INET6)
1354 GNUNET_STATISTICS_update (stats,
1355 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1360 /* throw away IP-payload, exit will have to make it up anyway */
1361 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1364 GNUNET_STATISTICS_update (stats,
1365 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1370 /* end of AF_INET */
1375 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1376 if (destination->details.exit_destination.af == AF_INET6)
1377 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1378 /* throw away IP-payload, exit will have to make it up anyway */
1379 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1381 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1382 if (destination->details.exit_destination.af == AF_INET)
1383 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1384 /* throw away IP-payload, exit will have to make it up anyway */
1385 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1387 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1388 if (destination->details.exit_destination.af == AF_INET)
1390 GNUNET_STATISTICS_update (stats,
1391 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1396 /* throw away IP-payload, exit will have to make it up anyway */
1397 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1399 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1400 if (destination->details.exit_destination.af == AF_INET)
1402 GNUNET_STATISTICS_update (stats,
1403 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1408 /* throw away IP-payload, exit will have to make it up anyway */
1409 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1411 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1412 if (destination->details.exit_destination.af == AF_INET)
1413 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1415 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1416 if (destination->details.exit_destination.af == AF_INET)
1417 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1420 GNUNET_STATISTICS_update (stats,
1421 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1426 /* end of AF_INET6 */
1431 /* update length calculations, as payload_length may have changed */
1432 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1433 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1435 iim->header.size = htons ((uint16_t) mlen);
1437 /* need to tell destination ICMP protocol family! */
1438 iim->af = htonl (destination->details.exit_destination.af);
1439 switch (destination->details.exit_destination.af)
1442 ip4dst = (struct in_addr *) &iim[1];
1443 *ip4dst = destination->details.exit_destination.ip.v4;
1444 payload = &ip4dst[1];
1447 ip6dst = (struct in6_addr *) &iim[1];
1448 *ip6dst = destination->details.exit_destination.ip.v6;
1449 payload = &ip6dst[1];
1456 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1460 /* not supported above, how can we get here !? */
1464 send_to_tunnel (tnq, ts);
1469 * Receive packets from the helper-process (someone send to the local
1470 * virtual tunnel interface). Find the destination mapping, and if it
1471 * exists, identify the correct MESH tunnel (or possibly create it)
1472 * and forward the packet.
1474 * @param cls closure, NULL
1475 * @param client NULL
1476 * @param message message we got from the client (VPN tunnel interface)
1479 message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED,
1480 const struct GNUNET_MessageHeader *message)
1482 const struct GNUNET_TUN_Layer2PacketHeader *tun;
1484 GNUNET_HashCode key;
1485 struct DestinationEntry *de;
1487 GNUNET_STATISTICS_update (stats,
1488 gettext_noop ("# Packets received from TUN interface"),
1490 mlen = ntohs (message->size);
1491 if ( (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
1492 (mlen < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader)) )
1497 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1498 mlen -= (sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader));
1499 switch (ntohs (tun->proto))
1503 const struct GNUNET_TUN_IPv6Header *pkt6;
1505 if (mlen < sizeof (struct GNUNET_TUN_IPv6Header))
1511 pkt6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1512 get_destination_key_from_ip (AF_INET6,
1513 &pkt6->destination_address,
1515 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1516 /* FIXME: do we need to guard against hash collision?
1517 (if so, we need to also store the local destination IP in the
1518 destination entry and then compare here; however, the risk
1519 of collision seems minimal AND the impact is unlikely to be
1520 super-problematic as well... */
1523 char buf[INET6_ADDRSTRLEN];
1525 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1526 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1527 inet_ntop (AF_INET6,
1528 &pkt6->destination_address,
1536 &pkt6->source_address,
1537 &pkt6->destination_address,
1539 mlen - sizeof (struct GNUNET_TUN_IPv6Header));
1544 struct GNUNET_TUN_IPv4Header *pkt4;
1546 if (mlen < sizeof (struct GNUNET_TUN_IPv4Header))
1552 pkt4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1553 get_destination_key_from_ip (AF_INET,
1554 &pkt4->destination_address,
1556 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1557 /* FIXME: do we need to guard against hash collision?
1558 (if so, we need to also store the local destination IP in the
1559 destination entry and then compare here; however, the risk
1560 of collision seems minimal AND the impact is unlikely to be
1561 super-problematic as well... */
1564 char buf[INET_ADDRSTRLEN];
1566 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1567 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1569 &pkt4->destination_address,
1574 if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header))
1576 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1577 _("Received IPv4 packet with options (dropping it)\n"));
1583 &pkt4->source_address,
1584 &pkt4->destination_address,
1586 mlen - sizeof (struct GNUNET_TUN_IPv4Header));
1590 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1591 _("Received packet of unknown protocol %d from TUN (dropping it)\n"),
1592 (unsigned int) ntohs (tun->proto));
1599 * Synthesize a plausible ICMP payload for an ICMP error
1600 * response on the given tunnel.
1602 * @param ts tunnel information
1603 * @param ipp IPv4 header to fill in (ICMP payload)
1604 * @param udp "UDP" header to fill in (ICMP payload); might actually
1605 * also be the first 8 bytes of the TCP header
1608 make_up_icmpv4_payload (struct TunnelState *ts,
1609 struct GNUNET_TUN_IPv4Header *ipp,
1610 struct GNUNET_TUN_UdpHeader *udp)
1612 GNUNET_TUN_initialize_ipv4_header (ipp,
1614 sizeof (struct GNUNET_TUN_TcpHeader),
1616 &ts->destination_ip.v4);
1617 udp->spt = htons (ts->source_port);
1618 udp->dpt = htons (ts->destination_port);
1619 udp->len = htons (0);
1620 udp->crc = htons (0);
1625 * Synthesize a plausible ICMP payload for an ICMP error
1626 * response on the given tunnel.
1628 * @param ts tunnel information
1629 * @param ipp IPv6 header to fill in (ICMP payload)
1630 * @param udp "UDP" header to fill in (ICMP payload); might actually
1631 * also be the first 8 bytes of the TCP header
1634 make_up_icmpv6_payload (struct TunnelState *ts,
1635 struct GNUNET_TUN_IPv6Header *ipp,
1636 struct GNUNET_TUN_UdpHeader *udp)
1638 GNUNET_TUN_initialize_ipv6_header (ipp,
1640 sizeof (struct GNUNET_TUN_TcpHeader),
1642 &ts->destination_ip.v6);
1643 udp->spt = htons (ts->source_port);
1644 udp->dpt = htons (ts->destination_port);
1645 udp->len = htons (0);
1646 udp->crc = htons (0);
1651 * We got an ICMP packet back from the MESH tunnel. Pass it on to the
1652 * local virtual interface via the helper.
1654 * @param cls closure, NULL
1655 * @param tunnel connection to the other end
1656 * @param tunnel_ctx pointer to our 'struct TunnelState *'
1657 * @param sender who sent the message
1658 * @param message the actual message
1659 * @param atsi performance data for the connection
1660 * @return GNUNET_OK to keep the connection open,
1661 * GNUNET_SYSERR to close it (signal serious error)
1664 receive_icmp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1665 void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender,
1666 const struct GNUNET_MessageHeader *message,
1667 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
1669 struct TunnelState *ts = *tunnel_ctx;
1670 const struct GNUNET_EXIT_IcmpToVPNMessage *i2v;
1673 GNUNET_STATISTICS_update (stats,
1674 gettext_noop ("# ICMP packets received from mesh"),
1676 mlen = ntohs (message->size);
1677 if (mlen < sizeof (struct GNUNET_EXIT_IcmpToVPNMessage))
1679 GNUNET_break_op (0);
1680 return GNUNET_SYSERR;
1682 if (NULL == ts->heap_node)
1684 GNUNET_break_op (0);
1685 return GNUNET_SYSERR;
1687 if (AF_UNSPEC == ts->af)
1689 GNUNET_break_op (0);
1690 return GNUNET_SYSERR;
1692 i2v = (const struct GNUNET_EXIT_IcmpToVPNMessage *) message;
1693 mlen -= sizeof (struct GNUNET_EXIT_IcmpToVPNMessage);
1695 char sbuf[INET6_ADDRSTRLEN];
1696 char dbuf[INET6_ADDRSTRLEN];
1698 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1699 "Received ICMP packet from mesh, sending %u bytes from %s -> %s via TUN\n",
1700 (unsigned int) mlen,
1701 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
1702 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)));
1708 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
1709 + sizeof (struct GNUNET_TUN_IcmpHeader)
1710 + sizeof (struct GNUNET_MessageHeader) +
1711 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1714 /* reserve some extra space in case we have an ICMP type here where
1715 we will need to make up the payload ourselves */
1716 char buf[size + sizeof (struct GNUNET_TUN_IPv4Header) + 8];
1717 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1718 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1719 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1720 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv4[1];
1721 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1722 tun->flags = htons (0);
1723 tun->proto = htons (ETH_P_IPV4);
1724 GNUNET_TUN_initialize_ipv4_header (ipv4,
1726 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1727 &ts->destination_ip.v4,
1729 *icmp = i2v->icmp_header;
1733 /* For some ICMP types, we need to adjust (make up) the payload here.
1734 Also, depending on the AF used on the other side, we have to
1735 do ICMP PT (translate ICMP types) */
1736 switch (ntohl (i2v->af))
1741 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1742 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1744 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1745 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1746 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1748 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1749 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1753 /* sender did not strip ICMP payload? */
1754 GNUNET_break_op (0);
1755 return GNUNET_SYSERR;
1757 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1758 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1759 make_up_icmpv4_payload (ts, ipp, udp);
1763 GNUNET_break_op (0);
1764 GNUNET_STATISTICS_update (stats,
1765 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1767 return GNUNET_SYSERR;
1772 /* ICMP PT 6-to-4 and possibly making up payloads */
1775 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1776 icmp->type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
1778 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1779 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1783 /* sender did not strip ICMP payload? */
1784 GNUNET_break_op (0);
1785 return GNUNET_SYSERR;
1787 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1788 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1789 make_up_icmpv4_payload (ts, ipp, udp);
1792 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1793 icmp->type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1795 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1796 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1800 /* sender did not strip ICMP payload? */
1801 GNUNET_break_op (0);
1802 return GNUNET_SYSERR;
1804 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1805 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1806 make_up_icmpv4_payload (ts, ipp, udp);
1809 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1810 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1811 GNUNET_STATISTICS_update (stats,
1812 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1815 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1816 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1818 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1819 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1822 GNUNET_break_op (0);
1823 GNUNET_STATISTICS_update (stats,
1824 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1826 return GNUNET_SYSERR;
1831 GNUNET_break_op (0);
1832 return GNUNET_SYSERR;
1834 msg->size = htons (size);
1835 GNUNET_TUN_calculate_icmp_checksum (icmp,
1838 (void) GNUNET_HELPER_send (helper_handle,
1847 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
1848 + sizeof (struct GNUNET_TUN_IcmpHeader)
1849 + sizeof (struct GNUNET_MessageHeader) +
1850 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1853 char buf[size + sizeof (struct GNUNET_TUN_IPv6Header) + 8];
1854 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1855 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1856 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
1857 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv6[1];
1858 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1859 tun->flags = htons (0);
1860 tun->proto = htons (ETH_P_IPV6);
1861 GNUNET_TUN_initialize_ipv6_header (ipv6,
1863 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1864 &ts->destination_ip.v6,
1866 *icmp = i2v->icmp_header;
1871 /* For some ICMP types, we need to adjust (make up) the payload here.
1872 Also, depending on the AF used on the other side, we have to
1873 do ICMP PT (translate ICMP types) */
1874 switch (ntohl (i2v->af))
1877 /* ICMP PT 4-to-6 and possibly making up payloads */
1880 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1881 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1883 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1884 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1886 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1887 icmp->type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1889 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1890 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1894 /* sender did not strip ICMP payload? */
1895 GNUNET_break_op (0);
1896 return GNUNET_SYSERR;
1898 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1899 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1900 make_up_icmpv6_payload (ts, ipp, udp);
1903 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1904 icmp->type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1906 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1907 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1911 /* sender did not strip ICMP payload? */
1912 GNUNET_break_op (0);
1913 return GNUNET_SYSERR;
1915 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1916 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1917 make_up_icmpv6_payload (ts, ipp, udp);
1920 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1921 GNUNET_STATISTICS_update (stats,
1922 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1926 GNUNET_break_op (0);
1927 GNUNET_STATISTICS_update (stats,
1928 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1930 return GNUNET_SYSERR;
1937 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1938 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1939 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1940 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1942 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1943 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1947 /* sender did not strip ICMP payload? */
1948 GNUNET_break_op (0);
1949 return GNUNET_SYSERR;
1951 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1952 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1953 make_up_icmpv6_payload (ts, ipp, udp);
1956 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1959 GNUNET_break_op (0);
1960 GNUNET_STATISTICS_update (stats,
1961 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1963 return GNUNET_SYSERR;
1968 GNUNET_break_op (0);
1969 return GNUNET_SYSERR;
1971 msg->size = htons (size);
1972 GNUNET_TUN_calculate_icmp_checksum (icmp,
1974 (void) GNUNET_HELPER_send (helper_handle,
1984 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
1986 GNUNET_TIME_absolute_get ().abs_value);
1992 * We got a UDP packet back from the MESH tunnel. Pass it on to the
1993 * local virtual interface via the helper.
1995 * @param cls closure, NULL
1996 * @param tunnel connection to the other end
1997 * @param tunnel_ctx pointer to our 'struct TunnelState *'
1998 * @param sender who sent the message
1999 * @param message the actual message
2000 * @param atsi performance data for the connection
2001 * @return GNUNET_OK to keep the connection open,
2002 * GNUNET_SYSERR to close it (signal serious error)
2005 receive_udp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
2006 void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender,
2007 const struct GNUNET_MessageHeader *message,
2008 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
2010 struct TunnelState *ts = *tunnel_ctx;
2011 const struct GNUNET_EXIT_UdpReplyMessage *reply;
2014 GNUNET_STATISTICS_update (stats,
2015 gettext_noop ("# UDP packets received from mesh"),
2017 mlen = ntohs (message->size);
2018 if (mlen < sizeof (struct GNUNET_EXIT_UdpReplyMessage))
2020 GNUNET_break_op (0);
2021 return GNUNET_SYSERR;
2023 if (NULL == ts->heap_node)
2025 GNUNET_break_op (0);
2026 return GNUNET_SYSERR;
2028 if (AF_UNSPEC == ts->af)
2030 GNUNET_break_op (0);
2031 return GNUNET_SYSERR;
2033 reply = (const struct GNUNET_EXIT_UdpReplyMessage *) message;
2034 mlen -= sizeof (struct GNUNET_EXIT_UdpReplyMessage);
2036 char sbuf[INET6_ADDRSTRLEN];
2037 char dbuf[INET6_ADDRSTRLEN];
2039 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2040 "Received UDP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2041 (unsigned int) mlen,
2042 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2043 ts->destination_port,
2044 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2051 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2052 + sizeof (struct GNUNET_TUN_UdpHeader)
2053 + sizeof (struct GNUNET_MessageHeader) +
2054 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2058 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2059 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2060 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2061 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1];
2062 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2063 msg->size = htons (size);
2064 tun->flags = htons (0);
2065 tun->proto = htons (ETH_P_IPV4);
2066 GNUNET_TUN_initialize_ipv4_header (ipv4,
2068 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2069 &ts->destination_ip.v4,
2071 if (0 == ntohs (reply->source_port))
2072 udp->spt = htons (ts->destination_port);
2074 udp->spt = reply->source_port;
2075 if (0 == ntohs (reply->destination_port))
2076 udp->dpt = htons (ts->source_port);
2078 udp->dpt = reply->destination_port;
2079 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2080 GNUNET_TUN_calculate_udp4_checksum (ipv4,
2087 (void) GNUNET_HELPER_send (helper_handle,
2096 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2097 + sizeof (struct GNUNET_TUN_UdpHeader)
2098 + sizeof (struct GNUNET_MessageHeader) +
2099 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2103 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2104 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2105 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2106 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1];
2107 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2108 msg->size = htons (size);
2109 tun->flags = htons (0);
2110 tun->proto = htons (ETH_P_IPV6);
2111 GNUNET_TUN_initialize_ipv6_header (ipv6,
2113 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2114 &ts->destination_ip.v6,
2116 if (0 == ntohs (reply->source_port))
2117 udp->spt = htons (ts->destination_port);
2119 udp->spt = reply->source_port;
2120 if (0 == ntohs (reply->destination_port))
2121 udp->dpt = htons (ts->source_port);
2123 udp->dpt = reply->destination_port;
2124 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2125 GNUNET_TUN_calculate_udp6_checksum (ipv6,
2131 (void) GNUNET_HELPER_send (helper_handle,
2141 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2143 GNUNET_TIME_absolute_get ().abs_value);
2149 * We got a TCP packet back from the MESH tunnel. Pass it on to the
2150 * local virtual interface via the helper.
2152 * @param cls closure, NULL
2153 * @param tunnel connection to the other end
2154 * @param tunnel_ctx pointer to our 'struct TunnelState *'
2155 * @param sender who sent the message
2156 * @param message the actual message
2157 * @param atsi performance data for the connection
2158 * @return GNUNET_OK to keep the connection open,
2159 * GNUNET_SYSERR to close it (signal serious error)
2162 receive_tcp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
2164 const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED,
2165 const struct GNUNET_MessageHeader *message,
2166 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
2168 struct TunnelState *ts = *tunnel_ctx;
2169 const struct GNUNET_EXIT_TcpDataMessage *data;
2172 GNUNET_STATISTICS_update (stats,
2173 gettext_noop ("# TCP packets received from mesh"),
2175 mlen = ntohs (message->size);
2176 if (mlen < sizeof (struct GNUNET_EXIT_TcpDataMessage))
2178 GNUNET_break_op (0);
2179 return GNUNET_SYSERR;
2181 if (NULL == ts->heap_node)
2183 GNUNET_break_op (0);
2184 return GNUNET_SYSERR;
2186 data = (const struct GNUNET_EXIT_TcpDataMessage *) message;
2187 mlen -= sizeof (struct GNUNET_EXIT_TcpDataMessage);
2189 char sbuf[INET6_ADDRSTRLEN];
2190 char dbuf[INET6_ADDRSTRLEN];
2192 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2193 "Received TCP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2194 (unsigned int) mlen,
2195 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2196 ts->destination_port,
2197 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2204 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2205 + sizeof (struct GNUNET_TUN_TcpHeader)
2206 + sizeof (struct GNUNET_MessageHeader) +
2207 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2211 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2212 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2213 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2214 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv4[1];
2215 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2216 msg->size = htons (size);
2217 tun->flags = htons (0);
2218 tun->proto = htons (ETH_P_IPV4);
2219 GNUNET_TUN_initialize_ipv4_header (ipv4,
2221 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2222 &ts->destination_ip.v4,
2224 *tcp = data->tcp_header;
2225 tcp->spt = htons (ts->destination_port);
2226 tcp->dpt = htons (ts->source_port);
2227 GNUNET_TUN_calculate_tcp4_checksum (ipv4,
2234 (void) GNUNET_HELPER_send (helper_handle,
2243 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2244 + sizeof (struct GNUNET_TUN_TcpHeader)
2245 + sizeof (struct GNUNET_MessageHeader) +
2246 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2250 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2251 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2252 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2253 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv6[1];
2254 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2255 msg->size = htons (size);
2256 tun->flags = htons (0);
2257 tun->proto = htons (ETH_P_IPV6);
2258 GNUNET_TUN_initialize_ipv6_header (ipv6,
2260 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2261 &ts->destination_ip.v6,
2263 tcp->spt = htons (ts->destination_port);
2264 tcp->dpt = htons (ts->source_port);
2265 GNUNET_TUN_calculate_tcp6_checksum (ipv6,
2269 (void) GNUNET_HELPER_send (helper_handle,
2277 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2279 GNUNET_TIME_absolute_get ().abs_value);
2285 * Allocate an IPv4 address from the range of the tunnel
2286 * for a new redirection.
2288 * @param v4 where to store the address
2289 * @return GNUNET_OK on success,
2290 * GNUNET_SYSERR on error
2293 allocate_v4_address (struct in_addr *v4)
2295 const char *ipv4addr = vpn_argv[4];
2296 const char *ipv4mask = vpn_argv[5];
2297 struct in_addr addr;
2298 struct in_addr mask;
2300 GNUNET_HashCode key;
2303 GNUNET_assert (1 == inet_pton (AF_INET, ipv4addr, &addr));
2304 GNUNET_assert (1 == inet_pton (AF_INET, ipv4mask, &mask));
2305 /* Given 192.168.0.1/255.255.0.0, we want a mask
2306 of '192.168.255.255', thus: */
2307 mask.s_addr = addr.s_addr | ~mask.s_addr;
2314 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2315 _("Failed to find unallocated IPv4 address in VPN's range\n"));
2316 return GNUNET_SYSERR;
2318 /* Pick random IPv4 address within the subnet, except 'addr' or 'mask' itself */
2319 rnd.s_addr = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2321 v4->s_addr = (addr.s_addr | rnd.s_addr) & mask.s_addr;
2322 get_destination_key_from_ip (AF_INET,
2326 while ( (GNUNET_YES ==
2327 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2329 (v4->s_addr == addr.s_addr) ||
2330 (v4->s_addr == mask.s_addr) );
2336 * Allocate an IPv6 address from the range of the tunnel
2337 * for a new redirection.
2339 * @param v6 where to store the address
2340 * @return GNUNET_OK on success,
2341 * GNUNET_SYSERR on error
2344 allocate_v6_address (struct in6_addr *v6)
2346 const char *ipv6addr = vpn_argv[2];
2347 struct in6_addr addr;
2348 struct in6_addr mask;
2349 struct in6_addr rnd;
2351 GNUNET_HashCode key;
2354 GNUNET_assert (1 == inet_pton (AF_INET6, ipv6addr, &addr));
2355 GNUNET_assert (ipv6prefix < 128);
2356 /* Given ABCD::/96, we want a mask of 'ABCD::FFFF:FFFF,
2359 for (i=127;i>=128-ipv6prefix;i--)
2360 mask.s6_addr[i / 8] |= (1 << (i % 8));
2362 /* Pick random IPv6 address within the subnet, except 'addr' or 'mask' itself */
2369 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2370 _("Failed to find unallocated IPv6 address in VPN's range\n"));
2371 return GNUNET_SYSERR;
2376 rnd.s6_addr[i] = (unsigned char) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2379 = (addr.s6_addr[i] | rnd.s6_addr[i]) & mask.s6_addr[i];
2381 get_destination_key_from_ip (AF_INET6,
2385 while ( (GNUNET_YES ==
2386 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2390 sizeof (struct in6_addr))) ||
2393 sizeof (struct in6_addr))) );
2399 * Free resources occupied by a destination entry.
2401 * @param de entry to free
2404 free_destination_entry (struct DestinationEntry *de)
2406 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2407 "Cleaning up destination entry\n");
2408 GNUNET_STATISTICS_update (stats,
2409 gettext_noop ("# Active destinations"),
2413 free_tunnel_state (de->ts);
2414 GNUNET_assert (NULL == de->ts);
2416 if (NULL != de->heap_node)
2418 GNUNET_CONTAINER_heap_remove_node (de->heap_node);
2419 de->heap_node = NULL;
2420 GNUNET_assert (GNUNET_YES ==
2421 GNUNET_CONTAINER_multihashmap_remove (destination_map,
2430 * We have too many active destinations. Clean up the oldest destination.
2432 * @param except destination that must NOT be cleaned up, even if it is the oldest
2435 expire_destination (struct DestinationEntry *except)
2437 struct DestinationEntry *de;
2439 de = GNUNET_CONTAINER_heap_peek (destination_heap);
2440 GNUNET_assert (NULL != de);
2442 return; /* can't do this */
2443 free_destination_entry (de);
2448 * A client asks us to setup a redirection via some exit
2449 * node to a particular IP. Setup the redirection and
2450 * give the client the allocated IP.
2453 * @param client requesting client
2454 * @param message redirection request (a 'struct RedirectToIpRequestMessage')
2457 service_redirect_to_ip (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
2458 const struct GNUNET_MessageHeader *message)
2462 const struct RedirectToIpRequestMessage *msg;
2468 struct DestinationEntry *de;
2469 GNUNET_HashCode key;
2470 struct TunnelState *ts;
2472 /* validate and parse request */
2473 mlen = ntohs (message->size);
2474 if (mlen < sizeof (struct RedirectToIpRequestMessage))
2477 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2480 alen = mlen - sizeof (struct RedirectToIpRequestMessage);
2481 msg = (const struct RedirectToIpRequestMessage *) message;
2482 addr_af = (int) htonl (msg->addr_af);
2486 if (alen != sizeof (struct in_addr))
2489 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2494 if (alen != sizeof (struct in6_addr))
2497 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2503 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2507 /* allocate response IP */
2509 result_af = (int) htonl (msg->result_af);
2514 allocate_v4_address (&v4))
2515 result_af = AF_UNSPEC;
2521 allocate_v6_address (&v6))
2522 result_af = AF_UNSPEC;
2528 allocate_v4_address (&v4))
2531 result_af = AF_INET;
2533 else if (GNUNET_OK ==
2534 allocate_v6_address (&v6))
2537 result_af = AF_INET6;
2542 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2545 if ( (result_af == AF_UNSPEC) ||
2546 (GNUNET_NO == ntohl (msg->nac)) )
2548 /* send reply "instantly" */
2549 send_client_reply (client,
2554 if (result_af == AF_UNSPEC)
2556 /* failure, we're done */
2557 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2562 char sbuf[INET6_ADDRSTRLEN];
2563 char dbuf[INET6_ADDRSTRLEN];
2565 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2566 "Allocated address %s for redirection via exit to %s\n",
2567 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2569 &msg[1], dbuf, sizeof (dbuf)));
2572 /* setup destination record */
2573 de = GNUNET_malloc (sizeof (struct DestinationEntry));
2574 de->is_service = GNUNET_NO;
2575 de->details.exit_destination.af = addr_af;
2576 memcpy (&de->details.exit_destination.ip,
2579 get_destination_key_from_ip (result_af,
2583 GNUNET_assert (GNUNET_OK ==
2584 GNUNET_CONTAINER_multihashmap_put (destination_map,
2587 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2588 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2590 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
2591 GNUNET_STATISTICS_update (stats,
2592 gettext_noop ("# Active destinations"),
2594 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2595 expire_destination (de);
2597 /* setup tunnel to destination */
2598 ts = create_tunnel_to_destination (de,
2599 (GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
2605 ts->destination_ip.v4 = v4;
2608 ts->destination_ip.v6 = v6;
2614 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2619 * A client asks us to setup a redirection to a particular peer
2620 * offering a service. Setup the redirection and give the client the
2624 * @param client requesting client
2625 * @param message redirection request (a 'struct RedirectToPeerRequestMessage')
2628 service_redirect_to_service (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
2629 const struct GNUNET_MessageHeader *message)
2631 const struct RedirectToServiceRequestMessage *msg;
2636 struct DestinationEntry *de;
2637 GNUNET_HashCode key;
2638 struct TunnelState *ts;
2641 msg = (const struct RedirectToServiceRequestMessage *) message;
2643 /* allocate response IP */
2645 result_af = (int) htonl (msg->result_af);
2650 allocate_v4_address (&v4))
2651 result_af = AF_UNSPEC;
2657 allocate_v6_address (&v6))
2658 result_af = AF_UNSPEC;
2664 allocate_v4_address (&v4))
2667 result_af = AF_INET;
2669 else if (GNUNET_OK ==
2670 allocate_v6_address (&v6))
2673 result_af = AF_INET6;
2678 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2681 if ( (result_af == AF_UNSPEC) ||
2682 (GNUNET_NO == ntohl (msg->nac)) )
2684 /* send reply "instantly" */
2685 send_client_reply (client,
2690 if (result_af == AF_UNSPEC)
2692 /* failure, we're done */
2693 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2694 _("Failed to allocate IP address for new destination\n"));
2695 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2700 char sbuf[INET6_ADDRSTRLEN];
2702 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2703 "Allocated address %s for redirection to service %s on peer %s\n",
2704 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2705 GNUNET_h2s (&msg->service_descriptor),
2706 GNUNET_i2s (&msg->target));
2709 /* setup destination record */
2710 de = GNUNET_malloc (sizeof (struct DestinationEntry));
2711 de->is_service = GNUNET_YES;
2712 de->details.service_destination.service_descriptor = msg->service_descriptor;
2713 de->details.service_destination.target = msg->target;
2714 get_destination_key_from_ip (result_af,
2718 GNUNET_assert (GNUNET_OK ==
2719 GNUNET_CONTAINER_multihashmap_put (destination_map,
2722 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2723 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2725 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
2726 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2727 expire_destination (de);
2728 ts = create_tunnel_to_destination (de,
2729 (GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
2735 ts->destination_ip.v4 = v4;
2738 ts->destination_ip.v6 = v6;
2744 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2750 * Function called for inbound tunnels. As we don't offer
2751 * any mesh services, this function should never be called.
2753 * @param cls closure
2754 * @param tunnel new handle to the tunnel
2755 * @param initiator peer that started the tunnel
2756 * @param atsi performance information for the tunnel
2757 * @return initial tunnel context for the tunnel
2758 * (can be NULL -- that's not an error)
2761 inbound_tunnel_cb (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
2762 const struct GNUNET_PeerIdentity *initiator,
2763 const struct GNUNET_ATS_Information *atsi)
2765 /* How can and why should anyone open an inbound tunnel to vpn? */
2772 * Function called whenever an inbound tunnel is destroyed. Should clean up
2773 * any associated state.
2775 * @param cls closure (set from GNUNET_MESH_connect)
2776 * @param tunnel connection to the other end (henceforth invalid)
2777 * @param tunnel_ctx place where local state associated
2778 * with the tunnel is stored (our 'struct TunnelState')
2781 tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel_ctx)
2783 /* we don't have inbound tunnels, so this function should never be called */
2789 * Free memory occupied by an entry in the destination map.
2793 * @param value a 'struct DestinationEntry *'
2794 * @return GNUNET_OK (continue to iterate)
2797 cleanup_destination (void *cls,
2798 const GNUNET_HashCode *key,
2801 struct DestinationEntry *de = value;
2803 free_destination_entry (de);
2809 * Free memory occupied by an entry in the tunnel map.
2813 * @param value a 'struct TunnelState *'
2814 * @return GNUNET_OK (continue to iterate)
2817 cleanup_tunnel (void *cls,
2818 const GNUNET_HashCode *key,
2821 struct TunnelState *ts = value;
2823 free_tunnel_state (ts);
2829 * Function scheduled as very last function, cleans up after us
2835 cleanup (void *cls GNUNET_UNUSED,
2836 const struct GNUNET_SCHEDULER_TaskContext *tc)
2840 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2841 "VPN is shutting down\n");
2842 if (NULL != destination_map)
2844 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
2845 &cleanup_destination,
2847 GNUNET_CONTAINER_multihashmap_destroy (destination_map);
2848 destination_map = NULL;
2850 if (NULL != destination_heap)
2852 GNUNET_CONTAINER_heap_destroy (destination_heap);
2853 destination_heap = NULL;
2855 if (NULL != tunnel_map)
2857 GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
2860 GNUNET_CONTAINER_multihashmap_destroy (tunnel_map);
2863 if (NULL != tunnel_heap)
2865 GNUNET_CONTAINER_heap_destroy (tunnel_heap);
2868 if (NULL != mesh_handle)
2870 GNUNET_MESH_disconnect (mesh_handle);
2873 if (NULL != helper_handle)
2875 GNUNET_HELPER_stop (helper_handle);
2876 helper_handle = NULL;
2880 GNUNET_SERVER_notification_context_destroy (nc);
2885 GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
2889 GNUNET_free_non_null (vpn_argv[i]);
2894 * A client disconnected, clean up all references to it.
2896 * @param cls the client that disconnected
2898 * @param value a 'struct TunnelState *'
2899 * @return GNUNET_OK (continue to iterate)
2902 cleanup_tunnel_client (void *cls,
2903 const GNUNET_HashCode *key,
2906 struct GNUNET_SERVER_Client *client = cls;
2907 struct TunnelState *ts = value;
2909 if (client == ts->client)
2911 GNUNET_SERVER_client_drop (ts->client);
2919 * A client disconnected, clean up all references to it.
2921 * @param cls the client that disconnected
2923 * @param value a 'struct DestinationEntry *'
2924 * @return GNUNET_OK (continue to iterate)
2927 cleanup_destination_client (void *cls,
2928 const GNUNET_HashCode *key,
2931 struct GNUNET_SERVER_Client *client = cls;
2932 struct DestinationEntry *de = value;
2933 struct TunnelState *ts;
2935 if (NULL == (ts = de->ts))
2937 if (client == ts->client)
2939 GNUNET_SERVER_client_drop (ts->client);
2947 * A client has disconnected from us. If we are currently building
2948 * a tunnel for it, cancel the operation.
2951 * @param client handle to the client that disconnected
2954 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
2956 if (NULL != tunnel_map)
2957 GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
2958 &cleanup_tunnel_client,
2960 if (NULL != destination_map)
2961 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
2962 &cleanup_destination_client,
2968 * Main function that will be run by the scheduler.
2970 * @param cls closure
2971 * @param server the initialized server
2972 * @param cfg_ configuration
2976 struct GNUNET_SERVER_Handle *server,
2977 const struct GNUNET_CONFIGURATION_Handle *cfg_)
2979 static const struct GNUNET_SERVER_MessageHandler service_handlers[] = {
2980 /* callback, cls, type, size */
2981 { &service_redirect_to_ip, NULL, GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP, 0},
2982 { &service_redirect_to_service, NULL,
2983 GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE,
2984 sizeof (struct RedirectToServiceRequestMessage) },
2987 static const struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
2988 { &receive_udp_back, GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY, 0},
2989 { &receive_tcp_back, GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN, 0},
2990 { &receive_icmp_back, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN, 0},
2993 static const GNUNET_MESH_ApplicationType types[] = {
2994 GNUNET_APPLICATION_TYPE_END
3005 stats = GNUNET_STATISTICS_create ("vpn", cfg);
3007 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_MAPPING",
3008 &max_destination_mappings))
3009 max_destination_mappings = 200;
3011 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_TUNNELS",
3012 &max_tunnel_mappings))
3013 max_tunnel_mappings = 200;
3015 destination_map = GNUNET_CONTAINER_multihashmap_create (max_destination_mappings * 2);
3016 destination_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3017 tunnel_map = GNUNET_CONTAINER_multihashmap_create (max_tunnel_mappings * 2);
3018 tunnel_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3021 vpn_argv[0] = GNUNET_strdup ("vpn-gnunet");
3022 if (GNUNET_SYSERR ==
3023 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IFNAME", &ifname))
3025 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3026 "No entry 'IFNAME' in configuration!\n");
3027 GNUNET_SCHEDULER_shutdown ();
3030 vpn_argv[1] = ifname;
3031 if ( (GNUNET_SYSERR ==
3032 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6ADDR",
3034 (1 != inet_pton (AF_INET6, ipv6addr, &v6))) )
3036 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3037 "No valid entry 'IPV6ADDR' in configuration!\n");
3038 GNUNET_SCHEDULER_shutdown ();
3041 vpn_argv[2] = ipv6addr;
3042 if (GNUNET_SYSERR ==
3043 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6PREFIX",
3046 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3047 "No entry 'IPV6PREFIX' in configuration!\n");
3048 GNUNET_SCHEDULER_shutdown ();
3051 vpn_argv[3] = ipv6prefix_s;
3053 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn",
3056 (ipv6prefix >= 127) )
3058 GNUNET_SCHEDULER_shutdown ();
3062 if ( (GNUNET_SYSERR ==
3063 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4ADDR",
3065 (1 != inet_pton (AF_INET, ipv4addr, &v4))) )
3067 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3068 "No valid entry for 'IPV4ADDR' in configuration!\n");
3069 GNUNET_SCHEDULER_shutdown ();
3072 vpn_argv[4] = ipv4addr;
3073 if ( (GNUNET_SYSERR ==
3074 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4MASK",
3076 (1 != inet_pton (AF_INET, ipv4mask, &v4))) )
3078 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3079 "No valid entry 'IPV4MASK' in configuration!\n");
3080 GNUNET_SCHEDULER_shutdown ();
3083 vpn_argv[5] = ipv4mask;
3087 GNUNET_MESH_connect (cfg_, 42 /* queue length */, NULL,
3092 helper_handle = GNUNET_HELPER_start ("gnunet-helper-vpn", vpn_argv,
3093 &message_token, NULL);
3094 nc = GNUNET_SERVER_notification_context_create (server, 1);
3095 GNUNET_SERVER_add_handlers (server, service_handlers);
3096 GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
3097 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls);
3102 * The main function of the VPN service.
3104 * @param argc number of arguments from the command line
3105 * @param argv command line arguments
3106 * @return 0 ok, 1 on error
3109 main (int argc, char *const *argv)
3111 return (GNUNET_OK ==
3112 GNUNET_SERVICE_run (argc, argv, "vpn",
3113 GNUNET_SERVICE_OPTION_NONE,
3114 &run, NULL)) ? 0 : 1;
3117 /* end of gnunet-service-vpn.c */