gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r2823 - in GNUnet: . src/applications/vpn


From: grothoff
Subject: [GNUnet-SVN] r2823 - in GNUnet: . src/applications/vpn
Date: Sun, 14 May 2006 15:35:26 -0700 (PDT)

Author: grothoff
Date: 2006-05-14 15:35:23 -0700 (Sun, 14 May 2006)
New Revision: 2823

Added:
   GNUnet/src/applications/vpn/gnunet-vpn.c
   GNUnet/src/applications/vpn/vpn.c
Removed:
   GNUnet/src/applications/vpn/gnunet-template.c
   GNUnet/src/applications/vpn/template.c
Modified:
   GNUnet/AUTHORS
   GNUnet/src/applications/vpn/Makefile.am
Log:
sync

Modified: GNUnet/AUTHORS
===================================================================
--- GNUnet/AUTHORS      2006-05-14 22:31:33 UTC (rev 2822)
+++ GNUnet/AUTHORS      2006-05-14 22:35:23 UTC (rev 2823)
@@ -1,6 +1,7 @@
 Primary developers (0.7.x series):
 Christian Grothoff <address@hidden>
 Nils Durner <address@hidden>
+Michael John Wensley
 
 Code contributions also came from:
 Andrew McDonald <address@hidden> [ SHA-512]

Modified: GNUnet/src/applications/vpn/Makefile.am
===================================================================
--- GNUnet/src/applications/vpn/Makefile.am     2006-05-14 22:31:33 UTC (rev 
2822)
+++ GNUnet/src/applications/vpn/Makefile.am     2006-05-14 22:35:23 UTC (rev 
2823)
@@ -6,18 +6,18 @@
  $(top_builddir)/src/util/libgnunetutil.la 
 
 bin_PROGRAMS = \
-  gnunet-template
+  gnunet-vpn
 
 plugin_LTLIBRARIES = \
-  libgnunetmodule_template.la
+  libgnunetmodule_vpn.la
 
 
-gnunet_template_SOURCES = \
-  gnunet-template.c    
+gnunet_vpn_SOURCES = \
+  gnunet-vpn.c         
 
-libgnunetmodule_template_la_SOURCES = \
-  template.c 
-libgnunetmodule_template_la_LDFLAGS = \
+libgnunetmodule_vpn_la_SOURCES = \
+  vpn.c 
+libgnunetmodule_vpn_la_LDFLAGS = \
   -export-dynamic -avoid-version -module \
   $(LDADD)
 

Deleted: GNUnet/src/applications/vpn/gnunet-template.c
===================================================================
--- GNUnet/src/applications/vpn/gnunet-template.c       2006-05-14 22:31:33 UTC 
(rev 2822)
+++ GNUnet/src/applications/vpn/gnunet-template.c       2006-05-14 22:35:23 UTC 
(rev 2823)
@@ -1,144 +0,0 @@
-/*
-     This file is part of GNUnet.
-     (C) 2001, 2002, 2004 Christian Grothoff (and other contributing authors)
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 2, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-     Boston, MA 02111-1307, USA.
-*/
-
-/**
- * @file applications/template/gnunet-template.c
- * @brief template for writing a GNUnet tool (client)
- * @author Christian Grothoff
- */
-
-#include "gnunet_util.h"
-#include "platform.h"
-
-#define TEMPLATE_VERSION "0.0.0"
-
-static Semaphore * doneSem;
-
-/**
- * Parse the options, set the timeout.
- * @param argc the number of options
- * @param argv the option list (including keywords)
- * @return OK on error, SYSERR if we should exit
- */
-static int parseOptions(int argc,
-                       char ** argv) {
-  int option_index;
-  int c;
-
-  FREENONNULL(setConfigurationString("GNUNETD",
-                                    "LOGFILE",
-                                    NULL));
-  while (1) {
-    static struct GNoption long_options[] = {
-      LONG_DEFAULT_OPTIONS,
-      { 0,0,0,0 }
-    };
-    option_index=0;
-    c = GNgetopt_long(argc,
-                     argv,
-                     "vhdc:L:H:t",
-                     long_options,
-                     &option_index);
-    if (c == -1)
-      break;  /* No more flags to process */
-    if (YES == parseDefaultOptions(c, GNoptarg))
-      continue;
-    switch(c) {
-    case 'h': {
-      static Help help[] = {
-       HELP_CONFIG,
-       HELP_HELP,
-       HELP_LOGLEVEL,
-       { 't', "longoptionname", "ARGUMENT",
-         gettext_noop("helptext for -t") },
-       HELP_VERSION,
-       HELP_END,
-      };
-      formatHelp("gnunet-template [OPTIONS]",
-                _("Template for gnunet-clients."),
-                help);
-
-      return SYSERR;
-    }
-    case 'v':
-      printf("GNUnet v%s, gnunet-template v%s\n",
-            VERSION,
-            TEMPLATE_VERSION);
-      return SYSERR;
-    default:
-      LOG(LOG_FAILURE,
-         _("Use --help to get a list of options.\n"));
-      return -1;
-    } /* end of parsing commandline */
-  } /* while (1) */
-  return OK;
-}
-
-static void * receiveThread(GNUNET_TCP_SOCKET * sock) {
-  void * buffer;
-
-  buffer = MALLOC(MAX_BUFFER_SIZE);
-  while (OK == readFromSocket(sock,
-                             (CS_MESSAGE_HEADER**)&buffer)) {
-    /* process */
-  }
-  FREE(buffer);
-  SEMAPHORE_UP(doneSem);
-  return NULL;
-}
-
-/**
- * @param argc number of arguments from the command line
- * @param argv command line arguments
- * @return return value from gnunet-template: 0: ok, -1: error
- */
-int main(int argc, char ** argv) {
-  GNUNET_TCP_SOCKET * sock;
-  PTHREAD_T messageReceiveThread;
-  void * unused;
-
-  if (SYSERR == initUtil(argc, argv, &parseOptions))
-    return 0; /* parse error, --help, etc. */
-  sock = getClientSocket();
-
-  if (0 != PTHREAD_CREATE(&messageReceiveThread,
-                         (PThreadMain) &receiveThread,
-                         sock,
-                         128 * 1024))
-    DIE_STRERROR("pthread_create");
-
-  /*
-  if (SYSERR == writeToSocket(sock,
-                              &msg.header))
-    return -1;
-  */
-  /* wait for shutdown... */
-
-  closeSocketTemporarily(sock);
-  SEMAPHORE_DOWN(doneSem);
-  SEMAPHORE_FREE(doneSem);
-  PTHREAD_JOIN(&messageReceiveThread, &unused);
-  releaseClientSocket(sock);
-
-  doneUtil();
-  return 0;
-}
-
-/* end of gnunet-template.c */

Copied: GNUnet/src/applications/vpn/gnunet-vpn.c (from rev 2822, 
GNUnet/src/applications/vpn/gnunet-template.c)
===================================================================
--- GNUnet/src/applications/vpn/gnunet-template.c       2006-05-14 22:31:33 UTC 
(rev 2822)
+++ GNUnet/src/applications/vpn/gnunet-vpn.c    2006-05-14 22:35:23 UTC (rev 
2823)
@@ -0,0 +1,153 @@
+/*
+     This file is part of GNUnet.
+     (C) 2001, 2002, 2004 Christian Grothoff (and other contributing authors)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 2, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file applications/vpn/gnunet-vpn.c
+ * @brief Utility to admin VPN
+ * @author Michael John Wensley
+ */
+
+#include "gnunet_util.h"
+#include "platform.h"
+
+#define TEMPLATE_VERSION "0.0.0"
+
+#define CS_PROTO_VPN_MSG 0xfa
+
+static Semaphore * doneSem;
+
+/**
+ * Parse the options, set the timeout.
+ * @param argc the number of options
+ * @param argv the option list (including keywords)
+ * @return OK on error, SYSERR if we should exit
+ */
+static int parseOptions(int argc,
+                       char ** argv) {
+  int option_index;
+  int c;
+
+  FREENONNULL(setConfigurationString("GNUNETD",
+                                    "LOGFILE",
+                                    NULL));
+  while (1) {
+    static struct GNoption long_options[] = {
+      LONG_DEFAULT_OPTIONS,
+      { 0,0,0,0 }
+    };
+    option_index=0;
+    c = GNgetopt_long(argc,
+                     argv,
+                     "vhdc:L:H:t",
+                     long_options,
+                     &option_index);
+    if (c == -1)
+      break;  /* No more flags to process */
+    if (YES == parseDefaultOptions(c, GNoptarg))
+      continue;
+    switch(c) {
+    case 'h': {
+      static Help help[] = {
+       HELP_CONFIG,
+       HELP_HELP,
+       HELP_LOGLEVEL,
+       { 't', "longoptionname", "ARGUMENT",
+         gettext_noop("helptext for -t") },
+       HELP_VERSION,
+       HELP_END,
+      };
+      formatHelp("gnunet-vpn [OPTIONS]",
+                _("VPN over GNUnet."),
+                help);
+
+      return SYSERR;
+    }
+    case 'v':
+      printf("GNUnet v%s, gnunet-vpn v%s\n",
+            VERSION,
+            TEMPLATE_VERSION);
+      return SYSERR;
+    default:
+      LOG(LOG_FAILURE,
+         _("Use --help to get a list of options.\n"));
+      return -1;
+    } /* end of parsing commandline */
+  } /* while (1) */
+  return OK;
+}
+
+static void * receiveThread(GNUNET_TCP_SOCKET * sock) {
+  int i;
+  CS_MESSAGE_HEADER *buffer;
+  buffer = MALLOC(MAX_BUFFER_SIZE);
+  while (OK == readFromSocket(sock, &buffer)) {
+       if (ntohs(buffer->type) == CS_PROTO_VPN_MSG) {
+               for (i = sizeof(CS_MESSAGE_HEADER); i < ntohs(buffer->size); 
i++) {
+                       putchar(*(((char*)buffer)+i));
+               }
+       }
+  }
+  FREE(buffer);
+  SEMAPHORE_UP(doneSem);
+  return NULL;
+}
+
+/**
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return return value from gnunet-template: 0: ok, -1: error
+ */
+int main(int argc, char ** argv) {
+  GNUNET_TCP_SOCKET * sock;
+  PTHREAD_T messageReceiveThread;
+  void * unused;
+  char buffer[sizeof(CS_MESSAGE_HEADER) + 1024];
+
+  doneSem = SEMAPHORE_NEW(0);
+  if (SYSERR == initUtil(argc, argv, &parseOptions))
+    return 0; /* parse error, --help, etc. */
+  sock = getClientSocket();
+
+  if (0 != PTHREAD_CREATE(&messageReceiveThread,
+                         (PThreadMain) &receiveThread,
+                         sock,
+                         128 * 1024)) DIE_STRERROR("pthread_create");
+
+
+  /* accept keystrokes from user and send to gnunetd */
+  ((CS_MESSAGE_HEADER*)&buffer)->type = htons(CS_PROTO_VPN_MSG);
+  printf("Welcome to the VPN console: (Ctrl-D to exit)\n");
+  while (1) {
+       if (NULL == fgets(&buffer[sizeof(CS_MESSAGE_HEADER)], 1024, stdin)) 
break;
+       ((CS_MESSAGE_HEADER*)&buffer)->size = htons(sizeof(CS_MESSAGE_HEADER) + 
strlen(&buffer[sizeof(CS_MESSAGE_HEADER)]));
+       if (SYSERR == writeToSocket(sock, (CS_MESSAGE_HEADER*)&buffer)) return 
-1;
+  }
+  /* wait for shutdown... */
+  closeSocketTemporarily(sock);
+  SEMAPHORE_DOWN(doneSem);
+  SEMAPHORE_FREE(doneSem);
+  PTHREAD_JOIN(&messageReceiveThread, &unused);
+  releaseClientSocket(sock);
+
+  doneUtil();
+  return 0;
+}
+
+/* end of gnunet-template.c */

