]> git.meshlink.io Git - meshlink/commitdiff
Big bad commit:
authorGuus Sliepen <guus@tinc-vpn.org>
Sat, 27 Oct 2001 12:13:17 +0000 (12:13 +0000)
committerGuus Sliepen <guus@tinc-vpn.org>
Sat, 27 Oct 2001 12:13:17 +0000 (12:13 +0000)
- Transition to new node/vertex/connection structures
- Use new configuration handling everywhere
- Linux tun/tap device handling cleanup
- Start of IPv6 support in route.c

It compiles, but it won't link.

23 files changed:
src/conf.c
src/conf.h
src/connection.c
src/connection.h
src/device.h
src/linux/device.c
src/meta.c
src/net.c
src/net.h
src/netutl.c
src/netutl.h
src/node.c
src/node.h
src/process.c
src/protocol.c
src/protocol.h
src/route.c
src/route.h
src/subnet.c
src/subnet.h
src/tincd.c
src/vertex.c
src/vertex.h

index 1ac01c31b4e5727609f7bc71f501115c4384da79..bd546c6bd4fc2e1da26c8aebe537f99d5f327c9c 100644 (file)
@@ -19,7 +19,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: conf.c,v 1.9.4.44 2001/10/10 20:34:27 guus Exp $
+    $Id: conf.c,v 1.9.4.45 2001/10/27 12:13:17 guus Exp $
 */
 
 #include "config.h"
@@ -220,6 +220,59 @@ cp
   return 0;
 }
 
+int get_config_port(config_t *cfg, port_t *result)
+{
+cp
+  if(!cfg)
+    return 0;
+
+  if(sscanf(cfg->value, "%hu", result) == 1)
+    return 1;
+    
+  syslog(LOG_ERR, _("Port number expected for configuration variable %s in %s line %d"),
+         cfg->value, cfg->file, cfg->line);
+  return 0;
+}
+
+int get_config_subnet(config_t *cfg, subnet_t **result)
+{
+  ip_mask_t *ip;
+  subnet_t *subnet;
+cp
+  if(!cfg)
+    return 0;
+
+  ip = strtoip(cfg->value);
+
+  if(!ip)
+    {
+      syslog(LOG_ERR, _("IP address expected for configuration variable %s in %s line %d"),
+             cfg->value, cfg->file, cfg->line);
+      return 0;
+    }
+  
+  /* Teach newbies what subnets are... */
+
+  if((subnet->net.ipv4.address & subnet->net.ipv4.mask) != subnet->net.ipv4.address)
+    {
+      syslog(LOG_ERR, _("Network address and subnet mask for configuration variable %s in %s line %d"),
+             cfg->value, cfg->file, cfg->line);
+      free(ip);
+      return -1;
+    }
+
+  subnet = new_subnet();
+  subnet->type = SUBNET_IPV4;
+  subnet->net.ipv4.address = ip->address;
+  subnet->net.ipv4.mask = ip->mask;
+  
+  free(ip);
+
+  *result = subnet;
+  
+  return 1;
+}
+
 /*
   Read exactly one line and strip the trailing newline if any.  If the
   file was on EOF, return NULL. Otherwise, return all the data in a
index ca32a4893b4e91ff24cd51fc10c3cedaca067081..9136efa7b9cb7d0e2e323922f2aacb7c7982bacb 100644 (file)
@@ -17,7 +17,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: conf.h,v 1.6.4.27 2001/10/10 20:34:27 guus Exp $
+    $Id: conf.h,v 1.6.4.28 2001/10/27 12:13:17 guus Exp $
 */
 
 #ifndef __TINC_CONF_H__
@@ -25,6 +25,7 @@
 
 #include <avl_tree.h>
 #include "net.h"
+#include "subnet.h"
 
 typedef struct config_t {
   char *variable;
@@ -47,12 +48,15 @@ extern void exit_configuration(avl_tree_t **);
 extern config_t *new_config(void);
 extern void free_config(config_t *);
 extern void config_add(avl_tree_t *, config_t *);
-extern config_t *config_lookup(avl_tree_t *, char *);
-extern config_t *config_lookup_next(avl_tree_t *, config_t *);
+extern config_t *lookup_config(avl_tree_t *, char *);
+extern config_t *lookup_config_next(avl_tree_t *, config_t *);
 extern int get_config_bool(config_t *, int *);
 extern int get_config_int(config_t *, int *);
+extern int get_config_port(config_t *, port_t *);
 extern int get_config_string(config_t *, char **);
-extern int get_config_ip(config_t *, ip_mask_t **);
+extern int get_config_ip(config_t *, struct ip_mask_t **);
+struct subnet_t; /* Needed for next line. */
+extern int get_config_subnet(config_t *, struct subnet_t **);
 
 extern int read_config_file(avl_tree_t *, const char *);
 extern int read_server_config(void);
index d606e9c3a1c0c3cc2591bc01a7e624f0cb7f3ee4..a86faa9c6d5aeef9f779d96e3af6c3d6105eaf7d 100644 (file)
@@ -17,7 +17,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: connection.c,v 1.1.2.19 2001/10/10 20:35:10 guus Exp $
+    $Id: connection.c,v 1.1.2.20 2001/10/27 12:13:17 guus Exp $
 */
 
 #include "config.h"
@@ -71,8 +71,6 @@ void free_connection(connection_t *c)
 cp
   if(c->hostname)
     free(c->hostname);
-  if(c->rsa_key)
-    RSA_free(c->rsa_key);
   if(c->inkey)
     free(c->inkey);
   if(c->outkey)
@@ -120,10 +118,22 @@ cp
     {
       c = (connection_t *)node->data;
       syslog(LOG_DEBUG, _(" %s at %s port %hd options %ld socket %d status %04x"),
-             c->node->name, c->hostname, c->port, c->options,
+             c->name, c->hostname, c->port, c->options,
              c->socket, c->status);
     }
     
   syslog(LOG_DEBUG, _("End of connections."));
 cp
 }
+
+int read_connection_config(connection_t *c)
+{
+  char *fname;
+  int x;
+cp
+  asprintf(&fname, "%s/hosts/%s", confbase, c->name);
+  x = read_config_file(c->config_tree, fname);
+  free(fname);
+cp
+  return x;
+}
index 9a35461f7b4434e8c51703ec6c7db32d88a4da1b..b32e329cdb80560a96eaa33f888b58cd8d62074b 100644 (file)
@@ -17,7 +17,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: connection.h,v 1.1.2.16 2001/10/10 20:35:10 guus Exp $
+    $Id: connection.h,v 1.1.2.17 2001/10/27 12:13:17 guus Exp $
 */
 
 #ifndef __TINC_CONNECTION_H__
@@ -26,8 +26,6 @@
 #include <avl_tree.h>
 #include <list.h>
 
-#include "config.h"
-
 #ifdef HAVE_OPENSSL_EVP_H
 # include <openssl/evp.h>
 #else
 #include "node.h"
 #include "vertex.h"
 
-typedef struct status_bits_t {
+#define OPTION_INDIRECT                0x0001
+#define OPTION_TCPONLY         0x0002
+
+typedef struct connection_status_t {
   int pinged:1;                    /* sent ping */
-  int meta:1;                      /* meta connection exists */
   int active:1;                    /* 1 if active.. */
   int outgoing:1;                  /* I myself asked for this conn */
   int termreq:1;                   /* the termination of this connection was requested */
   int remove:1;                    /* Set to 1 if you want this connection removed */
   int timeout:1;                   /* 1 if gotten timeout */
-  int validkey:1;                  /* 1 if we currently have a valid key for him */
-  int waitingforkey:1;             /* 1 if we already sent out a request */
-  int dataopen:1;                  /* 1 if we have a valid UDP connection open */
   int encryptout:1;               /* 1 if we can encrypt outgoing traffic */
   int decryptin:1;                 /* 1 if we have to decrypt incoming traffic */
   int unused:18;
-} status_bits_t;
-
-#define OPTION_INDIRECT                0x0001
-#define OPTION_TCPONLY         0x0002
+} connection_status_t;
 
 typedef struct connection_t {
+  char *name;                      /* name he claims to have */
+
   ipv4_t address;                  /* his real (internet) ip */
   short unsigned int port;         /* port number of meta connection */
   char *hostname;                  /* the hostname of its real ip */
@@ -73,7 +69,7 @@ typedef struct connection_t {
 
   int socket;                      /* socket used for this connection */
   long int options;                /* options for this connection */
-  status_bits_t status;            /* status info */
+  struct connection_status_t status; /* status info */
 
   struct node_t *node;             /* node associated with the other end */
   struct vertex_t *vertex;         /* vertex associated with this connection */
@@ -96,8 +92,20 @@ typedef struct connection_t {
   int allow_request;               /* defined if there's only one request possible */
 
   time_t last_ping_time;           /* last time we saw some activity from the other end */
+
+  avl_tree_t *config_tree;         /* Pointer to configuration tree belonging to him */
 } connection_t;
 
 extern avl_tree_t *connection_tree;
 
+extern void init_connections(void);
+extern void exit_connection(void);
+extern connection_t *new_connection(void);
+extern void free_connection(connection_t *);
+extern void connection_add(connection_t *);
+extern void connection_del(connection_t *);
+extern connection_t *lookup_connection(ipv4_t, short unsigned int);
+extern void dump_connections(void);
+extern int read_connection_config(connection_t *);
+
 #endif /* __TINC_CONNECTION_H__ */
index a8b65ccbf3786fcad5c936844916fd3944326c81..dded47adb45cb1aadbdcd623b10fa381ad5b3f8f 100644 (file)
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: device.h,v 1.1.2.1 2001/10/12 15:16:03 guus Exp $
+    $Id: device.h,v 1.1.2.2 2001/10/27 12:13:17 guus Exp $
 */
 
 #ifndef __TINC_DEVICE_H__
 #define __TINC_DEVICE_H__
 
-extern void setup_device(void);
+extern int device_fd;
+
+extern int setup_device(void);
 extern void close_device(void);
 extern vpn_packet_t *read_packet(void);
-extern void write_packet(vpn_packet_t *);
+extern int write_packet(vpn_packet_t *);
 extern void dump_device_stats(void);
 
-#endif __TINC_DEVICE_H__
+#endif /* __TINC_DEVICE_H__ */
index a3bc2bb39a91ec92e3d0b2c3494c990e035584b7..c82a820e1779625c72fbe29c8f0a7b82ea840c33 100644 (file)
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: device.c,v 1.1.2.1 2001/10/12 15:16:03 guus Exp $
+    $Id: device.c,v 1.1.2.2 2001/10/27 12:13:17 guus Exp $
 */
 
+#include "config.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
 #ifdef HAVE_TUNTAP
  #ifdef LINUX_IF_TUN_H
   #include LINUX_IF_TUN_H
  #define DEFAULT_DEVICE "/dev/tap0"
 #endif
 
+#include <utils.h>
+#include "conf.h"
+#include "net.h"
+#include "subnet.h"
+
+#include "system.h"
+
 #define DEVICE_TYPE_ETHERTAP 0
 #define DEVICE_TYPE_TUNTAP 1
 
@@ -42,6 +61,8 @@ char *device_info;
 int device_total_in = 0;
 int device_total_out = 0;
 
+subnet_t mymac;
+
 /*
   open the local ethertap device
 */
@@ -50,7 +71,7 @@ int setup_device(void)
   struct ifreq ifr;
 
 cp
-  if(!get_config_string(lookup_config(config_tree, "Device"), &device_fname)))
+  if(!get_config_string(lookup_config(config_tree, "Device"), &device_fname))
     device_fname = DEFAULT_DEVICE;
 
 cp
@@ -60,8 +81,6 @@ cp
       return -1;
     }
 cp
-  device_fd = device_fd;
-
   /* Set default MAC address for ethertap devices */
 
   mymac.type = SUBNET_MAC;
@@ -90,14 +109,14 @@ cp
     if (!ioctl(device_fd, (('T'<< 8) | 202), (void *) &ifr))
     {
       syslog(LOG_WARNING, _("Old ioctl() request was needed for %s"), device_fname);
-      device_type = TAP_TYPE_TUNTAP;
+      device_type = DEVICE_TYPE_TUNTAP;
       device_info = _("Linux tun/tap device");
     }
     else
 #endif
     {
       device_info = _("Linux ethertap device");
-      device_type = TAP_TYPE_ETHERTAP;
+      device_type = DEVICE_TYPE_ETHERTAP;
     }
 
   syslog(LOG_INFO, _("%s is a %s"), device_fname, device_info);
@@ -125,7 +144,7 @@ cp
     }
   else /* ethertap */
     {
-      struct iovec vector[2] = {{packet->len, 2}, {packet->data, MTU}};
+      struct iovec vector[2] = {{&packet->len, 2}, {packet->data, MTU}};
 
       if((lenin = readv(device_fd, vector, 2)) <= 0)
         {
@@ -135,13 +154,12 @@ cp
 
       packet->len = lenin - 2;
     }
-#endif
 
   device_total_in += packet->len;
 
   if(debug_lvl >= DEBUG_TRAFFIC)
     {
-      syslog(LOG_DEBUG, _("Read packet of %d bytes from %s"), device_info, packet.len);
+      syslog(LOG_DEBUG, _("Read packet of %d bytes from %s"), packet->len, device_info);
     }
 
   return 0;
@@ -159,21 +177,22 @@ cp
     {
       if(write(device_fd, packet->data, packet->len) < 0)
         {
-          syslog(LOG_ERR, _("Can't write to %s %s: %m"), device_info, packet.len);
+          syslog(LOG_ERR, _("Can't write to %s %s: %m"), device_info, device_fname);
           return -1;
         }
     }
   else/* ethertap */
     {
-      struct iovec vector[2] = {{packet->len, 2}, {packet->data, MTU}};
+      struct iovec vector[2] = {{&packet->len, 2}, {packet->data, MTU}};
 
       if(writev(device_fd, vector, 2) < 0)
         {
-          syslog(LOG_ERR, _("Can't write to %s %s: %m"), device_info, packet.len);
+          syslog(LOG_ERR, _("Can't write to %s %s: %m"), device_info, device_fname);
           return -1;
         }
     }
 
   device_total_out += packet->len;
 cp
+  return 0;
 }
index e4ebb4268ed9112c9f2f55aba60bf0da34f03aa0..786d56af7aa64dff191503aa9ea5f5ccb130361d 100644 (file)
@@ -17,7 +17,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: meta.c,v 1.1.2.20 2001/07/20 13:54:19 guus Exp $
+    $Id: meta.c,v 1.1.2.21 2001/10/27 12:13:17 guus Exp $
 */
 
 #include "config.h"
@@ -39,7 +39,7 @@
 #include "system.h"
 #include "protocol.h"
 
-int send_meta(connection_t *cl, char *buffer, int length)
+int send_meta(connection_t *c, char *buffer, int length)
 {
   char *bufp;
   int outlen;
@@ -47,41 +47,41 @@ int send_meta(connection_t *cl, char *buffer, int length)
 cp
   if(debug_lvl >= DEBUG_META)
     syslog(LOG_DEBUG, _("Sending %d bytes of metadata to %s (%s)"), length,
-           cl->name, cl->hostname);
+           c->name, c->hostname);
 
-  if(cl->status.encryptout)
+  if(c->status.encryptout)
     {
-      EVP_EncryptUpdate(cl->cipher_outctx, outbuf, &outlen, buffer, length);
+      EVP_EncryptUpdate(c->outctx, outbuf, &outlen, buffer, length);
       bufp = outbuf;
       length = outlen;
     }
   else
       bufp = buffer;
 
-  if(write(cl->meta_socket, bufp, length) < 0)
+  if(write(c->socket, bufp, length) < 0)
     {
-      syslog(LOG_ERR, _("Sending meta data to %s (%s) failed: %m"), cl->name, cl->hostname);
+      syslog(LOG_ERR, _("Sending meta data to %s (%s) failed: %m"), c->name, c->hostname);
       return -1;
     }
 cp
   return 0;
 }
 
-void broadcast_meta(connection_t *cl, char *buffer, int length)
+void broadcast_meta(connection_t *from, char *buffer, int length)
 {
   avl_node_t *node;
-  connection_t *p;
+  connection_t *c;
 cp
   for(node = connection_tree->head; node; node = node->next)
     {
-      p = (connection_t *)node->data;
-      if(p != cl && p->status.active)
-        send_meta(p, buffer, length);
+      c = (connection_t *)node->data;
+      if(c != from && c->status.active)
+        send_meta(c, buffer, length);
     }
 cp
 }
 
-int receive_meta(connection_t *cl)
+int receive_meta(connection_t *c)
 {
   int x, l = sizeof(x);
   int oldlen, i;
@@ -89,16 +89,16 @@ int receive_meta(connection_t *cl)
   int decrypted = 0;
   char inbuf[MAXBUFSIZE];
 cp
-  if(getsockopt(cl->meta_socket, SOL_SOCKET, SO_ERROR, &x, &l) < 0)
+  if(getsockopt(c->socket, SOL_SOCKET, SO_ERROR, &x, &l) < 0)
     {
-      syslog(LOG_ERR, _("This is a bug: %s:%d: %d:%m %s (%s)"), __FILE__, __LINE__, cl->meta_socket,
-             cl->name, cl->hostname);
+      syslog(LOG_ERR, _("This is a bug: %s:%d: %d:%m %s (%s)"), __FILE__, __LINE__, c->socket,
+             c->name, c->hostname);
       return -1;
     }
   if(x)
     {
       syslog(LOG_ERR, _("Metadata socket error for %s (%s): %s"),
-             cl->name, cl->hostname, strerror(x));
+             c->name, c->hostname, strerror(x));
       return -1;
     }
 
@@ -111,7 +111,7 @@ cp
        - If not, keep stuff in buffer and exit.
    */
 
-  lenin = read(cl->meta_socket, cl->buffer + cl->buflen, MAXBUFSIZE - cl->buflen);
+  lenin = read(c->socket, c->buffer + c->buflen, MAXBUFSIZE - c->buflen);
 
   if(lenin<=0)
     {
@@ -119,45 +119,45 @@ cp
         {
           if(debug_lvl >= DEBUG_CONNECTIONS)
             syslog(LOG_NOTICE, _("Connection closed by %s (%s)"),
-                cl->name, cl->hostname);
+                c->name, c->hostname);
         }
       else
         if(errno==EINTR)
           return 0;      
         else
           syslog(LOG_ERR, _("Metadata socket read error for %s (%s): %m"),
-                 cl->name, cl->hostname);
+                 c->name, c->hostname);
 
       return -1;
     }
 
-  oldlen = cl->buflen;
-  cl->buflen += lenin;
+  oldlen = c->buflen;
+  c->buflen += lenin;
 
   while(lenin)
     {
       /* Decrypt */
 
-      if(cl->status.decryptin && !decrypted)
+      if(c->status.decryptin && !decrypted)
         {
-          EVP_DecryptUpdate(cl->cipher_inctx, inbuf, &lenin, cl->buffer + oldlen, lenin);
-          memcpy(cl->buffer + oldlen, inbuf, lenin);
+          EVP_DecryptUpdate(c->inctx, inbuf, &lenin, c->buffer + oldlen, lenin);
+          memcpy(c->buffer + oldlen, inbuf, lenin);
           decrypted = 1;
         }
 
       /* Are we receiving a TCPpacket? */
 
-      if(cl->tcplen)
+      if(c->tcplen)
         {
-          if(cl->tcplen <= cl->buflen)
+          if(c->tcplen <= c->buflen)
             {
-              receive_tcppacket(cl, cl->buffer, cl->tcplen);
+              receive_tcppacket(c, c->buffer, c->tcplen);
 
-              cl->buflen -= cl->tcplen;
-              lenin -= cl->tcplen;
-              memmove(cl->buffer, cl->buffer + cl->tcplen, cl->buflen);
+              c->buflen -= c->tcplen;
+              lenin -= c->tcplen;
+              memmove(c->buffer, c->buffer + c->tcplen, c->buflen);
               oldlen = 0;
-              cl->tcplen = 0;
+              c->tcplen = 0;
               continue;
             }
           else
@@ -170,11 +170,11 @@ cp
 
       reqlen = 0;
 
-      for(i = oldlen; i < cl->buflen; i++)
+      for(i = oldlen; i < c->buflen; i++)
         {
-          if(cl->buffer[i] == '\n')
+          if(c->buffer[i] == '\n')
             {
-              cl->buffer[i] = '\0';  /* replace end-of-line by end-of-string so we can use sscanf */
+              c->buffer[i] = '\0';  /* replace end-of-line by end-of-string so we can use sscanf */
               reqlen = i + 1;
               break;
             }
@@ -182,12 +182,12 @@ cp
 
       if(reqlen)
         {
-          if(receive_request(cl))
+          if(receive_request(c))
             return -1;
 
-          cl->buflen -= reqlen;
+          c->buflen -= reqlen;
           lenin -= reqlen;
-          memmove(cl->buffer, cl->buffer + reqlen, cl->buflen);
+          memmove(c->buffer, c->buffer + reqlen, c->buflen);
           oldlen = 0;
           continue;
         }
@@ -197,14 +197,14 @@ cp
         }
     }
 
-  if(cl->buflen >= MAXBUFSIZE)
+  if(c->buflen >= MAXBUFSIZE)
     {
       syslog(LOG_ERR, _("Metadata read buffer overflow for %s (%s)"),
-            cl->name, cl->hostname);
+            c->name, c->hostname);
       return -1;
     }
 
