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 tc scheduler 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 client_af address family of the address returned to the client
755 * @param request_id request ID to send in client notification (unused if client is NULL)
756 * @return tunnel state of the tunnel that was created
758 static struct TunnelState *
759 create_tunnel_to_destination (struct DestinationEntry *de,
760 struct GNUNET_SERVER_Client *client,
764 struct TunnelState *ts;
766 GNUNET_STATISTICS_update (stats,
767 gettext_noop ("# Mesh tunnels created"),
769 GNUNET_assert (NULL == de->ts);
770 ts = GNUNET_malloc (sizeof (struct TunnelState));
774 ts->request_id = request_id;
776 GNUNET_SERVER_client_keep (client);
778 ts->destination = *de;
779 ts->destination.heap_node = NULL; /* copy is NOT in destination heap */
781 ts->destination_container = de; /* we are referenced from de */
782 ts->tunnel = GNUNET_MESH_tunnel_create (mesh_handle,
784 &tunnel_peer_connect_handler,
785 &tunnel_peer_disconnect_handler,
787 if (NULL == ts->tunnel)
789 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
790 _("Failed to setup mesh tunnel!\n"));
792 GNUNET_SERVER_client_drop (client);
798 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
799 "Creating tunnel to peer %s offering service %s\n",
800 GNUNET_i2s (&de->details.service_destination.target),
801 GNUNET_h2s (&de->details.service_destination.service_descriptor));
802 GNUNET_MESH_peer_request_connect_add (ts->tunnel,
803 &de->details.service_destination.target);
807 switch (de->details.exit_destination.af)
810 GNUNET_MESH_peer_request_connect_by_type (ts->tunnel,
811 GNUNET_APPLICATION_TYPE_IPV4_GATEWAY);
812 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
813 "Creating tunnel to exit peer for %s\n",
817 GNUNET_MESH_peer_request_connect_by_type (ts->tunnel,
818 GNUNET_APPLICATION_TYPE_IPV6_GATEWAY);
819 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
820 "Creating tunnel to exit peer for %s\n",
833 * We have too many active tunnels. Clean up the oldest tunnel.
835 * @param except tunnel that must NOT be cleaned up, even if it is the oldest
838 expire_tunnel (struct TunnelState *except)
840 struct TunnelState *ts;
842 ts = GNUNET_CONTAINER_heap_peek (tunnel_heap);
843 GNUNET_assert (NULL != ts);
845 return; /* can't do this */
846 free_tunnel_state (ts);
851 * Route a packet via mesh to the given destination.
853 * @param destination description of the destination
854 * @param af address family on this end (AF_INET or AF_INET6)
855 * @param protocol IPPROTO_TCP or IPPROTO_UDP
856 * @param source_ip source IP used by the sender (struct in_addr or struct in6_addr)
857 * @param destination_ip destination IP used by the sender (struct in_addr or struct in6_addr)
858 * @param payload payload of the packet after the IP header
859 * @param payload_length number of bytes in payload
862 route_packet (struct DestinationEntry *destination,
865 const void *source_ip,
866 const void *destination_ip,
868 size_t payload_length)
871 struct TunnelState *ts;
872 struct TunnelMessageQueueEntry *tnq;
876 const struct GNUNET_TUN_UdpHeader *udp;
877 const struct GNUNET_TUN_TcpHeader *tcp;
878 const struct GNUNET_TUN_IcmpHeader *icmp;
886 if (payload_length < sizeof (struct GNUNET_TUN_UdpHeader))
893 spt = ntohs (udp->spt);
894 dpt = ntohs (udp->dpt);
895 get_tunnel_key_from_ips (af,
906 if (payload_length < sizeof (struct GNUNET_TUN_TcpHeader))
913 spt = ntohs (tcp->spt);
914 dpt = ntohs (tcp->dpt);
915 get_tunnel_key_from_ips (af,
926 if (payload_length < sizeof (struct GNUNET_TUN_IcmpHeader))
935 get_tunnel_key_from_ips (af,
945 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
946 _("Protocol %u not supported, dropping\n"),
947 (unsigned int) protocol);
950 if (! destination->is_service)
952 switch (destination->details.exit_destination.af)
955 alen = sizeof (struct in_addr);
958 alen = sizeof (struct in6_addr);
966 char sbuf[INET6_ADDRSTRLEN];
967 char dbuf[INET6_ADDRSTRLEN];
968 char xbuf[INET6_ADDRSTRLEN];
970 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
971 "Routing %s packet from %s:%u -> %s:%u to destination %s:%u\n",
972 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
973 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
975 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
977 inet_ntop (destination->details.exit_destination.af,
978 &destination->details.exit_destination.ip,
979 xbuf, sizeof (xbuf)),
985 /* make compiler happy */
988 char sbuf[INET6_ADDRSTRLEN];
989 char dbuf[INET6_ADDRSTRLEN];
991 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
992 "Routing %s packet from %s:%u -> %s:%u to service %s at peer %s\n",
993 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
994 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
996 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
998 GNUNET_h2s (&destination->details.service_destination.service_descriptor),
999 GNUNET_i2s (&destination->details.service_destination.target));
1004 /* see if we have an existing tunnel for this destination */
1005 ts = GNUNET_CONTAINER_multihashmap_get (tunnel_map,
1009 /* need to either use the existing tunnel from the destination (if still
1010 available) or create a fresh one */
1011 is_new = GNUNET_YES;
1012 if (NULL == destination->ts)
1013 ts = create_tunnel_to_destination (destination, NULL, af, 0);
1015 ts = destination->ts;
1018 destination->ts = NULL;
1019 ts->destination_container = NULL; /* no longer 'contained' */
1020 /* now bind existing "unbound" tunnel to our IP/port tuple */
1021 ts->protocol = protocol;
1025 ts->source_ip.v4 = * (const struct in_addr *) source_ip;
1026 ts->destination_ip.v4 = * (const struct in_addr *) destination_ip;
1030 ts->source_ip.v6 = * (const struct in6_addr *) source_ip;
1031 ts->destination_ip.v6 = * (const struct in6_addr *) destination_ip;
1033 ts->source_port = spt;
1034 ts->destination_port = dpt;
1035 ts->heap_node = GNUNET_CONTAINER_heap_insert (tunnel_heap,
1037 GNUNET_TIME_absolute_get ().abs_value);
1038 GNUNET_assert (GNUNET_YES ==
1039 GNUNET_CONTAINER_multihashmap_put (tunnel_map,
1042 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1043 GNUNET_STATISTICS_update (stats,
1044 gettext_noop ("# Active tunnels"),
1046 while (GNUNET_CONTAINER_multihashmap_size (tunnel_map) > max_tunnel_mappings)
1052 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
1054 GNUNET_TIME_absolute_get ().abs_value);
1056 GNUNET_assert (NULL != ts->tunnel);
1058 /* send via tunnel */
1062 if (destination->is_service)
1064 struct GNUNET_EXIT_UdpServiceMessage *usm;
1066 mlen = sizeof (struct GNUNET_EXIT_UdpServiceMessage) +
1067 payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1068 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1073 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1076 usm = (struct GNUNET_EXIT_UdpServiceMessage *) &tnq[1];
1077 usm->header.size = htons ((uint16_t) mlen);
1078 usm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE);
1079 /* if the source port is below 32000, we assume it has a special
1080 meaning; if not, we pick a random port (this is a heuristic) */
1081 usm->source_port = (ntohs (udp->spt) < 32000) ? udp->spt : 0;
1082 usm->destination_port = udp->dpt;
1083 usm->service_descriptor = destination->details.service_destination.service_descriptor;
1086 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1090 struct GNUNET_EXIT_UdpInternetMessage *uim;
1091 struct in_addr *ip4dst;
1092 struct in6_addr *ip6dst;
1095 mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) +
1096 alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1097 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1102 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) +
1106 uim = (struct GNUNET_EXIT_UdpInternetMessage *) &tnq[1];
1107 uim->header.size = htons ((uint16_t) mlen);
1108 uim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET);
1109 uim->af = htonl (destination->details.exit_destination.af);
1110 uim->source_port = (ntohs (udp->spt) < 32000) ? udp->spt : 0;
1111 uim->destination_port = udp->dpt;
1112 switch (destination->details.exit_destination.af)
1115 ip4dst = (struct in_addr *) &uim[1];
1116 *ip4dst = destination->details.exit_destination.ip.v4;
1117 payload = &ip4dst[1];
1120 ip6dst = (struct in6_addr *) &uim[1];
1121 *ip6dst = destination->details.exit_destination.ip.v6;
1122 payload = &ip6dst[1];
1129 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1135 if (destination->is_service)
1137 struct GNUNET_EXIT_TcpServiceStartMessage *tsm;
1139 mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) +
1140 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1141 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1146 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1149 tsm = (struct GNUNET_EXIT_TcpServiceStartMessage *) &tnq[1];
1150 tsm->header.size = htons ((uint16_t) mlen);
1151 tsm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START);
1152 tsm->reserved = htonl (0);
1153 tsm->service_descriptor = destination->details.service_destination.service_descriptor;
1154 tsm->tcp_header = *tcp;
1157 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1161 struct GNUNET_EXIT_TcpInternetStartMessage *tim;
1162 struct in_addr *ip4dst;
1163 struct in6_addr *ip6dst;
1166 mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) +
1167 alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1168 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1173 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1176 tim = (struct GNUNET_EXIT_TcpInternetStartMessage *) &tnq[1];
1177 tim->header.size = htons ((uint16_t) mlen);
1178 tim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START);
1179 tim->af = htonl (destination->details.exit_destination.af);
1180 tim->tcp_header = *tcp;
1181 switch (destination->details.exit_destination.af)
1184 ip4dst = (struct in_addr *) &tim[1];
1185 *ip4dst = destination->details.exit_destination.ip.v4;
1186 payload = &ip4dst[1];
1189 ip6dst = (struct in6_addr *) &tim[1];
1190 *ip6dst = destination->details.exit_destination.ip.v6;
1191 payload = &ip6dst[1];
1198 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1203 struct GNUNET_EXIT_TcpDataMessage *tdm;
1205 mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) +
1206 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1207 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1212 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1215 tdm = (struct GNUNET_EXIT_TcpDataMessage *) &tnq[1];
1216 tdm->header.size = htons ((uint16_t) mlen);
1217 tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT);
1218 tdm->reserved = htonl (0);
1219 tdm->tcp_header = *tcp;
1222 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1226 if (destination->is_service)
1228 struct GNUNET_EXIT_IcmpServiceMessage *ism;
1230 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1231 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1232 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1237 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1239 ism = (struct GNUNET_EXIT_IcmpServiceMessage *) &tnq[1];
1240 ism->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE);
1241 ism->af = htonl (af); /* need to tell destination ICMP protocol family! */
1242 ism->service_descriptor = destination->details.service_destination.service_descriptor;
1243 ism->icmp_header = *icmp;
1244 /* ICMP protocol translation will be done by the receiver (as we don't know
1245 the target AF); however, we still need to possibly discard the payload
1246 depending on the ICMP type */
1252 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1253 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1255 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1256 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1257 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1258 /* throw away ICMP payload, won't be useful for the other side anyway */
1259 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1262 GNUNET_STATISTICS_update (stats,
1263 gettext_noop ("# ICMPv4 packets dropped (not allowed)"),
1267 /* end of AF_INET */
1272 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1273 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1274 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1275 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1276 /* throw away ICMP payload, won't be useful for the other side anyway */
1277 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1279 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1280 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1283 GNUNET_STATISTICS_update (stats,
1284 gettext_noop ("# ICMPv6 packets dropped (not allowed)"),
1288 /* end of AF_INET6 */
1295 /* update length calculations, as payload_length may have changed */
1296 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1297 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1299 ism->header.size = htons ((uint16_t) mlen);
1300 /* finally, copy payload (if there is any left...) */
1303 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1307 struct GNUNET_EXIT_IcmpInternetMessage *iim;
1308 struct in_addr *ip4dst;
1309 struct in6_addr *ip6dst;
1312 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1313 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1314 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1319 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) +
1322 iim = (struct GNUNET_EXIT_IcmpInternetMessage *) &tnq[1];
1323 iim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET);
1324 iim->icmp_header = *icmp;
1325 /* Perform ICMP protocol-translation (depending on destination AF and source AF)
1326 and throw away ICMP payload depending on ICMP message type */
1332 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1333 if (destination->details.exit_destination.af == AF_INET6)
1334 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1336 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1337 if (destination->details.exit_destination.af == AF_INET6)
1338 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1340 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1341 if (destination->details.exit_destination.af == AF_INET6)
1342 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1343 /* throw away IP-payload, exit will have to make it up anyway */
1344 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1346 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1347 if (destination->details.exit_destination.af == AF_INET6)
1348 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1349 /* throw away IP-payload, exit will have to make it up anyway */
1350 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1352 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1353 if (destination->details.exit_destination.af == AF_INET6)
1355 GNUNET_STATISTICS_update (stats,
1356 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1361 /* throw away IP-payload, exit will have to make it up anyway */
1362 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1365 GNUNET_STATISTICS_update (stats,
1366 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1371 /* end of AF_INET */
1376 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1377 if (destination->details.exit_destination.af == AF_INET6)
1378 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1379 /* throw away IP-payload, exit will have to make it up anyway */
1380 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1382 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1383 if (destination->details.exit_destination.af == AF_INET)
1384 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1385 /* throw away IP-payload, exit will have to make it up anyway */
1386 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1388 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1389 if (destination->details.exit_destination.af == AF_INET)
1391 GNUNET_STATISTICS_update (stats,
1392 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1397 /* throw away IP-payload, exit will have to make it up anyway */
1398 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1400 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1401 if (destination->details.exit_destination.af == AF_INET)
1403 GNUNET_STATISTICS_update (stats,
1404 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1409 /* throw away IP-payload, exit will have to make it up anyway */
1410 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1412 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1413 if (destination->details.exit_destination.af == AF_INET)
1414 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1416 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1417 if (destination->details.exit_destination.af == AF_INET)
1418 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1421 GNUNET_STATISTICS_update (stats,
1422 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1427 /* end of AF_INET6 */
1432 /* update length calculations, as payload_length may have changed */
1433 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1434 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1436 iim->header.size = htons ((uint16_t) mlen);
1438 /* need to tell destination ICMP protocol family! */
1439 iim->af = htonl (destination->details.exit_destination.af);
1440 switch (destination->details.exit_destination.af)
1443 ip4dst = (struct in_addr *) &iim[1];
1444 *ip4dst = destination->details.exit_destination.ip.v4;
1445 payload = &ip4dst[1];
1448 ip6dst = (struct in6_addr *) &iim[1];
1449 *ip6dst = destination->details.exit_destination.ip.v6;
1450 payload = &ip6dst[1];
1457 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1461 /* not supported above, how can we get here !? */
1465 send_to_tunnel (tnq, ts);
1470 * Receive packets from the helper-process (someone send to the local
1471 * virtual tunnel interface). Find the destination mapping, and if it
1472 * exists, identify the correct MESH tunnel (or possibly create it)
1473 * and forward the packet.
1475 * @param cls closure, NULL
1476 * @param client NULL
1477 * @param message message we got from the client (VPN tunnel interface)
1480 message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED,
1481 const struct GNUNET_MessageHeader *message)
1483 const struct GNUNET_TUN_Layer2PacketHeader *tun;
1485 GNUNET_HashCode key;
1486 struct DestinationEntry *de;
1488 GNUNET_STATISTICS_update (stats,
1489 gettext_noop ("# Packets received from TUN interface"),
1491 mlen = ntohs (message->size);
1492 if ( (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
1493 (mlen < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader)) )
1498 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1499 mlen -= (sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader));
1500 switch (ntohs (tun->proto))
1504 const struct GNUNET_TUN_IPv6Header *pkt6;
1506 if (mlen < sizeof (struct GNUNET_TUN_IPv6Header))
1512 pkt6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1513 get_destination_key_from_ip (AF_INET6,
1514 &pkt6->destination_address,
1516 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1517 /* FIXME: do we need to guard against hash collision?
1518 (if so, we need to also store the local destination IP in the
1519 destination entry and then compare here; however, the risk
1520 of collision seems minimal AND the impact is unlikely to be
1521 super-problematic as well... */
1524 char buf[INET6_ADDRSTRLEN];
1526 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1527 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1528 inet_ntop (AF_INET6,
1529 &pkt6->destination_address,
1537 &pkt6->source_address,
1538 &pkt6->destination_address,
1540 mlen - sizeof (struct GNUNET_TUN_IPv6Header));
1545 struct GNUNET_TUN_IPv4Header *pkt4;
1547 if (mlen < sizeof (struct GNUNET_TUN_IPv4Header))
1553 pkt4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1554 get_destination_key_from_ip (AF_INET,
1555 &pkt4->destination_address,
1557 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1558 /* FIXME: do we need to guard against hash collision?
1559 (if so, we need to also store the local destination IP in the
1560 destination entry and then compare here; however, the risk
1561 of collision seems minimal AND the impact is unlikely to be
1562 super-problematic as well... */
1565 char buf[INET_ADDRSTRLEN];
1567 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1568 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1570 &pkt4->destination_address,
1575 if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header))
1577 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1578 _("Received IPv4 packet with options (dropping it)\n"));
1584 &pkt4->source_address,
1585 &pkt4->destination_address,
1587 mlen - sizeof (struct GNUNET_TUN_IPv4Header));
1591 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1592 _("Received packet of unknown protocol %d from TUN (dropping it)\n"),
1593 (unsigned int) ntohs (tun->proto));
1600 * Synthesize a plausible ICMP payload for an ICMP error
1601 * response on the given tunnel.
1603 * @param ts tunnel information
1604 * @param ipp IPv4 header to fill in (ICMP payload)
1605 * @param udp "UDP" header to fill in (ICMP payload); might actually
1606 * also be the first 8 bytes of the TCP header
1609 make_up_icmpv4_payload (struct TunnelState *ts,
1610 struct GNUNET_TUN_IPv4Header *ipp,
1611 struct GNUNET_TUN_UdpHeader *udp)
1613 GNUNET_TUN_initialize_ipv4_header (ipp,
1615 sizeof (struct GNUNET_TUN_TcpHeader),
1617 &ts->destination_ip.v4);
1618 udp->spt = htons (ts->source_port);
1619 udp->dpt = htons (ts->destination_port);
1620 udp->len = htons (0);
1621 udp->crc = htons (0);
1626 * Synthesize a plausible ICMP payload for an ICMP error
1627 * response on the given tunnel.
1629 * @param ts tunnel information
1630 * @param ipp IPv6 header to fill in (ICMP payload)
1631 * @param udp "UDP" header to fill in (ICMP payload); might actually
1632 * also be the first 8 bytes of the TCP header
1635 make_up_icmpv6_payload (struct TunnelState *ts,
1636 struct GNUNET_TUN_IPv6Header *ipp,
1637 struct GNUNET_TUN_UdpHeader *udp)
1639 GNUNET_TUN_initialize_ipv6_header (ipp,
1641 sizeof (struct GNUNET_TUN_TcpHeader),
1643 &ts->destination_ip.v6);
1644 udp->spt = htons (ts->source_port);
1645 udp->dpt = htons (ts->destination_port);
1646 udp->len = htons (0);
1647 udp->crc = htons (0);
1652 * We got an ICMP packet back from the MESH tunnel. Pass it on to the
1653 * local virtual interface via the helper.
1655 * @param cls closure, NULL
1656 * @param tunnel connection to the other end
1657 * @param tunnel_ctx pointer to our 'struct TunnelState *'
1658 * @param sender who sent the message
1659 * @param message the actual message
1660 * @param atsi performance data for the connection
1661 * @return GNUNET_OK to keep the connection open,
1662 * GNUNET_SYSERR to close it (signal serious error)
1665 receive_icmp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1666 void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender,
1667 const struct GNUNET_MessageHeader *message,
1668 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
1670 struct TunnelState *ts = *tunnel_ctx;
1671 const struct GNUNET_EXIT_IcmpToVPNMessage *i2v;
1674 GNUNET_STATISTICS_update (stats,
1675 gettext_noop ("# ICMP packets received from mesh"),
1677 mlen = ntohs (message->size);
1678 if (mlen < sizeof (struct GNUNET_EXIT_IcmpToVPNMessage))
1680 GNUNET_break_op (0);
1681 return GNUNET_SYSERR;
1683 if (NULL == ts->heap_node)
1685 GNUNET_break_op (0);
1686 return GNUNET_SYSERR;
1688 if (AF_UNSPEC == ts->af)
1690 GNUNET_break_op (0);
1691 return GNUNET_SYSERR;
1693 i2v = (const struct GNUNET_EXIT_IcmpToVPNMessage *) message;
1694 mlen -= sizeof (struct GNUNET_EXIT_IcmpToVPNMessage);
1696 char sbuf[INET6_ADDRSTRLEN];
1697 char dbuf[INET6_ADDRSTRLEN];
1699 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1700 "Received ICMP packet from mesh, sending %u bytes from %s -> %s via TUN\n",
1701 (unsigned int) mlen,
1702 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
1703 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)));
1709 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
1710 + sizeof (struct GNUNET_TUN_IcmpHeader)
1711 + sizeof (struct GNUNET_MessageHeader) +
1712 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1715 /* reserve some extra space in case we have an ICMP type here where
1716 we will need to make up the payload ourselves */
1717 char buf[size + sizeof (struct GNUNET_TUN_IPv4Header) + 8];
1718 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1719 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1720 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1721 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv4[1];
1722 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1723 tun->flags = htons (0);
1724 tun->proto = htons (ETH_P_IPV4);
1725 GNUNET_TUN_initialize_ipv4_header (ipv4,
1727 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1728 &ts->destination_ip.v4,
1730 *icmp = i2v->icmp_header;
1734 /* For some ICMP types, we need to adjust (make up) the payload here.
1735 Also, depending on the AF used on the other side, we have to
1736 do ICMP PT (translate ICMP types) */
1737 switch (ntohl (i2v->af))
1742 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1743 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1745 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1746 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1747 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1749 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1750 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1754 /* sender did not strip ICMP payload? */
1755 GNUNET_break_op (0);
1756 return GNUNET_SYSERR;
1758 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1759 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1760 make_up_icmpv4_payload (ts, ipp, udp);
1764 GNUNET_break_op (0);
1765 GNUNET_STATISTICS_update (stats,
1766 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1768 return GNUNET_SYSERR;
1773 /* ICMP PT 6-to-4 and possibly making up payloads */
1776 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1777 icmp->type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
1779 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1780 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1784 /* sender did not strip ICMP payload? */
1785 GNUNET_break_op (0);
1786 return GNUNET_SYSERR;
1788 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1789 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1790 make_up_icmpv4_payload (ts, ipp, udp);
1793 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1794 icmp->type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1796 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1797 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1801 /* sender did not strip ICMP payload? */
1802 GNUNET_break_op (0);
1803 return GNUNET_SYSERR;
1805 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1806 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1807 make_up_icmpv4_payload (ts, ipp, udp);
1810 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1811 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1812 GNUNET_STATISTICS_update (stats,
1813 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1816 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1817 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1819 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1820 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1823 GNUNET_break_op (0);
1824 GNUNET_STATISTICS_update (stats,
1825 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1827 return GNUNET_SYSERR;
1832 GNUNET_break_op (0);
1833 return GNUNET_SYSERR;
1835 msg->size = htons (size);
1836 GNUNET_TUN_calculate_icmp_checksum (icmp,
1839 (void) GNUNET_HELPER_send (helper_handle,
1848 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
1849 + sizeof (struct GNUNET_TUN_IcmpHeader)
1850 + sizeof (struct GNUNET_MessageHeader) +
1851 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1854 char buf[size + sizeof (struct GNUNET_TUN_IPv6Header) + 8];
1855 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1856 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1857 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
1858 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv6[1];
1859 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1860 tun->flags = htons (0);
1861 tun->proto = htons (ETH_P_IPV6);
1862 GNUNET_TUN_initialize_ipv6_header (ipv6,
1864 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1865 &ts->destination_ip.v6,
1867 *icmp = i2v->icmp_header;
1872 /* For some ICMP types, we need to adjust (make up) the payload here.
1873 Also, depending on the AF used on the other side, we have to
1874 do ICMP PT (translate ICMP types) */
1875 switch (ntohl (i2v->af))
1878 /* ICMP PT 4-to-6 and possibly making up payloads */
1881 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1882 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1884 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1885 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1887 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1888 icmp->type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1890 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1891 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1895 /* sender did not strip ICMP payload? */
1896 GNUNET_break_op (0);
1897 return GNUNET_SYSERR;
1899 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1900 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1901 make_up_icmpv6_payload (ts, ipp, udp);
1904 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1905 icmp->type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1907 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1908 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1912 /* sender did not strip ICMP payload? */
1913 GNUNET_break_op (0);
1914 return GNUNET_SYSERR;
1916 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1917 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1918 make_up_icmpv6_payload (ts, ipp, udp);
1921 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1922 GNUNET_STATISTICS_update (stats,
1923 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1927 GNUNET_break_op (0);
1928 GNUNET_STATISTICS_update (stats,
1929 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1931 return GNUNET_SYSERR;
1938 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1939 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1940 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1941 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1943 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1944 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1948 /* sender did not strip ICMP payload? */
1949 GNUNET_break_op (0);
1950 return GNUNET_SYSERR;
1952 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1953 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1954 make_up_icmpv6_payload (ts, ipp, udp);
1957 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1960 GNUNET_break_op (0);
1961 GNUNET_STATISTICS_update (stats,
1962 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1964 return GNUNET_SYSERR;
1969 GNUNET_break_op (0);
1970 return GNUNET_SYSERR;
1972 msg->size = htons (size);
1973 GNUNET_TUN_calculate_icmp_checksum (icmp,
1975 (void) GNUNET_HELPER_send (helper_handle,
1985 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
1987 GNUNET_TIME_absolute_get ().abs_value);
1993 * We got a UDP packet back from the MESH tunnel. Pass it on to the
1994 * local virtual interface via the helper.
1996 * @param cls closure, NULL
1997 * @param tunnel connection to the other end
1998 * @param tunnel_ctx pointer to our 'struct TunnelState *'
1999 * @param sender who sent the message
2000 * @param message the actual message
2001 * @param atsi performance data for the connection
2002 * @return GNUNET_OK to keep the connection open,
2003 * GNUNET_SYSERR to close it (signal serious error)
2006 receive_udp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
2007 void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender,
2008 const struct GNUNET_MessageHeader *message,
2009 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
2011 struct TunnelState *ts = *tunnel_ctx;
2012 const struct GNUNET_EXIT_UdpReplyMessage *reply;
2015 GNUNET_STATISTICS_update (stats,
2016 gettext_noop ("# UDP packets received from mesh"),
2018 mlen = ntohs (message->size);
2019 if (mlen < sizeof (struct GNUNET_EXIT_UdpReplyMessage))
2021 GNUNET_break_op (0);
2022 return GNUNET_SYSERR;
2024 if (NULL == ts->heap_node)
2026 GNUNET_break_op (0);
2027 return GNUNET_SYSERR;
2029 if (AF_UNSPEC == ts->af)
2031 GNUNET_break_op (0);
2032 return GNUNET_SYSERR;
2034 reply = (const struct GNUNET_EXIT_UdpReplyMessage *) message;
2035 mlen -= sizeof (struct GNUNET_EXIT_UdpReplyMessage);
2037 char sbuf[INET6_ADDRSTRLEN];
2038 char dbuf[INET6_ADDRSTRLEN];
2040 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2041 "Received UDP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2042 (unsigned int) mlen,
2043 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2044 ts->destination_port,
2045 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2052 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2053 + sizeof (struct GNUNET_TUN_UdpHeader)
2054 + sizeof (struct GNUNET_MessageHeader) +
2055 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2059 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2060 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2061 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2062 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1];
2063 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2064 msg->size = htons (size);
2065 tun->flags = htons (0);
2066 tun->proto = htons (ETH_P_IPV4);
2067 GNUNET_TUN_initialize_ipv4_header (ipv4,
2069 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2070 &ts->destination_ip.v4,
2072 if (0 == ntohs (reply->source_port))
2073 udp->spt = htons (ts->destination_port);
2075 udp->spt = reply->source_port;
2076 if (0 == ntohs (reply->destination_port))
2077 udp->dpt = htons (ts->source_port);
2079 udp->dpt = reply->destination_port;
2080 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2081 GNUNET_TUN_calculate_udp4_checksum (ipv4,
2088 (void) GNUNET_HELPER_send (helper_handle,
2097 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2098 + sizeof (struct GNUNET_TUN_UdpHeader)
2099 + sizeof (struct GNUNET_MessageHeader) +
2100 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2104 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2105 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2106 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2107 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1];
2108 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2109 msg->size = htons (size);
2110 tun->flags = htons (0);
2111 tun->proto = htons (ETH_P_IPV6);
2112 GNUNET_TUN_initialize_ipv6_header (ipv6,
2114 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2115 &ts->destination_ip.v6,
2117 if (0 == ntohs (reply->source_port))
2118 udp->spt = htons (ts->destination_port);
2120 udp->spt = reply->source_port;
2121 if (0 == ntohs (reply->destination_port))
2122 udp->dpt = htons (ts->source_port);
2124 udp->dpt = reply->destination_port;
2125 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2126 GNUNET_TUN_calculate_udp6_checksum (ipv6,
2132 (void) GNUNET_HELPER_send (helper_handle,
2142 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2144 GNUNET_TIME_absolute_get ().abs_value);
2150 * We got a TCP packet back from the MESH tunnel. Pass it on to the
2151 * local virtual interface via the helper.
2153 * @param cls closure, NULL
2154 * @param tunnel connection to the other end
2155 * @param tunnel_ctx pointer to our 'struct TunnelState *'
2156 * @param sender who sent the message
2157 * @param message the actual message
2158 * @param atsi performance data for the connection
2159 * @return GNUNET_OK to keep the connection open,
2160 * GNUNET_SYSERR to close it (signal serious error)
2163 receive_tcp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
2165 const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED,
2166 const struct GNUNET_MessageHeader *message,
2167 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
2169 struct TunnelState *ts = *tunnel_ctx;
2170 const struct GNUNET_EXIT_TcpDataMessage *data;
2173 GNUNET_STATISTICS_update (stats,
2174 gettext_noop ("# TCP packets received from mesh"),
2176 mlen = ntohs (message->size);
2177 if (mlen < sizeof (struct GNUNET_EXIT_TcpDataMessage))
2179 GNUNET_break_op (0);
2180 return GNUNET_SYSERR;
2182 if (NULL == ts->heap_node)
2184 GNUNET_break_op (0);
2185 return GNUNET_SYSERR;
2187 data = (const struct GNUNET_EXIT_TcpDataMessage *) message;
2188 mlen -= sizeof (struct GNUNET_EXIT_TcpDataMessage);
2190 char sbuf[INET6_ADDRSTRLEN];
2191 char dbuf[INET6_ADDRSTRLEN];
2193 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2194 "Received TCP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2195 (unsigned int) mlen,
2196 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2197 ts->destination_port,
2198 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2205 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2206 + sizeof (struct GNUNET_TUN_TcpHeader)
2207 + sizeof (struct GNUNET_MessageHeader) +
2208 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2212 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2213 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2214 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2215 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv4[1];
2216 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2217 msg->size = htons (size);
2218 tun->flags = htons (0);
2219 tun->proto = htons (ETH_P_IPV4);
2220 GNUNET_TUN_initialize_ipv4_header (ipv4,
2222 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2223 &ts->destination_ip.v4,
2225 *tcp = data->tcp_header;
2226 tcp->spt = htons (ts->destination_port);
2227 tcp->dpt = htons (ts->source_port);
2228 GNUNET_TUN_calculate_tcp4_checksum (ipv4,
2235 (void) GNUNET_HELPER_send (helper_handle,
2244 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2245 + sizeof (struct GNUNET_TUN_TcpHeader)
2246 + sizeof (struct GNUNET_MessageHeader) +
2247 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2251 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2252 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2253 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2254 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv6[1];
2255 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2256 msg->size = htons (size);
2257 tun->flags = htons (0);
2258 tun->proto = htons (ETH_P_IPV6);
2259 GNUNET_TUN_initialize_ipv6_header (ipv6,
2261 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2262 &ts->destination_ip.v6,
2264 tcp->spt = htons (ts->destination_port);
2265 tcp->dpt = htons (ts->source_port);
2266 GNUNET_TUN_calculate_tcp6_checksum (ipv6,
2270 (void) GNUNET_HELPER_send (helper_handle,
2278 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2280 GNUNET_TIME_absolute_get ().abs_value);
2286 * Allocate an IPv4 address from the range of the tunnel
2287 * for a new redirection.
2289 * @param v4 where to store the address
2290 * @return GNUNET_OK on success,
2291 * GNUNET_SYSERR on error
2294 allocate_v4_address (struct in_addr *v4)
2296 const char *ipv4addr = vpn_argv[4];
2297 const char *ipv4mask = vpn_argv[5];
2298 struct in_addr addr;
2299 struct in_addr mask;
2301 GNUNET_HashCode key;
2304 GNUNET_assert (1 == inet_pton (AF_INET, ipv4addr, &addr));
2305 GNUNET_assert (1 == inet_pton (AF_INET, ipv4mask, &mask));
2306 /* Given 192.168.0.1/255.255.0.0, we want a mask
2307 of '192.168.255.255', thus: */
2308 mask.s_addr = addr.s_addr | ~mask.s_addr;
2315 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2316 _("Failed to find unallocated IPv4 address in VPN's range\n"));
2317 return GNUNET_SYSERR;
2319 /* Pick random IPv4 address within the subnet, except 'addr' or 'mask' itself */
2320 rnd.s_addr = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2322 v4->s_addr = (addr.s_addr | rnd.s_addr) & mask.s_addr;
2323 get_destination_key_from_ip (AF_INET,
2327 while ( (GNUNET_YES ==
2328 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2330 (v4->s_addr == addr.s_addr) ||
2331 (v4->s_addr == mask.s_addr) );
2337 * Allocate an IPv6 address from the range of the tunnel
2338 * for a new redirection.
2340 * @param v6 where to store the address
2341 * @return GNUNET_OK on success,
2342 * GNUNET_SYSERR on error
2345 allocate_v6_address (struct in6_addr *v6)
2347 const char *ipv6addr = vpn_argv[2];
2348 struct in6_addr addr;
2349 struct in6_addr mask;
2350 struct in6_addr rnd;
2352 GNUNET_HashCode key;
2355 GNUNET_assert (1 == inet_pton (AF_INET6, ipv6addr, &addr));
2356 GNUNET_assert (ipv6prefix < 128);
2357 /* Given ABCD::/96, we want a mask of 'ABCD::FFFF:FFFF,
2360 for (i=127;i>=128-ipv6prefix;i--)
2361 mask.s6_addr[i / 8] |= (1 << (i % 8));
2363 /* Pick random IPv6 address within the subnet, except 'addr' or 'mask' itself */
2370 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2371 _("Failed to find unallocated IPv6 address in VPN's range\n"));
2372 return GNUNET_SYSERR;
2377 rnd.s6_addr[i] = (unsigned char) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2380 = (addr.s6_addr[i] | rnd.s6_addr[i]) & mask.s6_addr[i];
2382 get_destination_key_from_ip (AF_INET6,
2386 while ( (GNUNET_YES ==
2387 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2391 sizeof (struct in6_addr))) ||
2394 sizeof (struct in6_addr))) );
2400 * Free resources occupied by a destination entry.
2402 * @param de entry to free
2405 free_destination_entry (struct DestinationEntry *de)
2407 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2408 "Cleaning up destination entry\n");
2409 GNUNET_STATISTICS_update (stats,
2410 gettext_noop ("# Active destinations"),
2414 free_tunnel_state (de->ts);
2415 GNUNET_assert (NULL == de->ts);
2417 if (NULL != de->heap_node)
2419 GNUNET_CONTAINER_heap_remove_node (de->heap_node);
2420 de->heap_node = NULL;
2421 GNUNET_assert (GNUNET_YES ==
2422 GNUNET_CONTAINER_multihashmap_remove (destination_map,
2431 * We have too many active destinations. Clean up the oldest destination.
2433 * @param except destination that must NOT be cleaned up, even if it is the oldest
2436 expire_destination (struct DestinationEntry *except)
2438 struct DestinationEntry *de;
2440 de = GNUNET_CONTAINER_heap_peek (destination_heap);
2441 GNUNET_assert (NULL != de);
2443 return; /* can't do this */
2444 free_destination_entry (de);
2449 * A client asks us to setup a redirection via some exit
2450 * node to a particular IP. Setup the redirection and
2451 * give the client the allocated IP.
2454 * @param client requesting client
2455 * @param message redirection request (a 'struct RedirectToIpRequestMessage')
2458 service_redirect_to_ip (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
2459 const struct GNUNET_MessageHeader *message)
2463 const struct RedirectToIpRequestMessage *msg;
2469 struct DestinationEntry *de;
2470 GNUNET_HashCode key;
2471 struct TunnelState *ts;
2473 /* validate and parse request */
2474 mlen = ntohs (message->size);
2475 if (mlen < sizeof (struct RedirectToIpRequestMessage))
2478 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2481 alen = mlen - sizeof (struct RedirectToIpRequestMessage);
2482 msg = (const struct RedirectToIpRequestMessage *) message;
2483 addr_af = (int) htonl (msg->addr_af);
2487 if (alen != sizeof (struct in_addr))
2490 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2495 if (alen != sizeof (struct in6_addr))
2498 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2504 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2508 /* allocate response IP */
2510 result_af = (int) htonl (msg->result_af);
2515 allocate_v4_address (&v4))
2516 result_af = AF_UNSPEC;
2522 allocate_v6_address (&v6))
2523 result_af = AF_UNSPEC;
2529 allocate_v4_address (&v4))
2532 result_af = AF_INET;
2534 else if (GNUNET_OK ==
2535 allocate_v6_address (&v6))
2538 result_af = AF_INET6;
2543 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2546 if ( (result_af == AF_UNSPEC) ||
2547 (GNUNET_NO == ntohl (msg->nac)) )
2549 /* send reply "instantly" */
2550 send_client_reply (client,
2555 if (result_af == AF_UNSPEC)
2557 /* failure, we're done */
2558 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2563 char sbuf[INET6_ADDRSTRLEN];
2564 char dbuf[INET6_ADDRSTRLEN];
2566 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2567 "Allocated address %s for redirection via exit to %s\n",
2568 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2570 &msg[1], dbuf, sizeof (dbuf)));
2573 /* setup destination record */
2574 de = GNUNET_malloc (sizeof (struct DestinationEntry));
2575 de->is_service = GNUNET_NO;
2576 de->details.exit_destination.af = addr_af;
2577 memcpy (&de->details.exit_destination.ip,
2580 get_destination_key_from_ip (result_af,
2584 GNUNET_assert (GNUNET_OK ==
2585 GNUNET_CONTAINER_multihashmap_put (destination_map,
2588 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2589 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2591 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
2592 GNUNET_STATISTICS_update (stats,
2593 gettext_noop ("# Active destinations"),
2595 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2596 expire_destination (de);
2598 /* setup tunnel to destination */
2599 ts = create_tunnel_to_destination (de,
2600 (GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
2606 ts->destination_ip.v4 = v4;
2609 ts->destination_ip.v6 = v6;
2615 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2620 * A client asks us to setup a redirection to a particular peer
2621 * offering a service. Setup the redirection and give the client the
2625 * @param client requesting client
2626 * @param message redirection request (a 'struct RedirectToPeerRequestMessage')
2629 service_redirect_to_service (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
2630 const struct GNUNET_MessageHeader *message)
2632 const struct RedirectToServiceRequestMessage *msg;
2637 struct DestinationEntry *de;
2638 GNUNET_HashCode key;
2639 struct TunnelState *ts;
2642 msg = (const struct RedirectToServiceRequestMessage *) message;
2644 /* allocate response IP */
2646 result_af = (int) htonl (msg->result_af);
2651 allocate_v4_address (&v4))
2652 result_af = AF_UNSPEC;
2658 allocate_v6_address (&v6))
2659 result_af = AF_UNSPEC;
2665 allocate_v4_address (&v4))
2668 result_af = AF_INET;
2670 else if (GNUNET_OK ==
2671 allocate_v6_address (&v6))
2674 result_af = AF_INET6;
2679 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2682 if ( (result_af == AF_UNSPEC) ||
2683 (GNUNET_NO == ntohl (msg->nac)) )
2685 /* send reply "instantly" */
2686 send_client_reply (client,
2691 if (result_af == AF_UNSPEC)
2693 /* failure, we're done */
2694 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2695 _("Failed to allocate IP address for new destination\n"));
2696 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2701 char sbuf[INET6_ADDRSTRLEN];
2703 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2704 "Allocated address %s for redirection to service %s on peer %s\n",
2705 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2706 GNUNET_h2s (&msg->service_descriptor),
2707 GNUNET_i2s (&msg->target));
2710 /* setup destination record */
2711 de = GNUNET_malloc (sizeof (struct DestinationEntry));
2712 de->is_service = GNUNET_YES;
2713 de->details.service_destination.service_descriptor = msg->service_descriptor;
2714 de->details.service_destination.target = msg->target;
2715 get_destination_key_from_ip (result_af,
2719 GNUNET_assert (GNUNET_OK ==
2720 GNUNET_CONTAINER_multihashmap_put (destination_map,
2723 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2724 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2726 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
2727 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2728 expire_destination (de);
2729 ts = create_tunnel_to_destination (de,
2730 (GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
2736 ts->destination_ip.v4 = v4;
2739 ts->destination_ip.v6 = v6;
2745 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2751 * Function called for inbound tunnels. As we don't offer
2752 * any mesh services, this function should never be called.
2754 * @param cls closure
2755 * @param tunnel new handle to the tunnel
2756 * @param initiator peer that started the tunnel
2757 * @param atsi performance information for the tunnel
2758 * @return initial tunnel context for the tunnel
2759 * (can be NULL -- that's not an error)
2762 inbound_tunnel_cb (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
2763 const struct GNUNET_PeerIdentity *initiator,
2764 const struct GNUNET_ATS_Information *atsi)
2766 /* How can and why should anyone open an inbound tunnel to vpn? */
2773 * Function called whenever an inbound tunnel is destroyed. Should clean up
2774 * any associated state.
2776 * @param cls closure (set from GNUNET_MESH_connect)
2777 * @param tunnel connection to the other end (henceforth invalid)
2778 * @param tunnel_ctx place where local state associated
2779 * with the tunnel is stored (our 'struct TunnelState')
2782 tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel_ctx)
2784 /* we don't have inbound tunnels, so this function should never be called */
2790 * Free memory occupied by an entry in the destination map.
2794 * @param value a 'struct DestinationEntry *'
2795 * @return GNUNET_OK (continue to iterate)
2798 cleanup_destination (void *cls,
2799 const GNUNET_HashCode *key,
2802 struct DestinationEntry *de = value;
2804 free_destination_entry (de);
2810 * Free memory occupied by an entry in the tunnel map.
2814 * @param value a 'struct TunnelState *'
2815 * @return GNUNET_OK (continue to iterate)
2818 cleanup_tunnel (void *cls,
2819 const GNUNET_HashCode *key,
2822 struct TunnelState *ts = value;
2824 free_tunnel_state (ts);
2830 * Function scheduled as very last function, cleans up after us
2836 cleanup (void *cls GNUNET_UNUSED,
2837 const struct GNUNET_SCHEDULER_TaskContext *tc)
2841 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2842 "VPN is shutting down\n");
2843 if (NULL != destination_map)
2845 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
2846 &cleanup_destination,
2848 GNUNET_CONTAINER_multihashmap_destroy (destination_map);
2849 destination_map = NULL;
2851 if (NULL != destination_heap)
2853 GNUNET_CONTAINER_heap_destroy (destination_heap);
2854 destination_heap = NULL;
2856 if (NULL != tunnel_map)
2858 GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
2861 GNUNET_CONTAINER_multihashmap_destroy (tunnel_map);
2864 if (NULL != tunnel_heap)
2866 GNUNET_CONTAINER_heap_destroy (tunnel_heap);
2869 if (NULL != mesh_handle)
2871 GNUNET_MESH_disconnect (mesh_handle);
2874 if (NULL != helper_handle)
2876 GNUNET_HELPER_stop (helper_handle);
2877 helper_handle = NULL;
2881 GNUNET_SERVER_notification_context_destroy (nc);
2886 GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
2890 GNUNET_free_non_null (vpn_argv[i]);
2895 * A client disconnected, clean up all references to it.
2897 * @param cls the client that disconnected
2899 * @param value a 'struct TunnelState *'
2900 * @return GNUNET_OK (continue to iterate)
2903 cleanup_tunnel_client (void *cls,
2904 const GNUNET_HashCode *key,
2907 struct GNUNET_SERVER_Client *client = cls;
2908 struct TunnelState *ts = value;
2910 if (client == ts->client)
2912 GNUNET_SERVER_client_drop (ts->client);
2920 * A client disconnected, clean up all references to it.
2922 * @param cls the client that disconnected
2924 * @param value a 'struct DestinationEntry *'
2925 * @return GNUNET_OK (continue to iterate)
2928 cleanup_destination_client (void *cls,
2929 const GNUNET_HashCode *key,
2932 struct GNUNET_SERVER_Client *client = cls;
2933 struct DestinationEntry *de = value;
2934 struct TunnelState *ts;
2936 if (NULL == (ts = de->ts))
2938 if (client == ts->client)
2940 GNUNET_SERVER_client_drop (ts->client);
2948 * A client has disconnected from us. If we are currently building
2949 * a tunnel for it, cancel the operation.
2952 * @param client handle to the client that disconnected
2955 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
2957 if (NULL != tunnel_map)
2958 GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
2959 &cleanup_tunnel_client,
2961 if (NULL != destination_map)
2962 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
2963 &cleanup_destination_client,
2969 * Main function that will be run by the scheduler.
2971 * @param cls closure
2972 * @param server the initialized server
2973 * @param cfg_ configuration
2977 struct GNUNET_SERVER_Handle *server,
2978 const struct GNUNET_CONFIGURATION_Handle *cfg_)
2980 static const struct GNUNET_SERVER_MessageHandler service_handlers[] = {
2981 /* callback, cls, type, size */
2982 { &service_redirect_to_ip, NULL, GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP, 0},
2983 { &service_redirect_to_service, NULL,
2984 GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE,
2985 sizeof (struct RedirectToServiceRequestMessage) },
2988 static const struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
2989 { &receive_udp_back, GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY, 0},
2990 { &receive_tcp_back, GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN, 0},
2991 { &receive_icmp_back, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN, 0},
2994 static const GNUNET_MESH_ApplicationType types[] = {
2995 GNUNET_APPLICATION_TYPE_END
3006 stats = GNUNET_STATISTICS_create ("vpn", cfg);
3008 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_MAPPING",
3009 &max_destination_mappings))
3010 max_destination_mappings = 200;
3012 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_TUNNELS",
3013 &max_tunnel_mappings))
3014 max_tunnel_mappings = 200;
3016 destination_map = GNUNET_CONTAINER_multihashmap_create (max_destination_mappings * 2);
3017 destination_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3018 tunnel_map = GNUNET_CONTAINER_multihashmap_create (max_tunnel_mappings * 2);
3019 tunnel_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3022 vpn_argv[0] = GNUNET_strdup ("vpn-gnunet");
3023 if (GNUNET_SYSERR ==
3024 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IFNAME", &ifname))
3026 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3027 "No entry 'IFNAME' in configuration!\n");
3028 GNUNET_SCHEDULER_shutdown ();
3031 vpn_argv[1] = ifname;
3032 if ( (GNUNET_SYSERR ==
3033 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6ADDR",
3035 (1 != inet_pton (AF_INET6, ipv6addr, &v6))) )
3037 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3038 "No valid entry 'IPV6ADDR' in configuration!\n");
3039 GNUNET_SCHEDULER_shutdown ();
3042 vpn_argv[2] = ipv6addr;
3043 if (GNUNET_SYSERR ==
3044 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6PREFIX",
3047 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3048 "No entry 'IPV6PREFIX' in configuration!\n");
3049 GNUNET_SCHEDULER_shutdown ();
3052 vpn_argv[3] = ipv6prefix_s;
3054 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn",
3057 (ipv6prefix >= 127) )
3059 GNUNET_SCHEDULER_shutdown ();
3063 if ( (GNUNET_SYSERR ==
3064 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4ADDR",
3066 (1 != inet_pton (AF_INET, ipv4addr, &v4))) )
3068 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3069 "No valid entry for 'IPV4ADDR' in configuration!\n");
3070 GNUNET_SCHEDULER_shutdown ();
3073 vpn_argv[4] = ipv4addr;
3074 if ( (GNUNET_SYSERR ==
3075 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4MASK",
3077 (1 != inet_pton (AF_INET, ipv4mask, &v4))) )
3079 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3080 "No valid entry 'IPV4MASK' in configuration!\n");
3081 GNUNET_SCHEDULER_shutdown ();
3084 vpn_argv[5] = ipv4mask;
3088 GNUNET_MESH_connect (cfg_, 42 /* queue length */, NULL,
3093 helper_handle = GNUNET_HELPER_start ("gnunet-helper-vpn", vpn_argv,
3094 &message_token, NULL);
3095 nc = GNUNET_SERVER_notification_context_create (server, 1);
3096 GNUNET_SERVER_add_handlers (server, service_handlers);
3097 GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
3098 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls);
3103 * The main function of the VPN service.
3105 * @param argc number of arguments from the command line
3106 * @param argv command line arguments
3107 * @return 0 ok, 1 on error
3110 main (int argc, char *const *argv)
3112 return (GNUNET_OK ==
3113 GNUNET_SERVICE_run (argc, argv, "vpn",
3114 GNUNET_SERVICE_OPTION_NONE,
3115 &run, NULL)) ? 0 : 1;
3118 /* end of gnunet-service-vpn.c */