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 * Return value from 'main'.
290 static int global_ret;
293 * Configuration we use.
295 static const struct GNUNET_CONFIGURATION_Handle *cfg;
298 * Handle to the mesh service.
300 static struct GNUNET_MESH_Handle *mesh_handle;
303 * Map from IP address to destination information (possibly with a
304 * MESH tunnel handle for fast setup).
306 static struct GNUNET_CONTAINER_MultiHashMap *destination_map;
309 * Min-Heap sorted by activity time to expire old mappings.
311 static struct GNUNET_CONTAINER_Heap *destination_heap;
314 * Map from source and destination address (IP+port) to connection
315 * information (mostly with the respective MESH tunnel handle).
317 static struct GNUNET_CONTAINER_MultiHashMap *tunnel_map;
320 * Min-Heap sorted by activity time to expire old mappings; values are
321 * of type 'struct TunnelState'.
323 static struct GNUNET_CONTAINER_Heap *tunnel_heap;
328 static struct GNUNET_STATISTICS_Handle *stats;
331 * The handle to the VPN helper process "gnunet-helper-vpn".
333 static struct GNUNET_HELPER_Handle *helper_handle;
336 * Arguments to the vpn helper.
338 static char *vpn_argv[7];
341 * Length of the prefix of the VPN's IPv6 network.
343 static unsigned long long ipv6prefix;
346 * Notification context for sending replies to clients.
348 static struct GNUNET_SERVER_NotificationContext *nc;
351 * If there are more than this number of address-mappings, old ones
354 static unsigned long long max_destination_mappings;
357 * If there are more than this number of open tunnels, old ones
360 static unsigned long long max_tunnel_mappings;
364 * Compute the key under which we would store an entry in the
365 * destination_map for the given IP address.
367 * @param af address family (AF_INET or AF_INET6)
368 * @param address IP address, struct in_addr or struct in6_addr
369 * @param key where to store the key
372 get_destination_key_from_ip (int af,
374 GNUNET_HashCode *key)
379 GNUNET_CRYPTO_hash (address,
380 sizeof (struct in_addr),
384 GNUNET_CRYPTO_hash (address,
385 sizeof (struct in6_addr),
396 * Compute the key under which we would store an entry in the
397 * tunnel_map for the given socket address pair.
399 * @param af address family (AF_INET or AF_INET6)
400 * @param protocol IPPROTO_TCP or IPPROTO_UDP
401 * @param source_ip sender's source IP, struct in_addr or struct in6_addr
402 * @param source_port sender's source port
403 * @param destination_ip sender's destination IP, struct in_addr or struct in6_addr
404 * @param destination_port sender's destination port
405 * @param key where to store the key
408 get_tunnel_key_from_ips (int af,
410 const void *source_ip,
411 uint16_t source_port,
412 const void *destination_ip,
413 uint16_t destination_port,
414 GNUNET_HashCode *key)
418 memset (key, 0, sizeof (GNUNET_HashCode));
419 /* the GNUnet hashmap only uses the first sizeof(unsigned int) of the hash,
420 so we put the ports in there (and hope for few collisions) */
422 memcpy (off, &source_port, sizeof (uint16_t));
423 off += sizeof (uint16_t);
424 memcpy (off, &destination_port, sizeof (uint16_t));
425 off += sizeof (uint16_t);
429 memcpy (off, source_ip, sizeof (struct in_addr));
430 off += sizeof (struct in_addr);
431 memcpy (off, destination_ip, sizeof (struct in_addr));
432 off += sizeof (struct in_addr);
435 memcpy (off, source_ip, sizeof (struct in6_addr));
436 off += sizeof (struct in6_addr);
437 memcpy (off, destination_ip, sizeof (struct in6_addr));
438 off += sizeof (struct in6_addr);
444 memcpy (off, &protocol, sizeof (uint8_t));
445 off += sizeof (uint8_t);
450 * Notify the client about the result of its request.
452 * @param client client to notify
453 * @param request_id original request ID to include in response
454 * @param result_af resulting address family
455 * @param addr resulting IP address
458 send_client_reply (struct GNUNET_SERVER_Client *client,
463 char buf[sizeof (struct RedirectToIpResponseMessage) + sizeof (struct in6_addr)];
464 struct RedirectToIpResponseMessage *res;
470 rlen = sizeof (struct in_addr);
473 rlen = sizeof (struct in6_addr);
482 res = (struct RedirectToIpResponseMessage *) buf;
483 res->header.size = htons (sizeof (struct RedirectToIpResponseMessage) + rlen);
484 res->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP);
485 res->result_af = htonl (result_af);
486 res->request_id = request_id;
487 memcpy (&res[1], addr, rlen);
488 GNUNET_SERVER_notification_context_add (nc, client);
489 GNUNET_SERVER_notification_context_unicast (nc,
497 * Free resources associated with a tunnel state.
499 * @param ts state to free
502 free_tunnel_state (struct TunnelState *ts)
505 struct TunnelMessageQueueEntry *tnq;
506 struct GNUNET_MESH_Tunnel *tunnel;
508 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
509 "Cleaning up tunnel state\n");
510 GNUNET_STATISTICS_update (stats,
511 gettext_noop ("# Active tunnels"),
513 while (NULL != (tnq = ts->tmq_head))
515 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
521 GNUNET_assert (0 == ts->tmq_length);
522 if (NULL != ts->client)
524 GNUNET_SERVER_client_drop (ts->client);
529 GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
532 GNUNET_assert (NULL == ts->destination.heap_node);
533 if (NULL != (tunnel = ts->tunnel))
536 GNUNET_MESH_tunnel_destroy (tunnel);
538 if (GNUNET_SCHEDULER_NO_TASK != ts->destroy_task)
540 GNUNET_SCHEDULER_cancel (ts->destroy_task);
541 ts->destroy_task = GNUNET_SCHEDULER_NO_TASK;
543 if (NULL != ts->heap_node)
545 GNUNET_CONTAINER_heap_remove_node (ts->heap_node);
546 ts->heap_node = NULL;
547 get_tunnel_key_from_ips (ts->af,
552 ts->destination_port,
554 GNUNET_assert (GNUNET_YES ==
555 GNUNET_CONTAINER_multihashmap_remove (tunnel_map,
559 if (NULL != ts->destination_container)
561 GNUNET_assert (ts == ts->destination_container->ts);
562 ts->destination_container->ts = NULL;
563 ts->destination_container = NULL;
570 * Destroy the mesh tunnel.
572 * @param cls the 'struct TunnelState' with the tunnel to destroy
573 * @param tc scheduler context
576 destroy_tunnel_task (void *cls,
577 const struct GNUNET_SCHEDULER_TaskContext *tc)
579 struct TunnelState *ts = cls;
580 struct GNUNET_MESH_Tunnel *tunnel;
582 ts->destroy_task = GNUNET_SCHEDULER_NO_TASK;
583 GNUNET_assert (NULL != ts->tunnel);
586 GNUNET_MESH_tunnel_destroy (tunnel);
587 free_tunnel_state (ts);
592 * Method called whenever a peer has disconnected from the tunnel.
595 * @param peer peer identity the tunnel stopped working with
598 tunnel_peer_disconnect_handler (void *cls,
600 GNUNET_PeerIdentity * peer)
602 struct TunnelState *ts = cls;
604 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
605 "Peer %s disconnected from tunnel.\n",
607 GNUNET_STATISTICS_update (stats,
608 gettext_noop ("# Peers connected to mesh tunnels"),
612 GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
615 if (ts->destination.is_service)
616 return; /* hope for reconnect eventually */
617 /* as we are most likely going to change the exit node now,
618 we should just destroy the tunnel entirely... */
619 if (GNUNET_SCHEDULER_NO_TASK == ts->destroy_task)
620 ts->destroy_task = GNUNET_SCHEDULER_add_now (&destroy_tunnel_task, ts);
625 * Method called whenever a peer has connected to the tunnel. Notifies
626 * the waiting client that the tunnel is now up.
629 * @param peer peer identity the tunnel was created to, NULL on timeout
630 * @param atsi performance data for the connection
633 tunnel_peer_connect_handler (void *cls,
634 const struct GNUNET_PeerIdentity
637 GNUNET_ATS_Information * atsi)
639 struct TunnelState *ts = cls;
641 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
642 "Peer %s connected to tunnel.\n",
644 GNUNET_STATISTICS_update (stats,
645 gettext_noop ("# Peers connected to mesh tunnels"),
647 if (NULL == ts->client)
648 return; /* nothing to do */
649 send_client_reply (ts->client,
652 &ts->destination_ip);
653 GNUNET_SERVER_client_drop (ts->client);
659 * Send a message from the message queue via mesh.
661 * @param cls the 'struct TunnelState' with the message queue
662 * @param size number of bytes available in buf
663 * @param buf where to copy the message
664 * @return number of bytes copied to buf
667 send_to_peer_notify_callback (void *cls, size_t size, void *buf)
669 struct TunnelState *ts = cls;
670 struct TunnelMessageQueueEntry *tnq;
677 GNUNET_assert (NULL != tnq);
678 GNUNET_assert (size >= tnq->len);
679 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
680 "Sending %u bytes via mesh tunnel\n",
682 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
686 memcpy (buf, tnq->msg, tnq->len);
689 if (NULL != (tnq = ts->tmq_head))
690 ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel,
691 GNUNET_NO /* cork */,
693 GNUNET_TIME_UNIT_FOREVER_REL,
696 &send_to_peer_notify_callback,
698 GNUNET_STATISTICS_update (stats,
699 gettext_noop ("# Bytes given to mesh for transmission"),
706 * Add the given message to the given tunnel and trigger the
707 * transmission process.
709 * @param tnq message to queue
710 * @param ts tunnel to queue the message for
713 send_to_tunnel (struct TunnelMessageQueueEntry *tnq,
714 struct TunnelState *ts)
716 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
717 "Queueing %u bytes for transmission via mesh tunnel\n",
719 GNUNET_assert (NULL != ts->tunnel);
720 GNUNET_CONTAINER_DLL_insert_tail (ts->tmq_head,
724 if (ts->tmq_length > MAX_MESSAGE_QUEUE_SIZE)
726 struct TunnelMessageQueueEntry *dq;
729 GNUNET_assert (dq != tnq);
730 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
734 GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
736 GNUNET_STATISTICS_update (stats,
737 gettext_noop ("# Bytes dropped in mesh queue (overflow)"),
743 ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel,
744 GNUNET_NO /* cork */,
746 GNUNET_TIME_UNIT_FOREVER_REL,
749 &send_to_peer_notify_callback,
755 * Initialize the given destination entry's mesh tunnel.
757 * @param de destination entry for which we need to setup a tunnel
758 * @param client client to notify on successful tunnel setup, or NULL for none
759 * @param client_af address family of the address returned to the client
760 * @param request_id request ID to send in client notification (unused if client is NULL)
761 * @return tunnel state of the tunnel that was created
763 static struct TunnelState *
764 create_tunnel_to_destination (struct DestinationEntry *de,
765 struct GNUNET_SERVER_Client *client,
769 struct TunnelState *ts;
771 GNUNET_STATISTICS_update (stats,
772 gettext_noop ("# Mesh tunnels created"),
774 GNUNET_assert (NULL == de->ts);
775 ts = GNUNET_malloc (sizeof (struct TunnelState));
779 ts->request_id = request_id;
781 GNUNET_SERVER_client_keep (client);
783 ts->destination = *de;
784 ts->destination.heap_node = NULL; /* copy is NOT in destination heap */
786 ts->destination_container = de; /* we are referenced from de */
787 ts->tunnel = GNUNET_MESH_tunnel_create (mesh_handle,
789 &tunnel_peer_connect_handler,
790 &tunnel_peer_disconnect_handler,
792 if (NULL == ts->tunnel)
794 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
795 _("Failed to setup mesh tunnel!\n"));
797 GNUNET_SERVER_client_drop (client);
803 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
804 "Creating tunnel to peer %s offering service %s\n",
805 GNUNET_i2s (&de->details.service_destination.target),
806 GNUNET_h2s (&de->details.service_destination.service_descriptor));
807 GNUNET_MESH_peer_request_connect_add (ts->tunnel,
808 &de->details.service_destination.target);
812 switch (de->details.exit_destination.af)
815 GNUNET_MESH_peer_request_connect_by_type (ts->tunnel,
816 GNUNET_APPLICATION_TYPE_IPV4_GATEWAY);
817 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
818 "Creating tunnel to exit peer for %s\n",
822 GNUNET_MESH_peer_request_connect_by_type (ts->tunnel,
823 GNUNET_APPLICATION_TYPE_IPV6_GATEWAY);
824 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
825 "Creating tunnel to exit peer for %s\n",
838 * We have too many active tunnels. Clean up the oldest tunnel.
840 * @param except tunnel that must NOT be cleaned up, even if it is the oldest
843 expire_tunnel (struct TunnelState *except)
845 struct TunnelState *ts;
847 ts = GNUNET_CONTAINER_heap_peek (tunnel_heap);
848 GNUNET_assert (NULL != ts);
850 return; /* can't do this */
851 free_tunnel_state (ts);
856 * Route a packet via mesh to the given destination.
858 * @param destination description of the destination
859 * @param af address family on this end (AF_INET or AF_INET6)
860 * @param protocol IPPROTO_TCP or IPPROTO_UDP or IPPROTO_ICMP or IPPROTO_ICMPV6
861 * @param source_ip source IP used by the sender (struct in_addr or struct in6_addr)
862 * @param destination_ip destination IP used by the sender (struct in_addr or struct in6_addr)
863 * @param payload payload of the packet after the IP header
864 * @param payload_length number of bytes in payload
867 route_packet (struct DestinationEntry *destination,
870 const void *source_ip,
871 const void *destination_ip,
873 size_t payload_length)
876 struct TunnelState *ts;
877 struct TunnelMessageQueueEntry *tnq;
881 const struct GNUNET_TUN_UdpHeader *udp;
882 const struct GNUNET_TUN_TcpHeader *tcp;
883 const struct GNUNET_TUN_IcmpHeader *icmp;
884 uint16_t source_port;
885 uint16_t destination_port;
891 if (payload_length < sizeof (struct GNUNET_TUN_UdpHeader))
898 if (udp->len < sizeof (struct GNUNET_TUN_UdpHeader))
903 source_port = ntohs (udp->source_port);
904 destination_port = ntohs (udp->destination_port);
905 get_tunnel_key_from_ips (af,
916 if (payload_length < sizeof (struct GNUNET_TUN_TcpHeader))
923 if (tcp->off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
928 source_port = ntohs (tcp->source_port);
929 destination_port = ntohs (tcp->destination_port);
930 get_tunnel_key_from_ips (af,
942 if ( (AF_INET == af) ^ (protocol == IPPROTO_ICMP) )
947 if (payload_length < sizeof (struct GNUNET_TUN_IcmpHeader))
955 destination_port = 0;
956 get_tunnel_key_from_ips (af,
966 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
967 _("Protocol %u not supported, dropping\n"),
968 (unsigned int) protocol);
971 if (! destination->is_service)
973 switch (destination->details.exit_destination.af)
976 alen = sizeof (struct in_addr);
979 alen = sizeof (struct in6_addr);
987 char sbuf[INET6_ADDRSTRLEN];
988 char dbuf[INET6_ADDRSTRLEN];
989 char xbuf[INET6_ADDRSTRLEN];
991 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
992 "Routing %s packet from %s:%u -> %s:%u to destination %s:%u\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 inet_ntop (destination->details.exit_destination.af,
999 &destination->details.exit_destination.ip,
1000 xbuf, sizeof (xbuf)),
1006 /* make compiler happy */
1009 char sbuf[INET6_ADDRSTRLEN];
1010 char dbuf[INET6_ADDRSTRLEN];
1012 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1013 "Routing %s packet from %s:%u -> %s:%u to service %s at peer %s\n",
1014 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
1015 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
1017 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
1019 GNUNET_h2s (&destination->details.service_destination.service_descriptor),
1020 GNUNET_i2s (&destination->details.service_destination.target));
1025 /* see if we have an existing tunnel for this destination */
1026 ts = GNUNET_CONTAINER_multihashmap_get (tunnel_map,
1030 /* need to either use the existing tunnel from the destination (if still
1031 available) or create a fresh one */
1032 is_new = GNUNET_YES;
1033 if (NULL == destination->ts)
1034 ts = create_tunnel_to_destination (destination, NULL, af, 0);
1036 ts = destination->ts;
1039 destination->ts = NULL;
1040 ts->destination_container = NULL; /* no longer 'contained' */
1041 /* now bind existing "unbound" tunnel to our IP/port tuple */
1042 ts->protocol = protocol;
1046 ts->source_ip.v4 = * (const struct in_addr *) source_ip;
1047 ts->destination_ip.v4 = * (const struct in_addr *) destination_ip;
1051 ts->source_ip.v6 = * (const struct in6_addr *) source_ip;
1052 ts->destination_ip.v6 = * (const struct in6_addr *) destination_ip;
1054 ts->source_port = source_port;
1055 ts->destination_port = destination_port;
1056 ts->heap_node = GNUNET_CONTAINER_heap_insert (tunnel_heap,
1058 GNUNET_TIME_absolute_get ().abs_value);
1059 GNUNET_assert (GNUNET_YES ==
1060 GNUNET_CONTAINER_multihashmap_put (tunnel_map,
1063 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1064 GNUNET_STATISTICS_update (stats,
1065 gettext_noop ("# Active tunnels"),
1067 while (GNUNET_CONTAINER_multihashmap_size (tunnel_map) > max_tunnel_mappings)
1073 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
1075 GNUNET_TIME_absolute_get ().abs_value);
1077 GNUNET_assert (NULL != ts->tunnel);
1079 /* send via tunnel */
1083 if (destination->is_service)
1085 struct GNUNET_EXIT_UdpServiceMessage *usm;
1087 mlen = sizeof (struct GNUNET_EXIT_UdpServiceMessage) +
1088 payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1089 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1094 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1097 usm = (struct GNUNET_EXIT_UdpServiceMessage *) &tnq[1];
1098 usm->header.size = htons ((uint16_t) mlen);
1099 usm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE);
1100 /* if the source port is below 32000, we assume it has a special
1101 meaning; if not, we pick a random port (this is a heuristic) */
1102 usm->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1103 usm->destination_port = udp->destination_port;
1104 usm->service_descriptor = destination->details.service_destination.service_descriptor;
1107 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1111 struct GNUNET_EXIT_UdpInternetMessage *uim;
1112 struct in_addr *ip4dst;
1113 struct in6_addr *ip6dst;
1116 mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) +
1117 alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1118 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1123 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) +
1127 uim = (struct GNUNET_EXIT_UdpInternetMessage *) &tnq[1];
1128 uim->header.size = htons ((uint16_t) mlen);
1129 uim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET);
1130 uim->af = htonl (destination->details.exit_destination.af);
1131 uim->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1132 uim->destination_port = udp->destination_port;
1133 switch (destination->details.exit_destination.af)
1136 ip4dst = (struct in_addr *) &uim[1];
1137 *ip4dst = destination->details.exit_destination.ip.v4;
1138 payload = &ip4dst[1];
1141 ip6dst = (struct in6_addr *) &uim[1];
1142 *ip6dst = destination->details.exit_destination.ip.v6;
1143 payload = &ip6dst[1];
1150 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1156 if (destination->is_service)
1158 struct GNUNET_EXIT_TcpServiceStartMessage *tsm;
1160 mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) +
1161 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1162 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1167 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1170 tsm = (struct GNUNET_EXIT_TcpServiceStartMessage *) &tnq[1];
1171 tsm->header.size = htons ((uint16_t) mlen);
1172 tsm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START);
1173 tsm->reserved = htonl (0);
1174 tsm->service_descriptor = destination->details.service_destination.service_descriptor;
1175 tsm->tcp_header = *tcp;
1178 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1182 struct GNUNET_EXIT_TcpInternetStartMessage *tim;
1183 struct in_addr *ip4dst;
1184 struct in6_addr *ip6dst;
1187 mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) +
1188 alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1189 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1194 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1197 tim = (struct GNUNET_EXIT_TcpInternetStartMessage *) &tnq[1];
1198 tim->header.size = htons ((uint16_t) mlen);
1199 tim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START);
1200 tim->af = htonl (destination->details.exit_destination.af);
1201 tim->tcp_header = *tcp;
1202 switch (destination->details.exit_destination.af)
1205 ip4dst = (struct in_addr *) &tim[1];
1206 *ip4dst = destination->details.exit_destination.ip.v4;
1207 payload = &ip4dst[1];
1210 ip6dst = (struct in6_addr *) &tim[1];
1211 *ip6dst = destination->details.exit_destination.ip.v6;
1212 payload = &ip6dst[1];
1219 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1224 struct GNUNET_EXIT_TcpDataMessage *tdm;
1226 mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) +
1227 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1228 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1233 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1236 tdm = (struct GNUNET_EXIT_TcpDataMessage *) &tnq[1];
1237 tdm->header.size = htons ((uint16_t) mlen);
1238 tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT);
1239 tdm->reserved = htonl (0);
1240 tdm->tcp_header = *tcp;
1243 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1247 case IPPROTO_ICMPV6:
1248 if (destination->is_service)
1250 struct GNUNET_EXIT_IcmpServiceMessage *ism;
1252 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1253 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1254 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1259 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1261 ism = (struct GNUNET_EXIT_IcmpServiceMessage *) &tnq[1];
1262 ism->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE);
1263 ism->af = htonl (af); /* need to tell destination ICMP protocol family! */
1264 ism->service_descriptor = destination->details.service_destination.service_descriptor;
1265 ism->icmp_header = *icmp;
1266 /* ICMP protocol translation will be done by the receiver (as we don't know
1267 the target AF); however, we still need to possibly discard the payload
1268 depending on the ICMP type */
1274 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1275 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1277 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1278 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1279 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1280 /* throw away ICMP payload, won't be useful for the other side anyway */
1281 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1284 GNUNET_STATISTICS_update (stats,
1285 gettext_noop ("# ICMPv4 packets dropped (not allowed)"),
1289 /* end of AF_INET */
1294 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1295 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1296 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1297 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1298 /* throw away ICMP payload, won't be useful for the other side anyway */
1299 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1301 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1302 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1305 GNUNET_STATISTICS_update (stats,
1306 gettext_noop ("# ICMPv6 packets dropped (not allowed)"),
1310 /* end of AF_INET6 */
1317 /* update length calculations, as payload_length may have changed */
1318 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1319 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1321 ism->header.size = htons ((uint16_t) mlen);
1322 /* finally, copy payload (if there is any left...) */
1325 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1329 struct GNUNET_EXIT_IcmpInternetMessage *iim;
1330 struct in_addr *ip4dst;
1331 struct in6_addr *ip6dst;
1334 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1335 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1336 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1341 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) +
1344 iim = (struct GNUNET_EXIT_IcmpInternetMessage *) &tnq[1];
1345 iim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET);
1346 iim->icmp_header = *icmp;
1347 /* Perform ICMP protocol-translation (depending on destination AF and source AF)
1348 and throw away ICMP payload depending on ICMP message type */
1354 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1355 if (destination->details.exit_destination.af == AF_INET6)
1356 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1358 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1359 if (destination->details.exit_destination.af == AF_INET6)
1360 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1362 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1363 if (destination->details.exit_destination.af == AF_INET6)
1364 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1365 /* throw away IP-payload, exit will have to make it up anyway */
1366 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1368 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1369 if (destination->details.exit_destination.af == AF_INET6)
1370 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1371 /* throw away IP-payload, exit will have to make it up anyway */
1372 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1374 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1375 if (destination->details.exit_destination.af == AF_INET6)
1377 GNUNET_STATISTICS_update (stats,
1378 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1383 /* throw away IP-payload, exit will have to make it up anyway */
1384 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1387 GNUNET_STATISTICS_update (stats,
1388 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1393 /* end of AF_INET */
1398 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1399 if (destination->details.exit_destination.af == AF_INET6)
1400 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1401 /* throw away IP-payload, exit will have to make it up anyway */
1402 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1404 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1405 if (destination->details.exit_destination.af == AF_INET)
1406 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1407 /* throw away IP-payload, exit will have to make it up anyway */
1408 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1410 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1411 if (destination->details.exit_destination.af == AF_INET)
1413 GNUNET_STATISTICS_update (stats,
1414 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1419 /* throw away IP-payload, exit will have to make it up anyway */
1420 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1422 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1423 if (destination->details.exit_destination.af == AF_INET)
1425 GNUNET_STATISTICS_update (stats,
1426 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1431 /* throw away IP-payload, exit will have to make it up anyway */
1432 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1434 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1435 if (destination->details.exit_destination.af == AF_INET)
1436 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1438 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1439 if (destination->details.exit_destination.af == AF_INET)
1440 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1443 GNUNET_STATISTICS_update (stats,
1444 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1449 /* end of AF_INET6 */
1454 /* update length calculations, as payload_length may have changed */
1455 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1456 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1458 iim->header.size = htons ((uint16_t) mlen);
1460 /* need to tell destination ICMP protocol family! */
1461 iim->af = htonl (destination->details.exit_destination.af);
1462 switch (destination->details.exit_destination.af)
1465 ip4dst = (struct in_addr *) &iim[1];
1466 *ip4dst = destination->details.exit_destination.ip.v4;
1467 payload = &ip4dst[1];
1470 ip6dst = (struct in6_addr *) &iim[1];
1471 *ip6dst = destination->details.exit_destination.ip.v6;
1472 payload = &ip6dst[1];
1479 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1483 /* not supported above, how can we get here !? */
1487 send_to_tunnel (tnq, ts);
1492 * Receive packets from the helper-process (someone send to the local
1493 * virtual tunnel interface). Find the destination mapping, and if it
1494 * exists, identify the correct MESH tunnel (or possibly create it)
1495 * and forward the packet.
1497 * @param cls closure, NULL
1498 * @param client NULL
1499 * @param message message we got from the client (VPN tunnel interface)
1502 message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED,
1503 const struct GNUNET_MessageHeader *message)
1505 const struct GNUNET_TUN_Layer2PacketHeader *tun;
1507 GNUNET_HashCode key;
1508 struct DestinationEntry *de;
1510 GNUNET_STATISTICS_update (stats,
1511 gettext_noop ("# Packets received from TUN interface"),
1513 mlen = ntohs (message->size);
1514 if ( (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
1515 (mlen < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader)) )
1520 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1521 mlen -= (sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader));
1522 switch (ntohs (tun->proto))
1526 const struct GNUNET_TUN_IPv6Header *pkt6;
1528 if (mlen < sizeof (struct GNUNET_TUN_IPv6Header))
1534 pkt6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1535 get_destination_key_from_ip (AF_INET6,
1536 &pkt6->destination_address,
1538 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1539 /* FIXME: do we need to guard against hash collision?
1540 (if so, we need to also store the local destination IP in the
1541 destination entry and then compare here; however, the risk
1542 of collision seems minimal AND the impact is unlikely to be
1543 super-problematic as well... */
1546 char buf[INET6_ADDRSTRLEN];
1548 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1549 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1550 inet_ntop (AF_INET6,
1551 &pkt6->destination_address,
1559 &pkt6->source_address,
1560 &pkt6->destination_address,
1562 mlen - sizeof (struct GNUNET_TUN_IPv6Header));
1567 struct GNUNET_TUN_IPv4Header *pkt4;
1569 if (mlen < sizeof (struct GNUNET_TUN_IPv4Header))
1575 pkt4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1576 get_destination_key_from_ip (AF_INET,
1577 &pkt4->destination_address,
1579 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1580 /* FIXME: do we need to guard against hash collision?
1581 (if so, we need to also store the local destination IP in the
1582 destination entry and then compare here; however, the risk
1583 of collision seems minimal AND the impact is unlikely to be
1584 super-problematic as well... */
1587 char buf[INET_ADDRSTRLEN];
1589 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1590 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1592 &pkt4->destination_address,
1597 if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header))
1599 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1600 _("Received IPv4 packet with options (dropping it)\n"));
1606 &pkt4->source_address,
1607 &pkt4->destination_address,
1609 mlen - sizeof (struct GNUNET_TUN_IPv4Header));
1613 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1614 _("Received packet of unknown protocol %d from TUN (dropping it)\n"),
1615 (unsigned int) ntohs (tun->proto));
1622 * Synthesize a plausible ICMP payload for an ICMP error
1623 * response on the given tunnel.
1625 * @param ts tunnel information
1626 * @param ipp IPv4 header to fill in (ICMP payload)
1627 * @param udp "UDP" header to fill in (ICMP payload); might actually
1628 * also be the first 8 bytes of the TCP header
1631 make_up_icmpv4_payload (struct TunnelState *ts,
1632 struct GNUNET_TUN_IPv4Header *ipp,
1633 struct GNUNET_TUN_UdpHeader *udp)
1635 GNUNET_TUN_initialize_ipv4_header (ipp,
1637 sizeof (struct GNUNET_TUN_TcpHeader),
1639 &ts->destination_ip.v4);
1640 udp->source_port = htons (ts->source_port);
1641 udp->destination_port = htons (ts->destination_port);
1642 udp->len = htons (0);
1643 udp->crc = htons (0);
1648 * Synthesize a plausible ICMP payload for an ICMP error
1649 * response on the given tunnel.
1651 * @param ts tunnel information
1652 * @param ipp IPv6 header to fill in (ICMP payload)
1653 * @param udp "UDP" header to fill in (ICMP payload); might actually
1654 * also be the first 8 bytes of the TCP header
1657 make_up_icmpv6_payload (struct TunnelState *ts,
1658 struct GNUNET_TUN_IPv6Header *ipp,
1659 struct GNUNET_TUN_UdpHeader *udp)
1661 GNUNET_TUN_initialize_ipv6_header (ipp,
1663 sizeof (struct GNUNET_TUN_TcpHeader),
1665 &ts->destination_ip.v6);
1666 udp->source_port = htons (ts->source_port);
1667 udp->destination_port = htons (ts->destination_port);
1668 udp->len = htons (0);
1669 udp->crc = htons (0);
1674 * We got an ICMP packet back from the MESH tunnel. Pass it on to the
1675 * local virtual interface via the helper.
1677 * @param cls closure, NULL
1678 * @param tunnel connection to the other end
1679 * @param tunnel_ctx pointer to our 'struct TunnelState *'
1680 * @param sender who sent the message
1681 * @param message the actual message
1682 * @param atsi performance data for the connection
1683 * @return GNUNET_OK to keep the connection open,
1684 * GNUNET_SYSERR to close it (signal serious error)
1687 receive_icmp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1688 void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender,
1689 const struct GNUNET_MessageHeader *message,
1690 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
1692 struct TunnelState *ts = *tunnel_ctx;
1693 const struct GNUNET_EXIT_IcmpToVPNMessage *i2v;
1696 GNUNET_STATISTICS_update (stats,
1697 gettext_noop ("# ICMP packets received from mesh"),
1699 mlen = ntohs (message->size);
1700 if (mlen < sizeof (struct GNUNET_EXIT_IcmpToVPNMessage))
1702 GNUNET_break_op (0);
1703 return GNUNET_SYSERR;
1705 if (NULL == ts->heap_node)
1707 GNUNET_break_op (0);
1708 return GNUNET_SYSERR;
1710 if (AF_UNSPEC == ts->af)
1712 GNUNET_break_op (0);
1713 return GNUNET_SYSERR;
1715 i2v = (const struct GNUNET_EXIT_IcmpToVPNMessage *) message;
1716 mlen -= sizeof (struct GNUNET_EXIT_IcmpToVPNMessage);
1718 char sbuf[INET6_ADDRSTRLEN];
1719 char dbuf[INET6_ADDRSTRLEN];
1721 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1722 "Received ICMP packet from mesh, sending %u bytes from %s -> %s via TUN\n",
1723 (unsigned int) mlen,
1724 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
1725 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)));
1731 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
1732 + sizeof (struct GNUNET_TUN_IcmpHeader)
1733 + sizeof (struct GNUNET_MessageHeader) +
1734 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1737 /* reserve some extra space in case we have an ICMP type here where
1738 we will need to make up the payload ourselves */
1739 char buf[size + sizeof (struct GNUNET_TUN_IPv4Header) + 8];
1740 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1741 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1742 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1743 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv4[1];
1744 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1745 tun->flags = htons (0);
1746 tun->proto = htons (ETH_P_IPV4);
1747 GNUNET_TUN_initialize_ipv4_header (ipv4,
1749 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1750 &ts->destination_ip.v4,
1752 *icmp = i2v->icmp_header;
1756 /* For some ICMP types, we need to adjust (make up) the payload here.
1757 Also, depending on the AF used on the other side, we have to
1758 do ICMP PT (translate ICMP types) */
1759 switch (ntohl (i2v->af))
1764 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1765 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1767 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1768 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1769 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1771 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1772 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1776 /* sender did not strip ICMP payload? */
1777 GNUNET_break_op (0);
1778 return GNUNET_SYSERR;
1780 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1781 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1782 make_up_icmpv4_payload (ts, ipp, udp);
1786 GNUNET_break_op (0);
1787 GNUNET_STATISTICS_update (stats,
1788 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1790 return GNUNET_SYSERR;
1795 /* ICMP PT 6-to-4 and possibly making up payloads */
1798 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1799 icmp->type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
1801 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1802 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1806 /* sender did not strip ICMP payload? */
1807 GNUNET_break_op (0);
1808 return GNUNET_SYSERR;
1810 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1811 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1812 make_up_icmpv4_payload (ts, ipp, udp);
1815 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1816 icmp->type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1818 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1819 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1823 /* sender did not strip ICMP payload? */
1824 GNUNET_break_op (0);
1825 return GNUNET_SYSERR;
1827 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1828 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1829 make_up_icmpv4_payload (ts, ipp, udp);
1832 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1833 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1834 GNUNET_STATISTICS_update (stats,
1835 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1838 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1839 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1841 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1842 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1845 GNUNET_break_op (0);
1846 GNUNET_STATISTICS_update (stats,
1847 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1849 return GNUNET_SYSERR;
1854 GNUNET_break_op (0);
1855 return GNUNET_SYSERR;
1857 msg->size = htons (size);
1858 GNUNET_TUN_calculate_icmp_checksum (icmp,
1861 (void) GNUNET_HELPER_send (helper_handle,
1870 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
1871 + sizeof (struct GNUNET_TUN_IcmpHeader)
1872 + sizeof (struct GNUNET_MessageHeader) +
1873 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1876 char buf[size + sizeof (struct GNUNET_TUN_IPv6Header) + 8];
1877 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1878 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1879 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
1880 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv6[1];
1881 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1882 tun->flags = htons (0);
1883 tun->proto = htons (ETH_P_IPV6);
1884 GNUNET_TUN_initialize_ipv6_header (ipv6,
1886 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1887 &ts->destination_ip.v6,
1889 *icmp = i2v->icmp_header;
1894 /* For some ICMP types, we need to adjust (make up) the payload here.
1895 Also, depending on the AF used on the other side, we have to
1896 do ICMP PT (translate ICMP types) */
1897 switch (ntohl (i2v->af))
1900 /* ICMP PT 4-to-6 and possibly making up payloads */
1903 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1904 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1906 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1907 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1909 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1910 icmp->type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1912 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1913 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1917 /* sender did not strip ICMP payload? */
1918 GNUNET_break_op (0);
1919 return GNUNET_SYSERR;
1921 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1922 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1923 make_up_icmpv6_payload (ts, ipp, udp);
1926 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1927 icmp->type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1929 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1930 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1934 /* sender did not strip ICMP payload? */
1935 GNUNET_break_op (0);
1936 return GNUNET_SYSERR;
1938 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1939 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1940 make_up_icmpv6_payload (ts, ipp, udp);
1943 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1944 GNUNET_STATISTICS_update (stats,
1945 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1949 GNUNET_break_op (0);
1950 GNUNET_STATISTICS_update (stats,
1951 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1953 return GNUNET_SYSERR;
1960 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1961 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1962 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1963 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1965 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1966 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1970 /* sender did not strip ICMP payload? */
1971 GNUNET_break_op (0);
1972 return GNUNET_SYSERR;
1974 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1975 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1976 make_up_icmpv6_payload (ts, ipp, udp);
1979 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1982 GNUNET_break_op (0);
1983 GNUNET_STATISTICS_update (stats,
1984 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1986 return GNUNET_SYSERR;
1991 GNUNET_break_op (0);
1992 return GNUNET_SYSERR;
1994 msg->size = htons (size);
1995 GNUNET_TUN_calculate_icmp_checksum (icmp,
1997 (void) GNUNET_HELPER_send (helper_handle,
2007 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2009 GNUNET_TIME_absolute_get ().abs_value);
2015 * We got a UDP packet back from the MESH tunnel. Pass it on to the
2016 * local virtual interface via the helper.
2018 * @param cls closure, NULL
2019 * @param tunnel connection to the other end
2020 * @param tunnel_ctx pointer to our 'struct TunnelState *'
2021 * @param sender who sent the message
2022 * @param message the actual message
2023 * @param atsi performance data for the connection
2024 * @return GNUNET_OK to keep the connection open,
2025 * GNUNET_SYSERR to close it (signal serious error)
2028 receive_udp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
2029 void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender,
2030 const struct GNUNET_MessageHeader *message,
2031 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
2033 struct TunnelState *ts = *tunnel_ctx;
2034 const struct GNUNET_EXIT_UdpReplyMessage *reply;
2037 GNUNET_STATISTICS_update (stats,
2038 gettext_noop ("# UDP packets received from mesh"),
2040 mlen = ntohs (message->size);
2041 if (mlen < sizeof (struct GNUNET_EXIT_UdpReplyMessage))
2043 GNUNET_break_op (0);
2044 return GNUNET_SYSERR;
2046 if (NULL == ts->heap_node)
2048 GNUNET_break_op (0);
2049 return GNUNET_SYSERR;
2051 if (AF_UNSPEC == ts->af)
2053 GNUNET_break_op (0);
2054 return GNUNET_SYSERR;
2056 reply = (const struct GNUNET_EXIT_UdpReplyMessage *) message;
2057 mlen -= sizeof (struct GNUNET_EXIT_UdpReplyMessage);
2059 char sbuf[INET6_ADDRSTRLEN];
2060 char dbuf[INET6_ADDRSTRLEN];
2062 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2063 "Received UDP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2064 (unsigned int) mlen,
2065 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2066 ts->destination_port,
2067 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2074 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2075 + sizeof (struct GNUNET_TUN_UdpHeader)
2076 + sizeof (struct GNUNET_MessageHeader) +
2077 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2081 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2082 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2083 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2084 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1];
2085 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2086 msg->size = htons (size);
2087 tun->flags = htons (0);
2088 tun->proto = htons (ETH_P_IPV4);
2089 GNUNET_TUN_initialize_ipv4_header (ipv4,
2091 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2092 &ts->destination_ip.v4,
2094 if (0 == ntohs (reply->source_port))
2095 udp->source_port = htons (ts->destination_port);
2097 udp->source_port = reply->source_port;
2098 if (0 == ntohs (reply->destination_port))
2099 udp->destination_port = htons (ts->source_port);
2101 udp->destination_port = reply->destination_port;
2102 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2103 GNUNET_TUN_calculate_udp4_checksum (ipv4,
2110 (void) GNUNET_HELPER_send (helper_handle,
2119 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2120 + sizeof (struct GNUNET_TUN_UdpHeader)
2121 + sizeof (struct GNUNET_MessageHeader) +
2122 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2126 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2127 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2128 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2129 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1];
2130 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2131 msg->size = htons (size);
2132 tun->flags = htons (0);
2133 tun->proto = htons (ETH_P_IPV6);
2134 GNUNET_TUN_initialize_ipv6_header (ipv6,
2136 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2137 &ts->destination_ip.v6,
2139 if (0 == ntohs (reply->source_port))
2140 udp->source_port = htons (ts->destination_port);
2142 udp->source_port = reply->source_port;
2143 if (0 == ntohs (reply->destination_port))
2144 udp->destination_port = htons (ts->source_port);
2146 udp->destination_port = reply->destination_port;
2147 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2148 GNUNET_TUN_calculate_udp6_checksum (ipv6,
2154 (void) GNUNET_HELPER_send (helper_handle,
2164 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2166 GNUNET_TIME_absolute_get ().abs_value);
2172 * We got a TCP packet back from the MESH tunnel. Pass it on to the
2173 * local virtual interface via the helper.
2175 * @param cls closure, NULL
2176 * @param tunnel connection to the other end
2177 * @param tunnel_ctx pointer to our 'struct TunnelState *'
2178 * @param sender who sent the message
2179 * @param message the actual message
2180 * @param atsi performance data for the connection
2181 * @return GNUNET_OK to keep the connection open,
2182 * GNUNET_SYSERR to close it (signal serious error)
2185 receive_tcp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
2187 const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED,
2188 const struct GNUNET_MessageHeader *message,
2189 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
2191 struct TunnelState *ts = *tunnel_ctx;
2192 const struct GNUNET_EXIT_TcpDataMessage *data;
2195 GNUNET_STATISTICS_update (stats,
2196 gettext_noop ("# TCP packets received from mesh"),
2198 mlen = ntohs (message->size);
2199 if (mlen < sizeof (struct GNUNET_EXIT_TcpDataMessage))
2201 GNUNET_break_op (0);
2202 return GNUNET_SYSERR;
2204 if (NULL == ts->heap_node)
2206 GNUNET_break_op (0);
2207 return GNUNET_SYSERR;
2209 data = (const struct GNUNET_EXIT_TcpDataMessage *) message;
2210 mlen -= sizeof (struct GNUNET_EXIT_TcpDataMessage);
2212 char sbuf[INET6_ADDRSTRLEN];
2213 char dbuf[INET6_ADDRSTRLEN];
2215 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2216 "Received TCP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2217 (unsigned int) mlen,
2218 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2219 ts->destination_port,
2220 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2223 if (data->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
2225 GNUNET_break_op (0);
2226 return GNUNET_SYSERR;
2232 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2233 + sizeof (struct GNUNET_TUN_TcpHeader)
2234 + sizeof (struct GNUNET_MessageHeader) +
2235 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2239 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2240 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2241 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2242 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv4[1];
2243 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2244 msg->size = htons (size);
2245 tun->flags = htons (0);
2246 tun->proto = htons (ETH_P_IPV4);
2247 GNUNET_TUN_initialize_ipv4_header (ipv4,
2249 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2250 &ts->destination_ip.v4,
2252 *tcp = data->tcp_header;
2253 tcp->source_port = htons (ts->destination_port);
2254 tcp->destination_port = htons (ts->source_port);
2255 GNUNET_TUN_calculate_tcp4_checksum (ipv4,
2262 (void) GNUNET_HELPER_send (helper_handle,
2271 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2272 + sizeof (struct GNUNET_TUN_TcpHeader)
2273 + sizeof (struct GNUNET_MessageHeader) +
2274 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2278 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2279 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2280 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2281 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv6[1];
2282 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2283 msg->size = htons (size);
2284 tun->flags = htons (0);
2285 tun->proto = htons (ETH_P_IPV6);
2286 GNUNET_TUN_initialize_ipv6_header (ipv6,
2288 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2289 &ts->destination_ip.v6,
2291 *tcp = data->tcp_header;
2292 tcp->source_port = htons (ts->destination_port);
2293 tcp->destination_port = htons (ts->source_port);
2294 GNUNET_TUN_calculate_tcp6_checksum (ipv6,
2301 (void) GNUNET_HELPER_send (helper_handle,
2309 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2311 GNUNET_TIME_absolute_get ().abs_value);
2317 * Allocate an IPv4 address from the range of the tunnel
2318 * for a new redirection.
2320 * @param v4 where to store the address
2321 * @return GNUNET_OK on success,
2322 * GNUNET_SYSERR on error
2325 allocate_v4_address (struct in_addr *v4)
2327 const char *ipv4addr = vpn_argv[4];
2328 const char *ipv4mask = vpn_argv[5];
2329 struct in_addr addr;
2330 struct in_addr mask;
2332 GNUNET_HashCode key;
2335 GNUNET_assert (1 == inet_pton (AF_INET, ipv4addr, &addr));
2336 GNUNET_assert (1 == inet_pton (AF_INET, ipv4mask, &mask));
2337 /* Given 192.168.0.1/255.255.0.0, we want a mask
2338 of '192.168.255.255', thus: */
2339 mask.s_addr = addr.s_addr | ~mask.s_addr;
2346 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2347 _("Failed to find unallocated IPv4 address in VPN's range\n"));
2348 return GNUNET_SYSERR;
2350 /* Pick random IPv4 address within the subnet, except 'addr' or 'mask' itself */
2351 rnd.s_addr = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2353 v4->s_addr = (addr.s_addr | rnd.s_addr) & mask.s_addr;
2354 get_destination_key_from_ip (AF_INET,
2358 while ( (GNUNET_YES ==
2359 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2361 (v4->s_addr == addr.s_addr) ||
2362 (v4->s_addr == mask.s_addr) );
2368 * Allocate an IPv6 address from the range of the tunnel
2369 * for a new redirection.
2371 * @param v6 where to store the address
2372 * @return GNUNET_OK on success,
2373 * GNUNET_SYSERR on error
2376 allocate_v6_address (struct in6_addr *v6)
2378 const char *ipv6addr = vpn_argv[2];
2379 struct in6_addr addr;
2380 struct in6_addr mask;
2381 struct in6_addr rnd;
2383 GNUNET_HashCode key;
2386 GNUNET_assert (1 == inet_pton (AF_INET6, ipv6addr, &addr));
2387 GNUNET_assert (ipv6prefix < 128);
2388 /* Given ABCD::/96, we want a mask of 'ABCD::FFFF:FFFF,
2391 for (i=127;i>=ipv6prefix;i--)
2392 mask.s6_addr[i / 8] |= (1 << (i % 8));
2394 /* Pick random IPv6 address within the subnet, except 'addr' or 'mask' itself */
2401 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2402 _("Failed to find unallocated IPv6 address in VPN's range\n"));
2403 return GNUNET_SYSERR;
2408 rnd.s6_addr[i] = (unsigned char) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2411 = (addr.s6_addr[i] | rnd.s6_addr[i]) & mask.s6_addr[i];
2413 get_destination_key_from_ip (AF_INET6,
2417 while ( (GNUNET_YES ==
2418 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2422 sizeof (struct in6_addr))) ||
2425 sizeof (struct in6_addr))) );
2431 * Free resources occupied by a destination entry.
2433 * @param de entry to free
2436 free_destination_entry (struct DestinationEntry *de)
2438 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2439 "Cleaning up destination entry\n");
2440 GNUNET_STATISTICS_update (stats,
2441 gettext_noop ("# Active destinations"),
2445 free_tunnel_state (de->ts);
2446 GNUNET_assert (NULL == de->ts);
2448 if (NULL != de->heap_node)
2450 GNUNET_CONTAINER_heap_remove_node (de->heap_node);
2451 de->heap_node = NULL;
2452 GNUNET_assert (GNUNET_YES ==
2453 GNUNET_CONTAINER_multihashmap_remove (destination_map,
2462 * We have too many active destinations. Clean up the oldest destination.
2464 * @param except destination that must NOT be cleaned up, even if it is the oldest
2467 expire_destination (struct DestinationEntry *except)
2469 struct DestinationEntry *de;
2471 de = GNUNET_CONTAINER_heap_peek (destination_heap);
2472 GNUNET_assert (NULL != de);
2474 return; /* can't do this */
2475 free_destination_entry (de);
2480 * A client asks us to setup a redirection via some exit
2481 * node to a particular IP. Setup the redirection and
2482 * give the client the allocated IP.
2485 * @param client requesting client
2486 * @param message redirection request (a 'struct RedirectToIpRequestMessage')
2489 service_redirect_to_ip (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
2490 const struct GNUNET_MessageHeader *message)
2494 const struct RedirectToIpRequestMessage *msg;
2500 struct DestinationEntry *de;
2501 GNUNET_HashCode key;
2502 struct TunnelState *ts;
2504 /* validate and parse request */
2505 mlen = ntohs (message->size);
2506 if (mlen < sizeof (struct RedirectToIpRequestMessage))
2509 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2512 alen = mlen - sizeof (struct RedirectToIpRequestMessage);
2513 msg = (const struct RedirectToIpRequestMessage *) message;
2514 addr_af = (int) htonl (msg->addr_af);
2518 if (alen != sizeof (struct in_addr))
2521 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2526 if (alen != sizeof (struct in6_addr))
2529 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2535 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2539 /* allocate response IP */
2541 result_af = (int) htonl (msg->result_af);
2546 allocate_v4_address (&v4))
2547 result_af = AF_UNSPEC;
2553 allocate_v6_address (&v6))
2554 result_af = AF_UNSPEC;
2560 allocate_v4_address (&v4))
2563 result_af = AF_INET;
2565 else if (GNUNET_OK ==
2566 allocate_v6_address (&v6))
2569 result_af = AF_INET6;
2574 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2577 if ( (result_af == AF_UNSPEC) ||
2578 (GNUNET_NO == ntohl (msg->nac)) )
2580 /* send reply "instantly" */
2581 send_client_reply (client,
2586 if (result_af == AF_UNSPEC)
2588 /* failure, we're done */
2589 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2594 char sbuf[INET6_ADDRSTRLEN];
2595 char dbuf[INET6_ADDRSTRLEN];
2597 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2598 "Allocated address %s for redirection via exit to %s\n",
2599 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2601 &msg[1], dbuf, sizeof (dbuf)));
2604 /* setup destination record */
2605 de = GNUNET_malloc (sizeof (struct DestinationEntry));
2606 de->is_service = GNUNET_NO;
2607 de->details.exit_destination.af = addr_af;
2608 memcpy (&de->details.exit_destination.ip,
2611 get_destination_key_from_ip (result_af,
2615 GNUNET_assert (GNUNET_OK ==
2616 GNUNET_CONTAINER_multihashmap_put (destination_map,
2619 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2620 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2622 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
2623 GNUNET_STATISTICS_update (stats,
2624 gettext_noop ("# Active destinations"),
2626 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2627 expire_destination (de);
2629 /* setup tunnel to destination */
2630 ts = create_tunnel_to_destination (de,
2631 (GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
2637 ts->destination_ip.v4 = v4;
2640 ts->destination_ip.v6 = v6;
2646 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2651 * A client asks us to setup a redirection to a particular peer
2652 * offering a service. Setup the redirection and give the client the
2656 * @param client requesting client
2657 * @param message redirection request (a 'struct RedirectToPeerRequestMessage')
2660 service_redirect_to_service (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
2661 const struct GNUNET_MessageHeader *message)
2663 const struct RedirectToServiceRequestMessage *msg;
2668 struct DestinationEntry *de;
2669 GNUNET_HashCode key;
2670 struct TunnelState *ts;
2673 msg = (const struct RedirectToServiceRequestMessage *) message;
2675 /* allocate response IP */
2677 result_af = (int) htonl (msg->result_af);
2682 allocate_v4_address (&v4))
2683 result_af = AF_UNSPEC;
2689 allocate_v6_address (&v6))
2690 result_af = AF_UNSPEC;
2696 allocate_v4_address (&v4))
2699 result_af = AF_INET;
2701 else if (GNUNET_OK ==
2702 allocate_v6_address (&v6))
2705 result_af = AF_INET6;
2710 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2713 if ( (result_af == AF_UNSPEC) ||
2714 (GNUNET_NO == ntohl (msg->nac)) )
2716 /* send reply "instantly" */
2717 send_client_reply (client,
2722 if (result_af == AF_UNSPEC)
2724 /* failure, we're done */
2725 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2726 _("Failed to allocate IP address for new destination\n"));
2727 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2732 char sbuf[INET6_ADDRSTRLEN];
2734 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2735 "Allocated address %s for redirection to service %s on peer %s\n",
2736 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2737 GNUNET_h2s (&msg->service_descriptor),
2738 GNUNET_i2s (&msg->target));
2741 /* setup destination record */
2742 de = GNUNET_malloc (sizeof (struct DestinationEntry));
2743 de->is_service = GNUNET_YES;
2744 de->details.service_destination.service_descriptor = msg->service_descriptor;
2745 de->details.service_destination.target = msg->target;
2746 get_destination_key_from_ip (result_af,
2750 GNUNET_assert (GNUNET_OK ==
2751 GNUNET_CONTAINER_multihashmap_put (destination_map,
2754 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2755 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2757 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
2758 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2759 expire_destination (de);
2760 ts = create_tunnel_to_destination (de,
2761 (GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
2767 ts->destination_ip.v4 = v4;
2770 ts->destination_ip.v6 = v6;
2776 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2782 * Function called for inbound tunnels. As we don't offer
2783 * any mesh services, this function should never be called.
2785 * @param cls closure
2786 * @param tunnel new handle to the tunnel
2787 * @param initiator peer that started the tunnel
2788 * @param atsi performance information for the tunnel
2789 * @return initial tunnel context for the tunnel
2790 * (can be NULL -- that's not an error)
2793 inbound_tunnel_cb (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
2794 const struct GNUNET_PeerIdentity *initiator,
2795 const struct GNUNET_ATS_Information *atsi)
2797 /* How can and why should anyone open an inbound tunnel to vpn? */
2804 * Function called whenever an inbound tunnel is destroyed. Should clean up
2805 * any associated state.
2807 * @param cls closure (set from GNUNET_MESH_connect)
2808 * @param tunnel connection to the other end (henceforth invalid)
2809 * @param tunnel_ctx place where local state associated
2810 * with the tunnel is stored (our 'struct TunnelState')
2813 tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel_ctx)
2815 /* we don't have inbound tunnels, so this function should never be called */
2821 * Free memory occupied by an entry in the destination map.
2825 * @param value a 'struct DestinationEntry *'
2826 * @return GNUNET_OK (continue to iterate)
2829 cleanup_destination (void *cls,
2830 const GNUNET_HashCode *key,
2833 struct DestinationEntry *de = value;
2835 free_destination_entry (de);
2841 * Free memory occupied by an entry in the tunnel map.
2845 * @param value a 'struct TunnelState *'
2846 * @return GNUNET_OK (continue to iterate)
2849 cleanup_tunnel (void *cls,
2850 const GNUNET_HashCode *key,
2853 struct TunnelState *ts = value;
2855 free_tunnel_state (ts);
2861 * Function scheduled as very last function, cleans up after us
2867 cleanup (void *cls GNUNET_UNUSED,
2868 const struct GNUNET_SCHEDULER_TaskContext *tc)
2872 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2873 "VPN is shutting down\n");
2874 if (NULL != destination_map)
2876 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
2877 &cleanup_destination,
2879 GNUNET_CONTAINER_multihashmap_destroy (destination_map);
2880 destination_map = NULL;
2882 if (NULL != destination_heap)
2884 GNUNET_CONTAINER_heap_destroy (destination_heap);
2885 destination_heap = NULL;
2887 if (NULL != tunnel_map)
2889 GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
2892 GNUNET_CONTAINER_multihashmap_destroy (tunnel_map);
2895 if (NULL != tunnel_heap)
2897 GNUNET_CONTAINER_heap_destroy (tunnel_heap);
2900 if (NULL != mesh_handle)
2902 GNUNET_MESH_disconnect (mesh_handle);
2905 if (NULL != helper_handle)
2907 GNUNET_HELPER_stop (helper_handle);
2908 helper_handle = NULL;
2912 GNUNET_SERVER_notification_context_destroy (nc);
2917 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
2921 GNUNET_free_non_null (vpn_argv[i]);
2926 * A client disconnected, clean up all references to it.
2928 * @param cls the client that disconnected
2930 * @param value a 'struct TunnelState *'
2931 * @return GNUNET_OK (continue to iterate)
2934 cleanup_tunnel_client (void *cls,
2935 const GNUNET_HashCode *key,
2938 struct GNUNET_SERVER_Client *client = cls;
2939 struct TunnelState *ts = value;
2941 if (client == ts->client)
2943 GNUNET_SERVER_client_drop (ts->client);
2951 * A client disconnected, clean up all references to it.
2953 * @param cls the client that disconnected
2955 * @param value a 'struct DestinationEntry *'
2956 * @return GNUNET_OK (continue to iterate)
2959 cleanup_destination_client (void *cls,
2960 const GNUNET_HashCode *key,
2963 struct GNUNET_SERVER_Client *client = cls;
2964 struct DestinationEntry *de = value;
2965 struct TunnelState *ts;
2967 if (NULL == (ts = de->ts))
2969 if (client == ts->client)
2971 GNUNET_SERVER_client_drop (ts->client);
2979 * A client has disconnected from us. If we are currently building
2980 * a tunnel for it, cancel the operation.
2983 * @param client handle to the client that disconnected
2986 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
2988 if (NULL != tunnel_map)
2989 GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
2990 &cleanup_tunnel_client,
2992 if (NULL != destination_map)
2993 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
2994 &cleanup_destination_client,
3000 * Test if the given AF is supported by this system.
3003 * @return GNUNET_OK if the AF is supported
3010 s = socket (af, SOCK_STREAM, 0);
3013 if (EAFNOSUPPORT == errno)
3015 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
3017 return GNUNET_SYSERR;
3025 * Main function that will be run by the scheduler.
3027 * @param cls closure
3028 * @param server the initialized server
3029 * @param cfg_ configuration
3033 struct GNUNET_SERVER_Handle *server,
3034 const struct GNUNET_CONFIGURATION_Handle *cfg_)
3036 static const struct GNUNET_SERVER_MessageHandler service_handlers[] = {
3037 /* callback, cls, type, size */
3038 { &service_redirect_to_ip, NULL, GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP, 0},
3039 { &service_redirect_to_service, NULL,
3040 GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE,
3041 sizeof (struct RedirectToServiceRequestMessage) },
3044 static const struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
3045 { &receive_udp_back, GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY, 0},
3046 { &receive_tcp_back, GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN, 0},
3047 { &receive_icmp_back, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN, 0},
3050 static const GNUNET_MESH_ApplicationType types[] = {
3051 GNUNET_APPLICATION_TYPE_END
3062 GNUNET_OS_check_helper_binary ("gnunet-helper-vpn"))
3065 "`%s' is not SUID, refusing to run.\n",
3066 "gnunet-helper-vpn");
3071 stats = GNUNET_STATISTICS_create ("vpn", cfg);
3073 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_MAPPING",
3074 &max_destination_mappings))
3075 max_destination_mappings = 200;
3077 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_TUNNELS",
3078 &max_tunnel_mappings))
3079 max_tunnel_mappings = 200;
3081 destination_map = GNUNET_CONTAINER_multihashmap_create (max_destination_mappings * 2);
3082 destination_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3083 tunnel_map = GNUNET_CONTAINER_multihashmap_create (max_tunnel_mappings * 2);
3084 tunnel_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3087 vpn_argv[0] = GNUNET_strdup ("vpn-gnunet");
3088 if (GNUNET_SYSERR ==
3089 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IFNAME", &ifname))
3091 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3092 "No entry 'IFNAME' in configuration!\n");
3093 GNUNET_SCHEDULER_shutdown ();
3096 vpn_argv[1] = ifname;
3097 if (GNUNET_OK == test_af (AF_INET6))
3099 if ( (GNUNET_SYSERR ==
3100 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6ADDR",
3102 (1 != inet_pton (AF_INET6, ipv6addr, &v6))) )
3104 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3105 "No valid entry 'IPV6ADDR' in configuration!\n");
3106 GNUNET_SCHEDULER_shutdown ();
3109 vpn_argv[2] = ipv6addr;
3110 if (GNUNET_SYSERR ==
3111 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6PREFIX",
3114 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3115 "No entry 'IPV6PREFIX' in configuration!\n");
3116 GNUNET_SCHEDULER_shutdown ();
3119 vpn_argv[3] = ipv6prefix_s;
3121 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn",
3124 (ipv6prefix >= 127) )
3126 GNUNET_SCHEDULER_shutdown ();
3132 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3133 _("IPv6 support disabled as this system does not support IPv6\n"));
3134 vpn_argv[2] = GNUNET_strdup ("-");
3135 vpn_argv[3] = GNUNET_strdup ("-");
3137 if (GNUNET_OK == test_af (AF_INET))
3139 if ( (GNUNET_SYSERR ==
3140 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4ADDR",
3142 (1 != inet_pton (AF_INET, ipv4addr, &v4))) )
3144 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3145 "No valid entry for 'IPV4ADDR' in configuration!\n");
3146 GNUNET_SCHEDULER_shutdown ();
3149 vpn_argv[4] = ipv4addr;
3150 if ( (GNUNET_SYSERR ==
3151 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4MASK",
3153 (1 != inet_pton (AF_INET, ipv4mask, &v4))) )
3155 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3156 "No valid entry 'IPV4MASK' in configuration!\n");
3157 GNUNET_SCHEDULER_shutdown ();
3160 vpn_argv[5] = ipv4mask;
3164 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3165 _("IPv4 support disabled as this system does not support IPv4\n"));
3166 vpn_argv[4] = GNUNET_strdup ("-");
3167 vpn_argv[5] = GNUNET_strdup ("-");
3172 GNUNET_MESH_connect (cfg_, 42 /* queue length */, NULL,
3177 helper_handle = GNUNET_HELPER_start ("gnunet-helper-vpn", vpn_argv,
3178 &message_token, NULL);
3179 nc = GNUNET_SERVER_notification_context_create (server, 1);
3180 GNUNET_SERVER_add_handlers (server, service_handlers);
3181 GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
3182 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls);
3187 * The main function of the VPN service.
3189 * @param argc number of arguments from the command line
3190 * @param argv command line arguments
3191 * @return 0 ok, 1 on error
3194 main (int argc, char *const *argv)
3196 return (GNUNET_OK ==
3197 GNUNET_SERVICE_run (argc, argv, "vpn",
3198 GNUNET_SERVICE_OPTION_NONE,
3199 &run, NULL)) ? global_ret : 1;
3202 /* end of gnunet-service-vpn.c */