-  cl->last_ping_time = time(NULL);
+  c->last_ping_time = time(NULL);
 cp  
   return 0;
 }
index e96ae51a687eeca7dee494c171e3c53db10a3ed5..c0c8e66f0d519edab54ee51771530392426222b0 100644 (file)
--- a/src/net.c
+++ b/src/net.c
@@ -17,7 +17,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: net.c,v 1.35.4.136 2001/10/08 13:37:30 guus Exp $
+    $Id: net.c,v 1.35.4.137 2001/10/27 12:13:17 guus Exp $
 */
 
 #include "config.h"
 #define RAND_pseudo_bytes RAND_bytes
 #endif
 
-#ifdef HAVE_TUNTAP
- #ifdef HAVE_LINUX
-  #ifdef LINUX_IF_TUN_H
-   #include LINUX_IF_TUN_H
-  #else
-   #include <linux/if_tun.h>
-  #endif
- #else
-  #include <net/if_tun.h>
- #endif
-#endif
-
-#ifdef HAVE_SOLARIS
- #include <sys/sockio.h>
- #include <sys/stropts.h>
- #include <net/if_tun.h>
-#endif
-
 #include <utils.h>
 #include <xalloc.h>
 #include <avl_tree.h>
 #include "subnet.h"
 #include "process.h"
 #include "route.h"
+#include "device.h"
 
 #include "system.h"
 
-int tap_fd = -1;
-int taptype = TAP_TYPE_ETHERTAP;
-int total_tap_in = 0;
-int total_tap_out = 0;
-int total_socket_in = 0;
-int total_socket_out = 0;
-
 int seconds_till_retry = 5;
+int tcp_socket = -1;
+int udp_socket = -1;
 
 int keylifetime = 0;
 int keyexpires = 0;
 
-void send_udppacket(connection_t *cl, vpn_packet_t *inpkt)
+/* VPN packet I/O */
+
+void receive_udppacket(node_t *n, vpn_packet_t *inpkt)
+{
+  vpn_packet_t outpkt;
+  int outlen, outpad;
+  EVP_CIPHER_CTX ctx;
+cp
+  /* Decrypt the packet */
+
+  EVP_DecryptInit(&ctx, myself->cipher, myself->key, myself->key + myself->cipher->key_len);
+  EVP_DecryptUpdate(&ctx, outpkt.salt, &outlen, inpkt->salt, inpkt->len);
+  EVP_DecryptFinal(&ctx, outpkt.salt + outlen, &outpad);
+  outlen += outpad;
+  outpkt.len = outlen - sizeof(outpkt.salt);
+
+  receive_packet(n, &outpkt);
+cp
+}
+
+void receive_tcppacket(connection_t *c, char *buffer, int len)
+{
+  vpn_packet_t outpkt;
+cp
+  outpkt.len = len;
+  memcpy(outpkt.data, buffer, len);
+
+  receive_packet(c->node, &outpkt);
+cp
+}
+
+void receive_packet(node_t *n, vpn_packet_t *packet)
+{
+cp
+  if(debug_lvl >= DEBUG_TRAFFIC)
+    syslog(LOG_DEBUG, _("Received packet of %d bytes from %s (%s)"), packet->len, n->name, n->hostname);
+
+  route_incoming(n, packet);
+cp
+}
+
+void send_udppacket(node_t *n, vpn_packet_t *inpkt)
 {
   vpn_packet_t outpkt;
   int outlen, outpad;
@@ -110,11 +129,11 @@ void send_udppacket(connection_t *cl, vpn_packet_t *inpkt)
   socklen_t tolen = sizeof(to);
   vpn_packet_t *copy;
 cp
-  if(!cl->status.validkey)
+  if(!n->status.validkey)
     {
       if(debug_lvl >= DEBUG_TRAFFIC)
        syslog(LOG_INFO, _("No valid key known yet for %s (%s), queueing packet"),
-              cl->name, cl->hostname);
+              n->name, n->hostname);
 
       /* Since packet is on the stack of handle_tap_input(),
          we have to make a copy of it first. */
@@ -122,10 +141,10 @@ cp
       copy = xmalloc(sizeof(vpn_packet_t));
       memcpy(copy, inpkt, sizeof(vpn_packet_t));
 
-      list_insert_tail(cl->queue, copy);
+      list_insert_tail(n->queue, copy);
 
-      if(!cl->status.waitingforkey)
-       send_req_key(myself, cl);
+      if(!n->status.waitingforkey)
+       send_req_key(n->nexthop->connection, myself, n);
       return;
     }
 
@@ -133,110 +152,35 @@ cp
 
   RAND_pseudo_bytes(inpkt->salt, sizeof(inpkt->salt));
 
-  EVP_EncryptInit(&ctx, cl->cipher_pkttype, cl->cipher_pktkey, cl->cipher_pktkey + cl->cipher_pkttype->key_len);
+  EVP_EncryptInit(&ctx, n->cipher, n->key, n->key + n->cipher->key_len);
   EVP_EncryptUpdate(&ctx, outpkt.salt, &outlen, inpkt->salt, inpkt->len + sizeof(inpkt->salt));
   EVP_EncryptFinal(&ctx, outpkt.salt + outlen, &outpad);
   outlen += outpad;
 
-  total_socket_out += outlen;
-
   to.sin_family = AF_INET;
-  to.sin_addr.s_addr = htonl(cl->address);
-  to.sin_port = htons(cl->port);
+  to.sin_addr.s_addr = htonl(n->address);
+  to.sin_port = htons(n->port);
 
-  if((sendto(myself->socket, (char *) outpkt.salt, outlen, 0, (const struct sockaddr *)&to, tolen)) < 0)
+  if((sendto(socket, (char *) outpkt.salt, outlen, 0, (const struct sockaddr *)&to, tolen)) < 0)
     {
       syslog(LOG_ERR, _("Error sending packet to %s (%s): %m"),
-             cl->name, cl->hostname);
+             n->name, n->hostname);
       return;
     }
 cp
 }
 
-void receive_packet(connection_t *cl, vpn_packet_t *packet)
-{
-cp
-  if(debug_lvl >= DEBUG_TRAFFIC)
-    syslog(LOG_DEBUG, _("Received packet of %d bytes from %s (%s)"), packet->len, cl->name, cl->hostname);
-
-  route_incoming(cl, packet);
-cp
-}
-
-void receive_udppacket(connection_t *cl, vpn_packet_t *inpkt)
-{
-  vpn_packet_t outpkt;
-  int outlen, outpad;
-  EVP_CIPHER_CTX ctx;
-cp
-  /* Decrypt the packet */
-
-  EVP_DecryptInit(&ctx, myself->cipher_pkttype, myself->cipher_pktkey, myself->cipher_pktkey + myself->cipher_pkttype->key_len);
-  EVP_DecryptUpdate(&ctx, outpkt.salt, &outlen, inpkt->salt, inpkt->len);
-  EVP_DecryptFinal(&ctx, outpkt.salt + outlen, &outpad);
-  outlen += outpad;
-  outpkt.len = outlen - sizeof(outpkt.salt);
-
-  total_socket_in += outlen;
-
-  receive_packet(cl, &outpkt);
-cp
-}
-
-void receive_tcppacket(connection_t *cl, char *buffer, int len)
-{
-  vpn_packet_t outpkt;
-cp
-  outpkt.len = len;
-  memcpy(outpkt.data, buffer, len);
-
-  receive_packet(cl, &outpkt);
-cp
-}
-
-void accept_packet(vpn_packet_t *packet)
-{
-cp
-  if(debug_lvl >= DEBUG_TRAFFIC)
-    syslog(LOG_DEBUG, _("Writing packet of %d bytes to tap device"),
-           packet->len);
-
-#ifdef HAVE_SOLARIS
-  if(write(tap_fd, packet->data + 14, packet->len - 14) < 0)
-    syslog(LOG_ERR, _("Can't write to tun/tap device: %m"));
-  else
-    total_tap_out += packet->len;
-#else
-  if(taptype == TAP_TYPE_TUNTAP)
-    {
-      if(write(tap_fd, packet->data, packet->len) < 0)
-        syslog(LOG_ERR, _("Can't write to tun/tap device: %m"));
-      else
-        total_tap_out += packet->len;
-    }
-  else /* ethertap */
-    {
-      if(write(tap_fd, packet->data - 2, packet->len + 2) < 0)
-        syslog(LOG_ERR, _("Can't write to ethertap device: %m"));
-      else
-        total_tap_out += packet->len;
-    }
-#endif
-cp
-}
-
 /*
   send a packet to the given vpn ip.
 */
-void send_packet(connection_t *cl, vpn_packet_t *packet)
+void send_packet(node_t *n, vpn_packet_t *packet)
 {
-  connection_t *via;
 cp
   if(debug_lvl >= DEBUG_TRAFFIC)
     syslog(LOG_ERR, _("Sending packet of %d bytes to %s (%s)"),
-           packet->len, cl->name, cl->hostname);
+           packet->len, n->name, n->hostname);
 
-  if(cl == myself)
+  if(n == myself)
     {
       if(debug_lvl >= DEBUG_TRAFFIC)
         {
@@ -246,39 +190,40 @@ cp
       return;
     }
 
-  if(!cl->status.active)
+  if(!n->status.active)
     {
       if(debug_lvl >= DEBUG_TRAFFIC)
        syslog(LOG_INFO, _("%s (%s) is not active, dropping packet"),
-              cl->name, cl->hostname);
+              n->name, n->hostname);
 
       return;
     }
-
-  if(cl->via == myself)
-    via = cl->nexthop;
+/* FIXME
+  if(n->via == myself)
+    via = n->nexthop;
   else
-    via = cl->via;
+    via = n->via;
 
-  if(via != cl && debug_lvl >= DEBUG_TRAFFIC)
+  if(via != n && debug_lvl >= DEBUG_TRAFFIC)
     syslog(LOG_ERR, _("Sending packet to %s via %s (%s)"),
-           cl->name, via->name, via->hostname);
+           n->name, via->name, via->hostname);
 
   if((myself->options | via->options) & OPTION_TCPONLY)
     {
-      if(send_tcppacket(via, packet))
-        terminate_connection(via, 1);
+      if(send_tcppacket(via->connection, packet))
+        terminate_connection(via->connection, 1);
     }
   else
     send_udppacket(via, packet);
+*/
 }
 
 /* Broadcast a packet to all active direct connections */
 
-void broadcast_packet(connection_t *from, vpn_packet_t *packet)
+void broadcast_packet(node_t *from, vpn_packet_t *packet)
 {
   avl_node_t *node;
-  connection_t *cl;
+  connection_t *c;
 cp
   if(debug_lvl >= DEBUG_TRAFFIC)
     syslog(LOG_INFO, _("Broadcasting packet of %d bytes from %s (%s)"),
@@ -286,174 +231,39 @@ cp
 
   for(node = connection_tree->head; node; node = node->next)
     {
-      cl = (connection_t *)node->data;
-      if(cl->status.active && cl != from)
-        send_packet(cl, packet);
+      c = (connection_t *)node->data;
+      if(c->status.active && c != from->nexthop->connection)
+        send_packet(c->node, packet);
     }
 cp
 }
 
-void flush_queue(connection_t *cl)
+void flush_queue(node_t *n)
 {
   list_node_t *node, *next;
 cp
   if(debug_lvl >= DEBUG_TRAFFIC)
-    syslog(LOG_INFO, _("Flushing queue for %s (%s)"), cl->name, cl->hostname);
+    syslog(LOG_INFO, _("Flushing queue for %s (%s)"), n->name, n->hostname);
 
-  for(node = cl->queue->head; node; node = next)
+  for(node = n->queue->head; node; node = next)
     {
       next = node->next;
-      send_udppacket(cl, (vpn_packet_t *)node->data);
-      list_delete_node(cl->queue, node);
+      send_udppacket(n, (vpn_packet_t *)node->data);
+      list_delete_node(n->queue, node);
     }
 cp
 }
 
-/*
-  open the local ethertap device
-*/
-int setup_tap_fd(void)
-{
-  int nfd;
-  const char *tapfname;
-  config_t const *cfg;
-#ifdef HAVE_LINUX
-# ifdef HAVE_TUNTAP
-  struct ifreq ifr;
-# endif
-#endif
-#ifdef HAVE_SOLARIS
-  int ip_fd = -1, if_fd = -1;
-  int ppa;
-  char *ptr;
-#endif
-
-cp
-  if((cfg = get_config_val(config, config_tapdevice)))
-    tapfname = cfg->data.ptr;
-  else
-   {
-#ifdef HAVE_LINUX
-# ifdef HAVE_TUNTAP
-      tapfname = "/dev/net/tun";
-# else
-      tapfname = "/dev/tap0";
-# endif
-#endif
-#ifdef HAVE_FREEBSD
-      tapfname = "/dev/tap0";
-#endif
-#ifdef HAVE_SOLARIS
-      tapfname = "/dev/tun";
-#endif
-   }
-cp
-  if((nfd = open(tapfname, O_RDWR | O_NONBLOCK)) < 0)
-    {
-      syslog(LOG_ERR, _("Could not open %s: %m"), tapfname);
-      return -1;
-    }
-cp
-  tap_fd = nfd;
-
-  /* Set default MAC address for ethertap devices */
-
-  mymac.type = SUBNET_MAC;
-  mymac.net.mac.address.x[0] = 0xfe;
-  mymac.net.mac.address.x[1] = 0xfd;
-  mymac.net.mac.address.x[2] = 0x00;
-  mymac.net.mac.address.x[3] = 0x00;
-  mymac.net.mac.address.x[4] = 0x00;
-  mymac.net.mac.address.x[5] = 0x00;
+/* Setup sockets */
 
-#ifdef HAVE_LINUX
- #ifdef HAVE_TUNTAP
-  /* Ok now check if this is an old ethertap or a new tun/tap thingie */
-  memset(&ifr, 0, sizeof(ifr));
-cp
-  ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
-  if (netname)
-    strncpy(ifr.ifr_name, netname, IFNAMSIZ);
-cp
-  if (!ioctl(tap_fd, TUNSETIFF, (void *) &ifr))
-  {
-    syslog(LOG_INFO, _("%s is a Linux tun/tap device"), tapfname);
-    taptype = TAP_TYPE_TUNTAP;
-  }
-  else
-    if (!ioctl(tap_fd, (('T'<< 8) | 202), (void *) &ifr))
-    {
-      syslog(LOG_INFO, _("%s is a Linux tun/tap device"), tapfname);
-      syslog(LOG_WARNING, _("Old ioctl() request used"));
-      taptype = TAP_TYPE_TUNTAP;
-    }
-    else
- #endif
-    {
-      syslog(LOG_INFO, _("%s is a Linux ethertap device"), tapfname);
-      taptype = TAP_TYPE_ETHERTAP;
-    }
-#endif
-#ifdef HAVE_FREEBSD
- syslog(LOG_INFO, _("%s is a FreeBSD tap device"), tapfname);
- taptype = TAP_TYPE_TUNTAP;
-#endif
-#ifdef HAVE_SOLARIS
-  ppa = 0;
-
-  ptr = tapfname;
-  while(*ptr && !isdigit((int)*ptr)) ptr++;
-  ppa = atoi(ptr);
-
-  if( (ip_fd = open("/dev/ip", O_RDWR, 0)) < 0){
-     syslog(LOG_ERR, _("Could not open /dev/ip: %m"));
-     return -1;
-  }
-
-  /* Assign a new PPA and get its unit number. */
-  if( (ppa = ioctl(nfd, TUNNEWPPA, ppa)) < 0){
-     syslog(LOG_ERR, _("Can't assign new interface: %m"));
-     return -1;
-  }
-
-  if( (if_fd = open(tapfname, O_RDWR, 0)) < 0){
-     syslog(LOG_ERR, _("Could not open %s twice: %m"), tapfname);
-     return -1;
-  }
-
-  if(ioctl(if_fd, I_PUSH, "ip") < 0){
-     syslog(LOG_ERR, _("Can't push IP module: %m"));
-     return -1;
-  }
-
-  /* Assign ppa according to the unit number returned by tun device */
-  if(ioctl(if_fd, IF_UNITSEL, (char *)&ppa) < 0){
-     syslog(LOG_ERR, _("Can't set PPA %d: %m"), ppa);
-     return -1;
-  }
-
-  if(ioctl(ip_fd, I_LINK, if_fd) < 0){
-     syslog(LOG_ERR, _("Can't link TUN device to IP: %m"));
-     return -1;
-  }
-
-  syslog(LOG_INFO, _("%s is a Solaris tun device"), tapfname);
-#endif
-
-cp
-  return 0;
-}
-
-/*
-  set up the socket that we listen on for incoming
-  (tcp) connections
-*/
-int setup_listen_meta_socket(int port)
+int setup_listen_socket(int port)
 {
   int nfd, flags;
   struct sockaddr_in a;
   int option;
-  config_t const *cfg;
+  char *interface;
+  char *address;
+  ip_mask_t *ipmask;
 cp
   if((nfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
     {
@@ -481,25 +291,29 @@ cp
   option = IPTOS_LOWDELAY;
   setsockopt(nfd, SOL_IP, IP_TOS, &option, sizeof(option));
 
-  if((cfg = get_config_val(config, config_interface)))
-    {
-      if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, cfg->data.ptr, strlen(cfg->data.ptr)))
-        {
-          close(nfd);
-          syslog(LOG_ERR, _("Unable to bind listen socket to interface %s: %m"), cfg->data.ptr);
-          return -1;
-        }
-    }
+  if(get_config_string(lookup_config(config_tree, "BindToInterface"), &interface))
+    if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, interface, strlen(interface)))
+      {
+        close(nfd);
+        syslog(LOG_ERR, _("Can't bind to interface %s: %m"), interface);
+        return -1;
+      }
 #endif
 
   memset(&a, 0, sizeof(a));
   a.sin_family = AF_INET;
+  a.sin_addr.s_addr = htonl(INADDR_ANY);
   a.sin_port = htons(port);
 
-  if((cfg = get_config_val(config, config_interfaceip)))
-    a.sin_addr.s_addr = htonl(cfg->data.ip->address);
-  else
-    a.sin_addr.s_addr = htonl(INADDR_ANY);
+  if(get_config_string(lookup_config(config_tree, "BindToAddress"), &address))
+    {
+      ipmask = strtoip(address);
+      if(ipmask)
+      {
+        a.sin_addr.s_addr = htonl(ipmask->address);
+        free(ipmask);
+      }
+    }
 
   if(bind(nfd, (struct sockaddr *)&a, sizeof(struct sockaddr)))
     {
@@ -519,10 +333,6 @@ cp
   return nfd;
 }
 
-/*
-  setup the socket for incoming encrypted
-  data (the udp part)
-*/
 int setup_vpn_in_socket(int port)
 {
   int nfd, flags;
@@ -562,199 +372,171 @@ cp
   return nfd;
 }
 
-/*
-  setup an outgoing meta (tcp) socket
-*/
-int setup_outgoing_meta_socket(connection_t *cl)
+int setup_outgoing_socket(connection_t *c)
 {
   int flags;
   struct sockaddr_in a;
-  config_t const *cfg;
   int option;
 cp
   if(debug_lvl >= DEBUG_CONNECTIONS)
-    syslog(LOG_INFO, _("Trying to connect to %s"), cl->hostname);
+    syslog(LOG_INFO, _("Trying to connect to %s (%s)"), c->name, c->hostname);
 
-  if((cfg = get_config_val(cl->config, config_port)) == NULL)
-    cl->port = 655;
-  else
-    cl->port = cfg->data.val;
+  c->socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 
-  cl->meta_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-  if(cl->meta_socket == -1)
+  if(c->socket == -1)
     {
       syslog(LOG_ERR, _("Creating socket for %s port %d failed: %m"),
-             cl->hostname, cl->port);
+             c->hostname, c->port);
       return -1;
     }
 
-  /* Bind first to get a fix on our source port */
+  /* Bind first to get a fix on our source port???
 
   a.sin_family = AF_INET;
   a.sin_port = htons(0);
   a.sin_addr.s_addr = htonl(INADDR_ANY);
 
-  if(bind(cl->meta_socket, (struct sockaddr *)&a, sizeof(struct sockaddr)))
+  if(bind(c->socket, (struct sockaddr *)&a, sizeof(struct sockaddr)))
     {
-      close(cl->meta_socket);
+      close(c->socket);
       syslog(LOG_ERR, _("System call `%s' failed: %m"), "bind");
       return -1;
     }
 
-  /* Optimize TCP settings */
+  */
+
+  /* Optimize TCP settings?
 
   option = 1;
-  setsockopt(cl->meta_socket, SOL_SOCKET, SO_KEEPALIVE, &option, sizeof(option));
+  setsockopt(c->socket, SOL_SOCKET, SO_KEEPALIVE, &option, sizeof(option));
 #ifdef HAVE_LINUX
-  setsockopt(cl->meta_socket, SOL_TCP, TCP_NODELAY, &option, sizeof(option));
+  setsockopt(c->socket, SOL_TCP, TCP_NODELAY, &option, sizeof(option));
 
   option = IPTOS_LOWDELAY;
-  setsockopt(cl->meta_socket, SOL_IP, IP_TOS, &option, sizeof(option));
+  setsockopt(c->socket, SOL_IP, IP_TOS, &option, sizeof(option));
 #endif
+
+  */
+
   /* Connect */
 
   a.sin_family = AF_INET;
-  a.sin_port = htons(cl->port);
-  a.sin_addr.s_addr = htonl(cl->address);
+  a.sin_port = htons(c->port);
+  a.sin_addr.s_addr = htonl(c->address);
 
-  if(connect(cl->meta_socket, (struct sockaddr *)&a, sizeof(a)) == -1)
+  if(connect(c->socket, (struct sockaddr *)&a, sizeof(a)) == -1)
     {
-      close(cl->meta_socket);
-      syslog(LOG_ERR, _("%s port %hd: %m"), cl->hostname, cl->port);
+      close(c->socket);
+      syslog(LOG_ERR, _("%s port %hd: %m"), c->hostname, c->port);
       return -1;
     }
 
-  flags = fcntl(cl->meta_socket, F_GETFL);
-  if(fcntl(cl->meta_socket, F_SETFL, flags | O_NONBLOCK) < 0)
+  flags = fcntl(c->socket, F_GETFL);
+
+  if(fcntl(c->socket, F_SETFL, flags | O_NONBLOCK) < 0)
     {
-      close(cl->meta_socket);
+      close(c->socket);
       syslog(LOG_ERR, _("fcntl for %s port %d: %m"),
-             cl->hostname, cl->port);
+             c->hostname, c->port);
       return -1;
     }
 
   if(debug_lvl >= DEBUG_CONNECTIONS)
     syslog(LOG_INFO, _("Connected to %s port %hd"),
-         cl->hostname, cl->port);
-
-  cl->status.meta = 1;
+         c->hostname, c->port);
 cp
   return 0;
 }
 
