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"
38 #include "gnunet_regex_lib.h"
44 * Maximum number of messages we allow in the queue for mesh.
46 #define MAX_MESSAGE_QUEUE_SIZE 4
50 * State we keep for each of our tunnels.
56 * Information we track for each IP address to determine which tunnel
57 * to send the traffic over to the destination.
59 struct DestinationEntry
63 * Key under which this entry is in the 'destination_map' (only valid
64 * if 'heap_node != NULL').
66 struct GNUNET_HashCode key;
69 * Pre-allocated tunnel for this destination, or NULL for none.
71 struct TunnelState *ts;
74 * Entry for this entry in the destination_heap.
76 struct GNUNET_CONTAINER_HeapNode *heap_node;
79 * GNUNET_NO if this is a tunnel to an Internet-exit,
80 * GNUNET_YES if this tunnel is to a service.
85 * Details about the connection (depending on is_service).
93 * The description of the service (only used for service tunnels).
95 struct GNUNET_HashCode service_descriptor;
98 * Peer offering the service.
100 struct GNUNET_PeerIdentity target;
102 } service_destination;
108 * Address family used (AF_INET or AF_INET6).
113 * IP address of the ultimate destination (only used for exit tunnels).
118 * Address if af is AF_INET.
123 * Address if af is AF_INET6.
136 * A messages we have in queue for a particular tunnel.
138 struct TunnelMessageQueueEntry
141 * This is a doubly-linked list.
143 struct TunnelMessageQueueEntry *next;
146 * This is a doubly-linked list.
148 struct TunnelMessageQueueEntry *prev;
151 * Number of bytes in 'msg'.
156 * Message to transmit, allocated at the end of this struct.
163 * State we keep for each of our tunnels.
169 * Information about the tunnel to use, NULL if no tunnel
170 * is available right now.
172 struct GNUNET_MESH_Tunnel *tunnel;
175 * Active transmission handle, NULL for none.
177 struct GNUNET_MESH_TransmitHandle *th;
180 * Entry for this entry in the tunnel_heap, NULL as long as this
181 * tunnel state is not fully bound.
183 struct GNUNET_CONTAINER_HeapNode *heap_node;
186 * Head of list of messages scheduled for transmission.
188 struct TunnelMessageQueueEntry *tmq_head;
191 * Tail of list of messages scheduled for transmission.
193 struct TunnelMessageQueueEntry *tmq_tail;
196 * Client that needs to be notified about the tunnel being
197 * up as soon as a peer is connected; NULL for none.
199 struct GNUNET_SERVER_Client *client;
202 * Destination entry that has a pointer to this tunnel state;
203 * NULL if this tunnel state is in the tunnel map.
205 struct DestinationEntry *destination_container;
208 * ID of the client request that caused us to setup this entry.
213 * Destination to which this tunnel leads. Note that
214 * this struct is NOT in the destination_map (but a
215 * local copy) and that the 'heap_node' should always
218 struct DestinationEntry destination;
221 * Task scheduled to destroy the tunnel (or NO_TASK).
223 GNUNET_SCHEDULER_TaskIdentifier destroy_task;
226 * Addess family used for this tunnel on the local TUN interface.
231 * Length of the doubly linked 'tmq_head/tmq_tail' list.
233 unsigned int tmq_length;
236 * IPPROTO_TCP or IPPROTO_UDP once bound.
241 * IP address of the source on our end, initially uninitialized.
246 * Address if af is AF_INET.
251 * Address if af is AF_INET6.
258 * Destination IP address used by the source on our end (this is the IP
259 * that we pick freely within the VPN's tunnel IP range).
264 * Address if af is AF_INET.
269 * Address if af is AF_INET6.
276 * Source port used by the sender on our end; 0 for uninitialized.
278 uint16_t source_port;
281 * Destination port used by the sender on our end; 0 for uninitialized.
283 uint16_t destination_port;
289 * Return value from 'main'.
291 static int global_ret;
294 * Configuration we use.
296 static const struct GNUNET_CONFIGURATION_Handle *cfg;
299 * Handle to the mesh service.
301 static struct GNUNET_MESH_Handle *mesh_handle;
304 * Map from IP address to destination information (possibly with a
305 * MESH tunnel handle for fast setup).
307 static struct GNUNET_CONTAINER_MultiHashMap *destination_map;
310 * Min-Heap sorted by activity time to expire old mappings.
312 static struct GNUNET_CONTAINER_Heap *destination_heap;
315 * Map from source and destination address (IP+port) to connection
316 * information (mostly with the respective MESH tunnel handle).
318 static struct GNUNET_CONTAINER_MultiHashMap *tunnel_map;
321 * Min-Heap sorted by activity time to expire old mappings; values are
322 * of type 'struct TunnelState'.
324 static struct GNUNET_CONTAINER_Heap *tunnel_heap;
329 static struct GNUNET_STATISTICS_Handle *stats;
332 * The handle to the VPN helper process "gnunet-helper-vpn".
334 static struct GNUNET_HELPER_Handle *helper_handle;
337 * Arguments to the vpn helper.
339 static char *vpn_argv[7];
342 * Length of the prefix of the VPN's IPv6 network.
344 static unsigned long long ipv6prefix;
347 * Notification context for sending replies to clients.
349 static struct GNUNET_SERVER_NotificationContext *nc;
352 * If there are more than this number of address-mappings, old ones
355 static unsigned long long max_destination_mappings;
358 * If there are more than this number of open tunnels, old ones
361 static unsigned long long max_tunnel_mappings;
365 * Compute the key under which we would store an entry in the
366 * destination_map for the given IP address.
368 * @param af address family (AF_INET or AF_INET6)
369 * @param address IP address, struct in_addr or struct in6_addr
370 * @param key where to store the key
373 get_destination_key_from_ip (int af,
375 struct GNUNET_HashCode *key)
380 GNUNET_CRYPTO_hash (address,
381 sizeof (struct in_addr),
385 GNUNET_CRYPTO_hash (address,
386 sizeof (struct in6_addr),
397 * Compute the key under which we would store an entry in the
398 * tunnel_map for the given socket address pair.
400 * @param af address family (AF_INET or AF_INET6)
401 * @param protocol IPPROTO_TCP or IPPROTO_UDP
402 * @param source_ip sender's source IP, struct in_addr or struct in6_addr
403 * @param source_port sender's source port
404 * @param destination_ip sender's destination IP, struct in_addr or struct in6_addr
405 * @param destination_port sender's destination port
406 * @param key where to store the key
409 get_tunnel_key_from_ips (int af,
411 const void *source_ip,
412 uint16_t source_port,
413 const void *destination_ip,
414 uint16_t destination_port,
415 struct GNUNET_HashCode *key)
419 memset (key, 0, sizeof (struct GNUNET_HashCode));
420 /* the GNUnet hashmap only uses the first sizeof(unsigned int) of the hash,
421 so we put the ports in there (and hope for few collisions) */
423 memcpy (off, &source_port, sizeof (uint16_t));
424 off += sizeof (uint16_t);
425 memcpy (off, &destination_port, sizeof (uint16_t));
426 off += sizeof (uint16_t);
430 memcpy (off, source_ip, sizeof (struct in_addr));
431 off += sizeof (struct in_addr);
432 memcpy (off, destination_ip, sizeof (struct in_addr));
433 off += sizeof (struct in_addr);
436 memcpy (off, source_ip, sizeof (struct in6_addr));
437 off += sizeof (struct in6_addr);
438 memcpy (off, destination_ip, sizeof (struct in6_addr));
439 off += sizeof (struct in6_addr);
445 memcpy (off, &protocol, sizeof (uint8_t));
446 off += sizeof (uint8_t);
451 * Notify the client about the result of its request.
453 * @param client client to notify
454 * @param request_id original request ID to include in response
455 * @param result_af resulting address family
456 * @param addr resulting IP address
459 send_client_reply (struct GNUNET_SERVER_Client *client,
464 char buf[sizeof (struct RedirectToIpResponseMessage) + sizeof (struct in6_addr)] GNUNET_ALIGN;
465 struct RedirectToIpResponseMessage *res;
471 rlen = sizeof (struct in_addr);
474 rlen = sizeof (struct in6_addr);
483 res = (struct RedirectToIpResponseMessage *) buf;
484 res->header.size = htons (sizeof (struct RedirectToIpResponseMessage) + rlen);
485 res->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP);
486 res->result_af = htonl (result_af);
487 res->request_id = request_id;
488 memcpy (&res[1], addr, rlen);
489 GNUNET_SERVER_notification_context_add (nc, client);
490 GNUNET_SERVER_notification_context_unicast (nc,
498 * Free resources associated with a tunnel state.
500 * @param ts state to free
503 free_tunnel_state (struct TunnelState *ts)
505 struct GNUNET_HashCode key;
506 struct TunnelMessageQueueEntry *tnq;
507 struct GNUNET_MESH_Tunnel *tunnel;
509 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
510 "Cleaning up tunnel state\n");
511 GNUNET_STATISTICS_update (stats,
512 gettext_noop ("# Active tunnels"),
514 while (NULL != (tnq = ts->tmq_head))
516 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
522 GNUNET_assert (0 == ts->tmq_length);
523 if (NULL != ts->client)
525 GNUNET_SERVER_client_drop (ts->client);
530 GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
533 GNUNET_assert (NULL == ts->destination.heap_node);
534 if (NULL != (tunnel = ts->tunnel))
537 GNUNET_MESH_tunnel_destroy (tunnel);
539 if (GNUNET_SCHEDULER_NO_TASK != ts->destroy_task)
541 GNUNET_SCHEDULER_cancel (ts->destroy_task);
542 ts->destroy_task = GNUNET_SCHEDULER_NO_TASK;
544 if (NULL != ts->heap_node)
546 GNUNET_CONTAINER_heap_remove_node (ts->heap_node);
547 ts->heap_node = NULL;
548 get_tunnel_key_from_ips (ts->af,
553 ts->destination_port,
555 GNUNET_assert (GNUNET_YES ==
556 GNUNET_CONTAINER_multihashmap_remove (tunnel_map,
560 if (NULL != ts->destination_container)
562 GNUNET_assert (ts == ts->destination_container->ts);
563 ts->destination_container->ts = NULL;
564 ts->destination_container = NULL;
571 * Destroy the mesh tunnel.
573 * @param cls the 'struct TunnelState' with the tunnel to destroy
574 * @param tc scheduler context
577 destroy_tunnel_task (void *cls,
578 const struct GNUNET_SCHEDULER_TaskContext *tc)
580 struct TunnelState *ts = cls;
581 struct GNUNET_MESH_Tunnel *tunnel;
583 ts->destroy_task = GNUNET_SCHEDULER_NO_TASK;
584 GNUNET_assert (NULL != ts->tunnel);
587 GNUNET_MESH_tunnel_destroy (tunnel);
588 free_tunnel_state (ts);
593 * Method called whenever a peer has disconnected from the tunnel.
596 * @param peer peer identity the tunnel stopped working with
599 tunnel_peer_disconnect_handler (void *cls,
601 GNUNET_PeerIdentity * peer)
603 struct TunnelState *ts = cls;
605 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
606 "Peer %s disconnected from tunnel.\n",
608 GNUNET_STATISTICS_update (stats,
609 gettext_noop ("# peers connected to mesh tunnels"),
613 GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
616 if (ts->destination.is_service)
617 return; /* hope for reconnect eventually */
618 /* as we are most likely going to change the exit node now,
619 we should just destroy the tunnel entirely... */
620 if (GNUNET_SCHEDULER_NO_TASK == ts->destroy_task)
621 ts->destroy_task = GNUNET_SCHEDULER_add_now (&destroy_tunnel_task, ts);
626 * Method called whenever a peer has connected to the tunnel. Notifies
627 * the waiting client that the tunnel is now up.
630 * @param peer peer identity the tunnel was created to, NULL on timeout
631 * @param atsi performance data for the connection
634 tunnel_peer_connect_handler (void *cls,
635 const struct GNUNET_PeerIdentity
638 GNUNET_ATS_Information * atsi)
640 struct TunnelState *ts = cls;
642 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
643 "Peer %s connected to tunnel.\n",
645 GNUNET_STATISTICS_update (stats,
646 gettext_noop ("# peers connected to mesh tunnels"),
648 if (NULL == ts->client)
649 return; /* nothing to do */
650 send_client_reply (ts->client,
653 &ts->destination_ip);
654 GNUNET_SERVER_client_drop (ts->client);
660 * Send a message from the message queue via mesh.
662 * @param cls the 'struct TunnelState' with the message queue
663 * @param size number of bytes available in buf
664 * @param buf where to copy the message
665 * @return number of bytes copied to buf
668 send_to_peer_notify_callback (void *cls, size_t size, void *buf)
670 struct TunnelState *ts = cls;
671 struct TunnelMessageQueueEntry *tnq;
678 GNUNET_assert (NULL != tnq);
679 GNUNET_assert (size >= tnq->len);
680 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
681 "Sending %u bytes via mesh tunnel\n",
683 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
687 memcpy (buf, tnq->msg, tnq->len);
690 if (NULL != (tnq = ts->tmq_head))
691 ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel,
692 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 */,
745 GNUNET_TIME_UNIT_FOREVER_REL,
748 &send_to_peer_notify_callback,
754 * Initialize the given destination entry's mesh tunnel.
756 * @param de destination entry for which we need to setup a tunnel
757 * @param client client to notify on successful tunnel setup, or NULL for none
758 * @param client_af address family of the address returned to the client
759 * @param request_id request ID to send in client notification (unused if client is NULL)
760 * @return tunnel state of the tunnel that was created
762 static struct TunnelState *
763 create_tunnel_to_destination (struct DestinationEntry *de,
764 struct GNUNET_SERVER_Client *client,
768 struct TunnelState *ts;
770 GNUNET_STATISTICS_update (stats,
771 gettext_noop ("# Mesh tunnels created"),
773 GNUNET_assert (NULL == de->ts);
774 ts = GNUNET_malloc (sizeof (struct TunnelState));
778 ts->request_id = request_id;
780 GNUNET_SERVER_client_keep (client);
782 ts->destination = *de;
783 ts->destination.heap_node = NULL; /* copy is NOT in destination heap */
785 ts->destination_container = de; /* we are referenced from de */
786 ts->tunnel = GNUNET_MESH_tunnel_create (mesh_handle,
788 &tunnel_peer_connect_handler,
789 &tunnel_peer_disconnect_handler,
791 if (NULL == ts->tunnel)
793 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
794 _("Failed to setup mesh tunnel!\n"));
796 GNUNET_SERVER_client_drop (client);
802 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
803 "Creating tunnel to peer %s offering service %s\n",
804 GNUNET_i2s (&de->details.service_destination.target),
805 GNUNET_h2s (&de->details.service_destination.service_descriptor));
806 GNUNET_MESH_peer_request_connect_add (ts->tunnel,
807 &de->details.service_destination.target);
813 switch (de->details.exit_destination.af)
817 char address[GNUNET_REGEX_IPV4_REGEXLEN];
818 GNUNET_REGEX_ipv4toregex (&de->details.exit_destination.ip.v4,
819 "255.255.255.255", address);
820 GNUNET_asprintf (&policy, "%s%s%s",
821 GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
828 char address[GNUNET_REGEX_IPV6_REGEXLEN];
829 GNUNET_REGEX_ipv6toregex (&de->details.exit_destination.ip.v6,
831 GNUNET_asprintf (&policy, "%s%s%s",
832 GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
842 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Requesting connect by string: %s\n", policy);
844 GNUNET_MESH_peer_request_connect_by_string (ts->tunnel, policy);
845 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
846 "Creating tunnel to exit peer for policy `%s'\n",
848 GNUNET_free (policy);
855 * We have too many active tunnels. Clean up the oldest tunnel.
857 * @param except tunnel that must NOT be cleaned up, even if it is the oldest
860 expire_tunnel (struct TunnelState *except)
862 struct TunnelState *ts;
864 ts = GNUNET_CONTAINER_heap_peek (tunnel_heap);
865 GNUNET_assert (NULL != ts);
867 return; /* can't do this */
868 free_tunnel_state (ts);
873 * Route a packet via mesh to the given destination.
875 * @param destination description of the destination
876 * @param af address family on this end (AF_INET or AF_INET6)
877 * @param protocol IPPROTO_TCP or IPPROTO_UDP or IPPROTO_ICMP or IPPROTO_ICMPV6
878 * @param source_ip source IP used by the sender (struct in_addr or struct in6_addr)
879 * @param destination_ip destination IP used by the sender (struct in_addr or struct in6_addr)
880 * @param payload payload of the packet after the IP header
881 * @param payload_length number of bytes in payload
884 route_packet (struct DestinationEntry *destination,
887 const void *source_ip,
888 const void *destination_ip,
890 size_t payload_length)
892 struct GNUNET_HashCode key;
893 struct TunnelState *ts;
894 struct TunnelMessageQueueEntry *tnq;
898 const struct GNUNET_TUN_UdpHeader *udp;
899 const struct GNUNET_TUN_TcpHeader *tcp;
900 const struct GNUNET_TUN_IcmpHeader *icmp;
901 uint16_t source_port;
902 uint16_t destination_port;
908 if (payload_length < sizeof (struct GNUNET_TUN_UdpHeader))
914 tcp = NULL; /* make compiler happy */
915 icmp = NULL; /* make compiler happy */
917 if (udp->len < sizeof (struct GNUNET_TUN_UdpHeader))
922 source_port = ntohs (udp->source_port);
923 destination_port = ntohs (udp->destination_port);
924 get_tunnel_key_from_ips (af,
935 if (payload_length < sizeof (struct GNUNET_TUN_TcpHeader))
941 udp = NULL; /* make compiler happy */
942 icmp = NULL; /* make compiler happy */
944 if (tcp->off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
949 source_port = ntohs (tcp->source_port);
950 destination_port = ntohs (tcp->destination_port);
951 get_tunnel_key_from_ips (af,
963 if ( (AF_INET == af) ^ (protocol == IPPROTO_ICMP) )
968 if (payload_length < sizeof (struct GNUNET_TUN_IcmpHeader))
974 tcp = NULL; /* make compiler happy */
975 udp = NULL; /* make compiler happy */
978 destination_port = 0;
979 get_tunnel_key_from_ips (af,
989 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
990 _("Protocol %u not supported, dropping\n"),
991 (unsigned int) protocol);
994 if (! destination->is_service)
996 switch (destination->details.exit_destination.af)
999 alen = sizeof (struct in_addr);
1002 alen = sizeof (struct in6_addr);
1010 char sbuf[INET6_ADDRSTRLEN];
1011 char dbuf[INET6_ADDRSTRLEN];
1012 char xbuf[INET6_ADDRSTRLEN];
1014 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1015 "Routing %s packet from %s:%u -> %s:%u to destination %s:%u\n",
1016 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
1017 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
1019 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
1021 inet_ntop (destination->details.exit_destination.af,
1022 &destination->details.exit_destination.ip,
1023 xbuf, sizeof (xbuf)),
1029 /* make compiler happy */
1032 char sbuf[INET6_ADDRSTRLEN];
1033 char dbuf[INET6_ADDRSTRLEN];
1035 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1036 "Routing %s packet from %s:%u -> %s:%u to service %s at peer %s\n",
1037 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
1038 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
1040 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
1042 GNUNET_h2s (&destination->details.service_destination.service_descriptor),
1043 GNUNET_i2s (&destination->details.service_destination.target));
1048 /* see if we have an existing tunnel for this destination */
1049 ts = GNUNET_CONTAINER_multihashmap_get (tunnel_map,
1053 /* need to either use the existing tunnel from the destination (if still
1054 available) or create a fresh one */
1055 is_new = GNUNET_YES;
1056 if (NULL == destination->ts)
1057 ts = create_tunnel_to_destination (destination, NULL, af, 0);
1059 ts = destination->ts;
1062 destination->ts = NULL;
1063 ts->destination_container = NULL; /* no longer 'contained' */
1064 /* now bind existing "unbound" tunnel to our IP/port tuple */
1065 ts->protocol = protocol;
1069 ts->source_ip.v4 = * (const struct in_addr *) source_ip;
1070 ts->destination_ip.v4 = * (const struct in_addr *) destination_ip;
1074 ts->source_ip.v6 = * (const struct in6_addr *) source_ip;
1075 ts->destination_ip.v6 = * (const struct in6_addr *) destination_ip;
1077 ts->source_port = source_port;
1078 ts->destination_port = destination_port;
1079 ts->heap_node = GNUNET_CONTAINER_heap_insert (tunnel_heap,
1081 GNUNET_TIME_absolute_get ().abs_value);
1082 GNUNET_assert (GNUNET_YES ==
1083 GNUNET_CONTAINER_multihashmap_put (tunnel_map,
1086 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1087 GNUNET_STATISTICS_update (stats,
1088 gettext_noop ("# Active tunnels"),
1090 while (GNUNET_CONTAINER_multihashmap_size (tunnel_map) > max_tunnel_mappings)
1096 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
1098 GNUNET_TIME_absolute_get ().abs_value);
1100 GNUNET_assert (NULL != ts->tunnel);
1102 /* send via tunnel */
1106 if (destination->is_service)
1108 struct GNUNET_EXIT_UdpServiceMessage *usm;
1110 mlen = sizeof (struct GNUNET_EXIT_UdpServiceMessage) +
1111 payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1112 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1117 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1120 usm = (struct GNUNET_EXIT_UdpServiceMessage *) &tnq[1];
1121 usm->header.size = htons ((uint16_t) mlen);
1122 usm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE);
1123 /* if the source port is below 32000, we assume it has a special
1124 meaning; if not, we pick a random port (this is a heuristic) */
1125 usm->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1126 usm->destination_port = udp->destination_port;
1127 usm->service_descriptor = destination->details.service_destination.service_descriptor;
1130 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1134 struct GNUNET_EXIT_UdpInternetMessage *uim;
1135 struct in_addr *ip4dst;
1136 struct in6_addr *ip6dst;
1139 mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) +
1140 alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1141 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1146 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) +
1150 uim = (struct GNUNET_EXIT_UdpInternetMessage *) &tnq[1];
1151 uim->header.size = htons ((uint16_t) mlen);
1152 uim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET);
1153 uim->af = htonl (destination->details.exit_destination.af);
1154 uim->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1155 uim->destination_port = udp->destination_port;
1156 switch (destination->details.exit_destination.af)
1159 ip4dst = (struct in_addr *) &uim[1];
1160 *ip4dst = destination->details.exit_destination.ip.v4;
1161 payload = &ip4dst[1];
1164 ip6dst = (struct in6_addr *) &uim[1];
1165 *ip6dst = destination->details.exit_destination.ip.v6;
1166 payload = &ip6dst[1];
1173 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1179 if (destination->is_service)
1181 struct GNUNET_EXIT_TcpServiceStartMessage *tsm;
1183 mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) +
1184 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1185 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1190 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1193 tsm = (struct GNUNET_EXIT_TcpServiceStartMessage *) &tnq[1];
1194 tsm->header.size = htons ((uint16_t) mlen);
1195 tsm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START);
1196 tsm->reserved = htonl (0);
1197 tsm->service_descriptor = destination->details.service_destination.service_descriptor;
1198 tsm->tcp_header = *tcp;
1201 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1205 struct GNUNET_EXIT_TcpInternetStartMessage *tim;
1206 struct in_addr *ip4dst;
1207 struct in6_addr *ip6dst;
1210 mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) +
1211 alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1212 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1217 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1220 tim = (struct GNUNET_EXIT_TcpInternetStartMessage *) &tnq[1];
1221 tim->header.size = htons ((uint16_t) mlen);
1222 tim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START);
1223 tim->af = htonl (destination->details.exit_destination.af);
1224 tim->tcp_header = *tcp;
1225 switch (destination->details.exit_destination.af)
1228 ip4dst = (struct in_addr *) &tim[1];
1229 *ip4dst = destination->details.exit_destination.ip.v4;
1230 payload = &ip4dst[1];
1233 ip6dst = (struct in6_addr *) &tim[1];
1234 *ip6dst = destination->details.exit_destination.ip.v6;
1235 payload = &ip6dst[1];
1242 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1247 struct GNUNET_EXIT_TcpDataMessage *tdm;
1249 mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) +
1250 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1251 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1256 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1259 tdm = (struct GNUNET_EXIT_TcpDataMessage *) &tnq[1];
1260 tdm->header.size = htons ((uint16_t) mlen);
1261 tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT);
1262 tdm->reserved = htonl (0);
1263 tdm->tcp_header = *tcp;
1266 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1270 case IPPROTO_ICMPV6:
1271 if (destination->is_service)
1273 struct GNUNET_EXIT_IcmpServiceMessage *ism;
1275 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1276 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1277 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1282 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1284 ism = (struct GNUNET_EXIT_IcmpServiceMessage *) &tnq[1];
1285 ism->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE);
1286 ism->af = htonl (af); /* need to tell destination ICMP protocol family! */
1287 ism->service_descriptor = destination->details.service_destination.service_descriptor;
1288 ism->icmp_header = *icmp;
1289 /* ICMP protocol translation will be done by the receiver (as we don't know
1290 the target AF); however, we still need to possibly discard the payload
1291 depending on the ICMP type */
1297 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1298 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1300 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1301 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1302 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1303 /* throw away ICMP payload, won't be useful for the other side anyway */
1304 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1307 GNUNET_STATISTICS_update (stats,
1308 gettext_noop ("# ICMPv4 packets dropped (not allowed)"),
1312 /* end of AF_INET */
1317 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1318 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1319 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1320 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1321 /* throw away ICMP payload, won't be useful for the other side anyway */
1322 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1324 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1325 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1328 GNUNET_STATISTICS_update (stats,
1329 gettext_noop ("# ICMPv6 packets dropped (not allowed)"),
1333 /* end of AF_INET6 */
1340 /* update length calculations, as payload_length may have changed */
1341 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1342 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1344 ism->header.size = htons ((uint16_t) mlen);
1345 /* finally, copy payload (if there is any left...) */
1348 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1352 struct GNUNET_EXIT_IcmpInternetMessage *iim;
1353 struct in_addr *ip4dst;
1354 struct in6_addr *ip6dst;
1357 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1358 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1359 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1364 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) +
1367 iim = (struct GNUNET_EXIT_IcmpInternetMessage *) &tnq[1];
1368 iim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET);
1369 iim->icmp_header = *icmp;
1370 /* Perform ICMP protocol-translation (depending on destination AF and source AF)
1371 and throw away ICMP payload depending on ICMP message type */
1377 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1378 if (destination->details.exit_destination.af == AF_INET6)
1379 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1381 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1382 if (destination->details.exit_destination.af == AF_INET6)
1383 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1385 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1386 if (destination->details.exit_destination.af == AF_INET6)
1387 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1388 /* throw away IP-payload, exit will have to make it up anyway */
1389 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1391 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1392 if (destination->details.exit_destination.af == AF_INET6)
1393 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1394 /* throw away IP-payload, exit will have to make it up anyway */
1395 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1397 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1398 if (destination->details.exit_destination.af == AF_INET6)
1400 GNUNET_STATISTICS_update (stats,
1401 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1406 /* throw away IP-payload, exit will have to make it up anyway */
1407 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1410 GNUNET_STATISTICS_update (stats,
1411 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1416 /* end of AF_INET */
1421 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1422 if (destination->details.exit_destination.af == AF_INET6)
1423 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1424 /* throw away IP-payload, exit will have to make it up anyway */
1425 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1427 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1428 if (destination->details.exit_destination.af == AF_INET)
1429 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1430 /* throw away IP-payload, exit will have to make it up anyway */
1431 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1433 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1434 if (destination->details.exit_destination.af == AF_INET)
1436 GNUNET_STATISTICS_update (stats,
1437 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1442 /* throw away IP-payload, exit will have to make it up anyway */
1443 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1445 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1446 if (destination->details.exit_destination.af == AF_INET)
1448 GNUNET_STATISTICS_update (stats,
1449 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1454 /* throw away IP-payload, exit will have to make it up anyway */
1455 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1457 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1458 if (destination->details.exit_destination.af == AF_INET)
1459 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1461 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1462 if (destination->details.exit_destination.af == AF_INET)
1463 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1466 GNUNET_STATISTICS_update (stats,
1467 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1472 /* end of AF_INET6 */
1477 /* update length calculations, as payload_length may have changed */
1478 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1479 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1481 iim->header.size = htons ((uint16_t) mlen);
1483 /* need to tell destination ICMP protocol family! */
1484 iim->af = htonl (destination->details.exit_destination.af);
1485 switch (destination->details.exit_destination.af)
1488 ip4dst = (struct in_addr *) &iim[1];
1489 *ip4dst = destination->details.exit_destination.ip.v4;
1490 payload = &ip4dst[1];
1493 ip6dst = (struct in6_addr *) &iim[1];
1494 *ip6dst = destination->details.exit_destination.ip.v6;
1495 payload = &ip6dst[1];
1502 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1506 /* not supported above, how can we get here !? */
1510 send_to_tunnel (tnq, ts);
1515 * Receive packets from the helper-process (someone send to the local
1516 * virtual tunnel interface). Find the destination mapping, and if it
1517 * exists, identify the correct MESH tunnel (or possibly create it)
1518 * and forward the packet.
1520 * @param cls closure, NULL
1521 * @param client NULL
1522 * @param message message we got from the client (VPN tunnel interface)
1525 message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED,
1526 const struct GNUNET_MessageHeader *message)
1528 const struct GNUNET_TUN_Layer2PacketHeader *tun;
1530 struct GNUNET_HashCode key;
1531 struct DestinationEntry *de;
1533 GNUNET_STATISTICS_update (stats,
1534 gettext_noop ("# Packets received from TUN interface"),
1536 mlen = ntohs (message->size);
1537 if ( (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
1538 (mlen < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader)) )
1543 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1544 mlen -= (sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader));
1545 switch (ntohs (tun->proto))
1549 const struct GNUNET_TUN_IPv6Header *pkt6;
1551 if (mlen < sizeof (struct GNUNET_TUN_IPv6Header))
1557 pkt6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1558 get_destination_key_from_ip (AF_INET6,
1559 &pkt6->destination_address,
1561 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1562 /* FIXME: do we need to guard against hash collision?
1563 (if so, we need to also store the local destination IP in the
1564 destination entry and then compare here; however, the risk
1565 of collision seems minimal AND the impact is unlikely to be
1566 super-problematic as well... */
1569 char buf[INET6_ADDRSTRLEN];
1571 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1572 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1573 inet_ntop (AF_INET6,
1574 &pkt6->destination_address,
1582 &pkt6->source_address,
1583 &pkt6->destination_address,
1585 mlen - sizeof (struct GNUNET_TUN_IPv6Header));
1590 struct GNUNET_TUN_IPv4Header *pkt4;
1592 if (mlen < sizeof (struct GNUNET_TUN_IPv4Header))
1598 pkt4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1599 get_destination_key_from_ip (AF_INET,
1600 &pkt4->destination_address,
1602 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1603 /* FIXME: do we need to guard against hash collision?
1604 (if so, we need to also store the local destination IP in the
1605 destination entry and then compare here; however, the risk
1606 of collision seems minimal AND the impact is unlikely to be
1607 super-problematic as well... */
1610 char buf[INET_ADDRSTRLEN];
1612 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1613 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1615 &pkt4->destination_address,
1620 if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header))
1622 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1623 _("Received IPv4 packet with options (dropping it)\n"));
1629 &pkt4->source_address,
1630 &pkt4->destination_address,
1632 mlen - sizeof (struct GNUNET_TUN_IPv4Header));
1636 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1637 _("Received packet of unknown protocol %d from TUN (dropping it)\n"),
1638 (unsigned int) ntohs (tun->proto));
1646 * Synthesize a plausible ICMP payload for an ICMP error
1647 * response on the given tunnel.
1649 * @param ts tunnel information
1650 * @param ipp IPv4 header to fill in (ICMP payload)
1651 * @param udp "UDP" header to fill in (ICMP payload); might actually
1652 * also be the first 8 bytes of the TCP header
1655 make_up_icmpv4_payload (struct TunnelState *ts,
1656 struct GNUNET_TUN_IPv4Header *ipp,
1657 struct GNUNET_TUN_UdpHeader *udp)
1659 GNUNET_TUN_initialize_ipv4_header (ipp,
1661 sizeof (struct GNUNET_TUN_TcpHeader),
1663 &ts->destination_ip.v4);
1664 udp->source_port = htons (ts->source_port);
1665 udp->destination_port = htons (ts->destination_port);
1666 udp->len = htons (0);
1667 udp->crc = htons (0);
1672 * Synthesize a plausible ICMP payload for an ICMP error
1673 * response on the given tunnel.
1675 * @param ts tunnel information
1676 * @param ipp IPv6 header to fill in (ICMP payload)
1677 * @param udp "UDP" header to fill in (ICMP payload); might actually
1678 * also be the first 8 bytes of the TCP header
1681 make_up_icmpv6_payload (struct TunnelState *ts,
1682 struct GNUNET_TUN_IPv6Header *ipp,
1683 struct GNUNET_TUN_UdpHeader *udp)
1685 GNUNET_TUN_initialize_ipv6_header (ipp,
1687 sizeof (struct GNUNET_TUN_TcpHeader),
1689 &ts->destination_ip.v6);
1690 udp->source_port = htons (ts->source_port);
1691 udp->destination_port = htons (ts->destination_port);
1692 udp->len = htons (0);
1693 udp->crc = htons (0);
1698 * We got an ICMP packet back from the MESH tunnel. Pass it on to the
1699 * local virtual interface via the helper.
1701 * @param cls closure, NULL
1702 * @param tunnel connection to the other end
1703 * @param tunnel_ctx pointer to our 'struct TunnelState *'
1704 * @param sender who sent the message
1705 * @param message the actual message
1706 * @param atsi performance data for the connection
1707 * @return GNUNET_OK to keep the connection open,
1708 * GNUNET_SYSERR to close it (signal serious error)
1711 receive_icmp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1712 void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender,
1713 const struct GNUNET_MessageHeader *message,
1714 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
1716 struct TunnelState *ts = *tunnel_ctx;
1717 const struct GNUNET_EXIT_IcmpToVPNMessage *i2v;
1720 GNUNET_STATISTICS_update (stats,
1721 gettext_noop ("# ICMP packets received from mesh"),
1723 mlen = ntohs (message->size);
1724 if (mlen < sizeof (struct GNUNET_EXIT_IcmpToVPNMessage))
1726 GNUNET_break_op (0);
1727 return GNUNET_SYSERR;
1729 if (NULL == ts->heap_node)
1731 GNUNET_break_op (0);
1732 return GNUNET_SYSERR;
1734 if (AF_UNSPEC == ts->af)
1736 GNUNET_break_op (0);
1737 return GNUNET_SYSERR;
1739 i2v = (const struct GNUNET_EXIT_IcmpToVPNMessage *) message;
1740 mlen -= sizeof (struct GNUNET_EXIT_IcmpToVPNMessage);
1742 char sbuf[INET6_ADDRSTRLEN];
1743 char dbuf[INET6_ADDRSTRLEN];
1745 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1746 "Received ICMP packet from mesh, sending %u bytes from %s -> %s via TUN\n",
1747 (unsigned int) mlen,
1748 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
1749 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)));
1755 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
1756 + sizeof (struct GNUNET_TUN_IcmpHeader)
1757 + sizeof (struct GNUNET_MessageHeader) +
1758 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1761 /* reserve some extra space in case we have an ICMP type here where
1762 we will need to make up the payload ourselves */
1763 char buf[size + sizeof (struct GNUNET_TUN_IPv4Header) + 8] GNUNET_ALIGN;
1764 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1765 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1766 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1767 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv4[1];
1768 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1769 tun->flags = htons (0);
1770 tun->proto = htons (ETH_P_IPV4);
1771 GNUNET_TUN_initialize_ipv4_header (ipv4,
1773 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1774 &ts->destination_ip.v4,
1776 *icmp = i2v->icmp_header;
1780 /* For some ICMP types, we need to adjust (make up) the payload here.
1781 Also, depending on the AF used on the other side, we have to
1782 do ICMP PT (translate ICMP types) */
1783 switch (ntohl (i2v->af))
1788 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1789 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1791 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1792 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1793 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1795 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1796 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1800 /* sender did not strip ICMP payload? */
1801 GNUNET_break_op (0);
1802 return GNUNET_SYSERR;
1804 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1805 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1806 make_up_icmpv4_payload (ts, ipp, udp);
1810 GNUNET_break_op (0);
1811 GNUNET_STATISTICS_update (stats,
1812 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1814 return GNUNET_SYSERR;
1819 /* ICMP PT 6-to-4 and possibly making up payloads */
1822 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1823 icmp->type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
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_TIME_EXCEEDED:
1840 icmp->type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1842 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1843 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1847 /* sender did not strip ICMP payload? */
1848 GNUNET_break_op (0);
1849 return GNUNET_SYSERR;
1851 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1852 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1853 make_up_icmpv4_payload (ts, ipp, udp);
1856 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1857 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1858 GNUNET_STATISTICS_update (stats,
1859 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1862 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1863 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1865 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1866 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1869 GNUNET_break_op (0);
1870 GNUNET_STATISTICS_update (stats,
1871 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1873 return GNUNET_SYSERR;
1878 GNUNET_break_op (0);
1879 return GNUNET_SYSERR;
1881 msg->size = htons (size);
1882 GNUNET_TUN_calculate_icmp_checksum (icmp,
1885 (void) GNUNET_HELPER_send (helper_handle,
1894 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
1895 + sizeof (struct GNUNET_TUN_IcmpHeader)
1896 + sizeof (struct GNUNET_MessageHeader) +
1897 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1900 char buf[size + sizeof (struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN;
1901 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1902 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1903 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
1904 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv6[1];
1905 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1906 tun->flags = htons (0);
1907 tun->proto = htons (ETH_P_IPV6);
1908 GNUNET_TUN_initialize_ipv6_header (ipv6,
1910 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1911 &ts->destination_ip.v6,
1913 *icmp = i2v->icmp_header;
1918 /* For some ICMP types, we need to adjust (make up) the payload here.
1919 Also, depending on the AF used on the other side, we have to
1920 do ICMP PT (translate ICMP types) */
1921 switch (ntohl (i2v->af))
1924 /* ICMP PT 4-to-6 and possibly making up payloads */
1927 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1928 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1930 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1931 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1933 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1934 icmp->type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
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_TIME_EXCEEDED:
1951 icmp->type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1953 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1954 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1958 /* sender did not strip ICMP payload? */
1959 GNUNET_break_op (0);
1960 return GNUNET_SYSERR;
1962 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1963 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1964 make_up_icmpv6_payload (ts, ipp, udp);
1967 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1968 GNUNET_STATISTICS_update (stats,
1969 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1973 GNUNET_break_op (0);
1974 GNUNET_STATISTICS_update (stats,
1975 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1977 return GNUNET_SYSERR;
1984 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1985 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1986 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1987 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1989 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1990 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1994 /* sender did not strip ICMP payload? */
1995 GNUNET_break_op (0);
1996 return GNUNET_SYSERR;
1998 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1999 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
2000 make_up_icmpv6_payload (ts, ipp, udp);
2003 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
2006 GNUNET_break_op (0);
2007 GNUNET_STATISTICS_update (stats,
2008 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
2010 return GNUNET_SYSERR;
2015 GNUNET_break_op (0);
2016 return GNUNET_SYSERR;
2018 msg->size = htons (size);
2019 GNUNET_TUN_calculate_icmp_checksum (icmp,
2021 (void) GNUNET_HELPER_send (helper_handle,
2031 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2033 GNUNET_TIME_absolute_get ().abs_value);
2039 * We got a UDP packet back from the MESH tunnel. Pass it on to the
2040 * local virtual interface via the helper.
2042 * @param cls closure, NULL
2043 * @param tunnel connection to the other end
2044 * @param tunnel_ctx pointer to our 'struct TunnelState *'
2045 * @param sender who sent the message
2046 * @param message the actual message
2047 * @param atsi performance data for the connection
2048 * @return GNUNET_OK to keep the connection open,
2049 * GNUNET_SYSERR to close it (signal serious error)
2052 receive_udp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
2053 void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender,
2054 const struct GNUNET_MessageHeader *message,
2055 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
2057 struct TunnelState *ts = *tunnel_ctx;
2058 const struct GNUNET_EXIT_UdpReplyMessage *reply;
2061 GNUNET_STATISTICS_update (stats,
2062 gettext_noop ("# UDP packets received from mesh"),
2064 mlen = ntohs (message->size);
2065 if (mlen < sizeof (struct GNUNET_EXIT_UdpReplyMessage))
2067 GNUNET_break_op (0);
2068 return GNUNET_SYSERR;
2070 if (NULL == ts->heap_node)
2072 GNUNET_break_op (0);
2073 return GNUNET_SYSERR;
2075 if (AF_UNSPEC == ts->af)
2077 GNUNET_break_op (0);
2078 return GNUNET_SYSERR;
2080 reply = (const struct GNUNET_EXIT_UdpReplyMessage *) message;
2081 mlen -= sizeof (struct GNUNET_EXIT_UdpReplyMessage);
2083 char sbuf[INET6_ADDRSTRLEN];
2084 char dbuf[INET6_ADDRSTRLEN];
2086 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2087 "Received UDP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2088 (unsigned int) mlen,
2089 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2090 ts->destination_port,
2091 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2098 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2099 + sizeof (struct GNUNET_TUN_UdpHeader)
2100 + sizeof (struct GNUNET_MessageHeader) +
2101 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2104 char buf[size] GNUNET_ALIGN;
2105 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2106 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2107 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2108 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1];
2109 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2110 msg->size = htons (size);
2111 tun->flags = htons (0);
2112 tun->proto = htons (ETH_P_IPV4);
2113 GNUNET_TUN_initialize_ipv4_header (ipv4,
2115 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2116 &ts->destination_ip.v4,
2118 if (0 == ntohs (reply->source_port))
2119 udp->source_port = htons (ts->destination_port);
2121 udp->source_port = reply->source_port;
2122 if (0 == ntohs (reply->destination_port))
2123 udp->destination_port = htons (ts->source_port);
2125 udp->destination_port = reply->destination_port;
2126 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2127 GNUNET_TUN_calculate_udp4_checksum (ipv4,
2134 (void) GNUNET_HELPER_send (helper_handle,
2143 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2144 + sizeof (struct GNUNET_TUN_UdpHeader)
2145 + sizeof (struct GNUNET_MessageHeader) +
2146 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2149 char buf[size] GNUNET_ALIGN;
2150 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2151 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2152 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2153 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1];
2154 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2155 msg->size = htons (size);
2156 tun->flags = htons (0);
2157 tun->proto = htons (ETH_P_IPV6);
2158 GNUNET_TUN_initialize_ipv6_header (ipv6,
2160 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2161 &ts->destination_ip.v6,
2163 if (0 == ntohs (reply->source_port))
2164 udp->source_port = htons (ts->destination_port);
2166 udp->source_port = reply->source_port;
2167 if (0 == ntohs (reply->destination_port))
2168 udp->destination_port = htons (ts->source_port);
2170 udp->destination_port = reply->destination_port;
2171 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2172 GNUNET_TUN_calculate_udp6_checksum (ipv6,
2178 (void) GNUNET_HELPER_send (helper_handle,
2188 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2190 GNUNET_TIME_absolute_get ().abs_value);
2196 * We got a TCP packet back from the MESH tunnel. Pass it on to the
2197 * local virtual interface via the helper.
2199 * @param cls closure, NULL
2200 * @param tunnel connection to the other end
2201 * @param tunnel_ctx pointer to our 'struct TunnelState *'
2202 * @param sender who sent the message
2203 * @param message the actual message
2204 * @param atsi performance data for the connection
2205 * @return GNUNET_OK to keep the connection open,
2206 * GNUNET_SYSERR to close it (signal serious error)
2209 receive_tcp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
2211 const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED,
2212 const struct GNUNET_MessageHeader *message,
2213 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
2215 struct TunnelState *ts = *tunnel_ctx;
2216 const struct GNUNET_EXIT_TcpDataMessage *data;
2219 GNUNET_STATISTICS_update (stats,
2220 gettext_noop ("# TCP packets received from mesh"),
2222 mlen = ntohs (message->size);
2223 if (mlen < sizeof (struct GNUNET_EXIT_TcpDataMessage))
2225 GNUNET_break_op (0);
2226 return GNUNET_SYSERR;
2228 if (NULL == ts->heap_node)
2230 GNUNET_break_op (0);
2231 return GNUNET_SYSERR;
2233 data = (const struct GNUNET_EXIT_TcpDataMessage *) message;
2234 mlen -= sizeof (struct GNUNET_EXIT_TcpDataMessage);
2236 char sbuf[INET6_ADDRSTRLEN];
2237 char dbuf[INET6_ADDRSTRLEN];
2239 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2240 "Received TCP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2241 (unsigned int) mlen,
2242 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2243 ts->destination_port,
2244 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2247 if (data->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
2249 GNUNET_break_op (0);
2250 return GNUNET_SYSERR;
2256 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2257 + sizeof (struct GNUNET_TUN_TcpHeader)
2258 + sizeof (struct GNUNET_MessageHeader) +
2259 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2262 char buf[size] GNUNET_ALIGN;
2263 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2264 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2265 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2266 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv4[1];
2267 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2268 msg->size = htons (size);
2269 tun->flags = htons (0);
2270 tun->proto = htons (ETH_P_IPV4);
2271 GNUNET_TUN_initialize_ipv4_header (ipv4,
2273 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2274 &ts->destination_ip.v4,
2276 *tcp = data->tcp_header;
2277 tcp->source_port = htons (ts->destination_port);
2278 tcp->destination_port = htons (ts->source_port);
2279 GNUNET_TUN_calculate_tcp4_checksum (ipv4,
2286 (void) GNUNET_HELPER_send (helper_handle,
2295 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2296 + sizeof (struct GNUNET_TUN_TcpHeader)
2297 + sizeof (struct GNUNET_MessageHeader) +
2298 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2301 char buf[size] GNUNET_ALIGN;
2302 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2303 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2304 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2305 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv6[1];
2306 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2307 msg->size = htons (size);
2308 tun->flags = htons (0);
2309 tun->proto = htons (ETH_P_IPV6);
2310 GNUNET_TUN_initialize_ipv6_header (ipv6,
2312 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2313 &ts->destination_ip.v6,
2315 *tcp = data->tcp_header;
2316 tcp->source_port = htons (ts->destination_port);
2317 tcp->destination_port = htons (ts->source_port);
2318 GNUNET_TUN_calculate_tcp6_checksum (ipv6,
2325 (void) GNUNET_HELPER_send (helper_handle,
2333 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2335 GNUNET_TIME_absolute_get ().abs_value);
2341 * Allocate an IPv4 address from the range of the tunnel
2342 * for a new redirection.
2344 * @param v4 where to store the address
2345 * @return GNUNET_OK on success,
2346 * GNUNET_SYSERR on error
2349 allocate_v4_address (struct in_addr *v4)
2351 const char *ipv4addr = vpn_argv[4];
2352 const char *ipv4mask = vpn_argv[5];
2353 struct in_addr addr;
2354 struct in_addr mask;
2356 struct GNUNET_HashCode key;
2359 GNUNET_assert (1 == inet_pton (AF_INET, ipv4addr, &addr));
2360 GNUNET_assert (1 == inet_pton (AF_INET, ipv4mask, &mask));
2361 /* Given 192.168.0.1/255.255.0.0, we want a mask
2362 of '192.168.255.255', thus: */
2363 mask.s_addr = addr.s_addr | ~mask.s_addr;
2370 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2371 _("Failed to find unallocated IPv4 address in VPN's range\n"));
2372 return GNUNET_SYSERR;
2374 /* Pick random IPv4 address within the subnet, except 'addr' or 'mask' itself */
2375 rnd.s_addr = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2377 v4->s_addr = (addr.s_addr | rnd.s_addr) & mask.s_addr;
2378 get_destination_key_from_ip (AF_INET,
2382 while ( (GNUNET_YES ==
2383 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2385 (v4->s_addr == addr.s_addr) ||
2386 (v4->s_addr == mask.s_addr) );
2392 * Allocate an IPv6 address from the range of the tunnel
2393 * for a new redirection.
2395 * @param v6 where to store the address
2396 * @return GNUNET_OK on success,
2397 * GNUNET_SYSERR on error
2400 allocate_v6_address (struct in6_addr *v6)
2402 const char *ipv6addr = vpn_argv[2];
2403 struct in6_addr addr;
2404 struct in6_addr mask;
2405 struct in6_addr rnd;
2407 struct GNUNET_HashCode key;
2410 GNUNET_assert (1 == inet_pton (AF_INET6, ipv6addr, &addr));
2411 GNUNET_assert (ipv6prefix < 128);
2412 /* Given ABCD::/96, we want a mask of 'ABCD::FFFF:FFFF,
2415 for (i=127;i>=ipv6prefix;i--)
2416 mask.s6_addr[i / 8] |= (1 << (i % 8));
2418 /* Pick random IPv6 address within the subnet, except 'addr' or 'mask' itself */
2425 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2426 _("Failed to find unallocated IPv6 address in VPN's range\n"));
2427 return GNUNET_SYSERR;
2432 rnd.s6_addr[i] = (unsigned char) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2435 = (addr.s6_addr[i] | rnd.s6_addr[i]) & mask.s6_addr[i];
2437 get_destination_key_from_ip (AF_INET6,
2441 while ( (GNUNET_YES ==
2442 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2446 sizeof (struct in6_addr))) ||
2449 sizeof (struct in6_addr))) );
2455 * Free resources occupied by a destination entry.
2457 * @param de entry to free
2460 free_destination_entry (struct DestinationEntry *de)
2462 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2463 "Cleaning up destination entry\n");
2464 GNUNET_STATISTICS_update (stats,
2465 gettext_noop ("# Active destinations"),
2469 free_tunnel_state (de->ts);
2470 GNUNET_assert (NULL == de->ts);
2472 if (NULL != de->heap_node)
2474 GNUNET_CONTAINER_heap_remove_node (de->heap_node);
2475 de->heap_node = NULL;
2476 GNUNET_assert (GNUNET_YES ==
2477 GNUNET_CONTAINER_multihashmap_remove (destination_map,
2486 * We have too many active destinations. Clean up the oldest destination.
2488 * @param except destination that must NOT be cleaned up, even if it is the oldest
2491 expire_destination (struct DestinationEntry *except)
2493 struct DestinationEntry *de;
2495 de = GNUNET_CONTAINER_heap_peek (destination_heap);
2496 GNUNET_assert (NULL != de);
2498 return; /* can't do this */
2499 free_destination_entry (de);
2504 * Allocate an IP address for the response.
2506 * @param result_af desired address family; set to the actual
2507 * address family; can initially be AF_UNSPEC if there
2508 * is no preference; will be set to AF_UNSPEC if the
2510 * @param addr set to either v4 or v6 depending on which
2511 * storage location was used; set to NULL if allocation failed
2512 * @param v4 storage space for an IPv4 address
2513 * @param v6 storage space for an IPv6 address
2514 * @return GNUNET_OK normally, GNUNET_SYSERR if '*result_af' was
2515 * an unsupported address family (not AF_INET, AF_INET6 or AF_UNSPEC)
2518 allocate_response_ip (int *result_af,
2521 struct in6_addr *v6)
2528 allocate_v4_address (v4))
2529 *result_af = AF_UNSPEC;
2535 allocate_v6_address (v6))
2536 *result_af = AF_UNSPEC;
2542 allocate_v4_address (v4))
2545 *result_af = AF_INET;
2547 else if (GNUNET_OK ==
2548 allocate_v6_address (v6))
2551 *result_af = AF_INET6;
2556 return GNUNET_SYSERR;
2563 * A client asks us to setup a redirection via some exit
2564 * node to a particular IP. Setup the redirection and
2565 * give the client the allocated IP.
2568 * @param client requesting client
2569 * @param message redirection request (a 'struct RedirectToIpRequestMessage')
2572 service_redirect_to_ip (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
2573 const struct GNUNET_MessageHeader *message)
2577 const struct RedirectToIpRequestMessage *msg;
2583 struct DestinationEntry *de;
2584 struct GNUNET_HashCode key;
2585 struct TunnelState *ts;
2587 /* validate and parse request */
2588 mlen = ntohs (message->size);
2589 if (mlen < sizeof (struct RedirectToIpRequestMessage))
2592 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2595 alen = mlen - sizeof (struct RedirectToIpRequestMessage);
2596 msg = (const struct RedirectToIpRequestMessage *) message;
2597 addr_af = (int) htonl (msg->addr_af);
2601 if (alen != sizeof (struct in_addr))
2604 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2609 if (alen != sizeof (struct in6_addr))
2612 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2618 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2622 /* allocate response IP */
2623 result_af = (int) htonl (msg->result_af);
2624 if (GNUNET_OK != allocate_response_ip (&result_af,
2628 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2631 if ( (result_af == AF_UNSPEC) ||
2632 (GNUNET_NO == ntohl (msg->nac)) )
2634 /* send reply "instantly" */
2635 send_client_reply (client,
2640 if (result_af == AF_UNSPEC)
2642 /* failure, we're done */
2643 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2648 char sbuf[INET6_ADDRSTRLEN];
2649 char dbuf[INET6_ADDRSTRLEN];
2651 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2652 "Allocated address %s for redirection via exit to %s\n",
2653 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2655 &msg[1], dbuf, sizeof (dbuf)));
2658 /* setup destination record */
2659 de = GNUNET_malloc (sizeof (struct DestinationEntry));
2660 de->is_service = GNUNET_NO;
2661 de->details.exit_destination.af = addr_af;
2662 memcpy (&de->details.exit_destination.ip,
2665 get_destination_key_from_ip (result_af,
2669 GNUNET_assert (GNUNET_OK ==
2670 GNUNET_CONTAINER_multihashmap_put (destination_map,
2673 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2674 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2676 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
2677 GNUNET_STATISTICS_update (stats,
2678 gettext_noop ("# Active destinations"),
2680 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2681 expire_destination (de);
2683 /* setup tunnel to destination */
2684 ts = create_tunnel_to_destination (de,
2685 (GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
2691 ts->destination_ip.v4 = v4;
2694 ts->destination_ip.v6 = v6;
2700 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2705 * A client asks us to setup a redirection to a particular peer
2706 * offering a service. Setup the redirection and give the client the
2710 * @param client requesting client
2711 * @param message redirection request (a 'struct RedirectToPeerRequestMessage')
2714 service_redirect_to_service (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
2715 const struct GNUNET_MessageHeader *message)
2717 const struct RedirectToServiceRequestMessage *msg;
2722 struct DestinationEntry *de;
2723 struct GNUNET_HashCode key;
2724 struct TunnelState *ts;
2727 msg = (const struct RedirectToServiceRequestMessage *) message;
2729 /* allocate response IP */
2730 result_af = (int) htonl (msg->result_af);
2731 if (GNUNET_OK != allocate_response_ip (&result_af,
2735 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2738 if ( (result_af == AF_UNSPEC) ||
2739 (GNUNET_NO == ntohl (msg->nac)) )
2741 /* send reply "instantly" */
2742 send_client_reply (client,
2747 if (result_af == AF_UNSPEC)
2749 /* failure, we're done */
2750 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2751 _("Failed to allocate IP address for new destination\n"));
2752 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2757 char sbuf[INET6_ADDRSTRLEN];
2759 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2760 "Allocated address %s for redirection to service %s on peer %s\n",
2761 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2762 GNUNET_h2s (&msg->service_descriptor),
2763 GNUNET_i2s (&msg->target));
2766 /* setup destination record */
2767 de = GNUNET_malloc (sizeof (struct DestinationEntry));
2768 de->is_service = GNUNET_YES;
2769 de->details.service_destination.service_descriptor = msg->service_descriptor;
2770 de->details.service_destination.target = msg->target;
2771 get_destination_key_from_ip (result_af,
2775 GNUNET_assert (GNUNET_OK ==
2776 GNUNET_CONTAINER_multihashmap_put (destination_map,
2779 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2780 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2782 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
2783 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2784 expire_destination (de);
2785 ts = create_tunnel_to_destination (de,
2786 (GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
2792 ts->destination_ip.v4 = v4;
2795 ts->destination_ip.v6 = v6;
2801 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2807 * Function called for inbound tunnels. As we don't offer
2808 * any mesh services, this function should never be called.
2810 * @param cls closure
2811 * @param tunnel new handle to the tunnel
2812 * @param initiator peer that started the tunnel
2813 * @param atsi performance information for the tunnel
2814 * @return initial tunnel context for the tunnel
2815 * (can be NULL -- that's not an error)
2818 inbound_tunnel_cb (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
2819 const struct GNUNET_PeerIdentity *initiator,
2820 const struct GNUNET_ATS_Information *atsi)
2822 /* How can and why should anyone open an inbound tunnel to vpn? */
2829 * Function called whenever an inbound tunnel is destroyed. Should clean up
2830 * any associated state.
2832 * @param cls closure (set from GNUNET_MESH_connect)
2833 * @param tunnel connection to the other end (henceforth invalid)
2834 * @param tunnel_ctx place where local state associated
2835 * with the tunnel is stored (our 'struct TunnelState')
2838 tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel_ctx)
2840 /* we don't have inbound tunnels, so this function should never be called */
2846 * Free memory occupied by an entry in the destination map.
2850 * @param value a 'struct DestinationEntry *'
2851 * @return GNUNET_OK (continue to iterate)
2854 cleanup_destination (void *cls,
2855 const struct GNUNET_HashCode *key,
2858 struct DestinationEntry *de = value;
2860 free_destination_entry (de);
2866 * Free memory occupied by an entry in the tunnel map.
2870 * @param value a 'struct TunnelState *'
2871 * @return GNUNET_OK (continue to iterate)
2874 cleanup_tunnel (void *cls,
2875 const struct GNUNET_HashCode *key,
2878 struct TunnelState *ts = value;
2880 free_tunnel_state (ts);
2886 * Function scheduled as very last function, cleans up after us
2892 cleanup (void *cls GNUNET_UNUSED,
2893 const struct GNUNET_SCHEDULER_TaskContext *tc)
2897 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2898 "VPN is shutting down\n");
2899 if (NULL != destination_map)
2901 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
2902 &cleanup_destination,
2904 GNUNET_CONTAINER_multihashmap_destroy (destination_map);
2905 destination_map = NULL;
2907 if (NULL != destination_heap)
2909 GNUNET_CONTAINER_heap_destroy (destination_heap);
2910 destination_heap = NULL;
2912 if (NULL != tunnel_map)
2914 GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
2917 GNUNET_CONTAINER_multihashmap_destroy (tunnel_map);
2920 if (NULL != tunnel_heap)
2922 GNUNET_CONTAINER_heap_destroy (tunnel_heap);
2925 if (NULL != mesh_handle)
2927 GNUNET_MESH_disconnect (mesh_handle);
2930 if (NULL != helper_handle)
2932 GNUNET_HELPER_stop (helper_handle, GNUNET_NO);
2933 helper_handle = NULL;
2937 GNUNET_SERVER_notification_context_destroy (nc);
2942 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
2946 GNUNET_free_non_null (vpn_argv[i]);
2951 * A client disconnected, clean up all references to it.
2953 * @param cls the client that disconnected
2955 * @param value a 'struct TunnelState *'
2956 * @return GNUNET_OK (continue to iterate)
2959 cleanup_tunnel_client (void *cls,
2960 const struct GNUNET_HashCode *key,
2963 struct GNUNET_SERVER_Client *client = cls;
2964 struct TunnelState *ts = value;
2966 if (client == ts->client)
2968 GNUNET_SERVER_client_drop (ts->client);
2976 * A client disconnected, clean up all references to it.
2978 * @param cls the client that disconnected
2980 * @param value a 'struct DestinationEntry *'
2981 * @return GNUNET_OK (continue to iterate)
2984 cleanup_destination_client (void *cls,
2985 const struct GNUNET_HashCode *key,
2988 struct GNUNET_SERVER_Client *client = cls;
2989 struct DestinationEntry *de = value;
2990 struct TunnelState *ts;
2992 if (NULL == (ts = de->ts))
2994 if (client == ts->client)
2996 GNUNET_SERVER_client_drop (ts->client);
3004 * A client has disconnected from us. If we are currently building
3005 * a tunnel for it, cancel the operation.
3008 * @param client handle to the client that disconnected
3011 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
3013 if (NULL != tunnel_map)
3014 GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
3015 &cleanup_tunnel_client,
3017 if (NULL != destination_map)
3018 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
3019 &cleanup_destination_client,
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 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-vpn");
3065 GNUNET_OS_check_helper_binary (binary, GNUNET_YES, "-d gnunet-vpn - - 169.1.3.3.7 255.255.255.0")) //ipv4 only please!
3068 "`%s' is not SUID, refusing to run.\n",
3069 "gnunet-helper-vpn");
3070 GNUNET_free (binary);
3074 GNUNET_free (binary);
3076 stats = GNUNET_STATISTICS_create ("vpn", cfg);
3078 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_MAPPING",
3079 &max_destination_mappings))
3080 max_destination_mappings = 200;
3082 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_TUNNELS",
3083 &max_tunnel_mappings))
3084 max_tunnel_mappings = 200;
3086 destination_map = GNUNET_CONTAINER_multihashmap_create (max_destination_mappings * 2, GNUNET_NO);
3087 destination_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3088 tunnel_map = GNUNET_CONTAINER_multihashmap_create (max_tunnel_mappings * 2, GNUNET_NO);
3089 tunnel_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3092 vpn_argv[0] = GNUNET_strdup ("vpn-gnunet");
3093 if (GNUNET_SYSERR ==
3094 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IFNAME", &ifname))
3096 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3097 "No entry 'IFNAME' in configuration!\n");
3098 GNUNET_SCHEDULER_shutdown ();
3101 vpn_argv[1] = ifname;
3102 if (GNUNET_OK == GNUNET_NETWORK_test_pf (PF_INET6))
3104 if ( (GNUNET_SYSERR ==
3105 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6ADDR",
3107 (1 != inet_pton (AF_INET6, ipv6addr, &v6))) )
3109 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3110 "No valid entry 'IPV6ADDR' in configuration!\n");
3111 GNUNET_SCHEDULER_shutdown ();
3114 vpn_argv[2] = ipv6addr;
3115 if (GNUNET_SYSERR ==
3116 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6PREFIX",
3119 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3120 "No entry 'IPV6PREFIX' in configuration!\n");
3121 GNUNET_SCHEDULER_shutdown ();
3124 vpn_argv[3] = ipv6prefix_s;
3126 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn",
3129 (ipv6prefix >= 127) )
3131 GNUNET_SCHEDULER_shutdown ();
3137 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3138 _("IPv6 support disabled as this system does not support IPv6\n"));
3139 vpn_argv[2] = GNUNET_strdup ("-");
3140 vpn_argv[3] = GNUNET_strdup ("-");
3142 if (GNUNET_OK == GNUNET_NETWORK_test_pf (PF_INET))
3144 if ( (GNUNET_SYSERR ==
3145 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4ADDR",
3147 (1 != inet_pton (AF_INET, ipv4addr, &v4))) )
3149 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3150 "No valid entry for 'IPV4ADDR' in configuration!\n");
3151 GNUNET_SCHEDULER_shutdown ();
3154 vpn_argv[4] = ipv4addr;
3155 if ( (GNUNET_SYSERR ==
3156 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4MASK",
3158 (1 != inet_pton (AF_INET, ipv4mask, &v4))) )
3160 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3161 "No valid entry 'IPV4MASK' in configuration!\n");
3162 GNUNET_SCHEDULER_shutdown ();
3165 vpn_argv[5] = ipv4mask;
3169 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3170 _("IPv4 support disabled as this system does not support IPv4\n"));
3171 vpn_argv[4] = GNUNET_strdup ("-");
3172 vpn_argv[5] = GNUNET_strdup ("-");
3177 GNUNET_MESH_connect (cfg_, NULL,
3182 helper_handle = GNUNET_HELPER_start (GNUNET_NO,
3183 "gnunet-helper-vpn", vpn_argv,
3184 &message_token, NULL, NULL);
3185 nc = GNUNET_SERVER_notification_context_create (server, 1);
3186 GNUNET_SERVER_add_handlers (server, service_handlers);
3187 GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
3188 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls);
3193 * The main function of the VPN service.
3195 * @param argc number of arguments from the command line
3196 * @param argv command line arguments
3197 * @return 0 ok, 1 on error
3200 main (int argc, char *const *argv)
3202 return (GNUNET_OK ==
3203 GNUNET_SERVICE_run (argc, argv, "vpn",
3204 GNUNET_SERVICE_OPTION_NONE,
3205 &run, NULL)) ? global_ret : 1;
3208 /* end of gnunet-service-vpn.c */