Deleted: GNUnet/src/applications/vpn/template.c
===================================================================
--- GNUnet/src/applications/vpn/template.c      2006-05-14 22:31:33 UTC (rev 
2822)
+++ GNUnet/src/applications/vpn/template.c      2006-05-14 22:35:23 UTC (rev 
2823)
@@ -1,86 +0,0 @@
-/*
-     This file is part of GNUnet.
-     (C) 2001, 2002, 2004 Christian Grothoff (and other contributing authors)
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 2, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-     Boston, MA 02111-1307, USA.
-*/
-
-/**
- * @file applications/template/template.c
- * @author Christian Grothoff
- * @brief template for a GNUnet module
- */
-
-#include "platform.h"
-#include "gnunet_util.h"
-#include "gnunet_core.h"
-#include "gnunet_protocols.h"
-
-static CoreAPIForApplication * coreAPI = NULL;
-static ClientHandle client;
-static Mutex lock;
-
-static int handlep2pMSG(const PeerIdentity * sender,
-                       const P2P_MESSAGE_HEADER * message) {
-  return OK;
-}
-
-static int csHandle(ClientHandle client,
-                   const CS_MESSAGE_HEADER * message) {
-  return OK;
-}
-
-static void clientExitHandler(ClientHandle c) {
-  MUTEX_LOCK(&lock);
-  if (c == client)
-    client = NULL;
-  MUTEX_UNLOCK(&lock);
-}
-
-int initialize_module_template(CoreAPIForApplication * capi) {
-  int ok = OK;
-
-  MUTEX_CREATE(&lock);
-  client = NULL;
-  coreAPI = capi;
-
-  LOG(LOG_DEBUG,
-      _("`%s' registering client handler %d and %d\n"),
-      "template",
-      CS_PROTO_MAX_USED,
-      P2P_PROTO_MAX_USED);
-  if (SYSERR == capi->registerHandler(P2P_PROTO_MAX_USED,
-                                     &handlep2pMSG))
-    ok = SYSERR;
-  if (SYSERR == capi->registerClientExitHandler(&clientExitHandler))
-    ok = SYSERR;
-  if (SYSERR == capi->registerClientHandler(CS_PROTO_MAX_USED,
-                                           &csHandle))
-    ok = SYSERR;
-  return ok;
-}
-
-void done_module_template() {
-  coreAPI->unregisterHandler(P2P_PROTO_MAX_USED,
-                            &handlep2pMSG);
-  coreAPI->unregisterClientExitHandler(&clientExitHandler);
-  coreAPI->unregisterClientHandler(CS_PROTO_MAX_USED,
-                                  &csHandle);
-  MUTEX_DESTROY(&lock);
-  coreAPI = NULL;
-}
-
-/* end of template.c */

