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 spt = ntohs (udp->spt);
899 dpt = ntohs (udp->dpt);
900 get_tunnel_key_from_ips (af,
911 if (payload_length < sizeof (struct GNUNET_TUN_TcpHeader))
918 spt = ntohs (tcp->spt);
919 dpt = ntohs (tcp->dpt);
920 get_tunnel_key_from_ips (af,
931 if (payload_length < sizeof (struct GNUNET_TUN_IcmpHeader))
940 get_tunnel_key_from_ips (af,
950 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
951 _("Protocol %u not supported, dropping\n"),
952 (unsigned int) protocol);
955 if (! destination->is_service)
957 switch (destination->details.exit_destination.af)
960 alen = sizeof (struct in_addr);
963 alen = sizeof (struct in6_addr);
971 char sbuf[INET6_ADDRSTRLEN];
972 char dbuf[INET6_ADDRSTRLEN];
973 char xbuf[INET6_ADDRSTRLEN];
975 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
976 "Routing %s packet from %s:%u -> %s:%u to destination %s:%u\n",
977 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
978 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
980 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
982 inet_ntop (destination->details.exit_destination.af,
983 &destination->details.exit_destination.ip,
984 xbuf, sizeof (xbuf)),
990 /* make compiler happy */
993 char sbuf[INET6_ADDRSTRLEN];
994 char dbuf[INET6_ADDRSTRLEN];
996 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
997 "Routing %s packet from %s:%u -> %s:%u to service %s at peer %s\n",
998 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
999 inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
1001 inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
1003 GNUNET_h2s (&destination->details.service_destination.service_descriptor),
1004 GNUNET_i2s (&destination->details.service_destination.target));
1009 /* see if we have an existing tunnel for this destination */
1010 ts = GNUNET_CONTAINER_multihashmap_get (tunnel_map,
1014 /* need to either use the existing tunnel from the destination (if still
1015 available) or create a fresh one */
1016 is_new = GNUNET_YES;
1017 if (NULL == destination->ts)
1018 ts = create_tunnel_to_destination (destination, NULL, af, 0);
1020 ts = destination->ts;
1023 destination->ts = NULL;
1024 ts->destination_container = NULL; /* no longer 'contained' */
1025 /* now bind existing "unbound" tunnel to our IP/port tuple */
1026 ts->protocol = protocol;
1030 ts->source_ip.v4 = * (const struct in_addr *) source_ip;
1031 ts->destination_ip.v4 = * (const struct in_addr *) destination_ip;
1035 ts->source_ip.v6 = * (const struct in6_addr *) source_ip;
1036 ts->destination_ip.v6 = * (const struct in6_addr *) destination_ip;
1038 ts->source_port = spt;
1039 ts->destination_port = dpt;
1040 ts->heap_node = GNUNET_CONTAINER_heap_insert (tunnel_heap,
1042 GNUNET_TIME_absolute_get ().abs_value);
1043 GNUNET_assert (GNUNET_YES ==
1044 GNUNET_CONTAINER_multihashmap_put (tunnel_map,
1047 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1048 GNUNET_STATISTICS_update (stats,
1049 gettext_noop ("# Active tunnels"),
1051 while (GNUNET_CONTAINER_multihashmap_size (tunnel_map) > max_tunnel_mappings)
1057 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
1059 GNUNET_TIME_absolute_get ().abs_value);
1061 GNUNET_assert (NULL != ts->tunnel);
1063 /* send via tunnel */
1067 if (destination->is_service)
1069 struct GNUNET_EXIT_UdpServiceMessage *usm;
1071 mlen = sizeof (struct GNUNET_EXIT_UdpServiceMessage) +
1072 payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1073 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1078 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1081 usm = (struct GNUNET_EXIT_UdpServiceMessage *) &tnq[1];
1082 usm->header.size = htons ((uint16_t) mlen);
1083 usm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE);
1084 /* if the source port is below 32000, we assume it has a special
1085 meaning; if not, we pick a random port (this is a heuristic) */
1086 usm->source_port = (ntohs (udp->spt) < 32000) ? udp->spt : 0;
1087 usm->destination_port = udp->dpt;
1088 usm->service_descriptor = destination->details.service_destination.service_descriptor;
1091 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1095 struct GNUNET_EXIT_UdpInternetMessage *uim;
1096 struct in_addr *ip4dst;
1097 struct in6_addr *ip6dst;
1100 mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) +
1101 alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1102 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1107 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) +
1111 uim = (struct GNUNET_EXIT_UdpInternetMessage *) &tnq[1];
1112 uim->header.size = htons ((uint16_t) mlen);
1113 uim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET);
1114 uim->af = htonl (destination->details.exit_destination.af);
1115 uim->source_port = (ntohs (udp->spt) < 32000) ? udp->spt : 0;
1116 uim->destination_port = udp->dpt;
1117 switch (destination->details.exit_destination.af)
1120 ip4dst = (struct in_addr *) &uim[1];
1121 *ip4dst = destination->details.exit_destination.ip.v4;
1122 payload = &ip4dst[1];
1125 ip6dst = (struct in6_addr *) &uim[1];
1126 *ip6dst = destination->details.exit_destination.ip.v6;
1127 payload = &ip6dst[1];
1134 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1140 if (destination->is_service)
1142 struct GNUNET_EXIT_TcpServiceStartMessage *tsm;
1144 mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) +
1145 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1146 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1151 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1154 tsm = (struct GNUNET_EXIT_TcpServiceStartMessage *) &tnq[1];
1155 tsm->header.size = htons ((uint16_t) mlen);
1156 tsm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START);
1157 tsm->reserved = htonl (0);
1158 tsm->service_descriptor = destination->details.service_destination.service_descriptor;
1159 tsm->tcp_header = *tcp;
1162 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1166 struct GNUNET_EXIT_TcpInternetStartMessage *tim;
1167 struct in_addr *ip4dst;
1168 struct in6_addr *ip6dst;
1171 mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) +
1172 alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1173 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1178 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1181 tim = (struct GNUNET_EXIT_TcpInternetStartMessage *) &tnq[1];
1182 tim->header.size = htons ((uint16_t) mlen);
1183 tim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START);
1184 tim->af = htonl (destination->details.exit_destination.af);
1185 tim->tcp_header = *tcp;
1186 switch (destination->details.exit_destination.af)
1189 ip4dst = (struct in_addr *) &tim[1];
1190 *ip4dst = destination->details.exit_destination.ip.v4;
1191 payload = &ip4dst[1];
1194 ip6dst = (struct in6_addr *) &tim[1];
1195 *ip6dst = destination->details.exit_destination.ip.v6;
1196 payload = &ip6dst[1];
1203 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1208 struct GNUNET_EXIT_TcpDataMessage *tdm;
1210 mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) +
1211 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1212 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1217 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1220 tdm = (struct GNUNET_EXIT_TcpDataMessage *) &tnq[1];
1221 tdm->header.size = htons ((uint16_t) mlen);
1222 tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT);
1223 tdm->reserved = htonl (0);
1224 tdm->tcp_header = *tcp;
1227 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1231 if (destination->is_service)
1233 struct GNUNET_EXIT_IcmpServiceMessage *ism;
1235 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1236 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1237 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1242 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1244 ism = (struct GNUNET_EXIT_IcmpServiceMessage *) &tnq[1];
1245 ism->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE);
1246 ism->af = htonl (af); /* need to tell destination ICMP protocol family! */
1247 ism->service_descriptor = destination->details.service_destination.service_descriptor;
1248 ism->icmp_header = *icmp;
1249 /* ICMP protocol translation will be done by the receiver (as we don't know
1250 the target AF); however, we still need to possibly discard the payload
1251 depending on the ICMP type */
1257 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1258 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1260 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1261 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1262 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1263 /* throw away ICMP payload, won't be useful for the other side anyway */
1264 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1267 GNUNET_STATISTICS_update (stats,
1268 gettext_noop ("# ICMPv4 packets dropped (not allowed)"),
1272 /* end of AF_INET */
1277 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1278 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1279 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1280 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1281 /* throw away ICMP payload, won't be useful for the other side anyway */
1282 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1284 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1285 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1288 GNUNET_STATISTICS_update (stats,
1289 gettext_noop ("# ICMPv6 packets dropped (not allowed)"),
1293 /* end of AF_INET6 */
1300 /* update length calculations, as payload_length may have changed */
1301 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1302 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1304 ism->header.size = htons ((uint16_t) mlen);
1305 /* finally, copy payload (if there is any left...) */
1308 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1312 struct GNUNET_EXIT_IcmpInternetMessage *iim;
1313 struct in_addr *ip4dst;
1314 struct in6_addr *ip6dst;
1317 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1318 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1319 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1324 tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) +
1327 iim = (struct GNUNET_EXIT_IcmpInternetMessage *) &tnq[1];
1328 iim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET);
1329 iim->icmp_header = *icmp;
1330 /* Perform ICMP protocol-translation (depending on destination AF and source AF)
1331 and throw away ICMP payload depending on ICMP message type */
1337 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1338 if (destination->details.exit_destination.af == AF_INET6)
1339 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1341 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1342 if (destination->details.exit_destination.af == AF_INET6)
1343 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1345 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1346 if (destination->details.exit_destination.af == AF_INET6)
1347 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1348 /* throw away IP-payload, exit will have to make it up anyway */
1349 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1351 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1352 if (destination->details.exit_destination.af == AF_INET6)
1353 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1354 /* throw away IP-payload, exit will have to make it up anyway */
1355 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1357 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1358 if (destination->details.exit_destination.af == AF_INET6)
1360 GNUNET_STATISTICS_update (stats,
1361 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1366 /* throw away IP-payload, exit will have to make it up anyway */
1367 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1370 GNUNET_STATISTICS_update (stats,
1371 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1376 /* end of AF_INET */
1381 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1382 if (destination->details.exit_destination.af == AF_INET6)
1383 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1384 /* throw away IP-payload, exit will have to make it up anyway */
1385 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1387 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1388 if (destination->details.exit_destination.af == AF_INET)
1389 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1390 /* throw away IP-payload, exit will have to make it up anyway */
1391 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1393 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1394 if (destination->details.exit_destination.af == AF_INET)
1396 GNUNET_STATISTICS_update (stats,
1397 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1402 /* throw away IP-payload, exit will have to make it up anyway */
1403 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1405 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1406 if (destination->details.exit_destination.af == AF_INET)
1408 GNUNET_STATISTICS_update (stats,
1409 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1414 /* throw away IP-payload, exit will have to make it up anyway */
1415 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1417 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1418 if (destination->details.exit_destination.af == AF_INET)
1419 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1421 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1422 if (destination->details.exit_destination.af == AF_INET)
1423 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1426 GNUNET_STATISTICS_update (stats,
1427 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1432 /* end of AF_INET6 */
1437 /* update length calculations, as payload_length may have changed */
1438 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1439 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1441 iim->header.size = htons ((uint16_t) mlen);
1443 /* need to tell destination ICMP protocol family! */
1444 iim->af = htonl (destination->details.exit_destination.af);
1445 switch (destination->details.exit_destination.af)
1448 ip4dst = (struct in_addr *) &iim[1];
1449 *ip4dst = destination->details.exit_destination.ip.v4;
1450 payload = &ip4dst[1];
1453 ip6dst = (struct in6_addr *) &iim[1];
1454 *ip6dst = destination->details.exit_destination.ip.v6;
1455 payload = &ip6dst[1];
1462 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1466 /* not supported above, how can we get here !? */
1470 send_to_tunnel (tnq, ts);
1475 * Receive packets from the helper-process (someone send to the local
1476 * virtual tunnel interface). Find the destination mapping, and if it
1477 * exists, identify the correct MESH tunnel (or possibly create it)
1478 * and forward the packet.
1480 * @param cls closure, NULL
1481 * @param client NULL
1482 * @param message message we got from the client (VPN tunnel interface)
1485 message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED,
1486 const struct GNUNET_MessageHeader *message)
1488 const struct GNUNET_TUN_Layer2PacketHeader *tun;
1490 GNUNET_HashCode key;
1491 struct DestinationEntry *de;
1493 GNUNET_STATISTICS_update (stats,
1494 gettext_noop ("# Packets received from TUN interface"),
1496 mlen = ntohs (message->size);
1497 if ( (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
1498 (mlen < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader)) )
1503 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1504 mlen -= (sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader));
1505 switch (ntohs (tun->proto))
1509 const struct GNUNET_TUN_IPv6Header *pkt6;
1511 if (mlen < sizeof (struct GNUNET_TUN_IPv6Header))
1517 pkt6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1518 get_destination_key_from_ip (AF_INET6,
1519 &pkt6->destination_address,
1521 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1522 /* FIXME: do we need to guard against hash collision?
1523 (if so, we need to also store the local destination IP in the
1524 destination entry and then compare here; however, the risk
1525 of collision seems minimal AND the impact is unlikely to be
1526 super-problematic as well... */
1529 char buf[INET6_ADDRSTRLEN];
1531 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1532 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1533 inet_ntop (AF_INET6,
1534 &pkt6->destination_address,
1542 &pkt6->source_address,
1543 &pkt6->destination_address,
1545 mlen - sizeof (struct GNUNET_TUN_IPv6Header));
1550 struct GNUNET_TUN_IPv4Header *pkt4;
1552 if (mlen < sizeof (struct GNUNET_TUN_IPv4Header))
1558 pkt4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1559 get_destination_key_from_ip (AF_INET,
1560 &pkt4->destination_address,
1562 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1563 /* FIXME: do we need to guard against hash collision?
1564 (if so, we need to also store the local destination IP in the
1565 destination entry and then compare here; however, the risk
1566 of collision seems minimal AND the impact is unlikely to be
1567 super-problematic as well... */
1570 char buf[INET_ADDRSTRLEN];
1572 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1573 _("Packet received for unmapped destination `%s' (dropping it)\n"),
1575 &pkt4->destination_address,
1580 if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header))
1582 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1583 _("Received IPv4 packet with options (dropping it)\n"));
1589 &pkt4->source_address,
1590 &pkt4->destination_address,
1592 mlen - sizeof (struct GNUNET_TUN_IPv4Header));
1596 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1597 _("Received packet of unknown protocol %d from TUN (dropping it)\n"),
1598 (unsigned int) ntohs (tun->proto));
1605 * Synthesize a plausible ICMP payload for an ICMP error
1606 * response on the given tunnel.
1608 * @param ts tunnel information
1609 * @param ipp IPv4 header to fill in (ICMP payload)
1610 * @param udp "UDP" header to fill in (ICMP payload); might actually
1611 * also be the first 8 bytes of the TCP header
1614 make_up_icmpv4_payload (struct TunnelState *ts,
1615 struct GNUNET_TUN_IPv4Header *ipp,
1616 struct GNUNET_TUN_UdpHeader *udp)
1618 GNUNET_TUN_initialize_ipv4_header (ipp,
1620 sizeof (struct GNUNET_TUN_TcpHeader),
1622 &ts->destination_ip.v4);
1623 udp->spt = htons (ts->source_port);
1624 udp->dpt = htons (ts->destination_port);
1625 udp->len = htons (0);
1626 udp->crc = htons (0);
1631 * Synthesize a plausible ICMP payload for an ICMP error
1632 * response on the given tunnel.
1634 * @param ts tunnel information
1635 * @param ipp IPv6 header to fill in (ICMP payload)
1636 * @param udp "UDP" header to fill in (ICMP payload); might actually
1637 * also be the first 8 bytes of the TCP header
1640 make_up_icmpv6_payload (struct TunnelState *ts,
1641 struct GNUNET_TUN_IPv6Header *ipp,
1642 struct GNUNET_TUN_UdpHeader *udp)
1644 GNUNET_TUN_initialize_ipv6_header (ipp,
1646 sizeof (struct GNUNET_TUN_TcpHeader),
1648 &ts->destination_ip.v6);
1649 udp->spt = htons (ts->source_port);
1650 udp->dpt = htons (ts->destination_port);
1651 udp->len = htons (0);
1652 udp->crc = htons (0);
1657 * We got an ICMP packet back from the MESH tunnel. Pass it on to the
1658 * local virtual interface via the helper.
1660 * @param cls closure, NULL
1661 * @param tunnel connection to the other end
1662 * @param tunnel_ctx pointer to our 'struct TunnelState *'
1663 * @param sender who sent the message
1664 * @param message the actual message
1665 * @param atsi performance data for the connection
1666 * @return GNUNET_OK to keep the connection open,
1667 * GNUNET_SYSERR to close it (signal serious error)
1670 receive_icmp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1671 void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender,
1672 const struct GNUNET_MessageHeader *message,
1673 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
1675 struct TunnelState *ts = *tunnel_ctx;
1676 const struct GNUNET_EXIT_IcmpToVPNMessage *i2v;
1679 GNUNET_STATISTICS_update (stats,
1680 gettext_noop ("# ICMP packets received from mesh"),
1682 mlen = ntohs (message->size);
1683 if (mlen < sizeof (struct GNUNET_EXIT_IcmpToVPNMessage))
1685 GNUNET_break_op (0);
1686 return GNUNET_SYSERR;
1688 if (NULL == ts->heap_node)
1690 GNUNET_break_op (0);
1691 return GNUNET_SYSERR;
1693 if (AF_UNSPEC == ts->af)
1695 GNUNET_break_op (0);
1696 return GNUNET_SYSERR;
1698 i2v = (const struct GNUNET_EXIT_IcmpToVPNMessage *) message;
1699 mlen -= sizeof (struct GNUNET_EXIT_IcmpToVPNMessage);
1701 char sbuf[INET6_ADDRSTRLEN];
1702 char dbuf[INET6_ADDRSTRLEN];
1704 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1705 "Received ICMP packet from mesh, sending %u bytes from %s -> %s via TUN\n",
1706 (unsigned int) mlen,
1707 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
1708 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)));
1714 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
1715 + sizeof (struct GNUNET_TUN_IcmpHeader)
1716 + sizeof (struct GNUNET_MessageHeader) +
1717 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1720 /* reserve some extra space in case we have an ICMP type here where
1721 we will need to make up the payload ourselves */
1722 char buf[size + sizeof (struct GNUNET_TUN_IPv4Header) + 8];
1723 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1724 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1725 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1726 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv4[1];
1727 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1728 tun->flags = htons (0);
1729 tun->proto = htons (ETH_P_IPV4);
1730 GNUNET_TUN_initialize_ipv4_header (ipv4,
1732 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1733 &ts->destination_ip.v4,
1735 *icmp = i2v->icmp_header;
1739 /* For some ICMP types, we need to adjust (make up) the payload here.
1740 Also, depending on the AF used on the other side, we have to
1741 do ICMP PT (translate ICMP types) */
1742 switch (ntohl (i2v->af))
1747 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1748 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1750 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1751 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1752 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1754 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1755 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1759 /* sender did not strip ICMP payload? */
1760 GNUNET_break_op (0);
1761 return GNUNET_SYSERR;
1763 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1764 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1765 make_up_icmpv4_payload (ts, ipp, udp);
1769 GNUNET_break_op (0);
1770 GNUNET_STATISTICS_update (stats,
1771 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1773 return GNUNET_SYSERR;
1778 /* ICMP PT 6-to-4 and possibly making up payloads */
1781 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1782 icmp->type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
1784 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1785 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1789 /* sender did not strip ICMP payload? */
1790 GNUNET_break_op (0);
1791 return GNUNET_SYSERR;
1793 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1794 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1795 make_up_icmpv4_payload (ts, ipp, udp);
1798 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1799 icmp->type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1801 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1802 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1806 /* sender did not strip ICMP payload? */
1807 GNUNET_break_op (0);
1808 return GNUNET_SYSERR;
1810 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1811 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1812 make_up_icmpv4_payload (ts, ipp, udp);
1815 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1816 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1817 GNUNET_STATISTICS_update (stats,
1818 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1821 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1822 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1824 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1825 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1828 GNUNET_break_op (0);
1829 GNUNET_STATISTICS_update (stats,
1830 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1832 return GNUNET_SYSERR;
1837 GNUNET_break_op (0);
1838 return GNUNET_SYSERR;
1840 msg->size = htons (size);
1841 GNUNET_TUN_calculate_icmp_checksum (icmp,
1844 (void) GNUNET_HELPER_send (helper_handle,
1853 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
1854 + sizeof (struct GNUNET_TUN_IcmpHeader)
1855 + sizeof (struct GNUNET_MessageHeader) +
1856 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1859 char buf[size + sizeof (struct GNUNET_TUN_IPv6Header) + 8];
1860 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1861 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1862 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
1863 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv6[1];
1864 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1865 tun->flags = htons (0);
1866 tun->proto = htons (ETH_P_IPV6);
1867 GNUNET_TUN_initialize_ipv6_header (ipv6,
1869 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1870 &ts->destination_ip.v6,
1872 *icmp = i2v->icmp_header;
1877 /* For some ICMP types, we need to adjust (make up) the payload here.
1878 Also, depending on the AF used on the other side, we have to
1879 do ICMP PT (translate ICMP types) */
1880 switch (ntohl (i2v->af))
1883 /* ICMP PT 4-to-6 and possibly making up payloads */
1886 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1887 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1889 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1890 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1892 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1893 icmp->type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1895 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1896 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1900 /* sender did not strip ICMP payload? */
1901 GNUNET_break_op (0);
1902 return GNUNET_SYSERR;
1904 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1905 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1906 make_up_icmpv6_payload (ts, ipp, udp);
1909 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1910 icmp->type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1912 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1913 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1917 /* sender did not strip ICMP payload? */
1918 GNUNET_break_op (0);
1919 return GNUNET_SYSERR;
1921 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1922 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1923 make_up_icmpv6_payload (ts, ipp, udp);
1926 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1927 GNUNET_STATISTICS_update (stats,
1928 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1932 GNUNET_break_op (0);
1933 GNUNET_STATISTICS_update (stats,
1934 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1936 return GNUNET_SYSERR;
1943 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1944 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1945 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1946 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1948 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1949 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1953 /* sender did not strip ICMP payload? */
1954 GNUNET_break_op (0);
1955 return GNUNET_SYSERR;
1957 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1958 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1959 make_up_icmpv6_payload (ts, ipp, udp);
1962 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1965 GNUNET_break_op (0);
1966 GNUNET_STATISTICS_update (stats,
1967 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1969 return GNUNET_SYSERR;
1974 GNUNET_break_op (0);
1975 return GNUNET_SYSERR;
1977 msg->size = htons (size);
1978 GNUNET_TUN_calculate_icmp_checksum (icmp,
1980 (void) GNUNET_HELPER_send (helper_handle,
1990 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
1992 GNUNET_TIME_absolute_get ().abs_value);
1998 * We got a UDP packet back from the MESH tunnel. Pass it on to the
1999 * local virtual interface via the helper.
2001 * @param cls closure, NULL
2002 * @param tunnel connection to the other end
2003 * @param tunnel_ctx pointer to our 'struct TunnelState *'
2004 * @param sender who sent the message
2005 * @param message the actual message
2006 * @param atsi performance data for the connection
2007 * @return GNUNET_OK to keep the connection open,
2008 * GNUNET_SYSERR to close it (signal serious error)
2011 receive_udp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
2012 void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender,
2013 const struct GNUNET_MessageHeader *message,
2014 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
2016 struct TunnelState *ts = *tunnel_ctx;
2017 const struct GNUNET_EXIT_UdpReplyMessage *reply;
2020 GNUNET_STATISTICS_update (stats,
2021 gettext_noop ("# UDP packets received from mesh"),
2023 mlen = ntohs (message->size);
2024 if (mlen < sizeof (struct GNUNET_EXIT_UdpReplyMessage))
2026 GNUNET_break_op (0);
2027 return GNUNET_SYSERR;
2029 if (NULL == ts->heap_node)
2031 GNUNET_break_op (0);
2032 return GNUNET_SYSERR;
2034 if (AF_UNSPEC == ts->af)
2036 GNUNET_break_op (0);
2037 return GNUNET_SYSERR;
2039 reply = (const struct GNUNET_EXIT_UdpReplyMessage *) message;
2040 mlen -= sizeof (struct GNUNET_EXIT_UdpReplyMessage);
2042 char sbuf[INET6_ADDRSTRLEN];
2043 char dbuf[INET6_ADDRSTRLEN];
2045 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2046 "Received UDP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2047 (unsigned int) mlen,
2048 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2049 ts->destination_port,
2050 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2057 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2058 + sizeof (struct GNUNET_TUN_UdpHeader)
2059 + sizeof (struct GNUNET_MessageHeader) +
2060 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2064 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2065 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2066 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2067 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1];
2068 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2069 msg->size = htons (size);
2070 tun->flags = htons (0);
2071 tun->proto = htons (ETH_P_IPV4);
2072 GNUNET_TUN_initialize_ipv4_header (ipv4,
2074 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2075 &ts->destination_ip.v4,
2077 if (0 == ntohs (reply->source_port))
2078 udp->spt = htons (ts->destination_port);
2080 udp->spt = reply->source_port;
2081 if (0 == ntohs (reply->destination_port))
2082 udp->dpt = htons (ts->source_port);
2084 udp->dpt = reply->destination_port;
2085 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2086 GNUNET_TUN_calculate_udp4_checksum (ipv4,
2093 (void) GNUNET_HELPER_send (helper_handle,
2102 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2103 + sizeof (struct GNUNET_TUN_UdpHeader)
2104 + sizeof (struct GNUNET_MessageHeader) +
2105 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2109 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2110 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2111 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2112 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1];
2113 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2114 msg->size = htons (size);
2115 tun->flags = htons (0);
2116 tun->proto = htons (ETH_P_IPV6);
2117 GNUNET_TUN_initialize_ipv6_header (ipv6,
2119 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2120 &ts->destination_ip.v6,
2122 if (0 == ntohs (reply->source_port))
2123 udp->spt = htons (ts->destination_port);
2125 udp->spt = reply->source_port;
2126 if (0 == ntohs (reply->destination_port))
2127 udp->dpt = htons (ts->source_port);
2129 udp->dpt = reply->destination_port;
2130 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2131 GNUNET_TUN_calculate_udp6_checksum (ipv6,
2137 (void) GNUNET_HELPER_send (helper_handle,
2147 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2149 GNUNET_TIME_absolute_get ().abs_value);
2155 * We got a TCP packet back from the MESH tunnel. Pass it on to the
2156 * local virtual interface via the helper.
2158 * @param cls closure, NULL
2159 * @param tunnel connection to the other end
2160 * @param tunnel_ctx pointer to our 'struct TunnelState *'
2161 * @param sender who sent the message
2162 * @param message the actual message
2163 * @param atsi performance data for the connection
2164 * @return GNUNET_OK to keep the connection open,
2165 * GNUNET_SYSERR to close it (signal serious error)
2168 receive_tcp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
2170 const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED,
2171 const struct GNUNET_MessageHeader *message,
2172 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
2174 struct TunnelState *ts = *tunnel_ctx;
2175 const struct GNUNET_EXIT_TcpDataMessage *data;
2178 GNUNET_STATISTICS_update (stats,
2179 gettext_noop ("# TCP packets received from mesh"),
2181 mlen = ntohs (message->size);
2182 if (mlen < sizeof (struct GNUNET_EXIT_TcpDataMessage))
2184 GNUNET_break_op (0);
2185 return GNUNET_SYSERR;
2187 if (NULL == ts->heap_node)
2189 GNUNET_break_op (0);
2190 return GNUNET_SYSERR;
2192 data = (const struct GNUNET_EXIT_TcpDataMessage *) message;
2193 mlen -= sizeof (struct GNUNET_EXIT_TcpDataMessage);
2195 char sbuf[INET6_ADDRSTRLEN];
2196 char dbuf[INET6_ADDRSTRLEN];
2198 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2199 "Received TCP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2200 (unsigned int) mlen,
2201 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2202 ts->destination_port,
2203 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2210 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2211 + sizeof (struct GNUNET_TUN_TcpHeader)
2212 + sizeof (struct GNUNET_MessageHeader) +
2213 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2217 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2218 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2219 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2220 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv4[1];
2221 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2222 msg->size = htons (size);
2223 tun->flags = htons (0);
2224 tun->proto = htons (ETH_P_IPV4);
2225 GNUNET_TUN_initialize_ipv4_header (ipv4,
2227 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2228 &ts->destination_ip.v4,
2230 *tcp = data->tcp_header;
2231 tcp->spt = htons (ts->destination_port);
2232 tcp->dpt = htons (ts->source_port);
2233 GNUNET_TUN_calculate_tcp4_checksum (ipv4,
2240 (void) GNUNET_HELPER_send (helper_handle,
2249 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2250 + sizeof (struct GNUNET_TUN_TcpHeader)
2251 + sizeof (struct GNUNET_MessageHeader) +
2252 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2256 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2257 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2258 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2259 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv6[1];
2260 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2261 msg->size = htons (size);
2262 tun->flags = htons (0);
2263 tun->proto = htons (ETH_P_IPV6);
2264 GNUNET_TUN_initialize_ipv6_header (ipv6,
2266 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2267 &ts->destination_ip.v6,
2269 tcp->spt = htons (ts->destination_port);
2270 tcp->dpt = htons (ts->source_port);
2271 GNUNET_TUN_calculate_tcp6_checksum (ipv6,
2275 (void) GNUNET_HELPER_send (helper_handle,
2283 GNUNET_CONTAINER_heap_update_cost (tunnel_heap,
2285 GNUNET_TIME_absolute_get ().abs_value);
2291 * Allocate an IPv4 address from the range of the tunnel
2292 * for a new redirection.
2294 * @param v4 where to store the address
2295 * @return GNUNET_OK on success,
2296 * GNUNET_SYSERR on error
2299 allocate_v4_address (struct in_addr *v4)
2301 const char *ipv4addr = vpn_argv[4];
2302 const char *ipv4mask = vpn_argv[5];
2303 struct in_addr addr;
2304 struct in_addr mask;
2306 GNUNET_HashCode key;
2309 GNUNET_assert (1 == inet_pton (AF_INET, ipv4addr, &addr));
2310 GNUNET_assert (1 == inet_pton (AF_INET, ipv4mask, &mask));
2311 /* Given 192.168.0.1/255.255.0.0, we want a mask
2312 of '192.168.255.255', thus: */
2313 mask.s_addr = addr.s_addr | ~mask.s_addr;
2320 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2321 _("Failed to find unallocated IPv4 address in VPN's range\n"));
2322 return GNUNET_SYSERR;
2324 /* Pick random IPv4 address within the subnet, except 'addr' or 'mask' itself */
2325 rnd.s_addr = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2327 v4->s_addr = (addr.s_addr | rnd.s_addr) & mask.s_addr;
2328 get_destination_key_from_ip (AF_INET,
2332 while ( (GNUNET_YES ==
2333 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2335 (v4->s_addr == addr.s_addr) ||
2336 (v4->s_addr == mask.s_addr) );
2342 * Allocate an IPv6 address from the range of the tunnel
2343 * for a new redirection.
2345 * @param v6 where to store the address
2346 * @return GNUNET_OK on success,
2347 * GNUNET_SYSERR on error
2350 allocate_v6_address (struct in6_addr *v6)
2352 const char *ipv6addr = vpn_argv[2];
2353 struct in6_addr addr;
2354 struct in6_addr mask;
2355 struct in6_addr rnd;
2357 GNUNET_HashCode key;
2360 GNUNET_assert (1 == inet_pton (AF_INET6, ipv6addr, &addr));
2361 GNUNET_assert (ipv6prefix < 128);
2362 /* Given ABCD::/96, we want a mask of 'ABCD::FFFF:FFFF,
2365 for (i=127;i>=128-ipv6prefix;i--)
2366 mask.s6_addr[i / 8] |= (1 << (i % 8));
2368 /* Pick random IPv6 address within the subnet, except 'addr' or 'mask' itself */
2375 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2376 _("Failed to find unallocated IPv6 address in VPN's range\n"));
2377 return GNUNET_SYSERR;
2382 rnd.s6_addr[i] = (unsigned char) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2385 = (addr.s6_addr[i] | rnd.s6_addr[i]) & mask.s6_addr[i];
2387 get_destination_key_from_ip (AF_INET6,
2391 while ( (GNUNET_YES ==
2392 GNUNET_CONTAINER_multihashmap_contains (destination_map,
2396 sizeof (struct in6_addr))) ||
2399 sizeof (struct in6_addr))) );
2405 * Free resources occupied by a destination entry.
2407 * @param de entry to free
2410 free_destination_entry (struct DestinationEntry *de)
2412 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2413 "Cleaning up destination entry\n");
2414 GNUNET_STATISTICS_update (stats,
2415 gettext_noop ("# Active destinations"),
2419 free_tunnel_state (de->ts);
2420 GNUNET_assert (NULL == de->ts);
2422 if (NULL != de->heap_node)
2424 GNUNET_CONTAINER_heap_remove_node (de->heap_node);
2425 de->heap_node = NULL;
2426 GNUNET_assert (GNUNET_YES ==
2427 GNUNET_CONTAINER_multihashmap_remove (destination_map,
2436 * We have too many active destinations. Clean up the oldest destination.
2438 * @param except destination that must NOT be cleaned up, even if it is the oldest
2441 expire_destination (struct DestinationEntry *except)
2443 struct DestinationEntry *de;
2445 de = GNUNET_CONTAINER_heap_peek (destination_heap);
2446 GNUNET_assert (NULL != de);
2448 return; /* can't do this */
2449 free_destination_entry (de);
2454 * A client asks us to setup a redirection via some exit
2455 * node to a particular IP. Setup the redirection and
2456 * give the client the allocated IP.
2459 * @param client requesting client
2460 * @param message redirection request (a 'struct RedirectToIpRequestMessage')
2463 service_redirect_to_ip (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
2464 const struct GNUNET_MessageHeader *message)
2468 const struct RedirectToIpRequestMessage *msg;
2474 struct DestinationEntry *de;
2475 GNUNET_HashCode key;
2476 struct TunnelState *ts;
2478 /* validate and parse request */
2479 mlen = ntohs (message->size);
2480 if (mlen < sizeof (struct RedirectToIpRequestMessage))
2483 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2486 alen = mlen - sizeof (struct RedirectToIpRequestMessage);
2487 msg = (const struct RedirectToIpRequestMessage *) message;
2488 addr_af = (int) htonl (msg->addr_af);
2492 if (alen != sizeof (struct in_addr))
2495 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2500 if (alen != sizeof (struct in6_addr))
2503 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2509 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2513 /* allocate response IP */
2515 result_af = (int) htonl (msg->result_af);
2520 allocate_v4_address (&v4))
2521 result_af = AF_UNSPEC;
2527 allocate_v6_address (&v6))
2528 result_af = AF_UNSPEC;
2534 allocate_v4_address (&v4))
2537 result_af = AF_INET;
2539 else if (GNUNET_OK ==
2540 allocate_v6_address (&v6))
2543 result_af = AF_INET6;
2548 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2551 if ( (result_af == AF_UNSPEC) ||
2552 (GNUNET_NO == ntohl (msg->nac)) )
2554 /* send reply "instantly" */
2555 send_client_reply (client,
2560 if (result_af == AF_UNSPEC)
2562 /* failure, we're done */
2563 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2568 char sbuf[INET6_ADDRSTRLEN];
2569 char dbuf[INET6_ADDRSTRLEN];
2571 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2572 "Allocated address %s for redirection via exit to %s\n",
2573 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2575 &msg[1], dbuf, sizeof (dbuf)));
2578 /* setup destination record */
2579 de = GNUNET_malloc (sizeof (struct DestinationEntry));
2580 de->is_service = GNUNET_NO;
2581 de->details.exit_destination.af = addr_af;
2582 memcpy (&de->details.exit_destination.ip,
2585 get_destination_key_from_ip (result_af,
2589 GNUNET_assert (GNUNET_OK ==
2590 GNUNET_CONTAINER_multihashmap_put (destination_map,
2593 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2594 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2596 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
2597 GNUNET_STATISTICS_update (stats,
2598 gettext_noop ("# Active destinations"),
2600 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2601 expire_destination (de);
2603 /* setup tunnel to destination */
2604 ts = create_tunnel_to_destination (de,
2605 (GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
2611 ts->destination_ip.v4 = v4;
2614 ts->destination_ip.v6 = v6;
2620 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2625 * A client asks us to setup a redirection to a particular peer
2626 * offering a service. Setup the redirection and give the client the
2630 * @param client requesting client
2631 * @param message redirection request (a 'struct RedirectToPeerRequestMessage')
2634 service_redirect_to_service (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
2635 const struct GNUNET_MessageHeader *message)
2637 const struct RedirectToServiceRequestMessage *msg;
2642 struct DestinationEntry *de;
2643 GNUNET_HashCode key;
2644 struct TunnelState *ts;
2647 msg = (const struct RedirectToServiceRequestMessage *) message;
2649 /* allocate response IP */
2651 result_af = (int) htonl (msg->result_af);
2656 allocate_v4_address (&v4))
2657 result_af = AF_UNSPEC;
2663 allocate_v6_address (&v6))
2664 result_af = AF_UNSPEC;
2670 allocate_v4_address (&v4))
2673 result_af = AF_INET;
2675 else if (GNUNET_OK ==
2676 allocate_v6_address (&v6))
2679 result_af = AF_INET6;
2684 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2687 if ( (result_af == AF_UNSPEC) ||
2688 (GNUNET_NO == ntohl (msg->nac)) )
2690 /* send reply "instantly" */
2691 send_client_reply (client,
2696 if (result_af == AF_UNSPEC)
2698 /* failure, we're done */
2699 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2700 _("Failed to allocate IP address for new destination\n"));
2701 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2706 char sbuf[INET6_ADDRSTRLEN];
2708 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2709 "Allocated address %s for redirection to service %s on peer %s\n",
2710 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2711 GNUNET_h2s (&msg->service_descriptor),
2712 GNUNET_i2s (&msg->target));
2715 /* setup destination record */
2716 de = GNUNET_malloc (sizeof (struct DestinationEntry));
2717 de->is_service = GNUNET_YES;
2718 de->details.service_destination.service_descriptor = msg->service_descriptor;
2719 de->details.service_destination.target = msg->target;
2720 get_destination_key_from_ip (result_af,
2724 GNUNET_assert (GNUNET_OK ==
2725 GNUNET_CONTAINER_multihashmap_put (destination_map,
2728 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2729 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2731 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
2732 while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2733 expire_destination (de);
2734 ts = create_tunnel_to_destination (de,
2735 (GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
2741 ts->destination_ip.v4 = v4;
2744 ts->destination_ip.v6 = v6;
2750 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2756 * Function called for inbound tunnels. As we don't offer
2757 * any mesh services, this function should never be called.
2759 * @param cls closure
2760 * @param tunnel new handle to the tunnel
2761 * @param initiator peer that started the tunnel
2762 * @param atsi performance information for the tunnel
2763 * @return initial tunnel context for the tunnel
2764 * (can be NULL -- that's not an error)
2767 inbound_tunnel_cb (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
2768 const struct GNUNET_PeerIdentity *initiator,
2769 const struct GNUNET_ATS_Information *atsi)
2771 /* How can and why should anyone open an inbound tunnel to vpn? */
2778 * Function called whenever an inbound tunnel is destroyed. Should clean up
2779 * any associated state.
2781 * @param cls closure (set from GNUNET_MESH_connect)
2782 * @param tunnel connection to the other end (henceforth invalid)
2783 * @param tunnel_ctx place where local state associated
2784 * with the tunnel is stored (our 'struct TunnelState')
2787 tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel_ctx)
2789 /* we don't have inbound tunnels, so this function should never be called */
2795 * Free memory occupied by an entry in the destination map.
2799 * @param value a 'struct DestinationEntry *'
2800 * @return GNUNET_OK (continue to iterate)
2803 cleanup_destination (void *cls,
2804 const GNUNET_HashCode *key,
2807 struct DestinationEntry *de = value;
2809 free_destination_entry (de);
2815 * Free memory occupied by an entry in the tunnel map.
2819 * @param value a 'struct TunnelState *'
2820 * @return GNUNET_OK (continue to iterate)
2823 cleanup_tunnel (void *cls,
2824 const GNUNET_HashCode *key,
2827 struct TunnelState *ts = value;
2829 free_tunnel_state (ts);
2835 * Function scheduled as very last function, cleans up after us
2841 cleanup (void *cls GNUNET_UNUSED,
2842 const struct GNUNET_SCHEDULER_TaskContext *tc)
2846 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2847 "VPN is shutting down\n");
2848 if (NULL != destination_map)
2850 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
2851 &cleanup_destination,
2853 GNUNET_CONTAINER_multihashmap_destroy (destination_map);
2854 destination_map = NULL;
2856 if (NULL != destination_heap)
2858 GNUNET_CONTAINER_heap_destroy (destination_heap);
2859 destination_heap = NULL;
2861 if (NULL != tunnel_map)
2863 GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
2866 GNUNET_CONTAINER_multihashmap_destroy (tunnel_map);
2869 if (NULL != tunnel_heap)
2871 GNUNET_CONTAINER_heap_destroy (tunnel_heap);
2874 if (NULL != mesh_handle)
2876 GNUNET_MESH_disconnect (mesh_handle);
2879 if (NULL != helper_handle)
2881 GNUNET_HELPER_stop (helper_handle);
2882 helper_handle = NULL;
2886 GNUNET_SERVER_notification_context_destroy (nc);
2891 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
2895 GNUNET_free_non_null (vpn_argv[i]);
2900 * A client disconnected, clean up all references to it.
2902 * @param cls the client that disconnected
2904 * @param value a 'struct TunnelState *'
2905 * @return GNUNET_OK (continue to iterate)
2908 cleanup_tunnel_client (void *cls,
2909 const GNUNET_HashCode *key,
2912 struct GNUNET_SERVER_Client *client = cls;
2913 struct TunnelState *ts = value;
2915 if (client == ts->client)
2917 GNUNET_SERVER_client_drop (ts->client);
2925 * A client disconnected, clean up all references to it.
2927 * @param cls the client that disconnected
2929 * @param value a 'struct DestinationEntry *'
2930 * @return GNUNET_OK (continue to iterate)
2933 cleanup_destination_client (void *cls,
2934 const GNUNET_HashCode *key,
2937 struct GNUNET_SERVER_Client *client = cls;
2938 struct DestinationEntry *de = value;
2939 struct TunnelState *ts;
2941 if (NULL == (ts = de->ts))
2943 if (client == ts->client)
2945 GNUNET_SERVER_client_drop (ts->client);
2953 * A client has disconnected from us. If we are currently building
2954 * a tunnel for it, cancel the operation.
2957 * @param client handle to the client that disconnected
2960 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
2962 if (NULL != tunnel_map)
2963 GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
2964 &cleanup_tunnel_client,
2966 if (NULL != destination_map)
2967 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
2968 &cleanup_destination_client,
2974 * Main function that will be run by the scheduler.
2976 * @param cls closure
2977 * @param server the initialized server
2978 * @param cfg_ configuration
2982 struct GNUNET_SERVER_Handle *server,
2983 const struct GNUNET_CONFIGURATION_Handle *cfg_)
2985 static const struct GNUNET_SERVER_MessageHandler service_handlers[] = {
2986 /* callback, cls, type, size */
2987 { &service_redirect_to_ip, NULL, GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP, 0},
2988 { &service_redirect_to_service, NULL,
2989 GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE,
2990 sizeof (struct RedirectToServiceRequestMessage) },
2993 static const struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
2994 { &receive_udp_back, GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY, 0},
2995 { &receive_tcp_back, GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN, 0},
2996 { &receive_icmp_back, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN, 0},
2999 static const GNUNET_MESH_ApplicationType types[] = {
3000 GNUNET_APPLICATION_TYPE_END
3011 GNUNET_OS_check_helper_binary ("gnunet-helper-vpn"))
3014 "`%s' is not SUID, refusing to run.\n",
3015 "gnunet-helper-vpn");
3020 stats = GNUNET_STATISTICS_create ("vpn", cfg);
3022 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_MAPPING",
3023 &max_destination_mappings))
3024 max_destination_mappings = 200;
3026 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_TUNNELS",
3027 &max_tunnel_mappings))
3028 max_tunnel_mappings = 200;
3030 destination_map = GNUNET_CONTAINER_multihashmap_create (max_destination_mappings * 2);
3031 destination_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3032 tunnel_map = GNUNET_CONTAINER_multihashmap_create (max_tunnel_mappings * 2);
3033 tunnel_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3036 vpn_argv[0] = GNUNET_strdup ("vpn-gnunet");
3037 if (GNUNET_SYSERR ==
3038 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IFNAME", &ifname))
3040 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3041 "No entry 'IFNAME' in configuration!\n");
3042 GNUNET_SCHEDULER_shutdown ();
3045 vpn_argv[1] = ifname;
3046 if ( (GNUNET_SYSERR ==
3047 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6ADDR",
3049 (1 != inet_pton (AF_INET6, ipv6addr, &v6))) )
3051 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3052 "No valid entry 'IPV6ADDR' in configuration!\n");
3053 GNUNET_SCHEDULER_shutdown ();
3056 vpn_argv[2] = ipv6addr;
3057 if (GNUNET_SYSERR ==
3058 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6PREFIX",
3061 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3062 "No entry 'IPV6PREFIX' in configuration!\n");
3063 GNUNET_SCHEDULER_shutdown ();
3066 vpn_argv[3] = ipv6prefix_s;
3068 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn",
3071 (ipv6prefix >= 127) )
3073 GNUNET_SCHEDULER_shutdown ();
3077 if ( (GNUNET_SYSERR ==
3078 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4ADDR",
3080 (1 != inet_pton (AF_INET, ipv4addr, &v4))) )
3082 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3083 "No valid entry for 'IPV4ADDR' in configuration!\n");
3084 GNUNET_SCHEDULER_shutdown ();
3087 vpn_argv[4] = ipv4addr;
3088 if ( (GNUNET_SYSERR ==
3089 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4MASK",
3091 (1 != inet_pton (AF_INET, ipv4mask, &v4))) )
3093 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3094 "No valid entry 'IPV4MASK' in configuration!\n");
3095 GNUNET_SCHEDULER_shutdown ();
3098 vpn_argv[5] = ipv4mask;
3102 GNUNET_MESH_connect (cfg_, 42 /* queue length */, NULL,
3107 helper_handle = GNUNET_HELPER_start ("gnunet-helper-vpn", vpn_argv,
3108 &message_token, NULL);
3109 nc = GNUNET_SERVER_notification_context_create (server, 1);
3110 GNUNET_SERVER_add_handlers (server, service_handlers);
3111 GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
3112 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls);
3117 * The main function of the VPN service.
3119 * @param argc number of arguments from the command line
3120 * @param argv command line arguments
3121 * @return 0 ok, 1 on error
3124 main (int argc, char *const *argv)
3126 return (GNUNET_OK ==
3127 GNUNET_SERVICE_run (argc, argv, "vpn",
3128 GNUNET_SERVICE_OPTION_NONE,
3129 &run, NULL)) ? global_ret : 1;
3132 /* end of gnunet-service-vpn.c */