-/*
-  Setup an outgoing meta connection.
-*/
 int setup_outgoing_connection(char *name)
 {
-  connection_t *ncn, *old;
+  connection_t *c;
   struct hostent *h;
-  config_t const *cfg;
 cp
-  if(check_id(name))
-    {
-      syslog(LOG_ERR, _("Invalid name for outgoing connection"));
-      return -1;
-    }
-
-  /* Make sure we don't make an outgoing connection to a host that is already in our connection list */
+  c = new_connection();
+  c->name = xstrdup(name);
 
-  if((old = lookup_id(name)))
-    {
-      if(!old->status.outgoing)
-        {
-          if(debug_lvl >= DEBUG_CONNECTIONS)
-            syslog(LOG_NOTICE, _("We are already connected to %s."), name);
-
-          old->status.outgoing = 1;
-        }
-      return 0;
-    }
-    
-  ncn = new_connection();
-  asprintf(&ncn->name, "%s", name);
-
-  if(read_host_config(ncn))
+  read_connection_config(c);
+  
+  if(!get_config_string(lookup_config(c->config_tree, "Address"), &c->hostname))
     {
-      syslog(LOG_ERR, _("Error reading host configuration file for %s"), ncn->name);
-      free_connection(ncn);
+      syslog(LOG_ERR, _("No address specified for %s"), c->name);
+      free_connection(c);
       return -1;
     }
 
-  if(!(cfg = get_config_val(ncn->config, config_address)))
+  if(!get_config_port(lookup_config(c->config_tree, "Port"), &c->port))
     {
-      syslog(LOG_ERR, _("No address specified for %s"), ncn->name);
-      free_connection(ncn);
+      syslog(LOG_ERR, _("No port specified for %s"), c->name);
+      free_connection(c);
       return -1;
     }
 
-  if(!(h = gethostbyname(cfg->data.ptr)))
+  if(!(h = gethostbyname(c->hostname)))
     {
-      syslog(LOG_ERR, _("Error looking up `%s': %m"), cfg->data.ptr);
-      free_connection(ncn);
+      syslog(LOG_ERR, _("Error looking up `%s': %m"), c->hostname);
+      free_connection(c);
       return -1;
     }
 
-  ncn->address = ntohl(*((ipv4_t*)(h->h_addr_list[0])));
-  ncn->hostname = hostlookup(htonl(ncn->address));
+  c->address = ntohl(*((ipv4_t*)(h->h_addr_list[0])));
+  c->hostname = hostlookup(htonl(c->address));
 
-  if(setup_outgoing_meta_socket(ncn) < 0)
+  if(setup_outgoing_socket(c) < 0)
     {
-      syslog(LOG_ERR, _("Could not set up a meta connection to %s"),
-             ncn->hostname);
-      free_connection(ncn);
+      syslog(LOG_ERR, _("Could not set up a meta connection to %s (%s)"),
+             c->name, c->hostname);
+      free_connection(c);
       return -1;
     }
 
-  ncn->status.outgoing = 1;
-  ncn->buffer = xmalloc(MAXBUFSIZE);
-  ncn->buflen = 0;
-  ncn->last_ping_time = time(NULL);
+  c->status.outgoing = 1;
+  c->last_ping_time = time(NULL);
 
-  connection_add(ncn);
+  connection_add(c);
 
-  send_id(ncn);
+  send_id(c);
 cp
   return 0;
 }
 
-int read_rsa_public_key(connection_t *cl)
+int read_rsa_public_key(connection_t *c)
 {
-  config_t const *cfg;
   FILE *fp;
   char *fname;
+  char *key;
   void *result;
 cp
-  if(!cl->rsa_key)
-    cl->rsa_key = RSA_new();
+  if(!c->rsa_key)
+    c->rsa_key = RSA_new();
 
   /* First, check for simple PublicKey statement */
 
-  if((cfg = get_config_val(cl->config, config_publickey)))
+  if(get_config_string(lookup_config(c->config_tree, "PublicKey"), &key))
     {
-      BN_hex2bn(&cl->rsa_key->n, cfg->data.ptr);
-      BN_hex2bn(&cl->rsa_key->e, "FFFF");
+      BN_hex2bn(&c->rsa_key->n, key);
+      BN_hex2bn(&c->rsa_key->e, "FFFF");
       return 0;
     }
 
   /* Else, check for PublicKeyFile statement and read it */
 
-  if((cfg = get_config_val(cl->config, config_publickeyfile)))
+  if(get_config_string(lookup_config(c->config_tree, "PublicKeyFile"), &fname))
     {
-      if(is_safe_path(cfg->data.ptr))
+      if(is_safe_path(fname))
         {
-          if((fp = fopen(cfg->data.ptr, "r")) == NULL)
+          if((fp = fopen(fname, "r")) == NULL)
             {
               syslog(LOG_ERR, _("Error reading RSA public key file `%s': %m"),
-                    cfg->data.ptr);
+                    fname);
               return -1;
             }
-          result = PEM_read_RSAPublicKey(fp, &cl->rsa_key, NULL, NULL);
+          result = PEM_read_RSAPublicKey(fp, &c->rsa_key, NULL, NULL);
           fclose(fp);
           if(!result)
             {
               syslog(LOG_ERR, _("Reading RSA public key file `%s' failed: %m"),
-                    cfg->data.ptr);
+                    fname);
               return -1;
             }
           return 0;
@@ -765,53 +547,55 @@ cp
 
   /* Else, check if a harnessed public key is in the config file */
 
-  asprintf(&fname, "%s/hosts/%s", confbase, cl->name);
+  result = NULL;
+
+  asprintf(&fname, "%s/hosts/%s", confbase, c->name);
   if((fp = fopen(fname, "r")))
     {
-      result = PEM_read_RSAPublicKey(fp, &cl->rsa_key, NULL, NULL);
+      result = PEM_read_RSAPublicKey(fp, &c->rsa_key, NULL, NULL);
       fclose(fp);
       free(fname);
-      if(result)
-        return 0;
     }
 
   free(fname);
 
-  /* Nothing worked. */
-
-  syslog(LOG_ERR, _("No public key for %s specified!"), cl->name);
-cp
-  return -1;
+  if(result)
+    return 0;
+  else
+    {
+      syslog(LOG_ERR, _("No public key for %s specified!"), c->name);
+      return -1;
+    }
 }
 
 int read_rsa_private_key(void)
 {
-  config_t const *cfg;
   FILE *fp;
   void *result;
+  char *fname, *key;
 cp
-  if(!myself->rsa_key)
-    myself->rsa_key = RSA_new();
+  if(!myself->connection->rsa_key)
+    myself->connection->rsa_key = RSA_new();
 
-  if((cfg = get_config_val(config, config_privatekey)))
+  if(get_config_string(lookup_config(config_tree, "PrivateKey"), &key))
     {
-      BN_hex2bn(&myself->rsa_key->d, cfg->data.ptr);
-      BN_hex2bn(&myself->rsa_key->e, "FFFF");
+      BN_hex2bn(&myself->connection->rsa_key->d, key);
+      BN_hex2bn(&myself->connection->rsa_key->e, "FFFF");
     }
-  else if((cfg = get_config_val(config, config_privatekeyfile)))
+  else if(get_config_string(lookup_config(config_tree, "PrivateKeyFile"), &fname))
     {
-      if((fp = fopen(cfg->data.ptr, "r")) == NULL)
+      if((fp = fopen(fname, "r")) == NULL)
         {
           syslog(LOG_ERR, _("Error reading RSA private key file `%s': %m"),
-                cfg->data.ptr);
+                fname);
           return -1;
         }
-      result = PEM_read_RSAPrivateKey(fp, &myself->rsa_key, NULL, NULL);
+      result = PEM_read_RSAPrivateKey(fp, &myself->connection->rsa_key, NULL, NULL);
       fclose(fp);
       if(!result)
         {
           syslog(LOG_ERR, _("Reading RSA private key file `%s' failed: %m"),
-                cfg->data.ptr);
+                fname);
           return -1;
         }
     }
