2 This file is part of GNUnet.
3 (C) 2010, 2011, 2012 Christian Grothoff
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file vpn/gnunet-service-vpn.c
23 * @brief service that opens a virtual interface and allows its clients
24 * to allocate IPs on the virtual interface and to then redirect
25 * IP traffic received on those IPs via the GNUnet mesh
26 * @author Philipp Toelke
27 * @author Christian Grothoff
30 #include "gnunet_util_lib.h"
31 #include "gnunet_common.h"
32 #include "gnunet_protocols.h"
33 #include "gnunet_applications.h"
34 #include "gnunet_mesh_service.h"
35 #include "gnunet_statistics_service.h"
36 #include "gnunet_constants.h"
37 #include "gnunet_tun_lib.h"
43 * Maximum number of messages we allow in the queue for mesh.
45 #define MAX_MESSAGE_QUEUE_SIZE 4
49 * State we keep for each of our tunnels.
55 * Information we track for each IP address to determine which tunnel
56 * to send the traffic over to the destination.
58 struct DestinationEntry
62 * Key under which this entry is in the 'destination_map' (only valid
63 * if 'heap_node != NULL').
68 * Pre-allocated tunnel for this destination, or NULL for none.
70 struct TunnelState *ts;
73 * Entry for this entry in the destination_heap.
75 struct GNUNET_CONTAINER_HeapNode *heap_node;
78 * GNUNET_NO if this is a tunnel to an Internet-exit,
79 * GNUNET_YES if this tunnel is to a service.
84 * Details about the connection (depending on is_service).
92 * The description of the service (only used for service tunnels).
94 GNUNET_HashCode service_descriptor;
97 * Peer offering the service.
99 struct GNUNET_PeerIdentity target;
101 } service_destination;
107 * Address family used (AF_INET or AF_INET6).
112 * IP address of the ultimate destination (only used for exit tunnels).
117 * Address if af is AF_INET.
122 * Address if af is AF_INET6.
135 * A messages we have in queue for a particular tunnel.
137 struct TunnelMessageQueueEntry
140 * This is a doubly-linked list.
142 struct TunnelMessageQueueEntry *next;
145 * This is a doubly-linked list.
147 struct TunnelMessageQueueEntry *prev;
150 * Number of bytes in 'msg'.
155 * Message to transmit, allocated at the end of this struct.
162 * State we keep for each of our tunnels.
168 * Information about the tunnel to use, NULL if no tunnel
169 * is available right now.
171 struct GNUNET_MESH_Tunnel *tunnel;
174 * Active transmission handle, NULL for none.
176 struct GNUNET_MESH_TransmitHandle *th;
179 * Entry for this entry in the tunnel_heap, NULL as long as this
180 * tunnel state is not fully bound.
182 struct GNUNET_CONTAINER_HeapNode *heap_node;
185 * Head of list of messages scheduled for transmission.
187 struct TunnelMessageQueueEntry *tmq_head;
190 * Tail of list of messages scheduled for transmission.
192 struct TunnelMessageQueueEntry *tmq_tail;
195 * Client that needs to be notified about the tunnel being
196 * up as soon as a peer is connected; NULL for none.
198 struct GNUNET_SERVER_Client *client;
201 * Destination entry that has a pointer to this tunnel state;
202 * NULL if this tunnel state is in the tunnel map.
204 struct DestinationEntry *destination_container;
207 * ID of the client request that caused us to setup this entry.
212 * Destination to which this tunnel leads. Note that
213 * this struct is NOT in the destination_map (but a
214 * local copy) and that the 'heap_node' should always
217 struct DestinationEntry destination;
220 * Task scheduled to destroy the tunnel (or NO_TASK).
222 GNUNET_SCHEDULER_TaskIdentifier destroy_task;
225 * Addess family used for this tunnel on the local TUN interface.
230 * Length of the doubly linked 'tmq_head/tmq_tail' list.
232 unsigned int tmq_length;
235 * IPPROTO_TCP or IPPROTO_UDP once bound.
240 * IP address of the source on our end, initially uninitialized.
245 * Address if af is AF_INET.
250 * Address if af is AF_INET6.
257 * Destination IP address used by the source on our end (this is the IP
258 * that we pick freely within the VPN's tunnel IP range).
263 * Address if af is AF_INET.
268 * Address if af is AF_INET6.
275 * Source port used by the sender on our end; 0 for uninitialized.
277 uint16_t source_port;
280 * Destination port used by the sender on our end; 0 for uninitialized.
282 uint16_t destination_port;
288 * Return value from 'main'.
290 static int global_ret;
293 * Configuration we use.
295 static const struct GNUNET_CONFIGURATION_Handle *cfg;
298 * Handle to the mesh service.
300 static struct GNUNET_MESH_Handle *mesh_handle;
303 * Map from IP address to destination information (possibly with a
304 * MESH tunnel handle for fast setup).
306 static struct GNUNET_CONTAINER_MultiHashMap *destination_map;
309 * Min-Heap sorted by activity time to expire old mappings.
311 static struct GNUNET_CONTAINER_Heap *destination_heap;
314 * Map from source and destination address (IP+port) to connection
315 * information (mostly with the respective MESH tunnel handle).
317 static struct GNUNET_CONTAINER_MultiHashMap *tunnel_map;
320 * Min-Heap sorted by activity time to expire old mappings; values are
321 * of type 'struct TunnelState'.
323 static struct GNUNET_CONTAINER_Heap *tunnel_heap;
328 static struct GNUNET_STATISTICS_Handle *stats;
331 * The handle to the VPN helper process "gnunet-helper-vpn".
333 static struct GNUNET_HELPER_Handle *helper_handle;
336 * Arguments to the vpn helper.
338 static char *vpn_argv[7];
341 * Length of the prefix of the VPN's IPv6 network.
343 static unsigned long long ipv6prefix;
346 * Notification context for sending replies to clients.
348 static struct GNUNET_SERVER_NotificationContext *nc;
351 * If there are more than this number of address-mappings, old ones
354 static unsigned long long max_destination_mappings;
357 * If there are more than this number of open tunnels, old ones
360 static unsigned long long max_tunnel_mappings;
364 * Compute the key under which we would store an entry in the
365 * destination_map for the given IP address.
367 * @param af address family (AF_INET or AF_INET6)
368 * @param address IP address, struct in_addr or struct in6_addr
369 * @param key where to store the key
372 get_destination_key_from_ip (int af,
374 GNUNET_HashCode *key)
379 GNUNET_CRYPTO_hash (address,
380 sizeof (struct in_addr),
384 GNUNET_CRYPTO_hash (address,
385 sizeof (struct in6_addr),
396 * Compute the key under which we would store an entry in the
397 * tunnel_map for the given socket address pair.
399 * @param af address family (AF_INET or AF_INET6)
400 * @param protocol IPPROTO_TCP or IPPROTO_UDP
401 * @param source_ip sender's source IP, struct in_addr or struct in6_addr
402 * @param source_port sender's source port
403 * @param destination_ip sender's destination IP, struct in_addr or struct in6_addr
404 * @param destination_port sender's destination port
405 * @param key where to store the key
408 get_tunnel_key_from_ips (int af,
410 const void *source_ip,
411 uint16_t source_port,
412 const void *destination_ip,
413 uint16_t destination_port,
414 GNUNET_HashCode *key)
418 memset (key, 0, sizeof (GNUNET_HashCode));
419 /* the GNUnet hashmap only uses the first sizeof(unsigned int) of the hash,
420 so we put the ports in there (and hope for few collisions) */
422 memcpy (off, &source_port, sizeof (uint16_t));
423 off += sizeof (uint16_t);
424 memcpy (off, &destination_port, sizeof (uint16_t));
425 off += sizeof (uint16_t);
429 memcpy (off, source_ip, sizeof (struct in_addr));
430 off += sizeof (struct in_addr);
431 memcpy (off, destination_ip, sizeof (struct in_addr));
432 off += sizeof (struct in_addr);
435 memcpy (off, source_ip, sizeof (struct in6_addr));
436 off += sizeof (struct in6_addr);
437 memcpy (off, destination_ip, sizeof (struct in6_addr));
438 off += sizeof (struct in6_addr);
444 memcpy (off, &protocol, sizeof (uint8_t));
445 off += sizeof (uint8_t);
450 * Notify the client about the result of its request.
452 * @param client client to notify
453 * @param request_id original request ID to include in response
454 * @param result_af resulting address family
455 * @param addr resulting IP address
458 send_client_reply (struct GNUNET_SERVER_Client *client,
463 char buf[sizeof (struct RedirectToIpResponseMessage) + sizeof (struct in6_addr)];
464 struct RedirectToIpResponseMessage *res;
470 rlen = sizeof (struct in_addr);
473 rlen = sizeof (struct in6_addr);
482 res = (struct RedirectToIpResponseMessage *) buf;
483 res->header.size = htons (sizeof (struct RedirectToIpResponseMessage) + rlen);
484 res->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP);
485 res->result_af = htonl (result_af);
486 res->request_id = request_id;
487 memcpy (&res[1], addr, rlen);
488 GNUNET_SERVER_notification_context_add (nc, client);
489 GNUNET_SERVER_notification_context_unicast (nc,
497 * Free resources associated with a tunnel state.
499 * @param ts state to free
502 free_tunnel_state (struct TunnelState *ts)
505 struct TunnelMessageQueueEntry *tnq;
506 struct GNUNET_MESH_Tunnel *tunnel;
508 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
509 "Cleaning up tunnel state\n");
510 GNUNET_STATISTICS_update (stats,
511 gettext_noop ("# Active tunnels"),
513 while (NULL != (tnq = ts->tmq_head))
515 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
521 GNUNET_assert (0 == ts->tmq_length);
522 if (NULL != ts->client)
524 GNUNET_SERVER_client_drop (ts->client);
529 GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
532 GNUNET_assert (NULL == ts->destination.heap_node);
533 if (NULL != (tunnel = ts->tunnel))
536 GNUNET_MESH_tunnel_destroy (tunnel);
538 if (GNUNET_SCHEDULER_NO_TASK != ts->destroy_task)
540 GNUNET_SCHEDULER_cancel (ts->destroy_task);
541 ts->destroy_task = GNUNET_SCHEDULER_NO_TASK;
543 if (NULL != ts->heap_node)
545 GNUNET_CONTAINER_heap_remove_node (ts->heap_node);
546 ts->heap_node = NULL;
547 get_tunnel_key_from_ips (ts->af,
552 ts->destination_port,
554 GNUNET_assert (GNUNET_YES ==
555 GNUNET_CONTAINER_multihashmap_remove (tunnel_map,
559 if (NULL != ts->destination_container)
561 GNUNET_assert (ts == ts->destination_container->ts);
562 ts->destination_container->ts = NULL;
563 ts->destination_container = NULL;
570 * Destroy the mesh tunnel.
572 * @param cls the 'struct TunnelState' with the tunnel to destroy
573 * @param tc scheduler context
576 destroy_tunnel_task (void *cls,
577 const struct GNUNET_SCHEDULER_TaskContext *tc)
579 struct TunnelState *ts = cls;
580 struct GNUNET_MESH_Tunnel *tunnel;
582 ts->destroy_task = GNUNET_SCHEDULER_NO_TASK;
583 GNUNET_assert (NULL != ts->tunnel);
586 GNUNET_MESH_tunnel_destroy (tunnel);
587 free_tunnel_state (ts);
592 * Method called whenever a peer has disconnected from the tunnel.
595 * @param peer peer identity the tunnel stopped working with
598 tunnel_peer_disconnect_handler (void *cls,
600 GNUNET_PeerIdentity * peer)
602 struct TunnelState *ts = cls;
604 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
605 "Peer %s disconnected from tunnel.\n",
607 GNUNET_STATISTICS_update (stats,
608 gettext_noop ("# Peers connected to mesh tunnels"),
612 GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
615 if (ts->destination.is_service)
616 return; /* hope for reconnect eventually */
617 /* as we are most likely going to change the exit node now,
618 we should just destroy the tunnel entirely... */
619 if (GNUNET_SCHEDULER_NO_TASK == ts->destroy_task)
620 ts->destroy_task = GNUNET_SCHEDULER_add_now (&destroy_tunnel_task, ts);
625 * Method called whenever a peer has connected to the tunnel. Notifies
626 * the waiting client that the tunnel is now up.
629 * @param peer peer identity the tunnel was created to, NULL on timeout
630 * @param atsi performance data for the connection
633 tunnel_peer_connect_handler (void *cls,
634 const struct GNUNET_PeerIdentity
637 GNUNET_ATS_Information * atsi)
639 struct TunnelState *ts = cls;
641 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
642 "Peer %s connected to tunnel.\n",
644 GNUNET_STATISTICS_update (stats,
645 gettext_noop ("# Peers connected to mesh tunnels"),
647 if (NULL == ts->client)
648 return; /* nothing to do */
649 send_client_reply (ts->client,
652 &ts->destination_ip);
653 GNUNET_SERVER_client_drop (ts->client);
659 * Send a message from the message queue via mesh.
661 * @param cls the 'struct TunnelState' with the message queue
662 * @param size number of bytes available in buf
663 * @param buf where to copy the message
664 * @return number of bytes copied to buf
667 send_to_peer_notify_callback (void *cls, size_t size, void *buf)
669 struct TunnelState *ts = cls;
670 struct TunnelMessageQueueEntry *tnq;
677 GNUNET_assert (NULL != tnq);
678 GNUNET_assert (size >= tnq->len);
679 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
680 "Sending %u bytes via mesh tunnel\n",
682 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
686 memcpy (buf, tnq->msg, tnq->len);
689 if (NULL != (tnq = ts->tmq_head))
690 ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel,
691 GNUNET_NO /* cork */,
693 GNUNET_TIME_UNIT_FOREVER_REL,
696 &send_to_peer_notify_callback,
698 GNUNET_STATISTICS_update (stats,
699 gettext_noop ("# Bytes given to mesh for transmission"),
706 * Add the given message to the given tunnel and trigger the
707 * transmission process.
709 * @param tnq message to queue
710 * @param ts tunnel to queue the message for
713 send_to_tunnel (struct TunnelMessageQueueEntry *tnq,
714 struct TunnelState *ts)
716 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
717 "Queueing %u bytes for transmission via mesh tunnel\n",
719 GNUNET_assert (NULL != ts->tunnel);
720 GNUNET_CONTAINER_DLL_insert_tail (ts->tmq_head,
724 if (ts->tmq_length > MAX_MESSAGE_QUEUE_SIZE)
726 struct TunnelMessageQueueEntry *dq;
729 GNUNET_assert (dq != tnq);
730 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
734 GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
736 GNUNET_STATISTICS_update (stats,
737 gettext_noop ("# Bytes dropped in mesh queue (overflow)"),
743 ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel,
744 GNUNET_NO /* cork */,
746 GNUNET_TIME_UNIT_FOREVER_REL,
749 &send_to_peer_notify_callback,
755 * Initialize the given destination entry's mesh tunnel.
757 * @param de destination entry for which we need to setup a tunnel
758 * @param client client to notify on successful tunnel setup, or NULL for none
759 * @param client_af address family of the address returned to the client
760 * @param request_id request ID to send in client notification (unused if client is NULL)
761 * @return tunnel state of the tunnel that was created
763 static struct TunnelState *
764 create_tunnel_to_destination (struct DestinationEntry *de,
765 struct GNUNET_SERVER_Client *client,
769 struct TunnelState *ts;
771 GNUNET_STATISTICS_update (stats,
772 gettext_noop ("# Mesh tunnels created"),
774 GNUNET_assert (NULL == de->ts);
775 ts = GNUNET_malloc (sizeof (struct TunnelState));
779 ts->request_id = request_id;
781 GNUNET_SERVER_client_keep (client);
783 ts->destination = *de;
784 ts->destination.heap_node = NULL; /* copy is NOT in destination heap */
786 ts->destination_container = de; /* we are referenced from de */
787 ts->tunnel = GNUNET_MESH_tunnel_create (mesh_handle,
789 &tunnel_peer_connect_handler,
790 &tunnel_peer_disconnect_handler,
792 if (NULL == ts->tunnel)
794 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
795 _("Failed to setup mesh tunnel!\n"));
797 GNUNET_SERVER_client_drop (client);
803 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
804 "Creating tunnel to peer %s offering service %s\n",
805 GNUNET_i2s (&de->details.service_destination.target),
806 GNUNET_h2s (&de->details.service_destination.service_descriptor));
807 GNUNET_MESH_peer_request_connect_add (ts->tunnel,
808 &de->details.service_destination.target);
812 switch (de->details.exit_destination.af)
815 GNUNET_MESH_peer_request_connect_by_type (ts->tunnel,
816 GNUNET_APPLICATION_TYPE_IPV4_GATEWAY);
817 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
818 "Creating tunnel to exit peer for %s\n",
822 GNUNET_MESH_peer_request_connect_by_type (ts->tunnel,
823 GNUNET_APPLICATION_TYPE_IPV6_GATEWAY);
824 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
825 "Creating tunnel to exit peer for %s\n",
838 * We have too many active tunnels. Clean up the oldest tunnel.
840 * @param except tunnel that must NOT be cleaned up, even if it is the oldest
843 expire_tunnel (struct TunnelState *except)
845 struct TunnelState *ts;
847 ts = GNUNET_CONTAINER_heap_peek (tunnel_heap);
848 GNUNET_assert (NULL != ts);
850 return; /* can't do this */
851 free_tunnel_state (ts);
856 * Route a packet via mesh to the given destination.
858 * @param destination description of the destination
859 * @param af address family on this end (AF_INET or AF_INET6)
860 * @param protocol IPPROTO_TCP or IPPROTO_UDP
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;
891 if (payload_length < sizeof (struct GNUNET_TUN_UdpHeader))
898 if (udp->len < sizeof (struct GNUNET_TUN_UdpHeader))
903 spt = ntohs (udp->spt);
904 dpt = ntohs (udp->dpt);
905 get_tunnel_key_from_ips (af,
916 if (payload_length < sizeof (struct GNUNET_TUN_TcpHeader))
923 if (tcp->off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
928 spt = ntohs (tcp->spt);
929 dpt = ntohs (tcp->dpt);
930 get_tunnel_key_from_ips (af,
941 if (payload_length < sizeof (struct GNUNET_TUN_IcmpHeader))
950 get_tunnel_key_from_ips (af,
960 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
961 _("Protocol %u not supported, dropping\n"),
962 (unsigned int) protocol);
965 if (! destination->is_service)
967 switch (destination->details.exit_destination.af)
970 alen = sizeof (struct in_addr);
973 alen = sizeof (struct in6_addr);
981 char sbuf[INET6_ADDRSTRLEN];
982 char dbuf[INET6_ADDRSTRLEN];
983 char xbuf[INET6_ADDRSTRLEN];
985 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
986 "Routing %s packet from %s:%u -> %s:%u to destination %s:%u\n",
987 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
988 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
990 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
992 inet_ntop (destination->details.exit_destination.af,
993 &destination->details.exit_destination.ip,
994 xbuf, sizeof (xbuf)),
1000 /* make compiler happy */
1003 char sbuf[INET6_ADDRSTRLEN];
1004 char dbuf[INET6_ADDRSTRLEN];
1006 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1007 "Routing %s packet from %s:%u -> %s:%u to service %s at peer %s\n",
1008 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
1009 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
1011 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
1013 GNUNET_h2s (&destination->details.service_destination.service_descriptor),
1014 GNUNET_i2s (&destination->details.service_destination.target));
1019 /* see if we have an existing tunnel for this destination */
1020 ts = GNUNET_CONTAINER_multihashmap_get (tunnel_map,
1024 /* need to either use the existing tunnel from the destination (if still
1025 available) or create a fresh one */
1026 is_new = GNUNET_YES;
1027 if (NULL == destination->ts)
1028 ts = create_tunnel_to_destination (destination, NULL, af, 0);
1030 ts = destination->ts;
1033 destination->ts = NULL;
1034 ts->destination_container = NULL; /* no longer 'contained' */
1035 /* now bind existing "unbound" tunnel to our IP/port tuple */
1036 ts->protocol = protocol;
1040 ts->source_ip.v4 = * (const struct in_addr *) source_ip;
1041 ts->destination_ip.v4 = * (const struct in_addr *) destination_ip;
1045 ts->source_ip.v6 = * (const struct in6_addr *) source_ip;
1046 ts->destination_ip.v6 = * (const struct in6_addr *) destination_ip;
1048 ts->source_port = spt;
1049 ts->destination_port = dpt;
1050 ts->heap_node = GNUNET_CONTAINER_heap_insert (tunnel_heap,
1052 GNUNET_TIME_absolute_get ().abs_value);
1053 GNUNET_assert (GNUNET_YES ==
1054 GNUNET_CONTAINER_multihashmap_put (tunnel_map,
1057 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1058 GNUNET_STATISTICS_update (stats,
1059 gettext_noop ("# Active tunnels"),
1061 while (GNUNET_CONTAINER_multihashmap_size (tunnel_map) > max_tunnel_mappings)
1067 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
1069 GNUNET_TIME_absolute_get ().abs_value);
1071 GNUNET_assert (NULL != ts->tunnel);
1073 /* send via tunnel */
1077 if (destination->is_service)
1079 struct GNUNET_EXIT_UdpServiceMessage *usm;
1081 mlen = sizeof (struct GNUNET_EXIT_UdpServiceMessage) +
1082 payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1083 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1088 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1091 usm = (struct GNUNET_EXIT_UdpServiceMessage *) &tnq[1];
1092 usm->header.size = htons ((uint16_t) mlen);
1093 usm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE);
1094 /* if the source port is below 32000, we assume it has a special
1095 meaning; if not, we pick a random port (this is a heuristic) */
1096 usm->source_port = (ntohs (udp->spt) < 32000) ? udp->spt : 0;
1097 usm->destination_port = udp->dpt;
1098 usm->service_descriptor = destination->details.service_destination.service_descriptor;
1101 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1105 struct GNUNET_EXIT_UdpInternetMessage *uim;
1106 struct in_addr *ip4dst;
1107 struct in6_addr *ip6dst;
1110 mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) +
1111 alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1112 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1117 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) +
1121 uim = (struct GNUNET_EXIT_UdpInternetMessage *) &tnq[1];
1122 uim->header.size = htons ((uint16_t) mlen);
1123 uim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET);
1124 uim->af = htonl (destination->details.exit_destination.af);
1125 uim->source_port = (ntohs (udp->spt) < 32000) ? udp->spt : 0;
1126 uim->destination_port = udp->dpt;
1127 switch (destination->details.exit_destination.af)
1130 ip4dst = (struct in_addr *) &uim[1];
1131 *ip4dst = destination->details.exit_destination.ip.v4;
1132 payload = &ip4dst[1];
1135 ip6dst = (struct in6_addr *) &uim[1];
1136 *ip6dst = destination->details.exit_destination.ip.v6;
1137 payload = &ip6dst[1];
1144 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1150 if (destination->is_service)
1152 struct GNUNET_EXIT_TcpServiceStartMessage *tsm;
1154 mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) +
1155 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1156 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1161 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1164 tsm = (struct GNUNET_EXIT_TcpServiceStartMessage *) &tnq[1];
1165 tsm->header.size = htons ((uint16_t) mlen);
1166 tsm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START);
1167 tsm->reserved = htonl (0);
1168 tsm->service_descriptor = destination->details.service_destination.service_descriptor;
1169 tsm->tcp_header = *tcp;
1172 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1176 struct GNUNET_EXIT_TcpInternetStartMessage *tim;
1177 struct in_addr *ip4dst;
1178 struct in6_addr *ip6dst;
1181 mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) +
1182 alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1183 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1188 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1191 tim = (struct GNUNET_EXIT_TcpInternetStartMessage *) &tnq[1];
1192 tim->header.size = htons ((uint16_t) mlen);
1193 tim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START);
1194 tim->af = htonl (destination->details.exit_destination.af);
1195 tim->tcp_header = *tcp;
1196 switch (destination->details.exit_destination.af)
1199 ip4dst = (struct in_addr *) &tim[1];
1200 *ip4dst = destination->details.exit_destination.ip.v4;
1201 payload = &ip4dst[1];
1204 ip6dst = (struct in6_addr *) &tim[1];
1205 *ip6dst = destination->details.exit_destination.ip.v6;
1206 payload = &ip6dst[1];
1213 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1218 struct GNUNET_EXIT_TcpDataMessage *tdm;
1220 mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) +
1221 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1222 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1227 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1230 tdm = (struct GNUNET_EXIT_TcpDataMessage *) &tnq[1];
1231 tdm->header.size = htons ((uint16_t) mlen);
1232 tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT);
1233 tdm->reserved = htonl (0);
1234 tdm->tcp_header = *tcp;
1237 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1241 if (destination->is_service)
1243 struct GNUNET_EXIT_IcmpServiceMessage *ism;
1245 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1246 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1247 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1252 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1254 ism = (struct GNUNET_EXIT_IcmpServiceMessage *) &tnq[1];
1255 ism->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE);
1256 ism->af = htonl (af); /* need to tell destination ICMP protocol family! */
1257 ism->service_descriptor = destination->details.service_destination.service_descriptor;
1258 ism->icmp_header = *icmp;
1259 /* ICMP protocol translation will be done by the receiver (as we don't know
1260 the target AF); however, we still need to possibly discard the payload
1261 depending on the ICMP type */
1267 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1268 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1270 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1271 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1272 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1273 /* throw away ICMP payload, won't be useful for the other side anyway */
1274 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1277 GNUNET_STATISTICS_update (stats,
1278 gettext_noop ("# ICMPv4 packets dropped (not allowed)"),
1282 /* end of AF_INET */
1287 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1288 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1289 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1290 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1291 /* throw away ICMP payload, won't be useful for the other side anyway */
1292 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1294 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1295 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1298 GNUNET_STATISTICS_update (stats,
1299 gettext_noop ("# ICMPv6 packets dropped (not allowed)"),
1303 /* end of AF_INET6 */
1310 /* update length calculations, as payload_length may have changed */
1311 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1312 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1314 ism->header.size = htons ((uint16_t) mlen);
1315 /* finally, copy payload (if there is any left...) */
1318 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1322 struct GNUNET_EXIT_IcmpInternetMessage *iim;
1323 struct in_addr *ip4dst;
1324 struct in6_addr *ip6dst;
1327 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1328 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1329 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1334 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) +
1337 iim = (struct GNUNET_EXIT_IcmpInternetMessage *) &tnq[1];
1338 iim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET);
1339 iim->icmp_header = *icmp;
1340 /* Perform ICMP protocol-translation (depending on destination AF and source AF)
1341 and throw away ICMP payload depending on ICMP message type */
1347 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1348 if (destination->details.exit_destination.af == AF_INET6)
1349 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1351 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1352 if (destination->details.exit_destination.af == AF_INET6)
1353 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1355 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1356 if (destination->details.exit_destination.af == AF_INET6)
1357 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1358 /* throw away IP-payload, exit will have to make it up anyway */
1359 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1361 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1362 if (destination->details.exit_destination.af == AF_INET6)
1363 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1364 /* throw away IP-payload, exit will have to make it up anyway */
1365 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1367 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1368 if (destination->details.exit_destination.af == AF_INET6)
1370 GNUNET_STATISTICS_update (stats,
1371 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1376 /* throw away IP-payload, exit will have to make it up anyway */
1377 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1380 GNUNET_STATISTICS_update (stats,
1381 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1386 /* end of AF_INET */
1391 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1392 if (destination->details.exit_destination.af == AF_INET6)
1393 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1394 /* throw away IP-payload, exit will have to make it up anyway */
1395 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1397 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1398 if (destination->details.exit_destination.af == AF_INET)
1399 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1400 /* throw away IP-payload, exit will have to make it up anyway */
1401 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1403 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1404 if (destination->details.exit_destination.af == AF_INET)
1406 GNUNET_STATISTICS_update (stats,
1407 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1412 /* throw away IP-payload, exit will have to make it up anyway */
1413 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1415 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1416 if (destination->details.exit_destination.af == AF_INET)
1418 GNUNET_STATISTICS_update (stats,
1419 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
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_ECHO_REQUEST:
1428 if (destination->details.exit_destination.af == AF_INET)
1429 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1431 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1432 if (destination->details.exit_destination.af == AF_INET)
1433 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1436 GNUNET_STATISTICS_update (stats,
1437 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1442 /* end of AF_INET6 */
1447 /* update length calculations, as payload_length may have changed */
1448 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1449 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1451 iim->header.size = htons ((uint16_t) mlen);
1453 /* need to tell destination ICMP protocol family! */
1454 iim->af = htonl (destination->details.exit_destination.af);
1455 switch (destination->details.exit_destination.af)
1458 ip4dst = (struct in_addr *) &iim[1];
1459 *ip4dst = destination->details.exit_destination.ip.v4;
1460 payload = &ip4dst[1];
1463 ip6dst = (struct in6_addr *) &iim[1];
1464 *ip6dst = destination->details.exit_destination.ip.v6;
1465 payload = &ip6dst[1];
1472 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1476 /* not supported above, how can we get here !? */
1480 send_to_tunnel (tnq, ts);
1485 * Receive packets from the helper-process (someone send to the local
1486 * virtual tunnel interface). Find the destination mapping, and if it
1487 * exists, identify the correct MESH tunnel (or possibly create it)
1488 * and forward the packet.
1490 * @param cls closure, NULL
1491 * @param client NULL
1492 * @param message message we got from the client (VPN tunnel interface)
1495 message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED,
1496 const struct GNUNET_MessageHeader *message)
1498 const struct GNUNET_TUN_Layer2PacketHeader *tun;
1500 GNUNET_HashCode key;
1501 struct DestinationEntry *de;
1503 GNUNET_STATISTICS_update (stats,
1504 gettext_noop ("# Packets received from TUN interface"),
1506 mlen = ntohs (message->size);
1507 if ( (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
1508 (mlen < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader)) )
1513 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1514 mlen -= (sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader));
1515 switch (ntohs (tun->proto))
1519 const struct GNUNET_TUN_IPv6Header *pkt6;
1521 if (mlen < sizeof (struct GNUNET_TUN_IPv6Header))
1527 pkt6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1528 get_destination_key_from_ip (AF_INET6,
1529 &pkt6->destination_address,
1531 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1532 /* FIXME: do we need to guard against hash collision?
1533 (if so, we need to also store the local destination IP in the
1534 destination entry and then compare here; however, the risk
1535 of collision seems minimal AND the impact is unlikely to be
1536 super-problematic as well... */
1539 char buf[INET6_ADDRSTRLEN];
1541 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1542 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1543 inet_ntop (AF_INET6,
1544 &pkt6->destination_address,
1552 &pkt6->source_address,
1553 &pkt6->destination_address,
1555 mlen - sizeof (struct GNUNET_TUN_IPv6Header));
1560 struct GNUNET_TUN_IPv4Header *pkt4;
1562 if (mlen < sizeof (struct GNUNET_TUN_IPv4Header))
1568 pkt4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1569 get_destination_key_from_ip (AF_INET,
1570 &pkt4->destination_address,
1572 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1573 /* FIXME: do we need to guard against hash collision?
1574 (if so, we need to also store the local destination IP in the
1575 destination entry and then compare here; however, the risk
1576 of collision seems minimal AND the impact is unlikely to be
1577 super-problematic as well... */
1580 char buf[INET_ADDRSTRLEN];
1582 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1583 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1585 &pkt4->destination_address,
1590 if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header))
1592 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1593 _("Received IPv4 packet with options (dropping it)\n"));
1599 &pkt4->source_address,
1600 &pkt4->destination_address,
1602 mlen - sizeof (struct GNUNET_TUN_IPv4Header));
1606 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1607 _("Received packet of unknown protocol %d from TUN (dropping it)\n"),
1608 (unsigned int) ntohs (tun->proto));
1615 * Synthesize a plausible ICMP payload for an ICMP error
1616 * response on the given tunnel.
1618 * @param ts tunnel information
1619 * @param ipp IPv4 header to fill in (ICMP payload)
1620 * @param udp "UDP" header to fill in (ICMP payload); might actually
1621 * also be the first 8 bytes of the TCP header
1624 make_up_icmpv4_payload (struct TunnelState *ts,
1625 struct GNUNET_TUN_IPv4Header *ipp,
1626 struct GNUNET_TUN_UdpHeader *udp)
1628 GNUNET_TUN_initialize_ipv4_header (ipp,
1630 sizeof (struct GNUNET_TUN_TcpHeader),
1632 &ts->destination_ip.v4);
1633 udp->spt = htons (ts->source_port);
1634 udp->dpt = htons (ts->destination_port);
1635 udp->len = htons (0);
1636 udp->crc = htons (0);
1641 * Synthesize a plausible ICMP payload for an ICMP error
1642 * response on the given tunnel.
1644 * @param ts tunnel information
1645 * @param ipp IPv6 header to fill in (ICMP payload)
1646 * @param udp "UDP" header to fill in (ICMP payload); might actually
1647 * also be the first 8 bytes of the TCP header
1650 make_up_icmpv6_payload (struct TunnelState *ts,
1651 struct GNUNET_TUN_IPv6Header *ipp,
1652 struct GNUNET_TUN_UdpHeader *udp)
1654 GNUNET_TUN_initialize_ipv6_header (ipp,
1656 sizeof (struct GNUNET_TUN_TcpHeader),
1658 &ts->destination_ip.v6);
1659 udp->spt = htons (ts->source_port);
1660 udp->dpt = htons (ts->destination_port);
1661 udp->len = htons (0);
1662 udp->crc = htons (0);
1667 * We got an ICMP packet back from the MESH tunnel. Pass it on to the
1668 * local virtual interface via the helper.
1670 * @param cls closure, NULL
1671 * @param tunnel connection to the other end
1672 * @param tunnel_ctx pointer to our 'struct TunnelState *'
1673 * @param sender who sent the message
1674 * @param message the actual message
1675 * @param atsi performance data for the connection
1676 * @return GNUNET_OK to keep the connection open,
1677 * GNUNET_SYSERR to close it (signal serious error)
1680 receive_icmp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1681 void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender,
1682 const struct GNUNET_MessageHeader *message,
1683 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
1685 struct TunnelState *ts = *tunnel_ctx;
1686 const struct GNUNET_EXIT_IcmpToVPNMessage *i2v;
1689 GNUNET_STATISTICS_update (stats,
1690 gettext_noop ("# ICMP packets received from mesh"),
1692 mlen = ntohs (message->size);
1693 if (mlen < sizeof (struct GNUNET_EXIT_IcmpToVPNMessage))
1695 GNUNET_break_op (0);
1696 return GNUNET_SYSERR;
1698 if (NULL == ts->heap_node)
1700 GNUNET_break_op (0);
1701 return GNUNET_SYSERR;
1703 if (AF_UNSPEC == ts->af)
1705 GNUNET_break_op (0);
1706 return GNUNET_SYSERR;
1708 i2v = (const struct GNUNET_EXIT_IcmpToVPNMessage *) message;
1709 mlen -= sizeof (struct GNUNET_EXIT_IcmpToVPNMessage);
1711 char sbuf[INET6_ADDRSTRLEN];
1712 char dbuf[INET6_ADDRSTRLEN];
1714 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1715 "Received ICMP packet from mesh, sending %u bytes from %s -> %s via TUN\n",
1716 (unsigned int) mlen,
1717 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
1718 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)));
1724 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
1725 + sizeof (struct GNUNET_TUN_IcmpHeader)
1726 + sizeof (struct GNUNET_MessageHeader) +
1727 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1730 /* reserve some extra space in case we have an ICMP type here where
1731 we will need to make up the payload ourselves */
1732 char buf[size + sizeof (struct GNUNET_TUN_IPv4Header) + 8];
1733 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1734 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1735 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1736 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv4[1];
1737 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1738 tun->flags = htons (0);
1739 tun->proto = htons (ETH_P_IPV4);
1740 GNUNET_TUN_initialize_ipv4_header (ipv4,
1742 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1743 &ts->destination_ip.v4,
1745 *icmp = i2v->icmp_header;
1749 /* For some ICMP types, we need to adjust (make up) the payload here.
1750 Also, depending on the AF used on the other side, we have to
1751 do ICMP PT (translate ICMP types) */
1752 switch (ntohl (i2v->af))
1757 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1758 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1760 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1761 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1762 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1764 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1765 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1769 /* sender did not strip ICMP payload? */
1770 GNUNET_break_op (0);
1771 return GNUNET_SYSERR;
1773 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1774 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1775 make_up_icmpv4_payload (ts, ipp, udp);
1779 GNUNET_break_op (0);
1780 GNUNET_STATISTICS_update (stats,
1781 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1783 return GNUNET_SYSERR;
1788 /* ICMP PT 6-to-4 and possibly making up payloads */
1791 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1792 icmp->type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
1794 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1795 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1799 /* sender did not strip ICMP payload? */
1800 GNUNET_break_op (0);
1801 return GNUNET_SYSERR;
1803 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1804 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1805 make_up_icmpv4_payload (ts, ipp, udp);
1808 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1809 icmp->type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1811 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1812 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1816 /* sender did not strip ICMP payload? */
1817 GNUNET_break_op (0);
1818 return GNUNET_SYSERR;
1820 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1821 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1822 make_up_icmpv4_payload (ts, ipp, udp);
1825 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1826 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1827 GNUNET_STATISTICS_update (stats,
1828 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1831 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1832 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1834 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1835 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1838 GNUNET_break_op (0);
1839 GNUNET_STATISTICS_update (stats,
1840 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1842 return GNUNET_SYSERR;
1847 GNUNET_break_op (0);
1848 return GNUNET_SYSERR;
1850 msg->size = htons (size);
1851 GNUNET_TUN_calculate_icmp_checksum (icmp,
1854 (void) GNUNET_HELPER_send (helper_handle,
1863 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
1864 + sizeof (struct GNUNET_TUN_IcmpHeader)
1865 + sizeof (struct GNUNET_MessageHeader) +
1866 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1869 char buf[size + sizeof (struct GNUNET_TUN_IPv6Header) + 8];
1870 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1871 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1872 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
1873 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv6[1];
1874 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1875 tun->flags = htons (0);
1876 tun->proto = htons (ETH_P_IPV6);
1877 GNUNET_TUN_initialize_ipv6_header (ipv6,
1879 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1880 &ts->destination_ip.v6,
1882 *icmp = i2v->icmp_header;
1887 /* For some ICMP types, we need to adjust (make up) the payload here.
1888 Also, depending on the AF used on the other side, we have to
1889 do ICMP PT (translate ICMP types) */
1890 switch (ntohl (i2v->af))
1893 /* ICMP PT 4-to-6 and possibly making up payloads */
1896 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1897 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1899 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1900 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1902 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1903 icmp->type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1905 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1906 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1910 /* sender did not strip ICMP payload? */
1911 GNUNET_break_op (0);
1912 return GNUNET_SYSERR;
1914 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1915 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1916 make_up_icmpv6_payload (ts, ipp, udp);
1919 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1920 icmp->type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1922 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1923 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1927 /* sender did not strip ICMP payload? */
1928 GNUNET_break_op (0);
1929 return GNUNET_SYSERR;
1931 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1932 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1933 make_up_icmpv6_payload (ts, ipp, udp);
1936 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1937 GNUNET_STATISTICS_update (stats,
1938 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1942 GNUNET_break_op (0);
1943 GNUNET_STATISTICS_update (stats,
1944 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1946 return GNUNET_SYSERR;
1953 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1954 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1955 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1956 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1958 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1959 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1963 /* sender did not strip ICMP payload? */
1964 GNUNET_break_op (0);
1965 return GNUNET_SYSERR;
1967 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1968 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1969 make_up_icmpv6_payload (ts, ipp, udp);
1972 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1975 GNUNET_break_op (0);
1976 GNUNET_STATISTICS_update (stats,
1977 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1979 return GNUNET_SYSERR;
1984 GNUNET_break_op (0);
1985 return GNUNET_SYSERR;
1987 msg->size = htons (size);
1988 GNUNET_TUN_calculate_icmp_checksum (icmp,
1990 (void) GNUNET_HELPER_send (helper_handle,
2000 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2002 GNUNET_TIME_absolute_get ().abs_value);
2008 * We got a UDP packet back from the MESH tunnel. Pass it on to the
2009 * local virtual interface via the helper.
2011 * @param cls closure, NULL
2012 * @param tunnel connection to the other end
2013 * @param tunnel_ctx pointer to our 'struct TunnelState *'
2014 * @param sender who sent the message
2015 * @param message the actual message
2016 * @param atsi performance data for the connection
2017 * @return GNUNET_OK to keep the connection open,
2018 * GNUNET_SYSERR to close it (signal serious error)
2021 receive_udp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
2022 void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender,
2023 const struct GNUNET_MessageHeader *message,
2024 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
2026 struct TunnelState *ts = *tunnel_ctx;
2027 const struct GNUNET_EXIT_UdpReplyMessage *reply;
2030 GNUNET_STATISTICS_update (stats,
2031 gettext_noop ("# UDP packets received from mesh"),
2033 mlen = ntohs (message->size);
2034 if (mlen < sizeof (struct GNUNET_EXIT_UdpReplyMessage))
2036 GNUNET_break_op (0);
2037 return GNUNET_SYSERR;
2039 if (NULL == ts->heap_node)
2041 GNUNET_break_op (0);
2042 return GNUNET_SYSERR;
2044 if (AF_UNSPEC == ts->af)
2046 GNUNET_break_op (0);
2047 return GNUNET_SYSERR;
2049 reply = (const struct GNUNET_EXIT_UdpReplyMessage *) message;
2050 mlen -= sizeof (struct GNUNET_EXIT_UdpReplyMessage);
2052 char sbuf[INET6_ADDRSTRLEN];
2053 char dbuf[INET6_ADDRSTRLEN];
2055 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2056 "Received UDP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2057 (unsigned int) mlen,
2058 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2059 ts->destination_port,
2060 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2067 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2068 + sizeof (struct GNUNET_TUN_UdpHeader)
2069 + sizeof (struct GNUNET_MessageHeader) +
2070 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2074 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2075 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2076 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2077 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1];
2078 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2079 msg->size = htons (size);
2080 tun->flags = htons (0);
2081 tun->proto = htons (ETH_P_IPV4);
2082 GNUNET_TUN_initialize_ipv4_header (ipv4,
2084 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2085 &ts->destination_ip.v4,
2087 if (0 == ntohs (reply->source_port))
2088 udp->spt = htons (ts->destination_port);
2090 udp->spt = reply->source_port;
2091 if (0 == ntohs (reply->destination_port))
2092 udp->dpt = htons (ts->source_port);
2094 udp->dpt = reply->destination_port;
2095 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2096 GNUNET_TUN_calculate_udp4_checksum (ipv4,
2103 (void) GNUNET_HELPER_send (helper_handle,
2112 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2113 + sizeof (struct GNUNET_TUN_UdpHeader)
2114 + sizeof (struct GNUNET_MessageHeader) +
2115 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2119 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2120 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2121 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2122 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1];
2123 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2124 msg->size = htons (size);
2125 tun->flags = htons (0);
2126 tun->proto = htons (ETH_P_IPV6);
2127 GNUNET_TUN_initialize_ipv6_header (ipv6,
2129 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2130 &ts->destination_ip.v6,
2132 if (0 == ntohs (reply->source_port))
2133 udp->spt = htons (ts->destination_port);
2135 udp->spt = reply->source_port;
2136 if (0 == ntohs (reply->destination_port))
2137 udp->dpt = htons (ts->source_port);
2139 udp->dpt = reply->destination_port;
2140 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2141 GNUNET_TUN_calculate_udp6_checksum (ipv6,
2147 (void) GNUNET_HELPER_send (helper_handle,
2157 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2159 GNUNET_TIME_absolute_get ().abs_value);
2165 * We got a TCP packet back from the MESH tunnel. Pass it on to the
2166 * local virtual interface via the helper.
2168 * @param cls closure, NULL
2169 * @param tunnel connection to the other end
2170 * @param tunnel_ctx pointer to our 'struct TunnelState *'
2171 * @param sender who sent the message
2172 * @param message the actual message
2173 * @param atsi performance data for the connection
2174 * @return GNUNET_OK to keep the connection open,
2175 * GNUNET_SYSERR to close it (signal serious error)
2178 receive_tcp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
2180 const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED,
2181 const struct GNUNET_MessageHeader *message,
2182 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
2184 struct TunnelState *ts = *tunnel_ctx;
2185 const struct GNUNET_EXIT_TcpDataMessage *data;
2188 GNUNET_STATISTICS_update (stats,
2189 gettext_noop ("# TCP packets received from mesh"),
2191 mlen = ntohs (message->size);
2192 if (mlen < sizeof (struct GNUNET_EXIT_TcpDataMessage))
2194 GNUNET_break_op (0);
2195 return GNUNET_SYSERR;
2197 if (NULL == ts->heap_node)
2199 GNUNET_break_op (0);
2200 return GNUNET_SYSERR;
2202 data = (const struct GNUNET_EXIT_TcpDataMessage *) message;
2203 mlen -= sizeof (struct GNUNET_EXIT_TcpDataMessage);
2205 char sbuf[INET6_ADDRSTRLEN];
2206 char dbuf[INET6_ADDRSTRLEN];
2208 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2209 "Received TCP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2210 (unsigned int) mlen,
2211 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2212 ts->destination_port,
2213 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2216 if (data->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
2218 GNUNET_break_op (0);
2219 return GNUNET_SYSERR;
2225 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2226 + sizeof (struct GNUNET_TUN_TcpHeader)
2227 + sizeof (struct GNUNET_MessageHeader) +
2228 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2232 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2233 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2234 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2235 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv4[1];
2236 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2237 msg->size = htons (size);
2238 tun->flags = htons (0);
2239 tun->proto = htons (ETH_P_IPV4);
2240 GNUNET_TUN_initialize_ipv4_header (ipv4,
2242 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2243 &ts->destination_ip.v4,
2245 *tcp = data->tcp_header;
2246 tcp->spt = htons (ts->destination_port);
2247 tcp->dpt = htons (ts->source_port);
2248 GNUNET_TUN_calculate_tcp4_checksum (ipv4,
2255 (void) GNUNET_HELPER_send (helper_handle,
2264 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2265 + sizeof (struct GNUNET_TUN_TcpHeader)
2266 + sizeof (struct GNUNET_MessageHeader) +
2267 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2271 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2272 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2273 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2274 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv6[1];
2275 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2276 msg->size = htons (size);
2277 tun->flags = htons (0);
2278 tun->proto = htons (ETH_P_IPV6);
2279 GNUNET_TUN_initialize_ipv6_header (ipv6,
2281 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2282 &ts->destination_ip.v6,
2284 *tcp = data->tcp_header;
2285 tcp->spt = htons (ts->destination_port);
2286 tcp->dpt = htons (ts->source_port);
2287 GNUNET_TUN_calculate_tcp6_checksum (ipv6,
2291 (void) GNUNET_HELPER_send (helper_handle,
2299 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2301 GNUNET_TIME_absolute_get ().abs_value);
2307 * Allocate an IPv4 address from the range of the tunnel
2308 * for a new redirection.
2310 * @param v4 where to store the address
2311 * @return GNUNET_OK on success,
2312 * GNUNET_SYSERR on error
2315 allocate_v4_address (struct in_addr *v4)
2317 const char *ipv4addr = vpn_argv[4];
2318 const char *ipv4mask = vpn_argv[5];
2319 struct in_addr addr;
2320 struct in_addr mask;
2322 GNUNET_HashCode key;
2325 GNUNET_assert (1 == inet_pton (AF_INET, ipv4addr, &addr));
2326 GNUNET_assert (1 == inet_pton (AF_INET, ipv4mask, &mask));
2327 /* Given 192.168.0.1/255.255.0.0, we want a mask
2328 of '192.168.255.255', thus: */
2329 mask.s_addr = addr.s_addr | ~mask.s_addr;
2336 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2337 _("Failed to find unallocated IPv4 address in VPN's range\n"));
2338 return GNUNET_SYSERR;
2340 /* Pick random IPv4 address within the subnet, except 'addr' or 'mask' itself */
2341 rnd.s_addr = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2343 v4->s_addr = (addr.s_addr | rnd.s_addr) & mask.s_addr;
2344 get_destination_key_from_ip (AF_INET,
2348 while ( (GNUNET_YES ==
2349 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2351 (v4->s_addr == addr.s_addr) ||
2352 (v4->s_addr == mask.s_addr) );
2358 * Allocate an IPv6 address from the range of the tunnel
2359 * for a new redirection.
2361 * @param v6 where to store the address
2362 * @return GNUNET_OK on success,
2363 * GNUNET_SYSERR on error
2366 allocate_v6_address (struct in6_addr *v6)
2368 const char *ipv6addr = vpn_argv[2];
2369 struct in6_addr addr;
2370 struct in6_addr mask;
2371 struct in6_addr rnd;
2373 GNUNET_HashCode key;
2376 GNUNET_assert (1 == inet_pton (AF_INET6, ipv6addr, &addr));
2377 GNUNET_assert (ipv6prefix < 128);
2378 /* Given ABCD::/96, we want a mask of 'ABCD::FFFF:FFFF,
2381 for (i=127;i>=ipv6prefix;i--)
2382 mask.s6_addr[i / 8] |= (1 << (i % 8));
2384 /* Pick random IPv6 address within the subnet, except 'addr' or 'mask' itself */
2391 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2392 _("Failed to find unallocated IPv6 address in VPN's range\n"));
2393 return GNUNET_SYSERR;
2398 rnd.s6_addr[i] = (unsigned char) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2401 = (addr.s6_addr[i] | rnd.s6_addr[i]) & mask.s6_addr[i];
2403 get_destination_key_from_ip (AF_INET6,
2407 while ( (GNUNET_YES ==
2408 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2412 sizeof (struct in6_addr))) ||
2415 sizeof (struct in6_addr))) );
2421 * Free resources occupied by a destination entry.
2423 * @param de entry to free
2426 free_destination_entry (struct DestinationEntry *de)
2428 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2429 "Cleaning up destination entry\n");
2430 GNUNET_STATISTICS_update (stats,
2431 gettext_noop ("# Active destinations"),
2435 free_tunnel_state (de->ts);
2436 GNUNET_assert (NULL == de->ts);
2438 if (NULL != de->heap_node)
2440 GNUNET_CONTAINER_heap_remove_node (de->heap_node);
2441 de->heap_node = NULL;
2442 GNUNET_assert (GNUNET_YES ==
2443 GNUNET_CONTAINER_multihashmap_remove (destination_map,
2452 * We have too many active destinations. Clean up the oldest destination.
2454 * @param except destination that must NOT be cleaned up, even if it is the oldest
2457 expire_destination (struct DestinationEntry *except)
2459 struct DestinationEntry *de;
2461 de = GNUNET_CONTAINER_heap_peek (destination_heap);
2462 GNUNET_assert (NULL != de);
2464 return; /* can't do this */
2465 free_destination_entry (de);
2470 * A client asks us to setup a redirection via some exit
2471 * node to a particular IP. Setup the redirection and
2472 * give the client the allocated IP.
2475 * @param client requesting client
2476 * @param message redirection request (a 'struct RedirectToIpRequestMessage')
2479 service_redirect_to_ip (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
2480 const struct GNUNET_MessageHeader *message)
2484 const struct RedirectToIpRequestMessage *msg;
2490 struct DestinationEntry *de;
2491 GNUNET_HashCode key;
2492 struct TunnelState *ts;
2494 /* validate and parse request */
2495 mlen = ntohs (message->size);
2496 if (mlen < sizeof (struct RedirectToIpRequestMessage))
2499 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2502 alen = mlen - sizeof (struct RedirectToIpRequestMessage);
2503 msg = (const struct RedirectToIpRequestMessage *) message;
2504 addr_af = (int) htonl (msg->addr_af);
2508 if (alen != sizeof (struct in_addr))
2511 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2516 if (alen != sizeof (struct in6_addr))
2519 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2525 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2529 /* allocate response IP */
2531 result_af = (int) htonl (msg->result_af);
2536 allocate_v4_address (&v4))
2537 result_af = AF_UNSPEC;
2543 allocate_v6_address (&v6))
2544 result_af = AF_UNSPEC;
2550 allocate_v4_address (&v4))
2553 result_af = AF_INET;
2555 else if (GNUNET_OK ==
2556 allocate_v6_address (&v6))
2559 result_af = AF_INET6;
2564 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2567 if ( (result_af == AF_UNSPEC) ||
2568 (GNUNET_NO == ntohl (msg->nac)) )
2570 /* send reply "instantly" */
2571 send_client_reply (client,
2576 if (result_af == AF_UNSPEC)
2578 /* failure, we're done */
2579 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2584 char sbuf[INET6_ADDRSTRLEN];
2585 char dbuf[INET6_ADDRSTRLEN];
2587 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2588 "Allocated address %s for redirection via exit to %s\n",
2589 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2591 &msg[1], dbuf, sizeof (dbuf)));
2594 /* setup destination record */
2595 de = GNUNET_malloc (sizeof (struct DestinationEntry));
2596 de->is_service = GNUNET_NO;
2597 de->details.exit_destination.af = addr_af;
2598 memcpy (&de->details.exit_destination.ip,
2601 get_destination_key_from_ip (result_af,
2605 GNUNET_assert (GNUNET_OK ==
2606 GNUNET_CONTAINER_multihashmap_put (destination_map,
2609 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2610 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2612 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
2613 GNUNET_STATISTICS_update (stats,
2614 gettext_noop ("# Active destinations"),
2616 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2617 expire_destination (de);
2619 /* setup tunnel to destination */
2620 ts = create_tunnel_to_destination (de,
2621 (GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
2627 ts->destination_ip.v4 = v4;
2630 ts->destination_ip.v6 = v6;
2636 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2641 * A client asks us to setup a redirection to a particular peer
2642 * offering a service. Setup the redirection and give the client the
2646 * @param client requesting client
2647 * @param message redirection request (a 'struct RedirectToPeerRequestMessage')
2650 service_redirect_to_service (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
2651 const struct GNUNET_MessageHeader *message)
2653 const struct RedirectToServiceRequestMessage *msg;
2658 struct DestinationEntry *de;
2659 GNUNET_HashCode key;
2660 struct TunnelState *ts;
2663 msg = (const struct RedirectToServiceRequestMessage *) message;
2665 /* allocate response IP */
2667 result_af = (int) htonl (msg->result_af);
2672 allocate_v4_address (&v4))
2673 result_af = AF_UNSPEC;
2679 allocate_v6_address (&v6))
2680 result_af = AF_UNSPEC;
2686 allocate_v4_address (&v4))
2689 result_af = AF_INET;
2691 else if (GNUNET_OK ==
2692 allocate_v6_address (&v6))
2695 result_af = AF_INET6;
2700 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2703 if ( (result_af == AF_UNSPEC) ||
2704 (GNUNET_NO == ntohl (msg->nac)) )
2706 /* send reply "instantly" */
2707 send_client_reply (client,
2712 if (result_af == AF_UNSPEC)
2714 /* failure, we're done */
2715 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2716 _("Failed to allocate IP address for new destination\n"));
2717 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2722 char sbuf[INET6_ADDRSTRLEN];
2724 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2725 "Allocated address %s for redirection to service %s on peer %s\n",
2726 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2727 GNUNET_h2s (&msg->service_descriptor),
2728 GNUNET_i2s (&msg->target));
2731 /* setup destination record */
2732 de = GNUNET_malloc (sizeof (struct DestinationEntry));
2733 de->is_service = GNUNET_YES;
2734 de->details.service_destination.service_descriptor = msg->service_descriptor;
2735 de->details.service_destination.target = msg->target;
2736 get_destination_key_from_ip (result_af,
2740 GNUNET_assert (GNUNET_OK ==
2741 GNUNET_CONTAINER_multihashmap_put (destination_map,
2744 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2745 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2747 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
2748 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2749 expire_destination (de);
2750 ts = create_tunnel_to_destination (de,
2751 (GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
2757 ts->destination_ip.v4 = v4;
2760 ts->destination_ip.v6 = v6;
2766 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2772 * Function called for inbound tunnels. As we don't offer
2773 * any mesh services, this function should never be called.
2775 * @param cls closure
2776 * @param tunnel new handle to the tunnel
2777 * @param initiator peer that started the tunnel
2778 * @param atsi performance information for the tunnel
2779 * @return initial tunnel context for the tunnel
2780 * (can be NULL -- that's not an error)
2783 inbound_tunnel_cb (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
2784 const struct GNUNET_PeerIdentity *initiator,
2785 const struct GNUNET_ATS_Information *atsi)
2787 /* How can and why should anyone open an inbound tunnel to vpn? */
2794 * Function called whenever an inbound tunnel is destroyed. Should clean up
2795 * any associated state.
2797 * @param cls closure (set from GNUNET_MESH_connect)
2798 * @param tunnel connection to the other end (henceforth invalid)
2799 * @param tunnel_ctx place where local state associated
2800 * with the tunnel is stored (our 'struct TunnelState')
2803 tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel_ctx)
2805 /* we don't have inbound tunnels, so this function should never be called */
2811 * Free memory occupied by an entry in the destination map.
2815 * @param value a 'struct DestinationEntry *'
2816 * @return GNUNET_OK (continue to iterate)
2819 cleanup_destination (void *cls,
2820 const GNUNET_HashCode *key,
2823 struct DestinationEntry *de = value;
2825 free_destination_entry (de);
2831 * Free memory occupied by an entry in the tunnel map.
2835 * @param value a 'struct TunnelState *'
2836 * @return GNUNET_OK (continue to iterate)
2839 cleanup_tunnel (void *cls,
2840 const GNUNET_HashCode *key,
2843 struct TunnelState *ts = value;
2845 free_tunnel_state (ts);
2851 * Function scheduled as very last function, cleans up after us
2857 cleanup (void *cls GNUNET_UNUSED,
2858 const struct GNUNET_SCHEDULER_TaskContext *tc)
2862 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2863 "VPN is shutting down\n");
2864 if (NULL != destination_map)
2866 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
2867 &cleanup_destination,
2869 GNUNET_CONTAINER_multihashmap_destroy (destination_map);
2870 destination_map = NULL;
2872 if (NULL != destination_heap)
2874 GNUNET_CONTAINER_heap_destroy (destination_heap);
2875 destination_heap = NULL;
2877 if (NULL != tunnel_map)
2879 GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
2882 GNUNET_CONTAINER_multihashmap_destroy (tunnel_map);
2885 if (NULL != tunnel_heap)
2887 GNUNET_CONTAINER_heap_destroy (tunnel_heap);
2890 if (NULL != mesh_handle)
2892 GNUNET_MESH_disconnect (mesh_handle);
2895 if (NULL != helper_handle)
2897 GNUNET_HELPER_stop (helper_handle);
2898 helper_handle = NULL;
2902 GNUNET_SERVER_notification_context_destroy (nc);
2907 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
2911 GNUNET_free_non_null (vpn_argv[i]);
2916 * A client disconnected, clean up all references to it.
2918 * @param cls the client that disconnected
2920 * @param value a 'struct TunnelState *'
2921 * @return GNUNET_OK (continue to iterate)
2924 cleanup_tunnel_client (void *cls,
2925 const GNUNET_HashCode *key,
2928 struct GNUNET_SERVER_Client *client = cls;
2929 struct TunnelState *ts = value;
2931 if (client == ts->client)
2933 GNUNET_SERVER_client_drop (ts->client);
2941 * A client disconnected, clean up all references to it.
2943 * @param cls the client that disconnected
2945 * @param value a 'struct DestinationEntry *'
2946 * @return GNUNET_OK (continue to iterate)
2949 cleanup_destination_client (void *cls,
2950 const GNUNET_HashCode *key,
2953 struct GNUNET_SERVER_Client *client = cls;
2954 struct DestinationEntry *de = value;
2955 struct TunnelState *ts;
2957 if (NULL == (ts = de->ts))
2959 if (client == ts->client)
2961 GNUNET_SERVER_client_drop (ts->client);
2969 * A client has disconnected from us. If we are currently building
2970 * a tunnel for it, cancel the operation.
2973 * @param client handle to the client that disconnected
2976 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
2978 if (NULL != tunnel_map)
2979 GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
2980 &cleanup_tunnel_client,
2982 if (NULL != destination_map)
2983 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
2984 &cleanup_destination_client,
2990 * Main function that will be run by the scheduler.
2992 * @param cls closure
2993 * @param server the initialized server
2994 * @param cfg_ configuration
2998 struct GNUNET_SERVER_Handle *server,
2999 const struct GNUNET_CONFIGURATION_Handle *cfg_)
3001 static const struct GNUNET_SERVER_MessageHandler service_handlers[] = {
3002 /* callback, cls, type, size */
3003 { &service_redirect_to_ip, NULL, GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP, 0},
3004 { &service_redirect_to_service, NULL,
3005 GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE,
3006 sizeof (struct RedirectToServiceRequestMessage) },
3009 static const struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
3010 { &receive_udp_back, GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY, 0},
3011 { &receive_tcp_back, GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN, 0},
3012 { &receive_icmp_back, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN, 0},
3015 static const GNUNET_MESH_ApplicationType types[] = {
3016 GNUNET_APPLICATION_TYPE_END
3027 GNUNET_OS_check_helper_binary ("gnunet-helper-vpn"))
3030 "`%s' is not SUID, refusing to run.\n",
3031 "gnunet-helper-vpn");
3036 stats = GNUNET_STATISTICS_create ("vpn", cfg);
3038 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_MAPPING",
3039 &max_destination_mappings))
3040 max_destination_mappings = 200;
3042 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_TUNNELS",
3043 &max_tunnel_mappings))
3044 max_tunnel_mappings = 200;
3046 destination_map = GNUNET_CONTAINER_multihashmap_create (max_destination_mappings * 2);
3047 destination_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3048 tunnel_map = GNUNET_CONTAINER_multihashmap_create (max_tunnel_mappings * 2);
3049 tunnel_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3052 vpn_argv[0] = GNUNET_strdup ("vpn-gnunet");
3053 if (GNUNET_SYSERR ==
3054 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IFNAME", &ifname))
3056 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3057 "No entry 'IFNAME' in configuration!\n");
3058 GNUNET_SCHEDULER_shutdown ();
3061 vpn_argv[1] = ifname;
3062 if ( (GNUNET_SYSERR ==
3063 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6ADDR",
3065 (1 != inet_pton (AF_INET6, ipv6addr, &v6))) )
3067 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3068 "No valid entry 'IPV6ADDR' in configuration!\n");
3069 GNUNET_SCHEDULER_shutdown ();
3072 vpn_argv[2] = ipv6addr;
3073 if (GNUNET_SYSERR ==
3074 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6PREFIX",
3077 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3078 "No entry 'IPV6PREFIX' in configuration!\n");
3079 GNUNET_SCHEDULER_shutdown ();
3082 vpn_argv[3] = ipv6prefix_s;
3084 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn",
3087 (ipv6prefix >= 127) )
3089 GNUNET_SCHEDULER_shutdown ();
3093 if ( (GNUNET_SYSERR ==
3094 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4ADDR",
3096 (1 != inet_pton (AF_INET, ipv4addr, &v4))) )
3098 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3099 "No valid entry for 'IPV4ADDR' in configuration!\n");
3100 GNUNET_SCHEDULER_shutdown ();
3103 vpn_argv[4] = ipv4addr;
3104 if ( (GNUNET_SYSERR ==
3105 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4MASK",
3107 (1 != inet_pton (AF_INET, ipv4mask, &v4))) )
3109 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3110 "No valid entry 'IPV4MASK' in configuration!\n");
3111 GNUNET_SCHEDULER_shutdown ();
3114 vpn_argv[5] = ipv4mask;
3118 GNUNET_MESH_connect (cfg_, 42 /* queue length */, NULL,
3123 helper_handle = GNUNET_HELPER_start ("gnunet-helper-vpn", vpn_argv,
3124 &message_token, NULL);
3125 nc = GNUNET_SERVER_notification_context_create (server, 1);
3126 GNUNET_SERVER_add_handlers (server, service_handlers);
3127 GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
3128 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls);
3133 * The main function of the VPN service.
3135 * @param argc number of arguments from the command line
3136 * @param argv command line arguments
3137 * @return 0 ok, 1 on error
3140 main (int argc, char *const *argv)
3142 return (GNUNET_OK ==
3143 GNUNET_SERVICE_run (argc, argv, "vpn",
3144 GNUNET_SERVICE_OPTION_NONE,
3145 &run, NULL)) ? global_ret : 1;
3148 /* end of gnunet-service-vpn.c */