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)] GNUNET_ALIGN;
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))
897 tcp = NULL; /* make compiler happy */
898 icmp = NULL; /* make compiler happy */
900 if (udp->len < sizeof (struct GNUNET_TUN_UdpHeader))
905 source_port = ntohs (udp->source_port);
906 destination_port = ntohs (udp->destination_port);
907 get_tunnel_key_from_ips (af,
918 if (payload_length < sizeof (struct GNUNET_TUN_TcpHeader))
924 udp = NULL; /* make compiler happy */
925 icmp = NULL; /* make compiler happy */
927 if (tcp->off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
932 source_port = ntohs (tcp->source_port);
933 destination_port = ntohs (tcp->destination_port);
934 get_tunnel_key_from_ips (af,
946 if ( (AF_INET == af) ^ (protocol == IPPROTO_ICMP) )
951 if (payload_length < sizeof (struct GNUNET_TUN_IcmpHeader))
957 tcp = NULL; /* make compiler happy */
958 udp = NULL; /* make compiler happy */
961 destination_port = 0;
962 get_tunnel_key_from_ips (af,
972 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
973 _("Protocol %u not supported, dropping\n"),
974 (unsigned int) protocol);
977 if (! destination->is_service)
979 switch (destination->details.exit_destination.af)
982 alen = sizeof (struct in_addr);
985 alen = sizeof (struct in6_addr);
993 char sbuf[INET6_ADDRSTRLEN];
994 char dbuf[INET6_ADDRSTRLEN];
995 char xbuf[INET6_ADDRSTRLEN];
997 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
998 "Routing %s packet from %s:%u -> %s:%u to destination %s:%u\n",
999 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
1000 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
1002 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
1004 inet_ntop (destination->details.exit_destination.af,
1005 &destination->details.exit_destination.ip,
1006 xbuf, sizeof (xbuf)),
1012 /* make compiler happy */
1015 char sbuf[INET6_ADDRSTRLEN];
1016 char dbuf[INET6_ADDRSTRLEN];
1018 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1019 "Routing %s packet from %s:%u -> %s:%u to service %s at peer %s\n",
1020 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
1021 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
1023 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
1025 GNUNET_h2s (&destination->details.service_destination.service_descriptor),
1026 GNUNET_i2s (&destination->details.service_destination.target));
1031 /* see if we have an existing tunnel for this destination */
1032 ts = GNUNET_CONTAINER_multihashmap_get (tunnel_map,
1036 /* need to either use the existing tunnel from the destination (if still
1037 available) or create a fresh one */
1038 is_new = GNUNET_YES;
1039 if (NULL == destination->ts)
1040 ts = create_tunnel_to_destination (destination, NULL, af, 0);
1042 ts = destination->ts;
1045 destination->ts = NULL;
1046 ts->destination_container = NULL; /* no longer 'contained' */
1047 /* now bind existing "unbound" tunnel to our IP/port tuple */
1048 ts->protocol = protocol;
1052 ts->source_ip.v4 = * (const struct in_addr *) source_ip;
1053 ts->destination_ip.v4 = * (const struct in_addr *) destination_ip;
1057 ts->source_ip.v6 = * (const struct in6_addr *) source_ip;
1058 ts->destination_ip.v6 = * (const struct in6_addr *) destination_ip;
1060 ts->source_port = source_port;
1061 ts->destination_port = destination_port;
1062 ts->heap_node = GNUNET_CONTAINER_heap_insert (tunnel_heap,
1064 GNUNET_TIME_absolute_get ().abs_value);
1065 GNUNET_assert (GNUNET_YES ==
1066 GNUNET_CONTAINER_multihashmap_put (tunnel_map,
1069 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1070 GNUNET_STATISTICS_update (stats,
1071 gettext_noop ("# Active tunnels"),
1073 while (GNUNET_CONTAINER_multihashmap_size (tunnel_map) > max_tunnel_mappings)
1079 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
1081 GNUNET_TIME_absolute_get ().abs_value);
1083 GNUNET_assert (NULL != ts->tunnel);
1085 /* send via tunnel */
1089 if (destination->is_service)
1091 struct GNUNET_EXIT_UdpServiceMessage *usm;
1093 mlen = sizeof (struct GNUNET_EXIT_UdpServiceMessage) +
1094 payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1095 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1100 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1103 usm = (struct GNUNET_EXIT_UdpServiceMessage *) &tnq[1];
1104 usm->header.size = htons ((uint16_t) mlen);
1105 usm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE);
1106 /* if the source port is below 32000, we assume it has a special
1107 meaning; if not, we pick a random port (this is a heuristic) */
1108 usm->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1109 usm->destination_port = udp->destination_port;
1110 usm->service_descriptor = destination->details.service_destination.service_descriptor;
1113 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1117 struct GNUNET_EXIT_UdpInternetMessage *uim;
1118 struct in_addr *ip4dst;
1119 struct in6_addr *ip6dst;
1122 mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) +
1123 alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1124 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1129 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) +
1133 uim = (struct GNUNET_EXIT_UdpInternetMessage *) &tnq[1];
1134 uim->header.size = htons ((uint16_t) mlen);
1135 uim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET);
1136 uim->af = htonl (destination->details.exit_destination.af);
1137 uim->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1138 uim->destination_port = udp->destination_port;
1139 switch (destination->details.exit_destination.af)
1142 ip4dst = (struct in_addr *) &uim[1];
1143 *ip4dst = destination->details.exit_destination.ip.v4;
1144 payload = &ip4dst[1];
1147 ip6dst = (struct in6_addr *) &uim[1];
1148 *ip6dst = destination->details.exit_destination.ip.v6;
1149 payload = &ip6dst[1];
1156 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1162 if (destination->is_service)
1164 struct GNUNET_EXIT_TcpServiceStartMessage *tsm;
1166 mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) +
1167 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1168 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1173 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1176 tsm = (struct GNUNET_EXIT_TcpServiceStartMessage *) &tnq[1];
1177 tsm->header.size = htons ((uint16_t) mlen);
1178 tsm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START);
1179 tsm->reserved = htonl (0);
1180 tsm->service_descriptor = destination->details.service_destination.service_descriptor;
1181 tsm->tcp_header = *tcp;
1184 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1188 struct GNUNET_EXIT_TcpInternetStartMessage *tim;
1189 struct in_addr *ip4dst;
1190 struct in6_addr *ip6dst;
1193 mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) +
1194 alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1195 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1200 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1203 tim = (struct GNUNET_EXIT_TcpInternetStartMessage *) &tnq[1];
1204 tim->header.size = htons ((uint16_t) mlen);
1205 tim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START);
1206 tim->af = htonl (destination->details.exit_destination.af);
1207 tim->tcp_header = *tcp;
1208 switch (destination->details.exit_destination.af)
1211 ip4dst = (struct in_addr *) &tim[1];
1212 *ip4dst = destination->details.exit_destination.ip.v4;
1213 payload = &ip4dst[1];
1216 ip6dst = (struct in6_addr *) &tim[1];
1217 *ip6dst = destination->details.exit_destination.ip.v6;
1218 payload = &ip6dst[1];
1225 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1230 struct GNUNET_EXIT_TcpDataMessage *tdm;
1232 mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) +
1233 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1234 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1239 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1242 tdm = (struct GNUNET_EXIT_TcpDataMessage *) &tnq[1];
1243 tdm->header.size = htons ((uint16_t) mlen);
1244 tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT);
1245 tdm->reserved = htonl (0);
1246 tdm->tcp_header = *tcp;
1249 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1253 case IPPROTO_ICMPV6:
1254 if (destination->is_service)
1256 struct GNUNET_EXIT_IcmpServiceMessage *ism;
1258 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1259 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1260 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1265 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1267 ism = (struct GNUNET_EXIT_IcmpServiceMessage *) &tnq[1];
1268 ism->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE);
1269 ism->af = htonl (af); /* need to tell destination ICMP protocol family! */
1270 ism->service_descriptor = destination->details.service_destination.service_descriptor;
1271 ism->icmp_header = *icmp;
1272 /* ICMP protocol translation will be done by the receiver (as we don't know
1273 the target AF); however, we still need to possibly discard the payload
1274 depending on the ICMP type */
1280 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1281 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1283 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1284 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1285 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1286 /* throw away ICMP payload, won't be useful for the other side anyway */
1287 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1290 GNUNET_STATISTICS_update (stats,
1291 gettext_noop ("# ICMPv4 packets dropped (not allowed)"),
1295 /* end of AF_INET */
1300 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1301 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1302 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1303 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1304 /* throw away ICMP payload, won't be useful for the other side anyway */
1305 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1307 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1308 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1311 GNUNET_STATISTICS_update (stats,
1312 gettext_noop ("# ICMPv6 packets dropped (not allowed)"),
1316 /* end of AF_INET6 */
1323 /* update length calculations, as payload_length may have changed */
1324 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1325 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1327 ism->header.size = htons ((uint16_t) mlen);
1328 /* finally, copy payload (if there is any left...) */
1331 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1335 struct GNUNET_EXIT_IcmpInternetMessage *iim;
1336 struct in_addr *ip4dst;
1337 struct in6_addr *ip6dst;
1340 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1341 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1342 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1347 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) +
1350 iim = (struct GNUNET_EXIT_IcmpInternetMessage *) &tnq[1];
1351 iim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET);
1352 iim->icmp_header = *icmp;
1353 /* Perform ICMP protocol-translation (depending on destination AF and source AF)
1354 and throw away ICMP payload depending on ICMP message type */
1360 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1361 if (destination->details.exit_destination.af == AF_INET6)
1362 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1364 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1365 if (destination->details.exit_destination.af == AF_INET6)
1366 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1368 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1369 if (destination->details.exit_destination.af == AF_INET6)
1370 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
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_TIME_EXCEEDED:
1375 if (destination->details.exit_destination.af == AF_INET6)
1376 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1377 /* throw away IP-payload, exit will have to make it up anyway */
1378 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1380 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1381 if (destination->details.exit_destination.af == AF_INET6)
1383 GNUNET_STATISTICS_update (stats,
1384 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1389 /* throw away IP-payload, exit will have to make it up anyway */
1390 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1393 GNUNET_STATISTICS_update (stats,
1394 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1399 /* end of AF_INET */
1404 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1405 if (destination->details.exit_destination.af == AF_INET6)
1406 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
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_TIME_EXCEEDED:
1411 if (destination->details.exit_destination.af == AF_INET)
1412 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1413 /* throw away IP-payload, exit will have to make it up anyway */
1414 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1416 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1417 if (destination->details.exit_destination.af == AF_INET)
1419 GNUNET_STATISTICS_update (stats,
1420 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1425 /* throw away IP-payload, exit will have to make it up anyway */
1426 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1428 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1429 if (destination->details.exit_destination.af == AF_INET)
1431 GNUNET_STATISTICS_update (stats,
1432 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1437 /* throw away IP-payload, exit will have to make it up anyway */
1438 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1440 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1441 if (destination->details.exit_destination.af == AF_INET)
1442 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1444 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1445 if (destination->details.exit_destination.af == AF_INET)
1446 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1449 GNUNET_STATISTICS_update (stats,
1450 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1455 /* end of AF_INET6 */
1460 /* update length calculations, as payload_length may have changed */
1461 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1462 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1464 iim->header.size = htons ((uint16_t) mlen);
1466 /* need to tell destination ICMP protocol family! */
1467 iim->af = htonl (destination->details.exit_destination.af);
1468 switch (destination->details.exit_destination.af)
1471 ip4dst = (struct in_addr *) &iim[1];
1472 *ip4dst = destination->details.exit_destination.ip.v4;
1473 payload = &ip4dst[1];
1476 ip6dst = (struct in6_addr *) &iim[1];
1477 *ip6dst = destination->details.exit_destination.ip.v6;
1478 payload = &ip6dst[1];
1485 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1489 /* not supported above, how can we get here !? */
1493 send_to_tunnel (tnq, ts);
1498 * Receive packets from the helper-process (someone send to the local
1499 * virtual tunnel interface). Find the destination mapping, and if it
1500 * exists, identify the correct MESH tunnel (or possibly create it)
1501 * and forward the packet.
1503 * @param cls closure, NULL
1504 * @param client NULL
1505 * @param message message we got from the client (VPN tunnel interface)
1508 message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED,
1509 const struct GNUNET_MessageHeader *message)
1511 const struct GNUNET_TUN_Layer2PacketHeader *tun;
1513 GNUNET_HashCode key;
1514 struct DestinationEntry *de;
1516 GNUNET_STATISTICS_update (stats,
1517 gettext_noop ("# Packets received from TUN interface"),
1519 mlen = ntohs (message->size);
1520 if ( (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
1521 (mlen < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader)) )
1526 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1527 mlen -= (sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader));
1528 switch (ntohs (tun->proto))
1532 const struct GNUNET_TUN_IPv6Header *pkt6;
1534 if (mlen < sizeof (struct GNUNET_TUN_IPv6Header))
1540 pkt6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1541 get_destination_key_from_ip (AF_INET6,
1542 &pkt6->destination_address,
1544 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1545 /* FIXME: do we need to guard against hash collision?
1546 (if so, we need to also store the local destination IP in the
1547 destination entry and then compare here; however, the risk
1548 of collision seems minimal AND the impact is unlikely to be
1549 super-problematic as well... */
1552 char buf[INET6_ADDRSTRLEN];
1554 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1555 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1556 inet_ntop (AF_INET6,
1557 &pkt6->destination_address,
1565 &pkt6->source_address,
1566 &pkt6->destination_address,
1568 mlen - sizeof (struct GNUNET_TUN_IPv6Header));
1573 struct GNUNET_TUN_IPv4Header *pkt4;
1575 if (mlen < sizeof (struct GNUNET_TUN_IPv4Header))
1581 pkt4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1582 get_destination_key_from_ip (AF_INET,
1583 &pkt4->destination_address,
1585 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1586 /* FIXME: do we need to guard against hash collision?
1587 (if so, we need to also store the local destination IP in the
1588 destination entry and then compare here; however, the risk
1589 of collision seems minimal AND the impact is unlikely to be
1590 super-problematic as well... */
1593 char buf[INET_ADDRSTRLEN];
1595 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1596 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1598 &pkt4->destination_address,
1603 if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header))
1605 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1606 _("Received IPv4 packet with options (dropping it)\n"));
1612 &pkt4->source_address,
1613 &pkt4->destination_address,
1615 mlen - sizeof (struct GNUNET_TUN_IPv4Header));
1619 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1620 _("Received packet of unknown protocol %d from TUN (dropping it)\n"),
1621 (unsigned int) ntohs (tun->proto));
1629 * Synthesize a plausible ICMP payload for an ICMP error
1630 * response on the given tunnel.
1632 * @param ts tunnel information
1633 * @param ipp IPv4 header to fill in (ICMP payload)
1634 * @param udp "UDP" header to fill in (ICMP payload); might actually
1635 * also be the first 8 bytes of the TCP header
1638 make_up_icmpv4_payload (struct TunnelState *ts,
1639 struct GNUNET_TUN_IPv4Header *ipp,
1640 struct GNUNET_TUN_UdpHeader *udp)
1642 GNUNET_TUN_initialize_ipv4_header (ipp,
1644 sizeof (struct GNUNET_TUN_TcpHeader),
1646 &ts->destination_ip.v4);
1647 udp->source_port = htons (ts->source_port);
1648 udp->destination_port = htons (ts->destination_port);
1649 udp->len = htons (0);
1650 udp->crc = htons (0);
1655 * Synthesize a plausible ICMP payload for an ICMP error
1656 * response on the given tunnel.
1658 * @param ts tunnel information
1659 * @param ipp IPv6 header to fill in (ICMP payload)
1660 * @param udp "UDP" header to fill in (ICMP payload); might actually
1661 * also be the first 8 bytes of the TCP header
1664 make_up_icmpv6_payload (struct TunnelState *ts,
1665 struct GNUNET_TUN_IPv6Header *ipp,
1666 struct GNUNET_TUN_UdpHeader *udp)
1668 GNUNET_TUN_initialize_ipv6_header (ipp,
1670 sizeof (struct GNUNET_TUN_TcpHeader),
1672 &ts->destination_ip.v6);
1673 udp->source_port = htons (ts->source_port);
1674 udp->destination_port = htons (ts->destination_port);
1675 udp->len = htons (0);
1676 udp->crc = htons (0);
1681 * We got an ICMP packet back from the MESH tunnel. Pass it on to the
1682 * local virtual interface via the helper.
1684 * @param cls closure, NULL
1685 * @param tunnel connection to the other end
1686 * @param tunnel_ctx pointer to our 'struct TunnelState *'
1687 * @param sender who sent the message
1688 * @param message the actual message
1689 * @param atsi performance data for the connection
1690 * @return GNUNET_OK to keep the connection open,
1691 * GNUNET_SYSERR to close it (signal serious error)
1694 receive_icmp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1695 void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender,
1696 const struct GNUNET_MessageHeader *message,
1697 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
1699 struct TunnelState *ts = *tunnel_ctx;
1700 const struct GNUNET_EXIT_IcmpToVPNMessage *i2v;
1703 GNUNET_STATISTICS_update (stats,
1704 gettext_noop ("# ICMP packets received from mesh"),
1706 mlen = ntohs (message->size);
1707 if (mlen < sizeof (struct GNUNET_EXIT_IcmpToVPNMessage))
1709 GNUNET_break_op (0);
1710 return GNUNET_SYSERR;
1712 if (NULL == ts->heap_node)
1714 GNUNET_break_op (0);
1715 return GNUNET_SYSERR;
1717 if (AF_UNSPEC == ts->af)
1719 GNUNET_break_op (0);
1720 return GNUNET_SYSERR;
1722 i2v = (const struct GNUNET_EXIT_IcmpToVPNMessage *) message;
1723 mlen -= sizeof (struct GNUNET_EXIT_IcmpToVPNMessage);
1725 char sbuf[INET6_ADDRSTRLEN];
1726 char dbuf[INET6_ADDRSTRLEN];
1728 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1729 "Received ICMP packet from mesh, sending %u bytes from %s -> %s via TUN\n",
1730 (unsigned int) mlen,
1731 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
1732 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)));
1738 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
1739 + sizeof (struct GNUNET_TUN_IcmpHeader)
1740 + sizeof (struct GNUNET_MessageHeader) +
1741 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1744 /* reserve some extra space in case we have an ICMP type here where
1745 we will need to make up the payload ourselves */
1746 char buf[size + sizeof (struct GNUNET_TUN_IPv4Header) + 8] GNUNET_ALIGN;
1747 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1748 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1749 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1750 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv4[1];
1751 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1752 tun->flags = htons (0);
1753 tun->proto = htons (ETH_P_IPV4);
1754 GNUNET_TUN_initialize_ipv4_header (ipv4,
1756 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1757 &ts->destination_ip.v4,
1759 *icmp = i2v->icmp_header;
1763 /* For some ICMP types, we need to adjust (make up) the payload here.
1764 Also, depending on the AF used on the other side, we have to
1765 do ICMP PT (translate ICMP types) */
1766 switch (ntohl (i2v->af))
1771 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1772 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1774 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1775 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1776 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1778 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1779 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1783 /* sender did not strip ICMP payload? */
1784 GNUNET_break_op (0);
1785 return GNUNET_SYSERR;
1787 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1788 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1789 make_up_icmpv4_payload (ts, ipp, udp);
1793 GNUNET_break_op (0);
1794 GNUNET_STATISTICS_update (stats,
1795 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1797 return GNUNET_SYSERR;
1802 /* ICMP PT 6-to-4 and possibly making up payloads */
1805 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1806 icmp->type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
1808 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1809 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1813 /* sender did not strip ICMP payload? */
1814 GNUNET_break_op (0);
1815 return GNUNET_SYSERR;
1817 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1818 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1819 make_up_icmpv4_payload (ts, ipp, udp);
1822 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1823 icmp->type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1825 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1826 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1830 /* sender did not strip ICMP payload? */
1831 GNUNET_break_op (0);
1832 return GNUNET_SYSERR;
1834 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1835 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1836 make_up_icmpv4_payload (ts, ipp, udp);
1839 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1840 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1841 GNUNET_STATISTICS_update (stats,
1842 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1845 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1846 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1848 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1849 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1852 GNUNET_break_op (0);
1853 GNUNET_STATISTICS_update (stats,
1854 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1856 return GNUNET_SYSERR;
1861 GNUNET_break_op (0);
1862 return GNUNET_SYSERR;
1864 msg->size = htons (size);
1865 GNUNET_TUN_calculate_icmp_checksum (icmp,
1868 (void) GNUNET_HELPER_send (helper_handle,
1877 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
1878 + sizeof (struct GNUNET_TUN_IcmpHeader)
1879 + sizeof (struct GNUNET_MessageHeader) +
1880 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1883 char buf[size + sizeof (struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN;
1884 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1885 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1886 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
1887 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv6[1];
1888 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1889 tun->flags = htons (0);
1890 tun->proto = htons (ETH_P_IPV6);
1891 GNUNET_TUN_initialize_ipv6_header (ipv6,
1893 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1894 &ts->destination_ip.v6,
1896 *icmp = i2v->icmp_header;
1901 /* For some ICMP types, we need to adjust (make up) the payload here.
1902 Also, depending on the AF used on the other side, we have to
1903 do ICMP PT (translate ICMP types) */
1904 switch (ntohl (i2v->af))
1907 /* ICMP PT 4-to-6 and possibly making up payloads */
1910 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1911 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1913 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1914 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1916 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1917 icmp->type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1919 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1920 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1924 /* sender did not strip ICMP payload? */
1925 GNUNET_break_op (0);
1926 return GNUNET_SYSERR;
1928 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1929 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1930 make_up_icmpv6_payload (ts, ipp, udp);
1933 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1934 icmp->type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1936 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1937 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1941 /* sender did not strip ICMP payload? */
1942 GNUNET_break_op (0);
1943 return GNUNET_SYSERR;
1945 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1946 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1947 make_up_icmpv6_payload (ts, ipp, udp);
1950 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1951 GNUNET_STATISTICS_update (stats,
1952 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1956 GNUNET_break_op (0);
1957 GNUNET_STATISTICS_update (stats,
1958 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1960 return GNUNET_SYSERR;
1967 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1968 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1969 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1970 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1972 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1973 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1977 /* sender did not strip ICMP payload? */
1978 GNUNET_break_op (0);
1979 return GNUNET_SYSERR;
1981 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1982 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1983 make_up_icmpv6_payload (ts, ipp, udp);
1986 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1989 GNUNET_break_op (0);
1990 GNUNET_STATISTICS_update (stats,
1991 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1993 return GNUNET_SYSERR;
1998 GNUNET_break_op (0);
1999 return GNUNET_SYSERR;
2001 msg->size = htons (size);
2002 GNUNET_TUN_calculate_icmp_checksum (icmp,
2004 (void) GNUNET_HELPER_send (helper_handle,
2014 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2016 GNUNET_TIME_absolute_get ().abs_value);
2022 * We got a UDP packet back from the MESH tunnel. Pass it on to the
2023 * local virtual interface via the helper.
2025 * @param cls closure, NULL
2026 * @param tunnel connection to the other end
2027 * @param tunnel_ctx pointer to our 'struct TunnelState *'
2028 * @param sender who sent the message
2029 * @param message the actual message
2030 * @param atsi performance data for the connection
2031 * @return GNUNET_OK to keep the connection open,
2032 * GNUNET_SYSERR to close it (signal serious error)
2035 receive_udp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
2036 void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender,
2037 const struct GNUNET_MessageHeader *message,
2038 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
2040 struct TunnelState *ts = *tunnel_ctx;
2041 const struct GNUNET_EXIT_UdpReplyMessage *reply;
2044 GNUNET_STATISTICS_update (stats,
2045 gettext_noop ("# UDP packets received from mesh"),
2047 mlen = ntohs (message->size);
2048 if (mlen < sizeof (struct GNUNET_EXIT_UdpReplyMessage))
2050 GNUNET_break_op (0);
2051 return GNUNET_SYSERR;
2053 if (NULL == ts->heap_node)
2055 GNUNET_break_op (0);
2056 return GNUNET_SYSERR;
2058 if (AF_UNSPEC == ts->af)
2060 GNUNET_break_op (0);
2061 return GNUNET_SYSERR;
2063 reply = (const struct GNUNET_EXIT_UdpReplyMessage *) message;
2064 mlen -= sizeof (struct GNUNET_EXIT_UdpReplyMessage);
2066 char sbuf[INET6_ADDRSTRLEN];
2067 char dbuf[INET6_ADDRSTRLEN];
2069 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2070 "Received UDP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2071 (unsigned int) mlen,
2072 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2073 ts->destination_port,
2074 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2081 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2082 + sizeof (struct GNUNET_TUN_UdpHeader)
2083 + sizeof (struct GNUNET_MessageHeader) +
2084 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2087 char buf[size] GNUNET_ALIGN;
2088 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2089 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2090 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2091 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1];
2092 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2093 msg->size = htons (size);
2094 tun->flags = htons (0);
2095 tun->proto = htons (ETH_P_IPV4);
2096 GNUNET_TUN_initialize_ipv4_header (ipv4,
2098 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2099 &ts->destination_ip.v4,
2101 if (0 == ntohs (reply->source_port))
2102 udp->source_port = htons (ts->destination_port);
2104 udp->source_port = reply->source_port;
2105 if (0 == ntohs (reply->destination_port))
2106 udp->destination_port = htons (ts->source_port);
2108 udp->destination_port = reply->destination_port;
2109 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2110 GNUNET_TUN_calculate_udp4_checksum (ipv4,
2117 (void) GNUNET_HELPER_send (helper_handle,
2126 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2127 + sizeof (struct GNUNET_TUN_UdpHeader)
2128 + sizeof (struct GNUNET_MessageHeader) +
2129 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2132 char buf[size] GNUNET_ALIGN;
2133 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2134 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2135 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2136 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1];
2137 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2138 msg->size = htons (size);
2139 tun->flags = htons (0);
2140 tun->proto = htons (ETH_P_IPV6);
2141 GNUNET_TUN_initialize_ipv6_header (ipv6,
2143 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2144 &ts->destination_ip.v6,
2146 if (0 == ntohs (reply->source_port))
2147 udp->source_port = htons (ts->destination_port);
2149 udp->source_port = reply->source_port;
2150 if (0 == ntohs (reply->destination_port))
2151 udp->destination_port = htons (ts->source_port);
2153 udp->destination_port = reply->destination_port;
2154 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2155 GNUNET_TUN_calculate_udp6_checksum (ipv6,
2161 (void) GNUNET_HELPER_send (helper_handle,
2171 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2173 GNUNET_TIME_absolute_get ().abs_value);
2179 * We got a TCP packet back from the MESH tunnel. Pass it on to the
2180 * local virtual interface via the helper.
2182 * @param cls closure, NULL
2183 * @param tunnel connection to the other end
2184 * @param tunnel_ctx pointer to our 'struct TunnelState *'
2185 * @param sender who sent the message
2186 * @param message the actual message
2187 * @param atsi performance data for the connection
2188 * @return GNUNET_OK to keep the connection open,
2189 * GNUNET_SYSERR to close it (signal serious error)
2192 receive_tcp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
2194 const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED,
2195 const struct GNUNET_MessageHeader *message,
2196 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
2198 struct TunnelState *ts = *tunnel_ctx;
2199 const struct GNUNET_EXIT_TcpDataMessage *data;
2202 GNUNET_STATISTICS_update (stats,
2203 gettext_noop ("# TCP packets received from mesh"),
2205 mlen = ntohs (message->size);
2206 if (mlen < sizeof (struct GNUNET_EXIT_TcpDataMessage))
2208 GNUNET_break_op (0);
2209 return GNUNET_SYSERR;
2211 if (NULL == ts->heap_node)
2213 GNUNET_break_op (0);
2214 return GNUNET_SYSERR;
2216 data = (const struct GNUNET_EXIT_TcpDataMessage *) message;
2217 mlen -= sizeof (struct GNUNET_EXIT_TcpDataMessage);
2219 char sbuf[INET6_ADDRSTRLEN];
2220 char dbuf[INET6_ADDRSTRLEN];
2222 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2223 "Received TCP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2224 (unsigned int) mlen,
2225 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2226 ts->destination_port,
2227 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2230 if (data->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
2232 GNUNET_break_op (0);
2233 return GNUNET_SYSERR;
2239 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2240 + sizeof (struct GNUNET_TUN_TcpHeader)
2241 + sizeof (struct GNUNET_MessageHeader) +
2242 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2245 char buf[size] GNUNET_ALIGN;
2246 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2247 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2248 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2249 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv4[1];
2250 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2251 msg->size = htons (size);
2252 tun->flags = htons (0);
2253 tun->proto = htons (ETH_P_IPV4);
2254 GNUNET_TUN_initialize_ipv4_header (ipv4,
2256 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2257 &ts->destination_ip.v4,
2259 *tcp = data->tcp_header;
2260 tcp->source_port = htons (ts->destination_port);
2261 tcp->destination_port = htons (ts->source_port);
2262 GNUNET_TUN_calculate_tcp4_checksum (ipv4,
2269 (void) GNUNET_HELPER_send (helper_handle,
2278 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2279 + sizeof (struct GNUNET_TUN_TcpHeader)
2280 + sizeof (struct GNUNET_MessageHeader) +
2281 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2284 char buf[size] GNUNET_ALIGN;
2285 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2286 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2287 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2288 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv6[1];
2289 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2290 msg->size = htons (size);
2291 tun->flags = htons (0);
2292 tun->proto = htons (ETH_P_IPV6);
2293 GNUNET_TUN_initialize_ipv6_header (ipv6,
2295 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2296 &ts->destination_ip.v6,
2298 *tcp = data->tcp_header;
2299 tcp->source_port = htons (ts->destination_port);
2300 tcp->destination_port = htons (ts->source_port);
2301 GNUNET_TUN_calculate_tcp6_checksum (ipv6,
2308 (void) GNUNET_HELPER_send (helper_handle,
2316 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2318 GNUNET_TIME_absolute_get ().abs_value);
2324 * Allocate an IPv4 address from the range of the tunnel
2325 * for a new redirection.
2327 * @param v4 where to store the address
2328 * @return GNUNET_OK on success,
2329 * GNUNET_SYSERR on error
2332 allocate_v4_address (struct in_addr *v4)
2334 const char *ipv4addr = vpn_argv[4];
2335 const char *ipv4mask = vpn_argv[5];
2336 struct in_addr addr;
2337 struct in_addr mask;
2339 GNUNET_HashCode key;
2342 GNUNET_assert (1 == inet_pton (AF_INET, ipv4addr, &addr));
2343 GNUNET_assert (1 == inet_pton (AF_INET, ipv4mask, &mask));
2344 /* Given 192.168.0.1/255.255.0.0, we want a mask
2345 of '192.168.255.255', thus: */
2346 mask.s_addr = addr.s_addr | ~mask.s_addr;
2353 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2354 _("Failed to find unallocated IPv4 address in VPN's range\n"));
2355 return GNUNET_SYSERR;
2357 /* Pick random IPv4 address within the subnet, except 'addr' or 'mask' itself */
2358 rnd.s_addr = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2360 v4->s_addr = (addr.s_addr | rnd.s_addr) & mask.s_addr;
2361 get_destination_key_from_ip (AF_INET,
2365 while ( (GNUNET_YES ==
2366 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2368 (v4->s_addr == addr.s_addr) ||
2369 (v4->s_addr == mask.s_addr) );
2375 * Allocate an IPv6 address from the range of the tunnel
2376 * for a new redirection.
2378 * @param v6 where to store the address
2379 * @return GNUNET_OK on success,
2380 * GNUNET_SYSERR on error
2383 allocate_v6_address (struct in6_addr *v6)
2385 const char *ipv6addr = vpn_argv[2];
2386 struct in6_addr addr;
2387 struct in6_addr mask;
2388 struct in6_addr rnd;
2390 GNUNET_HashCode key;
2393 GNUNET_assert (1 == inet_pton (AF_INET6, ipv6addr, &addr));
2394 GNUNET_assert (ipv6prefix < 128);
2395 /* Given ABCD::/96, we want a mask of 'ABCD::FFFF:FFFF,
2398 for (i=127;i>=ipv6prefix;i--)
2399 mask.s6_addr[i / 8] |= (1 << (i % 8));
2401 /* Pick random IPv6 address within the subnet, except 'addr' or 'mask' itself */
2408 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2409 _("Failed to find unallocated IPv6 address in VPN's range\n"));
2410 return GNUNET_SYSERR;
2415 rnd.s6_addr[i] = (unsigned char) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2418 = (addr.s6_addr[i] | rnd.s6_addr[i]) & mask.s6_addr[i];
2420 get_destination_key_from_ip (AF_INET6,
2424 while ( (GNUNET_YES ==
2425 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2429 sizeof (struct in6_addr))) ||
2432 sizeof (struct in6_addr))) );
2438 * Free resources occupied by a destination entry.
2440 * @param de entry to free
2443 free_destination_entry (struct DestinationEntry *de)
2445 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2446 "Cleaning up destination entry\n");
2447 GNUNET_STATISTICS_update (stats,
2448 gettext_noop ("# Active destinations"),
2452 free_tunnel_state (de->ts);
2453 GNUNET_assert (NULL == de->ts);
2455 if (NULL != de->heap_node)
2457 GNUNET_CONTAINER_heap_remove_node (de->heap_node);
2458 de->heap_node = NULL;
2459 GNUNET_assert (GNUNET_YES ==
2460 GNUNET_CONTAINER_multihashmap_remove (destination_map,
2469 * We have too many active destinations. Clean up the oldest destination.
2471 * @param except destination that must NOT be cleaned up, even if it is the oldest
2474 expire_destination (struct DestinationEntry *except)
2476 struct DestinationEntry *de;
2478 de = GNUNET_CONTAINER_heap_peek (destination_heap);
2479 GNUNET_assert (NULL != de);
2481 return; /* can't do this */
2482 free_destination_entry (de);
2487 * Allocate an IP address for the response.
2489 * @param result_af desired address family; set to the actual
2490 * address family; can initially be AF_UNSPEC if there
2491 * is no preference; will be set to AF_UNSPEC if the
2493 * @param addr set to either v4 or v6 depending on which
2494 * storage location was used; set to NULL if allocation failed
2495 * @param v4 storage space for an IPv4 address
2496 * @param v6 storage space for an IPv6 address
2497 * @return GNUNET_OK normally, GNUNET_SYSERR if '*result_af' was
2498 * an unsupported address family (not AF_INET, AF_INET6 or AF_UNSPEC)
2501 allocate_response_ip (int *result_af,
2504 struct in6_addr *v6)
2511 allocate_v4_address (v4))
2512 *result_af = AF_UNSPEC;
2518 allocate_v6_address (v6))
2519 *result_af = AF_UNSPEC;
2525 allocate_v4_address (v4))
2528 *result_af = AF_INET;
2530 else if (GNUNET_OK ==
2531 allocate_v6_address (v6))
2534 *result_af = AF_INET6;
2539 return GNUNET_SYSERR;
2546 * A client asks us to setup a redirection via some exit
2547 * node to a particular IP. Setup the redirection and
2548 * give the client the allocated IP.
2551 * @param client requesting client
2552 * @param message redirection request (a 'struct RedirectToIpRequestMessage')
2555 service_redirect_to_ip (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
2556 const struct GNUNET_MessageHeader *message)
2560 const struct RedirectToIpRequestMessage *msg;
2566 struct DestinationEntry *de;
2567 GNUNET_HashCode key;
2568 struct TunnelState *ts;
2570 /* validate and parse request */
2571 mlen = ntohs (message->size);
2572 if (mlen < sizeof (struct RedirectToIpRequestMessage))
2575 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2578 alen = mlen - sizeof (struct RedirectToIpRequestMessage);
2579 msg = (const struct RedirectToIpRequestMessage *) message;
2580 addr_af = (int) htonl (msg->addr_af);
2584 if (alen != sizeof (struct in_addr))
2587 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2592 if (alen != sizeof (struct in6_addr))
2595 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2601 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2605 /* allocate response IP */
2606 result_af = (int) htonl (msg->result_af);
2607 if (GNUNET_OK != allocate_response_ip (&result_af,
2611 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2614 if ( (result_af == AF_UNSPEC) ||
2615 (GNUNET_NO == ntohl (msg->nac)) )
2617 /* send reply "instantly" */
2618 send_client_reply (client,
2623 if (result_af == AF_UNSPEC)
2625 /* failure, we're done */
2626 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2631 char sbuf[INET6_ADDRSTRLEN];
2632 char dbuf[INET6_ADDRSTRLEN];
2634 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2635 "Allocated address %s for redirection via exit to %s\n",
2636 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2638 &msg[1], dbuf, sizeof (dbuf)));
2641 /* setup destination record */
2642 de = GNUNET_malloc (sizeof (struct DestinationEntry));
2643 de->is_service = GNUNET_NO;
2644 de->details.exit_destination.af = addr_af;
2645 memcpy (&de->details.exit_destination.ip,
2648 get_destination_key_from_ip (result_af,
2652 GNUNET_assert (GNUNET_OK ==
2653 GNUNET_CONTAINER_multihashmap_put (destination_map,
2656 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2657 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2659 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
2660 GNUNET_STATISTICS_update (stats,
2661 gettext_noop ("# Active destinations"),
2663 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2664 expire_destination (de);
2666 /* setup tunnel to destination */
2667 ts = create_tunnel_to_destination (de,
2668 (GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
2674 ts->destination_ip.v4 = v4;
2677 ts->destination_ip.v6 = v6;
2683 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2688 * A client asks us to setup a redirection to a particular peer
2689 * offering a service. Setup the redirection and give the client the
2693 * @param client requesting client
2694 * @param message redirection request (a 'struct RedirectToPeerRequestMessage')
2697 service_redirect_to_service (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
2698 const struct GNUNET_MessageHeader *message)
2700 const struct RedirectToServiceRequestMessage *msg;
2705 struct DestinationEntry *de;
2706 GNUNET_HashCode key;
2707 struct TunnelState *ts;
2710 msg = (const struct RedirectToServiceRequestMessage *) message;
2712 /* allocate response IP */
2713 result_af = (int) htonl (msg->result_af);
2714 if (GNUNET_OK != allocate_response_ip (&result_af,
2718 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2721 if ( (result_af == AF_UNSPEC) ||
2722 (GNUNET_NO == ntohl (msg->nac)) )
2724 /* send reply "instantly" */
2725 send_client_reply (client,
2730 if (result_af == AF_UNSPEC)
2732 /* failure, we're done */
2733 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2734 _("Failed to allocate IP address for new destination\n"));
2735 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2740 char sbuf[INET6_ADDRSTRLEN];
2742 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2743 "Allocated address %s for redirection to service %s on peer %s\n",
2744 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2745 GNUNET_h2s (&msg->service_descriptor),
2746 GNUNET_i2s (&msg->target));
2749 /* setup destination record */
2750 de = GNUNET_malloc (sizeof (struct DestinationEntry));
2751 de->is_service = GNUNET_YES;
2752 de->details.service_destination.service_descriptor = msg->service_descriptor;
2753 de->details.service_destination.target = msg->target;
2754 get_destination_key_from_ip (result_af,
2758 GNUNET_assert (GNUNET_OK ==
2759 GNUNET_CONTAINER_multihashmap_put (destination_map,
2762 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2763 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2765 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
2766 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2767 expire_destination (de);
2768 ts = create_tunnel_to_destination (de,
2769 (GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
2775 ts->destination_ip.v4 = v4;
2778 ts->destination_ip.v6 = v6;
2784 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2790 * Function called for inbound tunnels. As we don't offer
2791 * any mesh services, this function should never be called.
2793 * @param cls closure
2794 * @param tunnel new handle to the tunnel
2795 * @param initiator peer that started the tunnel
2796 * @param atsi performance information for the tunnel
2797 * @return initial tunnel context for the tunnel
2798 * (can be NULL -- that's not an error)
2801 inbound_tunnel_cb (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
2802 const struct GNUNET_PeerIdentity *initiator,
2803 const struct GNUNET_ATS_Information *atsi)
2805 /* How can and why should anyone open an inbound tunnel to vpn? */
2812 * Function called whenever an inbound tunnel is destroyed. Should clean up
2813 * any associated state.
2815 * @param cls closure (set from GNUNET_MESH_connect)
2816 * @param tunnel connection to the other end (henceforth invalid)
2817 * @param tunnel_ctx place where local state associated
2818 * with the tunnel is stored (our 'struct TunnelState')
2821 tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel_ctx)
2823 /* we don't have inbound tunnels, so this function should never be called */
2829 * Free memory occupied by an entry in the destination map.
2833 * @param value a 'struct DestinationEntry *'
2834 * @return GNUNET_OK (continue to iterate)
2837 cleanup_destination (void *cls,
2838 const GNUNET_HashCode *key,
2841 struct DestinationEntry *de = value;
2843 free_destination_entry (de);
2849 * Free memory occupied by an entry in the tunnel map.
2853 * @param value a 'struct TunnelState *'
2854 * @return GNUNET_OK (continue to iterate)
2857 cleanup_tunnel (void *cls,
2858 const GNUNET_HashCode *key,
2861 struct TunnelState *ts = value;
2863 free_tunnel_state (ts);
2869 * Function scheduled as very last function, cleans up after us
2875 cleanup (void *cls GNUNET_UNUSED,
2876 const struct GNUNET_SCHEDULER_TaskContext *tc)
2880 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2881 "VPN is shutting down\n");
2882 if (NULL != destination_map)
2884 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
2885 &cleanup_destination,
2887 GNUNET_CONTAINER_multihashmap_destroy (destination_map);
2888 destination_map = NULL;
2890 if (NULL != destination_heap)
2892 GNUNET_CONTAINER_heap_destroy (destination_heap);
2893 destination_heap = NULL;
2895 if (NULL != tunnel_map)
2897 GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
2900 GNUNET_CONTAINER_multihashmap_destroy (tunnel_map);
2903 if (NULL != tunnel_heap)
2905 GNUNET_CONTAINER_heap_destroy (tunnel_heap);
2908 if (NULL != mesh_handle)
2910 GNUNET_MESH_disconnect (mesh_handle);
2913 if (NULL != helper_handle)
2915 GNUNET_HELPER_stop (helper_handle);
2916 helper_handle = NULL;
2920 GNUNET_SERVER_notification_context_destroy (nc);
2925 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
2929 GNUNET_free_non_null (vpn_argv[i]);
2934 * A client disconnected, clean up all references to it.
2936 * @param cls the client that disconnected
2938 * @param value a 'struct TunnelState *'
2939 * @return GNUNET_OK (continue to iterate)
2942 cleanup_tunnel_client (void *cls,
2943 const GNUNET_HashCode *key,
2946 struct GNUNET_SERVER_Client *client = cls;
2947 struct TunnelState *ts = value;
2949 if (client == ts->client)
2951 GNUNET_SERVER_client_drop (ts->client);
2959 * A client disconnected, clean up all references to it.
2961 * @param cls the client that disconnected
2963 * @param value a 'struct DestinationEntry *'
2964 * @return GNUNET_OK (continue to iterate)
2967 cleanup_destination_client (void *cls,
2968 const GNUNET_HashCode *key,
2971 struct GNUNET_SERVER_Client *client = cls;
2972 struct DestinationEntry *de = value;
2973 struct TunnelState *ts;
2975 if (NULL == (ts = de->ts))
2977 if (client == ts->client)
2979 GNUNET_SERVER_client_drop (ts->client);
2987 * A client has disconnected from us. If we are currently building
2988 * a tunnel for it, cancel the operation.
2991 * @param client handle to the client that disconnected
2994 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
2996 if (NULL != tunnel_map)
2997 GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
2998 &cleanup_tunnel_client,
3000 if (NULL != destination_map)
3001 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
3002 &cleanup_destination_client,
3008 * Test if the given AF is supported by this system.
3011 * @return GNUNET_OK if the AF is supported
3018 s = socket (af, SOCK_STREAM, 0);
3021 if (EAFNOSUPPORT == errno)
3023 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
3025 return GNUNET_SYSERR;
3033 * Main function that will be run by the scheduler.
3035 * @param cls closure
3036 * @param server the initialized server
3037 * @param cfg_ configuration
3041 struct GNUNET_SERVER_Handle *server,
3042 const struct GNUNET_CONFIGURATION_Handle *cfg_)
3044 static const struct GNUNET_SERVER_MessageHandler service_handlers[] = {
3045 /* callback, cls, type, size */
3046 { &service_redirect_to_ip, NULL, GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP, 0},
3047 { &service_redirect_to_service, NULL,
3048 GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE,
3049 sizeof (struct RedirectToServiceRequestMessage) },
3052 static const struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
3053 { &receive_udp_back, GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY, 0},
3054 { &receive_tcp_back, GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN, 0},
3055 { &receive_icmp_back, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN, 0},
3058 static const GNUNET_MESH_ApplicationType types[] = {
3059 GNUNET_APPLICATION_TYPE_END
3070 GNUNET_OS_check_helper_binary ("gnunet-helper-vpn"))
3073 "`%s' is not SUID, refusing to run.\n",
3074 "gnunet-helper-vpn");
3079 stats = GNUNET_STATISTICS_create ("vpn", cfg);
3081 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_MAPPING",
3082 &max_destination_mappings))
3083 max_destination_mappings = 200;
3085 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_TUNNELS",
3086 &max_tunnel_mappings))
3087 max_tunnel_mappings = 200;
3089 destination_map = GNUNET_CONTAINER_multihashmap_create (max_destination_mappings * 2);
3090 destination_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3091 tunnel_map = GNUNET_CONTAINER_multihashmap_create (max_tunnel_mappings * 2);
3092 tunnel_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3095 vpn_argv[0] = GNUNET_strdup ("vpn-gnunet");
3096 if (GNUNET_SYSERR ==
3097 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IFNAME", &ifname))
3099 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3100 "No entry 'IFNAME' in configuration!\n");
3101 GNUNET_SCHEDULER_shutdown ();
3104 vpn_argv[1] = ifname;
3105 if (GNUNET_OK == test_af (AF_INET6))
3107 if ( (GNUNET_SYSERR ==
3108 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6ADDR",
3110 (1 != inet_pton (AF_INET6, ipv6addr, &v6))) )
3112 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3113 "No valid entry 'IPV6ADDR' in configuration!\n");
3114 GNUNET_SCHEDULER_shutdown ();
3117 vpn_argv[2] = ipv6addr;
3118 if (GNUNET_SYSERR ==
3119 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6PREFIX",
3122 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3123 "No entry 'IPV6PREFIX' in configuration!\n");
3124 GNUNET_SCHEDULER_shutdown ();
3127 vpn_argv[3] = ipv6prefix_s;
3129 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn",
3132 (ipv6prefix >= 127) )
3134 GNUNET_SCHEDULER_shutdown ();
3140 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3141 _("IPv6 support disabled as this system does not support IPv6\n"));
3142 vpn_argv[2] = GNUNET_strdup ("-");
3143 vpn_argv[3] = GNUNET_strdup ("-");
3145 if (GNUNET_OK == test_af (AF_INET))
3147 if ( (GNUNET_SYSERR ==
3148 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4ADDR",
3150 (1 != inet_pton (AF_INET, ipv4addr, &v4))) )
3152 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3153 "No valid entry for 'IPV4ADDR' in configuration!\n");
3154 GNUNET_SCHEDULER_shutdown ();
3157 vpn_argv[4] = ipv4addr;
3158 if ( (GNUNET_SYSERR ==
3159 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4MASK",
3161 (1 != inet_pton (AF_INET, ipv4mask, &v4))) )
3163 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3164 "No valid entry 'IPV4MASK' in configuration!\n");
3165 GNUNET_SCHEDULER_shutdown ();
3168 vpn_argv[5] = ipv4mask;
3172 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3173 _("IPv4 support disabled as this system does not support IPv4\n"));
3174 vpn_argv[4] = GNUNET_strdup ("-");
3175 vpn_argv[5] = GNUNET_strdup ("-");
3180 GNUNET_MESH_connect (cfg_, 42 /* queue length */, NULL,
3185 helper_handle = GNUNET_HELPER_start ("gnunet-helper-vpn", vpn_argv,
3186 &message_token, NULL);
3187 nc = GNUNET_SERVER_notification_context_create (server, 1);
3188 GNUNET_SERVER_add_handlers (server, service_handlers);
3189 GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
3190 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls);
3195 * The main function of the VPN service.
3197 * @param argc number of arguments from the command line
3198 * @param argv command line arguments
3199 * @return 0 ok, 1 on error
3202 main (int argc, char *const *argv)
3204 return (GNUNET_OK ==
3205 GNUNET_SERVICE_run (argc, argv, "vpn",
3206 GNUNET_SERVICE_OPTION_NONE,
3207 &run, NULL)) ? global_ret : 1;
3210 /* end of gnunet-service-vpn.c */