@@ -825,108 +609,107 @@ cp
 }
 
 /*
-  Configure connection_t myself and set up the local sockets (listen only)
+  Configure node_t myself and set up the local sockets (listen only)
 */
 int setup_myself(void)
 {
-  config_t const *cfg;
-  config_t *next;
-  subnet_t *net;
+  config_t *cfg;
+  subnet_t *subnet;
+  char *name, *mode;
+  int choice;
 cp
-  myself = new_connection();
+  myself = new_node();
+  myself->connection = new_connection();
 
   asprintf(&myself->hostname, _("MYSELF"));
-  myself->options = 0;
-  myself->protocol_version = PROT_CURRENT;
+  asprintf(&myself->connection->hostname, _("MYSELF"));
 
-  if(!(cfg = get_config_val(config, config_name))) /* Not acceptable */
+  myself->connection->options = 0;
+  myself->connection->protocol_version = PROT_CURRENT;
+
+  if(!get_config_string(lookup_config(config_tree, "Name"), &name)) /* Not acceptable */
     {
       syslog(LOG_ERR, _("Name for tinc daemon required!"));
       return -1;
     }
-  else
-    asprintf(&myself->name, "%s", (char*)cfg->data.val);
 
-  if(check_id(myself->name))
+  if(check_id(name))
     {
       syslog(LOG_ERR, _("Invalid name for myself!"));
+      free(name);
       return -1;
     }
+
+  myself->name = name;
+  myself->connection->name = xstrdup(name);
+
 cp
   if(read_rsa_private_key())
     return -1;
 
-  if(read_host_config(myself))
+  if(read_connection_config(myself->connection))
     {
       syslog(LOG_ERR, _("Cannot open host configuration file for myself!"));
       return -1;
     }
 
-  if(read_rsa_public_key(myself))
+  if(read_rsa_public_key(myself->connection))
     return -1;
 cp
 
 /*
-  if(RSA_check_key(myself->rsa_key) != 1)
+  if(RSA_check_key(rsa_key) != 1)
     {
       syslog(LOG_ERR, _("Invalid public/private keypair!"));
       return -1;
     }
 */
-  if(!(cfg = get_config_val(myself->config, config_port)))
+  if(!get_config_port(lookup_config(myself->connection->config_tree, "Port"), &myself->connection->port))
     myself->port = 655;
-  else
-    myself->port = cfg->data.val;
 
 /* Read in all the subnets specified in the host configuration file */
 
-  for(next = myself->config; (cfg = get_config_val(next, config_subnet)); next = cfg->next)
-    {
-      net = new_subnet();
-      net->type = SUBNET_IPV4;
-      net->net.ipv4.address = cfg->data.ip->address;
-      net->net.ipv4.mask = cfg->data.ip->mask;
+  cfg = lookup_config(myself->connection->config_tree, "Subnet");
 
-      /* Teach newbies what subnets are... */
+  while(cfg)
+    {
+      if(!get_config_subnet(cfg, &subnet))
+        return -1;
 
-      if((net->net.ipv4.address & net->net.ipv4.mask) != net->net.ipv4.address)
-        {
-          syslog(LOG_ERR, _("Network address and subnet mask do not match!"));
-          return -1;
-        }
+      subnet_add(myself, subnet);
 
-      subnet_add(myself, net);
+      cfg = lookup_config_next(myself->connection->config_tree, cfg);
     }
 
 cp
   /* Check some options */
 
-  if((cfg = get_config_val(config, config_indirectdata)))
-    if(cfg->data.val == stupid_true)
+  if(get_config_bool(lookup_config(config_tree, "IndirectData"), &choice))
+    if(choice)
       myself->options |= OPTION_INDIRECT;
 
-  if((cfg = get_config_val(config, config_tcponly)))
-    if(cfg->data.val == stupid_true)
+  if(get_config_bool(lookup_config(config_tree, "TCPOnly"), &choice))
+    if(choice)
       myself->options |= OPTION_TCPONLY;
 
-  if((cfg = get_config_val(myself->config, config_indirectdata)))
-    if(cfg->data.val == stupid_true)
+  if(get_config_bool(lookup_config(myself->connection->config_tree, "IndirectData"), &choice))
+    if(choice)
       myself->options |= OPTION_INDIRECT;
 
-  if((cfg = get_config_val(myself->config, config_tcponly)))
-    if(cfg->data.val == stupid_true)
+  if(get_config_bool(lookup_config(myself->connection->config_tree, "TCPOnly"), &choice))
+    if(choice)
       myself->options |= OPTION_TCPONLY;
 
   if(myself->options & OPTION_TCPONLY)
     myself->options |= OPTION_INDIRECT;
 
-  if((cfg = get_config_val(config, config_mode)))
+  if(get_config_string(lookup_config(myself->connection->config_tree, "Mode"), &mode))
     {
-      if(!strcasecmp(cfg->data.ptr, "router"))
+      if(!strcasecmp(mode, "router"))
         routing_mode = RMODE_ROUTER;
-      else if (!strcasecmp(cfg->data.ptr, "switch"))
+      else if (!strcasecmp(mode, "switch"))
         routing_mode = RMODE_SWITCH;
-      else if (!strcasecmp(cfg->data.ptr, "hub"))
+      else if (!strcasecmp(mode, "hub"))
         routing_mode = RMODE_HUB;
       else
         {
@@ -940,13 +723,13 @@ cp
 cp
   /* Open sockets */
   
-  if((myself->meta_socket = setup_listen_meta_socket(myself->port)) < 0)
+  if((tcp_socket = setup_listen_socket(myself->port)) < 0)
     {
       syslog(LOG_ERR, _("Unable to set up a listening TCP socket!"));
       return -1;
     }
 
-  if((myself->socket = setup_vpn_in_socket(myself->port)) < 0)
+  if((udp_socket = setup_vpn_in_socket(myself->port)) < 0)
     {
       syslog(LOG_ERR, _("Unable to set up a listening UDP socket!"));
       return -1;
@@ -954,96 +737,50 @@ cp
 cp
   /* Generate packet encryption key */
 
-  myself->cipher_pkttype = EVP_bf_cbc();
+  myself->cipher = EVP_bf_cbc();
 
-  myself->cipher_pktkeylength = myself->cipher_pkttype->key_len + myself->cipher_pkttype->iv_len;
+  myself->keylength = myself->cipher->key_len + myself->cipher->iv_len;
 
-  myself->cipher_pktkey = (char *)xmalloc(myself->cipher_pktkeylength);
-  RAND_pseudo_bytes(myself->cipher_pktkey, myself->cipher_pktkeylength);
+  myself->key = (char *)xmalloc(myself->keylength);
+  RAND_pseudo_bytes(myself->key, myself->keylength);
 
-  if(!(cfg = get_config_val(config, config_keyexpire)))
+  if(!get_config_int(lookup_config(myself->connection->config_tree, "KeyExpire"), &keylifetime))
     keylifetime = 3600;
-  else
-    keylifetime = cfg->data.val;
 
   keyexpires = time(NULL) + keylifetime;
 cp
   /* Done */
 
   myself->nexthop = myself;
-  myself->prevhop = myself;
   myself->via = myself;
   myself->status.active = 1;
-  id_add(myself);
+  node_add(myself);
 
   syslog(LOG_NOTICE, _("Ready: listening on port %hd"), myself->port);
 cp
   return 0;
 }
 
-void randomized_alarm(int seconds)
-{
-  unsigned char r;
-  RAND_pseudo_bytes(&r, 1);
-  alarm((seconds * (int)r) / 128 + 1);
-}
-
-RETSIGTYPE
-try_outgoing_connections(int a)
-{
-  config_t const *cfg;
-  int retry = 0;
-cp
-  cfg = get_config_val(config, config_connectto);
-
-  while(cfg)
-    {
-      if(setup_outgoing_connection(cfg->data.ptr))   /* function returns 0 when there are no problems */
-        retry = 1;
-      cfg = get_config_val(cfg->next, config_connectto); /* Or else we try the next ConnectTo line */
-    }
-
-  if(retry)
-    {
-      seconds_till_retry += 5;
-      if(seconds_till_retry > MAXTIMEOUT)    /* Don't wait more than MAXTIMEOUT seconds. */
-        seconds_till_retry = MAXTIMEOUT;
-
-      syslog(LOG_ERR, _("Failed to setup all outgoing connections, will retry in %d seconds"),
-        seconds_till_retry);
-  
-      /* Randomize timeout to avoid global synchronisation effects */
-      randomized_alarm(seconds_till_retry);
-    }
-  else
-    {
-      seconds_till_retry = 5;
-    }
-cp
-}
-
 /*
   setup all initial network connections
 */
 int setup_network_connections(void)
 {
-  config_t const *cfg;
 cp
   init_connections();
   init_subnets();
 
-  if((cfg = get_config_val(config, config_pingtimeout)) == NULL)
-    timeout = 60;
-  else
+  if(get_config_int(lookup_config(myself->connection->config_tree, "PingTimeout"), &timeout))
     {
-      timeout = cfg->data.val;
       if(timeout < 1)
         {
           timeout = 86400;
         }
-     }
+    }
+  else
+    timeout = 60;
 
-  if(setup_tap_fd() < 0)
+  if(setup_device() < 0)
     return -1;
 
   /* Run tinc-up script to further initialize the tap interface */
@@ -1064,23 +801,23 @@ cp
 void close_network_connections(void)
 {
   avl_node_t *node, *next;
-  connection_t *p;
+  connection_t *c;
 cp
   for(node = connection_tree->head; node; node = next)
     {
       next = node->next;
-      p = (connection_t *)node->data;
-      p->status.outgoing = 0;
-      terminate_connection(p, 0);
+      c = (connection_t *)node->data;
+      c->status.outgoing = 0;
+      terminate_connection(c, 0);
     }
 
-  terminate_connection(myself, 0);
+//  terminate_connection(myself, 0);
 
-  destroy_trees();
+//  destroy_trees();
 
   execute_script("tinc-down");
 
-  close(tap_fd);
+  close_device();
 cp
   return;
 }
@@ -1091,11 +828,11 @@ cp
 */
 connection_t *create_new_connection(int sfd)
 {
-  connection_t *p;
+  connection_t *c;
   struct sockaddr_in ci;
   int len = sizeof(ci);
 cp
-  p = new_connection();
+  c = new_connection();
 
   if(getpeername(sfd, (struct sockaddr *) &ci, (socklen_t *) &len) < 0)
     {
@@ -1105,23 +842,19 @@ cp
       return NULL;
     }
 
-  asprintf(&p->name, _("UNKNOWN"));
-  p->address = ntohl(ci.sin_addr.s_addr);
-  p->hostname = hostlookup(ci.sin_addr.s_addr);
-  p->port = htons(ci.sin_port);                                /* This one will be overwritten later */
-  p->meta_socket = sfd;
-  p->status.meta = 1;
-  p->buffer = xmalloc(MAXBUFSIZE);
-  p->buflen = 0;
-  p->last_ping_time = time(NULL);
+  c->address = ntohl(ci.sin_addr.s_addr);
+  c->hostname = hostlookup(ci.sin_addr.s_addr);
+  c->port = htons(ci.sin_port);                                /* This one will be overwritten later */
+  c->socket = sfd;
+  c->last_ping_time = time(NULL);
 
   if(debug_lvl >= DEBUG_CONNECTIONS)
     syslog(LOG_NOTICE, _("Connection from %s port %d"),
-         p->hostname, htons(ci.sin_port));
+         c->hostname, htons(ci.sin_port));
 
-  p->allow_request = ID;
+  c->allow_request = ID;
 cp
-  return p;
+  return c;
 }
 
 /*
@@ -1130,20 +863,19 @@ cp
 void build_fdset(fd_set *fs)
 {
   avl_node_t *node;
-  connection_t *p;
+  connection_t *c;
 cp
   FD_ZERO(fs);
 
-  FD_SET(myself->socket, fs);
-
   for(node = connection_tree->head; node; node = node->next)
     {
-      p = (connection_t *)node->data;
-      FD_SET(p->meta_socket, fs);
+      c = (connection_t *)node->data;
+      FD_SET(c->socket, fs);
     }
 
-  FD_SET(myself->meta_socket, fs);
-  FD_SET(tap_fd, fs);
+  FD_SET(tcp_socket, fs);
+  FD_SET(udp_socket, fs);
+  FD_SET(device_fd, fs);
 cp
 }
 
@@ -1158,12 +890,12 @@ void handle_incoming_vpn_data(void)
   int x, l = sizeof(x);
   struct sockaddr_in from;
   socklen_t fromlen = sizeof(from);
-  connection_t *cl;
+  node_t *n;
 cp
-  if(getsockopt(myself->socket, SOL_SOCKET, SO_ERROR, &x, &l) < 0)
+  if(getsockopt(udp_socket, SOL_SOCKET, SO_ERROR, &x, &l) < 0)
     {
       syslog(LOG_ERR, _("This is a bug: %s:%d: %d:%m"),
-            __FILE__, __LINE__, myself->socket);
+            __FILE__, __LINE__, udp_socket);
       return;
     }
   if(x)
@@ -1172,23 +904,24 @@ cp
       return;
     }
 
-  if((pkt.len = recvfrom(myself->socket, (char *) pkt.salt, MTU, 0, (struct sockaddr *)&from, &fromlen)) <= 0)
+  if((pkt.len = recvfrom(udp_socket, (char *) pkt.salt, MTU, 0, (struct sockaddr *)&from, &fromlen)) <= 0)
     {
       syslog(LOG_ERR, _("Receiving packet failed: %m"));
       return;
     }
 
-  cl = lookup_active(ntohl(from.sin_addr.s_addr), ntohs(from.sin_port));
+  n = lookup_node_udp(ntohl(from.sin_addr.s_addr), ntohs(from.sin_port));
 
-  if(!cl)
+  if(!n)
     {
       syslog(LOG_WARNING, _("Received UDP packets on port %hd from unknown source %x:%hd"), myself->port, ntohl(from.sin_addr.s_addr), ntohs(from.sin_port));
       return;
     }
-
-  cl->last_ping_time = time(NULL);
-
-  receive_udppacket(cl, &pkt);
+/*
+  if(n->connection)
+    n->connection->last_ping_time = time(NULL);
+*/
+  receive_udppacket(n, &pkt);
 cp
 }
 
@@ -1200,77 +933,9 @@ cp
   - Since it might still be referenced, put it on the prune list.
   - If report == 1, then send DEL_HOST messages to the other tinc daemons.
 */
-void terminate_connection(connection_t *cl, int report)
+void terminate_connection(connection_t *c, int report)
 {
-  connection_t *p;
-  subnet_t *subnet;
-  avl_node_t *node, *next;
-cp
-  if(cl->status.remove)
-    return;
-  else
-    cl->status.remove = 1;
-
-  if(cl->socket)
-    close(cl->socket);
-  if(cl->meta_socket)
-    close(cl->meta_socket);
-
-  connection_del(cl);
-
-  if(cl->status.meta)
-    {
-      if(debug_lvl >= DEBUG_CONNECTIONS)
-        syslog(LOG_NOTICE, _("Closing connection with %s (%s)"),
-               cl->name, cl->hostname);
-
-      if(cl->status.active)
-        {
-          /* Find all connections that were lost because they were behind cl
-             (the connection that was dropped). */
-
-          for(node = active_tree->head; node; node = next)
-            {
-              next = node->next;
-              p = (connection_t *)node->data;
-              if(p->nexthop == cl)
-                terminate_connection(p, report);
-            }
-        }
-    }
-
-  /* Inform others of termination if needed */
-
-  if(report)
-    for(node = connection_tree->head; node; node = node->next)
-      {
-        p = (connection_t *)node->data;
-        if(p->status.active)
-          send_del_host(p, cl);        /* Sounds like recursion, but p does not have a meta connection :) */
-      }
-
-  /* Remove the associated subnets */
-
-  for(node = cl->subnet_tree->head; node; node = next)
-    {
-      next = node->next;
-      subnet = (subnet_t *)node->data;
-      subnet_del(subnet);
-    }
-
-  /* Check if this was our outgoing connection */
-
-  if(cl->status.outgoing)
-    {
-      cl->status.outgoing = 0;
-      signal(SIGALRM, try_outgoing_connections);
-      alarm(seconds_till_retry);
-      syslog(LOG_NOTICE, _("Trying to re-establish outgoing connection in %d seconds"), seconds_till_retry);
-    }
-cp
-  /* Schedule it for pruning */
-
-  prune_add(cl);
+  /* Needs a serious rewrite. */
 }
 
 /*
@@ -1285,37 +950,37 @@ void check_dead_connections(void)
 {
   time_t now;
   avl_node_t *node, *next;
-  connection_t *cl;
+  connection_t *c;
 cp
   now = time(NULL);
 
   for(node = connection_tree->head; node; node = next)
     {
       next = node->next;
-      cl = (connection_t *)node->data;
-      if(cl->last_ping_time + timeout < now)
+      c = (connection_t *)node->data;
+      if(c->last_ping_time + timeout < now)
         {
-          if(cl->status.active)
+          if(c->status.active)
             {
-              if(cl->status.pinged)
+              if(c->status.pinged)
                 {
                   if(debug_lvl >= DEBUG_PROTOCOL)
                    syslog(LOG_INFO, _("%s (%s) didn't respond to PING"),
-                          cl->name, cl->hostname);
-                 cl->status.timeout = 1;
-                 terminate_connection(cl, 1);
+                          c->name, c->hostname);
+                 c->status.timeout = 1;
+                 terminate_connection(c, 1);
                 }
               else
                 {
-                  send_ping(cl);
+                  send_ping(c);
                 }
             }
           else
             {
               if(debug_lvl >= DEBUG_CONNECTIONS)
                 syslog(LOG_WARNING, _("Timeout from %s (%s) during authentication"),
-                       cl->name, cl->hostname);
-              terminate_connection(cl, 0);
+                       c->name, c->hostname);
+              terminate_connection(c, 0);
             }
         }
     }
 */
 int handle_new_meta_connection()
 {
-  connection_t *ncn;
+  connection_t *new;
   struct sockaddr client;
-  int nfd, len = sizeof(client);
+  int fd, len = sizeof(client);
 cp
-  if((nfd = accept(myself->meta_socket, &client, &len)) < 0)
+  if((fd = accept(tcp_socket, &client, &len)) < 0)
     {
       syslog(LOG_ERR, _("Accepting a new connection failed: %m"));
       return -1;
     }
 
-  if(!(ncn = create_new_connection(nfd)))
+  if(!(new = create_new_connection(fd)))
     {
-      shutdown(nfd, 2);
-      close(nfd);
+      shutdown(fd, 2);
+      close(fd);
       syslog(LOG_NOTICE, _("Closed attempted connection"));
       return 0;
     }
 
-  connection_add(ncn);
+  connection_add(new);
 
-  send_id(ncn);
+  send_id(new);
 cp
   return 0;
 }
 
-/*
-  check all connections to see if anything
-  happened on their sockets
+void randomized_alarm(int seconds)
+{
+  unsigned char r;
+  RAND_pseudo_bytes(&r, 1);
+  alarm((seconds * (int)r) / 128 + 1);
+}
+
+/* This function is severely fucked up.
+   We want to redesign it so the following rules apply:
+   
+   - Try all ConnectTo's in a row:
+     - if a connect() fails, try next one immediately,
+     - if it works, wait 5 seconds or so.
+   - If none of them were succesful, increase delay and retry.
+   - If all were succesful, don't try anymore.
 */
-void check_network_activity(fd_set *f)
+
+RETSIGTYPE
+try_outgoing_connections(int a)
 {
-  connection_t *p;
-  avl_node_t *node;
+  static config_t *cfg = NULL;
+  static int retry = 0;
+  char *name;
+  int maxtimeout = 900;
 cp
-  if(FD_ISSET(myself->socket, f))
-    handle_incoming_vpn_data();
+  if(!cfg)
+    cfg = lookup_config(config_tree, "ConnectTo");
 
-  for(node = connection_tree->head; node; node = node->next)
+  if(!cfg)
+    return;
+
+  while(cfg)
     {
-      p = (connection_t *)node->data;
+      get_config_string(cfg, &name);
+      cfg = lookup_config_next(config_tree, cfg);  /* Next time skip to next ConnectTo line */
 
-      if(p->status.remove)
-       return;
+      if(!setup_outgoing_connection(name))   /* function returns 0 when there are no problems */
+        retry = 1;
 
-      if(FD_ISSET(p->meta_socket, f))
-       if(receive_meta(p) < 0)
-         {
-           terminate_connection(p, p->status.active);
-           return;
-         }
     }
 
-  if(FD_ISSET(myself->meta_socket, f))
-    handle_new_meta_connection();
+  get_config_int(lookup_config(config_tree, "MaxTimeout"), &maxtimeout);
+
+  if(retry)
+    {
+      seconds_till_retry += 5;
+      if(seconds_till_retry > maxtimeout)    /* Don't wait more than MAXTIMEOUT seconds. */
+        seconds_till_retry = maxtimeout;
+
+      syslog(LOG_ERR, _("Failed to setup all outgoing connections, will retry in %d seconds"),
+        seconds_till_retry);
+  
+      /* Randomize timeout to avoid global synchronisation effects */
+      randomized_alarm(seconds_till_retry);
+    }
+  else
+    {
+      seconds_till_retry = 5;
+    }
 cp
 }
 
 /*
-  read, encrypt and send data that is
-  available through the ethertap device
+  check all connections to see if anything
+  happened on their sockets
 */
-void handle_tap_input(void)
+void check_network_activity(fd_set *f)
 {
-  vpn_packet_t vp;
-  int lenin;
+  connection_t *c;
+  avl_node_t *node;
 cp
-#ifdef HAVE_SOLARIS
-  if((lenin = read(tap_fd, vp.data + 14, MTU)) <= 0)
-    {
-      syslog(LOG_ERR, _("Error while reading from tun device: %m"));
-      return;
-    }
-  memcpy(vp.data, mymac.net.mac.address.x, 6);
-  memcpy(vp.data + 6, mymac.net.mac.address.x, 6);
-  vp.data[12] = 0x08;
-  vp.data[13] = 0x00;
-  vp.len = lenin + 14;
-#else
-  if(taptype == TAP_TYPE_TUNTAP)
-    {
-      if((lenin = read(tap_fd, vp.data, MTU)) <= 0)
-        {
-          syslog(LOG_ERR, _("Error while reading from tun/tap device: %m"));
-          return;
-        }
-      vp.len = lenin;
-    }
-  else                 /* ethertap */
-    {
-      if((lenin = read(tap_fd, vp.data - 2, MTU)) <= 0)
-        {
-          syslog(LOG_ERR, _("Error while reading from ethertap device: %m"));
-          return;
-        }
-      vp.len = lenin - 2;
-    }
-#endif
-
-  total_tap_in += vp.len;
+  if(FD_ISSET(udp_socket, f))
+    handle_incoming_vpn_data();
 
-  if(lenin < 32)
+  for(node = connection_tree->head; node; node = node->next)
     {
-      if(debug_lvl >= DEBUG_TRAFFIC)
-       syslog(LOG_WARNING, _("Received short packet from tap device"));
-      return;
-    }
+      c = (connection_t *)node->data;
 
-  if(debug_lvl >= DEBUG_TRAFFIC)
-    {
-      syslog(LOG_DEBUG, _("Read packet of length %d from tap device"), vp.len);
+      if(c->status.remove)
+       return;
+
+      if(FD_ISSET(c->socket, f))
+       if(receive_meta(c) < 0)
+         {
+           terminate_connection(c, c->status.active);
+           return;
+         }
     }
 
-  route_outgoing(&vp);
+  if(FD_ISSET(tcp_socket, f))
+    handle_new_meta_connection();
 cp
 }
 
@@ -1462,7 +1130,6 @@ cp
       tv.tv_sec = timeout;
       tv.tv_usec = 0;
 
-      prune_flush();
       build_fdset(&fset);
 
       if((r = select(FD_SETSIZE, &fset, NULL, NULL, &tv)) < 0)
@@ -1479,7 +1146,7 @@ cp
           syslog(LOG_INFO, _("Rereading configuration file and restarting in 5 seconds"));
           sighup = 0;
           close_network_connections();
-          clear_config(&config);
+          exit_configuration(&config_tree);
 
           if(read_server_config())
             {
@@ -1511,8 +1178,8 @@ cp
               if(debug_lvl >= DEBUG_STATUS)
                 syslog(LOG_INFO, _("Regenerating symmetric key"));
 
-              RAND_pseudo_bytes(myself->cipher_pktkey, myself->cipher_pktkeylength);
-              send_key_changed(myself, NULL);
+              RAND_pseudo_bytes(myself->key, myself->keylength);
+              send_key_changed(myself->connection, myself);
               keyexpires = time(NULL) + keylifetime;
             }
        }
@@ -1522,7 +1189,7 @@ cp
           check_network_activity(&fset);
 
           /* local tap data */
-          if(FD_ISSET(tap_fd, &fset))
+          if(FD_ISSET(device_fd, &fset))
            handle_tap_input();
         }
     }
index 7c1784162d8907f6f9ead5dbec448be2032960e9..eb7ad7eaba2ccae94ed6cf4b77339af9bb275626 100644 (file)
--- a/src/net.h
+++ b/src/net.h
@@ -17,7 +17,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: net.h,v 1.9.4.34 2001/07/21 15:34:18 guus Exp $
+    $Id: net.h,v 1.9.4.35 2001/10/27 12:13:17 guus Exp $
 */
 
 #ifndef __TINC_NET_H__
@@ -59,6 +59,11 @@ typedef struct mac_t
 
 typedef unsigned long ipv4_t;
 
+typedef struct ip_mask_t {
+  ipv4_t address;
+  ipv4_t mask;
+} ip_mask_t;
+
 typedef struct ipv6_t
 {
   unsigned short x[8];
@@ -85,19 +90,6 @@ typedef struct packet_queue_t {
   queue_element_t *tail;
 } packet_queue_t;
 
-typedef struct enc_key_t {
-  int length;
-  char *key;
-  time_t expiry;
-} enc_key_t;
-
-extern int tap_fd;
-
-extern int total_tap_in;
-extern int total_tap_out;
-extern int total_socket_in;
-extern int total_socket_out;
-
 extern int seconds_till_retry;
 
 extern char *request_name[256];
@@ -105,26 +97,16 @@ extern char *status_text[10];
 
 #include "connection.h"                /* Yes, very strange placement indeed, but otherwise the typedefs get all tangled up */
 
-extern int str2opt(const char *);
-extern char *opt2str(int);
-extern void send_packet(connection_t *, vpn_packet_t *);
-extern void receive_packet(connection_t *, vpn_packet_t *);
-extern void receive_tcppacket(connection_t *, char *, int);
-extern void accept_packet(vpn_packet_t *);
-extern void broadcast_packet(connection_t *, vpn_packet_t *);
+extern void send_packet(struct node_t *, vpn_packet_t *);
+extern void receive_packet(struct node_t *, vpn_packet_t *);
+extern void receive_tcppacket(struct connection_t *, char *, int);
+extern void broadcast_packet(struct node_t *, vpn_packet_t *);
 extern int setup_network_connections(void);
 extern void close_network_connections(void);
 extern void main_loop(void);
 extern void terminate_connection(connection_t *, int);
-extern void flush_queue(connection_t *);
-
-#include <config.h>
-#ifdef HAVE_OPENSSL_RSA_H
-# include <openssl/rsa.h>
-#else
-# include <rsa.h>
-#endif
-
-extern int read_rsa_public_key(connection_t *);
+extern void flush_queue(struct node_t *);
+extern int read_rsa_public_key(struct connection_t *);
+extern RETSIGTYPE try_outgoing_connections(int);
 
 #endif /* __TINC_NET_H__ */
index 562b105dfb90fd25f605945442909f1f4db809c8..e869e348cb66b4c93b01093c264f022a375bfe1b 100644 (file)
@@ -17,7 +17,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: netutl.c,v 1.12.4.19 2001/05/07 19:08:46 guus Exp $
+    $Id: netutl.c,v 1.12.4.20 2001/10/27 12:13:17 guus Exp $
 */
 
 #include "config.h"
@@ -46,15 +46,11 @@ char *hostlookup(unsigned long addr)
   char *name;
   struct hostent *host = NULL;
   struct in_addr in;
-  config_t const *cfg;
-  int lookup_hostname;
+  int lookup_hostname = 0;
 cp
   in.s_addr = addr;
 
-  lookup_hostname = 0;
-  if((cfg = get_config_val(config, config_hostnames)) != NULL)
-    if(cfg->data.val == stupid_true)
-      lookup_hostname = 1;
+  get_config_int(lookup_config(config_tree, "Hostnames"), &lookup_hostname);
 
   if(lookup_hostname)
     host = gethostbyaddr((char *)&in, sizeof(in), AF_INET);
index bcc84c88efb03b63c95ffbc2be027375c595a53e..3f6d009fcfa4c21f43c518e130710415f40117f2 100644 (file)
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: netutl.h,v 1.2.4.6 2001/01/07 17:09:02 guus Exp $
+    $Id: netutl.h,v 1.2.4.7 2001/10/27 12:13:17 guus Exp $
 */
 
 #ifndef __TINC_NETUTL_H__
 #define __TINC_NETUTL_H__
 
 #include "net.h"
-#include "conf.h"
 
 extern char *hostlookup(unsigned long);
 extern ip_mask_t *strtoip(char*);
index d2553625dbf9425c08b5e538a3d98b825715e714..53e520e92f8d4980ac5d073f9601e409738fb2fc 100644 (file)
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: node.c,v 1.1.2.1 2001/10/10 08:49:47 guus Exp $
+    $Id: node.c,v 1.1.2.2 2001/10/27 12:13:17 guus Exp $
 */
 
+#include "config.h"
+
+#include <string.h>
+#include <syslog.h>
+
+#include <avl_tree.h>
+#include "node.h"
+#include "net.h"
+#include <utils.h>
+#include <xalloc.h>
+
+#include "system.h"
+
 avl_tree_t *node_tree;         /* Known nodes, sorted by name */
+avl_tree_t *node_udp_tree;     /* Known nodes, sorted by address and port */
 
-int node_compare(connection_t *a, connection_t *b)
+int node_compare(node_t *a, node_t *b)
 {
   return strcmp(a->name, b->name);
 }
 
+int node_udp_compare(connection_t *a, connection_t *b)
+{
+  if(a->address < b->address)
+    return -1;
+  else if (a->address > b->address)
+    return 1;
+  else
+    return a->port - b->port;
+}
+
 void init_nodes(void)
 {
 cp
   node_tree = avl_alloc_tree((avl_compare_t)node_compare, NULL);
+  node_udp_tree = avl_alloc_tree((avl_compare_t)node_udp_compare, NULL);
 cp
 }
 
@@ -38,6 +63,7 @@ void exit_nodes(void)
 {
 cp
   avl_delete_tree(node_tree);
+  avl_delete_tree(node_udp_tree);
 cp
 }
 
@@ -62,12 +88,26 @@ cp
     free(n->hostname);
   if(n->key)
     free(n->key);
-  if(n->config)
-    clear_config(&n->config);
   free(n);
 cp
 }
 
