*
* TODO:
* Basics:
- * - need some logging
- * - need some statistics
* - test!
* - better message queue management (bounded state, drop oldest/RED?)
* - actually destroy "stale" tunnels once we have too many!
#include "gnunet_protocols.h"
#include "gnunet_applications.h"
#include "gnunet_mesh_service.h"
+#include "gnunet_statistics_service.h"
#include "gnunet_constants.h"
#include "tcpip_tun.h"
#include "vpn.h"
*/
static struct GNUNET_CONTAINER_Heap *tunnel_heap;
+/**
+ * Statistics.
+ */
+static struct GNUNET_STATISTICS_Handle *stats;
+
/**
* The handle to the VPN helper process "gnunet-helper-vpn".
*/
GNUNET_PeerIdentity * peer)
{
struct TunnelState *ts = cls;
-
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %s disconnected from tunnel.\n",
+ GNUNET_i2s (peer));
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# Peers connected to mesh tunnels"),
+ -1, GNUNET_NO);
if (NULL != ts->th)
{
GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
{
struct TunnelState *ts = cls;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %s connected to tunnel.\n",
+ GNUNET_i2s (peer));
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# Peers connected to mesh tunnels"),
+ 1, GNUNET_NO);
if (NULL == ts->client)
return; /* nothing to do */
send_client_reply (ts->client,
tnq = ts->head;
GNUNET_assert (NULL != tnq);
GNUNET_assert (size >= tnq->len);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending %u bytes via mesh tunnel\n",
+ tnq->len);
GNUNET_CONTAINER_DLL_remove (ts->head,
ts->tail,
tnq);
tnq->len,
&send_to_peer_notify_callback,
ts);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# Bytes given to mesh for transmission"),
+ ret, GNUNET_NO);
return ret;
}
send_to_tunnel (struct TunnelMessageQueueEntry *tnq,
struct TunnelState *ts)
{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Queueing %u bytes for transmission via mesh tunnel\n",
+ tnq->len);
GNUNET_CONTAINER_DLL_insert_tail (ts->head,
ts->tail,
tnq);
{
struct TunnelState *ts;
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# Mesh tunnels created"),
+ 1, GNUNET_NO);
GNUNET_assert (NULL == de->ts);
ts = GNUNET_malloc (sizeof (struct TunnelState));
if (NULL != client)
ts);
if (de->is_service)
{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Creating tunnel to peer %s offering service %s\n",
+ GNUNET_i2s (&de->details.service_destination.target),
+ GNUNET_h2s (&de->details.service_destination.service_descriptor));
GNUNET_MESH_peer_request_connect_add (ts->tunnel,
&de->details.service_destination.target);
}
case AF_INET:
GNUNET_MESH_peer_request_connect_by_type (ts->tunnel,
GNUNET_APPLICATION_TYPE_IPV4_GATEWAY);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Creating tunnel to exit peer for %s\n",
+ "IPv4");
break;
case AF_INET6:
GNUNET_MESH_peer_request_connect_by_type (ts->tunnel,
GNUNET_APPLICATION_TYPE_IPV6_GATEWAY);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Creating tunnel to exit peer for %s\n",
+ "IPv6");
break;
default:
GNUNET_assert (0);
struct TunnelMessageQueueEntry *tnq;
size_t alen;
size_t mlen;
- GNUNET_MESH_ApplicationType app_type;
int is_new;
const struct udp_packet *udp;
const struct tcp_packet *tcp;
(unsigned int) protocol);
return;
}
-
if (! destination->is_service)
{
switch (destination->details.exit_destination.af)
{
case AF_INET:
alen = sizeof (struct in_addr);
- app_type = GNUNET_APPLICATION_TYPE_IPV4_GATEWAY;
break;
case AF_INET6:
alen = sizeof (struct in6_addr);
- app_type = GNUNET_APPLICATION_TYPE_IPV6_GATEWAY;
break;
default:
alen = 0;
GNUNET_assert (0);
}
+
+ {
+ char sbuf[INET6_ADDRSTRLEN];
+ char dbuf[INET6_ADDRSTRLEN];
+ char xbuf[INET6_ADDRSTRLEN];
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Routing %s packet from %s:%u -> %s:%u to destination %s:%u\n",
+ (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
+ inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
+ spt,
+ inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
+ dpt,
+ inet_ntop (destination->details.exit_destination.af,
+ &destination->details.exit_destination.ip,
+ xbuf, sizeof (xbuf)));
+ }
}
else
{
/* make compiler happy */
alen = 0;
- app_type = 0;
+ {
+ char sbuf[INET6_ADDRSTRLEN];
+ char dbuf[INET6_ADDRSTRLEN];
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Routing %s packet from %s:%u -> %s:%u to service %s at peer %s\n",
+ (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
+ inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
+ spt,
+ inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
+ dpt,
+ GNUNET_h2s (&destination->details.service_destination.service_descriptor),
+ GNUNET_i2s (&destination->details.service_destination.target));
+ }
+
}
/* see if we have an existing tunnel for this destination */
&key,
ts,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# Active tunnels"),
+ 1, GNUNET_NO);
/* FIXME: expire OLD tunnels if we have too many! */
}
else
return;
}
tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
+ tnq->len = mlen;
+ tnq->msg = &tnq[1];
usm = (struct GNUNET_EXIT_UdpServiceMessage *) &tnq[1];
usm->header.size = htons ((uint16_t) mlen);
usm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE);
}
tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) +
mlen);
+ tnq->len = mlen;
+ tnq->msg = &tnq[1];
uim = (struct GNUNET_EXIT_UdpInternetMessage *) &tnq[1];
uim->header.size = htons ((uint16_t) mlen);
uim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET);
return;
}
tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
+ tnq->len = mlen;
+ tnq->msg = &tnq[1];
tsm = (struct GNUNET_EXIT_TcpServiceStartMessage *) &tnq[1];
tsm->header.size = htons ((uint16_t) mlen);
tsm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START);
return;
}
tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
+ tnq->len = mlen;
+ tnq->msg = &tnq[1];
tim = (struct GNUNET_EXIT_TcpInternetStartMessage *) &tnq[1];
tim->header.size = htons ((uint16_t) mlen);
tim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START);
return;
}
tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
+ tnq->len = mlen;
+ tnq->msg = &tnq[1];
tdm = (struct GNUNET_EXIT_TcpDataMessage *) &tnq[1];
tdm->header.size = htons ((uint16_t) mlen);
tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA);
GNUNET_HashCode key;
struct DestinationEntry *de;
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# Packets received from TUN interface"),
+ 1, GNUNET_NO);
mlen = ntohs (message->size);
if ( (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
(mlen < sizeof (struct GNUNET_MessageHeader) + sizeof (struct tun_header)) )
const struct GNUNET_EXIT_UdpReplyMessage *reply;
size_t mlen;
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# UDP packets received from mesh"),
+ 1, GNUNET_NO);
mlen = ntohs (message->size);
if (mlen < sizeof (struct GNUNET_EXIT_UdpReplyMessage))
{
}
reply = (const struct GNUNET_EXIT_UdpReplyMessage *) message;
mlen -= sizeof (struct GNUNET_EXIT_UdpReplyMessage);
+ {
+ char sbuf[INET6_ADDRSTRLEN];
+ char dbuf[INET6_ADDRSTRLEN];
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received UDP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
+ (unsigned int) mlen,
+ inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
+ ts->destination_port,
+ inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
+ ts->source_port);
+ }
switch (ts->af)
{
case AF_INET:
const struct GNUNET_EXIT_TcpDataMessage *data;
size_t mlen;
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# TCP packets received from mesh"),
+ 1, GNUNET_NO);
mlen = ntohs (message->size);
if (mlen < sizeof (struct GNUNET_EXIT_TcpDataMessage))
{
}
data = (const struct GNUNET_EXIT_TcpDataMessage *) message;
mlen -= sizeof (struct GNUNET_EXIT_TcpDataMessage);
+ {
+ char sbuf[INET6_ADDRSTRLEN];
+ char dbuf[INET6_ADDRSTRLEN];
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received TCP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
+ (unsigned int) mlen,
+ inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
+ ts->destination_port,
+ inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
+ ts->source_port);
+ }
switch (ts->af)
{
case AF_INET:
void *addr;
struct DestinationEntry *de;
GNUNET_HashCode key;
- GNUNET_MESH_ApplicationType app_type;
/* validate and parse request */
mlen = ntohs (message->size);
GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
return;
}
- app_type = GNUNET_APPLICATION_TYPE_IPV4_GATEWAY;
break;
case AF_INET6:
if (alen != sizeof (struct in6_addr))
GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
return;
}
- app_type = GNUNET_APPLICATION_TYPE_IPV6_GATEWAY;
break;
default:
GNUNET_break (0);
GNUNET_SERVER_receive_done (client, GNUNET_OK);
return;
}
+
+ {
+ char sbuf[INET6_ADDRSTRLEN];
+ char dbuf[INET6_ADDRSTRLEN];
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Allocated address %s for redirection via exit to %s\n",
+ inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
+ inet_ntop (addr_af,
+ &msg[1], dbuf, sizeof (dbuf)));
+ }
/* setup destination record */
de = GNUNET_malloc (sizeof (struct DestinationEntry));
de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
de,
GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# Active destinations"),
+ 1, GNUNET_NO);
+
/* FIXME: expire OLD destinations if we have too many! */
/* setup tunnel to destination */
(void) create_tunnel_to_destination (de,
if (result_af == AF_UNSPEC)
{
/* failure, we're done */
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Failed to allocate IP address for new destination\n"));
GNUNET_SERVER_receive_done (client, GNUNET_OK);
return;
}
+
+ {
+ char sbuf[INET6_ADDRSTRLEN];
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Allocated address %s for redirection to service %s on peer %s\n",
+ inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
+ GNUNET_h2s (&msg->service_descriptor),
+ GNUNET_i2s (&msg->target));
+ }
/* setup destination record */
de = GNUNET_malloc (sizeof (struct DestinationEntry));
GNUNET_HashCode key;
struct TunnelMessageQueueEntry *tnq;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Cleaning up tunnel state\n");
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# Active tunnels"),
+ -1, GNUNET_NO);
while (NULL != (tnq = ts->head))
{
GNUNET_CONTAINER_DLL_remove (ts->head,
static void
free_destination_entry (struct DestinationEntry *de)
{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Cleaning up destination entry\n");
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# Active destinations"),
+ -1, GNUNET_NO);
if (NULL != de->ts)
{
free_tunnel_state (de->ts);
{
unsigned int i;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "VPN is shutting down\n");
if (NULL != destination_map)
{
GNUNET_CONTAINER_multihashmap_iterate (destination_map,
GNUNET_SERVER_notification_context_destroy (nc);
nc = NULL;
}
+ if (stats != NULL)
+ {
+ GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
+ stats = NULL;
+ }
for (i=0;i<5;i++)
GNUNET_free_non_null (vpn_argv[i]);
}
struct in6_addr v6;
cfg = cfg_;
+ stats = GNUNET_STATISTICS_create ("vpn", cfg);
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_MAPPING",
&max_destination_mappings))