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,
762 struct TunnelState *ts;
764 GNUNET_STATISTICS_update (stats,
765 gettext_noop ("# Mesh tunnels created"),
767 GNUNET_assert (NULL == de->ts);
768 ts = GNUNET_malloc (sizeof (struct TunnelState));
771 ts->request_id = request_id;
773 GNUNET_SERVER_client_keep (client);
775 ts->destination = *de;
776 ts->destination.heap_node = NULL; /* copy is NOT in destination heap */
778 ts->destination_container = de; /* we are referenced from de */
779 ts->af = AF_UNSPEC; /* so far, unknown */
780 ts->tunnel = GNUNET_MESH_tunnel_create (mesh_handle,
782 &tunnel_peer_connect_handler,
783 &tunnel_peer_disconnect_handler,
785 if (NULL == ts->tunnel)
787 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
788 _("Failed to setup mesh tunnel!\n"));
790 GNUNET_SERVER_client_drop (client);
796 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
797 "Creating tunnel to peer %s offering service %s\n",
798 GNUNET_i2s (&de->details.service_destination.target),
799 GNUNET_h2s (&de->details.service_destination.service_descriptor));
800 GNUNET_MESH_peer_request_connect_add (ts->tunnel,
801 &de->details.service_destination.target);
805 switch (de->details.exit_destination.af)
808 GNUNET_MESH_peer_request_connect_by_type (ts->tunnel,
809 GNUNET_APPLICATION_TYPE_IPV4_GATEWAY);
810 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
811 "Creating tunnel to exit peer for %s\n",
815 GNUNET_MESH_peer_request_connect_by_type (ts->tunnel,
816 GNUNET_APPLICATION_TYPE_IPV6_GATEWAY);
817 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
818 "Creating tunnel to exit peer for %s\n",
831 * We have too many active tunnels. Clean up the oldest tunnel.
833 * @param except tunnel that must NOT be cleaned up, even if it is the oldest
836 expire_tunnel (struct TunnelState *except)
838 struct TunnelState *ts;
840 ts = GNUNET_CONTAINER_heap_peek (tunnel_heap);
842 return; /* can't do this */
843 free_tunnel_state (ts);
848 * Route a packet via mesh to the given destination.
850 * @param destination description of the destination
851 * @param af address family on this end (AF_INET or AF_INET6)
852 * @param protocol IPPROTO_TCP or IPPROTO_UDP
853 * @param source_ip source IP used by the sender (struct in_addr or struct in6_addr)
854 * @param destination_ip destination IP used by the sender (struct in_addr or struct in6_addr)
855 * @param payload payload of the packet after the IP header
856 * @param payload_length number of bytes in payload
859 route_packet (struct DestinationEntry *destination,
862 const void *source_ip,
863 const void *destination_ip,
865 size_t payload_length)
868 struct TunnelState *ts;
869 struct TunnelMessageQueueEntry *tnq;
873 const struct GNUNET_TUN_UdpHeader *udp;
874 const struct GNUNET_TUN_TcpHeader *tcp;
875 const struct GNUNET_TUN_IcmpHeader *icmp;
883 if (payload_length < sizeof (struct GNUNET_TUN_UdpHeader))
890 spt = ntohs (udp->spt);
891 dpt = ntohs (udp->dpt);
892 get_tunnel_key_from_ips (af,
903 if (payload_length < sizeof (struct GNUNET_TUN_TcpHeader))
910 spt = ntohs (tcp->spt);
911 dpt = ntohs (tcp->dpt);
912 get_tunnel_key_from_ips (af,
923 if (payload_length < sizeof (struct GNUNET_TUN_IcmpHeader))
932 get_tunnel_key_from_ips (af,
942 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
943 _("Protocol %u not supported, dropping\n"),
944 (unsigned int) protocol);
947 if (! destination->is_service)
949 switch (destination->details.exit_destination.af)
952 alen = sizeof (struct in_addr);
955 alen = sizeof (struct in6_addr);
963 char sbuf[INET6_ADDRSTRLEN];
964 char dbuf[INET6_ADDRSTRLEN];
965 char xbuf[INET6_ADDRSTRLEN];
967 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
968 "Routing %s packet from %s:%u -> %s:%u to destination %s:%u\n",
969 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
970 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
972 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
974 inet_ntop (destination->details.exit_destination.af,
975 &destination->details.exit_destination.ip,
976 xbuf, sizeof (xbuf)),
982 /* make compiler happy */
985 char sbuf[INET6_ADDRSTRLEN];
986 char dbuf[INET6_ADDRSTRLEN];
988 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
989 "Routing %s packet from %s:%u -> %s:%u to service %s at peer %s\n",
990 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
991 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
993 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
995 GNUNET_h2s (&destination->details.service_destination.service_descriptor),
996 GNUNET_i2s (&destination->details.service_destination.target));
1001 /* see if we have an existing tunnel for this destination */
1002 ts = GNUNET_CONTAINER_multihashmap_get (tunnel_map,
1006 /* need to either use the existing tunnel from the destination (if still
1007 available) or create a fresh one */
1008 is_new = GNUNET_YES;
1009 if (NULL == destination->ts)
1010 ts = create_tunnel_to_destination (destination, NULL, 0);
1012 ts = destination->ts;
1015 destination->ts = NULL;
1016 ts->destination_container = NULL; /* no longer 'contained' */
1017 /* now bind existing "unbound" tunnel to our IP/port tuple */
1018 ts->protocol = protocol;
1022 ts->source_ip.v4 = * (const struct in_addr *) source_ip;
1023 ts->destination_ip.v4 = * (const struct in_addr *) destination_ip;
1027 ts->source_ip.v6 = * (const struct in6_addr *) source_ip;
1028 ts->destination_ip.v6 = * (const struct in6_addr *) destination_ip;
1030 ts->source_port = spt;
1031 ts->destination_port = dpt;
1032 ts->heap_node = GNUNET_CONTAINER_heap_insert (tunnel_heap,
1034 GNUNET_TIME_absolute_get ().abs_value);
1035 GNUNET_assert (GNUNET_YES ==
1036 GNUNET_CONTAINER_multihashmap_put (tunnel_map,
1039 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1040 GNUNET_STATISTICS_update (stats,
1041 gettext_noop ("# Active tunnels"),
1043 while (GNUNET_CONTAINER_multihashmap_size (tunnel_map) > max_tunnel_mappings)
1049 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
1051 GNUNET_TIME_absolute_get ().abs_value);
1053 GNUNET_assert (NULL != ts->tunnel);
1055 /* send via tunnel */
1059 if (destination->is_service)
1061 struct GNUNET_EXIT_UdpServiceMessage *usm;
1063 mlen = sizeof (struct GNUNET_EXIT_UdpServiceMessage) +
1064 payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1065 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1070 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1073 usm = (struct GNUNET_EXIT_UdpServiceMessage *) &tnq[1];
1074 usm->header.size = htons ((uint16_t) mlen);
1075 usm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE);
1076 /* if the source port is below 32000, we assume it has a special
1077 meaning; if not, we pick a random port (this is a heuristic) */
1078 usm->source_port = (ntohs (udp->spt) < 32000) ? udp->spt : 0;
1079 usm->destination_port = udp->dpt;
1080 usm->service_descriptor = destination->details.service_destination.service_descriptor;
1083 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1087 struct GNUNET_EXIT_UdpInternetMessage *uim;
1088 struct in_addr *ip4dst;
1089 struct in6_addr *ip6dst;
1092 mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) +
1093 alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1094 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1099 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) +
1103 uim = (struct GNUNET_EXIT_UdpInternetMessage *) &tnq[1];
1104 uim->header.size = htons ((uint16_t) mlen);
1105 uim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET);
1106 uim->af = htonl (destination->details.exit_destination.af);
1107 uim->source_port = (ntohs (udp->spt) < 32000) ? udp->spt : 0;
1108 uim->destination_port = udp->dpt;
1109 switch (destination->details.exit_destination.af)
1112 ip4dst = (struct in_addr *) &uim[1];
1113 *ip4dst = destination->details.exit_destination.ip.v4;
1114 payload = &ip4dst[1];
1117 ip6dst = (struct in6_addr *) &uim[1];
1118 *ip6dst = destination->details.exit_destination.ip.v6;
1119 payload = &ip6dst[1];
1126 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1132 if (destination->is_service)
1134 struct GNUNET_EXIT_TcpServiceStartMessage *tsm;
1136 mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) +
1137 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1138 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1143 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1146 tsm = (struct GNUNET_EXIT_TcpServiceStartMessage *) &tnq[1];
1147 tsm->header.size = htons ((uint16_t) mlen);
1148 tsm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START);
1149 tsm->reserved = htonl (0);
1150 tsm->service_descriptor = destination->details.service_destination.service_descriptor;
1151 tsm->tcp_header = *tcp;
1154 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1158 struct GNUNET_EXIT_TcpInternetStartMessage *tim;
1159 struct in_addr *ip4dst;
1160 struct in6_addr *ip6dst;
1163 mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) +
1164 alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1165 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1170 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1173 tim = (struct GNUNET_EXIT_TcpInternetStartMessage *) &tnq[1];
1174 tim->header.size = htons ((uint16_t) mlen);
1175 tim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START);
1176 tim->af = htonl (destination->details.exit_destination.af);
1177 tim->tcp_header = *tcp;
1178 switch (destination->details.exit_destination.af)
1181 ip4dst = (struct in_addr *) &tim[1];
1182 *ip4dst = destination->details.exit_destination.ip.v4;
1183 payload = &ip4dst[1];
1186 ip6dst = (struct in6_addr *) &tim[1];
1187 *ip6dst = destination->details.exit_destination.ip.v6;
1188 payload = &ip6dst[1];
1195 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1200 struct GNUNET_EXIT_TcpDataMessage *tdm;
1202 mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) +
1203 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1204 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1209 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1212 tdm = (struct GNUNET_EXIT_TcpDataMessage *) &tnq[1];
1213 tdm->header.size = htons ((uint16_t) mlen);
1214 tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT);
1215 tdm->reserved = htonl (0);
1216 tdm->tcp_header = *tcp;
1219 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1223 if (destination->is_service)
1225 struct GNUNET_EXIT_IcmpServiceMessage *ism;
1227 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1228 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1229 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1234 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1236 ism = (struct GNUNET_EXIT_IcmpServiceMessage *) &tnq[1];
1237 ism->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE);
1238 ism->af = htonl (af); /* need to tell destination ICMP protocol family! */
1239 ism->service_descriptor = destination->details.service_destination.service_descriptor;
1240 ism->icmp_header = *icmp;
1241 /* ICMP protocol translation will be done by the receiver (as we don't know
1242 the target AF); however, we still need to possibly discard the payload
1243 depending on the ICMP type */
1249 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1250 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1252 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1253 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1254 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1255 /* throw away ICMP payload, won't be useful for the other side anyway */
1256 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1259 GNUNET_STATISTICS_update (stats,
1260 gettext_noop ("# ICMPv4 packets dropped (not allowed)"),
1264 /* end of AF_INET */
1269 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1270 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1271 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1272 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1273 /* throw away ICMP payload, won't be useful for the other side anyway */
1274 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1276 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1277 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1280 GNUNET_STATISTICS_update (stats,
1281 gettext_noop ("# ICMPv6 packets dropped (not allowed)"),
1285 /* end of AF_INET6 */
1292 /* update length calculations, as payload_length may have changed */
1293 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1294 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1296 ism->header.size = htons ((uint16_t) mlen);
1297 /* finally, copy payload (if there is any left...) */
1300 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1304 struct GNUNET_EXIT_IcmpInternetMessage *iim;
1305 struct in_addr *ip4dst;
1306 struct in6_addr *ip6dst;
1309 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1310 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1311 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1316 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) +
1319 iim = (struct GNUNET_EXIT_IcmpInternetMessage *) &tnq[1];
1320 iim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET);
1321 iim->icmp_header = *icmp;
1322 /* Perform ICMP protocol-translation (depending on destination AF and source AF)
1323 and throw away ICMP payload depending on ICMP message type */
1329 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1330 if (destination->details.exit_destination.af == AF_INET6)
1331 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1333 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1334 if (destination->details.exit_destination.af == AF_INET6)
1335 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1337 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1338 if (destination->details.exit_destination.af == AF_INET6)
1339 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1340 /* throw away IP-payload, exit will have to make it up anyway */
1341 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1343 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1344 if (destination->details.exit_destination.af == AF_INET6)
1345 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1346 /* throw away IP-payload, exit will have to make it up anyway */
1347 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1349 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1350 if (destination->details.exit_destination.af == AF_INET6)
1352 GNUNET_STATISTICS_update (stats,
1353 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1358 /* throw away IP-payload, exit will have to make it up anyway */
1359 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1362 GNUNET_STATISTICS_update (stats,
1363 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1368 /* end of AF_INET */
1373 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1374 if (destination->details.exit_destination.af == AF_INET6)
1375 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1376 /* throw away IP-payload, exit will have to make it up anyway */
1377 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1379 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1380 if (destination->details.exit_destination.af == AF_INET)
1381 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1382 /* throw away IP-payload, exit will have to make it up anyway */
1383 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1385 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1386 if (destination->details.exit_destination.af == AF_INET)
1388 GNUNET_STATISTICS_update (stats,
1389 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1394 /* throw away IP-payload, exit will have to make it up anyway */
1395 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1397 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1398 if (destination->details.exit_destination.af == AF_INET)
1400 GNUNET_STATISTICS_update (stats,
1401 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1406 /* throw away IP-payload, exit will have to make it up anyway */
1407 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1409 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1410 if (destination->details.exit_destination.af == AF_INET)
1411 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1413 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1414 if (destination->details.exit_destination.af == AF_INET)
1415 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1418 GNUNET_STATISTICS_update (stats,
1419 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1424 /* end of AF_INET6 */
1429 /* update length calculations, as payload_length may have changed */
1430 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1431 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1433 iim->header.size = htons ((uint16_t) mlen);
1435 /* need to tell destination ICMP protocol family! */
1436 iim->af = htonl (destination->details.exit_destination.af);
1437 switch (destination->details.exit_destination.af)
1440 ip4dst = (struct in_addr *) &iim[1];
1441 *ip4dst = destination->details.exit_destination.ip.v4;
1442 payload = &ip4dst[1];
1445 ip6dst = (struct in6_addr *) &iim[1];
1446 *ip6dst = destination->details.exit_destination.ip.v6;
1447 payload = &ip6dst[1];
1454 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1458 /* not supported above, how can we get here !? */
1462 send_to_tunnel (tnq, ts);
1467 * Receive packets from the helper-process (someone send to the local
1468 * virtual tunnel interface). Find the destination mapping, and if it
1469 * exists, identify the correct MESH tunnel (or possibly create it)
1470 * and forward the packet.
1472 * @param cls closure, NULL
1473 * @param client NULL
1474 * @param message message we got from the client (VPN tunnel interface)
1477 message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED,
1478 const struct GNUNET_MessageHeader *message)
1480 const struct GNUNET_TUN_Layer2PacketHeader *tun;
1482 GNUNET_HashCode key;
1483 struct DestinationEntry *de;
1485 GNUNET_STATISTICS_update (stats,
1486 gettext_noop ("# Packets received from TUN interface"),
1488 mlen = ntohs (message->size);
1489 if ( (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
1490 (mlen < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader)) )
1495 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1496 mlen -= (sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader));
1497 switch (ntohs (tun->proto))
1501 const struct GNUNET_TUN_IPv6Header *pkt6;
1503 if (mlen < sizeof (struct GNUNET_TUN_IPv6Header))
1509 pkt6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1510 get_destination_key_from_ip (AF_INET6,
1511 &pkt6->destination_address,
1513 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1514 /* FIXME: do we need to guard against hash collision?
1515 (if so, we need to also store the local destination IP in the
1516 destination entry and then compare here; however, the risk
1517 of collision seems minimal AND the impact is unlikely to be
1518 super-problematic as well... */
1521 char buf[INET6_ADDRSTRLEN];
1523 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1524 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1525 inet_ntop (AF_INET6,
1526 &pkt6->destination_address,
1534 &pkt6->source_address,
1535 &pkt6->destination_address,
1537 mlen - sizeof (struct GNUNET_TUN_IPv6Header));
1542 struct GNUNET_TUN_IPv4Header *pkt4;
1544 if (mlen < sizeof (struct GNUNET_TUN_IPv4Header))
1550 pkt4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1551 get_destination_key_from_ip (AF_INET,
1552 &pkt4->destination_address,
1554 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1555 /* FIXME: do we need to guard against hash collision?
1556 (if so, we need to also store the local destination IP in the
1557 destination entry and then compare here; however, the risk
1558 of collision seems minimal AND the impact is unlikely to be
1559 super-problematic as well... */
1562 char buf[INET_ADDRSTRLEN];
1564 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1565 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1567 &pkt4->destination_address,
1572 if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header))
1574 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1575 _("Received IPv4 packet with options (dropping it)\n"));
1581 &pkt4->source_address,
1582 &pkt4->destination_address,
1584 mlen - sizeof (struct GNUNET_TUN_IPv4Header));
1588 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1589 _("Received packet of unknown protocol %d from TUN (dropping it)\n"),
1590 (unsigned int) ntohs (tun->proto));
1597 * Synthesize a plausible ICMP payload for an ICMP error
1598 * response on the given tunnel.
1600 * @param ts tunnel information
1601 * @param ipp IPv4 header to fill in (ICMP payload)
1602 * @param udp "UDP" header to fill in (ICMP payload); might actually
1603 * also be the first 8 bytes of the TCP header
1606 make_up_icmpv4_payload (struct TunnelState *ts,
1607 struct GNUNET_TUN_IPv4Header *ipp,
1608 struct GNUNET_TUN_UdpHeader *udp)
1610 GNUNET_TUN_initialize_ipv4_header (ipp,
1612 sizeof (struct GNUNET_TUN_TcpHeader),
1614 &ts->destination_ip.v4);
1615 udp->spt = htons (ts->source_port);
1616 udp->dpt = htons (ts->destination_port);
1617 udp->len = htons (0);
1618 udp->crc = htons (0);
1623 * Synthesize a plausible ICMP payload for an ICMP error
1624 * response on the given tunnel.
1626 * @param ts tunnel information
1627 * @param ipp IPv6 header to fill in (ICMP payload)
1628 * @param udp "UDP" header to fill in (ICMP payload); might actually
1629 * also be the first 8 bytes of the TCP header
1632 make_up_icmpv6_payload (struct TunnelState *ts,
1633 struct GNUNET_TUN_IPv6Header *ipp,
1634 struct GNUNET_TUN_UdpHeader *udp)
1636 GNUNET_TUN_initialize_ipv6_header (ipp,
1638 sizeof (struct GNUNET_TUN_TcpHeader),
1640 &ts->destination_ip.v6);
1641 udp->spt = htons (ts->source_port);
1642 udp->dpt = htons (ts->destination_port);
1643 udp->len = htons (0);
1644 udp->crc = htons (0);
1649 * We got an ICMP packet back from the MESH tunnel. Pass it on to the
1650 * local virtual interface via the helper.
1652 * @param cls closure, NULL
1653 * @param tunnel connection to the other end
1654 * @param tunnel_ctx pointer to our 'struct TunnelState *'
1655 * @param sender who sent the message
1656 * @param message the actual message
1657 * @param atsi performance data for the connection
1658 * @return GNUNET_OK to keep the connection open,
1659 * GNUNET_SYSERR to close it (signal serious error)
1662 receive_icmp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1663 void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender,
1664 const struct GNUNET_MessageHeader *message,
1665 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
1667 struct TunnelState *ts = *tunnel_ctx;
1668 const struct GNUNET_EXIT_IcmpToVPNMessage *i2v;
1671 GNUNET_STATISTICS_update (stats,
1672 gettext_noop ("# ICMP packets received from mesh"),
1674 mlen = ntohs (message->size);
1675 if (mlen < sizeof (struct GNUNET_EXIT_IcmpToVPNMessage))
1677 GNUNET_break_op (0);
1678 return GNUNET_SYSERR;
1680 if (NULL == ts->heap_node)
1682 GNUNET_break_op (0);
1683 return GNUNET_SYSERR;
1685 if (AF_UNSPEC == ts->af)
1687 GNUNET_break_op (0);
1688 return GNUNET_SYSERR;
1690 i2v = (const struct GNUNET_EXIT_IcmpToVPNMessage *) message;
1691 mlen -= sizeof (struct GNUNET_EXIT_IcmpToVPNMessage);
1693 char sbuf[INET6_ADDRSTRLEN];
1694 char dbuf[INET6_ADDRSTRLEN];
1696 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1697 "Received ICMP packet from mesh, sending %u bytes from %s -> %s via TUN\n",
1698 (unsigned int) mlen,
1699 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
1700 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)));
1706 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
1707 + sizeof (struct GNUNET_TUN_IcmpHeader)
1708 + sizeof (struct GNUNET_MessageHeader) +
1709 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1712 /* reserve some extra space in case we have an ICMP type here where
1713 we will need to make up the payload ourselves */
1714 char buf[size + sizeof (struct GNUNET_TUN_IPv4Header) + 8];
1715 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1716 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1717 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1718 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv4[1];
1719 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1720 tun->flags = htons (0);
1721 tun->proto = htons (ETH_P_IPV4);
1722 GNUNET_TUN_initialize_ipv4_header (ipv4,
1724 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1725 &ts->destination_ip.v4,
1727 *icmp = i2v->icmp_header;
1731 /* For some ICMP types, we need to adjust (make up) the payload here.
1732 Also, depending on the AF used on the other side, we have to
1733 do ICMP PT (translate ICMP types) */
1734 switch (ntohl (i2v->af))
1739 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1740 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1742 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1743 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1744 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1746 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1747 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1751 /* sender did not strip ICMP payload? */
1752 GNUNET_break_op (0);
1753 return GNUNET_SYSERR;
1755 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1756 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1757 make_up_icmpv4_payload (ts, ipp, udp);
1761 GNUNET_break_op (0);
1762 GNUNET_STATISTICS_update (stats,
1763 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1765 return GNUNET_SYSERR;
1770 /* ICMP PT 6-to-4 and possibly making up payloads */
1773 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1774 icmp->type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
1776 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1777 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1781 /* sender did not strip ICMP payload? */
1782 GNUNET_break_op (0);
1783 return GNUNET_SYSERR;
1785 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1786 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1787 make_up_icmpv4_payload (ts, ipp, udp);
1790 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1791 icmp->type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1793 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1794 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1798 /* sender did not strip ICMP payload? */
1799 GNUNET_break_op (0);
1800 return GNUNET_SYSERR;
1802 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1803 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1804 make_up_icmpv4_payload (ts, ipp, udp);
1807 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1808 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1809 GNUNET_STATISTICS_update (stats,
1810 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1813 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1814 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1816 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1817 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1820 GNUNET_break_op (0);
1821 GNUNET_STATISTICS_update (stats,
1822 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1824 return GNUNET_SYSERR;
1829 GNUNET_break_op (0);
1830 return GNUNET_SYSERR;
1832 msg->size = htons (size);
1833 GNUNET_TUN_calculate_icmp_checksum (icmp,
1836 (void) GNUNET_HELPER_send (helper_handle,
1845 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
1846 + sizeof (struct GNUNET_TUN_IcmpHeader)
1847 + sizeof (struct GNUNET_MessageHeader) +
1848 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1851 char buf[size + sizeof (struct GNUNET_TUN_IPv6Header) + 8];
1852 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1853 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1854 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
1855 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv6[1];
1856 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1857 tun->flags = htons (0);
1858 tun->proto = htons (ETH_P_IPV6);
1859 GNUNET_TUN_initialize_ipv6_header (ipv6,
1861 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1862 &ts->destination_ip.v6,
1864 *icmp = i2v->icmp_header;
1869 /* For some ICMP types, we need to adjust (make up) the payload here.
1870 Also, depending on the AF used on the other side, we have to
1871 do ICMP PT (translate ICMP types) */
1872 switch (ntohl (i2v->af))
1875 /* ICMP PT 4-to-6 and possibly making up payloads */
1878 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1879 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1881 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1882 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1884 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1885 icmp->type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1887 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1888 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1892 /* sender did not strip ICMP payload? */
1893 GNUNET_break_op (0);
1894 return GNUNET_SYSERR;
1896 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1897 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1898 make_up_icmpv6_payload (ts, ipp, udp);
1901 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1902 icmp->type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1904 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1905 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1909 /* sender did not strip ICMP payload? */
1910 GNUNET_break_op (0);
1911 return GNUNET_SYSERR;
1913 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1914 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1915 make_up_icmpv6_payload (ts, ipp, udp);
1918 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1919 GNUNET_STATISTICS_update (stats,
1920 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1924 GNUNET_break_op (0);
1925 GNUNET_STATISTICS_update (stats,
1926 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1928 return GNUNET_SYSERR;
1935 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1936 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1937 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1938 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1940 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1941 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1945 /* sender did not strip ICMP payload? */
1946 GNUNET_break_op (0);
1947 return GNUNET_SYSERR;
1949 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1950 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1951 make_up_icmpv6_payload (ts, ipp, udp);
1954 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1957 GNUNET_break_op (0);
1958 GNUNET_STATISTICS_update (stats,
1959 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1961 return GNUNET_SYSERR;
1966 GNUNET_break_op (0);
1967 return GNUNET_SYSERR;
1969 msg->size = htons (size);
1970 GNUNET_TUN_calculate_icmp_checksum (icmp,
1972 (void) GNUNET_HELPER_send (helper_handle,
1982 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
1984 GNUNET_TIME_absolute_get ().abs_value);
1990 * We got a UDP packet back from the MESH tunnel. Pass it on to the
1991 * local virtual interface via the helper.
1993 * @param cls closure, NULL
1994 * @param tunnel connection to the other end
1995 * @param tunnel_ctx pointer to our 'struct TunnelState *'
1996 * @param sender who sent the message
1997 * @param message the actual message
1998 * @param atsi performance data for the connection
1999 * @return GNUNET_OK to keep the connection open,
2000 * GNUNET_SYSERR to close it (signal serious error)
2003 receive_udp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
2004 void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender,
2005 const struct GNUNET_MessageHeader *message,
2006 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
2008 struct TunnelState *ts = *tunnel_ctx;
2009 const struct GNUNET_EXIT_UdpReplyMessage *reply;
2012 GNUNET_STATISTICS_update (stats,
2013 gettext_noop ("# UDP packets received from mesh"),
2015 mlen = ntohs (message->size);
2016 if (mlen < sizeof (struct GNUNET_EXIT_UdpReplyMessage))
2018 GNUNET_break_op (0);
2019 return GNUNET_SYSERR;
2021 if (NULL == ts->heap_node)
2023 GNUNET_break_op (0);
2024 return GNUNET_SYSERR;
2026 if (AF_UNSPEC == ts->af)
2028 GNUNET_break_op (0);
2029 return GNUNET_SYSERR;
2031 reply = (const struct GNUNET_EXIT_UdpReplyMessage *) message;
2032 mlen -= sizeof (struct GNUNET_EXIT_UdpReplyMessage);
2034 char sbuf[INET6_ADDRSTRLEN];
2035 char dbuf[INET6_ADDRSTRLEN];
2037 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2038 "Received UDP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2039 (unsigned int) mlen,
2040 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2041 ts->destination_port,
2042 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2049 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2050 + sizeof (struct GNUNET_TUN_UdpHeader)
2051 + sizeof (struct GNUNET_MessageHeader) +
2052 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2056 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2057 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2058 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2059 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1];
2060 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2061 msg->size = htons (size);
2062 tun->flags = htons (0);
2063 tun->proto = htons (ETH_P_IPV4);
2064 GNUNET_TUN_initialize_ipv4_header (ipv4,
2066 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2067 &ts->destination_ip.v4,
2069 if (0 == ntohs (reply->source_port))
2070 udp->spt = htons (ts->destination_port);
2072 udp->spt = reply->source_port;
2073 if (0 == ntohs (reply->destination_port))
2074 udp->dpt = htons (ts->source_port);
2076 udp->dpt = reply->destination_port;
2077 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2078 GNUNET_TUN_calculate_udp4_checksum (ipv4,
2085 (void) GNUNET_HELPER_send (helper_handle,
2094 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2095 + sizeof (struct GNUNET_TUN_UdpHeader)
2096 + sizeof (struct GNUNET_MessageHeader) +
2097 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2101 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2102 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2103 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2104 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1];
2105 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2106 msg->size = htons (size);
2107 tun->flags = htons (0);
2108 tun->proto = htons (ETH_P_IPV6);
2109 GNUNET_TUN_initialize_ipv6_header (ipv6,
2111 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2112 &ts->destination_ip.v6,
2114 if (0 == ntohs (reply->source_port))
2115 udp->spt = htons (ts->destination_port);
2117 udp->spt = reply->source_port;
2118 if (0 == ntohs (reply->destination_port))
2119 udp->dpt = htons (ts->source_port);
2121 udp->dpt = reply->destination_port;
2122 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2123 GNUNET_TUN_calculate_udp6_checksum (ipv6,
2129 (void) GNUNET_HELPER_send (helper_handle,
2139 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2141 GNUNET_TIME_absolute_get ().abs_value);
2147 * We got a TCP packet back from the MESH tunnel. Pass it on to the
2148 * local virtual interface via the helper.
2150 * @param cls closure, NULL
2151 * @param tunnel connection to the other end
2152 * @param tunnel_ctx pointer to our 'struct TunnelState *'
2153 * @param sender who sent the message
2154 * @param message the actual message
2155 * @param atsi performance data for the connection
2156 * @return GNUNET_OK to keep the connection open,
2157 * GNUNET_SYSERR to close it (signal serious error)
2160 receive_tcp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
2162 const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED,
2163 const struct GNUNET_MessageHeader *message,
2164 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
2166 struct TunnelState *ts = *tunnel_ctx;
2167 const struct GNUNET_EXIT_TcpDataMessage *data;
2170 GNUNET_STATISTICS_update (stats,
2171 gettext_noop ("# TCP packets received from mesh"),
2173 mlen = ntohs (message->size);
2174 if (mlen < sizeof (struct GNUNET_EXIT_TcpDataMessage))
2176 GNUNET_break_op (0);
2177 return GNUNET_SYSERR;
2179 if (NULL == ts->heap_node)
2181 GNUNET_break_op (0);
2182 return GNUNET_SYSERR;
2184 data = (const struct GNUNET_EXIT_TcpDataMessage *) message;
2185 mlen -= sizeof (struct GNUNET_EXIT_TcpDataMessage);
2187 char sbuf[INET6_ADDRSTRLEN];
2188 char dbuf[INET6_ADDRSTRLEN];
2190 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2191 "Received TCP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2192 (unsigned int) mlen,
2193 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2194 ts->destination_port,
2195 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2202 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2203 + sizeof (struct GNUNET_TUN_TcpHeader)
2204 + sizeof (struct GNUNET_MessageHeader) +
2205 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2209 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2210 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2211 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2212 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv4[1];
2213 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2214 msg->size = htons (size);
2215 tun->flags = htons (0);
2216 tun->proto = htons (ETH_P_IPV4);
2217 GNUNET_TUN_initialize_ipv4_header (ipv4,
2219 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2220 &ts->destination_ip.v4,
2222 *tcp = data->tcp_header;
2223 tcp->spt = htons (ts->destination_port);
2224 tcp->dpt = htons (ts->source_port);
2225 GNUNET_TUN_calculate_tcp4_checksum (ipv4,
2232 (void) GNUNET_HELPER_send (helper_handle,
2241 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2242 + sizeof (struct GNUNET_TUN_TcpHeader)
2243 + sizeof (struct GNUNET_MessageHeader) +
2244 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2248 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2249 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2250 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2251 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv6[1];
2252 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2253 msg->size = htons (size);
2254 tun->flags = htons (0);
2255 tun->proto = htons (ETH_P_IPV6);
2256 GNUNET_TUN_initialize_ipv6_header (ipv6,
2258 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2259 &ts->destination_ip.v6,
2261 tcp->spt = htons (ts->destination_port);
2262 tcp->dpt = htons (ts->source_port);
2263 GNUNET_TUN_calculate_tcp6_checksum (ipv6,
2267 (void) GNUNET_HELPER_send (helper_handle,
2275 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2277 GNUNET_TIME_absolute_get ().abs_value);
2283 * Allocate an IPv4 address from the range of the tunnel
2284 * for a new redirection.
2286 * @param v4 where to store the address
2287 * @return GNUNET_OK on success,
2288 * GNUNET_SYSERR on error
2291 allocate_v4_address (struct in_addr *v4)
2293 const char *ipv4addr = vpn_argv[4];
2294 const char *ipv4mask = vpn_argv[5];
2295 struct in_addr addr;
2296 struct in_addr mask;
2298 GNUNET_HashCode key;
2301 GNUNET_assert (1 == inet_pton (AF_INET, ipv4addr, &addr));
2302 GNUNET_assert (1 == inet_pton (AF_INET, ipv4mask, &mask));
2303 /* Given 192.168.0.1/255.255.0.0, we want a mask
2304 of '192.168.255.255', thus: */
2305 mask.s_addr = addr.s_addr | ~mask.s_addr;
2312 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2313 _("Failed to find unallocated IPv4 address in VPN's range\n"));
2314 return GNUNET_SYSERR;
2316 /* Pick random IPv4 address within the subnet, except 'addr' or 'mask' itself */
2317 rnd.s_addr = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2319 v4->s_addr = (addr.s_addr | rnd.s_addr) & mask.s_addr;
2320 get_destination_key_from_ip (AF_INET,
2324 while ( (GNUNET_YES ==
2325 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2327 (v4->s_addr == addr.s_addr) ||
2328 (v4->s_addr == mask.s_addr) );
2334 * Allocate an IPv6 address from the range of the tunnel
2335 * for a new redirection.
2337 * @param v6 where to store the address
2338 * @return GNUNET_OK on success,
2339 * GNUNET_SYSERR on error
2342 allocate_v6_address (struct in6_addr *v6)
2344 const char *ipv6addr = vpn_argv[2];
2345 struct in6_addr addr;
2346 struct in6_addr mask;
2347 struct in6_addr rnd;
2349 GNUNET_HashCode key;
2352 GNUNET_assert (1 == inet_pton (AF_INET6, ipv6addr, &addr));
2353 GNUNET_assert (ipv6prefix < 128);
2354 /* Given ABCD::/96, we want a mask of 'ABCD::FFFF:FFFF,
2357 for (i=127;i>=128-ipv6prefix;i--)
2358 mask.s6_addr[i / 8] |= (1 << (i % 8));
2360 /* Pick random IPv6 address within the subnet, except 'addr' or 'mask' itself */
2367 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2368 _("Failed to find unallocated IPv6 address in VPN's range\n"));
2369 return GNUNET_SYSERR;
2374 rnd.s6_addr[i] = (unsigned char) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2377 = (addr.s6_addr[i] | rnd.s6_addr[i]) & mask.s6_addr[i];
2379 get_destination_key_from_ip (AF_INET6,
2383 while ( (GNUNET_YES ==
2384 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2388 sizeof (struct in6_addr))) ||
2391 sizeof (struct in6_addr))) );
2397 * Free resources occupied by a destination entry.
2399 * @param de entry to free
2402 free_destination_entry (struct DestinationEntry *de)
2404 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2405 "Cleaning up destination entry\n");
2406 GNUNET_STATISTICS_update (stats,
2407 gettext_noop ("# Active destinations"),
2411 free_tunnel_state (de->ts);
2412 GNUNET_assert (NULL == de->ts);
2414 if (NULL != de->heap_node)
2416 GNUNET_CONTAINER_heap_remove_node (de->heap_node);
2417 de->heap_node = NULL;
2418 GNUNET_assert (GNUNET_YES ==
2419 GNUNET_CONTAINER_multihashmap_remove (destination_map,
2428 * We have too many active destinations. Clean up the oldest destination.
2430 * @param except destination that must NOT be cleaned up, even if it is the oldest
2433 expire_destination (struct DestinationEntry *except)
2435 struct DestinationEntry *de;
2437 de = GNUNET_CONTAINER_heap_peek (destination_heap);
2439 return; /* can't do this */
2440 free_destination_entry (de);
2445 * A client asks us to setup a redirection via some exit
2446 * node to a particular IP. Setup the redirection and
2447 * give the client the allocated IP.
2450 * @param client requesting client
2451 * @param message redirection request (a 'struct RedirectToIpRequestMessage')
2454 service_redirect_to_ip (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
2455 const struct GNUNET_MessageHeader *message)
2459 const struct RedirectToIpRequestMessage *msg;
2465 struct DestinationEntry *de;
2466 GNUNET_HashCode key;
2468 /* validate and parse request */
2469 mlen = ntohs (message->size);
2470 if (mlen < sizeof (struct RedirectToIpRequestMessage))
2473 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2476 alen = mlen - sizeof (struct RedirectToIpRequestMessage);
2477 msg = (const struct RedirectToIpRequestMessage *) message;
2478 addr_af = (int) htonl (msg->addr_af);
2482 if (alen != sizeof (struct in_addr))
2485 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2490 if (alen != sizeof (struct in6_addr))
2493 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2499 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2503 /* allocate response IP */
2505 result_af = (int) htonl (msg->result_af);
2510 allocate_v4_address (&v4))
2511 result_af = AF_UNSPEC;
2517 allocate_v6_address (&v6))
2518 result_af = AF_UNSPEC;
2524 allocate_v4_address (&v4))
2527 result_af = AF_INET;
2529 else if (GNUNET_OK ==
2530 allocate_v6_address (&v6))
2533 result_af = AF_INET6;
2538 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2541 if ( (result_af == AF_UNSPEC) ||
2542 (GNUNET_NO == ntohl (msg->nac)) )
2544 /* send reply "instantly" */
2545 send_client_reply (client,
2550 if (result_af == AF_UNSPEC)
2552 /* failure, we're done */
2553 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2558 char sbuf[INET6_ADDRSTRLEN];
2559 char dbuf[INET6_ADDRSTRLEN];
2561 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2562 "Allocated address %s for redirection via exit to %s\n",
2563 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2565 &msg[1], dbuf, sizeof (dbuf)));
2568 /* setup destination record */
2569 de = GNUNET_malloc (sizeof (struct DestinationEntry));
2570 de->is_service = GNUNET_NO;
2571 de->details.exit_destination.af = addr_af;
2572 memcpy (&de->details.exit_destination.ip,
2575 get_destination_key_from_ip (result_af,
2579 GNUNET_assert (GNUNET_OK ==
2580 GNUNET_CONTAINER_multihashmap_put (destination_map,
2583 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2584 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2586 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
2587 GNUNET_STATISTICS_update (stats,
2588 gettext_noop ("# Active destinations"),
2590 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2591 expire_destination (de);
2593 /* setup tunnel to destination */
2594 (void) create_tunnel_to_destination (de,
2595 (GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
2598 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2603 * A client asks us to setup a redirection to a particular peer
2604 * offering a service. Setup the redirection and give the client the
2608 * @param client requesting client
2609 * @param message redirection request (a 'struct RedirectToPeerRequestMessage')
2612 service_redirect_to_service (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
2613 const struct GNUNET_MessageHeader *message)
2615 const struct RedirectToServiceRequestMessage *msg;
2620 struct DestinationEntry *de;
2621 GNUNET_HashCode key;
2624 msg = (const struct RedirectToServiceRequestMessage *) message;
2626 /* allocate response IP */
2628 result_af = (int) htonl (msg->result_af);
2633 allocate_v4_address (&v4))
2634 result_af = AF_UNSPEC;
2640 allocate_v6_address (&v6))
2641 result_af = AF_UNSPEC;
2647 allocate_v4_address (&v4))
2650 result_af = AF_INET;
2652 else if (GNUNET_OK ==
2653 allocate_v6_address (&v6))
2656 result_af = AF_INET6;
2661 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2664 if ( (result_af == AF_UNSPEC) ||
2665 (GNUNET_NO == ntohl (msg->nac)) )
2667 /* send reply "instantly" */
2668 send_client_reply (client,
2673 if (result_af == AF_UNSPEC)
2675 /* failure, we're done */
2676 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2677 _("Failed to allocate IP address for new destination\n"));
2678 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2683 char sbuf[INET6_ADDRSTRLEN];
2685 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2686 "Allocated address %s for redirection to service %s on peer %s\n",
2687 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2688 GNUNET_h2s (&msg->service_descriptor),
2689 GNUNET_i2s (&msg->target));
2692 /* setup destination record */
2693 de = GNUNET_malloc (sizeof (struct DestinationEntry));
2694 de->is_service = GNUNET_YES;
2695 de->details.service_destination.service_descriptor = msg->service_descriptor;
2696 de->details.service_destination.target = msg->target;
2697 get_destination_key_from_ip (result_af,
2701 GNUNET_assert (GNUNET_OK ==
2702 GNUNET_CONTAINER_multihashmap_put (destination_map,
2705 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2706 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2708 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
2709 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2710 expire_destination (de);
2711 (void) create_tunnel_to_destination (de,
2712 (GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
2715 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2721 * Function called for inbound tunnels. As we don't offer
2722 * any mesh services, this function should never be called.
2724 * @param cls closure
2725 * @param tunnel new handle to the tunnel
2726 * @param initiator peer that started the tunnel
2727 * @param atsi performance information for the tunnel
2728 * @return initial tunnel context for the tunnel
2729 * (can be NULL -- that's not an error)
2732 inbound_tunnel_cb (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
2733 const struct GNUNET_PeerIdentity *initiator,
2734 const struct GNUNET_ATS_Information *atsi)
2736 /* How can and why should anyone open an inbound tunnel to vpn? */
2743 * Function called whenever an inbound tunnel is destroyed. Should clean up
2744 * any associated state.
2746 * @param cls closure (set from GNUNET_MESH_connect)
2747 * @param tunnel connection to the other end (henceforth invalid)
2748 * @param tunnel_ctx place where local state associated
2749 * with the tunnel is stored (our 'struct TunnelState')
2752 tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel_ctx)
2754 /* we don't have inbound tunnels, so this function should never be called */
2760 * Free memory occupied by an entry in the destination map.
2764 * @param value a 'struct DestinationEntry *'
2765 * @return GNUNET_OK (continue to iterate)
2768 cleanup_destination (void *cls,
2769 const GNUNET_HashCode *key,
2772 struct DestinationEntry *de = value;
2774 free_destination_entry (de);
2780 * Free memory occupied by an entry in the tunnel map.
2784 * @param value a 'struct TunnelState *'
2785 * @return GNUNET_OK (continue to iterate)
2788 cleanup_tunnel (void *cls,
2789 const GNUNET_HashCode *key,
2792 struct TunnelState *ts = value;
2794 free_tunnel_state (ts);
2800 * Function scheduled as very last function, cleans up after us
2806 cleanup (void *cls GNUNET_UNUSED,
2807 const struct GNUNET_SCHEDULER_TaskContext *tc)
2811 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2812 "VPN is shutting down\n");
2813 if (NULL != destination_map)
2815 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
2816 &cleanup_destination,
2818 GNUNET_CONTAINER_multihashmap_destroy (destination_map);
2819 destination_map = NULL;
2821 if (NULL != destination_heap)
2823 GNUNET_CONTAINER_heap_destroy (destination_heap);
2824 destination_heap = NULL;
2826 if (NULL != tunnel_map)
2828 GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
2831 GNUNET_CONTAINER_multihashmap_destroy (tunnel_map);
2834 if (NULL != tunnel_heap)
2836 GNUNET_CONTAINER_heap_destroy (tunnel_heap);
2839 if (NULL != mesh_handle)
2841 GNUNET_MESH_disconnect (mesh_handle);
2844 if (NULL != helper_handle)
2846 GNUNET_HELPER_stop (helper_handle);
2847 helper_handle = NULL;
2851 GNUNET_SERVER_notification_context_destroy (nc);
2856 GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
2860 GNUNET_free_non_null (vpn_argv[i]);
2865 * A client disconnected, clean up all references to it.
2867 * @param cls the client that disconnected
2869 * @param value a 'struct TunnelState *'
2870 * @return GNUNET_OK (continue to iterate)
2873 cleanup_tunnel_client (void *cls,
2874 const GNUNET_HashCode *key,
2877 struct GNUNET_SERVER_Client *client = cls;
2878 struct TunnelState *ts = value;
2880 if (client == ts->client)
2882 GNUNET_SERVER_client_drop (ts->client);
2890 * A client disconnected, clean up all references to it.
2892 * @param cls the client that disconnected
2894 * @param value a 'struct DestinationEntry *'
2895 * @return GNUNET_OK (continue to iterate)
2898 cleanup_destination_client (void *cls,
2899 const GNUNET_HashCode *key,
2902 struct GNUNET_SERVER_Client *client = cls;
2903 struct DestinationEntry *de = value;
2904 struct TunnelState *ts;
2906 if (NULL == (ts = de->ts))
2908 if (client == ts->client)
2910 GNUNET_SERVER_client_drop (ts->client);
2918 * A client has disconnected from us. If we are currently building
2919 * a tunnel for it, cancel the operation.
2922 * @param client handle to the client that disconnected
2925 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
2927 if (NULL != tunnel_map)
2928 GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
2929 &cleanup_tunnel_client,
2931 if (NULL != destination_map)
2932 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
2933 &cleanup_destination_client,
2939 * Main function that will be run by the scheduler.
2941 * @param cls closure
2942 * @param server the initialized server
2943 * @param cfg_ configuration
2947 struct GNUNET_SERVER_Handle *server,
2948 const struct GNUNET_CONFIGURATION_Handle *cfg_)
2950 static const struct GNUNET_SERVER_MessageHandler service_handlers[] = {
2951 /* callback, cls, type, size */
2952 { &service_redirect_to_ip, NULL, GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP, 0},
2953 { &service_redirect_to_service, NULL,
2954 GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE,
2955 sizeof (struct RedirectToServiceRequestMessage) },
2958 static const struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
2959 { &receive_udp_back, GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY, 0},
2960 { &receive_tcp_back, GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN, 0},
2961 { &receive_icmp_back, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN, 0},
2964 static const GNUNET_MESH_ApplicationType types[] = {
2965 GNUNET_APPLICATION_TYPE_END
2976 stats = GNUNET_STATISTICS_create ("vpn", cfg);
2978 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_MAPPING",
2979 &max_destination_mappings))
2980 max_destination_mappings = 200;
2982 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_TUNNELS",
2983 &max_tunnel_mappings))
2984 max_tunnel_mappings = 200;
2986 destination_map = GNUNET_CONTAINER_multihashmap_create (max_destination_mappings * 2);
2987 destination_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
2988 tunnel_map = GNUNET_CONTAINER_multihashmap_create (max_tunnel_mappings * 2);
2989 tunnel_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
2992 vpn_argv[0] = GNUNET_strdup ("vpn-gnunet");
2993 if (GNUNET_SYSERR ==
2994 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IFNAME", &ifname))
2996 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2997 "No entry 'IFNAME' in configuration!\n");
2998 GNUNET_SCHEDULER_shutdown ();
3001 vpn_argv[1] = ifname;
3002 if ( (GNUNET_SYSERR ==
3003 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6ADDR",
3005 (1 != inet_pton (AF_INET6, ipv6addr, &v6))) )
3007 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3008 "No valid entry 'IPV6ADDR' in configuration!\n");
3009 GNUNET_SCHEDULER_shutdown ();
3012 vpn_argv[2] = ipv6addr;
3013 if (GNUNET_SYSERR ==
3014 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6PREFIX",
3017 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3018 "No entry 'IPV6PREFIX' in configuration!\n");
3019 GNUNET_SCHEDULER_shutdown ();
3022 vpn_argv[3] = ipv6prefix_s;
3024 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn",
3027 (ipv6prefix >= 127) )
3029 GNUNET_SCHEDULER_shutdown ();
3033 if ( (GNUNET_SYSERR ==
3034 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4ADDR",
3036 (1 != inet_pton (AF_INET, ipv4addr, &v4))) )
3038 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3039 "No valid entry for 'IPV4ADDR' in configuration!\n");
3040 GNUNET_SCHEDULER_shutdown ();
3043 vpn_argv[4] = ipv4addr;
3044 if ( (GNUNET_SYSERR ==
3045 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4MASK",
3047 (1 != inet_pton (AF_INET, ipv4mask, &v4))) )
3049 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3050 "No valid entry 'IPV4MASK' in configuration!\n");
3051 GNUNET_SCHEDULER_shutdown ();
3054 vpn_argv[5] = ipv4mask;
3058 GNUNET_MESH_connect (cfg_, 42 /* queue length */, NULL,
3063 helper_handle = GNUNET_HELPER_start ("gnunet-helper-vpn", vpn_argv,
3064 &message_token, NULL);
3065 nc = GNUNET_SERVER_notification_context_create (server, 1);
3066 GNUNET_SERVER_add_handlers (server, service_handlers);
3067 GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
3068 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls);
3073 * The main function of the VPN service.
3075 * @param argc number of arguments from the command line
3076 * @param argv command line arguments
3077 * @return 0 ok, 1 on error
3080 main (int argc, char *const *argv)
3082 return (GNUNET_OK ==
3083 GNUNET_SERVICE_run (argc, argv, "vpn",
3084 GNUNET_SERVICE_OPTION_NONE,
3085 &run, NULL)) ? 0 : 1;
3088 /* end of gnunet-service-vpn.c */