+void node_add(node_t *n)
+{
+cp
+  avl_insert(node_tree, n);
+  avl_insert(node_udp_tree, n);
+cp
+}
+
+void node_del(node_t *n)
+{
+cp
+  avl_delete(node_tree, n);
+  avl_delete(node_udp_tree, n);
+cp
+}
+
 node_t *lookup_node(char *name)
 {
   node_t n;
@@ -76,17 +116,13 @@ cp
   return avl_search(node_tree, &n);
 }
 
-
-int read_host_config(nodet *n)
+node_t *lookup_node_udp(ipv4_t address, port_t port)
 {
-  char *fname;
-  int x;
-cp
-  asprintf(&fname, "%s/hosts/%s", confbase, n->name);
-  x = read_config_file(&n->config, fname);
-  free(fname);
+  node_t n;
 cp
-  return x;
+  n.address = address;
+  n.port = port;
+  return avl_search(node_udp_tree, &n);
 }
 
 void dump_nodes(void)
@@ -98,10 +134,10 @@ cp
 
   for(node = node_tree->head; node; node = node->next)
     {
-      n = (connection_t *)node->data;
-      syslog(LOG_DEBUG, _(" %s at %s port %hd options %ld sockets %d, %d status %04x"),
+      n = (node_t *)node->data;
+      syslog(LOG_DEBUG, _(" %s at %s port %hd options %ld status %04x"),
              n->name, n->hostname, n->port, n->options,
-             n->socket, n->meta_socket, n->status);
+             n->status);
     }
     
   syslog(LOG_DEBUG, _("End of nodes."));
index 16bdb7c08d200910818a766357e425ff7db88935..9f2a35a7ab90ed2c46bcebed04fb5719d4f2754a 100644 (file)
@@ -17,7 +17,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: node.h,v 1.1.2.4 2001/10/10 20:35:10 guus Exp $
+    $Id: node.h,v 1.1.2.5 2001/10/27 12:13:17 guus Exp $
 */
 
 #ifndef __TINC_NODE_H__
 
 #include <avl_tree.h>
 
+#include "subnet.h"
+#include "connection.h"
+
+typedef struct node_status_t {
+  int active:1;                    /* 1 if active.. */
+  int validkey:1;                  /* 1 if we currently have a valid key for him */
+  int waitingforkey:1;             /* 1 if we already sent out a request */
+  int unused:29;
+} node_status_t;
+
 typedef struct node_t {
-  char *name;                      /* name of this connection */
-  int protocol_version;            /* used protocol */
-  long int options;                /* options turned on for this connection */
+  char *name;                      /* name of this node */
+  long int options;                /* options turned on for this node */
 
   ipv4_t address;                  /* his real (internet) ip to send UDP packets to */
   short unsigned int port;         /* port number of UDP connection */
   char *hostname;                  /* the hostname of its real ip */
 
+  struct node_status_t status;
+
   EVP_CIPHER *cipher;              /* Cipher type for UDP packets */ 
   char *key;                       /* Cipher key and iv */
   int keylength;                   /* Cipher key and iv length*/
 
-  list_t *queue;                   /* Queue for packets awaiting to be encrypted */
+  list_t *queue;               /* Queue for packets awaiting to be encrypted */
 
-  struct node_t *nexthop;          /* nearest meta-hop from us to him */
-  struct node_t *prevhop;          /* nearest meta-hop from him to us */
+  struct node_t *nexthop;          /* nearest node from us to him */
   struct node_t *via;              /* next hop for UDP packets */
   
   avl_tree_t *subnet_tree;         /* Pointer to a tree of subnets belonging to this node */
 
-  struct config_t *config;         /* Pointer to configuration tree belonging to this node */
+  struct connection_t *connection; /* Connection associated with this node (if a direct connection exists) */
 } node_t;
 
-struct node_t *myself;
+extern struct node_t *myself;
 extern avl_tree_t *node_tree;
 
+extern void init_nodes(void);
+extern void exit_nodes(void);
+extern node_t *new_node(void);
+extern void free_node(node_t *n);
+extern void node_add(node_t *n);
+extern void node_del(node_t *n);
+extern node_t *lookup_node(char *);
+extern node_t *lookup_node_udp(ipv4_t, port_t);
+extern void dump_nodes(void);
+
+
 #endif /* __TINC_NODE_H__ */
index f395496fa2e53c18ff460a5647360d1bb9e10aa9..9acb5fddac3376ce6d68bcbfe8153b3a45e4d98f 100644 (file)
@@ -17,7 +17,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: process.c,v 1.1.2.25 2001/09/05 18:38:09 zarq Exp $
+    $Id: process.c,v 1.1.2.26 2001/10/27 12:13:17 guus Exp $
 */
 
 #include "config.h"
@@ -42,6 +42,7 @@
 #include "conf.h"
 #include "process.h"
 #include "subnet.h"
+#include "device.h"
 #include "connection.h"
 
 #include "system.h"
@@ -87,8 +88,7 @@ cp
   close_network_connections();
 
   if(debug_lvl > DEBUG_NOTHING)
-    syslog(LOG_INFO, _("Total bytes written: tap %d, socket %d; bytes read: tap %d, socket %d"),
-          total_tap_out, total_socket_out, total_tap_in, total_socket_in);
+    dump_device_stats();
 
   syslog(LOG_NOTICE, _("Terminating"));
 
index 492f2893878f11910cdc6084981c9649c1523125..f275f3e221ffaccbba3fdf31f926fbbd73c7c366 100644 (file)
@@ -17,7 +17,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: protocol.c,v 1.28.4.108 2001/10/08 15:37:14 guus Exp $
+    $Id: protocol.c,v 1.28.4.109 2001/10/27 12:13:17 guus Exp $
 */
 
 #include "config.h"
@@ -54,6 +54,8 @@
 #include "protocol.h"
 #include "meta.h"
 #include "connection.h"
+#include "node.h"
+#include "vertex.h"
 
 #include "system.h"
 
@@ -73,7 +75,7 @@ int check_id(char *id)
 /* Generic request routines - takes care of logging and error
    detection as well */
 
-int send_request(connection_t *cl, const char *format, ...)
+int send_request(connection_t *c, const char *format, ...)
 {
   va_list args;
   char buffer[MAXBUFSIZE];
@@ -91,37 +93,37 @@ cp
 
   if(len < 0 || len > MAXBUFSIZE-1)
     {
-      syslog(LOG_ERR, _("Output buffer overflow while sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
+      syslog(LOG_ERR, _("Output buffer overflow while sending %s to %s (%s)"), request_name[request], c->name, c->hostname);
       return -1;
     }
 
   if(debug_lvl >= DEBUG_PROTOCOL)
     {
       if(debug_lvl >= DEBUG_META)
-        syslog(LOG_DEBUG, _("Sending %s to %s (%s): %s"), request_name[request], cl->name, cl->hostname, buffer);
+        syslog(LOG_DEBUG, _("Sending %s to %s (%s): %s"), request_name[request], c->name, c->hostname, buffer);
       else
-        syslog(LOG_DEBUG, _("Sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
+        syslog(LOG_DEBUG, _("Sending %s to %s (%s)"), request_name[request], c->name, c->hostname);
     }
 
   buffer[len++] = '\n';
 cp
-  return send_meta(cl, buffer, len);
+  return send_meta(c, buffer, len);
 }
 
-int receive_request(connection_t *cl)
+int receive_request(connection_t *c)
 {
   int request;
 cp
-  if(sscanf(cl->buffer, "%d", &request) == 1)
+  if(sscanf(c->buffer, "%d", &request) == 1)
     {
       if((request < 0) || (request >= LAST) || (request_handlers[request] == NULL))
         {
           if(debug_lvl >= DEBUG_META)
             syslog(LOG_DEBUG, _("Unknown request from %s (%s): %s"),
-                  cl->name, cl->hostname, cl->buffer);
+                  c->name, c->hostname, c->buffer);
           else
             syslog(LOG_ERR, _("Unknown request from %s (%s)"),
-                   cl->name, cl->hostname);
+                   c->name, c->hostname);
                    
           return -1;
         }
@@ -131,31 +133,31 @@ cp
             {
               if(debug_lvl >= DEBUG_META)
                 syslog(LOG_DEBUG, _("Got %s from %s (%s): %s"),
-                      request_name[request], cl->name, cl->hostname, cl->buffer);
+                      request_name[request], c->name, c->hostname, c->buffer);
               else
                 syslog(LOG_DEBUG, _("Got %s from %s (%s)"),
-                      request_name[request], cl->name, cl->hostname);
+                      request_name[request], c->name, c->hostname);
             }
        }
 
-      if((cl->allow_request != ALL) && (cl->allow_request != request))
+      if((c->allow_request != ALL) && (c->allow_request != request))
         {
-          syslog(LOG_ERR, _("Unauthorized request from %s (%s)"), cl->name, cl->hostname);
+          syslog(LOG_ERR, _("Unauthorized request from %s (%s)"), c->name, c->hostname);
           return -1;
         }
 
-      if(request_handlers[request](cl))
+      if(request_handlers[request](c))
        /* Something went wrong. Probably scriptkiddies. Terminate. */
         {
           syslog(LOG_ERR, _("Error while processing %s from %s (%s)"),
-                request_name[request], cl->name, cl->hostname);
+                request_name[request], c->name, c->hostname);
           return -1;
         }
     }
   else
     {
       syslog(LOG_ERR, _("Bogus data received from %s (%s)"),
-            cl->name, cl->hostname);
+            c->name, c->hostname);
       return -1;
     }
 cp
@@ -165,258 +167,294 @@ cp
 /* The authentication protocol is described in detail in doc/SECURITY2,
    the rest will be described in doc/PROTOCOL. */
 
-int send_id(connection_t *cl)
+int send_id(connection_t *c)
 {
 cp
-  return send_request(cl, "%d %s %d %lx %hd", ID, myself->name, myself->protocol_version, myself->options, myself->port);
+  return send_request(c, "%d %s %d", ID, myself->connection->name, myself->connection->protocol_version);
 }
 
-int id_h(connection_t *cl)
+int id_h(connection_t *c)
 {
   char name[MAX_STRING_SIZE];
 cp
-  if(sscanf(cl->buffer, "%*d "MAX_STRING" %d %lx %hd", name, &cl->protocol_version, &cl->options, &cl->port) != 4)
+  if(sscanf(c->buffer, "%*d "MAX_STRING" %d", name, &c->protocol_version) != 2)
     {
-       syslog(LOG_ERR, _("Got bad ID from %s"), cl->hostname);
+       syslog(LOG_ERR, _("Got bad %s from %s"), "ID", c->hostname);
        return -1;
     }
 
-  /* Check if version matches */
-
-  if(cl->protocol_version != myself->protocol_version)
-    {
-      syslog(LOG_ERR, _("Peer %s (%s) uses incompatible version %d"),
-             cl->name, cl->hostname, cl->protocol_version);
-      return -1;
-    }
-
   /* Check if identity is a valid name */
 
   if(check_id(name))
     {
-      syslog(LOG_ERR, _("Peer %s uses invalid identity name"), cl->hostname);
+      syslog(LOG_ERR, _("Peer %s uses invalid identity name"), c->hostname);
       return -1;
     }
+
+  /* If we set c->name in advance, make sure we are connected to the right host */
   
-  /* Copy string to cl */
-  
-  if(cl->name)
-    free(cl->name);
-    
-  cl->name = xstrdup(name);
+  if(c->name)
+    {
+      if(strcmp(c->name, name))
+        {
+          syslog(LOG_ERR, _("Peer %s is %s instead of %s"), c->hostname, name, c->name);
+          return -1;
+        }
+    }
+  else
+    c->name = xstrdup(name);
 
-  /* Load information about peer */
+  /* Check if version matches */
 
-  if(read_host_config(cl))
+  if(c->protocol_version != myself->connection->protocol_version)
     {
-      syslog(LOG_ERR, _("Peer %s had unknown identity (%s)"), cl->hostname, cl->name);
+      syslog(LOG_ERR, _("Peer %s (%s) uses incompatible version %d"),
+             c->name, c->hostname, c->protocol_version);
       return -1;
     }
+  
+  if(!c->config_tree)
+    {
+      if(read_connection_config(c))
+        {
+          syslog(LOG_ERR, _("Peer %s had unknown identity (%s)"), c->hostname, c->name);
+          return -1;
+        }
 
-  /* Read in the public key, so that we can send a metakey */
-
-  if(read_rsa_public_key(cl))
-    return -1;
+      if(read_rsa_public_key(c))
+        {
+          return -1;
+        }
+    }
 
-  cl->allow_request = METAKEY;
+  c->allow_request = METAKEY;
 cp
-  return send_metakey(cl);
+  return send_metakey(c);
 }
 
-int ack_h(connection_t *cl)
+int send_metakey(connection_t *c)
 {
-  config_t const *cfg;
-  connection_t *old, *p;
-  subnet_t *subnet;
-  avl_node_t *node, *node2;
+  char *buffer;
+  int len, x;
 cp
-  /* Okay, before we active the connection, we check if there is another entry
-     in the connection list with the same name. If so, it presumably is an
-     old connection that has timed out but we don't know it yet.
-   */
+  len = RSA_size(c->rsa_key);
 
-  if((old = lookup_id(cl->name)))
-    {
-      if(debug_lvl >= DEBUG_CONNECTIONS)
-        syslog(LOG_NOTICE, _("Removing old connection for %s at %s in favour of new connection at %s"),
-               old->name, old->hostname, cl->hostname);
-      if(old->status.outgoing)
-        {
-          cl->status.outgoing = 1;
-          old->status.outgoing = 0;
-        }
+  /* Allocate buffers for the meta key */
 
-      terminate_connection(old, 0);
-    }
+  buffer = xmalloc(len*2+1);
+
+  if(!c->outkey)
+    c->outkey = xmalloc(len);
     
-  /* Also check if no other tinc daemon uses the same IP and port for UDP traffic */
+  if(!c->outctx)
+    c->outctx = xmalloc(sizeof(*c->outctx));
+cp
+  /* Copy random data to the buffer */
+
+  RAND_bytes(c->outkey, len);
+
+  /* The message we send must be smaller than the modulus of the RSA key.
+     By definition, for a key of k bits, the following formula holds:
+     
+       2^(k-1) <= modulus < 2^(k)
+     
+     Where ^ means "to the power of", not "xor".
+     This means that to be sure, we must choose our message < 2^(k-1).
+     This can be done by setting the most significant bit to zero.
+  */
   
-  old = avl_search(active_tree, cl);
-  if(old)
-  {
-    syslog(LOG_ERR, _("%s is listening on %s:%hd, which is already in use by %s!"),
-           cl->name, cl->hostname, cl->port, old->name);
-    return -1;
-  }
-    
-  /* Activate this connection */
+  c->outkey[0] &= 0x7F;
+  
+  if(debug_lvl >= DEBUG_SCARY_THINGS)
+    {
+      bin2hex(c->outkey, buffer, len);
+      buffer[len*2] = '\0';
+      syslog(LOG_DEBUG, _("Generated random meta key (unencrypted): %s"), buffer);
+    }
 
-  cl->allow_request = ALL;
-  cl->nexthop = cl;
-  cl->prevhop = myself;
-  cl->cipher_pkttype = EVP_bf_cbc();
-  cl->cipher_pktkeylength = cl->cipher_pkttype->key_len + cl->cipher_pkttype->iv_len;
+  /* Encrypt the random data
+  
+     We do not use one of the PKCS padding schemes here.
+     This is allowed, because we encrypt a totally random string
+     with a length equal to that of the modulus of the RSA key.
+  */
+  
+  if(RSA_public_encrypt(len, c->outkey, buffer, c->rsa_key, RSA_NO_PADDING) != len)
+    {
+      syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), c->name, c->hostname);
+      free(buffer);
+      return -1;
+    }
+cp
+  /* Convert the encrypted random data to a hexadecimal formatted string */
 
-  active_add(cl);
+  bin2hex(buffer, buffer, len);
+  buffer[len*2] = '\0';
 
-  if(debug_lvl >= DEBUG_CONNECTIONS)
-    syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), cl->name, cl->hostname);
+  /* Send the meta key */
+
+  x = send_request(c, "%d %s", METAKEY, buffer);
+  free(buffer);
+
+  /* Further outgoing requests are encrypted with the key we just generated */
 
-  if(cl->status.outgoing)
-    seconds_till_retry = 5;    /* Reset retry timeout */
+  EVP_EncryptInit(c->outctx, EVP_bf_cfb(),
+                  c->outkey + len - EVP_bf_cfb()->key_len,
+                  c->outkey + len - EVP_bf_cfb()->key_len - EVP_bf_cfb()->iv_len);
+
+  c->status.encryptout = 1;
 cp
-  /* Check some options */
-  
-  if((cfg = get_config_val(cl->config, config_indirectdata)))
+  return x;
+}
+
+int metakey_h(connection_t *c)
+{
+  char buffer[MAX_STRING_SIZE];
+  int len;
+cp
+  if(sscanf(c->buffer, "%*d "MAX_STRING, buffer) != 1)
     {
-      if(cfg->data.val == stupid_true)
-        cl->options |= OPTION_INDIRECT;
+       syslog(LOG_ERR, _("Got bad METAKEY from %s (%s)"), c->name, c->hostname);
+       return -1;
     }
 
-  if((cfg = get_config_val(cl->config, config_tcponly)))
+  len = RSA_size(myself->connection->rsa_key);
+
+  /* Check if the length of the meta key is all right */
+
+  if(strlen(buffer) != len*2)
     {
-      if(cfg->data.val == stupid_true)
-        cl->options |= OPTION_TCPONLY;
+      syslog(LOG_ERR, _("Intruder: wrong meta key length from %s (%s)"), c->name, c->hostname);
+      return -1;
     }
 
-  if((myself->options | cl->options) & OPTION_INDIRECT)
-    cl->via = myself;
-  else
-    cl->via = cl;
+  /* Allocate buffers for the meta key */
 
-  /* Send him our subnets */
+  if(!c->inkey)
+    c->inkey = xmalloc(len);
+
+  if(!c->inctx)
+    c->inctx = xmalloc(sizeof(*c->inctx));
+
+  /* Convert the challenge from hexadecimal back to binary */
+
+  hex2bin(buffer,buffer,len);
+
+  /* Decrypt the meta key */
   
-  for(node = myself->subnet_tree->head; node; node = node->next)
+  if(RSA_private_decrypt(len, buffer, c->inkey, myself->connection->rsa_key, RSA_NO_PADDING) != len)   /* See challenge() */
     {
-      subnet = (subnet_t *)node->data;
-      send_add_subnet(cl, subnet);
+      syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), c->name, c->hostname);
+      return -1;
     }
 
-  /* And send him all the hosts and their subnets we know... */
-  
-  for(node = active_tree->head; node; node = node->next)
+  if(debug_lvl >= DEBUG_SCARY_THINGS)
     {
-      p = (connection_t *)node->data;
-      
-      if(p != cl)
-        {
-          /* Notify others of this connection */
-
-          if(p->status.meta)
-            send_add_host(p, cl);
+      bin2hex(c->inkey, buffer, len);
+      buffer[len*2] = '\0';
+      syslog(LOG_DEBUG, _("Received random meta key (unencrypted): %s"), buffer);
+    }
 
-          /* Notify new connection of everything we know */
+  /* All incoming requests will now be encrypted. */
 
-          send_add_host(cl, p);
+  EVP_DecryptInit(c->inctx, EVP_bf_cfb(),
+                  c->inkey + len - EVP_bf_cfb()->key_len,
+                  c->inkey + len - EVP_bf_cfb()->key_len - EVP_bf_cfb()->iv_len);
+  
+  c->status.decryptin = 1;
 
-          for(node2 = p->subnet_tree->head; node2; node2 = node2->next)
-            {
-              subnet = (subnet_t *)node2->data;
-              send_add_subnet(cl, subnet);
-            }
-        }
-    }
+  c->allow_request = CHALLENGE;
 cp
-  return 0;
+  return send_challenge(c);
 }
 
-int send_challenge(connection_t *cl)
+int send_challenge(connection_t *c)
 {
   char *buffer;
   int len, x;
 cp
   /* CHECKME: what is most reasonable value for len? */
 
-  len = RSA_size(cl->rsa_key);
+  len = RSA_size(c->rsa_key);
 
   /* Allocate buffers for the challenge */
 
   buffer = xmalloc(len*2+1);
 
-  if(cl->hischallenge)
-    free(cl->hischallenge);
+  if(c->hischallenge)
+    free(c->hischallenge);
     
-  cl->hischallenge = xmalloc(len);
+  c->hischallenge = xmalloc(len);
 cp
   /* Copy random data to the buffer */
 
-  RAND_bytes(cl->hischallenge, len);
+  RAND_bytes(c->hischallenge, len);
 
 cp
   /* Convert to hex */
 
-  bin2hex(cl->hischallenge, buffer, len);
+  bin2hex(c->hischallenge, buffer, len);
   buffer[len*2] = '\0';
 
 cp
   /* Send the challenge */
 
-  x = send_request(cl, "%d %s", CHALLENGE, buffer);
+  x = send_request(c, "%d %s", CHALLENGE, buffer);
   free(buffer);
 cp
   return x;
 }
 