Copied: GNUnet/src/applications/vpn/vpn.c (from rev 2822, 
GNUnet/src/applications/vpn/template.c)
===================================================================
--- GNUnet/src/applications/vpn/template.c      2006-05-14 22:31:33 UTC (rev 
2822)
+++ GNUnet/src/applications/vpn/vpn.c   2006-05-14 22:35:23 UTC (rev 2823)
@@ -0,0 +1,1425 @@
+/*
+     This file is part of GNUnet.
+     (C) 2001, 2002, 2004 Christian Grothoff (and other contributing authors)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 2, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file applications/template/template.c
+ * @author Michael John Wensley
+ * @brief tunnel RFC 4193 in GNUnet
+ *
+ * 
+ * http://gnunet.wensley.org.uk/
+ *
+ * This isnt really going to be called template...
+ * It's just that renaming it means messing
+ * with that autotools thing all over again :-(
+ *
+ * Yes this will thoroughly break most of the coding guidelines :-/ at least 
the first release.
+ *
+ * test^h^h^h^hhack cycle goes like this, make; ./install; /etc/init.d/gnunet 
stop; /etc/init.d/gnunet start
+ *
+ * We use IPv6 addresses because they provide a larger space, and are
+ * not as likely to be in use by other applications such as NAT.
+ *
+ * we also follow the guidance in RFC4193 and use only the 40 bits specified
+ * for the randomly generated publickey. This allows nodes to
+ * connect subnets to the network.
+ *
+ * It also allows interoperation with other users of this
+ * space such as anonymous internets. We use GNUnet to benefit from
+ * its key infrastructure, though other users may well rip fdxx:: bits directly
+ * from public keys, using the private key to sign route announcements.
+ *
+ * CHANGELOG:
+ * 20060110 Change ifconfig/route to ioctl's
+ * 20060111 P2P packet includes length of the header.
+ */
+
+#include "platform.h"
+#include "gnunet_util.h"
+#include "gnunet_core.h"
+#include "gnunet_protocols.h"
+#include "gnunet_identity_service.h"
+
+/* i'm going to put platform dependent code here for now */
+#include <linux/if_tun.h>
+#include <linux/if_ether.h>
+
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+
+/* require struct in6_rtmsg */
+#include <net/route.h>
+
+/* This is derived from ifconfig source code... in6_ifreq needed from 
<linux/ipv6.h> */
+#include <asm/types.h>
+#ifndef _LINUX_IN6_H
+struct in6_ifreq {
+       struct in6_addr ifr6_addr;
+       __u32 ifr6_prefixlen;
+       unsigned int ifr6_ifindex;
+};
+#endif
+
+/* Would usually go in gnunet_protocols.h */
+#define P2P_PROTO_aip_IP 0xfd  /* contains IPv6 frame */
+#define P2P_PROTO_aip_ROUTE 0xf0 /* a route to a node */
+#define P2P_PROTO_aip_ROUTES 0xf1 /* no more routes in my table */
+#define P2P_PROTO_aip_GETROUTE 0xf2 /* request for a table entry from a peer */
+
+/* the idea is that you can use the first subnet number as a persistent 
identifier for your
+ * website, services etc, so numbering of virtual circuits to other nodes 
begins at 2.
+ * If you want to use more subnets locally, you can of course increase this 
number.
+ */
+#define VC_START 2
+
+#define CS_PROTO_VPN_MSG 0xfa
+
+#define MAXSIG_BUF 128
+
+/* Here we define the maximum size of any headers that go in front of IP 
packets
+ * it's the maximum of the GNUnet header and any platform headers, such as 
TUN/TAP's
+ * packet information header on Linux.
+ */
+#define maxi(a,b) ((a)>(b)?(a):(b))
+#define mini(a,b) ((a)<(b)?(a):(b))
+#define HEADER_FRAME maxi(sizeof(P2P_MESSAGE_HEADER), sizeof(struct tun_pi))
+
+/* we can't actually send messages this long... maybe 2 bytes shorter tho
+ * planned includes a way to send yet longer messages
+ */
+#define IP_FRAME 65536
+
+/**
+ * Identity service, to reset the core.
+ */
+static Identity_ServiceAPI * identity;
+
+static CoreAPIForApplication * coreAPI = NULL;
+
+static ClientHandle client;
+static int cdebug = 0;
+static int interval = 60;
+static Mutex lock;
+
+PTHREAD_T tunThreadInfo;
+
+static int delay_destroyed = -1;
+
+typedef struct {
+/*     char name[IFNAMSIZ]; */
+       int id;
+       int fd;
+       int active;
+       int route_entry;
+       int ifindex;
+       PeerIdentity peer;
+} tunnel_info;
+
+/* from bluetooth agent */
+static tunnel_info *store1 = NULL;
+static int entries1 = 0;
+static int capacity1 = 0;
+
+/**
+ * Pipe to communicate with select thread
+ * Used to tell it there is something to do...
+ */
+static int signalingPipe[2];
+
+/** is thread to stop? */
+static int running = 0;
+
+static int admin_fd;
+/** 
+ * Routing goes like this. Gather routes from all peers and put them in 
prototype store.
+ * Only store lowest hop count if get multiple of the same public key from the 
same peer.
+ *
+ * When this process is complete, sort (so that 0 hop comes first and put in 
complete list.
+ * complete list used to upload routing table to os.
+ *
+ * as the routes table can grow very large (need an entry for every reachable 
node in gnunet!) we can set a limit
+ * below (GNUNET_VIEW_LIMIT)
+ */
+
+/* This is an entry in the routing table */
+typedef struct {
+       /** owner's public key */
+       PublicKey owner;
+       /** hops to owner 1 = have a tunnel to owner, 0 = I am the owner.*/
+       int hops;
+       /** which tunnel entry in tunnels array */
+       int tunnel;
+} route_info;
+
+/* here we define a constant to limit the growth of your routing tables, and 
hence memory consumption
+ * of course, increasing this helps the network by providing more routes to 
nodes further away in the mesh,
+ * so long as it does not slow down your node significantly. :-)
+ * 100 * 30 peers * 1000 (typical size of public key) = 3 meg of ram.
+ * 100 * 30 = upto 3000 accessible peers. (reverse exponential will affect 
this though)
+ */
+#define GNUNET_VIEW_LIMIT 100
+
+/* same thing as route but without the tunnel info,
+ * which is implicit with the sender PeerIdentity anyway.
+ *
+ * also the fields here are network byte order.
+ */
+typedef struct {
+       PublicKey owner;
+       int hops;
+} transit_route;
+       
+static route_info *route_store = NULL;
+static int route_entries = 0;
+static int route_capacity = 0;
+
+static route_info *realised_store = NULL;
+static int realised_entries = 0;
+static int realised_capacity = 0;
+
+/** send given string to client */
+static void cprintf(ClientHandle c, const char* format, ...) {
+       va_list args;
+       int r = -1;
+       int size = 100;
+       CS_MESSAGE_HEADER *b = NULL, *nb = NULL;
+
+       if ((b = MALLOC(sizeof(CS_MESSAGE_HEADER)+size)) == NULL) {
+               return;
+       }
+       while (1) {
+               va_start(args, format);
+               r = VSNPRINTF((char*)(b+1), size, format, args);
+               va_end(args);
+               if (r > -1 && r < size)
+                       break;
+               if (r > -1) {
+                       size = r + 1;
+               } else {
+                       size *= 2;
+               }
+               if ((nb = REALLOC(b, sizeof(CS_MESSAGE_HEADER) + size)) == 
NULL) {
+                       FREE(b);
+                       return;
+               } else {
+                       b = nb;
+               }
+       }
+       b->type=htons(CS_PROTO_VPN_MSG);
+       b->size=htons(sizeof(CS_MESSAGE_HEADER) + strlen((char*)(b+1)));
+       coreAPI->sendToClient(c, b);
+       FREE(b);
+}
+#define VLOG if ((cdebug >= LOG_DEBUG) && (client != NULL)) cprintf(client,
+
+/** Test if two PublicKey are equal or not */
+static int isEqualP(const PublicKey *first, const PublicKey *second) {
+       int i;
+       int ln = maxi(first->sizen, second->sizen);
+       int sn = mini(first->sizen, second->sizen);
+       
+       /* compare common mode modulus */
+       if (memcmp( (first->key)+((first->sizen)-sn), 
(second->key)+((second->sizen)-sn), sn) != 0)
+               return NO;
+
+       /* difference before n should be 0 */
+       for(i = 0; i < (first->sizen)-sn; i++) {
+               if (*(first->key+i) != 0)
+                       return NO;
+       }
+       for(i = 0; i < (second->sizen)-sn; i++) {
+               if (*(second->key+i) != 0)
+                       return NO;
+       }
+
+       /* compare common mode exponent */
+       if (memcmp( (first->key)+ln, (second->key)+ln, RSA_KEY_LEN-ln) != 0)
+               return NO;
+
+       for(i = first->sizen; i < ln; i++) {
+               if (*(first->key+i) != 0)
+                       return NO;
+       }
+       for(i = second->sizen; i < ln; i++) {
+               if (*(second->key+i) != 0)
+                       return NO;
+       }
+
+       return YES;
+}
+
+/** 
+ * clear out the prototype routes table
+ * called at start or when we know a peer changes its route table.
+ */
+static void init_router() {
+       int reqcapacity;
+       route_info *reqstore;   
+       reqcapacity = sizeof(route_info);
+       if (reqcapacity > route_capacity) {
+               reqstore = REALLOC(route_store, reqcapacity);
+               if (reqstore == NULL) return; /* not enough ram, cannot init! */
+               route_store = reqstore;
+               route_capacity = reqcapacity;
+       }
+       route_entries = 1;
+       route_store->hops = 0; /* us! */
+       route_store->tunnel = -1; /* n/a! */
+       route_store->owner = *(identity->getPublicPrivateKey()); /* us! */
+}
+
+/** 
+ * clear out the actual route at startup only
+ */
+static void init_realised() {
+       int reqcapacity;
+       route_info *reqstore;   
+       reqcapacity = sizeof(route_info);
+       if (reqcapacity > realised_capacity) {
+               reqstore = REALLOC(realised_store, reqcapacity);
+               if (reqstore == NULL) return; /* not enough ram, cannot init! */
+               realised_store = reqstore;
+               realised_capacity = reqcapacity;
+       }
+       realised_entries = 1;
+       realised_store->hops = 0; /* us! */
+       realised_store->tunnel = -1; /* n/a! */
+       realised_store->owner = *(identity->getPublicPrivateKey()); /* us! */
+}
+
+/* adds a route to prototype route table, unless it has same PublicKey and 
tunnel as another entry */
+static void add_route(PublicKey* them, int hops, int tunnel) {
+       int i;
+       route_info *rstore;
+       int rcapacity;  
+
+       for (i = 0; i < route_entries; i++) {
+               if (isEqualP(them, &(route_store+i)->owner)) {
+                       if ((route_store+i)->hops == 0) {
+                               /* we don't store alternative routes to 
ourselves,
+                                * as we already know how to route to ourself
+                                */
+                               VLOG _("Not storing route to myself from peer 
%d\n"), tunnel);
+                               return;
+                       }
+                       if ((route_store+i)->tunnel == tunnel) {
+                               /* also, we only keep one route to a node per 
peer,
+                                * but store the lowest hop count that the peer 
is advertising for that node.
+                                */
+                               (route_store+i)->hops = 
mini((route_store+i)->hops, hops);
+                               VLOG _("Duplicate route to node from peer %d, 
choosing minimum hops"), tunnel);
+                               return;
+                       }
+               }
+       }
+
+       route_entries++;
+        rcapacity = route_entries * sizeof(route_info);
+        if (rcapacity > route_capacity) {
+                       rstore = REALLOC(route_store, rcapacity);
+                       if (rstore == NULL) { 
+                       route_entries--;
+                       return; /* not enough ram, we will have to drop this 
route. */
+               }
+                       route_capacity = rcapacity;
+                       route_store = rstore;
+       }
+       /* 
+        * we really should keep the route table in ascending hop count order...
+        */
+       if (route_entries > 0) {
+               i = route_entries - 1; /* i = insert location */
+               while ((i > 0) && ((route_store+(i-1))->hops > hops)) {
+                       (route_store+i)->hops = (route_store+(i-1))->hops;
+                       (route_store+i)->tunnel = (route_store+(i-1))->hops;
+                       (route_store+i)->owner = (route_store+(i-1))->owner;
+                       i--;
+               }
+               VLOG _("Inserting route from peer %d in route table at location 
%d\n"), tunnel, i);
+               (route_store+i)->hops = hops;
+               (route_store+i)->tunnel = tunnel;
+               (route_store+i)->owner = *them;
+       }
+}
+
+/**
+ * Render IPv4 or IPv6 packet info for logging.
+ */
+static void ipinfo(char *info, const struct ip6_hdr* fp) {
+        struct in_addr fr4;
+        struct in_addr to4;
+
+       if ((((const struct iphdr*)fp)->version == 4)) {
+               fr4.s_addr = ((const struct iphdr*)fp)->saddr;
+               to4.s_addr = ((const struct iphdr*)fp)->daddr;
+               sprintf(info, "IPv4 %s -> ", inet_ntoa(fr4));
+               strcat(info, inet_ntoa(to4));
+               return;
+       }
+       if ((((const struct iphdr*)fp)->version == 6)) {
+               sprintf(info, "IPv6 %x:%x:%x:%x:%x:%x:%x:%x -> 
%x:%x:%x:%x:%x:%x:%x:%x",
+                       ntohs(fp->ip6_src.s6_addr16[0]),
+                       ntohs(fp->ip6_src.s6_addr16[1]),
+                       ntohs(fp->ip6_src.s6_addr16[2]),
+                       ntohs(fp->ip6_src.s6_addr16[3]),
+                       ntohs(fp->ip6_src.s6_addr16[4]),
+                       ntohs(fp->ip6_src.s6_addr16[5]),
+                       ntohs(fp->ip6_src.s6_addr16[6]),
+                       ntohs(fp->ip6_src.s6_addr16[7]),
+                       ntohs(fp->ip6_dst.s6_addr16[0]),
+                       ntohs(fp->ip6_dst.s6_addr16[1]),
+                       ntohs(fp->ip6_dst.s6_addr16[2]),
+                       ntohs(fp->ip6_dst.s6_addr16[3]),
+                       ntohs(fp->ip6_dst.s6_addr16[4]),
+                       ntohs(fp->ip6_dst.s6_addr16[5]),
+                       ntohs(fp->ip6_dst.s6_addr16[6]),
+                       ntohs(fp->ip6_dst.s6_addr16[7])
+               );
+               return;
+       }
+       sprintf(info, "IPv%d ?", ((const struct iphdr*)fp)->version);
+}
+
+/** check that ethertype matches ip version for incoming packets from linux 
specific code */
+static int valid_incoming(int len, struct tun_pi* tp, struct ip6_hdr* fp) {
+       char info[100];
+       if (len > (65535 - sizeof(struct tun_pi))) {
+               LOG(LOG_ERROR, _("RFC4193 Frame length %d is too big for 
GNUnet!\n"), len);
+               return NO;
+       }
+       if (len < sizeof(struct tun_pi)) {
+               LOG(LOG_ERROR, _("RFC4193 Frame length %d too small\n"), len);
+               return NO;
+       }
+       if ((ntohs(tp->proto) == ETH_P_IP) && (((struct iphdr*)fp)->version == 
4)) {
+               return YES;
+       } else if ((ntohs(tp->proto) == ETH_P_IPV6) && (((struct 
iphdr*)fp)->version == 6)) {
+               ipinfo(info, fp);
+               VLOG "-> GNUnet(%d) : %s\n", len - sizeof(struct tun_pi), info);
+               return YES;
+       }
+       LOG(LOG_ERROR, _("RFC4193 Ethertype %x and IP version %x do not 
match!\n"),
+               ntohs(tp->proto), ((struct iphdr*)fp)->version);
+       return NO;
+}
+
+/** Test if two PeerIdentity are equal or not */
+static int isEqual(const PeerIdentity *first, const PeerIdentity *second) {
+       int i;
+       for (i = 0; i < 512/8/sizeof(unsigned int); i++) {
+               if (first->hashPubKey.bits[i] != second->hashPubKey.bits[i]) {
+                       return 0;
+               }
+       }
+       return -1;
+}
+
+/**
+ * Convert a PeerIdentify into a "random" RFC4193 prefix
+ * actually we make the first 40 bits of the hash into the prefix!
+ */
+static void id2ip(ClientHandle cx, const PeerIdentity* them) {
+       unsigned char a,b,c,d,e;
+       a = (them->hashPubKey.bits[0] >> 8) & 0xff;
+       b = (them->hashPubKey.bits[0] >> 0) & 0xff;
+       c = (them->hashPubKey.bits[1] >> 8) & 0xff;
+       d = (them->hashPubKey.bits[1] >> 0) & 0xff;
+       e = (them->hashPubKey.bits[2] >> 8) & 0xff;
+       cprintf(cx, "fd%02x:%02x%02x:%02x%02x",a,b,c,d,e);
+}
+/* convert PeerIdentity into network octet order IPv6 address */
+static void id2net(struct in6_addr* buf, const PeerIdentity* them) {
+       unsigned char a,b,c,d,e;
+       a = (them->hashPubKey.bits[0] >> 8) & 0xff;
+       b = (them->hashPubKey.bits[0] >> 0) & 0xff;
+       c = (them->hashPubKey.bits[1] >> 8) & 0xff;
+       d = (them->hashPubKey.bits[1] >> 0) & 0xff;
+       e = (them->hashPubKey.bits[2] >> 8) & 0xff;
+
+       /* we are unique random */
+       buf->s6_addr16[0] = htons(0xfd00  + a);
+       buf->s6_addr16[1] = htons(b * 256 + c);
+       buf->s6_addr16[2] = htons(d * 256 + e);
+       
+       /* IPv6 /48 subnet number is zero */
+       buf->s6_addr16[3] = 0;
+
+       /* IPV6 /64 interface is zero */
+       buf->s6_addr16[4] = 0;
+       buf->s6_addr16[5] = 0;
+       buf->s6_addr16[6] = 0;
+       buf->s6_addr16[7] = 0;
+}
+
+static void setup_tunnel(int n, const PeerIdentity *them) {
+       struct ifreq ifr;
+       struct in6_ifreq ifr6;
+       struct in6_rtmsg rt;
+       int i, used, fd, id = 0;
+
+
+       LOG(LOG_DEBUG, _("RFC4193 Going to try and make a tunnel in slot 
%d\n"), n);
+
+       fd = open("/dev/net/tun", O_RDWR);
+       if (fd < 0) {
+               LOG(LOG_ERROR, _("Cannot open tunnel device because of %s"), 
strerror(fd));
+               DIE_STRERROR("open");
+       }
+       memset(&ifr, 0, sizeof(ifr));
+
+       /* IFF_TUN = IP Packets
+        * IFF_TAP = Ethernet packets
+        *
+        * IFF_NO_PI = Do not provide packet information
+        */
+
+       /* we know its going to be ipv6 cause the version tells us.
+        * except that linux *assumes* it will be sent IPv4 frames 
+        * unless we configure IFF_PI.... hmmmm.... :-/
+        * lets see the tun linux module source
+        *
+        * this needs PI as type = htons(0x86DD)
+        * ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
+        * We do need PI otherwise TUNTAP assumes it is receiving IPv4...
+        */
+       ifr.ifr_flags = IFF_TUN;
+
+       /* try various names until we find a free one */
+       do {
+               used = 0;
+               for (i = 0; i < entries1; i++) {
+                       if ((store1+i)->id == id) { 
+                               LOG(LOG_DEBUG, _("RFC4193 Create skips gnu%d as 
we are already using it\n"), id);
+                               id++;
+                               used = 1;
+                       }
+               }
+               if (used == 0) {
+                       sprintf(ifr.ifr_name, "gnu%d", id);
+                       if ( ioctl(fd, TUNSETIFF, (void *) &ifr) < 0) {
+                               LOG(LOG_ERROR, _("Cannot set tunnel name to %s 
because of %s\n"), ifr.ifr_name, strerror(errno));
+                               id++;
+                               used = 1;
+                       } else {
+                               LOG(LOG_ERROR, _("Configured tunnel name to 
%s\n"), ifr.ifr_name);
+                       }
+               }
+       } while (used);
+
+
+       ioctl(fd, TUNSETNOCSUM, 1);
+       memcpy(&((store1+n)->peer), them, sizeof(PeerIdentity));
+       (store1+n)->id = id;
+       (store1+n)->fd = fd;
+       (store1+n)->active = NO;
+       (store1+n)->route_entry = 0;
+
+       /* tun_alloc can change the tunnel name */
+       /* strncpy((store1+n)->name, ifr.ifr_name,IFNAMSIZ); */
+
+       /* here we should give the tunnel an IPv6 address and fake up a route 
to the other end
+        * the format looks like this, and the net/host split is fixed at /48 
as in rfc4193
+        * local /64
+        *      net: my PeerIdentity
+        *      subnet: interface number+2
+        *      interface: NULL
+        *
+        * remote /48
+        *      net: their PeerIdentity
+        *      host: NULL (it's not needed for routes)
+        */
+
+       /* Run some system commands to set it up... */
+/*     sprintf(cmd, "sudo ifconfig %s up", name);
+ *     LOG(LOG_DEBUG, _("RFC4193 Calling %s\n"), cmd);
+ *     system(cmd);
+ */
+
+       /* Bring interface up, like system("sudo ifconfig %s up"); */
+       
+       /* not needed, we already have the iface name ... strncpy(ifr.ifr_name, 
name, IFNAMSIZ); */
+       if (ioctl(admin_fd, SIOCGIFFLAGS, &ifr) < 0) {
+               LOG(LOG_ERROR, _("Cannot get socket flags for gnu%d because 
%s\n"), id, strerror(errno));
+       } else {
+               ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
+               if (ioctl(admin_fd, SIOCSIFFLAGS, &ifr) < 0) {
+                       LOG(LOG_ERROR, _("Cannot set socket flags for gnu%d 
because %s\n"), id, strerror(errno));
+               }
+       }
+       
+       /* Seems to go better with lower mtu, aka system("sudo ifconfig %s mtu 
1280") */
+       ifr.ifr_mtu = 1280;
+       if (ioctl(admin_fd, SIOCSIFMTU, &ifr) < 0) {
+               LOG(LOG_ERROR, _("Cannot set MTU for gnu%d because %s\n"), id, 
strerror(errno));
+       }
+
+       /* lets add an IP address... aka "sudo ifconfig %s add %s:%04x::1/64" */
+       if (ioctl(admin_fd, SIOCGIFINDEX, &ifr) < 0) {
+               LOG(LOG_ERROR, _("Cannot get interface index for gnu%d because 
%s\n"), id, strerror(errno));
+       } else {
+               /* note to self... htons(64) = kernel oops. */
+               (store1+n)->ifindex = ifr.ifr_ifindex;
+               ifr6.ifr6_prefixlen = 64;
+               ifr6.ifr6_ifindex = ifr.ifr_ifindex;
+               id2net(&ifr6.ifr6_addr, coreAPI->myIdentity);
+               ifr6.ifr6_addr.s6_addr16[3] = htons(n+VC_START);
+               LOG(LOG_DEBUG, _("IPv6 ifaddr gnu%d - 
%x:%x:%x:%x:%x:%x:%x:%x/%d\n"),
+                       id,
+                       ntohs(ifr6.ifr6_addr.s6_addr16[0]),
+                       ntohs(ifr6.ifr6_addr.s6_addr16[1]),
+                       ntohs(ifr6.ifr6_addr.s6_addr16[2]),
+                       ntohs(ifr6.ifr6_addr.s6_addr16[3]),
+                       ntohs(ifr6.ifr6_addr.s6_addr16[4]),
+                       ntohs(ifr6.ifr6_addr.s6_addr16[5]),
+                       ntohs(ifr6.ifr6_addr.s6_addr16[6]),
+                       ntohs(ifr6.ifr6_addr.s6_addr16[7]),
+                       ifr6.ifr6_prefixlen);
+               if (ioctl(admin_fd, SIOCSIFADDR, &ifr6) < 0) {
+                       LOG(LOG_ERROR, _("Cannot set interface IPv6 address for 
gnu%d because %s\n"), id, strerror(errno));
+               }
+               
+               /* lets add a route to the peer, aka "sudo route -A inet6 add 
%s::/48 dev %s" */
+               memset((char*)&rt, 0, sizeof(struct in6_rtmsg));
+               /* rtmsg_ifindex would be zero for routes not specifying a 
device, such as by gateway */
+               rt.rtmsg_ifindex = ifr.ifr_ifindex;
+               id2net(&rt.rtmsg_dst, them);
+               rt.rtmsg_flags = RTF_UP;
+               rt.rtmsg_metric = 1;   /* how many hops to owner of public key 
*/
+               rt.rtmsg_dst_len = 48; /* network prefix len is 48 by standard 
*/
+               LOG(LOG_DEBUG, _("IPv6 route gnu%d - destination 
%x:%x:%x:%x:%x:%x:%x:%x/%d\n"),
+                       id,
+                       ntohs(rt.rtmsg_dst.s6_addr16[0]),
+                       ntohs(rt.rtmsg_dst.s6_addr16[1]),
+                       ntohs(rt.rtmsg_dst.s6_addr16[2]),
+                       ntohs(rt.rtmsg_dst.s6_addr16[3]),
+                       ntohs(rt.rtmsg_dst.s6_addr16[4]),
+                       ntohs(rt.rtmsg_dst.s6_addr16[5]),
+                       ntohs(rt.rtmsg_dst.s6_addr16[6]),
+                       ntohs(rt.rtmsg_dst.s6_addr16[7]),
+                       rt.rtmsg_dst_len);
+               if (ioctl(admin_fd, SIOCADDRT, &rt) < 0) {
+                       LOG(LOG_ERROR, _("Cannot add route IPv6 address for 
gnu%s because %s\n"), id, strerror(errno));
+               }
+       }
+}
+
+/**
+ * See if we already got a TUN/TAP open for the given GNUnet peer. if not, 
make one, stick 
+ * PeerIdentity and the filehandle and name of the TUN/TAP in an array so we 
remember we did it. 
+ */
+static void checkensure_peer(const PeerIdentity *them, void *callerinfo) {
+       int i;
+       tunnel_info* rstore1;
+       int rcapacity1;
+
+       /* LOG(LOG_DEBUG, _("RFC4193 Going to checkensure peer %x then\n"), 
them->hashPubKey.bits[0]); */
+       /* first entry in array will be known as gnu0 */
+
+       /* if a tunnel is already setup, we don't setup another */
+       for (i = 0; i < entries1; i++) {
+               if (isEqual(them, &((store1+i)->peer))) {
+                       return;
+               }
+       }
+
+       /*
+        * append it at the end.
+        */
+       entries1++;
+       rcapacity1 = entries1 * sizeof(tunnel_info);
+       if (rcapacity1 > capacity1) {
+               rstore1 = REALLOC(store1, rcapacity1);
+               if (rstore1 == NULL) {
+                       LOG(LOG_ERROR, _("RFC4193 We have run out of memory and 
so I can't store a tunnel for this peer.\n"));
+                       entries1--;
+                       return;
+               }
+               store1 = rstore1;
+               capacity1 = rcapacity1;
+       }
+
+       /* LOG(LOG_DEBUG, _("RFC4193 Extending array for new tunnel\n")); */
+       setup_tunnel((entries1 - 1), them);
+}
+
+/* make new thread...
+ * repeat {
+ *     call forAllConnectedNodes, create/destroy tunnels to match connected 
peers, 1 per peer.
+ *     Give new tunnels their IPv6 addresses like "ifconfig gnu0 add 
fdXX:XXXX:XXXX::/48"
+ *     SELECT for incoming packets, unicast those thru gnunet, or (pipe 
activity = exit this thread) or timeout.
+ * }
+ * own IPv6 addr is fdXX:XXXX:XXXX::P/48 where X= 40 bits own key, P = gnu0 + 2
+ * route add -net fdXX(remote key) dev gnu0 is then used.
+ */
+static void * tunThread(void* arg) {
+       fd_set readSet;
+       fd_set errorSet;
+       fd_set writeSet;
+       int i, ret, max;
+       char tmp[MAXSIG_BUF];
+       struct stat statinfo;
+
+       /**
+        * IP frames are preceeded by the TUN/TAP header (for Linux) or by the 
GNUnet header
+        * other systems like HURD, etc may use different headers
+        */
+       char frame[IP_FRAME + HEADER_FRAME];
+       struct ip6_hdr* fp;
+       struct tun_pi* tp;
+       P2P_MESSAGE_HEADER* gp;
+       struct timeval timeout;
+
+       /* need the cast otherwise it increments by HEADER_FRAME * 
sizeof(frame) rather than HEADER_FRAME */
+       fp = (struct ip6_hdr*)(((char*)&frame) + HEADER_FRAME);
+
+       /* this trick decrements the pointer by the sizes of the respective 
structs */
+       tp = ((struct tun_pi*)fp)-1;
+       gp = ((P2P_MESSAGE_HEADER*)fp)-1;
+       running = 1;
+       LOG(LOG_DEBUG, _("RFC4193 Thread running (frame %d tunnel %d f2f %d) 
...\n"), fp, tp, gp);
+
+       MUTEX_LOCK(&lock);
+       while (running) {
+
+               FD_ZERO(&readSet);
+               FD_ZERO(&errorSet);
+               FD_ZERO(&writeSet);
+
+               max = signalingPipe[0];
+
+               if (-1 != FSTAT(signalingPipe[0], &statinfo)) {
+                       FD_SET(signalingPipe[0], &readSet);
+               } else {
+                       DIE_STRERROR("fstat");
+               }
+               for (i = 0; i < entries1; i++) {
+                       FD_SET(((store1+i)->fd), &readSet);
+                       max = maxi(max,(store1+i)->fd);
+               }
+               MUTEX_UNLOCK(&lock);
+               timeout.tv_sec = interval;
+               timeout.tv_usec = 0;
+
+               ret = SELECT(max+1,
+                       &readSet,
+                       &writeSet,
+                       &errorSet,
+                       &timeout);
+               if (ret < 0) {
+                       running = 0;
+                       break;
+               }
+               if (FD_ISSET(signalingPipe[0], &readSet)) {
+                       if (0 >= READ(signalingPipe[0],
+                       &tmp[0],
+                       MAXSIG_BUF))
+                       LOG_STRERROR(LOG_WARNING, "read");
+               }
+               MUTEX_LOCK(&lock);
+               for (i = 0; i < entries1; i++) {
+                       if (FD_ISSET(((store1+i)->fd), &readSet)) {
+                               ret = read(((store1+i)->fd), tp, IP_FRAME);
+
+                               /* goodbye IPv6 packet, enjoy the GNUnet... :-)
+                                * IP is of course very important so it will 
enjoy
+                                * the very highest priority
+                                */
+                               if (valid_incoming(ret, tp, fp)) {
+                                       gp->type = htons(P2P_PROTO_aip_IP);
+                                       gp->size = 
htons(sizeof(P2P_MESSAGE_HEADER) + ret - sizeof(struct tun_pi));
+                                       
coreAPI->unicast(&((store1+i)->peer),gp,EXTREME_PRIORITY,1);
+                                       
coreAPI->preferTrafficFrom(&((store1+i)->peer),1000);
+                               }
+                       }
+               }
+               if (timeout.tv_sec < (interval / 2)) {
+//                     for (i = 0; i < entries1; i++) (store1+i)->connected = 
NO;
+//                     coreAPI->forAllConnectedNodes(&checkensure_peer, NULL);
+                       for (i = 0; i < entries1; i++) {
+                               if (((store1+i)->active) > 0) {
+                                       if 
(identity->isBlacklistedStrict(&((store1+i)->peer))) {
+                                               LOG(LOG_INFO, _("RFC4193 --- 
whitelist of peer %x\n"),
+                                                       
(store1+i)->peer.hashPubKey.bits[0]);
+                                               
identity->whitelistHost(&((store1+i)->peer));
+                                       }
+                               }
+                               /* This prevents our list of peers becoming too 
big....
+                                * they have never used VPN, and they have 
disconnected...
+                                */
+/*                             if (((store1+i)->active) == 0) {
+ *                                     LOG(LOG_INFO, _("RFC4193 --- dropping 
connection %x\n"), i);
+ *                                     close( (store1+i)->fd );
+ *                                     *(store1+i) = *(store1+(entries1-1));
+ *                                     entries1--;
+ *                             }
+ */
+                       }
+               }
+       }
+       LOG(LOG_DEBUG, _("RFC4193 Thread exiting\n"));
+       MUTEX_UNLOCK(&lock);
+       return NULL;
+}
+
+/**
+ * Pass IP packet to tap. Which tap depends on what the PeerIdentity is.
+ * If we've not seen the peer before, create a new TAP and tell our thread 
about it?
+ * else scan the array of TAPS and copy the message into it.
+ *
+ * Mainly this routine exchanges the P2P_MESSAGE_HEADER on incoming ipv6 
packets
+ * for a TUN/TAP header for writing it to TUNTAP.
+ */
+static int handlep2pMSG(const PeerIdentity * sender, const P2P_MESSAGE_HEADER 
* gp) {
+       int i = 0, fd;
+       char loginfo[100];
+
+       P2P_MESSAGE_HEADER * rgp = NULL;
+       char frame[IP_FRAME + sizeof(struct tun_pi)];
+        const struct ip6_hdr* fp = (struct ip6_hdr*)(gp+1);
+        struct ip6_hdr* new_fp = (struct ip6_hdr*)(((char*)&frame) + 
sizeof(struct tun_pi));
+        struct tun_pi* tp = (struct tun_pi*)(&frame);
+
+       switch (ntohs(gp->type)) {
+       case P2P_PROTO_aip_IP:
+               tp->flags = 0;
+
+               /* better check src/dst IP for anonymity preservation 
requirements here...
+                * I.e. in fd::/8 and check next header as well.
+                *
+                * Also permit multicast [ RFC 3306 ] 
ff3x:0030:fdnn:nnnn:nnnn::/96
+                * where x = diameter. n are the random bits from the 
allocater's IP
+                * (and must match the sender's )
+                * 30 = usual bit length of a sender's node/network-prefix,
+                * we allow longer, and that must match sender if specified.
+                */
+               switch (((struct iphdr*)fp)->version) {
+                       case 6:
+                               tp->proto = htons(ETH_P_IPV6);
+                               if ( ntohs(fp->ip6_src.s6_addr16[0]) < 0xFD00 ) 
{
+                                       LOG(LOG_DEBUG, _("VPN IP src not 
anonymous. drop..\n"));
+                                       return OK;
+                               }
+                               if ( ntohs(fp->ip6_dst.s6_addr16[0]) < 0xFD00 ) 
{
+                                       LOG(LOG_DEBUG, _("VPN IP not anonymous, 
drop.\n"));
+                                       return OK;
+                               }
+                               break;
+                       case 4:
+                               tp->proto = htons(ETH_P_IP);
+                               LOG(LOG_DEBUG, _("VPN Received, not anonymous, 
drop.\n"));
+                               return OK;
+                       default: 
+                               LOG(LOG_ERROR, _("VPN Received unknown IP 
version %d...\n"), ((struct iphdr*)fp)->version);
+                               return OK;
+               }
+
+               ipinfo(loginfo, fp);
+
+               /* do packet memcpy outside of mutex for speed */
+               memcpy(new_fp, fp, ntohs(gp->size)-sizeof(P2P_MESSAGE_HEADER));
+
+               MUTEX_LOCK(&lock);
+               VLOG _("<- GNUnet(%d) : %s\n"), ntohs(gp->size) - 
sizeof(P2P_MESSAGE_HEADER), loginfo);
+               for (i = 0; i < entries1; i++) {
+                       if (isEqual(sender, &((store1+i)->peer))) {
+                               fd = ((store1+i)->fd);
+       
+                               (store1+i)->active = YES;
+
+                               /* We are only allowed one call to write() per 
packet.
+                                * We need to write packet and packetinfo 
together in one go.
+                                */
+                               write(fd, tp, ntohs(gp->size) + sizeof(struct 
tun_pi) - sizeof(P2P_MESSAGE_HEADER));
+                               
coreAPI->preferTrafficFrom(&((store1+i)->peer),1000);
+                               MUTEX_UNLOCK(&lock);
+                               return OK;
+                       }
+               }
+               /* do not normally get here... but checkensure so any future 
packets could be routed... */
+               checkensure_peer(sender, NULL);
+               MUTEX_UNLOCK(&lock);
+               LOG(LOG_DEBUG, _("Could not write the tunnelled IP to the OS... 
Did to setup a tunnel?\n"));
+               return OK;
+       case p2p_PROTO_PONG:
+               MUTEX_LOCK(&lock);
+               checkensure_peer(sender, NULL);
+               MUTEX_UNLOCK(&lock);
+               return OK;
+       case P2P_PROTO_hangup:
+               /*
+                * Remove node's entry in access table if it did not VPN.
+                */
+               MUTEX_LOCK(&lock);
+               for (i = 0; i < entries1; i++) {
+                       if ((((store1+i)->fd) > 0) && isEqual(sender, 
&((store1+i)->peer))) {
+                               if (((store1+i)->active) == 0) {
+                                       LOG(LOG_INFO, _("RFC4193 -- non-vpn 
node hangs up. close down gnu%d (%d in %d)\n"),
+                                               (store1+i)->id,  i, entries1);
+
+                                       close( (store1+i)->fd );
+                                       delay_destroyed = (store1+i)->id;
+
+                                       *(store1+i) = *(store1+(entries1-1));
+                                       entries1--;
+                               }
+
+                       }
+               }
+               MUTEX_UNLOCK(&lock);
+               return OK;
+       case P2P_PROTO_aip_GETROUTE:
+               /** peer wants an entry from our routing table */
+               VLOG _("Receive route request\n"));
+               if (ntohs(gp->size) == (sizeof(P2P_MESSAGE_HEADER) + 
sizeof(int))) {
+                       i = ntohl(*((int*)fp));
+                       MUTEX_LOCK(&lock);
+                       if (i < realised_entries) {
+                               VLOG _("Prepare route announcement level 
%d\n"), i);
+                               rgp = MALLOC(sizeof(P2P_MESSAGE_HEADER) + 
sizeof(transit_route));
+                               if (rgp == NULL) {
+                                       MUTEX_UNLOCK(&lock);
+                                       return OK;
+                               }
+                               rgp->size = htons(sizeof(P2P_MESSAGE_HEADER) + 
sizeof(transit_route));
+                               rgp->type = htons(P2P_PROTO_aip_ROUTE);
+                               ((transit_route*)(rgp+1))->owner = 
(realised_store+i)->owner;
+                               ((transit_route*)(rgp+1))->hops = 
htonl((realised_store+i)->hops);
+                               MUTEX_UNLOCK(&lock);
+                               VLOG _("Send route announcement %d with route 
announce\n"), i);
+                               /* it must be delivered if possible, but it can 
wait longer than IP */
+                               coreAPI->unicast(sender, rgp, EXTREME_PRIORITY, 
15);
+                               FREE(rgp);
+                               return OK;
+                       }
+                       VLOG _("Send outside table info %d\n"), i);
+                       rgp = MALLOC(sizeof(P2P_MESSAGE_HEADER) + sizeof(int));
+                       if (rgp == NULL) {
+                               MUTEX_UNLOCK(&lock);
+                               return OK;
+                       }
+                       rgp->size = htons(sizeof(P2P_MESSAGE_HEADER) + 
sizeof(int));
+                       rgp->type = htons(P2P_PROTO_aip_ROUTES);
+                       *((int*)(rgp+1)) = htonl(realised_entries);
+                       MUTEX_UNLOCK(&lock);
+                       coreAPI->unicast(sender, rgp, EXTREME_PRIORITY, 15);
+                       FREE(rgp);
+                       return OK;
+               }
+               return OK;
+       case P2P_PROTO_aip_ROUTE:
+               VLOG _("Receive route announce.\n"));
+               /** peer sent us a route, insert it into routing table, then 
req next entry */
+               if (ntohs(gp->size) == (sizeof(P2P_MESSAGE_HEADER) + 
sizeof(transit_route))) {
+                       MUTEX_LOCK(&lock);
+                       VLOG _("Going to try insert route into local 
table.\n"));
+                       for (i = 0; i < entries1; i++) {
+                               if (isEqual(sender, &((store1+i)->peer))) {
+                                       (store1+i)->active = YES;
+                                       VLOG _("Inserting with hops %d\n"), 
ntohl( ((transit_route*)(gp+1))->hops));
+                                       add_route(      &( 
((transit_route*)(gp+1))->owner ), 
+                                                       1 + ntohl( 
((transit_route*)(gp+1))->hops),
+                                                       i);
+                                       if ((store1+i)->route_entry < 
GNUNET_VIEW_LIMIT) {
+                                               (store1+i)->route_entry++;
+                                               rgp = 
MALLOC(sizeof(P2P_MESSAGE_HEADER) + sizeof(int));
+                                               if (rgp == NULL) {
+                                                       MUTEX_UNLOCK(&lock);
+                                                       return OK;
+                                               }
+                                               rgp->type = 
htons(P2P_PROTO_aip_GETROUTE);
+                                               rgp->size = 
htons(sizeof(P2P_MESSAGE_HEADER) + sizeof(int));
+                                               *((int*)(rgp+1)) = 
htonl((store1+i)->route_entry);
+                                               VLOG _("Request level %d from 
peer %d\n"), (store1+i)->route_entry, i);
+                                               
coreAPI->unicast(&((store1+i)->peer),rgp,EXTREME_PRIORITY,60);
+                                               FREE(rgp);
+                                       }
+                                       break;
+                               }
+                       }
+                       MUTEX_UNLOCK(&lock);
+               }
+               return OK;
+       case P2P_PROTO_aip_ROUTES:
+               if (ntohs(gp->size) == (sizeof(P2P_MESSAGE_HEADER) + 
sizeof(int))) {
+                       /* if this is the last route message, we do route 
realisation
+                        * that is, insert the routes into the operating system.
+                        */
+                       VLOG _("Receive table limit on peer reached %d\n"), 
ntohl( *((int*)fp)) );
+/*                     MUTEX_LOCK(&lock);
+                       for (i = 0; i < entries1; i++) {
+                               if (isEqual(sender, &((store1+i)->peer))) {
+                                       VLOG _("Storing table limit %d for peer 
%d\n"), ntohl( *((int*)fp)), i );
+                                       (store1+i)->route_limit = ntohl( 
*((int*)fp));
+                                       break;
+                               }
+                       }
+                       MUTEX_UNLOCK(&lock);
+*/             }
+               return OK;
+       }
+       return OK;
+}
+
+/** compare msg from client with given string */
+static int iscmd(const int len, const char* ccmd, const char* cmd) {
+       if (len != strlen(cmd)) return NO;
+       if (strncmp(ccmd, cmd, len)) return NO;
+       return YES;
+}
+
+/* here we copy the prototype route table we are collecting from peers to the 
actual
+ * "realised" route table we distribute to peers, and to the kernel's table.
+ */
+static void realise(ClientHandle c) {
+       int i, j, found;
+       PeerIdentity id;
+       int reqcapacity;
+       route_info *reqstore;
+       struct in6_rtmsg rt;
+
+       cprintf(c, "Realisation in progress\n");
+       cprintf(c, "-----------------\n");
+       cprintf(c, "\n");
+        MUTEX_LOCK(&lock);
+       /* make sure realised table can take the new routes - if it wont, abort 
now! */
+       LOG(LOG_DEBUG, _("realise alloc ram\n"));
+       if (route_entries > realised_entries) {
+               reqcapacity = sizeof(route_info) * route_entries;
+               if (reqcapacity > realised_capacity) {
+                       reqstore = REALLOC(realised_store, reqcapacity);
+                       if (reqstore == NULL) {
+                               cprintf(c, "I cannot up the ram for realised 
routes.\n");
+                               MUTEX_UNLOCK(&lock);
+                               return;
+                       }
+                       realised_store = reqstore;
+                       realised_capacity = reqcapacity;
+               }
+       }
+       /* add routes that are in the new table but not the old */
+       LOG(LOG_DEBUG, _("realise add routes\n"));
+       for (i = 0; i < route_entries; i++) {
+               found = 0;
+               for (j = 0; j < realised_entries; j++) {
+                       /* compare public key */
+                       if 
(isEqualP(&(route_store+i)->owner,&(realised_store+j)->owner) &&
+                               ((route_store+i)->hops == 
(realised_store+j)->hops) &&
+                               ((route_store+i)->tunnel == 
(realised_store+j)->tunnel)
+                       ) {
+                               found = 1;
+                       }
+               }
+               /* we are hops == 0
+                * hops == 1 auto added by tunneler
+                * hops >= 2 added here!
+                */
+               if (!(found) && ((route_store+i)->hops > 1)) {
+                       /* lets add a route to this long remote node */
+                       memset((char*)&rt, 0, sizeof(struct in6_rtmsg));
+                       /* rtmsg_ifindex would be zero for routes not 
specifying a device, such as by gateway */
+                       rt.rtmsg_ifindex = 
(store1+((route_store+i)->tunnel))->ifindex;
+                       identity->getPeerIdentity(&(route_store+i)->owner, &id);
+                       id2net(&rt.rtmsg_dst, &id);
+                       rt.rtmsg_flags = RTF_UP;
+                       rt.rtmsg_metric = (route_store+i)->hops;
+                       /* how many hops to owner of public key */
+                       rt.rtmsg_dst_len = 48; /* always 48 as per RFC4193 */
+                       cprintf(c, "Add route gnu%d hops %d dst 
%x:%x:%x:%x:%x:%x:%x:%x/%d\n",
+                               id,
+                               rt.rtmsg_metric,
+                               ntohs(rt.rtmsg_dst.s6_addr16[0]),
+                               ntohs(rt.rtmsg_dst.s6_addr16[1]),
+                               ntohs(rt.rtmsg_dst.s6_addr16[2]),
+                               ntohs(rt.rtmsg_dst.s6_addr16[3]),
+                               ntohs(rt.rtmsg_dst.s6_addr16[4]),
+                               ntohs(rt.rtmsg_dst.s6_addr16[5]),
+                               ntohs(rt.rtmsg_dst.s6_addr16[6]),
+                               ntohs(rt.rtmsg_dst.s6_addr16[7]),
+                               rt.rtmsg_dst_len);
+                       if (ioctl(admin_fd, SIOCADDRT, &rt) < 0) {
+                               cprintf(c,"Cannot add route IPv6 address for 
gnu%s because %s\n", id, strerror(errno));
+                       }
+               }
+       }
+       cprintf(c, "Removing routes\n");
+       LOG(LOG_DEBUG, _("realise pull routes\n"));
+       /* pull routes that are in the old table but not the new */
+       for (i = 0; i < realised_entries; i++) {
+               found = 0;
+               for (j = 0; j < route_entries; j++) {
+                       /* compare public key */
+                       if 
(isEqualP(&(realised_store+i)->owner,&(route_store+j)->owner) &&
+                               ((realised_store+i)->hops == 
(route_store+j)->hops) &&
+                               ((realised_store+i)->tunnel == 
(route_store+j)->tunnel)
+                       ) {
+                               found = 1;
+                       }
+               }
+               /* we are hops == 0
+                * hops == 1 auto added by tunneler
+                * hops >= 2 added here!
+                */
+               if (!(found) && ((realised_store+i)->hops > 1)) {
+                       /* remove the route to this long remote node */
+                       memset((char*)&rt, 0, sizeof(struct in6_rtmsg));
+                       /* rtmsg_ifindex would be zero for routes not 
specifying a device, such as by gateway */
+                       rt.rtmsg_ifindex = 
(store1+((realised_store+i)->tunnel))->ifindex;
+                       identity->getPeerIdentity(&(realised_store+i)->owner, 
&id);
+                       id2net(&rt.rtmsg_dst, &id);
+                       rt.rtmsg_flags = RTF_UP;
+                       rt.rtmsg_metric = (realised_store+i)->hops;
+                       /* how many hops to owner of public key */
+                       rt.rtmsg_dst_len = 48; /* always 48 as per RFC4193 */
+                       cprintf(c, "Delete route gnu%d hops %d dst 
%x:%x:%x:%x:%x:%x:%x:%x/%d\n",
+                               id,
+                               rt.rtmsg_metric,
+                               ntohs(rt.rtmsg_dst.s6_addr16[0]),
+                               ntohs(rt.rtmsg_dst.s6_addr16[1]),
+                               ntohs(rt.rtmsg_dst.s6_addr16[2]),
+                               ntohs(rt.rtmsg_dst.s6_addr16[3]),
+                               ntohs(rt.rtmsg_dst.s6_addr16[4]),
+                               ntohs(rt.rtmsg_dst.s6_addr16[5]),
+                               ntohs(rt.rtmsg_dst.s6_addr16[6]),
+                               ntohs(rt.rtmsg_dst.s6_addr16[7]),
+                               rt.rtmsg_dst_len);
+                       if (ioctl(admin_fd, SIOCDELRT, &rt) < 0) {
+                               cprintf(c,"Cannot del route IPv6 address for 
gnu%s because %s\n", id, strerror(errno));
+                       }
+               }
+       }
+       cprintf(c, "Copying table\n");
+       LOG(LOG_DEBUG, _("realise copy table\n"));
+       realised_entries = route_entries;
+       memcpy(realised_store,route_store, sizeof(route_info) * route_entries);
+
+       MUTEX_UNLOCK(&lock);
+}
+
+/** The console client is used to admin/debug vpn */
+static int csHandle(ClientHandle c, const CS_MESSAGE_HEADER * message) {
+       P2P_MESSAGE_HEADER * rgp = NULL;
+       int i;
+       PeerIdentity id;
+       int cl = 1; 
+       int cll = ntohs(message->size) - sizeof(CS_MESSAGE_HEADER);
+       char* ccmd = (char*)(message+1);
+       char* parm;
+
+       MUTEX_LOCK(&lock);
+               client = c;
+       MUTEX_UNLOCK(&lock);
+       /* issued command from client */
+       if (ntohs(message->type) == CS_PROTO_VPN_MSG) {
+               if (ntohs(message->size) == 0) return OK;
+               while ((cl < cll) && (*(ccmd+cl) > 32)) cl++;
+
+               if (iscmd(cl,ccmd,"help")) {
+                       cprintf(c, "\
+Welcome to the GNUnet VPN debugging interface.\n\
+Written by Michael John Wensley\n\
+commands include: help, debug0, debug1, tunnel, route, reset\r\n\
+");
+                       return OK;
+               }
+               if (iscmd(cl,ccmd,"debug0")) {
+                       MUTEX_LOCK(&lock);
+                               cdebug = LOG_NOTHING;
+                       MUTEX_UNLOCK(&lock);
+                       cprintf(c, "LOG NOTHING\n");
+                       return OK;
+               }
+               if (iscmd(cl,ccmd,"debug1")) {
+                       MUTEX_LOCK(&lock);
+                               cdebug = LOG_DEBUG;
+                       MUTEX_UNLOCK(&lock);
+                       cprintf(c, "LOG DEBUG\n");
+                       return OK;
+               }
+               if (iscmd(cl,ccmd,"tunnel")) {
+                       cprintf(c, "Tunnel Information\n");
+                       cprintf(c, "------------------\n");
+                       cprintf(c, "\n");
+                       MUTEX_LOCK(&lock);
+                       id2ip(c, coreAPI->myIdentity);
+                       cprintf(c, "::/48 This Node\n");
+                       for (i = 0; i < entries1; i++) {
+                               id2ip(c, &(store1+i)->peer);
+                               cprintf(c, "::/48 gnu%d active=%s 
routeentry=%d\n", (store1+i)->id, 
+                                               (store1+i)->active ? _("Yes") : 
_("No"), 
+                                               (store1+i)->route_entry);
+                       }
+                       MUTEX_UNLOCK(&lock);
+               }
+               if (iscmd(cl,ccmd,"route")) {
+                       cprintf(c, "Route Information\n");
+                       cprintf(c, "-----------------\n");
+                        cprintf(c, "\n");
+                        MUTEX_LOCK(&lock);
+                       for (i = 0; i < route_entries; i++) {
+                               
identity->getPeerIdentity(&(route_store+i)->owner, &id);
+                               id2ip(c, &id);
+                               if ((route_store+i)->hops == 0) {
+                                       cprintf(c, "::/48 hops 0 (This 
Node)\n");
+                               } else {
+                                       cprintf(c, "::/48 hops %d tunnel 
gnu%d\n", (route_store+i)->hops,
+                                               
(store1+((route_store+i)->tunnel))->id);
+                               }
+                       }
+                       MUTEX_UNLOCK(&lock);
+               }
+               if (iscmd(cl,ccmd,"realised")) {
+                       cprintf(c, "Realised Route Information\n");
+                       cprintf(c, "-----------------\n");
+                        cprintf(c, "\n");
+                        MUTEX_LOCK(&lock);
+                       for (i = 0; i < realised_entries; i++) {
+                               
identity->getPeerIdentity(&(realised_store+i)->owner, &id);
+                               id2ip(c, &id);
+                               if ((realised_store+i)->hops == 0) {
+                                       cprintf(c, "::/48 hops 0 (This 
Node)\n");
+                               } else {
+                                       cprintf(c, "::/48 hops %d tunnel 
gnu%d\n", (realised_store+i)->hops,
+                                               
(store1+((realised_store+i)->tunnel))->id);
+                               }
+                       }
+                       MUTEX_UNLOCK(&lock);
+               }
+               /* add routes in route but not realised to OS
+                * delete routes in realised but not route from OS
+                * memcpy routes to realised metric
+                */
+               if (iscmd(cl,ccmd,"realise")) {
+                       realise(c);
+               }
+               if (iscmd(cl,ccmd,"reset")) {
+                       cprintf(c, "Rebuilding routing tables\n");
+                        cprintf(c, "\n");
+                        MUTEX_LOCK(&lock);
+                       init_router();
+                       for (i = 0; i < entries1; i++) {
+                               (store1+i)->route_entry = 0;
+                               /* lets send it to everyone - expect response 
only from VPN enabled nodes tho :-) */
+/*                             if ((store1+i)->active == YES) { */
+                                       rgp = MALLOC(sizeof(P2P_MESSAGE_HEADER) 
+ sizeof(int));
+                                       if (rgp == NULL) { break; }
+                                       rgp->type = 
htons(P2P_PROTO_aip_GETROUTE);
+                                       rgp->size = 
htons(sizeof(P2P_MESSAGE_HEADER) + sizeof(int));
+                                       *((int*)(rgp+1)) = 
htonl((store1+i)->route_entry);
+                                       cprintf(c, "Request level %d from peer 
%d ", (store1+i)->route_entry, i);
+                                       id2ip(c, &((store1+i)->peer));
+                                       cprintf(c, "\n");
+                                       
coreAPI->unicast(&((store1+i)->peer),rgp,EXTREME_PRIORITY,60);
+                                       FREE(rgp);
+/*                             }       */
+                       }
+                       MUTEX_UNLOCK(&lock);
+                       cprintf(c, "Rebuilding routing tables done\n");
+                        cprintf(c, "\n");
+               }
+               /* not really used any more */
+               if (iscmd(cl,ccmd,"fast")) {
+                       cprintf(c, "Going faster for you.\n");
+                        cprintf(c, "\n");
+                        MUTEX_LOCK(&lock);
+                       interval = 2;
+                       MUTEX_UNLOCK(&lock);
+               }
+               if (iscmd(cl,ccmd,"trust")) {
+                       cprintf(c, "Give credit to active nodes...\n");
+                       MUTEX_LOCK(&lock);
+                       for (i = 0; i < entries1; i++) {
+                               if ((store1+i)->active == YES) {
+                                       cprintf(c, "Uprating peer ");
+                                       id2ip(c, &(store1+i)->peer);
+                                       cprintf(c, " with credit %d\n", 
identity->changeHostTrust(&(store1+i)->peer, 1000));
+                               }
+                       }
+                       MUTEX_UNLOCK(&lock);
+               }
+               /* user wants add a peer - actually this does not work very 
well */
+               if (iscmd(cl,ccmd,"add")) {
+                       if ((cll - cl) > 1) {
+                               if ((parm = MALLOC(cll - cl)) != NULL) {
+                                       strncpy(parm, ccmd+(cl+1), cll-cl-1);
+                                       *(parm+(cll-cl)) = 0;
+                                       cprintf(c, "Connect %s for ", parm);
+                                       if (OK == enc2hash(parm, 
&(id.hashPubKey))) {
+                                               id2ip(c, &id);
+
+                                               /* this does not seem to work, 
strangeness with threads and capabilities?
+                                                * MUTEX_LOCK(&lock);
+                                                * checkensure_peer(&id, NULL);
+                                                * MUTEX_UNLOCK(&lock);
+                                                */
+
+                                               /* get it off the local 
blacklist */
+                                               identity->whitelistHost(&id);
+
+                                               /* req route level 0 */
+                                               rgp = 
MALLOC(sizeof(P2P_MESSAGE_HEADER) + sizeof(int));
+                                               if (rgp != NULL) { 
+                                                       rgp->type = 
htons(P2P_PROTO_aip_GETROUTE);
+                                                       rgp->size = 
htons(sizeof(P2P_MESSAGE_HEADER) + sizeof(int));
+                                                       *((int*)(rgp+1)) = 0;
+                                                       
coreAPI->unicast(&id,rgp,EXTREME_PRIORITY,4);
+                                                       cprintf(c, " Sent");
+                                                       FREE(rgp);
+                                               }
+
+                                               cprintf(c, "\n");
+                                               FREE(parm);
+                                       } else {
+                                               cprintf(c, "Could not decode 
PeerId from parameter.\n");
+                                       }
+                               } else {
+                                       cprintf(c, "Could not allocate for 
key.\n");
+                               }
+                       } else {
+                               cprintf(c, "Require key for parameter\n");
+                       }
+               }
+       }
+       return OK;
+}
+
+static void clientExitHandler(ClientHandle c) {
+       MUTEX_LOCK(&lock);
+       if (c == client)
+               client = NULL;
+       MUTEX_UNLOCK(&lock);
+}
+
+/**
+ * Module inserted... create thread to listen to TUNTAP and pass
+ * these messages on to GNUnet.
+ *
+ * Also enumerate all current peers and create taps for them.
+ *
+ */
+int initialize_module_vpn(CoreAPIForApplication * capi) {
+       MUTEX_CREATE(&lock);
+
+       /** client to write debug msg to */
+       client = NULL;
+       coreAPI = capi;
+
+       /* Give GNUnet permission to administrate net interfaces itself. Needs 
access in /etc/sudoers
+        */
+       system("sudo setpcaps cap_net_admin+eip `pidof gnunetd`");
+       admin_fd = socket(AF_INET6, SOCK_DGRAM, 0);
+       
+       LOG(LOG_DEBUG, _("`%s' initialising RFC4913 module  %d and %d\n"), 
"template", CS_PROTO_MAX_USED, P2P_PROTO_MAX_USED);
+       LOG(LOG_DEBUG, _("RFC4193 my First 4 hex digits of host id are %x\n"), 
capi->myIdentity->hashPubKey.bits[0]);
+
+       /* core calls us to receive messages */
+       /* get a PONG = peer is online */
+       /* get a HANGUP = peer is offline */
+       if (SYSERR == capi->registerHandler(P2P_PROTO_aip_IP, &handlep2pMSG)) 
return SYSERR;
+       if (SYSERR == capi->registerHandler(P2P_PROTO_aip_GETROUTE, 
&handlep2pMSG)) return SYSERR;
+       if (SYSERR == capi->registerHandler(P2P_PROTO_aip_ROUTE, 
&handlep2pMSG)) return SYSERR;
+       if (SYSERR == capi->registerHandler(P2P_PROTO_aip_ROUTES, 
&handlep2pMSG)) return SYSERR;
+       if (SYSERR == capi->registerHandler(p2p_PROTO_PONG, &handlep2pMSG)) 
return SYSERR;
+       if (SYSERR == capi->registerHandler(P2P_PROTO_hangup, &handlep2pMSG)) 
return SYSERR;
+       if (SYSERR == capi->registerClientExitHandler(&clientExitHandler)) 
return SYSERR;
+       if (SYSERR == capi->registerClientHandler(CS_PROTO_VPN_MSG, &csHandle)) 
return SYSERR;
+
+       identity = coreAPI->requestService("identity");
+
+       GNUNET_ASSERT(identity != NULL);
+
+       init_router();  /* reqire identity */
+       init_realised();        /* reqire identity */
+
+       PIPE(signalingPipe);
+       /* important: make signalingPipe non-blocking
+               to avoid stalling on signaling! */
+       setBlocking(signalingPipe[1], NO);
+
+       /* Yes we have to make our own thread, cause the GUNnet API is
+        * missing some callbacks (Namely CanReadThisFd - SELECT()) that I 
would like ;-(
+        * They may go in the thread that usually monitors the GUI port.
+        */
+       PTHREAD_CREATE(&tunThreadInfo, (PThreadMain) &tunThread, NULL, 128 * 
1024);
+
+       /* use capi->unicast to send messages to connected peers */
+
+       setConfigurationString("ABOUT",
+                         "template",
+                         _("enables IPv6 over GNUnet (incomplete)"));
+
+       return OK;
+}
+
+/**
+ * Module uninserted.
+ */
+void done_module_vpn() {
+       int i;
+       int ret;
+       void *returnval;
+
+       coreAPI->unregisterHandler(P2P_PROTO_aip_IP, &handlep2pMSG);
+       coreAPI->unregisterHandler(P2P_PROTO_aip_GETROUTE, &handlep2pMSG);
+       coreAPI->unregisterHandler(P2P_PROTO_aip_ROUTE, &handlep2pMSG);
+       coreAPI->unregisterHandler(P2P_PROTO_aip_ROUTES, &handlep2pMSG);
+       coreAPI->unregisterHandler(p2p_PROTO_PONG, &handlep2pMSG);
+       coreAPI->unregisterHandler(P2P_PROTO_hangup, &handlep2pMSG);
+       coreAPI->unregisterClientHandler(CS_PROTO_VPN_MSG, &csHandle);
+       coreAPI->unregisterClientExitHandler(&clientExitHandler);
+
+       LOG(LOG_INFO, _("RFC4193 Waiting for tun thread to end\n"));
+
+       running = 0;
+       /* thread should wake up and exit */
+       ret = write(signalingPipe[1], &running, sizeof(char));
+       if (ret != sizeof(char))
+               if (errno != EAGAIN)
+                       LOG_STRERROR(LOG_ERROR, "RFC4193 cant tell thread to 
exit");
+
+       /* wait for it to exit */
+       PTHREAD_JOIN(&tunThreadInfo, &returnval);
+       LOG(LOG_INFO, _("RFC4193 The tun thread has ended\n"));
+
+       coreAPI->releaseService(identity);
+       identity = NULL;
+
+       closefile(signalingPipe[0]);
+       closefile(signalingPipe[1]);
+
+       /* bye bye TUNTAP ... */
+       for (i = 0; i < entries1; i++) {
+               if (((store1+i)->fd) != 0) {
+                       LOG(LOG_DEBUG, _("RFC4193 Closing tunnel %d fd %d\n"), 
i, (store1+i)->fd);
+                       close((store1+i)->fd);
+                       (store1+i)->fd = 0;
+               }
+       }
+       if (store1 != NULL) {
+               entries1 = 0;
+               capacity1 = 0;
+               FREE(store1);
+       }
+       close(admin_fd);
+
+       MUTEX_DESTROY(&lock);
+       coreAPI = NULL;
+}
+
+/* end of template.c */





reply via email to

[Prev in Thread] Current Thread [Next in Thread]