-removing legacy dns/vpn/exit code and renaming -new versions to current
[oweals/gnunet.git] / src / vpn / gnunet-service-vpn.c
index 7219471bf061100f174d4a03c14ee8f99f46e745..afa577f983e9efc2ec60cc2399228fe997d1fc30 100644 (file)
@@ -28,8 +28,6 @@
  *
  * 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!
@@ -47,6 +45,7 @@
 #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"
@@ -314,6 +313,11 @@ static struct GNUNET_CONTAINER_MultiHashMap *tunnel_map;
  */
 static struct GNUNET_CONTAINER_Heap *tunnel_heap;
 
+/**
+ * Statistics.
+ */
+static struct GNUNET_STATISTICS_Handle *stats;
+
 /**
  * The handle to the VPN helper process "gnunet-helper-vpn".
  */
@@ -492,7 +496,13 @@ tunnel_peer_disconnect_handler (void *cls,
                                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);
@@ -523,6 +533,12 @@ tunnel_peer_connect_handler (void *cls,
 {
   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,
@@ -555,6 +571,9 @@ send_to_peer_notify_callback (void *cls, size_t size, void *buf)
   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);
@@ -570,6 +589,9 @@ send_to_peer_notify_callback (void *cls, size_t size, void *buf)
                                                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;
 }
 
@@ -587,6 +609,9 @@ static void
 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);
@@ -617,6 +642,9 @@ create_tunnel_to_destination (struct DestinationEntry *de,
 {
   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)
@@ -637,6 +665,10 @@ create_tunnel_to_destination (struct DestinationEntry *de,
                                          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);  
   }
@@ -647,10 +679,16 @@ create_tunnel_to_destination (struct DestinationEntry *de,
     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);
@@ -686,7 +724,6 @@ route_packet (struct DestinationEntry *destination,
   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;
@@ -741,29 +778,57 @@ route_packet (struct DestinationEntry *destination,
                (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 */
@@ -803,6 +868,9 @@ route_packet (struct DestinationEntry *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
@@ -829,6 +897,8 @@ route_packet (struct DestinationEntry *destination,
        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);
@@ -857,6 +927,8 @@ route_packet (struct DestinationEntry *destination,
       }
       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); 
@@ -898,6 +970,8 @@ route_packet (struct DestinationEntry *destination,
          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);
@@ -923,6 +997,8 @@ route_packet (struct DestinationEntry *destination,
          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);
@@ -960,6 +1036,8 @@ route_packet (struct DestinationEntry *destination,
        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);
@@ -998,6 +1076,9 @@ message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED,
   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)) )
@@ -1129,6 +1210,9 @@ receive_udp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
   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))
   {
@@ -1147,6 +1231,18 @@ receive_udp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
   }
   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:
@@ -1297,6 +1393,9 @@ receive_tcp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
   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))
   {
@@ -1310,6 +1409,18 @@ receive_tcp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
   }
   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:
@@ -1566,7 +1677,6 @@ service_redirect_to_ip (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *cl
   void *addr;
   struct DestinationEntry *de;
   GNUNET_HashCode key;
-  GNUNET_MESH_ApplicationType app_type;
   
   /* validate and parse request */
   mlen = ntohs (message->size);
@@ -1588,7 +1698,6 @@ service_redirect_to_ip (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *cl
       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))
@@ -1597,7 +1706,6 @@ service_redirect_to_ip (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *cl
       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
       return;      
     }
-    app_type = GNUNET_APPLICATION_TYPE_IPV6_GATEWAY; 
     break;
   default:
     GNUNET_break (0);
@@ -1658,6 +1766,17 @@ service_redirect_to_ip (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *cl
     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));
@@ -1678,6 +1797,10 @@ service_redirect_to_ip (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *cl
   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, 
@@ -1763,9 +1886,21 @@ service_redirect_to_service (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Clien
   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));
@@ -1827,6 +1962,11 @@ free_tunnel_state (struct TunnelState *ts)
   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,
@@ -1884,6 +2024,11 @@ free_tunnel_state (struct TunnelState *ts)
 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);
@@ -1979,6 +2124,8 @@ cleanup (void *cls GNUNET_UNUSED,
 {
   unsigned int i;
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "VPN is shutting down\n");
   if (NULL != destination_map)
   {  
     GNUNET_CONTAINER_multihashmap_iterate (destination_map,
@@ -2020,6 +2167,11 @@ cleanup (void *cls GNUNET_UNUSED,
     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]);
 }
@@ -2138,6 +2290,7 @@ run (void *cls,
   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))