-int challenge_h(connection_t *cl)
+int challenge_h(connection_t *c)
 {
   char buffer[MAX_STRING_SIZE];
   int len;
 cp
-  if(sscanf(cl->buffer, "%*d "MAX_STRING, buffer) != 1)
+  if(sscanf(c->buffer, "%*d "MAX_STRING, buffer) != 1)
     {
-       syslog(LOG_ERR, _("Got bad CHALLENGE from %s (%s)"), cl->name, cl->hostname);
+       syslog(LOG_ERR, _("Got bad CHALLENGE from %s (%s)"), c->name, c->hostname);
        return -1;
     }
 
-  len = RSA_size(myself->rsa_key);
+  len = RSA_size(myself->connection->rsa_key);
 
   /* Check if the length of the challenge is all right */
 
   if(strlen(buffer) != len*2)
     {
-      syslog(LOG_ERR, _("Intruder: wrong challenge length from %s (%s)"), cl->name, cl->hostname);
+      syslog(LOG_ERR, _("Intruder: wrong challenge length from %s (%s)"), c->name, c->hostname);
       return -1;
     }
 
   /* Allocate buffers for the challenge */
 
-  if(!cl->mychallenge)
-    cl->mychallenge = xmalloc(len);
+  if(!c->mychallenge)
+    c->mychallenge = xmalloc(len);
 
   /* Convert the challenge from hexadecimal back to binary */
 
-  hex2bin(buffer,cl->mychallenge,len);
+  hex2bin(buffer,c->mychallenge,len);
 
-  cl->allow_request = CHAL_REPLY;
+  c->allow_request = CHAL_REPLY;
 
   /* Rest is done by send_chal_reply() */
 cp
-  return send_chal_reply(cl);
+  return send_chal_reply(c);
 }
 
-int send_chal_reply(connection_t *cl)
+int send_chal_reply(connection_t *c)
 {
   char hash[SHA_DIGEST_LENGTH*2+1];
 cp
-  if(!cl->mychallenge)
+  if(!c->mychallenge)
     {
-      syslog(LOG_ERR, _("Trying to send CHAL_REPLY to %s (%s) without a valid CHALLENGE"), cl->name, cl->hostname);
+      syslog(LOG_ERR, _("Trying to send CHAL_REPLY to %s (%s) without a valid CHALLENGE"), c->name, c->hostname);
       return -1;
     }
      
   /* Calculate the hash from the challenge we received */
 
-  SHA1(cl->mychallenge, RSA_size(myself->rsa_key), hash);
+  SHA1(c->mychallenge, RSA_size(myself->connection->rsa_key), hash);
 
   /* Convert the hash to a hexadecimal formatted string */
 
@@ -426,17 +464,17 @@ cp
   /* Send the reply */
 
 cp
-  return send_request(cl, "%d %s", CHAL_REPLY, hash);
+  return send_request(c, "%d %s", CHAL_REPLY, hash);
 }
 
-int chal_reply_h(connection_t *cl)
+int chal_reply_h(connection_t *c)
 {
   char hishash[MAX_STRING_SIZE];
   char myhash[SHA_DIGEST_LENGTH];
 cp
-  if(sscanf(cl->buffer, "%*d "MAX_STRING, hishash) != 1)
+  if(sscanf(c->buffer, "%*d "MAX_STRING, hishash) != 1)
     {
-       syslog(LOG_ERR, _("Got bad CHAL_REPLY from %s (%s)"), cl->name, cl->hostname);
+       syslog(LOG_ERR, _("Got bad CHAL_REPLY from %s (%s)"), c->name, c->hostname);
        return -1;
     }
 
@@ -444,7 +482,7 @@ cp
 
   if(strlen(hishash) != SHA_DIGEST_LENGTH*2)
     {
-      syslog(LOG_ERR, _("Intruder: wrong challenge reply length from %s (%s)"), cl->name, cl->hostname);
+      syslog(LOG_ERR, _("Intruder: wrong challenge reply length from %s (%s)"), c->name, c->hostname);
       return -1;
     }
 
@@ -454,13 +492,13 @@ cp
 
   /* Calculate the hash from the challenge we sent */
 
-  SHA1(cl->hischallenge, RSA_size(cl->rsa_key), myhash);
+  SHA1(c->hischallenge, RSA_size(c->rsa_key), myhash);
 
   /* Verify the incoming hash with the calculated hash */
 
   if(memcmp(hishash, myhash, SHA_DIGEST_LENGTH))
     {
-      syslog(LOG_ERR, _("Intruder: wrong challenge reply from %s (%s)"), cl->name, cl->hostname);
+      syslog(LOG_ERR, _("Intruder: wrong challenge reply from %s (%s)"), c->name, c->hostname);
       if(debug_lvl >= DEBUG_SCARY_THINGS)
         {
           bin2hex(myhash, hishash, SHA_DIGEST_LENGTH);
@@ -471,176 +509,169 @@ cp
     }
 
   /* Identity has now been positively verified.
-     ack_h() handles the rest from now on.
+     Send an acknowledgement with the rest of the information needed.
    */
+
+  c->allow_request = ACK;
 cp
-  return ack_h(cl);
+  return send_ack(c);
 }
 
-int send_metakey(connection_t *cl)
+int send_ack(connection_t *c)
 {
-  char *buffer;
-  int len, x;
+  /* ACK message contains rest of the information the other end needs
+     to create node_t and vertex_t structures. */
 cp
-  len = RSA_size(cl->rsa_key);
-
-  /* Allocate buffers for the meta key */
-
-  buffer = xmalloc(len*2+1);
+  return send_request(c, "%d %d", ACK, myself->port);
+}
 
-  if(!cl->cipher_outkey)
-    cl->cipher_outkey = xmalloc(len);
-    
-  if(!cl->cipher_outctx)
-    cl->cipher_outctx = xmalloc(sizeof(*cl->cipher_outctx));
+int ack_h(connection_t *c)
+{
+  port_t port;
+  node_t *n;
+  subnet_t *s;
+  avl_node_t *node, *node2;
 cp
-  /* Copy random data to the buffer */
+  if(sscanf(c->buffer, "%*d %hd", &port) != 1)
+    {
+       syslog(LOG_ERR, _("Got bad %s from %s"), "ACK", c->hostname);
+       return -1;
+    }
 
-  RAND_bytes(cl->cipher_outkey, len);
+  /* Check if we already have a node_t for him */
 
-  /* The message we send must be smaller than the modulus of the RSA key.
-     By definition, for a key of k bits, the following formula holds:
-     
-       2^(k-1) <= modulus < 2^(k)
-     
-     Where ^ means "to the power of", not "xor".
-     This means that to be sure, we must choose our message < 2^(k-1).
-     This can be done by setting the most significant bit to zero.
-  */
+  n = lookup_node(c->name);
   
-  cl->cipher_outkey[0] &= 0x7F;
-  
-  if(debug_lvl >= DEBUG_SCARY_THINGS)
+  if(!n)
     {
-      bin2hex(cl->cipher_outkey, buffer, len);
-      buffer[len*2] = '\0';
-      syslog(LOG_DEBUG, _("Generated random meta key (unencrypted): %s"), buffer);
-    }
+      n = new_node();
+      n->name = xstrdup(c->name);
+      n->hostname = xstrdup(c->hostname);
+      n->port = port;
 
-  /* Encrypt the random data
+      /* FIXME: Also check if no other tinc daemon uses the same IP and port for UDP traffic */
+
+      node_add(n);
+    }
+  else
+    {
+      if(n->connection)
+        {
+          /* Oh dear, we already have a connection to this node. */
+          syslog(LOG_DEBUG, _("Established a second connection with %s (%s), closing old connection"), n->name, n->hostname);
+          terminate_connection(n->connection, 0);
+        }
+          
+      /* FIXME: check if information in existing node matches that of the other end of this connection */
+    }
   
-     We do not use one of the PKCS padding schemes here.
-     This is allowed, because we encrypt a totally random string
-     with a length equal to that of the modulus of the RSA key.
-  */
+  n->connection = c;
+  c->node = n;
   
-  if(RSA_public_encrypt(len, cl->cipher_outkey, buffer, cl->rsa_key, RSA_NO_PADDING) != len)
+  /* Check some options
+  
+  if((cfg = get_config_val(c->config, config_indirectdata)))
     {
-      syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), cl->name, cl->hostname);
-      free(buffer);
-      return -1;
+      if(cfg->data.val == stupid_true)
+        c->options |= OPTION_INDIRECT;
     }
-cp
-  /* Convert the encrypted random data to a hexadecimal formatted string */
 
-  bin2hex(buffer, buffer, len);
-  buffer[len*2] = '\0';
-
-  /* Send the meta key */
-
-  x = send_request(cl, "%d %s", METAKEY, buffer);
-  free(buffer);
-
-  /* Further outgoing requests are encrypted with the key we just generated */
-
-  EVP_EncryptInit(cl->cipher_outctx, EVP_bf_cfb(),
-                  cl->cipher_outkey + len - EVP_bf_cfb()->key_len,
-                  cl->cipher_outkey + len - EVP_bf_cfb()->key_len - EVP_bf_cfb()->iv_len);
-
-  cl->status.encryptout = 1;
-cp
-  return x;
-}
-
-int metakey_h(connection_t *cl)
-{
-  char buffer[MAX_STRING_SIZE];
-  int len;
-cp
-  if(sscanf(cl->buffer, "%*d "MAX_STRING, buffer) != 1)
+  if((cfg = get_config_val(c->config, config_tcponly)))
     {
-       syslog(LOG_ERR, _("Got bad METAKEY from %s (%s)"), cl->name, cl->hostname);
-       return -1;
+      if(cfg->data.val == stupid_true)
+        c->options |= OPTION_TCPONLY;
     }
 
-  len = RSA_size(myself->rsa_key);
+  if((myself->options | c->options) & OPTION_INDIRECT)
+    c->via = myself;
+  else
+    c->via = c;
 
-  /* Check if the length of the meta key is all right */
+  */
 
-  if(strlen(buffer) != len*2)
-    {
-      syslog(LOG_ERR, _("Intruder: wrong meta key length from %s (%s)"), cl->name, cl->hostname);
-      return -1;
-    }
+  /* Create a vertex_t for this connection */
 
-  /* Allocate buffers for the meta key */
+  c->vertex = new_vertex();
+  
+  c->vertex->from = myself;
+  c->vertex->to = n;
+  c->vertex->metric = 1;
+  c->vertex->connection = c;
 
-  if(!cl->cipher_inkey)
-    cl->cipher_inkey = xmalloc(len);
+  vertex_add(c->vertex);
 
-  if(!cl->cipher_inctx)
-    cl->cipher_inctx = xmalloc(sizeof(*cl->cipher_inctx));
+  /* Activate this connection */
 
-  /* Convert the challenge from hexadecimal back to binary */
+  c->allow_request = ALL;
 
-  hex2bin(buffer,buffer,len);
+  if(debug_lvl >= DEBUG_CONNECTIONS)
+    syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), c->name, c->hostname);
 
-  /* Decrypt the meta key */
+cp
+  /* Send him our subnets */
   
-  if(RSA_private_decrypt(len, buffer, cl->cipher_inkey, myself->rsa_key, RSA_NO_PADDING) != len)       /* See challenge() */
+  for(node = myself->subnet_tree->head; node; node = node->next)
     {
-      syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), cl->name, cl->hostname);
-      return -1;
+      s = (subnet_t *)node->data;
+      send_add_subnet(c, s);
     }
 
-  if(debug_lvl >= DEBUG_SCARY_THINGS)
+  /* And send him all known nodes and their subnets */
+  
+  for(node = node_tree->head; node; node = node->next)
     {
-      bin2hex(cl->cipher_inkey, buffer, len);
-      buffer[len*2] = '\0';
-      syslog(LOG_DEBUG, _("Received random meta key (unencrypted): %s"), buffer);
-    }
+      n = (node_t *)node->data;
+      
+      if(n != c->node)
+        {
+          /* Notify others of this connection */
 
-  /* All incoming requests will now be encrypted. */
+          if(n->connection)
+            send_add_node(n->connection, c->node);
 
-  EVP_DecryptInit(cl->cipher_inctx, EVP_bf_cfb(),
-                  cl->cipher_inkey + len - EVP_bf_cfb()->key_len,
-                  cl->cipher_inkey + len - EVP_bf_cfb()->key_len - EVP_bf_cfb()->iv_len);
-  
-  cl->status.decryptin = 1;
+          /* Notify new connection of everything we know */
+
+          send_add_node(c, n);
 
-  cl->allow_request = CHALLENGE;
+          for(node2 = c->node->subnet_tree->head; node2; node2 = node2->next)
+            {
+              s = (subnet_t *)node2->data;
+              send_add_subnet(c, s);
+            }
+        }
+    }
 cp
-  return send_challenge(cl);
+  return 0;
 }
 
+
+
 /* Address and subnet information exchange */
 
-int send_add_subnet(connection_t *cl, subnet_t *subnet)
+int send_add_subnet(connection_t *c, subnet_t *subnet)
 {
   int x;
   char *netstr;
-  char *owner;
 cp
-  owner = subnet->owner->name;
-
-  x = send_request(cl, "%d %s %s", ADD_SUBNET,
-                      owner, netstr = net2str(subnet));
+  x = send_request(c, "%d %s %s", ADD_SUBNET,
+                      subnet->owner->name, netstr = net2str(subnet));
   free(netstr);
 cp
   return x;
 }
 
-int add_subnet_h(connection_t *cl)
+int add_subnet_h(connection_t *c)
 {
   char subnetstr[MAX_STRING_SIZE];
   char name[MAX_STRING_SIZE];
-  connection_t *owner, *p;
-  subnet_t *subnet;
+  node_t *owner;
+  connection_t *other;
+  subnet_t *s;
   avl_node_t *node;
 cp
-  if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING, name, subnetstr) != 2)
+  if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING, name, subnetstr) != 2)
     {
-      syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s)"), cl->name, cl->hostname);
+      syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s)"), c->name, c->hostname);
       return -1;
     }
 
@@ -648,78 +679,66 @@ cp
 
   if(check_id(name))
     {
-      syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
+      syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid identity name"), c->name, c->hostname);
       return -1;
     }
 
   /* Check if subnet string is valid */
 
-  if(!(subnet = str2net(subnetstr)))
+  if(!(s = str2net(subnetstr)))
     {
-      syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
+      syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid subnet string"), c->name, c->hostname);
       return -1;
     }
 
-  /* Check if somebody tries to add a subnet of ourself */
-
-  if(!strcmp(name, myself->name))
-    {
-      syslog(LOG_ERR, _("Warning: got ADD_SUBNET from %s (%s) for ourself, restarting"),
-             cl->name, cl->hostname);
-      sighup = 1;
-      return 0;
-    }
-
   /* Check if the owner of the new subnet is in the connection list */
 
-  if(!(owner = lookup_id(name)))
+  if(!(owner = lookup_node(name)))
     {
       syslog(LOG_ERR, _("Got ADD_SUBNET for %s from %s (%s) which is not in our connection list"),
-             name, cl->name, cl->hostname);
+             name, c->name, c->hostname);
       return -1;
     }
 
   /* If everything is correct, add the subnet to the list of the owner */
 
-  subnet_add(owner, subnet);
+  subnet_add(owner, s);
 
   /* Tell the rest */
   
   for(node = connection_tree->head; node; node = node->next)
     {
-      p = (connection_t *)node->data;
-      if(p->status.active && p!= cl)
-        send_add_subnet(p, subnet);
+      other = (connection_t *)node->data;
+      if(other->status.active && other != c)
+        send_add_subnet(other, s);
     }
 cp
   return 0;
 }
 
-int send_del_subnet(connection_t *cl, subnet_t *subnet)
+int send_del_subnet(connection_t *c, subnet_t *s)
 {
   int x;
   char *netstr;
-  char *owner;
 cp
-  owner = subnet->owner->name;
-
-  x = send_request(cl, "%d %s %s", DEL_SUBNET, owner, netstr = net2str(subnet));
+  x = send_request(c, "%d %s %s", DEL_SUBNET, s->owner->name, netstr = net2str(s));
   free(netstr);
 cp
   return x;
 }
 
-int del_subnet_h(connection_t *cl)
+int del_subnet_h(connection_t *c)
 {
   char subnetstr[MAX_STRING_SIZE];
   char name[MAX_STRING_SIZE];
-  connection_t *owner, *p;
-  subnet_t *subnet;
+  node_t *owner;
+  connection_t *other;
+  subnet_t *s, *find;
   avl_node_t *node;
 cp
-  if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING, name, subnetstr) != 3)
+  if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING, name, subnetstr) != 3)
     {
-      syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s)"), cl->name, cl->hostname);
+      syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s)"), c->name, c->hostname);
       return -1;
     }
 
@@ -727,50 +746,47 @@ cp
 
   if(check_id(name))
     {
-      syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
+      syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid identity name"), c->name, c->hostname);
       return -1;
     }
 
   /* Check if subnet string is valid */
 
-  if(!(subnet = str2net(subnetstr)))
+  if(!(s = str2net(subnetstr)))
     {
-      syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
+      syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid subnet string"), c->name, c->hostname);
       return -1;
     }
 
-  free(subnetstr);
-  
-  /* Check if somebody tries to add a subnet of ourself */
-
-  if(!strcmp(name, myself->name))
-    {
-      syslog(LOG_ERR, _("Warning: got DEL_SUBNET from %s (%s) for ourself, restarting"),
-             cl->name, cl->hostname);
-      sighup = 1;
-      return 0;
-    }
-
   /* Check if the owner of the new subnet is in the connection list */
 
-  if(!(owner = lookup_id(name)))
+  if(!(owner = lookup_node(name)))
     {
       syslog(LOG_ERR, _("Got DEL_SUBNET for %s from %s (%s) which is not in our connection list"),
-             name, cl->name, cl->hostname);
+             name, c->name, c->hostname);
       return -1;
     }
 
   /* If everything is correct, delete the subnet from the list of the owner */
 
-  subnet_del(subnet);
+  find = lookup_subnet(owner, s);
+  
+  if(!find)
+    {
+      syslog(LOG_ERR, _("Got DEL_SUBNET for %s from %s (%s) which does not appear in his subnet tree"),
+             name, c->name, c->hostname);
+      return -1;
+    }
+  
+  subnet_del(owner, s);
 
   /* Tell the rest */
   
   for(node = connection_tree->head; node; node = node->next)
     {
-      p = (connection_t *)node->data;
-      if(p->status.active && p!= cl)
-        send_del_subnet(p, subnet);
+      other = (connection_t *)node->data;
+      if(other->status.active && other != c)
+        send_del_subnet(other, s);
     }
 cp
   return 0;
@@ -778,24 +794,25 @@ cp
 
 /* New and closed connections notification */
 
-int send_add_host(connection_t *cl, connection_t *other)
+int send_add_node(connection_t *c, node_t *n)
 {
 cp
-  return send_request(cl, "%d %s %lx:%d %lx %s", ADD_HOST,
-                      other->name, other->address, other->port, other->options, other->prevhop->name);
+  return send_request(c, "%d %s %lx:%d", ADD_NODE,
+                      n->name, n->address, n->port);
 }
 
-int add_host_h(connection_t *cl)
+int add_node_h(connection_t *c)
 {
-  connection_t *old, *new, *p;
-  char name[MAX_STRING_SIZE], prevhop[MAX_STRING_SIZE];
+  connection_t *other;
+  node_t *n;
+  char name[MAX_STRING_SIZE];
+  ipv4_t address;
+  port_t port;
   avl_node_t *node;
 cp
-  new = new_connection();
-
-  if(sscanf(cl->buffer, "%*d "MAX_STRING" %lx:%hd %lx "MAX_STRING, name, &new->address, &new->port, &new->options, prevhop) != 5)
+  if(sscanf(c->buffer, "%*d "MAX_STRING" %lx:%hd", name, &address, &port) != 3)
     {
-       syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s)"), cl->name, cl->hostname);
+       syslog(LOG_ERR, _("Got bad ADD_NODE from %s (%s)"), c->name, c->hostname);
        return -1;
     }
 
@@ -803,15 +820,7 @@ cp
 
   if(check_id(name))
     {
-      syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
-      free_connection(new);
-      return -1;
-    }
-
-  if(check_id(prevhop))
-    {
-      syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid prevhop name"), cl->name, cl->hostname);
-      free_connection(new);
+      syslog(LOG_ERR, _("Got bad ADD_NODE from %s (%s): invalid identity name"), c->name, c->hostname);
       return -1;
     }
 
@@ -819,94 +828,60 @@ cp
 
   if(!strcmp(name, myself->name))
     {
-      syslog(LOG_ERR, _("Got ADD_HOST from %s (%s) for ourself!"), cl->name, cl->hostname);
-      free_connection(new);
+      syslog(LOG_ERR, _("Got ADD_NODE from %s (%s) for ourself!"), c->name, c->hostname);
       return -1;
     }
     
-  /* Fill in more of the new connection structure */
-
-  new->hostname = hostlookup(htonl(new->address));
-
-  new->prevhop = lookup_id(prevhop);
+  /* Check if node already exists */
   
-  if(!new->prevhop)
+  n = lookup_node(name);
+  
+  if(n)
     {
-      syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): unknown prevhop"), cl->name, cl->hostname);
-      free_connection(new);
-      return -1;
+      /* Check if it matches */
     }
-
-  /* Check if the new host already exists in the connnection list */
-
-  if((old = lookup_id(name)))
+  else
     {
-      if((new->address == old->address) && (new->port == old->port) && (cl->nexthop == old->nexthop))
-        {
-          if(debug_lvl >= DEBUG_CONNECTIONS)
-            syslog(LOG_NOTICE, _("Got duplicate ADD_HOST for %s (%s) from %s (%s)"),
-                   old->name, old->hostname, cl->name, cl->hostname);
-          free_connection(new);
-          return 0;
-        }
-      else
-        {
-          if(debug_lvl >= DEBUG_CONNECTIONS)
-            syslog(LOG_NOTICE, _("Removing old entry for %s (%s) from %s in favour of new connection from %s"),
-                   old->name, old->hostname, old->nexthop->name, cl->nexthop->name);
-
-          terminate_connection(old, 0);
-        }
+      n = new_node();
+      n->name = xstrdup(name);
+      n->address = address;
+      n->port = port;
+      node_add(n);
     }
 
-  /* Hook it up into the active tree */
-
-  new->name = xstrdup(name);
-  active_add(new);
-
-  /* Tell the rest about the new host */
+  /* Tell the rest about the new node */
 
   for(node = connection_tree->head; node; node = node->next)
     {
-      p = (connection_t *)node->data;
-      if(p->status.active && p!=cl)
-        send_add_host(p, new);
+      other = (connection_t *)node->data;
+      if(other->status.active && other !=c)
+        send_add_node(other, n);
     }
 
-  /* Fill in rest of connection structure */
-
-  new->nexthop = cl;
-  new->cipher_pkttype = EVP_bf_cbc();
-  new->cipher_pktkeylength = cl->cipher_pkttype->key_len + cl->cipher_pkttype->iv_len;
-
-  if(new->options & OPTION_INDIRECT || new->prevhop->via != new->prevhop)
-    new->via = new->prevhop->via;
-  else
-    new->via = new;
 cp
   return 0;
 }
 
-int send_del_host(connection_t *cl, connection_t *other)
+int send_del_node(connection_t *c, node_t *n)
 {
 cp
-  return send_request(cl, "%d %s %lx:%d %lx %s", DEL_HOST,
-                      other->name, other->address, other->port, other->options, other->prevhop->name);
+  return send_request(c, "%d %s %lx:%d", DEL_NODE,
+                      n->name, n->address, n->port);
 }
 
-int del_host_h(connection_t *cl)
+int del_node_h(connection_t *c)
 {
-  char name[MAX_STRING_SIZE], prevhop[MAX_STRING_SIZE];
+  node_t *n;
+  char name[MAX_STRING_SIZE];
   ipv4_t address;
   port_t port;
-  long int options;
-  connection_t *old, *p;
+  connection_t *other;
   avl_node_t *node;
 cp
-  if(sscanf(cl->buffer, "%*d "MAX_STRING" %lx:%hd %lx "MAX_STRING, name, &address, &port, &options, prevhop) != 5)
+  if(sscanf(c->buffer, "%*d "MAX_STRING" %lx:%hd", name, &address, &port) != 3)
     {
-      syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s)"),
-             cl->name, cl->hostname);
+      syslog(LOG_ERR, _("Got bad DEL_NODE from %s (%s)"),
+             c->name, c->hostname);
       return -1;
     }
 
@@ -914,13 +889,7 @@ cp
 
   if(check_id(name))
     {
-      syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
-      return -1;
-    }
-
-  if(check_id(prevhop))
-    {
-      syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s): invalid prevhop name"), cl->name, cl->hostname);
+      syslog(LOG_ERR, _("Got bad DEL_NODE from %s (%s): invalid identity name"), c->name, c->hostname);
       return -1;
     }
 
@@ -928,142 +897,143 @@ cp
 
   if(!strcmp(name, myself->name))
     {
-      syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) for ourself!"),
-             cl->name, cl->hostname);
+      syslog(LOG_ERR, _("Got DEL_NODE from %s (%s) for ourself!"),
+             c->name, c->hostname);
       return -1;
     }
 
-  /* Check if the deleted host already exists in the connnection list */
+  /* Check if the deleted host exists */
 
-  if(!(old = lookup_id(name)))
+  n = lookup_node(name);
+
+  if(!n)
     {
-      syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) for %s which is not in our connection list"),
-             cl->name, cl->hostname, name);
-      return -1;
+      syslog(LOG_WARNING, _("Got DEL_NODE from %s (%s) for %s which does not exist"), c->name, c->hostname, n->name);
+      return 0;
     }
   
   /* Check if the rest matches */
   
-  if(address!=old->address || port!=old->port || options!=old->options || cl!=old->nexthop || strcmp(prevhop, old->prevhop->name))
+  if(address != n->address || port != n->port)
     {
-      syslog(LOG_WARNING, _("Got DEL_HOST from %s (%s) for %s which doesn't match"), cl->name, cl->hostname, old->name);
+      syslog(LOG_WARNING, _("Got DEL_NODE from %s (%s) for %s which doesn't match"), c->name, c->hostname, n->name);
       return 0;
     }
 
-  /* Ok, since EVERYTHING seems to check out all right, delete it */
-
-  terminate_connection(old, 0);
-
-  /* Tell the rest about the deleted host */
+  /* Tell the rest about the deleted node */
 
   for(node = connection_tree->head; node; node = node->next)
     {
-      p = (connection_t *)node->data;
-      if(p->status.active && p!=cl)
-        send_del_host(p, old);
+      other = (connection_t *)node->data;
+      if(other->status.active && other != c)
+        send_del_node(other, n);
     }
+
+  /* Delete the node */
+  
+  node_del(n);
 cp
   return 0;
 }
 
 /* Status and error notification routines */
 
-int send_status(connection_t *cl, int statusno, char *statusstring)
+int send_status(connection_t *c, int statusno, char *statusstring)
 {
 cp
   if(!statusstring)
     statusstring = status_text[statusno];
 cp
-  return send_request(cl, "%d %d %s", STATUS, statusno, statusstring);
+  return send_request(c, "%d %d %s", STATUS, statusno, statusstring);
 }
 
-int status_h(connection_t *cl)
+int status_h(connection_t *c)
 {
   int statusno;
   char statusstring[MAX_STRING_SIZE];
 cp
-  if(sscanf(cl->buffer, "%*d %d "MAX_STRING, &statusno, statusstring) != 2)
+  if(sscanf(c->buffer, "%*d %d "MAX_STRING, &statusno, statusstring) != 2)
     {
        syslog(LOG_ERR, _("Got bad STATUS from %s (%s)"),
-              cl->name, cl->hostname);
+              c->name, c->hostname);
        return -1;
     }
 
   if(debug_lvl >= DEBUG_STATUS)
     {
       syslog(LOG_NOTICE, _("Status message from %s (%s): %s: %s"),
-             cl->name, cl->hostname, status_text[statusno], statusstring);
+             c->name, c->hostname, status_text[statusno], statusstring);
     }
 
 cp
   return 0;
 }
 
-int send_error(connection_t *cl, int err, char *errstring)
+int send_error(connection_t *c, int err, char *errstring)
 {
 cp
   if(!errstring)
     errstring = strerror(err);
-  return send_request(cl, "%d %d %s", ERROR, err, errstring);
+  return send_request(c, "%d %d %s", ERROR, err, errstring);
 }
 
-int error_h(connection_t *cl)
+int error_h(connection_t *c)
 {
   int err;
   char errorstring[MAX_STRING_SIZE];
 cp
-  if(sscanf(cl->buffer, "%*d %d "MAX_STRING, &err, errorstring) != 2)
+  if(sscanf(c->buffer, "%*d %d "MAX_STRING, &err, errorstring) != 2)
     {
        syslog(LOG_ERR, _("Got bad ERROR from %s (%s)"),
-              cl->name, cl->hostname);
+              c->name, c->hostname);
        return -1;
     }
 
   if(debug_lvl >= DEBUG_ERROR)
     {
       syslog(LOG_NOTICE, _("Error message from %s (%s): %s: %s"),
-             cl->name, cl->hostname, strerror(err), errorstring);
+             c->name, c->hostname, strerror(err), errorstring);
     }
 
-  terminate_connection(cl, cl->status.meta);
+  terminate_connection(c, c->status.active);
 cp
   return 0;
 }
 
-int send_termreq(connection_t *cl)
+int send_termreq(connection_t *c)
 {
 cp
-  return send_request(cl, "%d", TERMREQ);
+  return send_request(c, "%d", TERMREQ);
 }
 
-int termreq_h(connection_t *cl)
+int termreq_h(connection_t *c)
 {
 cp
-  terminate_connection(cl, cl->status.meta);
+  terminate_connection(c, c->status.active);
 cp
   return 0;
 }
 
-int send_ping(connection_t *cl)
+int send_ping(connection_t *c)
 {
   char salt[SALTLEN*2+1];
 cp
-  cl->status.pinged = 1;
-  cl->last_ping_time = time(NULL);
+  c->status.pinged = 1;
+  c->last_ping_time = time(NULL);
   RAND_pseudo_bytes(salt, SALTLEN);
   bin2hex(salt, salt, SALTLEN);
   salt[SALTLEN*2] = '\0';
 cp
-  return send_request(cl, "%d %s", PING, salt);
+  return send_request(c, "%d %s", PING, salt);
 }
 
-int ping_h(connection_t *cl)
+int ping_h(connection_t *c)
 {
 cp
-  return send_pong(cl);
+  return send_pong(c);
 }
 
-int send_pong(connection_t *cl)
+int send_pong(connection_t *c)
 {
   char salt[SALTLEN*2+1];
 cp
   bin2hex(salt, salt, SALTLEN);
   salt[SALTLEN*2] = '\0';
 cp
-  return send_request(cl, "%d %s", PONG, salt);
+  return send_request(c, "%d %s", PONG, salt);
 }
 
-int pong_h(connection_t *cl)
+int pong_h(connection_t *c)
 {
 cp
-  cl->status.pinged = 0;
+  c->status.pinged = 0;
 cp
   return 0;
 }
 
 /* Key exchange */
 
-int send_key_changed(connection_t *from, connection_t *cl)
+int send_key_changed(connection_t *c, node_t *n)
 {
-  connection_t *p;
+  connection_t *other;
   avl_node_t *node;
 cp
   /* Only send this message if some other daemon requested our key previously.
      This reduces unnecessary key_changed broadcasts.
   */
 
-  if(from==myself && !mykeyused)
+  if(n == myself && !mykeyused)
     return 0;
 
   for(node = connection_tree->head; node; node = node->next)
     {
-      p = (connection_t *)node->data;
-      if(p != cl && p->status.active)
-        send_request(p, "%d %s", KEY_CHANGED, from->name);
+      other = (connection_t *)node->data;
+      if(other != c && other->status.active)
+        send_request(other, "%d %s", KEY_CHANGED, n->name);
     }
 cp
   return 0;
 }
 
-int key_changed_h(connection_t *cl)
+int key_changed_h(connection_t *c)
 {
-  char from_id[MAX_STRING_SIZE];
-  connection_t *from;
+  char name[MAX_STRING_SIZE];
+  node_t *n;
 cp
-  if(sscanf(cl->buffer, "%*d "MAX_STRING, from_id) != 1)
+  if(sscanf(c->buffer, "%*d "MAX_STRING, name) != 1)
     {
       syslog(LOG_ERR, _("Got bad KEY_CHANGED from %s (%s)"),
-             cl->name, cl->hostname);
+             c->name, c->hostname);
       return -1;
     }
 
-  if(!(from = lookup_id(from_id)))
+  n = lookup_node(name);
+
+  if(!n)
     {
-      syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list"),
-             cl->name, cl->hostname, from_id);
+      syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist"),
+             c->name, c->hostname, name);
       return -1;
     }
 
-  from->status.validkey = 0;
-  from->status.waitingforkey = 0;
+  n->status.validkey = 0;
+  n->status.waitingforkey = 0;
 
-  send_key_changed(from, cl);
+  send_key_changed(c, n);
 cp
   return 0;
 }
 
-int send_req_key(connection_t *from, connection_t *to)
+int send_req_key(connection_t *c, node_t *from, node_t *to)
 {
 cp
-  return send_request(to->nexthop, "%d %s %s", REQ_KEY,
+  return send_request(c, "%d %s %s", REQ_KEY,
                       from->name, to->name);
 }
 
-int req_key_h(connection_t *cl)
+int req_key_h(connection_t *c)
 {
-  char from_id[MAX_STRING_SIZE];
-  char to_id[MAX_STRING_SIZE];
-  connection_t *from, *to;
-  char pktkey[129];
+  char from_name[MAX_STRING_SIZE];
+  char to_name[MAX_STRING_SIZE];
+  node_t *from, *to;
+  char key[MAX_STRING_SIZE];
 cp
-  if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING, from_id, to_id) != 2)
+  if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING, from_name, to_name) != 2)
     {
        syslog(LOG_ERR, _("Got bad REQ_KEY from %s (%s)"),
-              cl->name, cl->hostname);
+              c->name, c->hostname);
        return -1;
     }
 
-  if(!(from = lookup_id(from_id)))
+  from = lookup_node(from_name);
+
+  if(!from)
     {
       syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) origin %s which does not exist in our connection list"),
-             cl->name, cl->hostname, from_id);
+             c->name, c->hostname, from_name);
+      return -1;
+    }
+
+  to = lookup_node(to_name);
+  
+  if(!to)
+    {
+      syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list"),
+             c->name, c->hostname, to_name);
       return -1;
     }
 
   /* Check if this key request is for us */
 
-  if(!strcmp(to_id, myself->name))     /* Yes, send our own key back */
+  if(to == myself)     /* Yes, send our own key back */
     {
-      bin2hex(myself->cipher_pktkey, pktkey, myself->cipher_pktkeylength);
-      pktkey[myself->cipher_pktkeylength*2] = '\0';
-      send_ans_key(myself, from, pktkey);
+      bin2hex(myself->key, key, myself->keylength);
+      key[myself->keylength * 2] = '\0';
+      send_ans_key(c, myself, from, key);
       mykeyused = 1;
     }
   else
     {
-      if(!(to = lookup_id(to_id)))
-        {
-          syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list"),
-                 cl->name, cl->hostname, to_id);
-          return -1;
-        }
-        
       if(to->status.validkey)  /* Proxy keys */
         {
-          bin2hex(to->cipher_pktkey, pktkey, to->cipher_pktkeylength);
-          pktkey[to->cipher_pktkeylength*2] = '\0';
-          send_ans_key(to, from, pktkey);
+          bin2hex(to->key, key, to->keylength);
+          key[to->keylength * 2] = '\0';
+          send_ans_key(c, to, from, key);
         }
       else
-        send_req_key(from, to);
+        send_req_key(to->nexthop->connection, from, to);
     }
 
 cp
   return 0;
 }
 
-int send_ans_key(connection_t *from, connection_t *to, char *pktkey)
+int send_ans_key(connection_t *c, node_t *from, node_t *to, char *key)
 {
 cp
-  return send_request(to->nexthop, "%d %s %s %s", ANS_KEY,
-                      from->name, to->name, pktkey);
+  return send_request(c, "%d %s %s %s", ANS_KEY,
+                      from->name, to->name, key);
 }
 
-int ans_key_h(connection_t *cl)
+int ans_key_h(connection_t *c)
 {
-  char from_id[MAX_STRING_SIZE];
-  char to_id[MAX_STRING_SIZE];
-  char pktkey[MAX_STRING_SIZE];
+  char from_name[MAX_STRING_SIZE];
+  char to_name[MAX_STRING_SIZE];
+  char key[MAX_STRING_SIZE];
   int keylength;
-  connection_t *from, *to;
+  node_t *from, *to;
 cp
-  if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING, from_id, to_id, pktkey) != 3)
+  if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING, from_name, to_name, key) != 3)
     {
        syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s)"),
-              cl->name, cl->hostname);
+              c->name, c->hostname);
        return -1;
     }
 
-  if(!(from = lookup_id(from_id)))
+  from = lookup_node(from_name);
+
+  if(!from)
     {
       syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) origin %s which does not exist in our connection list"),
-             cl->name, cl->hostname, from_id);
+             c->name, c->hostname, from_name);
+      return -1;
+    }
+
+  to = lookup_node(to_name);
+
+  if(!to)
+    {
+      syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list"),
+             c->name, c->hostname, to_name);
       return -1;
     }
 
   /* Check correctness of packet key */
 
-  keylength = strlen(pktkey);
+  keylength = strlen(key);
 
-  if(keylength != from->cipher_pktkeylength*2)
+  if(keylength != from->keylength * 2)
     {
       syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s) origin %s: invalid key length"),
-             cl->name, cl->hostname, from->name);
+             c->name, c->hostname, from->name);
       return -1;
     }
 
   /* Forward it if necessary */
 
-  if(strcmp(to_id, myself->name))
+  if(to != myself)
     {
-      if(!(to = lookup_id(to_id)))
-        {
-          syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list"),
-                 cl->name, cl->hostname, to_id);
-          return -1;
-        }
-      send_ans_key(from, to, pktkey);
+      send_ans_key(to->nexthop->connection, from, to, key);
     }
 
   /* Update our copy of the origin's packet key */
 
-  if(from->cipher_pktkey)
-    free(from->cipher_pktkey);
+  if(from->key)
+    free(from->key);
 
-  from->cipher_pktkey = xstrdup(pktkey);
+  from->key = xstrdup(key);
   keylength /= 2;
-  hex2bin(from->cipher_pktkey, from->cipher_pktkey, keylength);
-  from->cipher_pktkey[keylength] = '\0';
+  hex2bin(from->key, from->key, keylength);
+  from->key[keylength] = '\0';
 
   from->status.validkey = 1;
   from->status.waitingforkey = 0;
@@ -1264,33 +1245,33 @@ cp
   return 0;
 }
 
-int send_tcppacket(connection_t *cl, vpn_packet_t *packet)
+int send_tcppacket(connection_t *c, vpn_packet_t *packet)
 {
   int x;
 cp  
   /* Evil hack. */
 
-  x = send_request(cl->nexthop, "%d %hd", PACKET, packet->len);
+  x = send_request(c, "%d %hd", PACKET, packet->len);
 
   if(x)
     return x;
 cp
-  return send_meta(cl, packet->data, packet->len);
+  return send_meta(c, packet->data, packet->len);
 }
 
-int tcppacket_h(connection_t *cl)
+int tcppacket_h(connection_t *c)
 {
   short int len;
 cp  
-  if(sscanf(cl->buffer, "%*d %hd", &len) != 1)
+  if(sscanf(c->buffer, "%*d %hd", &len) != 1)
     {
-      syslog(LOG_ERR, _("Got bad PACKET from %s (%s)"), cl->name, cl->hostname);
+      syslog(LOG_ERR, _("Got bad PACKET from %s (%s)"), c->name, c->hostname);
       return -1;
     }
 
   /* Set reqlen to len, this will tell receive_meta() that a tcppacket is coming. */
 
-  cl->tcplen = len;
+  c->tcplen = len;
 cp
   return 0;
 }
@@ -1298,10 +1279,10 @@ cp
 /* Jumptable for the request handlers */
 
 int (*request_handlers[])(connection_t*) = {
-  id_h, metakey_h, challenge_h, chal_reply_h,
+  id_h, metakey_h, challenge_h, chal_reply_h, ack_h,
   status_h, error_h, termreq_h,
   ping_h, pong_h,
-  add_host_h, del_host_h,
+  add_node_h, del_node_h,
   add_subnet_h, del_subnet_h,
   key_changed_h, req_key_h, ans_key_h,
   tcppacket_h,
@@ -1310,11 +1291,12 @@ int (*request_handlers[])(connection_t*) = {
 /* Request names */
 
 char (*request_name[]) = {
-  "ID", "METAKEY", "CHALLENGE", "CHAL_REPLY",
+  "ID", "METAKEY", "CHALLENGE", "CHAL_REPLY", "ACK",
   "STATUS", "ERROR", "TERMREQ",
   "PING", "PONG",
-  "ADD_HOST", "DEL_HOST",
+  "ADD_NODE", "DEL_NODE",
   "ADD_SUBNET", "DEL_SUBNET",
+  "ADD_VERTEX", "DEL_VERTEX",
   "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
   "PACKET",
 };
index 0d163868782f59d28e2f47880898f38c0c1e68c0..64e17ad0d67840797145cdaaedd0d80bf410d59a 100644 (file)
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: protocol.h,v 1.5.4.22 2001/09/24 14:12:00 guus Exp $
+    $Id: protocol.h,v 1.5.4.23 2001/10/27 12:13:17 guus Exp $
 */
 
 #ifndef __TINC_PROTOCOL_H__
 #define __TINC_PROTOCOL_H__
 
 #include "net.h"
+#include "node.h"
 #include "subnet.h"
 
 /* Protocol version. Different versions are incompatible,
 
 enum {
   ALL = -1,                         /* Guardian for allow_request */
-  ID = 0, METAKEY, CHALLENGE, CHAL_REPLY,
+  ID = 0, METAKEY, CHALLENGE, CHAL_REPLY, ACK,
   STATUS, ERROR, TERMREQ,
-  PING,  PONG,
-  ADD_HOST, DEL_HOST,
+  PING, PONG,
+  ADD_NODE, DEL_NODE,
   ADD_SUBNET, DEL_SUBNET,
+  ADD_VERTEX, DEL_VERTEX,
   KEY_CHANGED, REQ_KEY, ANS_KEY,
   PACKET,
   LAST                               /* Guardian for the highest request number */
@@ -54,21 +56,24 @@ enum {
 extern int (*request_handlers[])(connection_t*);
 
 extern int send_id(connection_t*);
+extern int send_metakey(connection_t*);
 extern int send_challenge(connection_t*);
 extern int send_chal_reply(connection_t*);
-extern int send_metakey(connection_t*);
+extern int send_ack(connection_t*);
 extern int send_status(connection_t*, int, char*);
 extern int send_error(connection_t*, int, char*);
 extern int send_termreq(connection_t*);
 extern int send_ping(connection_t*);
 extern int send_pong(connection_t*);
-extern int send_add_host(connection_t*, connection_t*);
-extern int send_del_host(connection_t*, connection_t*);
+extern int send_add_node(connection_t*, node_t*);
+extern int send_del_node(connection_t*, node_t*);
 extern int send_add_subnet(connection_t*, subnet_t*);
 extern int send_del_subnet(connection_t*, subnet_t*);
-extern int send_key_changed(connection_t*, connection_t*);
-extern int send_req_key(connection_t*, connection_t*);
-extern int send_ans_key(connection_t*, connection_t*, char*);
+extern int send_add_vertex(connection_t*, node_t*);
+extern int send_del_vertex(connection_t*, node_t*);
+extern int send_key_changed(connection_t*, node_t*);
+extern int send_req_key(connection_t*, node_t*, node_t*);
+extern int send_ans_key(connection_t*, node_t*, node_t*, char*);
 extern int send_tcppacket(connection_t *, vpn_packet_t *);
 
 /* Old functions */
index dc91940ac8d3c47ec1188d6deb431cc9d9774207..c8de7a57a42f54aa2107857183ba13ac679ed423 100644 (file)
@@ -17,7 +17,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: route.c,v 1.1.2.18 2001/07/21 20:21:25 guus Exp $
+    $Id: route.c,v 1.1.2.19 2001/10/27 12:13:17 guus Exp $
 */
 
 #include "config.h"
@@ -56,7 +56,7 @@ void learn_mac(mac_t *address)
 {
   subnet_t *subnet;
   avl_node_t *node;
-  connection_t *p;
+  connection_t *c;
 cp
   subnet = lookup_subnet_mac(address);
 
@@ -77,14 +77,14 @@ cp
       
       for(node = connection_tree->head; node; node = node->next)
         {
-          p = (connection_t *)node->data;
-          if(p->status.active)
-            send_add_subnet(p, subnet);
+          c = (connection_t *)node->data;
+          if(c->status.active)
+            send_add_subnet(c, subnet);
         }
     }
 }
 
-connection_t *route_mac(vpn_packet_t *packet)
+node_t *route_mac(vpn_packet_t *packet)
 {
   subnet_t *subnet;
 cp
@@ -102,7 +102,7 @@ cp
     return NULL;
 }
 
-connection_t *route_ipv4(vpn_packet_t *packet)
+node_t *route_ipv4(vpn_packet_t *packet)
 {
   ipv4_t dest;
   subnet_t *subnet;
@@ -130,15 +130,26 @@ cp
   return subnet->owner;  
 }
 
-connection_t *route_ipv6(vpn_packet_t *packet)
+node_t *route_ipv6(vpn_packet_t *packet)
 {
+  ipv6_t dest;
+  subnet_t *subnet;
+cp
+  memcpy(&dest, &packet->data[30], sizeof(ipv6_t));
+
+  subnet = lookup_subnet_ipv6(&dest);
 cp
-  if(debug_lvl > DEBUG_NOTHING)
+  if(!subnet)
     {
-      syslog(LOG_WARNING, _("Cannot route packet: IPv6 routing not yet implemented"));
-    } 
+      if(debug_lvl >= DEBUG_TRAFFIC)
+        {
+          syslog(LOG_WARNING, _("Cannot route packet: unknown IPv6 destination address"));
+        }
+
+      return NULL;
+    }
 cp
-  return NULL;
+  return subnet->owner;  
 }
 
 void route_arp(vpn_packet_t *packet)
@@ -213,7 +224,7 @@ cp
 void route_outgoing(vpn_packet_t *packet)
 {
   unsigned short int type;
-  connection_t *cl;
+  node_t *n;
 cp
   /* FIXME: multicast? */
 
@@ -224,10 +235,10 @@ cp
         switch(type)
           {
             case 0x0800:
-              cl = route_ipv4(packet);
+              n = route_ipv4(packet);
               break;
             case 0x86DD:
-              cl = route_ipv6(packet);
+              n = route_ipv6(packet);
               break;
             case 0x0806:
               route_arp(packet);
@@ -239,14 +250,14 @@ cp
                 }
               return;
            }
-         if(cl)
-           send_packet(cl, packet);
+         if(n)
+           send_packet(n, packet);
          break;
         
       case RMODE_SWITCH:
-        cl = route_mac(packet);
-        if(cl)
-          send_packet(cl, packet);
+        n = route_mac(packet);
+        if(n)
+          send_packet(n, packet);
         else
           broadcast_packet(myself, packet);
         break;
@@ -257,7 +268,7 @@ cp
     }
 }
 
-void route_incoming(connection_t *source, vpn_packet_t *packet)
+void route_incoming(node_t *source, vpn_packet_t *packet)
 {
   switch(routing_mode)
     {
@@ -286,7 +297,7 @@ void route_incoming(connection_t *source, vpn_packet_t *packet)
           }
         break;
       case RMODE_HUB:
-        broadcast_packet(source,packet);                       /* Spread it on */
+        broadcast_packet(source, packet);                      /* Spread it on */
         accept_packet(packet);
         break;
     }
index 4eafc3b95ccaf62d502e3c509bc1fbc022a56300..4423e7242bec50e2ee8d023c4b2728facbd263c1 100644 (file)
@@ -17,7 +17,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: route.h,v 1.1.2.3 2001/03/04 13:59:32 guus Exp $
+    $Id: route.h,v 1.1.2.4 2001/10/27 12:13:17 guus Exp $
 */
 
 #ifndef __TINC_ROUTE_H__
@@ -31,9 +31,8 @@ enum
 };
 
 extern int routing_mode;
-extern subnet_t mymac;
 
-extern void route_incoming(connection_t *, vpn_packet_t *);
+extern void route_incoming(node_t *, vpn_packet_t *);
 extern void route_outgoing(vpn_packet_t *);
 
 #endif /* __TINC_ROUTE_H__ */
index cb9cbb75e345e12952f5ac384e1008d859733226..48ac45e272a26e3884965cb3ce7d5cf54b8648f9 100644 (file)
@@ -17,7 +17,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: subnet.c,v 1.1.2.24 2001/08/28 20:52:39 guus Exp $
+    $Id: subnet.c,v 1.1.2.25 2001/10/27 12:13:17 guus Exp $
 */
 
 #include "config.h"
@@ -28,7 +28,7 @@
 
 #include "conf.h"
 #include "net.h"
-#include "connection.h"
+#include "node.h"
 #include "subnet.h"
 #include "system.h"
 
@@ -51,8 +51,14 @@ cp
 
 int subnet_compare_mac(subnet_t *a, subnet_t *b)
 {
+  int result;
 cp
-  return memcmp(&a->net.mac.address, &b->net.mac.address, sizeof(mac_t));
+  result = memcmp(&a->net.mac.address, &b->net.mac.address, sizeof(mac_t));
+  
+  if(result)
+    return result;
+
+  return strcmp(a->owner->name, b->owner->name);
 }
 
 int subnet_compare_ipv4(subnet_t *a, subnet_t *b)
@@ -60,43 +66,36 @@ int subnet_compare_ipv4(subnet_t *a, subnet_t *b)
 cp
   /* We compare as if a subnet is a number that equals (address << 32 + netmask). */
    
-  if(a->net.ipv4.address == b->net.ipv4.address)
-  {
-    if(a->net.ipv4.mask < b->net.ipv4.mask)
-      return -1;
-    else if(a->net.ipv4.mask > b->net.ipv4.mask)
-      return 1;
-    else
-      return 0;
-  }
-  else
-  {
-    if(a->net.ipv4.address < b->net.ipv4.address)
-      return -1;
-    else if(a->net.ipv4.address > b->net.ipv4.address)
-      return 1;
-    else
-      return 0;
-  }
+  if(a->net.ipv4.address < b->net.ipv4.address)
+    return -1;
+  else if(a->net.ipv4.address > b->net.ipv4.address)
+    return 1;
+
+  if(a->net.ipv4.mask < b->net.ipv4.mask)
+    return -1;
+  else if(a->net.ipv4.mask > b->net.ipv4.mask)
+    return 1;
+
+  return strcmp(a->owner->name, b->owner->name);
 }
 
 int subnet_compare_ipv6(subnet_t *a, subnet_t *b)
 {
+  int result;
 cp
   /* Same as ipv4 case, but with nasty 128 bit addresses */
   
-  if(memcmp(&a->net.ipv6.mask, &b->net.ipv6.mask, sizeof(ipv6_t)) > 0)
-    if((a->net.ipv6.address.x[0] & b->net.ipv6.mask.x[0]) == b->net.ipv6.address.x[0] &&
-       (a->net.ipv6.address.x[1] & b->net.ipv6.mask.x[1]) == b->net.ipv6.address.x[1] &&
-       (a->net.ipv6.address.x[2] & b->net.ipv6.mask.x[2]) == b->net.ipv6.address.x[2] &&
-       (a->net.ipv6.address.x[3] & b->net.ipv6.mask.x[3]) == b->net.ipv6.address.x[3] &&
-       (a->net.ipv6.address.x[4] & b->net.ipv6.mask.x[4]) == b->net.ipv6.address.x[4] &&
-       (a->net.ipv6.address.x[5] & b->net.ipv6.mask.x[5]) == b->net.ipv6.address.x[5] &&
-       (a->net.ipv6.address.x[6] & b->net.ipv6.mask.x[6]) == b->net.ipv6.address.x[6] &&
-       (a->net.ipv6.address.x[7] & b->net.ipv6.mask.x[7]) == b->net.ipv6.address.x[7])
-      return -1;
+  result = memcmp(a->net.ipv6.address.x, b->net.ipv6.address.x, sizeof(ipv6_t));
+  
+  if(result)
+    return result;
+
+  result = memcmp(a->net.ipv6.mask.x, b->net.ipv6.mask.x, sizeof(ipv6_t));
   
-  return memcmp(&a->net.ipv6.address, &b->net.ipv6.address, sizeof(ipv6_t));
+  if(result)
+    return result;
+
+  return strcmp(a->owner->name, b->owner->name);
 }
 
 int subnet_compare(subnet_t *a, subnet_t *b)
@@ -138,37 +137,21 @@ cp
 
 /* Linked list management */
 
-void subnet_add(connection_t *cl, subnet_t *subnet)
+void subnet_add(node_t *n, subnet_t *subnet)
 {
 cp
-  subnet->owner = cl;
+  subnet->owner = n;
 
-  while(!avl_insert(subnet_tree, subnet))
-    {
-      subnet_t *old;
-      
-      old = (subnet_t *)avl_search(subnet_tree, subnet);
-
-      if(debug_lvl >= DEBUG_PROTOCOL)
-        {
-          char *subnetstr;
-          subnetstr = net2str(subnet);
-          syslog(LOG_WARNING, _("Duplicate subnet %s for %s (%s), previous owner %s (%s)!"),
-                 subnetstr, cl->name, cl->hostname, old->owner->name, old->owner->hostname);
-          free(subnetstr);
-        }
-
-      subnet_del(old);
-    }
-
-  avl_insert(cl->subnet_tree, subnet);
+  avl_insert(subnet_tree, subnet);
+cp
+  avl_insert(n->subnet_tree, subnet);
 cp
 }
 
-void subnet_del(subnet_t *subnet)
+void subnet_del(node_t *n, subnet_t *subnet)
 {
 cp
-  avl_delete(subnet->owner->subnet_tree, subnet);
+  avl_delete(n->subnet_tree, subnet);
 cp
   avl_delete(subnet_tree, subnet);
 cp
@@ -285,6 +268,12 @@ cp
 
 /* Subnet lookup routines */
 
+subnet_t *lookup_subnet(node_t *owner, subnet_t *subnet)
+{
+cp  
+  return avl_search(owner->subnet_tree, subnet);
+}
+
 subnet_t *lookup_subnet_mac(mac_t *address)
 {
   subnet_t subnet, *p;
index 2659386e0c2f9bdcfdea48a723eee6e779efc4ed..5969301900745dd494371b4dd3c49ce2062b183d 100644 (file)
@@ -17,7 +17,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: subnet.h,v 1.1.2.10 2001/01/08 21:32:30 guus Exp $
+    $Id: subnet.h,v 1.1.2.11 2001/10/27 12:13:17 guus Exp $
 */
 
 #ifndef __TINC_SUBNET_H__
@@ -50,9 +50,11 @@ typedef struct subnet_ipv6_t
   ipv6_t mask;
 } subnet_ipv6_t;
 
+#include "node.h"
+
 typedef struct subnet_t {
-  struct connection_t *owner;          /* the owner of this subnet */
-  struct connection_t *uplink;         /* the uplink which we should send packets to for this subnet */
+  struct node_t *owner;                        /* the owner of this subnet */
+  struct node_t *uplink;               /* the uplink which we should send packets to for this subnet */
 
   int type;                            /* subnet type (IPv4? IPv6? MAC? something even weirder?) */
 
@@ -65,18 +67,17 @@ typedef struct subnet_t {
       subnet_ipv6_t ipv6;
     } net;
     
-} subnet_t;  
-
-#include "connection.h"
+} subnet_t;
 
 extern subnet_t *new_subnet(void);
 extern void free_subnet(subnet_t *);
 extern void init_subnets(void);
-extern void subnet_add(struct connection_t *, subnet_t *);
-extern void subnet_del(subnet_t *);
+extern void subnet_add(struct node_t *, subnet_t *);
+extern void subnet_del(struct node_t *, subnet_t *);
 extern char *net2str(subnet_t *);
 extern subnet_t *str2net(char *);
 extern int subnet_compare(subnet_t *, subnet_t *);
+extern subnet_t *lookup_subnet(struct node_t *, subnet_t *);
 extern subnet_t *lookup_subnet_mac(mac_t *);
 extern subnet_t *lookup_subnet_ipv4(ipv4_t *);
 extern subnet_t *lookup_subnet_ipv6(ipv6_t *);
index 8eeef1d3df8c7120ded020b87bce206cdf72615c..b790d7a14075fee88e28f8ae1105bfc3356ec667 100644 (file)
@@ -17,7 +17,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: tincd.c,v 1.10.4.52 2001/09/01 12:36:53 guus Exp $
+    $Id: tincd.c,v 1.10.4.53 2001/10/27 12:13:17 guus Exp $
 */
 
 #include "config.h"
@@ -205,7 +205,7 @@ int keygen(int bits)
 {
   RSA *rsa_key;
   FILE *f;
-  config_t const *cfg;
+  char *name = NULL;
   char *filename;
 
   fprintf(stderr, _("Generating %d bits keys:\n"), bits);
@@ -219,8 +219,10 @@ int keygen(int bits)
   else
     fprintf(stderr, _("Done.\n"));
 
-  if(config && (cfg = get_config_val(config, config_name)))
-    asprintf(&filename, "%s/hosts/%s", confbase, cfg->data.ptr);
+  get_config_string(lookup_config(config_tree, "Name"), &name);
+
+  if(name)
+    asprintf(&filename, "%s/hosts/%s", confbase, name);
   else
     asprintf(&filename, "%s/rsa_key.pub", confbase);
 
@@ -350,8 +352,8 @@ cp
 
       if(do_detach)
         {
-          syslog(LOG_NOTICE, _("Restarting in %d seconds!"), MAXTIMEOUT);
-          sleep(MAXTIMEOUT);
+          syslog(LOG_NOTICE, _("Restarting in %d seconds!"), maxtimeout);
+          sleep(maxtimeout);
         }
       else
         {
index 54da87201a88de0e813de7689bcf2c395d0d74e3..4f0b5d6e80eba97e4348fbbb2b51aa156234ee1c 100644 (file)
@@ -17,7 +17,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: vertex.c,v 1.1.2.1 2001/10/10 08:49:47 guus Exp $
+    $Id: vertex.c,v 1.1.2.2 2001/10/27 12:13:17 guus Exp $
 */
 
 #include "config.h"
@@ -44,7 +44,7 @@ avl_tree_t *connection_tree;    /* Tree with all meta connections with ourself *
 
 int connection_compare(connection_t *a, connection_t *b)
 {
-  return a->meta_socket - b->meta_socket;
+  return a->socket - b->socket;
 }
 
 int vertex_compare(vertex_t *a, vertex_t *b)
@@ -97,29 +97,38 @@ cp
 void free_vertex(vertex_t *v)
 {
 cp
-  if(v->from.hostname)
-    free(v->from.hostname)
-  if(v->to.hostname)
-    free(v->to.hostname)
-
   free(v);
 cp
 }
 
+void vertex_add(vertex_t *v)
+{
+cp
+  avl_insert(vertex_tree, v);
+cp
+}
+
+void vertex_del(vertex_t *v)
+{
+cp
+  avl_delete(vertex_tree, v);
+cp
+}
+
 vertex_t *lookup_vertex(node_t *from, node_t *to)
 {
   vertex_t v, *result;
 cp
-  v.from.node = from;
-  v.to.node = to;
+  v.from = from;
+  v.to = to;
 
   result = avl_search(vertex_tree, &v);
 
   if(result)
     return result;
 cp
-  v.from.node = to;
-  v.to.node = from;
+  v.from = to;
+  v.to = from;
 
   return avl_search(vertex_tree, &v);
 }
@@ -135,7 +144,7 @@ cp
     {
       v = (vertex_t *)node->data;
       syslog(LOG_DEBUG, _(" %s - %s options %ld"),
-             v->from.node->name, v->to.node->name, v->options);
+             v->from->name, v->to->name, v->options);
     }
     
   syslog(LOG_DEBUG, _("End of vertices."));
index 9b1ef2b99cfd495a337df7ff81e1d6c7a2d833e7..b967a2ed30763d3f96b52d1252eb3e04041dae7b 100644 (file)
@@ -17,7 +17,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: vertex.h,v 1.1.2.4 2001/10/10 20:35:10 guus Exp $
+    $Id: vertex.h,v 1.1.2.5 2001/10/27 12:13:17 guus Exp $
 */
 
 #ifndef __TINC_VERTEX_H__
@@ -28,6 +28,8 @@
 #include "node.h"
 #include "connection.h"
 
+/* I don't know if halfconnection_t is useful... */
+
 typedef struct halfconnection_t {
   struct node_t *node;             /* node associated with this end of the connection */
 
@@ -37,8 +39,8 @@ typedef struct halfconnection_t {
 } halfconnection_t;
 
 typedef struct vertex_t {
-  struct halfconnection_t from;
-  struct halfconnection_t to;
+  struct node_t *from;
+  struct node_t *to;
 
   long int options;                /* options turned on for this connection */
   int metric;                      /* weight of this vertex */
@@ -48,4 +50,13 @@ typedef struct vertex_t {
 
 extern avl_tree_t *vertex_tree;    /* Tree with all known vertices (replaces active_tree) */
 
+extern void init_vertices(void);
+extern void exit_vertices(void);
+extern vertex_t *new_vertex(void);
+extern void free_vertex(vertex_t *);
+extern void vertex_add(vertex_t *);
+extern void vertex_del(vertex_t *);
+extern vertex_t *lookup_vertex(struct node_t *, struct node_t *);
+extern void dump_vertices(void);
+
 #endif /* __TINC_VERTEX_H__ */