Move all source code to src/. 2.0
authorGuus Sliepen <guus@tinc-vpn.org>
Fri, 15 Dec 2006 14:05:26 +0000 (14:05 +0000)
committerGuus Sliepen <guus@tinc-vpn.org>
Fri, 15 Dec 2006 14:05:26 +0000 (14:05 +0000)
81 files changed:
cfg/Makefile.am [deleted file]
cfg/cfg.c [deleted file]
cfg/cfg.h [deleted file]
logger/Makefile.am [deleted file]
logger/log.h [deleted file]
logger/logger.c [deleted file]
logger/logger.h [deleted file]
process.c [deleted file]
rt/Makefile.am [deleted file]
rt/README [deleted file]
rt/edge.c [deleted file]
rt/edge.h [deleted file]
rt/graph.c [deleted file]
rt/graph.h [deleted file]
rt/node.c [deleted file]
rt/node.h [deleted file]
rt/route.c [deleted file]
rt/route.h [deleted file]
rt/rt.c [deleted file]
rt/rt.h [deleted file]
rt/subnet.c [deleted file]
rt/subnet.h [deleted file]
src/avl.c [new file with mode: 0644]
src/avl.h [new file with mode: 0644]
src/cfg.c [new file with mode: 0644]
src/cfg.h [new file with mode: 0644]
src/edge.c [new file with mode: 0644]
src/edge.h [new file with mode: 0644]
src/ethernet.h [new file with mode: 0644]
src/gettext.h [new file with mode: 0644]
src/graph.c [new file with mode: 0644]
src/graph.h [new file with mode: 0644]
src/ipv4.h [new file with mode: 0644]
src/ipv6.h [new file with mode: 0644]
src/list.c [new file with mode: 0644]
src/list.h [new file with mode: 0644]
src/log.h [new file with mode: 0644]
src/logger.c [new file with mode: 0644]
src/logger.h [new file with mode: 0644]
src/node.c [new file with mode: 0644]
src/node.h [new file with mode: 0644]
src/process.c [new file with mode: 0644]
src/route.c [new file with mode: 0644]
src/route.h [new file with mode: 0644]
src/rt.c [new file with mode: 0644]
src/rt.h [new file with mode: 0644]
src/sockaddr.h [new file with mode: 0644]
src/subnet.c [new file with mode: 0644]
src/subnet.h [new file with mode: 0644]
src/system.h [new file with mode: 0644]
src/test.c [new file with mode: 0644]
src/tincd.c [new file with mode: 0644]
src/tincd.h [new file with mode: 0644]
src/tnl.c [new file with mode: 0644]
src/tnl.h [new file with mode: 0644]
src/vnd.c [new file with mode: 0644]
src/vnd.h [new file with mode: 0644]
src/xalloc.c [new file with mode: 0644]
src/xalloc.h [new file with mode: 0644]
support/Makefile.am [deleted file]
support/avl.c [deleted file]
support/avl.h [deleted file]
support/ethernet.h [deleted file]
support/gettext.h [deleted file]
support/ipv4.h [deleted file]
support/ipv6.h [deleted file]
support/list.c [deleted file]
support/list.h [deleted file]
support/sockaddr.h [deleted file]
support/xalloc.c [deleted file]
support/xalloc.h [deleted file]
system.h [deleted file]
tincd.c [deleted file]
tincd.h [deleted file]
tnl/Makefile.am [deleted file]
tnl/test.c [deleted file]
tnl/tnl.c [deleted file]
tnl/tnl.h [deleted file]
vnd/Makefile.am [deleted file]
vnd/vnd.c [deleted file]
vnd/vnd.h [deleted file]

diff --git a/cfg/Makefile.am b/cfg/Makefile.am
deleted file mode 100644 (file)
index 49d353a..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-noinst_LIBRARIES = libcfg.a
-
-noinst_HEADERS = cfg.h
-
-libcfg_a_SOURCES = cfg.c
-
diff --git a/cfg/cfg.c b/cfg/cfg.c
deleted file mode 100644 (file)
index f0c8dad..0000000
--- a/cfg/cfg.c
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
-    cfg.c -- cfguration code
-
-    Copyright (C) 1998 Robert van der Meulen
-                  1998-2004 Ivo Timmermans <ivo@tinc-vpn.org>
-                  2000-2004 Guus Sliepen <guus@tinc-vpn.org>
-                 2000 Cris van Pelt <tribbel@arise.dhs.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#include "system.h"
-
-#include "cfg/cfg.h"
-#include "support/avl.h"
-#include "support/xalloc.h"
-
-static int cfg_compare(const cfg_t *a, const cfg_t *b) {
-       return strcasecmp(a->variable, b->variable) ?: (a->line - b->line) ?: strcmp(a->file, b->file);
-}
-
-avl_tree_t *cfg_tree_new(void) {
-       return avl_tree_new((avl_compare_t)cfg_compare, (avl_action_t)cfg_free);
-}
-
-void cfg_tree_del(avl_tree_t *cfgs) {
-       avl_tree_del(cfgs);
-}
-
-cfg_t *cfg_new(void) {
-       cfg_t *cfg;
-
-       return clear(new(cfg));
-}
-
-void cfg_free(cfg_t *cfg) {
-       replace(cfg->variable, NULL);
-       replace(cfg->value, NULL);
-       replace(cfg->file, NULL);
-       free(cfg);
-}
-
-void cfg_add(avl_tree_t *cfgs, cfg_t *cfg) {
-       avl_add(cfgs, cfg);
-}
-
-cfg_t *cfg_get(const avl_tree_t *cfgs, char *variable) {
-       cfg_t search, *cfg;
-
-       search.variable = variable;
-       search.file = "";
-       search.line = 0;
-
-       cfg = avl_get_closest_greater(cfgs, &search);
-
-       if(!cfg || strcasecmp(cfg->variable, variable))
-               return NULL;
-
-       return cfg;
-}
-
-cfg_t *cfg_get_next(const avl_tree_t *cfgs, const cfg_t *cfg) {
-       avl_node_t *avl;
-       cfg_t *next;
-
-       avl = avl_get_node(cfgs, cfg);
-
-       if(avl && avl->next) {
-               next = avl->next->data;
-
-               if(!strcasecmp(next->variable, cfg->variable))
-                       return next;
-       }
-
-       return NULL;
-}
-
-bool cfg_bool(const cfg_t *cfg, const bool def, bool *result) {
-       if(!cfg) {
-               *result = def;
-               return true;
-       }
-
-       if(!strcasecmp(cfg->value, "yes")) {
-               *result = true;
-               return true;
-       } else if(!strcasecmp(cfg->value, "no")) {
-               *result = false;
-               return true;
-       }
-
-       logger(LOG_ERR, _("cfg: \"yes\" or \"no\" expected for configuration variable %s in %s line %d"),
-                       cfg->variable, cfg->file, cfg->line);
-
-       return false;
-}
-
-bool cfg_int(const cfg_t *cfg, const int def, int *result) {
-       if(!cfg) {
-               *result = def;
-               return true;
-       }
-
-       if(sscanf(cfg->value, "%d", result) == 1)
-               return true;
-
-       logger(LOG_ERR, _("cfg: integer expected for configuration variable %s in %s line %d"),
-                  cfg->variable, cfg->file, cfg->line);
-
-       return false;
-}
-
-bool cfg_string(const cfg_t *cfg, const char *def, char **result) {
-       if(!cfg) {
-               *result = def ? xstrdup(def) : NULL;
-               return true;
-       }
-
-       *result = xstrdup(cfg->value);
-
-       return true;
-}
-
-bool cfg_choice(const cfg_t *cfg, const cfg_choice_t *choice, const int def, int *result) {
-       int i;
-       
-       if(!cfg) {
-               *result = def;
-               return true;
-       }
-
-       for(i = 0; choice[i].key; i++) {
-               if(!strcasecmp(cfg->variable, choice[i].key)) {
-                       *result = choice[i].value;
-                       return true;
-               }
-       }
-
-       logger(LOG_ERR, _("cfg: invalid choice for configuration variable %s in %s line %d"), 
-                       cfg->variable, cfg->file, cfg->line);
-
-       return false;
-}      
-
-bool cfg_period(const cfg_t *cfg, const int def, int *result) {
-       char unit;
-       
-       if(!cfg) {
-               *result = def;
-               return true;
-       }
-
-       if(sscanf(cfg->value, "%d%c", result, &unit) == 2) {
-               switch(unit) {
-                       case 's':
-                               break;
-                       case 'm':
-                               *result *= 60;
-                               break;
-                       case 'h':
-                               *result *= 60 * 60;
-                               break;
-                       case 'd':
-                               *result *= 60 * 60 * 24;
-                               break;
-                       case 'W':
-                               *result *= 60 * 60 * 24 * 7;
-                               break;
-                       case 'M':
-                               *result *= 60 * 60 * 24 * 30;
-                               break;
-                       case 'Y':
-                               *result *= 60 * 60 * 24 * 365;
-                               break;
-                       default:
-                               logger(LOG_ERR, _("cfg: invalid period for configuration variable %s in %s line %d"),
-                                               cfg->variable, cfg->file, cfg->line);
-                               return false;
-               }
-               return true;
-       }
-
-       if(sscanf(cfg->value, "%d", result) == 1)
-               return true;
-
-       logger(LOG_ERR, _("cfg: period expected for configuration variable %s in %s line %d"),
-                       cfg->variable, cfg->file, cfg->line);
-
-       return false;
-}
-
-static char *readline(FILE *fp, char **buf, size_t *buflen) {
-       char *newline = NULL;
-       char *p;
-       char *line;                                     /* The array that contains everything that has been read so far */
-       char *idx;                                      /* Read into this pointer, which points to an offset within line */
-       size_t size, newsize;                           /* The size of the current array pointed to by line */
-       size_t maxlen;                                  /* Maximum number of characters that may be read with fgets.  This is newsize - oldsize. */
-
-       if(feof(fp))
-               return NULL;
-
-       if(buf && buflen) {
-               size = *buflen;
-               line = *buf;
-       } else {
-               dim(line, size = 100);
-       }
-
-       maxlen = size;
-       idx = line;
-       *idx = 0;
-
-       for(;;) {
-               errno = 0;
-               p = fgets(idx, maxlen, fp);
-
-               if(!p) {
-                       if(feof(fp))
-                               break;
-
-                       logger(LOG_ERR, _("cfg: error while reading: %s"), strerror(errno));
-                       free(line);
-                       return NULL;
-               }
-
-               newline = strchr(p, '\n');
-
-               if(!newline) {
-                       idx = &line[size - 1];
-                       maxlen = size + 1;
-                       redim(line, size *= 2);
-               } else {
-                       *newline = '\0';
-                       break;
-               }
-       }
-
-       if(buf && buflen) {
-               *buflen = size;
-               *buf = line;
-       }
-
-       return line;
-}
-
-bool cfg_read_file(avl_tree_t *cfgs, const char *fname) {
-       FILE *fp;
-       char *buffer, *line;
-       char *variable, *value;
-       int lineno = 0;
-       int len;
-       bool result = false;
-       bool ignore = false;
-       cfg_t *cfg;
-       size_t bufsize;
-
-       fp = fopen(fname, "r");
-
-       if(!fp) {
-               logger(LOG_ERR, _("cfg: error opening %s: %s"), fname, strerror(errno));
-               return false;
-       }
-
-       dim(buffer, bufsize = 100);
-
-       for(;;) {
-               line = readline(fp, &buffer, &bufsize);
-
-               if(!line)
-                       break;
-
-               if(feof(fp)) {
-                       result = true;
-                       break;
-               }
-
-               lineno++;
-
-               if(!*line || *line == '#')
-                       continue;
-
-               if(ignore) {
-                       if(!strncmp(line, "-----END", 8))
-                               ignore = false;
-                       continue;
-               }
-               
-               if(!strncmp(line, "-----BEGIN", 10)) {
-                       ignore = true;
-                       continue;
-               }
-
-               variable = value = line;
-
-               len = strcspn(value, "\t =");
-               value += len;
-               value += strspn(value, "\t ");
-               if(*value == '=') {
-                       value++;
-                       value += strspn(value, "\t ");
-               }
-               variable[len] = '\0';
-
-               if(!*value) {
-                       logger(LOG_ERR, _("cfg: no value for variable %s on line %d while reading cfg file %s"),
-                                       variable, lineno, fname);
-                       break;
-               }
-
-               cfg = cfg_new();
-               replace(cfg->variable, variable);
-               replace(cfg->value, value);
-               replace(cfg->file, fname);
-               cfg->line = lineno;
-
-               cfg_add(cfgs, cfg);
-       }
-
-       free(buffer);
-       fclose(fp);
-
-       return result;
-}
diff --git a/cfg/cfg.h b/cfg/cfg.h
deleted file mode 100644 (file)
index bbc0139..0000000
--- a/cfg/cfg.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
-    conf.h -- header for conf.c
-
-    Copyright (C) 1998-2004 Ivo Timmermans <ivo@tinc-vpn.org>
-                  2000-2004 Guus Sliepen <guus@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#ifndef __TINC_CONF_H__
-#define __TINC_CONF_H__
-
-#include "support/avl.h"
-
-typedef struct cfg {
-       char *variable;
-       char *value;
-       char *file;
-       int line;
-} cfg_t;
-
-typedef struct cfg_choice {
-       char *key;
-       int value;
-} cfg_choice_t;
-
-extern avl_tree_t *cfgs;
-
-extern avl_tree_t *cfg_tree_new(void);
-extern void cfg_tree_free(avl_tree_t *);
-extern cfg_t *cfg_new(void) __attribute__ ((__malloc__));
-extern void cfg_free(cfg_t *);
-extern void cfg_add(avl_tree_t *, cfg_t *);
-extern void cfg_del(avl_tree_t *, cfg_t *);
-extern cfg_t *cfg_get(const avl_tree_t *, char *);
-extern cfg_t *cfg_get_next(const avl_tree_t *, const cfg_t *);
-extern bool cfg_bool(const cfg_t *, const bool, bool *);
-extern bool cfg_int(const cfg_t *, const int, int *);
-extern bool cfg_string(const cfg_t *, const char *, char **);
-extern bool cfg_choice(const cfg_t *, const cfg_choice_t *, const int, int *);
-extern bool cfg_period(const cfg_t *, const int, int *);
-#define cfg_get_bool(tree, var, def, result) cfg_bool(cfg_get(tree, var), def, result)
-#define cfg_get_int(tree, var, def, result) cfg_int(cfg_get(tree, var), def, result)
-#define cfg_get_string(tree, var, def, result) cfg_string(cfg_get(tree, var), def, result)
-#define cfg_get_choice(tree, var, choice, def, result) cfg_choice(cfg_get(tree, var), choice, def, (int *)result)
-#define cfg_get_period(tree, var, def, result) cfg_period(cfg_get(tree, var), def, (int *)result)
-
-extern bool cfg_read_file(avl_tree_t *, const char *);
-
-#endif
diff --git a/logger/Makefile.am b/logger/Makefile.am
deleted file mode 100644 (file)
index 6fe3047..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-noinst_LIBRARIES = liblogger.a
-
-noinst_HEADERS = logger.h
-
-liblogger_a_SOURCES = logger.c
-
diff --git a/logger/log.h b/logger/log.h
deleted file mode 100644 (file)
index e178d69..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
-    log.h -- logging
-
-    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#ifndef __LOGGER_H__
-#define __LOGGER_H__
-
-typedef enum debug_t {
-       DEBUG_NOTHING = 0,                      /* Quiet mode, only show starting/stopping of the daemon */
-       DEBUG_ALWAYS = 0,
-       DEBUG_CONNECTIONS = 1,          /* Show (dis)connects of other tinc daemons via TCP */
-       DEBUG_ERROR = 2,                        /* Show error messages received from other hosts */
-       DEBUG_STATUS = 2,                       /* Show status messages received from other hosts */
-       DEBUG_PROTOCOL = 3,                     /* Show the requests that are sent/received */
-       DEBUG_META = 4,                         /* Show contents of every request that is sent/received */
-       DEBUG_TRAFFIC = 5,                      /* Show network traffic information */
-       DEBUG_PACKET = 6,                       /* Show contents of each packet that is being sent/received */
-       DEBUG_SCARY_THINGS = 10         /* You have been warned */
-} debug_t;
-
-typedef enum logmode_t {
-       LOGMODE_NULL,
-       LOGMODE_STDERR,
-       LOGMODE_FILE,
-       LOGMODE_SYSLOG
-} logmode_t;
-
-#ifdef HAVE_MINGW
-#define LOG_EMERG EVENTLOG_ERROR_TYPE
-#define LOG_ALERT EVENTLOG_ERROR_TYPE
-#define LOG_CRIT EVENTLOG_ERROR_TYPE
-#define LOG_ERR EVENTLOG_ERROR_TYPE
-#define LOG_WARNING EVENTLOG_WARNING_TYPE
-#define LOG_NOTICE EVENTLOG_INFORMATION_TYPE
-#define LOG_INFO EVENTLOG_INFORMATION_TYPE
-#define LOG_DEBUG EVENTLOG_INFORMATION_TYPE
-#else
-#ifndef HAVE_SYSLOG_H
-enum {
-       LOG_EMERG,
-       LOG_ALERT,
-       LOG_CRIT,
-       LOG_ERR,
-       LOG_WARNING,
-       LOG_NOTICE,
-       LOG_INFO,
-       LOG_DEBUG,
-};
-#endif
-#endif
-
-extern debug_t debug_level;
-extern void openlogger(const char *, logmode_t);
-extern void logger(int, const char *, ...) __attribute__ ((__format__(printf, 2, 3)));
-extern void closelogger(void);
-
-#define ifdebug(l) if(debug_level >= DEBUG_##l)
-
-#endif /* __LOGGER_H__ */
diff --git a/logger/logger.c b/logger/logger.c
deleted file mode 100644 (file)
index 9bbd8fe..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
-    logger.c -- logging
-
-    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#include "system.h"
-
-#include "logger/logger.h"
-
-logger_level_t logger_level = LOGGER_LEVEL_NONE;
-
-static logger_mode_t logger_mode = LOGGER_MODE_STDERR;
-static pid_t logger_pid;
-char *logger_filename;
-static FILE *logger_file = NULL;
-#ifdef HAVE_MINGW
-static HANDLE logger_handle = NULL;
-#endif
-static const char *logger_ident = NULL;
-
-bool logger_init(const char *ident, logger_mode_t mode) {
-       logger_ident = ident;
-       logger_mode = mode;
-       
-       switch(mode) {
-               case LOGGER_MODE_STDERR:
-                       logger_pid = getpid();
-                       break;
-               case LOGGER_MODE_FILE:
-                       logger_pid = getpid();
-                       logger_file = fopen(logger_filename, "a");
-                       if(!logger_file)
-                               logger_mode = LOGGER_MODE_NULL;
-                       break;
-               case LOGGER_MODE_SYSLOG:
-#ifdef HAVE_MINGW
-                       logger_handle = RegisterEventSource(NULL, logger_ident);
-                       if(!logger_handle)
-                               logger_mode = LOGGER_MODE_NULL;
-                       break;
-#else
-#ifdef HAVE_SYSLOG_H
-                       openlog(logger_ident, LOG_CONS | LOG_PID, LOG_DAEMON);
-                       break;
-#endif
-#endif
-               case LOGGER_MODE_NULL:
-                       break;
-       }
-
-       return true;
-}
-
-bool logger_exit(void) {
-       switch(logger_mode) {
-               case LOGGER_MODE_FILE:
-                       fclose(logger_file);
-                       break;
-               case LOGGER_MODE_SYSLOG:
-#ifdef HAVE_MINGW
-                       DeregisterEventSource(logger_handle);
-                       break;
-#else
-#ifdef HAVE_SYSLOG_H
-                       closelog();
-                       break;
-#endif
-#endif
-               case LOGGER_MODE_NULL:
-               case LOGGER_MODE_STDERR:
-                       break;
-                       break;
-       }
-
-       return true;
-}
-
-void logger(int priority, const char *format, ...) {
-       va_list ap;
-
-       va_start(ap, format);
-
-       switch(logger_mode) {
-               case LOGGER_MODE_STDERR:
-                       vfprintf(stderr, format, ap);
-                       fprintf(stderr, "\n");
-                       fflush(stderr);
-                       break;
-               case LOGGER_MODE_FILE:
-                       fprintf(logger_file, "%ld %s[%ld]: ", time(NULL), logger_ident, (long)logger_pid);
-                       vfprintf(logger_file, format, ap);
-                       fprintf(logger_file, "\n");
-                       fflush(logger_file);
-                       break;
-               case LOGGER_MODE_SYSLOG:
-#ifdef HAVE_MINGW
-                       {
-                               char message[4096];
-                               char *messages[] = {message};
-                               vsnprintf(message, sizeof(message), format, ap);
-                               ReportEvent(logger_handle, priority, 0, 0, NULL, 1, 0, messages, NULL);
-                       }
-#else
-#ifdef HAVE_SYSLOG_H
-#ifdef HAVE_VSYSLOG
-                       vsyslog(priority, format, ap);
-#else
-                       {
-                               char message[4096];
-                               vsnprintf(message, sizeof(message), format, ap);
-                               syslog(priority, "%s", message);
-                       }
-#endif
-                       break;
-#endif
-#endif
-               case LOGGER_MODE_NULL:
-                       break;
-       }
-
-       va_end(ap);
-}
-
-
diff --git a/logger/logger.h b/logger/logger.h
deleted file mode 100644 (file)
index a65968e..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
-    logger.h -- logging
-
-    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#ifndef __LOGGER_H__
-#define __LOGGER_H__
-
-typedef enum logger_level {
-       LOGGER_LEVEL_NONE,
-       LOGGER_LEVEL_NOTICE,
-       LOGGER_LEVEL_WARNING,
-       LOGGER_LEVEL_ERROR,
-       LOGGER_LEVEL_DEBUG,
-} logger_level_t;
-
-typedef enum logger_mode {
-       LOGGER_MODE_NULL,
-       LOGGER_MODE_STDERR,
-       LOGGER_MODE_FILE,
-       LOGGER_MODE_SYSLOG,
-} logger_mode_t;
-
-extern bool logger_init(const char *, logger_mode_t);
-extern bool logger_exit(void);
-extern void logger(int, const char *, ...) __attribute__ ((__format__(printf, 2, 3)));
-
-extern enum logger_level logger_level;
-
-#endif
diff --git a/process.c b/process.c
deleted file mode 100644 (file)
index f04f7c0..0000000
--- a/process.c
+++ /dev/null
@@ -1,565 +0,0 @@
-/*
-    process.c -- process management functions
-    Copyright (C) 1999-2004 Ivo Timmermans <ivo@tinc-vpn.org>,
-                  2000-2004 Guus Sliepen <guus@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#include "system.h"
-
-#include "tincd.h"
-#include "logger/logger.h"
-
-static sigset_t emptysigset;
-
-/* Some functions the less gifted operating systems might lack... */
-
-#ifdef HAVE_MINGW
-static SC_HANDLE manager = NULL;
-static SC_HANDLE service = NULL;
-static SERVICE_STATUS status = {0};
-static SERVICE_STATUS_HANDLE statushandle = 0;
-
-bool install_service(void) {
-       char command[4096] = "\"";
-       char **argp;
-       bool space;
-       SERVICE_DESCRIPTION description = {"Virtual Private Network daemon"};
-
-       manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
-       if(!manager) {
-               logger(LOG_ERR, _("Could not open service manager: %s"), winerror(GetLastError()));
-               return false;
-       }
-
-       if(!strchr(program_name, '\\')) {
-               GetCurrentDirectory(sizeof(command) - 1, command + 1);
-               strncat(command, "\\", sizeof(command));
-       }
-
-       strncat(command, program_name, sizeof(command));
-
-       strncat(command, "\"", sizeof(command));
-
-       for(argp = g_argv + 1; *argp; argp++) {
-               space = strchr(*argp, ' ');
-               strncat(command, " ", sizeof(command));
-               
-               if(space)
-                       strncat(command, "\"", sizeof(command));
-               
-               strncat(command, *argp, sizeof(command));
-
-               if(space)
-                       strncat(command, "\"", sizeof(command));
-       }
-
-       service = CreateService(manager, identname, identname,
-                       SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
-                       command, "NDIS", NULL, NULL, NULL, NULL);
-       
-       if(!service) {
-               logger(LOG_ERR, _("Could not create %s service: %s"), identname, winerror(GetLastError()));
-               return false;
-       }
-
-       ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &description);
-
-       logger(LOG_INFO, _("%s service installed"), identname);
-
-       if(!StartService(service, 0, NULL))
-               logger(LOG_WARNING, _("Could not start %s service: %s"), identname, winerror(GetLastError()));
-       else
-               logger(LOG_INFO, _("%s service started"), identname);
-
-       return true;
-}
-
-bool remove_service(void) {
-       manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
-       if(!manager) {
-               logger(LOG_ERR, _("Could not open service manager: %s"), winerror(GetLastError()));
-               return false;
-       }
-
-       service = OpenService(manager, identname, SERVICE_ALL_ACCESS);
-
-       if(!service) {
-               logger(LOG_ERR, _("Could not open %s service: %s"), identname, winerror(GetLastError()));
-               return false;
-       }
-
-       if(!ControlService(service, SERVICE_CONTROL_STOP, &status))
-               logger(LOG_ERR, _("Could not stop %s service: %s"), identname, winerror(GetLastError()));
-       else
-               logger(LOG_INFO, _("%s service stopped"), identname);
-
-       if(!DeleteService(service)) {
-               logger(LOG_ERR, _("Could not remove %s service: %s"), identname, winerror(GetLastError()));
-               return false;
-       }
-
-       logger(LOG_INFO, _("%s service removed"), identname);
-
-       return true;
-}
-
-DWORD WINAPI controlhandler(DWORD request, DWORD type, LPVOID boe, LPVOID bah) {
-       switch(request) {
-               case SERVICE_CONTROL_STOP:
-                       logger(LOG_NOTICE, _("Got %s request"), "SERVICE_CONTROL_STOP");
-                       break;
-               case SERVICE_CONTROL_SHUTDOWN:
-                       logger(LOG_NOTICE, _("Got %s request"), "SERVICE_CONTROL_SHUTDOWN");
-                       break;
-               default:
-                       logger(LOG_WARNING, _("Got unexpected request %d"), request);
-                       return ERROR_CALL_NOT_IMPLEMENTED;
-       }
-
-       if(running) {
-               running = false;
-               status.dwWaitHint = 30000; 
-               status.dwCurrentState = SERVICE_STOP_PENDING; 
-               SetServiceStatus(statushandle, &status);
-               return NO_ERROR;
-       } else {
-               status.dwWaitHint = 0; 
-               status.dwCurrentState = SERVICE_STOPPED; 
-               SetServiceStatus(statushandle, &status);
-               exit(1);
-       }
-
-}
-
-VOID WINAPI run_service(DWORD argc, LPTSTR* argv)
-{
-       int err = 1;
-       extern int main2(int argc, char **argv);
-
-
-       status.dwServiceType = SERVICE_WIN32; 
-       status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
-       status.dwWin32ExitCode = 0; 
-       status.dwServiceSpecificExitCode = 0; 
-       status.dwCheckPoint = 0; 
-
-       statushandle = RegisterServiceCtrlHandlerEx(identname, controlhandler, NULL); 
-
-       if (!statushandle) {
-               logger(LOG_ERR, _("System call `%s' failed: %s"), "RegisterServiceCtrlHandlerEx", winerror(GetLastError()));
-               err = 1;
-       } else {
-               status.dwWaitHint = 30000; 
-               status.dwCurrentState = SERVICE_START_PENDING; 
-               SetServiceStatus(statushandle, &status);
-
-               status.dwWaitHint = 0; 
-               status.dwCurrentState = SERVICE_RUNNING;
-               SetServiceStatus(statushandle, &status);
-
-               err = main2(argc, argv);
-
-               status.dwWaitHint = 0;
-               status.dwCurrentState = SERVICE_STOPPED; 
-               //status.dwWin32ExitCode = err; 
-               SetServiceStatus(statushandle, &status);
-       }
-
-       return;
-}
-
-bool init_service(void) {
-       SERVICE_TABLE_ENTRY services[] = {
-               {identname, run_service},
-               {NULL, NULL}
-       };
-
-       if(!StartServiceCtrlDispatcher(services)) {
-               if(GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
-                       return false;
-               }
-               else
-                       logger(LOG_ERR, _("System call `%s' failed: %s"), "StartServiceCtrlDispatcher", winerror(GetLastError()));
-       }
-
-       return true;
-}
-#endif
-
-#ifndef HAVE_MINGW
-/*
-  check for an existing tinc for this net, and write pid to pidfile
-*/
-
-static pid_t read_pid(const char *pidfilename) {
-       FILE *pidfile;
-       long int pid = 0;
-
-       pidfile = fopen(pidfilename, "r");
-       if(!pidfile)
-               return 0;
-
-       fscanf(pidfile, "%ld", &pid);
-       fclose(pidfile);
-       
-       return pid;
-}
-
-static pid_t check_pid(const char *pidfilename) {
-       pid_t pid;
-       
-       pid = read_pid(pidfilename);
-
-       if (!pid || pid == getpid())
-               return 0;
-
-       if(kill(pid, 0) && errno == ESRCH)
-               return 0;
-
-       return pid;
-}
-
-static pid_t write_pid(const char *pidfilename) {
-       FILE *pidfile;
-       int pidfd;
-       pid_t pid;
-
-       pidfd = open(pidfilename, O_RDWR | O_CREAT);
-
-       if(pidfd == -1)
-               return 0;
-
-#ifdef HAVE_FLOCK
-       if(flock(pidfd, LOCK_EX | LOCK_NB) == -1) {
-               close(pidfd);
-               return 0;
-       }
-#endif
-
-       pidfile = fdopen(pidfd, "r+");
-
-       if(!pidfile) {
-               close(pidfd);
-               return 0;
-       }
-
-       pid = getpid();
-       fprintf(pidfile, "%ld\n", (long)pid);
-       fflush(pidfile);
-
-#ifdef HAVE_FLOCK
-       flock(pidfd, LOCK_UN);
-#endif
-
-       close(pidfd);
-
-       return pid;
-}
-
-bool remove_pid(const char *pidfilename) {
-       return unlink(pidfilename) == 0;
-}
-
-static bool write_pidfile(void)
-{
-       pid_t pid;
-
-       pid = check_pid(tinc_pidfilename);
-
-       if(pid) {
-               if(tinc_netname)
-                       fprintf(stderr, _("A tincd is already running for net `%s' with pid %ld.\n"),
-                                       tinc_netname, (long)pid);
-               else
-                       fprintf(stderr, _("A tincd is already running with pid %ld.\n"), (long)pid);
-               return false;
-       }
-
-       /* if it's locked, write-protected, or whatever */
-       if(!write_pid(tinc_pidfilename)) {
-               fprintf(stderr, _("Could write pid file %s: %s\n"), tinc_pidfilename, strerror(errno));
-               return false;
-       }
-
-       return true;
-}
-#endif
-
-/*
-  kill older tincd for this net
-*/
-bool kill_other(int signal)
-{
-#ifndef HAVE_MINGW
-       pid_t pid;
-
-       pid = read_pid(tinc_pidfilename);
-
-       if(!pid) {
-               if(tinc_netname)
-                       fprintf(stderr, _("No other tincd is running for net `%s'.\n"),
-                                       tinc_netname);
-               else
-                       fprintf(stderr, _("No other tincd is running.\n"));
-               return false;
-       }
-
-       errno = 0;                                      /* No error, sometimes errno is only changed on error */
-
-       /* ESRCH is returned when no process with that pid is found */
-       if(kill(pid, signal) && errno == ESRCH) {
-               if(tinc_netname)
-                       fprintf(stderr, _("The tincd for net `%s' is no longer running. "),
-                                       tinc_netname);
-               else
-                       fprintf(stderr, _("The tincd is no longer running. "));
-
-               fprintf(stderr, _("Removing stale lock file.\n"));
-               remove_pid(tinc_pidfilename);
-       }
-
-       return true;
-#else
-       return remove_service();
-#endif
-}
-
-/*
-  Detach from current terminal, write pidfile, kill parent
-*/
-bool detach(void) {
-#ifndef HAVE_MINGW
-       if(!write_pidfile())
-               return false;
-
-       /* If we succeeded in doing that, detach */
-
-       logger_exit();
-
-       if(daemon(0, 0)) {
-               fprintf(stderr, _("Couldn't detach from terminal: %s"),
-                               strerror(errno));
-               return false;
-       }
-
-       /* Now UPDATE the pid in the pidfile, because we changed it... */
-
-       if(!write_pid(tinc_pidfilename)) {
-               fprintf(stderr, _("Could not write pid file %s: %s\n"), tinc_pidfilename, strerror(errno));
-               return false;
-       }
-#else
-       if(!statushandle)
-               exit(install_service());
-#endif
-
-       logger_init(tinc_identname, tinc_use_logfile ? LOGGER_MODE_FILE : LOGGER_MODE_SYSLOG);
-
-       return true;
-}
-
-bool execute_script(const char *name, char **envp)
-{
-#ifdef HAVE_SYSTEM
-       int status, len;
-       struct stat s;
-       char *scriptname;
-
-#ifndef HAVE_MINGW
-       len = asprintf(&scriptname, "\"%s/%s\"", tinc_confbase, name);
-#else
-       len = asprintf(&scriptname, "\"%s/%s.bat\"", tinc_confbase, name);
-#endif
-       if(len < 0)
-               return false;
-
-       scriptname[len - 1] = '\0';
-
-       /* First check if there is a script */
-
-       if(stat(scriptname + 1, &s))
-               return true;
-
-       logger(LOG_INFO, _("Executing script %s"), name);
-
-#ifdef HAVE_PUTENV
-       /* Set environment */
-       
-       while(*envp)
-               putenv(*envp++);
-#endif
-
-       scriptname[len - 1] = '\"';
-       status = system(scriptname);
-
-       free(scriptname);
-
-       /* Unset environment? */
-
-#ifdef WEXITSTATUS
-       if(status != -1) {
-               if(WIFEXITED(status)) { /* Child exited by itself */
-                       if(WEXITSTATUS(status)) {
-                               logger(LOG_ERR, _("Script %s exited with non-zero status %d"),
-                                          name, WEXITSTATUS(status));
-                               return false;
-                       }
-               } else if(WIFSIGNALED(status)) {        /* Child was killed by a signal */
-                       logger(LOG_ERR, _("Script %s was killed by signal %d (%s)"),
-                                  name, WTERMSIG(status), strsignal(WTERMSIG(status)));
-                       return false;
-               } else {                        /* Something strange happened */
-                       logger(LOG_ERR, _("Script %s terminated abnormally"), name);
-                       return false;
-               }
-       } else {
-               logger(LOG_ERR, _("System call `%s' failed: %s"), "system", strerror(errno));
-               return false;
-       }
-#endif
-#endif
-       return true;
-}
-
-
-/*
-  Signal handlers.
-*/
-
-#ifndef HAVE_MINGW
-static RETSIGTYPE sigterm_handler(int a) {
-       logger(LOG_NOTICE, _("Got %s signal"), "TERM");
-       exit(1);
-}
-
-static RETSIGTYPE sigquit_handler(int a) {
-       logger(LOG_NOTICE, _("Got %s signal"), "QUIT");
-       exit(1);
-}
-
-static RETSIGTYPE fatal_signal_square(int a) {
-       logger(LOG_ERR, _("Got another fatal signal %d (%s): not restarting."), a,
-                  strsignal(a));
-       exit(1);
-}
-
-static RETSIGTYPE fatal_signal_handler(int a) {
-       struct sigaction act;
-       logger(LOG_ERR, _("Got fatal signal %d (%s)"), a, strsignal(a));
-       logger(LOG_NOTICE, _("Not restarting."));
-       exit(1);
-}
-
-static RETSIGTYPE sighup_handler(int a) {
-       logger(LOG_NOTICE, _("Got %s signal"), "HUP");
-//     sighup = true;
-}
-
-static RETSIGTYPE sigint_handler(int a) {
-       static logger_level_t saved_logger_level = -1;
-
-       logger(LOG_NOTICE, _("Got %s signal"), "INT");
-
-       if(saved_logger_level != -1) {
-               logger(LOG_NOTICE, _("Reverting to old debug level (%d)"),
-                       saved_logger_level);
-               logger_level = saved_logger_level;
-               saved_logger_level = -1;
-       } else {
-               logger(LOG_NOTICE,
-                       _("Temporarily setting debug level to 5.  Kill me with SIGINT again to go back to level %d."),
-                       logger_level);
-               saved_logger_level = logger_level;
-               logger_level = 5;
-       }
-}
-
-static RETSIGTYPE sigalrm_handler(int a) {
-       logger(LOG_NOTICE, _("Got %s signal"), "ALRM");
-       //sigalrm = true;
-}
-
-static RETSIGTYPE sigusr1_handler(int a) {
-}
-
-static RETSIGTYPE sigusr2_handler(int a) {
-}
-
-static RETSIGTYPE sigwinch_handler(int a) {
-       //do_purge = true;
-}
-
-static RETSIGTYPE unexpected_signal_handler(int a) {
-       logger(LOG_WARNING, _("Got unexpected signal %d (%s)"), a, strsignal(a));
-}
-
-static RETSIGTYPE ignore_signal_handler(int a) {
-       logger(LOG_DEBUG, _("Ignored signal %d (%s)"), a, strsignal(a));
-}
-
-static struct {
-       int signal;
-       void (*handler)(int);
-} sighandlers[] = {
-       {SIGHUP, sighup_handler},
-       {SIGTERM, sigterm_handler},
-       {SIGQUIT, sigquit_handler},
-       {SIGSEGV, SIG_DFL},
-       {SIGBUS, fatal_signal_handler},
-       {SIGILL, fatal_signal_handler},
-       {SIGPIPE, ignore_signal_handler},
-       {SIGINT, sigint_handler},
-       {SIGUSR1, sigusr1_handler},
-       {SIGUSR2, sigusr2_handler},
-       {SIGCHLD, ignore_signal_handler},
-       {SIGALRM, sigalrm_handler},
-       {SIGWINCH, sigwinch_handler},
-       {0, NULL}
-};
-#endif
-
-void setup_signals(void)
-{
-#ifndef HAVE_MINGW
-       int i;
-       struct sigaction act;
-
-       sigemptyset(&emptysigset);
-       act.sa_handler = NULL;
-       act.sa_mask = emptysigset;
-       act.sa_flags = 0;
-
-       /* Set a default signal handler for every signal, errors will be
-          ignored. */
-       for(i = 0; i < NSIG; i++) {
-               act.sa_handler = unexpected_signal_handler;
-               sigaction(i, &act, NULL);
-       }
-
-       /* Then, for each known signal that we want to catch, assign a
-          handler to the signal, with error checking this time. */
-       for(i = 0; sighandlers[i].signal; i++) {
-               act.sa_handler = sighandlers[i].handler;
-               if(sigaction(sighandlers[i].signal, &act, NULL) < 0)
-                       fprintf(stderr, _("Installing signal handler for signal %d (%s) failed: %s\n"),
-                                       sighandlers[i].signal, strsignal(sighandlers[i].signal),
-                                       strerror(errno));
-       }
-#endif
-}
diff --git a/rt/Makefile.am b/rt/Makefile.am
deleted file mode 100644 (file)
index 528c26c..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-noinst_LIBRARIES = librt.a
-
-noinst_HEADERS = edge.h graph.h node.h route.h rt.h subnet.h
-
-librt_a_SOURCES = edge.c graph.c node.c route.c rt.c subnet.c
-
diff --git a/rt/README b/rt/README
deleted file mode 100644 (file)
index d0b6dc8..0000000
--- a/rt/README
+++ /dev/null
@@ -1,31 +0,0 @@
-Routing subsystem
-=================
-
-The routing part of tinc reads/writes packets to/from the virtual network
-device, sets up tunnels on demand and routes packets to/from the virtual
-network device and the tunnels.  It can also exchange information about other
-daemons using the tunnels.
-
-The following datatypes are used in this subsystem:
-
-struct node
------------
-
-This represents a tinc daemon. It keeps track of the best way to reach this
-daemon (if it is reachable at all), which subnets are associated with this
-daemon, and the connections it has with other daemons.
-
-struct subnet
--------------
-
-This represents a subnet, can have an expiry time and is associated with a node.
-
-struct edge
------------
-
-This represents a connection from one tinc daemon to another. The edges have a
-specific direction, and normally if there really is a connection between tinc
-daemon A and B, there will be two edges, A -> B and B -> A.  This seems
-redundant, but is necessary to allow disparities between information learned
-from A and information learned from B.
-
diff --git a/rt/edge.c b/rt/edge.c
deleted file mode 100644 (file)
index bf78d1f..0000000
--- a/rt/edge.c
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
-    edge.c -- edge management
-
-    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
-                  2003-2004 Ivo Timmermans <ivo@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#include "system.h"
-
-#include "rt/edge.h"
-#include "rt/node.h"
-#include "support/avl.h"
-#include "support/xalloc.h"
-
-avl_tree_t *edges;
-
-static int edge_compare(const edge_t *a, const edge_t *b) {
-       return strcmp(a->to->name, b->to->name);
-}
-
-static int edge_weight_compare(const edge_t *a, const edge_t *b) {
-       return (a->weight - b->weight) ?: strcmp(a->from->name, b->from->name) ?: strcmp(a->to->name, b->to->name);
-}
-
-bool edge_init(void) {
-       edges = avl_tree_new((avl_compare_t)edge_weight_compare, NULL);
-
-       return true;
-}
-
-bool edge_exit(void) {
-       avl_tree_free(edges);
-
-       return true;
-}
-
-avl_tree_t *edge_tree_new(void) {
-       return avl_tree_new((avl_compare_t)edge_compare, (avl_action_t)edge_free);
-}
-
-void edge_tree_free(avl_tree_t *edge_tree) {
-       avl_tree_free(edge_tree);
-}
-
-edge_t *edge_new(void) {
-       edge_t *edge;
-
-       return clear(new(edge));
-}
-
-void edge_free(edge_t *edge) {
-       free(edge);
-}
-
-void edge_add(edge_t *edge) {
-       avl_add(edge->from->edges, edge);
-       avl_add(edges, edge);
-
-       edge->reverse = edge_get(edge->to, edge->from);
-
-       if(edge->reverse)
-               edge->reverse->reverse = edge;
-}
-
-void edge_del(edge_t *edge) {
-       if(edge->reverse)
-               edge->reverse->reverse = NULL;
-
-       avl_del(edges, edge);
-       avl_del(edge->from->edges, edge);
-}
-
-edge_t *edge_get(node_t *from, node_t *to) {
-       edge_t search = {0};
-       
-       search.from = from;
-       search.to = to;
-
-       return avl_get(from->edges, &search);
-}
-
diff --git a/rt/edge.h b/rt/edge.h
deleted file mode 100644 (file)
index 775d833..0000000
--- a/rt/edge.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
-    edge.h -- edge management
-    
-    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
-                  2003-2004 Ivo Timmermans <ivo@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#ifndef __EDGE_H__
-#define __EDGE_H__
-
-#include "rt/node.h"
-#include "support/avl.h"
-#include "tnl/tnl.h"
-
-typedef struct edge_status {
-       int visited:1;
-       int mst:1;
-} edge_status_t;
-
-typedef struct edge {
-       struct node *from;
-       struct node *to;
-       struct sockaddr_storage address;
-
-       int weight;
-
-       struct edge *reverse;
-       struct tnl *tnl;
-
-       edge_status_t status;
-       node_options_t options;
-} edge_t;
-
-extern avl_tree_t *edges;
-
-extern bool edge_init(void);
-extern bool edge_exit(void);
-extern struct edge *edge_new(void) __attribute__ ((__malloc__));
-extern void edge_free(struct edge *);
-extern avl_tree_t *edge_tree_new(void) __attribute__ ((__malloc__));
-extern void edge_tree_free(avl_tree_t *);
-extern void edge_add(struct edge *);
-extern void edge_del(struct edge *);
-extern struct edge *edge_get(struct node *, struct node *);
-
-#endif
diff --git a/rt/graph.c b/rt/graph.c
deleted file mode 100644 (file)
index 63e8faf..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
-    graph.c -- graph algorithms
-    Copyright (C) 2001-2004 Guus Sliepen <guus@tinc-vpn.org>,
-                  2001-2004 Ivo Timmermans <ivo@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-/* We need to generate two trees from the graph:
-
-   1. A minimum spanning tree for broadcasts,
-   2. A single-source shortest path tree for unicasts.
-
-   Actually, the first one alone would suffice but would make unicast packets
-   take longer routes than necessary.
-
-   For the MST algorithm we can choose from Prim's or Kruskal's. I personally
-   favour Kruskal's, because we make an extra AVL tree of edges sorted on
-   weights (metric). That tree only has to be updated when an edge is added or
-   removed, and during the MST algorithm we just have go linearly through that
-   tree, adding safe edges until #edges = #nodes - 1. The implementation here
-   however is not so fast, because I tried to avoid having to make a forest and
-   merge trees.
-
-   For the SSSP algorithm Dijkstra's seems to be a nice choice. Currently a
-   simple breadth-first search is presented here.
-
-   The SSSP algorithm will also be used to determine whether nodes are directly,
-   indirectly or not reachable from the source. It will also set the correct
-   destination address and port of a node if possible.
-*/
-
-#include "system.h"
-
-#include "rt/edge.h"
-#include "rt/node.h"
-#include "support/avl.h"
-#include "support/list.h"
-
-/* Implementation of Kruskal's algorithm.
-   Running time: O(EN)
-   Please note that sorting on weight is already done by add_edge().
-*/
-
-void mst_kruskal(void) {
-       avl_node_t *avl, *next;
-       edge_t *edge;
-       node_t *node;
-       int safe_edges = 0;
-       bool skipped;
-
-       /* Do we have something to do at all? */
-
-       if(!edges->head)
-               return;
-
-       logger(LOG_DEBUG, "Running Kruskal's algorithm:");
-
-       /* Clear MST status on edges */
-
-       avl_foreach(edges, edge, edge->status.mst = false);
-
-       /* Clear visited status on nodes */
-
-       avl_foreach(nodes, node, node->status.visited = false);
-
-       /* Starting point */
-
-       ((edge_t *) edges->head->data)->from->status.visited = true;
-
-       /* Add safe edges */
-
-       for(skipped = false, avl = edges->head; avl; avl = next) {
-               next = avl->next;
-               edge = avl->data;
-
-               if(!edge->reverse || edge->from->status.visited == edge->to->status.visited) {
-                       skipped = true;
-                       continue;
-               }
-
-               edge->from->status.visited = true;
-               edge->to->status.visited = true;
-               edge->status.mst = true;
-               edge->reverse->status.mst = true;
-
-               if(skipped) {
-                       skipped = false;
-                       next = edges->head;
-                       continue;
-               }
-       }
-}
-
-/* Implementation of a simple breadth-first search algorithm.
-   Running time: O(E)
-*/
-
-void sssp_bfs(void) {
-       list_t *todo;
-       list_node_t *todonode;
-       edge_t *edge;
-       node_t *node;
-       bool indirect;
-       char *name;
-       char *address, *port;
-       int i;
-
-       todo = list_new(NULL);
-
-       /* Clear visited status on nodes */
-
-       avl_foreach(nodes, node, {
-               node->status.visited = false;
-               node->status.indirect = true;
-       });
-
-       /* Begin with myself */
-
-       myself->status.visited = true;
-       myself->status.indirect = false;
-       myself->nexthop = myself;
-       myself->via = myself;
-
-       list_add_head(todo, myself);
-
-       /* Loop while todo list is filled */
-
-       while(todo->head) {
-               list_foreach_node(todo, todonode, {
-                       node = todonode->data;
-
-                       avl_foreach(node->edges, edge, {
-                               if(!edge->reverse)
-                                       continue;
-
-                               /* Situation:
-
-                                            /
-                                           /
-                                  ----->(node)---edge-->(edge->to)
-                                           \
-                                            \
-
-                                  node->address is set to the ->address of the edge left of node.
-                                  We are currently examining the edge right of node:
-
-                                  - If edge->reverse->address != node->address, then edge->to is probably
-                                    not reachable for the nodes left of node. We do as if the indirectdata
-                                    flag is set on edge.
-                                  - If edge provides for better reachability of edge->to, update
-                                    edge->to and (re)add it to the todo_tree to (re)examine the reachability
-                                    of nodes behind it.
-                                */
-
-                               indirect = node->status.indirect || edge->options & NODE_OPTION_INDIRECT
-                                       || ((node != myself) && sockaddrcmp(&node->address, &edge->reverse->address));
-
-                               if(edge->to->status.visited && (!edge->to->status.indirect || indirect))
-                                       continue;
-
-                               edge->to->status.visited = true;
-                               edge->to->status.indirect = indirect;
-                               edge->to->nexthop = (node->nexthop == myself) ? edge->to : node->nexthop;
-                               edge->to->via = indirect ? node->via : edge->to;
-                               edge->to->options = edge->options;
-
-                               list_add_head(todo, edge->to);
-                       });
-
-                       list_del_node(todo, todonode);
-               });
-       }
-
-       list_free(todo);
-
-       /* Check reachability status. */
-
-       avl_foreach(nodes, node, {
-               if(node->status.visited != node->status.reachable) {
-                       node->status.reachable = !node->status.reachable;
-
-                       if(node->status.reachable)
-                               logger(LOG_DEBUG, _("Node %s became reachable"), node->name);
-                       else
-                               logger(LOG_DEBUG, _("Node %s became unreachable"), node->name);
-
-#if 0
-                       asprintf(&envp[0], "NETNAME=%s", netname ? : "");
-                       asprintf(&envp[1], "DEVICE=%s", device ? : "");
-                       asprintf(&envp[2], "INTERFACE=%s", iface ? : "");
-                       asprintf(&envp[3], "NODE=%s", n->name);
-                       sockaddr2str(&n->address, &address, &port);
-                       asprintf(&envp[4], "REMOTEADDRESS=%s", address);
-                       asprintf(&envp[5], "REMOTEPORT=%s", port);
-                       envp[6] = NULL;
-
-                       asprintf(&name,
-                                        n->status.reachable ? "hosts/%s-up" : "hosts/%s-down",
-                                        n->name);
-                       execute_script(name, envp);
-
-                       free(name);
-                       free(address);
-                       free(port);
-
-                       for(i = 0; i < 7; i++)
-                               free(envp[i]);
-#endif
-               }
-       });
-}
-
-void graph(void)
-{
-       mst_kruskal();
-       sssp_bfs();
-}
diff --git a/rt/graph.h b/rt/graph.h
deleted file mode 100644 (file)
index 91f58fd..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
-    graph.h -- graph algorithms
-
-    Copyright (C) 2001-2004 Guus Sliepen <guus@tinc-vpn.org>,
-                  2001-2004 Ivo Timmermans <ivo@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#ifndef __GRAPH_H__
-#define __GRAPH_H__
-
-extern bool graph_changed;
-extern void graph(void);
-
-#endif /* __GRAPH_H__ */
diff --git a/rt/node.c b/rt/node.c
deleted file mode 100644 (file)
index 4eee529..0000000
--- a/rt/node.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
-    node.c -- node management
-
-    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
-                  2003-2004 Ivo Timmermans <ivo@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#include "system.h"
-
-#include "cfg/cfg.h"
-#include "logger/logger.h"
-#include "rt/node.h"
-#include "support/avl.h"
-#include "support/xalloc.h"
-#include "tincd.h"
-
-avl_tree_t *nodes;
-
-node_t *myself;
-
-static int node_compare(const node_t *a, const node_t *b) {
-       return strcmp(a->name, b->name);
-}
-
-bool node_validname(const char *name) {
-       for(; *name; name++)
-               if(!isalnum(*name) && *name != '_')
-                       return false;
-
-       return true;
-}
-
-bool node_init(void) {
-       char *cfgfilename;
-
-       nodes = avl_tree_new((avl_compare_t)node_compare, (avl_action_t)node_free);
-       myself = node_new();
-
-       if(!cfg_get_string(tinc_cfg, "Name", NULL, &myself->name) || !myself->name) {
-               logger(LOG_ERR, _("rt: name for tinc daemon required!"));
-               node_exit();
-               return false;
-       }
-
-       if(!node_validname(myself->name)) {
-               logger(LOG_ERR, _("rt: invalid name for myself!"));
-               node_exit();
-               return false;
-       }
-
-       myself->cfg = cfg_tree_new();
-
-       asprintf(&cfgfilename, "%s/hosts/%s", tinc_confbase, myself->name);
-
-       if(!cfg_read_file(myself->cfg, cfgfilename)) {
-               free(cfgfilename);
-               node_exit();
-               return false;
-       }
-
-       free(cfgfilename);
-       
-       return true;
-}
-
-bool node_exit(void) {
-       avl_tree_del(nodes);
-       return true;
-}
-
-node_t *node_new(void) {
-       node_t *node;
-
-       clear(new(node));
-       node->subnets = subnet_tree_new();
-       node->edges = edge_tree_new();
-       node->queue = avl_tree_new(NULL, (avl_action_t)free);
-
-       return node;
-}
-
-void node_free(node_t *node) {
-       if(node->queue)
-               avl_tree_free(node->queue);
-
-       if(node->subnets)
-               subnet_tree_free(node->subnets);
-
-       if(node->edges)
-               edge_tree_free(node->edges);
-
-       replace(node->name, NULL);
-
-       free(node);
-}
-
-void node_add(node_t *node) {
-       avl_add(nodes, node);
-}
-
-void node_del(node_t *node) {
-       edge_t *edge;
-       subnet_t *subnet;
-
-       avl_foreach(node->subnets, subnet, subnet_del(subnet));
-       avl_foreach(node->edges, edge, edge_del(edge));
-
-       avl_del(nodes, node);
-}
-
-node_t *node_get(char *name) {
-       node_t search = {0};
-
-       search.name = name;
-
-       return avl_get(nodes, &search);
-}
-
diff --git a/rt/node.h b/rt/node.h
deleted file mode 100644 (file)
index acf20bc..0000000
--- a/rt/node.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
-    node.h -- node management
-
-    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
-                  2003-2004 Ivo Timmermans <ivo@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#ifndef __NODE_H__
-#define __NODE_H__
-
-typedef int node_options_t;
-
-#define NODE_OPTION_INDIRECT 1
-
-#include "rt/edge.h"
-#include "rt/subnet.h"
-#include "support/avl.h"
-#include "tnl/tnl.h"
-
-typedef struct node_status {
-       int active:1;
-       int visited:1;
-       int reachable:1;
-       int indirect:1;
-} node_status_t;
-
-typedef struct node {
-       char *name;
-
-       avl_tree_t *queue;
-
-       struct node *nexthop;
-       struct node *via;
-
-       avl_tree_t *subnets;
-       avl_tree_t *edges;
-
-       struct tnl *tnl;
-
-       node_status_t status;
-       node_options_t options;
-
-       struct sockaddr_storage address;
-
-       avl_tree_t *cfg;
-} node_t;
-
-extern avl_tree_t *nodes;
-extern struct node *myself;
-
-extern bool node_init(void);
-extern bool node_exit(void);
-extern struct node *node_new(void) __attribute__ ((__malloc__));
-extern void node_free(struct node *);
-extern void node_add(struct node *);
-extern void node_del(struct node *);
-extern struct node *node_get(char *);
-
-#endif
diff --git a/rt/route.c b/rt/route.c
deleted file mode 100644 (file)
index 4721763..0000000
+++ /dev/null
@@ -1,754 +0,0 @@
-/*
-    route.c -- routing
-    Copyright (C) 2000-2004 Ivo Timmermans <ivo@tinc-vpn.org>,
-                  2000-2004 Guus Sliepen <guus@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#include "system.h"
-
-#ifdef HAVE_NET_ETHERNET_H
-#include <net/ethernet.h>
-#endif
-#ifdef HAVE_NET_IF_ARP_H
-#include <net/if_arp.h>
-#endif
-#ifdef HAVE_NETINET_IP_ICMP_H
-#include <netinet/ip_icmp.h>
-#endif
-#ifdef HAVE_NETINET_ICMP6_H
-#include <netinet/icmp6.h>
-#endif
-#ifdef HAVE_NETINET_IF_ETHER_H
-#include <netinet/if_ether.h>
-#endif
-
-#include "logger/logger.h"
-#include "rt/rt.h"
-#include "rt/subnet.h"
-#include "support/avl.h"
-#include "support/ethernet.h"
-#include "support/ipv4.h"
-#include "support/ipv6.h"
-
-static mac_t mymac = {{0xFE, 0xFD, 0, 0, 0, 0}};
-
-/* Sizes of various headers */
-
-static const size_t ether_size = sizeof(struct ether_header);
-static const size_t arp_size = sizeof(struct ether_arp);
-static const size_t ip_size = sizeof(struct ip);
-static const size_t icmp_size = sizeof(struct icmp) - sizeof(struct ip);
-static const size_t ip6_size = sizeof(struct ip6_hdr);
-static const size_t icmp6_size = sizeof(struct icmp6_hdr);
-static const size_t ns_size = sizeof(struct nd_neighbor_solicit);
-static const size_t opt_size = sizeof(struct nd_opt_hdr);
-
-static struct timeval expires(int seconds) {
-       struct timeval tv;
-
-       gettimeofday(&tv, NULL);
-       tv.tv_sec += seconds;
-
-       return tv;
-}
-
-/* RFC 1071 */
-
-static __inline__ uint16_t inet_checksum(const void *data, int len, uint16_t prevsum) {
-       const uint16_t *p = data;
-       uint32_t checksum = prevsum ^ 0xFFFF;
-
-       while(len >= 2) {
-               checksum += *p++;
-               len -= 2;
-       }
-       
-       if(len)
-               checksum += *(uint8_t *)p;
-
-       while(checksum >> 16)
-               checksum = (checksum & 0xFFFF) + (checksum >> 16);
-
-       return ~checksum;
-}
-
-static __inline__ bool ratelimit(int frequency) {
-       static time_t lasttime = 0;
-       static int count = 0;
-       time_t now = time(NULL);
-       
-       if(lasttime == now) {
-               if(++count > frequency)
-                       return true;
-       } else {
-               lasttime = now;
-               count = 0;
-       }
-
-       return false;
-}
-
-static __inline__ bool checklength(node_t *source, int len, int minlen) {
-       if(len < minlen) {
-               logger(LOG_WARNING, _("Got too short packet from %s"), source->name);
-               return false;
-       } else
-               return true;
-}
-       
-static __inline__ void learn_mac(mac_t *address) {
-       subnet_t *subnet;
-       avl_node_t *node;
-
-       subnet = subnet_get_mac(address);
-
-       /* If we don't know this MAC address yet, store it */
-
-       if(!subnet) {
-               logger(LOG_INFO, _("Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx"),
-                                  address->x[0], address->x[1], address->x[2], address->x[3],
-                                  address->x[4], address->x[5]);
-
-               subnet = subnet_new();
-               subnet->type = SUBNET_TYPE_MAC;
-               subnet->expires = expires(rt_macexpire);
-               subnet->net.mac.address = *address;
-               subnet->owner = myself;
-               subnet_add(subnet);
-
-               /* And tell all other tinc daemons it's our MAC */
-
-#if 0
-               for(node = connection_tree->head; node; node = node->next) {
-                       c = node->data;
-                       if(c->status.active)
-                               send_add_subnet(c, subnet);
-               }
-#endif
-       }
-
-       if(timerisset(&subnet->expires))
-               subnet->expires = expires(rt_macexpire);
-}
-
-void age_subnets(void) {
-       subnet_t *s;
-
-#if 0
-       for(node = myself->subnet_tree->head; node; node = next) {
-               next = node->next;
-               s = node->data;
-               if(s->expires && s->expires < now) {
-                       {
-                               char netstr[MAXNETSTR];
-                               if(net2str(netstr, sizeof netstr, s))
-                                       logger(LOG_INFO, _("Subnet %s expired"), netstr);
-                       }
-
-                       for(node2 = connection_tree->head; node2; node2 = node2->next) {
-                               c = node2->data;
-                               if(c->status.active)
-                                       send_del_subnet(c, s);
-                       }
-
-                       subnet_del(myself, s);
-               }
-       }
-#endif
-}
-
-static void send_packet(node_t *dest, const uint8_t *packet, int len) {
-       if(dest == myself) {
-               rt_vnd->send(rt_vnd, packet, len);
-       } else if (dest->tnl) {
-               dest->tnl->send_packet(dest->tnl, packet, len);
-       } else {
-               logger(LOG_ERR, _("No tunnel for packet destination %s!"), dest->name);
-       }
-}
-
-static void broadcast_packet(node_t *source, const uint8_t *packet, int len) {
-       tnl_t *tnl;
-       edge_t *edge;
-
-       if(source != myself)
-               send_packet(myself, packet, len);
-       
-       avl_foreach(rt_tnls, tnl, {
-               edge = tnl->data;
-               if(edge && edge->status.mst && edge->to != source)
-                       send_packet(edge->to, packet, len);
-       });
-}
-
-static __inline__ void route_mac(node_t *source, const uint8_t *packet, int len) {
-       subnet_t *subnet;
-
-       /* Learn source address */
-
-       if(source == myself)
-               learn_mac((mac_t *)(packet + 6));
-
-       /* Lookup destination address */
-
-       subnet = subnet_get_mac((mac_t *)(packet));
-
-       if(!subnet) {
-               broadcast_packet(source, packet, len);
-               return;
-       }
-
-       if(subnet->owner == source) {
-               logger(LOG_WARNING, _("Packet looping back to %s!"), source->name);
-               return;
-       }
-
-       send_packet(subnet->owner, packet, len);
-}
-
-/* RFC 792 */
-
-static void route_ipv4_unreachable(node_t *source, const uint8_t *packet, int len, uint8_t type, uint8_t code) {
-       uint8_t reply[ether_size + IP_MSS];
-
-       struct ip ip = {0};
-       struct icmp icmp = {0};
-       
-       struct in_addr ip_src;
-       struct in_addr ip_dst;
-       uint32_t oldlen;
-
-       if(ratelimit(3))
-               return;
-       
-       /* Copy headers from packet into properly aligned structs on the stack */
-
-       memcpy(&ip, packet + ether_size, ip_size);
-
-       /* Remember original source and destination */
-       
-       ip_src = ip.ip_src;
-       ip_dst = ip.ip_dst;
-
-       oldlen = len - ether_size;
-
-       if(type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)
-               icmp.icmp_nextmtu = htons(len - ether_size);
-
-       if(oldlen >= IP_MSS - ip_size - icmp_size)
-               oldlen = IP_MSS - ip_size - icmp_size;
-       
-       /* Copy first part of original contents to ICMP message */
-       
-       memmove(reply + ether_size + ip_size + icmp_size, packet + ether_size, oldlen);
-
-       /* Fill in IPv4 header */
-       
-       ip.ip_v = 4;
-       ip.ip_hl = ip_size / 4;
-       ip.ip_tos = 0;
-       ip.ip_len = htons(ip_size + icmp_size + oldlen);
-       ip.ip_id = 0;
-       ip.ip_off = 0;
-       ip.ip_ttl = 255;
-       ip.ip_p = IPPROTO_ICMP;
-       ip.ip_sum = 0;
-       ip.ip_src = ip_dst;
-       ip.ip_dst = ip_src;
-
-       ip.ip_sum = inet_checksum(&ip, ip_size, ~0);
-       
-       /* Fill in ICMP header */
-       
-       icmp.icmp_type = type;
-       icmp.icmp_code = code;
-       icmp.icmp_cksum = 0;
-       
-       icmp.icmp_cksum = inet_checksum(&icmp, icmp_size, ~0);
-       icmp.icmp_cksum = inet_checksum(packet + ether_size + ip_size + icmp_size, oldlen, icmp.icmp_cksum);
-
-       /* Copy structs on stack back to packet */
-
-       memcpy(reply + ether_size, &ip, ip_size);
-       memcpy(reply + ether_size + ip_size, &icmp, icmp_size);
-       
-       send_packet(source, reply, ether_size + ip_size + icmp_size + oldlen);
-}
-
-/* RFC 791 */
-
-static __inline__ void fragment_ipv4_packet(node_t *dest, const uint8_t *packet, int len) {
-       struct ip ip;
-       char fragment[dest->tnl->mtu];
-       int fraglen, maxlen, todo;
-       const uint8_t *offset;
-       uint16_t ip_off, origf;
-       
-       memcpy(&ip, packet + ether_size, ip_size);
-
-       if(ip.ip_hl != ip_size / 4)
-               return;
-       
-       todo = ntohs(ip.ip_len) - ip_size;
-
-       if(ether_size + ip_size + todo != len) {
-               logger(LOG_WARNING, _("Length of packet (%d) doesn't match length in IPv4 header (%d)"), len, ether_size + ip_size + todo);
-               return;
-       }
-
-       logger(LOG_INFO, _("Fragmenting packet of %d bytes to %s"), len, dest->name);
-
-       offset = packet + ether_size + ip_size;
-       maxlen = (dest->tnl->mtu - ether_size - ip_size) & ~0x7;
-       ip_off = ntohs(ip.ip_off);
-       origf = ip_off & ~IP_OFFMASK;
-       ip_off &= IP_OFFMASK;
-       
-       while(todo) {
-               fraglen = todo > maxlen ? maxlen : todo;
-               memcpy(fragment + ether_size + ip_size, offset, fraglen);
-               todo -= fraglen;
-               offset += fraglen;
-
-               ip.ip_len = htons(ip_size + fraglen);
-               ip.ip_off = htons(ip_off | origf | (todo ? IP_MF : 0));
-               ip.ip_sum = 0;
-               ip.ip_sum = inet_checksum(&ip, ip_size, ~0);
-               memcpy(fragment, packet, ether_size);
-               memcpy(fragment + ether_size, &ip, ip_size);
-
-               send_packet(dest, fragment, ether_size + ip_size + fraglen);
-
-               ip_off += fraglen / 8;
-       }       
-}
-
-static __inline__ void route_ipv4_unicast(node_t *source, const uint8_t *packet, int len) {
-       subnet_t *subnet;
-       node_t *via;
-
-       subnet = subnet_get_ipv4((ipv4_t *)(packet + 30));
-
-       if(!subnet) {
-               logger(LOG_WARNING, _("Cannot route packet from %s: unknown IPv4 destination address %d.%d.%d.%d"),
-                               source->name,
-                               packet[30],
-                               packet[31],
-                               packet[32],
-                               packet[33]);
-
-               route_ipv4_unreachable(source, packet, len, ICMP_DEST_UNREACH, ICMP_NET_UNKNOWN);
-               return;
-       }
-       
-       if(subnet->owner == source) {
-               logger(LOG_WARNING, _("Packet looping back to %s!"), source->name);
-               return;
-       }
-
-       if(!subnet->owner->status.reachable)
-               route_ipv4_unreachable(source, packet, len, ICMP_DEST_UNREACH, ICMP_NET_UNREACH);
-
-       via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
-       
-       if(len > via->tnl->mtu && via != myself) {
-               logger(LOG_INFO, _("Packet for %s length %d larger than MTU %d"), subnet->owner->name, len, via->tnl->mtu);
-               if(packet[20] & 0x40) {
-                       len = via->tnl->mtu;
-                       route_ipv4_unreachable(source, packet, len, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED);
-               } else {
-                       fragment_ipv4_packet(via, packet, len);
-               }
-
-               return;
-       }
-
-       send_packet(subnet->owner, packet, len);
-}
-
-static __inline__ void route_ipv4(node_t *source, const uint8_t *packet, int len) {
-       if(!checklength(source, len, ether_size + ip_size))
-               return;
-
-       route_ipv4_unicast(source, packet, len);
-}
-
-/* RFC 2463 */
-
-static void route_ipv6_unreachable(node_t *source, const uint8_t *packet, int len, uint8_t type, uint8_t code) {
-       uint8_t reply[ether_size + IP_MSS];
-       struct ip6_hdr ip6;
-       struct icmp6_hdr icmp6 = {0};
-       uint16_t checksum;      
-
-       struct {
-               struct in6_addr ip6_src;        /* source address */
-               struct in6_addr ip6_dst;        /* destination address */
-               uint32_t length;
-               uint32_t next;
-       } pseudo;
-
-       if(ratelimit(3))
-               return;
-       
-       /* Copy headers from packet to structs on the stack */
-
-       memcpy(&ip6, packet + ether_size, ip6_size);
-
-       /* Remember original source and destination */
-       
-       pseudo.ip6_src = ip6.ip6_dst;
-       pseudo.ip6_dst = ip6.ip6_src;
-
-       pseudo.length = len - ether_size;
-
-       if(type == ICMP6_PACKET_TOO_BIG)
-               icmp6.icmp6_mtu = htonl(pseudo.length);
-       
-       if(pseudo.length >= IP_MSS - ip6_size - icmp6_size)
-               pseudo.length = IP_MSS - ip6_size - icmp6_size;
-       
-       /* Copy first part of original contents to ICMP message */
-       
-       memcpy(reply + ether_size + ip6_size + icmp6_size, packet + ether_size, pseudo.length);
-
-       /* Fill in IPv6 header */
-       
-       ip6.ip6_flow = htonl(0x60000000UL);
-       ip6.ip6_plen = htons(icmp6_size + pseudo.length);
-       ip6.ip6_nxt = IPPROTO_ICMPV6;
-       ip6.ip6_hlim = 255;
-       ip6.ip6_src = pseudo.ip6_src;
-       ip6.ip6_dst = pseudo.ip6_dst;
-
-       /* Fill in ICMP header */
-       
-       icmp6.icmp6_type = type;
-       icmp6.icmp6_code = code;
-       icmp6.icmp6_cksum = 0;
-
-       /* Create pseudo header */
-               
-       pseudo.length = htonl(icmp6_size + pseudo.length);
-       pseudo.next = htonl(IPPROTO_ICMPV6);
-
-       /* Generate checksum */
-       
-       checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
-       checksum = inet_checksum(&icmp6, icmp6_size, checksum);
-       checksum = inet_checksum(reply + ether_size + ip6_size + icmp6_size, ntohl(pseudo.length) - icmp6_size, checksum);
-
-       icmp6.icmp6_cksum = checksum;
-
-       /* Copy structs on stack back to packet */
-
-       memcpy(reply + ether_size, &ip6, ip6_size);
-       memcpy(reply + ether_size + ip6_size, &icmp6, icmp6_size);
-       
-       send_packet(source, reply, ether_size + ip6_size + ntohl(pseudo.length));
-}
-
-static __inline__ void route_ipv6_unicast(node_t *source, const uint8_t *packet, int len) {
-       subnet_t *subnet;
-       node_t *via;
-
-       subnet = subnet_get_ipv6((ipv6_t *)(packet + 38));
-
-       if(!subnet) {
-               logger(LOG_WARNING, _("Cannot route packet from %s: unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
-                               source->name,
-                               ntohs(*(uint16_t *)(packet + 38)),
-                               ntohs(*(uint16_t *)(packet + 40)),
-                               ntohs(*(uint16_t *)(packet + 42)),
-                               ntohs(*(uint16_t *)(packet + 44)),
-                               ntohs(*(uint16_t *)(packet + 46)),
-                               ntohs(*(uint16_t *)(packet + 48)),
-                               ntohs(*(uint16_t *)(packet + 50)),
-                               ntohs(*(uint16_t *)(packet + 52)));
-
-               route_ipv6_unreachable(source, packet, len, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR);
-               return;
-       }
-
-       if(subnet->owner == source) {
-               logger(LOG_WARNING, _("Packet looping back to %s!"), source->name);
-               return;
-       }
-
-       if(!subnet->owner->status.reachable)
-               route_ipv6_unreachable(source, packet, len, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE);
-
-       via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
-       
-       if(len > via->tnl->mtu && via != myself) {
-               logger(LOG_INFO, _("Packet for %s length %d larger than MTU %d"), subnet->owner->name, len, via->tnl->mtu);
-               len = via->tnl->mtu;
-               route_ipv6_unreachable(source, packet, len, ICMP6_PACKET_TOO_BIG, 0);
-               return;
-       }
-
-       send_packet(subnet->owner, packet, len);
-}
-
-/* RFC 2461 */
-
-static void route_neighborsol(node_t *source, const uint8_t *packet, int len) {
-       uint8_t reply[len];
-       struct ip6_hdr ip6;
-       struct nd_neighbor_solicit ns;
-       struct nd_opt_hdr opt;
-       subnet_t *subnet;
-       uint16_t checksum;
-
-       struct {
-               struct in6_addr ip6_src;        /* source address */
-               struct in6_addr ip6_dst;        /* destination address */
-               uint32_t length;
-               uint32_t next;
-       } pseudo;
-
-       if(!checklength(source, len, ether_size + ip6_size + ns_size + opt_size + ETH_ALEN))
-               return;
-       
-       if(source != myself) {
-               logger(LOG_WARNING, _("Got neighbor solicitation request from %s while in router mode!"), source->name);
-               return;
-       }
-
-       /* Copy headers from packet to structs on the stack */
-
-       memcpy(&ip6, packet + ether_size, ip6_size);
-       memcpy(&ns, packet + ether_size + ip6_size, ns_size);
-       memcpy(&opt, packet + ether_size + ip6_size + ns_size, opt_size);
-
-       /* First, snatch the source address from the neighbor solicitation packet */
-
-       if(rt_overwrite_mac)
-               memcpy(mymac.x, packet + ETH_ALEN, ETH_ALEN);
-
-       /* Check if this is a valid neighbor solicitation request */
-
-       if(ns.nd_ns_hdr.icmp6_type != ND_NEIGHBOR_SOLICIT ||
-          opt.nd_opt_type != ND_OPT_SOURCE_LINKADDR) {
-               logger(LOG_WARNING, _("Cannot route packet: received unknown type neighbor solicitation request"));
-               return;
-       }
-
-       /* Create pseudo header */
-
-       pseudo.ip6_src = ip6.ip6_src;
-       pseudo.ip6_dst = ip6.ip6_dst;
-       pseudo.length = htonl(ns_size + opt_size + ETH_ALEN);
-       pseudo.next = htonl(IPPROTO_ICMPV6);
-
-       /* Generate checksum */
-
-       checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
-       checksum = inet_checksum(&ns, ns_size, checksum);
-       checksum = inet_checksum(&opt, opt_size, checksum);
-       checksum = inet_checksum(packet + ether_size + ip6_size + ns_size + opt_size, ETH_ALEN, checksum);
-
-       if(checksum) {
-               logger(LOG_WARNING, _("Cannot route packet: checksum error for neighbor solicitation request"));
-               return;
-       }
-
-       /* Check if the IPv6 address exists on the VPN */
-
-       subnet = subnet_get_ipv6((ipv6_t *) &ns.nd_ns_target);
-
-       if(!subnet) {
-               logger(LOG_WARNING, _("Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
-                                  ntohs(((uint16_t *) &ns.nd_ns_target)[0]),
-                                  ntohs(((uint16_t *) &ns.nd_ns_target)[1]),
-                                  ntohs(((uint16_t *) &ns.nd_ns_target)[2]),
-                                  ntohs(((uint16_t *) &ns.nd_ns_target)[3]),
-                                  ntohs(((uint16_t *) &ns.nd_ns_target)[4]),
-                                  ntohs(((uint16_t *) &ns.nd_ns_target)[5]),
-                                  ntohs(((uint16_t *) &ns.nd_ns_target)[6]),
-                                  ntohs(((uint16_t *) &ns.nd_ns_target)[7]));
-
-               return;
-       }
-
-       /* Check if it is for our own subnet */
-
-       if(subnet->owner == myself)
-               return;                                 /* silently ignore */
-
-       /* Create neighbor advertation reply */
-
-       memcpy(reply, packet + ETH_ALEN, ETH_ALEN);     /* copy destination address */
-       memcpy(reply + ETH_ALEN, packet + ETH_ALEN, ETH_ALEN);  /* copy destination address */
-       reply[ETH_ALEN * 2 - 1] ^= 0xFF;        /* mangle source address so it looks like it's not from us */
-
-       ip6.ip6_dst = ip6.ip6_src;                      /* swap destination and source protocoll address */
-       ip6.ip6_src = ns.nd_ns_target;
-
-       memcpy(reply + ether_size + ip6_size + ns_size + opt_size, reply + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */
-
-       ns.nd_ns_cksum = 0;
-       ns.nd_ns_type = ND_NEIGHBOR_ADVERT;
-       ns.nd_ns_reserved = htonl(0x40000000UL);        /* Set solicited flag */
-       opt.nd_opt_type = ND_OPT_TARGET_LINKADDR;
-
-       /* Create pseudo header */
-
-       pseudo.ip6_src = ip6.ip6_src;
-       pseudo.ip6_dst = ip6.ip6_dst;
-       pseudo.length = htonl(ns_size + opt_size + ETH_ALEN);
-       pseudo.next = htonl(IPPROTO_ICMPV6);
-
-       /* Generate checksum */
-
-       checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
-       checksum = inet_checksum(&ns, ns_size, checksum);
-       checksum = inet_checksum(&opt, opt_size, checksum);
-       checksum = inet_checksum(packet + ether_size + ip6_size + ns_size + opt_size, ETH_ALEN, checksum);
-
-       ns.nd_ns_hdr.icmp6_cksum = checksum;
-
-       /* Copy structs on stack back to packet */
-
-       memcpy(reply + ether_size, &ip6, ip6_size);
-       memcpy(reply + ether_size + ip6_size, &ns, ns_size);
-       memcpy(reply + ether_size + ip6_size + ns_size, &opt, opt_size);
-
-       send_packet(source, reply, len);
-}
-
-static __inline__ void route_ipv6(node_t *source, const uint8_t *packet, int len) {
-       if(!checklength(source, len, ether_size + ip6_size))
-               return;
-
-       if(packet[20] == IPPROTO_ICMPV6 && checklength(source, len, ether_size + ip6_size + icmp6_size) && packet[54] == ND_NEIGHBOR_SOLICIT) {
-               route_neighborsol(source, packet, len);
-               return;
-       }
-
-       route_ipv6_unicast(source, packet, len);
-}
-
-/* RFC 826 */
-
-static void route_arp(node_t *source, const uint8_t *packet, int len) {
-       uint8_t reply[len];
-       struct ether_arp arp;
-       subnet_t *subnet;
-       struct in_addr addr;
-
-       if(!checklength(source, len, ether_size + arp_size))
-               return;
-
-       if(source != myself) {
-               logger(LOG_WARNING, _("Got ARP request from %s while in router mode!"), source->name);
-               return;
-       }
-
-       /* First, snatch the source address from the ARP packet */
-
-       if(rt_overwrite_mac)
-               memcpy(mymac.x, packet + ETH_ALEN, ETH_ALEN);
-
-       /* Copy headers from packet to structs on the stack */
-
-       memcpy(&arp, packet + ether_size, arp_size);
-
-       /* Check if this is a valid ARP request */
-
-       if(ntohs(arp.arp_hrd) != ARPHRD_ETHER || ntohs(arp.arp_pro) != ETH_P_IP ||
-          arp.arp_hln != ETH_ALEN || arp.arp_pln != sizeof(addr) || ntohs(arp.arp_op) != ARPOP_REQUEST) {
-               logger(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
-               return;
-       }
-
-       /* Check if the IPv4 address exists on the VPN */
-
-       subnet = subnet_get_ipv4((ipv4_t *) &arp.arp_tpa);
-
-       if(!subnet) {
-               logger(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
-                                  arp.arp_tpa[0], arp.arp_tpa[1], arp.arp_tpa[2],
-                                  arp.arp_tpa[3]);
-               return;
-       }
-
-       /* Check if it is for our own subnet */
-
-       if(subnet->owner == myself)
-               return;                                 /* silently ignore */
-
-       memcpy(reply, packet + ETH_ALEN, ETH_ALEN);     /* copy destination address */
-       memcpy(reply + ETH_ALEN, packet + ETH_ALEN, ETH_ALEN);  /* copy destination address */
-       reply[ETH_ALEN * 2 - 1] ^= 0xFF;        /* mangle source address so it looks like it's not from us */
-
-       memcpy(&addr, arp.arp_tpa, sizeof(addr));       /* save protocol addr */
-       memcpy(arp.arp_tpa, arp.arp_spa, sizeof(addr)); /* swap destination and source protocol address */
-       memcpy(arp.arp_spa, &addr, sizeof(addr));       /* ... */
-
-       memcpy(arp.arp_tha, arp.arp_sha, ETH_ALEN);     /* set target hard/proto addr */
-       memcpy(arp.arp_sha, reply + ETH_ALEN, ETH_ALEN);        /* add fake source hard addr */
-       arp.arp_op = htons(ARPOP_REPLY);
-
-       /* Copy structs on stack back to packet */
-
-       memcpy(reply + ether_size, &arp, arp_size);
-
-       send_packet(source, reply, len);
-}
-
-void route(node_t *source, const uint8_t *packet, int len) {
-       if(!checklength(source, len, ether_size))
-               return;
-
-       switch (rt_mode) {
-               case RT_MODE_ROUTER:
-                       {
-                               uint16_t type;
-
-                               type = ntohs(*((uint16_t *)(packet + 12)));
-                               switch (type) {
-                                       case ETH_P_ARP:
-                                               route_arp(source, packet, len);
-                                               break;
-
-                                       case ETH_P_IP:
-                                               route_ipv4(source, packet, len);
-                                               break;
-
-                                       case ETH_P_IPV6:
-                                               route_ipv6(source, packet, len);
-                                               break;
-
-                                       default:
-                                               logger(LOG_WARNING, _("Cannot route packet from %s: unknown type %hx"), source->name, type);
-                                               break;
-                               }
-                       }
-                       break;
-
-               case RT_MODE_SWITCH:
-                       route_mac(source, packet, len);
-                       break;
-
-               case RT_MODE_HUB:
-                       broadcast_packet(source, packet, len);
-                       break;
-       }
-}
diff --git a/rt/route.h b/rt/route.h
deleted file mode 100644 (file)
index 42c587f..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
-    route.h -- routing
-
-    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
-                  2003-2004 Ivo Timmermans <ivo@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id: rt.h 1375 2004-03-22 12:30:39Z guus $
-*/
-
-#ifndef __ROUTE_H__
-#define __ROUTE_H__
-
-#include "rt/node.h"
-
-extern void route(node_t *, const uint8_t *, int);
-
-#endif
diff --git a/rt/rt.c b/rt/rt.c
deleted file mode 100644 (file)
index 43e33c6..0000000
--- a/rt/rt.c
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
-    rt.c -- routing
-
-    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
-                  2003-2004 Ivo Timmermans <ivo@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#include "system.h"
-
-#include "cfg/cfg.h"
-#include "rt/edge.h"
-#include "rt/node.h"
-#include "rt/rt.h"
-#include "rt/subnet.h"
-#include "support/xalloc.h"
-#include "tnl/tnl.h"
-#include "vnd/vnd.h"
-#include "tincd.h"
-
-vnd_t *rt_vnd = NULL;
-int rt_af = AF_UNSPEC;
-int rt_macexpire = 600;
-int rt_maxtimeout = 900;
-rt_mode_t rt_mode = RT_MODE_ROUTER;
-bool rt_priorityinheritance = false;
-bool rt_hostnames = false;
-bool rt_overwrite_mac = false;
-
-avl_tree_t *rt_tnls;
-avl_tree_t *rt_listeners;
-
-static bool rt_tnl_accept(tnl_t *t) {
-       
-}
-
-static bool rt_vnd_recv(vnd_t *vnd, const void *buf, int len) {
-       route(myself, buf, len);
-}
-
-static bool rt_tnl_recv_packet(tnl_t *tnl, const void *buf, int len) {
-       edge_t *edge = tnl->data;
-       route(edge->to, buf, len);
-}
-
-static bool rt_tnl_recv_meta(tnl_t *tnl, const void *buf, int len) {
-}
-
-static void rt_outgoing(char *name) {
-       tnl_t *tnl;
-
-       clear(new(tnl));
-       
-}
-
-bool rt_init(void) {
-       char *bindtoaddress = NULL;
-       char *bindtointerface = NULL;
-       char *device = NULL;
-       char *iface = NULL;
-       char *port = NULL;
-       cfg_t *cfg;
-       subnet_t *subnet;
-       struct addrinfo hint, *ai, *aip;
-       int err;
-       int listeners;
-       char *connectto = NULL;
-       
-       cfg_choice_t mode_choice[] = {
-               {"Router", RT_MODE_ROUTER},
-               {"Switch", RT_MODE_SWITCH},
-               {"Hub", RT_MODE_HUB},
-       };
-
-       cfg_choice_t af_choice[] = {
-               {"IPv4", AF_INET},
-               {"IPv6", AF_INET6},
-               {"Any", AF_UNSPEC},
-       };
-
-       logger(LOG_INFO, _("rt: initialising"));
-
-       if(!subnet_init() || !node_init() || !edge_init())
-               return false;
-
-       rt_tnls = avl_tree_new(NULL, NULL);
-       rt_listeners = avl_tree_new(NULL, NULL);
-
-       /* Read main configuration */
-
-       if(!cfg_get_choice(tinc_cfg, "AddressFamily", af_choice, AF_UNSPEC, &rt_af)
-                       || !cfg_get_string(tinc_cfg, "BindToAddress", NULL, &bindtoaddress)
-                       || !cfg_get_string(tinc_cfg, "BindToInterface", NULL, &bindtointerface)
-                       || !cfg_get_string(tinc_cfg, "Device", "/dev/net/tun", &device)
-                       || !cfg_get_bool(tinc_cfg, "Hostnames", false, &rt_hostnames)
-                       || !cfg_get_string(tinc_cfg, "Interface", tinc_netname, &iface)
-                       || !cfg_get_period(tinc_cfg, "MACExpire", 600, &rt_macexpire)
-                       || !cfg_get_period(tinc_cfg, "MaxTimeout", 3600, &rt_maxtimeout)
-                       || !cfg_get_choice(tinc_cfg, "Mode", mode_choice, RT_MODE_ROUTER, &rt_mode)
-                       || !cfg_get_bool(tinc_cfg, "PriorityInheritance", false, &rt_priorityinheritance))
-               return false;
-
-       /* Read host configuration for myself */
-       
-       if(!cfg_get_string(myself->cfg, "Port", "655", &port))
-               return false;
-
-       for(cfg = cfg_get(myself->cfg, "Subnet"); cfg; cfg = cfg_get_next(myself->cfg, cfg)) {
-               if(!cfg_subnet(cfg, &subnet))
-                       return false;
-
-               subnet->owner = myself;
-               subnet_add(subnet);
-       }
-
-       /* Open the virtual network device */
-
-       clear(new(rt_vnd));
-       
-       replace(rt_vnd->device, device);
-       replace(rt_vnd->interface, iface);
-       
-       rt_vnd->mode = (rt_mode == RT_MODE_ROUTER) ? VND_MODE_TUN : VND_MODE_TAP;
-       rt_vnd->recv = rt_vnd_recv;
-
-       if(!vnd_open(rt_vnd)) {
-               vnd_free(rt_vnd);
-               return false;
-       }
-       
-       /* Create listening sockets */
-
-       hint.ai_family = rt_af;
-       hint.ai_socktype = SOCK_STREAM;
-       hint.ai_protocol = IPPROTO_TCP;
-       hint.ai_flags = AI_PASSIVE;
-
-       err = getaddrinfo(bindtoaddress, port, &hint, &ai);
-
-       if(err || !ai) {
-               logger(LOG_ERR, _("rt: system call '%s' failed: %s"), "getaddrinfo", gai_strerror(err));
-               return false;
-       }
-
-       listeners = 0;
-
-       for(aip = ai; aip; aip = aip->ai_next) {
-               tnl_listen_t *listener;
-               
-               clear(new(listener));
-               listener->local.address = *(struct sockaddr_storage *)aip->ai_addr;
-               listener->local.id = myself->name;
-               listener->type = SOCK_STREAM;
-               listener->protocol = IPPROTO_TCP;
-               // listener->local.cred = ...;
-               listener->accept = rt_tnl_accept;
-
-               if(tnl_listen(listener))
-                       listeners++;
-       }
-
-       freeaddrinfo(ai);
-
-       if(!listeners) {
-               logger(LOG_ERR, _("rt: unable to create any listening socket!"));
-               return false;
-       }
-
-       /* Setup outgoing connections */
-
-       for(cfg = cfg_get(tinc_cfg, "ConnectTo"); cfg; cfg = cfg_get_next(tinc_cfg, cfg)) {
-               if(!cfg_string(cfg, NULL, &connectto))
-                       return false;
-
-               if(!node_validname(connectto)) {
-                       logger(LOG_ERR, _("rt: invalid name for outgoing connection in %s line %d"), cfg->file, cfg->line);
-                       free(connectto);
-                       continue;
-               }
-
-               rt_outgoing(connectto);
-       }
-
-       return true;
-}
-
-bool rt_exit(void) {
-       edge_exit();
-       node_exit();
-       subnet_exit();
-
-       logger(LOG_INFO, _("rt: exitting"));
-}
-
-
diff --git a/rt/rt.h b/rt/rt.h
deleted file mode 100644 (file)
index dd8126d..0000000
--- a/rt/rt.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
-    route.h -- routing
-
-    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
-                  2003-2004 Ivo Timmermans <ivo@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#ifndef __RT_H__
-#define __RT_H__
-
-#include "rt/node.h"
-#include "tnl/tnl.h"
-#include "vnd/vnd.h"
-
-#define RT_PROTOCOL 0
-
-typedef enum rt_mode {
-       RT_MODE_ROUTER,
-       RT_MODE_SWITCH,
-       RT_MODE_HUB,
-} rt_mode_t;
-
-extern int rt_af;
-extern enum rt_mode rt_mode;
-extern bool rt_hostnames;
-extern bool rt_priorityinheritance;
-extern int rt_macexpire;
-extern int rt_maxtimeout;
-extern bool rt_overwrite_mac;
-
-extern node_t *myself;
-extern vnd_t *rt_vnd;
-extern avl_tree_t *rt_tnls;
-
-extern bool rt_init(void);
-extern bool rt_exit(void);
-
-#endif
diff --git a/rt/subnet.c b/rt/subnet.c
deleted file mode 100644 (file)
index ced1695..0000000
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
-    subnet.c -- subnet handling
-
-    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
-                  2003-2004 Ivo Timmermans <ivo@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#include "system.h"
-
-#include "cfg/cfg.h"
-#include "logger/logger.h"
-#include "rt/node.h"
-#include "rt/subnet.h"
-#include "support/avl.h"
-#include "support/xalloc.h"
-
-avl_tree_t *subnets;
-/* Subnet mask handling */
-
-static int maskcmp(const void *va, const void *vb, int masklen, int len) {
-       int i, m, result;
-       const char *a = va;
-       const char *b = vb;
-
-       for(m = masklen, i = 0; m >= 8; m -= 8, i++) {
-               result = a[i] - b[i];
-               if(result)
-                       return result;
-       }
-
-       return m ? (a[i] & (0x100 - (1 << (8 - m)))) - (b[i] & (0x100 - (1 << (8 - m)))) : 0;
-}
-
-static void mask(void *va, int masklen, int len) {
-       int i;
-       char *a = va;
-
-       i = masklen / 8;
-       masklen %= 8;
-
-       if(masklen)
-               a[i++] &= (0x100 - (1 << masklen));
-
-       for(; i < len; i++)
-               a[i] = 0;
-}
-
-static void maskcpy(void *va, const void *vb, int masklen, int len) {
-       int i, m;
-       char *a = va;
-       const char *b = vb;
-
-       for(m = masklen, i = 0; m >= 8; m -= 8, i++)
-               a[i] = b[i];
-
-       if(m) {
-               a[i] = b[i] & (0x100 - (1 << m));
-               i++;
-       }
-
-       for(; i < len; i++)
-               a[i] = 0;
-}
-
-static bool maskcheck(const void *va, int masklen, int len) {
-       int i;
-       const char *a = va;
-
-       i = masklen / 8;
-       masklen %= 8;
-
-       if(masklen && a[i++] & (0xff >> masklen))
-               return false;
-
-       for(; i < len; i++)
-               if(a[i] != 0)
-                       return false;
-
-       return true;
-}
-
-/* Cache handling */
-
-struct {
-       subnet_t key;
-       subnet_t *subnet;
-} *cache;
-
-int cache_bits;
-int cache_size;
-uint32_t cache_mask;
-
-static void cache_flush(void) {
-       memset(cache, 0, sizeof *cache * cache_size);
-}
-
-static void cache_init(void) {
-       cache_bits = 8;
-       cache_size = 1 << 8;
-       cache_mask = cache_size - 1;
-
-       dim(cache, cache_size);
-
-       cache_flush();
-}
-
-static void cache_exit(void) {
-       free(cache);
-}
-
-static uint32_t subnet_hash(const subnet_t *subnet) {
-       uint32_t hash;
-       int i;
-
-       hash = subnet->type;
-
-       for(i = 0; i < sizeof subnet->net / sizeof(uint32_t); i++)
-               hash ^= ((uint32_t *)&subnet->net)[i];
-
-       hash ^= hash >> 16;
-       hash ^= hash >> 8;
-       
-       return hash & cache_mask;
-}
-
-static subnet_t *cache_get(subnet_t *subnet) {
-       uint32_t hash = subnet_hash(subnet);
-
-       if(cache[hash].subnet && memcmp(&cache[hash].key, subnet, sizeof *subnet))
-               return cache[hash].subnet;
-       else
-               return NULL;
-}
-
-static void cache_add(subnet_t *key, subnet_t *subnet) {
-       uint32_t hash = subnet_hash(subnet);
-
-       cache[hash].key = *key;
-       cache[hash].subnet = subnet;
-}
-
-/* Subnet tree handling */
-
-static int subnet_compare_mac(const subnet_t *a, const subnet_t *b) {
-       return memcmp(&a->net.mac.address, &b->net.mac.address, sizeof(mac_t))
-               ?: (a->owner && b->owner) ? strcmp(a->owner->name, b->owner->name) : 0;
-}
-
-static int subnet_compare_ipv4(const subnet_t *a, const subnet_t *b) {
-       return memcmp(&a->net.ipv4.address, &b->net.ipv4.address, sizeof(ipv4_t))
-               ?: (a->net.ipv4.prefixlength - b->net.ipv4.prefixlength)
-               ?: (a->owner && b->owner) ? strcmp(a->owner->name, b->owner->name) : 0;
-}
-
-static int subnet_compare_ipv6(const subnet_t *a, const subnet_t *b) {
-       return memcmp(&a->net.ipv6.address, &b->net.ipv6.address, sizeof(ipv6_t))
-               ?: (a->net.ipv6.prefixlength - b->net.ipv6.prefixlength)
-               ?: (a->owner && b->owner) ? strcmp(a->owner->name, b->owner->name) : 0;
-}
-
-static int subnet_compare(const subnet_t *a, const subnet_t *b) {
-       int result;
-
-       result = a->type - b->type;
-
-       if(result)
-               return result;
-
-       switch (a->type) {
-               case SUBNET_TYPE_MAC:
-                       return subnet_compare_mac(a, b);
-               case SUBNET_TYPE_IPV4:
-                       return subnet_compare_ipv4(a, b);
-               case SUBNET_TYPE_IPV6:
-                       return subnet_compare_ipv6(a, b);
-               default:
-                       logger(LOG_ERR, _("rt: subnet_compare() was called with unknown subnet type %d, exitting!"), a->type);
-                       exit(1);
-       }
-}
-
-avl_tree_t *subnet_tree_new(void) {
-       return avl_tree_new((avl_compare_t)subnet_compare, NULL);
-}
-
-void subnet_tree_free(avl_tree_t *subnets) {
-       avl_tree_free(subnets);
-}
-
-subnet_t *subnet_new(void) {
-       subnet_t *subnet;
-
-       return clear(new(subnet));
-}
-
-void subnet_free(subnet_t *subnet) {
-       free(subnet);
-}
-
-void subnet_add(subnet_t *subnet) {
-       avl_add(subnets, subnet);
-       avl_add(subnet->owner->subnets, subnet);
-       cache_flush();
-}
-
-void subnet_del(subnet_t *subnet) {
-       avl_del(subnet->owner->subnets, subnet);
-       avl_del(subnets, subnet);
-       cache_flush();
-}
-
-bool subnet_init(void) {
-       cache_init();
-       subnets = avl_tree_new((avl_compare_t)subnet_compare, (avl_action_t)subnet_free);
-
-       return true;
-}
-
-bool subnet_exit(void) {
-       avl_tree_del(subnets);
-       cache_exit();
-
-       return true;
-}
-
-subnet_t *str2net(const char *subnetstr) {
-       int i, l;
-       subnet_t subnet = {0};
-       uint16_t x[8];
-
-       if(sscanf(subnetstr, "%hu.%hu.%hu.%hu/%d",
-                         &x[0], &x[1], &x[2], &x[3], &l) == 5) {
-               subnet.type = SUBNET_TYPE_IPV4;
-               subnet.net.ipv4.prefixlength = l;
-
-               for(i = 0; i < 4; i++)
-                       subnet.net.ipv4.address.x[i] = x[i];
-
-               return copy(&subnet);
-       }
-
-       if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%d",
-                         &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7],
-                         &l) == 9) {
-               subnet.type = SUBNET_TYPE_IPV6;
-               subnet.net.ipv6.prefixlength = l;
-
-               for(i = 0; i < 8; i++)
-                       subnet.net.ipv6.address.x[i] = htons(x[i]);
-
-               return copy(&subnet);
-       }
-
-       if(sscanf(subnetstr, "%hu.%hu.%hu.%hu", &x[0], &x[1], &x[2], &x[3]) == 4) {
-               subnet.type = SUBNET_TYPE_IPV4;
-               subnet.net.ipv4.prefixlength = 32;
-
-               for(i = 0; i < 4; i++)
-                       subnet.net.ipv4.address.x[i] = x[i];
-
-               return copy(&subnet);
-       }
-
-       if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",
-                         &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7]) == 8) {
-               subnet.type = SUBNET_TYPE_IPV6;
-               subnet.net.ipv6.prefixlength = 128;
-
-               for(i = 0; i < 8; i++)
-                       subnet.net.ipv6.address.x[i] = htons(x[i]);
-
-               return copy(&subnet);
-       }
-
-       if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx",
-                         &x[0], &x[1], &x[2], &x[3], &x[4], &x[5]) == 6) {
-               subnet.type = SUBNET_TYPE_MAC;
-
-               for(i = 0; i < 6; i++)
-                       subnet.net.mac.address.x[i] = x[i];
-
-               return copy(&subnet);
-       }
-
-       return NULL;
-}
-
-char *net2str(const subnet_t *subnet) {
-       char *netstr;
-
-       switch (subnet->type) {
-               case SUBNET_TYPE_MAC:
-                       asprintf(&netstr, "%hx:%hx:%hx:%hx:%hx:%hx",
-                                        subnet->net.mac.address.x[0],
-                                        subnet->net.mac.address.x[1],
-                                        subnet->net.mac.address.x[2],
-                                        subnet->net.mac.address.x[3],
-                                        subnet->net.mac.address.x[4],
-                                        subnet->net.mac.address.x[5]);
-                       break;
-
-               case SUBNET_TYPE_IPV4:
-                       asprintf(&netstr, "%hu.%hu.%hu.%hu/%d",
-                                        subnet->net.ipv4.address.x[0],
-                                        subnet->net.ipv4.address.x[1],
-                                        subnet->net.ipv4.address.x[2],
-                                        subnet->net.ipv4.address.x[3],
-                                        subnet->net.ipv4.prefixlength);
-                       break;
-
-               case SUBNET_TYPE_IPV6:
-                       asprintf(&netstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%d",
-                                        ntohs(subnet->net.ipv6.address.x[0]),
-                                        ntohs(subnet->net.ipv6.address.x[1]),
-                                        ntohs(subnet->net.ipv6.address.x[2]),
-                                        ntohs(subnet->net.ipv6.address.x[3]),
-                                        ntohs(subnet->net.ipv6.address.x[4]),
-                                        ntohs(subnet->net.ipv6.address.x[5]),
-                                        ntohs(subnet->net.ipv6.address.x[6]),
-                                        ntohs(subnet->net.ipv6.address.x[7]),
-                                        subnet->net.ipv6.prefixlength);
-                       break;
-
-               default:
-                       logger(LOG_ERR, _("net2str() was called with unknown subnet type %d, exiting!"), subnet->type);
-                       exit(0);
-       }
-
-       return netstr;
-}
-
-bool cfg_subnet(cfg_t *cfg, subnet_t **result) {
-       subnet_t *subnet;
-
-       subnet = str2net(cfg->value);
-
-       if(!subnet) {
-               logger(LOG_ERR, _("rt: invalid subnet for configuration variable %s in %s line %d"),
-                  cfg->variable, cfg->file, cfg->line);
-               return false;
-       }
-
-       *result = subnet;
-
-       return true;
-}
-
-subnet_t *subnet_get(const subnet_t *subnet) {
-       return subnet->owner ? avl_get(subnet->owner->subnets, subnet) : avl_get(subnets, subnet);
-}
-
-subnet_t *subnet_get_mac(const mac_t *address) {
-       subnet_t *subnet, search = {0};
-
-       search.type = SUBNET_TYPE_MAC;
-       search.net.mac.address = *address;
-
-       subnet = cache_get(&search);
-       
-       if(subnet)
-               return subnet;
-
-       subnet = avl_get(subnets, &search);
-       
-       if(subnet)
-               cache_add(&search, subnet);
-
-       return subnet;
-}
-
-subnet_t *subnet_get_ipv4(const ipv4_t *address) {
-       subnet_t *subnet, search = {0};
-
-       search.type = SUBNET_TYPE_IPV4;
-       search.net.ipv4.address = *address;
-       search.net.ipv4.prefixlength = 32;
-
-       subnet = cache_get(&search);
-       
-       if(subnet)
-               return subnet;
-
-       while(subnet = avl_get_closest_smaller(subnets, &search)) {
-               if(subnet->type != SUBNET_TYPE_IPV4)
-                       return NULL;
-
-               if(!maskcmp(address, &subnet->net.ipv4.address, subnet->net.ipv4.prefixlength, sizeof(ipv4_t))) {
-                       cache_add(&search, subnet);
-                       return subnet;
-               }
-
-               search.net.ipv4.prefixlength = subnet->net.ipv4.prefixlength - 1;
-               maskcpy(&search.net.ipv4.address, &subnet->net.ipv4.address, search.net.ipv4.prefixlength, sizeof(ipv4_t));
-       }
-
-       return NULL;
-}
-
-subnet_t *subnet_get_ipv6(const ipv6_t *address) {
-       subnet_t *subnet, search = {0};
-
-       search.type = SUBNET_TYPE_IPV6;
-       search.net.ipv6.address = *address;
-       search.net.ipv6.prefixlength = 128;
-
-       subnet = cache_get(&search);
-       
-       if(subnet)
-               return subnet;
-
-       while(subnet = avl_get_closest_smaller(subnets, &search)) {
-               if(subnet->type != SUBNET_TYPE_IPV6)
-                       return NULL;
-
-               if(!maskcmp(address, &subnet->net.ipv6.address, subnet->net.ipv6.prefixlength, sizeof(ipv6_t))) {
-                       cache_add(&search, subnet);
-                       return subnet;
-               }
-
-               search.net.ipv6.prefixlength = subnet->net.ipv6.prefixlength - 1;
-               maskcpy(&search.net.ipv6.address, &subnet->net.ipv6.address, search.net.ipv6.prefixlength, sizeof(ipv6_t));
-       }
-
-       return NULL;
-}
diff --git a/rt/subnet.h b/rt/subnet.h
deleted file mode 100644 (file)
index 5134ae2..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
-    subnet.h -- subnet handling
-
-    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
-                  2003-2004 Ivo Timmermans <ivo@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#ifndef __SUBNET_H__
-#define __SUBNET_H__
-
-#include "rt/node.h"
-#include "support/avl.h"
-
-typedef struct mac {
-        uint8_t x[6];
-} mac_t;
-
-typedef struct ipv4 {
-        uint8_t x[4];
-} ipv4_t;
-
-typedef struct ipv6 {
-        uint16_t x[8];
-} ipv6_t;
-
-typedef enum subnet_type {
-       SUBNET_TYPE_MAC,
-       SUBNET_TYPE_IPV4,
-       SUBNET_TYPE_IPV6,
-} subnet_type_t;
-
-typedef struct subnet_mac {
-       mac_t address;
-} subnet_mac_t;
-
-typedef struct subnet_ipv4 {
-       ipv4_t address;
-       int prefixlength;
-} subnet_ipv4_t;
-
-typedef struct subnet_ipv6 {
-       ipv6_t address;
-       int prefixlength;
-} subnet_ipv6_t;
-
-typedef struct subnet {
-       struct node *owner;
-       struct timeval expires;
-
-       enum subnet_type type;
-
-       union net {
-               struct subnet_mac mac;
-               struct subnet_ipv4 ipv4;
-               struct subnet_ipv6 ipv6;
-       } net;
-} subnet_t;
-
-extern subnet_t *subnet_new(void) __attribute__ ((__malloc__));
-extern void subnet_free(struct subnet *);
-extern bool subnet_init(void);
-extern bool subnet_exit(void);
-extern avl_tree_t *subnet_tree_new(void) __attribute__ ((__malloc__));
-extern void subnet_tree_free(avl_tree_t *);
-extern void subnet_add(struct subnet *);
-extern void subnet_del(struct subnet *);
-extern char *net2str(const struct subnet *);
-extern struct subnet *str2net(const char *);
-extern struct subnet *subnet_get(const struct subnet *);
-extern struct subnet *subnet_get_mac(const struct mac *);
-extern struct subnet *subnet_get_ipv4(const struct ipv4 *);
-extern struct subnet *subnet_get_ipv6(const struct ipv6 *);
-
-#endif
diff --git a/src/avl.c b/src/avl.c
new file mode 100644 (file)
index 0000000..96500cb
--- /dev/null
+++ b/src/avl.c
@@ -0,0 +1,675 @@
+/*
+    avl.c -- AVL tree management
+
+    Copyright (C) 1998 Michael H. Buselli
+                  2000-2004 Ivo Timmermans <ivo@tinc-vpn.org>,
+                  2000-2004 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2004 Wessel Dankers <wsl@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    Original AVL tree library by Michael H. Buselli <cosine@cosine.org>.
+
+    Modified 2000-11-28 by Wessel Dankers <wsl@tinc-vpn.org> to use counts
+    instead of depths, to add the ->next and ->prev and to generally obfuscate
+    the code. Mail me if you found a bug.
+
+    Cleaned up and incorporated some of the ideas from the red-black tree
+    library for inclusion into tinc (http://www.tinc-vpn.org/) by
+    Guus Sliepen <guus@tinc-vpn.org>.
+
+    $Id$
+*/
+
+#include "system.h"
+
+#include "support/avl.h"
+#include "support/xalloc.h"
+
+#ifdef AVL_COUNT
+#define AVL_NODE_COUNT(n)  ((n) ? (n)->count : 0)
+#define AVL_L_COUNT(n)     (AVL_NODE_COUNT((n)->left))
+#define AVL_R_COUNT(n)     (AVL_NODE_COUNT((n)->right))
+#define AVL_CALC_COUNT(n)  (AVL_L_COUNT(n) + AVL_R_COUNT(n) + 1)
+#endif
+
+#ifdef AVL_DEPTH
+#define AVL_NODE_DEPTH(n)  ((n) ? (n)->depth : 0)
+#define L_AVL_DEPTH(n)     (AVL_NODE_DEPTH((n)->left))
+#define R_AVL_DEPTH(n)     (AVL_NODE_DEPTH((n)->right))
+#define AVL_CALC_DEPTH(n)  ((L_AVL_DEPTH(n)>R_AVL_DEPTH(n)?L_AVL_DEPTH(n):R_AVL_DEPTH(n)) + 1)
+#endif
+
+#ifndef AVL_DEPTH
+static int lg(unsigned int u) __attribute__ ((__const__));
+
+static int lg(unsigned int u) {
+       int r = 1;
+
+       if(!u)
+               return 0;
+
+       if(u & 0xffff0000) {
+               u >>= 16;
+               r += 16;
+       }
+
+       if(u & 0x0000ff00) {
+               u >>= 8;
+               r += 8;
+       }
+
+       if(u & 0x000000f0) {
+               u >>= 4;
+               r += 4;
+       }
+
+       if(u & 0x0000000c) {
+               u >>= 2;
+               r += 2;
+       }
+
+       if(u & 0x00000002)
+               r++;
+
+       return r;
+}
+#endif
+
+/* Internal helper functions */
+
+static int avl_check_balance(const avl_node_t *node) {
+#ifdef AVL_DEPTH
+       int d;
+
+       d = R_AVL_DEPTH(node) - L_AVL_DEPTH(node);
+
+       return d < -1 ? -1 : d > 1 ? 1 : 0;
+#else
+/*      int d;
+ *      d = lg(AVL_R_COUNT(node)) - lg(AVL_L_COUNT(node));
+ *      d = d<-1?-1:d>1?1:0;
+ */
+       int pl, r;
+
+       pl = lg(AVL_L_COUNT(node));
+       r = AVL_R_COUNT(node);
+
+       if(r >> pl + 1)
+               return 1;
+
+       if(pl < 2 || r >> pl - 2)
+               return 0;
+
+       return -1;
+#endif
+}
+
+static void avl_rebalance(avl_tree_t *tree, avl_node_t *node) {
+       avl_node_t *child;
+       avl_node_t *gchild;
+       avl_node_t *parent;
+       avl_node_t **superparent;
+
+       parent = node;
+
+       while(node) {
+               parent = node->parent;
+
+               superparent =
+                       parent ? node ==
+                       parent->left ? &parent->left : &parent->right : &tree->root;
+
+               switch (avl_check_balance(node)) {
+                       case -1:
+                               child = node->left;
+#ifdef AVL_DEPTH
+                               if(L_AVL_DEPTH(child) >= R_AVL_DEPTH(child)) {
+#else
+                               if(AVL_L_COUNT(child) >= AVL_R_COUNT(child)) {
+#endif
+                                       node->left = child->right;
+                                       if(node->left)
+                                               node->left->parent = node;
+
+                                       child->right = node;
+                                       node->parent = child;
+                                       *superparent = child;
+                                       child->parent = parent;
+#ifdef AVL_COUNT
+                                       node->count = AVL_CALC_COUNT(node);
+                                       child->count = AVL_CALC_COUNT(child);
+#endif
+#ifdef AVL_DEPTH
+                                       node->depth = AVL_CALC_DEPTH(node);
+                                       child->depth = AVL_CALC_DEPTH(child);
+#endif
+                               } else {
+                                       gchild = child->right;
+                                       node->left = gchild->right;
+
+                                       if(node->left)
+                                               node->left->parent = node;
+                                       child->right = gchild->left;
+
+                                       if(child->right)
+                                               child->right->parent = child;
+                                       gchild->right = node;
+
+                                       if(gchild->right)
+                                               gchild->right->parent = gchild;
+                                       gchild->left = child;
+
+                                       if(gchild->left)
+                                               gchild->left->parent = gchild;
+                                       *superparent = gchild;
+
+                                       gchild->parent = parent;
+#ifdef AVL_COUNT
+                                       node->count = AVL_CALC_COUNT(node);
+                                       child->count = AVL_CALC_COUNT(child);
+                                       gchild->count = AVL_CALC_COUNT(gchild);
+#endif
+#ifdef AVL_DEPTH
+                                       node->depth = AVL_CALC_DEPTH(node);
+                                       child->depth = AVL_CALC_DEPTH(child);
+                                       gchild->depth = AVL_CALC_DEPTH(gchild);
+#endif
+                               }
+                               break;
+
+                       case 1:
+                               child = node->right;
+#ifdef AVL_DEPTH
+                               if(R_AVL_DEPTH(child) >= L_AVL_DEPTH(child)) {
+#else
+                               if(AVL_R_COUNT(child) >= AVL_L_COUNT(child)) {
+#endif
+                                       node->right = child->left;
+                                       if(node->right)
+                                               node->right->parent = node;
+                                       child->left = node;
+                                       node->parent = child;
+                                       *superparent = child;
+                                       child->parent = parent;
+#ifdef AVL_COUNT
+                                       node->count = AVL_CALC_COUNT(node);
+                                       child->count = AVL_CALC_COUNT(child);
+#endif
+#ifdef AVL_DEPTH
+                                       node->depth = AVL_CALC_DEPTH(node);
+                                       child->depth = AVL_CALC_DEPTH(child);
+#endif
+                               } else {
+                                       gchild = child->left;
+                                       node->right = gchild->left;
+
+                                       if(node->right)
+                                               node->right->parent = node;
+                                       child->left = gchild->right;
+
+                                       if(child->left)
+                                               child->left->parent = child;
+                                       gchild->left = node;
+
+                                       if(gchild->left)
+                                               gchild->left->parent = gchild;
+                                       gchild->right = child;
+
+                                       if(gchild->right)
+                                               gchild->right->parent = gchild;
+
+                                       *superparent = gchild;
+                                       gchild->parent = parent;
+#ifdef AVL_COUNT
+                                       node->count = AVL_CALC_COUNT(node);
+                                       child->count = AVL_CALC_COUNT(child);
+                                       gchild->count = AVL_CALC_COUNT(gchild);
+#endif
+#ifdef AVL_DEPTH
+                                       node->depth = AVL_CALC_DEPTH(node);
+                                       child->depth = AVL_CALC_DEPTH(child);
+                                       gchild->depth = AVL_CALC_DEPTH(gchild);
+#endif
+                               }
+                               break;
+
+                       default:
+#ifdef AVL_COUNT
+                               node->count = AVL_CALC_COUNT(node);
+#endif
+#ifdef AVL_DEPTH
+                               node->depth = AVL_CALC_DEPTH(node);
+#endif
+               }
+               node = parent;
+       }
+}
+
+static int avl_compare(const void *a, const void *b) {
+       return a - b;
+}
+
+/* (De)constructors */
+
+avl_tree_t *avl_tree_new(avl_compare_t compare, avl_action_t free) {
+       avl_tree_t *tree;
+
+       clear(new(tree));
+       tree->compare = compare ?: avl_compare;
+       tree->free = free;
+
+       return tree;
+}
+
+void avl_tree_free(avl_tree_t *tree) {
+       free(tree);
+}
+
+avl_node_t *avl_node_new(void) {
+       avl_node_t *node;
+
+       return clear(new(node));
+}
+
+void avl_node_free(avl_tree_t *tree, avl_node_t *node) {
+       if(node->data && tree->free)
+               tree->free(node->data);
+
+       free(node);
+}
+
+/* Searching */
+
+void *avl_get(const avl_tree_t *tree, const void *data) {
+       avl_node_t *node;
+
+       node = avl_get_node(tree, data);
+
+       return node ? node->data : NULL;
+}
+
+void *avl_get_closest(const avl_tree_t *tree, const void *data, int *result) {
+       avl_node_t *node;
+
+       node = avl_get_closest_node(tree, data, result);
+
+       return node ? node->data : NULL;
+}
+
+void *avl_get_closest_smaller(const avl_tree_t *tree, const void *data) {
+       avl_node_t *node;
+
+       node = avl_get_closest_smaller_node(tree, data);
+
+       return node ? node->data : NULL;
+}
+
+void *avl_get_closest_greater(const avl_tree_t *tree, const void *data) {
+       avl_node_t *node;
+
+       node = avl_get_closest_greater_node(tree, data);
+
+       return node ? node->data : NULL;
+}
+
+avl_node_t *avl_get_node(const avl_tree_t *tree, const void *data) {
+       avl_node_t *node;
+       int result;
+
+       node = avl_get_closest_node(tree, data, &result);
+
+       return result ? NULL : node;
+}
+
+avl_node_t *avl_get_closest_node(const avl_tree_t *tree, const void *data, int *result) {
+       avl_node_t *node;
+       int c;
+
+       node = tree->root;
+
+       if(!node) {
+               if(result)
+                       *result = 0;
+               return NULL;
+       }
+
+       for(;;) {
+               c = tree->compare(data, node->data);
+
+               if(c < 0) {
+                       if(node->left)
+                               node = node->left;
+                       else {
+                               if(result)
+                                       *result = -1;
+                               break;
+                       }
+               } else if(c > 0) {
+                       if(node->right)
+                               node = node->right;
+                       else {
+                               if(result)
+                                       *result = 1;
+                               break;
+                       }
+               } else {
+                       if(result)
+                               *result = 0;
+                       break;
+               }
+       }
+
+       return node;
+}
+
+avl_node_t *avl_get_closest_smaller_node(const avl_tree_t *tree, const void *data) {
+       avl_node_t *node;
+       int result;
+
+       node = avl_get_closest_node(tree, data, &result);
+
+       if(result < 0)
+               node = node->prev;
+
+       return node;
+}
+
+avl_node_t *avl_get_closest_greater_node(const avl_tree_t *tree, const void *data) {
+       avl_node_t *node;
+       int result;
+
+       node = avl_get_closest_node(tree, data, &result);
+
+       if(result > 0)
+               node = node->next;
+
+       return node;
+}
+
+/* Insertion and deletion */
+
+avl_node_t *avl_add(avl_tree_t *tree, void *data) {
+       avl_node_t *node, *result;
+
+       node = avl_node_new();
+       node->data = data;
+       
+       result = avl_add_node(tree, node);
+
+       if(!result)
+               free(node);
+
+       return result;
+}
+
+avl_node_t *avl_add_node(avl_tree_t *tree, avl_node_t *node) {
+       avl_node_t *closest;
+       int result;
+
+       if(!tree->root)
+               avl_add_top(tree, node);
+       else {
+               closest = avl_get_closest_node(tree, node->data, &result);
+
+               switch (result) {
+                       case -1:
+                               avl_add_before(tree, closest, node);
+                               break;
+
+                       case 1:
+                               avl_add_after(tree, closest, node);
+                               break;
+
+                       case 0:
+                               return NULL;
+               }
+       }
+
+#ifdef AVL_COUNT
+       node->count = 1;
+#endif
+#ifdef AVL_DEPTH
+       node->depth = 1;
+#endif
+
+       return node;
+}
+
+void avl_add_top(avl_tree_t *tree, avl_node_t *node) {
+       node->prev = node->next = node->parent = NULL;
+       tree->head = tree->tail = tree->root = node;
+}
+
+void avl_add_before(avl_tree_t *tree, avl_node_t *before, avl_node_t *node) {
+       if(!before) {
+               if(tree->tail)
+                       avl_add_after(tree, tree->tail, node);
+               else
+                       avl_add_top(tree, node);
+               return;
+       }
+
+       node->next = before;
+       node->parent = before;
+       node->prev = before->prev;
+
+       if(before->left) {
+               avl_add_after(tree, before->prev, node);
+               return;
+       }
+
+       if(before->prev)
+               before->prev->next = node;
+       else
+               tree->head = node;
+
+       before->prev = node;
+       before->left = node;
+
+       avl_rebalance(tree, before);
+}
+
+void avl_add_after(avl_tree_t *tree, avl_node_t *after, avl_node_t *node) {
+       if(!after) {
+               if(tree->head)
+                       avl_add_before(tree, tree->head, node);
+               else
+                       avl_add_top(tree, node);
+               return;
+       }
+
+       if(after->right) {
+               avl_add_before(tree, after->next, node);
+               return;
+       }
+
+       node->prev = after;
+       node->parent = after;
+       node->next = after->next;
+
+       if(after->next)
+               after->next->prev = node;
+       else
+               tree->tail = node;
+
+       after->next = node;
+       after->right = node;
+
+       avl_rebalance(tree, after);
+}
+
+avl_node_t *avl_unlink(avl_tree_t *tree, const void *data) {
+       avl_node_t *node;
+
+       node = avl_get_node(tree, data);
+
+       if(node)
+               avl_unlink_node(tree, node);
+
+       return node;
+}
+
+void avl_unlink_node(avl_tree_t *tree, avl_node_t *node) {
+       avl_node_t *parent;
+       avl_node_t **superparent;
+       avl_node_t *subst, *left, *right;
+       avl_node_t *balnode;
+
+       if(node->prev)
+               node->prev->next = node->next;
+       else
+               tree->head = node->next;
+       if(node->next)
+               node->next->prev = node->prev;
+       else
+               tree->tail = node->prev;
+
+       parent = node->parent;
+
+       superparent =
+               parent ? node ==
+               parent->left ? &parent->left : &parent->right : &tree->root;
+
+       left = node->left;
+       right = node->right;
+       if(!left) {
+               *superparent = right;
+
+               if(right)
+                       right->parent = parent;
+
+               balnode = parent;
+       } else if(!right) {
+               *superparent = left;
+               left->parent = parent;
+               balnode = parent;
+       } else {
+               subst = node->prev;
+
+               if(subst == left) {
+                       balnode = subst;
+               } else {
+                       balnode = subst->parent;
+                       balnode->right = subst->left;
+
+                       if(balnode->right)
+                               balnode->right->parent = balnode;
+
+                       subst->left = left;
+                       left->parent = subst;
+               }
+
+               subst->right = right;
+               subst->parent = parent;
+               right->parent = subst;
+               *superparent = subst;
+       }
+
+       avl_rebalance(tree, balnode);
+
+       node->next = node->prev = node->parent = node->left = node->right = NULL;
+
+#ifdef AVL_COUNT
+       node->count = 0;
+#endif
+#ifdef AVL_DEPTH
+       node->depth = 0;
+#endif
+}
+
+void avl_del_node(avl_tree_t *tree, avl_node_t *node) {
+       avl_unlink_node(tree, node);
+       avl_node_free(tree, node);
+}
+
+bool avl_del(avl_tree_t *tree, void *data) {
+       avl_node_t *node;
+
+       node = avl_get_node(tree, data);
+
+       if(node)
+               avl_del_node(tree, node);
+
+       return node;
+}
+
+/* Fast tree cleanup */
+
+void avl_tree_del(avl_tree_t *tree) {
+       avl_node_t *node;
+
+       avl_foreach_node(tree, node, avl_node_free(tree, node));
+       
+       avl_tree_free(tree);
+}
+
+/* Indexing */
+
+#ifdef AVL_COUNT
+avl_count_t avl_count(const avl_tree_t *tree) {
+       return AVL_NODE_COUNT(tree->root);
+}
+
+void *avl_get_indexed(const avl_tree_t *tree, avl_count_t index) {
+       avl_node_t *node;
+
+       node = avl_get_indexed_node(tree, index);
+
+       return node ? node->data : NULL;
+}
+
+avl_node_t *avl_get_indexed_node(const avl_tree_t *tree, avl_count_t index) {
+       avl_node_t *node;
+       avl_count_t c;
+
+       node = tree->root;
+
+       while(node) {
+               c = AVL_L_COUNT(node);
+
+               if(index < c) {
+                       node = node->left;
+               } else if(index > c) {
+                       node = node->right;
+                       index -= c + 1;
+               } else {
+                       return node;
+               }
+       }
+
+       return NULL;
+}
+
+avl_count_t avl_index(const avl_node_t *node) {
+       avl_node_t *next;
+       avl_count_t index;
+
+       index = AVL_L_COUNT(node);
+
+       while((next = node->parent)) {
+               if(node == next->right)
+                       index += AVL_L_COUNT(next) + 1;
+               node = next;
+       }
+
+       return index;
+}
+#endif
+#ifdef AVL_DEPTH
+avl_depth_t avl_depth(const avl_tree_t *tree) {
+       return AVL_NODE_DEPTH(tree->root);
+}
+#endif
diff --git a/src/avl.h b/src/avl.h
new file mode 100644 (file)
index 0000000..ece7d1a
--- /dev/null
+++ b/src/avl.h
@@ -0,0 +1,149 @@
+/*
+    avl.h -- AVL tree management
+
+    Copyright (C) 1998 Michael H. Buselli
+                  2000-2004 Ivo Timmermans <ivo@tinc-vpn.org>,
+                  2000-2004 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2004 Wessel Dankers <wsl@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    Original AVL tree library by Michael H. Buselli <cosine@cosine.org>.
+
+    Modified 2000-11-28 by Wessel Dankers <wsl@tinc-vpn.org> to use counts
+    instead of depths, to add the ->next and ->prev and to generally obfuscate
+    the code. Mail me if you found a bug.
+
+    Cleaned up and incorporated some of the ideas from the red-black tree
+    library for inclusion into tinc (http://www.tinc-vpn.org/) by
+    Guus Sliepen <guus@tinc-vpn.org>.
+
+    $Id$
+*/
+
+
+#ifndef __AVL_H__
+#define __AVL_H__
+
+#ifndef AVL_DEPTH
+#ifndef AVL_COUNT
+#define AVL_DEPTH
+#endif
+#endif
+
+typedef uint32_t avl_count_t;
+typedef uint16_t avl_depth_t;
+
+typedef struct avl_node {
+       struct avl_node *next;
+       struct avl_node *prev;
+
+       struct avl_node *parent;
+       struct avl_node *left;
+       struct avl_node *right;
+
+#ifdef AVL_COUNT
+       avl_count_t count;
+#endif
+
+#ifdef AVL_DEPTH
+       avl_depth_t depth;
+#endif
+
+       void *data;
+} avl_node_t;
+
+typedef int (*avl_compare_t)(const void *, const void *);
+typedef void (*avl_action_t)(void *);
+typedef void (*avl_node_action_t)(struct avl_node *);
+
+typedef struct avl_tree {
+       struct avl_node *head;
+       struct avl_node *tail;
+
+       struct avl_node *root;
+
+       avl_compare_t compare;
+       avl_action_t free;
+} avl_tree_t;
+
+/* (De)constructors */
+
+extern struct avl_tree *avl_tree_new(avl_compare_t, avl_action_t);
+extern void avl_tree_free(struct avl_tree *);
+
+extern struct avl_node *avl_node_new(void);
+extern void avl_node_free(struct avl_tree *tree, struct avl_node *);
+
+/* Insertion and deletion */
+
+extern struct avl_node *avl_add(struct avl_tree *, void *);
+extern struct avl_node *avl_add_node(struct avl_tree *, struct avl_node *);
+
+extern void avl_add_top(struct avl_tree *, struct avl_node *);
+extern void avl_add_before(struct avl_tree *, struct avl_node *, struct avl_node *);
+extern void avl_add_after(struct avl_tree *, struct avl_node *, struct avl_node *);
+
+extern struct avl_node *avl_unlink(struct avl_tree *, const void *);
+extern void avl_unlink_node(struct avl_tree *tree, struct avl_node *);
+extern bool avl_del(struct avl_tree *, void *);
+extern void avl_del_node(struct avl_tree *, struct avl_node *);
+
+/* Fast tree cleanup */
+
+extern void avl_tree_del(struct avl_tree *);
+
+/* Searching */
+
+extern void *avl_get(const struct avl_tree *, const void *);
+extern void *avl_get_closest(const struct avl_tree *, const void *, int *);
+extern void *avl_get_closest_smaller(const struct avl_tree *, const void *);
+extern void *avl_get_closest_greater(const struct avl_tree *, const void *);
+
+extern struct avl_node *avl_get_node(const struct avl_tree *, const void *);
+extern struct avl_node *avl_get_closest_node(const struct avl_tree *, const void *, int *);
+extern struct avl_node *avl_get_closest_smaller_node(const struct avl_tree *, const void *);
+extern struct avl_node *avl_get_closest_greater_node(const struct avl_tree *, const void *);
+
+/* Tree walking */
+
+#define avl_foreach(tree, object, action) {avl_node_t *_node, *_next; \
+       for(_node = (tree)->head; _node; _node = _next) { \
+               _next = _node->next; \
+               (object) = _node->data; \
+               action; \
+       } \
+}
+
+#define avl_foreach_node(tree, node, action) {avl_node_t *_next; \
+       for((node) = (tree)->head; (node); (node) = _next) { \
+               _next = (node)->next; \
+               action; \
+       } \
+}
+
+/* Indexing */
+
+#ifdef AVL_COUNT
+extern avl_count_t avl_count(const struct avl_tree *);
+extern avl_count_t avl_index(const struct avl_node *);
+extern void *avl_get_indexed(const struct avl_tree *, avl_count_t);
+extern struct avl_node *avl_get_indexed_node(const struct avl_tree *, avl_count_t);
+#endif
+#ifdef AVL_DEPTH
+extern avl_depth_t avl_depth(const struct avl_tree *);
+#endif
+
+#endif
diff --git a/src/cfg.c b/src/cfg.c
new file mode 100644 (file)
index 0000000..f0c8dad
--- /dev/null
+++ b/src/cfg.c
@@ -0,0 +1,338 @@
+/*
+    cfg.c -- cfguration code
+
+    Copyright (C) 1998 Robert van der Meulen
+                  1998-2004 Ivo Timmermans <ivo@tinc-vpn.org>
+                  2000-2004 Guus Sliepen <guus@tinc-vpn.org>
+                 2000 Cris van Pelt <tribbel@arise.dhs.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#include "system.h"
+
+#include "cfg/cfg.h"
+#include "support/avl.h"
+#include "support/xalloc.h"
+
+static int cfg_compare(const cfg_t *a, const cfg_t *b) {
+       return strcasecmp(a->variable, b->variable) ?: (a->line - b->line) ?: strcmp(a->file, b->file);
+}
+
+avl_tree_t *cfg_tree_new(void) {
+       return avl_tree_new((avl_compare_t)cfg_compare, (avl_action_t)cfg_free);
+}
+
+void cfg_tree_del(avl_tree_t *cfgs) {
+       avl_tree_del(cfgs);
+}
+
+cfg_t *cfg_new(void) {
+       cfg_t *cfg;
+
+       return clear(new(cfg));
+}
+
+void cfg_free(cfg_t *cfg) {
+       replace(cfg->variable, NULL);
+       replace(cfg->value, NULL);
+       replace(cfg->file, NULL);
+       free(cfg);
+}
+
+void cfg_add(avl_tree_t *cfgs, cfg_t *cfg) {
+       avl_add(cfgs, cfg);
+}
+
+cfg_t *cfg_get(const avl_tree_t *cfgs, char *variable) {
+       cfg_t search, *cfg;
+
+       search.variable = variable;
+       search.file = "";
+       search.line = 0;
+
+       cfg = avl_get_closest_greater(cfgs, &search);
+
+       if(!cfg || strcasecmp(cfg->variable, variable))
+               return NULL;
+
+       return cfg;
+}
+
+cfg_t *cfg_get_next(const avl_tree_t *cfgs, const cfg_t *cfg) {
+       avl_node_t *avl;
+       cfg_t *next;
+
+       avl = avl_get_node(cfgs, cfg);
+
+       if(avl && avl->next) {
+               next = avl->next->data;
+
+               if(!strcasecmp(next->variable, cfg->variable))
+                       return next;
+       }
+
+       return NULL;
+}
+
+bool cfg_bool(const cfg_t *cfg, const bool def, bool *result) {
+       if(!cfg) {
+               *result = def;
+               return true;
+       }
+
+       if(!strcasecmp(cfg->value, "yes")) {
+               *result = true;
+               return true;
+       } else if(!strcasecmp(cfg->value, "no")) {
+               *result = false;
+               return true;
+       }
+
+       logger(LOG_ERR, _("cfg: \"yes\" or \"no\" expected for configuration variable %s in %s line %d"),
+                       cfg->variable, cfg->file, cfg->line);
+
+       return false;
+}
+
+bool cfg_int(const cfg_t *cfg, const int def, int *result) {
+       if(!cfg) {
+               *result = def;
+               return true;
+       }
+
+       if(sscanf(cfg->value, "%d", result) == 1)
+               return true;
+
+       logger(LOG_ERR, _("cfg: integer expected for configuration variable %s in %s line %d"),
+                  cfg->variable, cfg->file, cfg->line);
+
+       return false;
+}
+
+bool cfg_string(const cfg_t *cfg, const char *def, char **result) {
+       if(!cfg) {
+               *result = def ? xstrdup(def) : NULL;
+               return true;
+       }
+
+       *result = xstrdup(cfg->value);
+
+       return true;
+}
+
+bool cfg_choice(const cfg_t *cfg, const cfg_choice_t *choice, const int def, int *result) {
+       int i;
+       
+       if(!cfg) {
+               *result = def;
+               return true;
+       }
+
+       for(i = 0; choice[i].key; i++) {
+               if(!strcasecmp(cfg->variable, choice[i].key)) {
+                       *result = choice[i].value;
+                       return true;
+               }
+       }
+
+       logger(LOG_ERR, _("cfg: invalid choice for configuration variable %s in %s line %d"), 
+                       cfg->variable, cfg->file, cfg->line);
+
+       return false;
+}      
+
+bool cfg_period(const cfg_t *cfg, const int def, int *result) {
+       char unit;
+       
+       if(!cfg) {
+               *result = def;
+               return true;
+       }
+
+       if(sscanf(cfg->value, "%d%c", result, &unit) == 2) {
+               switch(unit) {
+                       case 's':
+                               break;
+                       case 'm':
+                               *result *= 60;
+                               break;
+                       case 'h':
+                               *result *= 60 * 60;
+                               break;
+                       case 'd':
+                               *result *= 60 * 60 * 24;
+                               break;
+                       case 'W':
+                               *result *= 60 * 60 * 24 * 7;
+                               break;
+                       case 'M':
+                               *result *= 60 * 60 * 24 * 30;
+                               break;
+                       case 'Y':
+                               *result *= 60 * 60 * 24 * 365;
+                               break;
+                       default:
+                               logger(LOG_ERR, _("cfg: invalid period for configuration variable %s in %s line %d"),
+                                               cfg->variable, cfg->file, cfg->line);
+                               return false;
+               }
+               return true;
+       }
+
+       if(sscanf(cfg->value, "%d", result) == 1)
+               return true;
+
+       logger(LOG_ERR, _("cfg: period expected for configuration variable %s in %s line %d"),
+                       cfg->variable, cfg->file, cfg->line);
+
+       return false;
+}
+
+static char *readline(FILE *fp, char **buf, size_t *buflen) {
+       char *newline = NULL;
+       char *p;
+       char *line;                                     /* The array that contains everything that has been read so far */
+       char *idx;                                      /* Read into this pointer, which points to an offset within line */
+       size_t size, newsize;                           /* The size of the current array pointed to by line */
+       size_t maxlen;                                  /* Maximum number of characters that may be read with fgets.  This is newsize - oldsize. */
+
+       if(feof(fp))
+               return NULL;
+
+       if(buf && buflen) {
+               size = *buflen;
+               line = *buf;
+       } else {
+               dim(line, size = 100);
+       }
+
+       maxlen = size;
+       idx = line;
+       *idx = 0;
+
+       for(;;) {
+               errno = 0;
+               p = fgets(idx, maxlen, fp);
+
+               if(!p) {
+                       if(feof(fp))
+                               break;
+
+                       logger(LOG_ERR, _("cfg: error while reading: %s"), strerror(errno));
+                       free(line);
+                       return NULL;
+               }
+
+               newline = strchr(p, '\n');
+
+               if(!newline) {
+                       idx = &line[size - 1];
+                       maxlen = size + 1;
+                       redim(line, size *= 2);
+               } else {
+                       *newline = '\0';
+                       break;
+               }
+       }
+
+       if(buf && buflen) {
+               *buflen = size;
+               *buf = line;
+       }
+
+       return line;
+}
+
+bool cfg_read_file(avl_tree_t *cfgs, const char *fname) {
+       FILE *fp;
+       char *buffer, *line;
+       char *variable, *value;
+       int lineno = 0;
+       int len;
+       bool result = false;
+       bool ignore = false;
+       cfg_t *cfg;
+       size_t bufsize;
+
+       fp = fopen(fname, "r");
+
+       if(!fp) {
+               logger(LOG_ERR, _("cfg: error opening %s: %s"), fname, strerror(errno));
+               return false;
+       }
+
+       dim(buffer, bufsize = 100);
+
+       for(;;) {
+               line = readline(fp, &buffer, &bufsize);
+
+               if(!line)
+                       break;
+
+               if(feof(fp)) {
+                       result = true;
+                       break;
+               }
+
+               lineno++;
+
+               if(!*line || *line == '#')
+                       continue;
+
+               if(ignore) {
+                       if(!strncmp(line, "-----END", 8))
+                               ignore = false;
+                       continue;
+               }
+               
+               if(!strncmp(line, "-----BEGIN", 10)) {
+                       ignore = true;
+                       continue;
+               }
+
+               variable = value = line;
+
+               len = strcspn(value, "\t =");
+               value += len;
+               value += strspn(value, "\t ");
+               if(*value == '=') {
+                       value++;
+                       value += strspn(value, "\t ");
+               }
+               variable[len] = '\0';
+
+               if(!*value) {
+                       logger(LOG_ERR, _("cfg: no value for variable %s on line %d while reading cfg file %s"),
+                                       variable, lineno, fname);
+                       break;
+               }
+
+               cfg = cfg_new();
+               replace(cfg->variable, variable);
+               replace(cfg->value, value);
+               replace(cfg->file, fname);
+               cfg->line = lineno;
+
+               cfg_add(cfgs, cfg);
+       }
+
+       free(buffer);
+       fclose(fp);
+
+       return result;
+}
diff --git a/src/cfg.h b/src/cfg.h
new file mode 100644 (file)
index 0000000..bbc0139
--- /dev/null
+++ b/src/cfg.h
@@ -0,0 +1,64 @@
+/*
+    conf.h -- header for conf.c
+
+    Copyright (C) 1998-2004 Ivo Timmermans <ivo@tinc-vpn.org>
+                  2000-2004 Guus Sliepen <guus@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#ifndef __TINC_CONF_H__
+#define __TINC_CONF_H__
+
+#include "support/avl.h"
+
+typedef struct cfg {
+       char *variable;
+       char *value;
+       char *file;
+       int line;
+} cfg_t;
+
+typedef struct cfg_choice {
+       char *key;
+       int value;
+} cfg_choice_t;
+
+extern avl_tree_t *cfgs;
+
+extern avl_tree_t *cfg_tree_new(void);
+extern void cfg_tree_free(avl_tree_t *);
+extern cfg_t *cfg_new(void) __attribute__ ((__malloc__));
+extern void cfg_free(cfg_t *);
+extern void cfg_add(avl_tree_t *, cfg_t *);
+extern void cfg_del(avl_tree_t *, cfg_t *);
+extern cfg_t *cfg_get(const avl_tree_t *, char *);
+extern cfg_t *cfg_get_next(const avl_tree_t *, const cfg_t *);
+extern bool cfg_bool(const cfg_t *, const bool, bool *);
+extern bool cfg_int(const cfg_t *, const int, int *);
+extern bool cfg_string(const cfg_t *, const char *, char **);
+extern bool cfg_choice(const cfg_t *, const cfg_choice_t *, const int, int *);
+extern bool cfg_period(const cfg_t *, const int, int *);
+#define cfg_get_bool(tree, var, def, result) cfg_bool(cfg_get(tree, var), def, result)
+#define cfg_get_int(tree, var, def, result) cfg_int(cfg_get(tree, var), def, result)
+#define cfg_get_string(tree, var, def, result) cfg_string(cfg_get(tree, var), def, result)
+#define cfg_get_choice(tree, var, choice, def, result) cfg_choice(cfg_get(tree, var), choice, def, (int *)result)
+#define cfg_get_period(tree, var, def, result) cfg_period(cfg_get(tree, var), def, (int *)result)
+
+extern bool cfg_read_file(avl_tree_t *, const char *);
+
+#endif
diff --git a/src/edge.c b/src/edge.c
new file mode 100644 (file)
index 0000000..bf78d1f
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+    edge.c -- edge management
+
+    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
+                  2003-2004 Ivo Timmermans <ivo@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#include "system.h"
+
+#include "rt/edge.h"
+#include "rt/node.h"
+#include "support/avl.h"
+#include "support/xalloc.h"
+
+avl_tree_t *edges;
+
+static int edge_compare(const edge_t *a, const edge_t *b) {
+       return strcmp(a->to->name, b->to->name);
+}
+
+static int edge_weight_compare(const edge_t *a, const edge_t *b) {
+       return (a->weight - b->weight) ?: strcmp(a->from->name, b->from->name) ?: strcmp(a->to->name, b->to->name);
+}
+
+bool edge_init(void) {
+       edges = avl_tree_new((avl_compare_t)edge_weight_compare, NULL);
+
+       return true;
+}
+
+bool edge_exit(void) {
+       avl_tree_free(edges);
+
+       return true;
+}
+
+avl_tree_t *edge_tree_new(void) {
+       return avl_tree_new((avl_compare_t)edge_compare, (avl_action_t)edge_free);
+}
+
+void edge_tree_free(avl_tree_t *edge_tree) {
+       avl_tree_free(edge_tree);
+}
+
+edge_t *edge_new(void) {
+       edge_t *edge;
+
+       return clear(new(edge));
+}
+
+void edge_free(edge_t *edge) {
+       free(edge);
+}
+
+void edge_add(edge_t *edge) {
+       avl_add(edge->from->edges, edge);
+       avl_add(edges, edge);
+
+       edge->reverse = edge_get(edge->to, edge->from);
+
+       if(edge->reverse)
+               edge->reverse->reverse = edge;
+}
+
+void edge_del(edge_t *edge) {
+       if(edge->reverse)
+               edge->reverse->reverse = NULL;
+
+       avl_del(edges, edge);
+       avl_del(edge->from->edges, edge);
+}
+
+edge_t *edge_get(node_t *from, node_t *to) {
+       edge_t search = {0};
+       
+       search.from = from;
+       search.to = to;
+
+       return avl_get(from->edges, &search);
+}
+
diff --git a/src/edge.h b/src/edge.h
new file mode 100644 (file)
index 0000000..775d833
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+    edge.h -- edge management
+    
+    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
+                  2003-2004 Ivo Timmermans <ivo@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#ifndef __EDGE_H__
+#define __EDGE_H__
+
+#include "rt/node.h"
+#include "support/avl.h"
+#include "tnl/tnl.h"
+
+typedef struct edge_status {
+       int visited:1;
+       int mst:1;
+} edge_status_t;
+
+typedef struct edge {
+       struct node *from;
+       struct node *to;
+       struct sockaddr_storage address;
+
+       int weight;
+
+       struct edge *reverse;
+       struct tnl *tnl;
+
+       edge_status_t status;
+       node_options_t options;
+} edge_t;
+
+extern avl_tree_t *edges;
+
+extern bool edge_init(void);
+extern bool edge_exit(void);
+extern struct edge *edge_new(void) __attribute__ ((__malloc__));
+extern void edge_free(struct edge *);
+extern avl_tree_t *edge_tree_new(void) __attribute__ ((__malloc__));
+extern void edge_tree_free(avl_tree_t *);
+extern void edge_add(struct edge *);
+extern void edge_del(struct edge *);
+extern struct edge *edge_get(struct node *, struct node *);
+
+#endif
diff --git a/src/ethernet.h b/src/ethernet.h
new file mode 100644 (file)
index 0000000..e7ad508
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+    ethernet.h -- missing Ethernet related definitions
+    Copyright (C) 2004 Ivo Timmermans <ivo@tinc-vpn.org>
+                  2004 Guus Sliepen <guus@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#ifndef __ETHERNET_H__
+#define __ETHERNET_H__
+
+#ifndef ETH_ALEN
+#define ETH_ALEN 6
+#endif
+
+#ifndef ARPHRD_ETHER
+#define ARPHRD_ETHER 1
+#endif
+
+#ifndef ETH_P_IP
+#define ETH_P_IP 0x0800
+#endif
+
+#ifndef ETH_P_ARP
+#define ETH_P_ARP 0x0806
+#endif
+
+#ifndef ETH_P_IPV6
+#define ETH_P_IPV6 0x86DD
+#endif
+
+#ifndef HAVE_STRUCT_ETHER_HEADER
+struct ether_header {
+       uint8_t ether_dhost[ETH_ALEN];
+       uint8_t ether_shost[ETH_ALEN];
+       uint16_t ether_type;
+} __attribute__ ((__packed__));
+#endif
+
+#ifndef HAVE_STRUCT_ARPHDR
+struct arphdr {
+       uint16_t ar_hrd;
+       uint16_t ar_pro;
+       uint8_t ar_hln;
+       uint8_t ar_pln; 
+       uint16_t ar_op; 
+} __attribute__ ((__packed__));
+
+#define ARPOP_REQUEST 1 
+#define ARPOP_REPLY 2 
+#define ARPOP_RREQUEST 3 
+#define ARPOP_RREPLY 4 
+#define ARPOP_InREQUEST 8 
+#define ARPOP_InREPLY 9 
+#define ARPOP_NAK 10 
+#endif
+
+#ifndef HAVE_STRUCT_ETHER_ARP
+struct  ether_arp {
+       struct  arphdr ea_hdr;
+       uint8_t arp_sha[ETH_ALEN];
+       uint8_t arp_spa[4];
+       uint8_t arp_tha[ETH_ALEN];
+       uint8_t arp_tpa[4];
+} __attribute__ ((__packed__));
+#define arp_hrd ea_hdr.ar_hrd
+#define arp_pro ea_hdr.ar_pro
+#define arp_hln ea_hdr.ar_hln
+#define arp_pln ea_hdr.ar_pln
+#define arp_op ea_hdr.ar_op
+#endif
+
+#endif
diff --git a/src/gettext.h b/src/gettext.h
new file mode 100644 (file)
index 0000000..a907403
--- /dev/null
@@ -0,0 +1,79 @@
+/* Convenience header for conditional use of GNU <libintl.h>.
+   Copyright (C) 1995-1998, 2000-2003 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Library General Public License as published
+   by the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+   USA.  */
+
+#ifndef _LIBGETTEXT_H
+#define _LIBGETTEXT_H 1
+
+/* NLS can be disabled through the configure --disable-nls option.  */
+#if ENABLE_NLS
+
+/* Get declarations of GNU message catalog functions.  */
+# include <libintl.h>
+# include <locale.h>
+
+/* Shorthand notation */
+
+# define _(Text) gettext (Text)
+
+#else
+
+/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which
+   chokes if dcgettext is defined as a macro.  So include it now, to make
+   later inclusions of <locale.h> a NOP.  We don't include <libintl.h>
+   as well because people using "gettext.h" will not include <libintl.h>,
+   and also including <libintl.h> would fail on SunOS 4, whereas <locale.h>
+   is OK.  */
+#if defined(__sun)
+# include <locale.h>
+#endif
+
+/* Disabled NLS.
+   The casts to 'const char *' serve the purpose of producing warnings
+   for invalid uses of the value returned from these functions.
+   On pre-ANSI systems without 'const', the config.h file is supposed to
+   contain "#define const".  */
+# define gettext(Msgid) ((const char *) (Msgid))
+# define dgettext(Domainname, Msgid) ((const char *) (Msgid))
+# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid))
+# define ngettext(Msgid1, Msgid2, N) \
+    ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
+# define dngettext(Domainname, Msgid1, Msgid2, N) \
+    ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
+# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \
+    ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
+# define textdomain(Domainname) ((const char *) (Domainname))
+# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname))
+# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset))
+
+# define _(Text) Text
+# define setlocale(Category, Locale) ((const char *) (Locale))
+
+#endif
+
+/* A pseudo function call that serves as a marker for the automated
+   extraction of messages, but does not call gettext().  The run-time
+   translation is done at a different place in the code.
+   The argument, String, should be a literal string.  Concatenated strings
+   and other string expressions won't work.
+   The macro's expansion is not parenthesized, so that it is suitable as
+   initializer for static 'char[]' or 'const char[]' variables.  */
+#define gettext_noop(String) String
+
+#define N_(Text) Text
+
+#endif /* _LIBGETTEXT_H */
diff --git a/src/graph.c b/src/graph.c
new file mode 100644 (file)
index 0000000..63e8faf
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+    graph.c -- graph algorithms
+    Copyright (C) 2001-2004 Guus Sliepen <guus@tinc-vpn.org>,
+                  2001-2004 Ivo Timmermans <ivo@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+/* We need to generate two trees from the graph:
+
+   1. A minimum spanning tree for broadcasts,
+   2. A single-source shortest path tree for unicasts.
+
+   Actually, the first one alone would suffice but would make unicast packets
+   take longer routes than necessary.
+
+   For the MST algorithm we can choose from Prim's or Kruskal's. I personally
+   favour Kruskal's, because we make an extra AVL tree of edges sorted on
+   weights (metric). That tree only has to be updated when an edge is added or
+   removed, and during the MST algorithm we just have go linearly through that
+   tree, adding safe edges until #edges = #nodes - 1. The implementation here
+   however is not so fast, because I tried to avoid having to make a forest and
+   merge trees.
+
+   For the SSSP algorithm Dijkstra's seems to be a nice choice. Currently a
+   simple breadth-first search is presented here.
+
+   The SSSP algorithm will also be used to determine whether nodes are directly,
+   indirectly or not reachable from the source. It will also set the correct
+   destination address and port of a node if possible.
+*/
+
+#include "system.h"
+
+#include "rt/edge.h"
+#include "rt/node.h"
+#include "support/avl.h"
+#include "support/list.h"
+
+/* Implementation of Kruskal's algorithm.
+   Running time: O(EN)
+   Please note that sorting on weight is already done by add_edge().
+*/
+
+void mst_kruskal(void) {
+       avl_node_t *avl, *next;
+       edge_t *edge;
+       node_t *node;
+       int safe_edges = 0;
+       bool skipped;
+
+       /* Do we have something to do at all? */
+
+       if(!edges->head)
+               return;
+
+       logger(LOG_DEBUG, "Running Kruskal's algorithm:");
+
+       /* Clear MST status on edges */
+
+       avl_foreach(edges, edge, edge->status.mst = false);
+
+       /* Clear visited status on nodes */
+
+       avl_foreach(nodes, node, node->status.visited = false);
+
+       /* Starting point */
+
+       ((edge_t *) edges->head->data)->from->status.visited = true;
+
+       /* Add safe edges */
+
+       for(skipped = false, avl = edges->head; avl; avl = next) {
+               next = avl->next;
+               edge = avl->data;
+
+               if(!edge->reverse || edge->from->status.visited == edge->to->status.visited) {
+                       skipped = true;
+                       continue;
+               }
+
+               edge->from->status.visited = true;
+               edge->to->status.visited = true;
+               edge->status.mst = true;
+               edge->reverse->status.mst = true;
+
+               if(skipped) {
+                       skipped = false;
+                       next = edges->head;
+                       continue;
+               }
+       }
+}
+
+/* Implementation of a simple breadth-first search algorithm.
+   Running time: O(E)
+*/
+
+void sssp_bfs(void) {
+       list_t *todo;
+       list_node_t *todonode;
+       edge_t *edge;
+       node_t *node;
+       bool indirect;
+       char *name;
+       char *address, *port;
+       int i;
+
+       todo = list_new(NULL);
+
+       /* Clear visited status on nodes */
+
+       avl_foreach(nodes, node, {
+               node->status.visited = false;
+               node->status.indirect = true;
+       });
+
+       /* Begin with myself */
+
+       myself->status.visited = true;
+       myself->status.indirect = false;
+       myself->nexthop = myself;
+       myself->via = myself;
+
+       list_add_head(todo, myself);
+
+       /* Loop while todo list is filled */
+
+       while(todo->head) {
+               list_foreach_node(todo, todonode, {
+                       node = todonode->data;
+
+                       avl_foreach(node->edges, edge, {
+                               if(!edge->reverse)
+                                       continue;
+
+                               /* Situation:
+
+                                            /
+                                           /
+                                  ----->(node)---edge-->(edge->to)
+                                           \
+                                            \
+
+                                  node->address is set to the ->address of the edge left of node.
+                                  We are currently examining the edge right of node:
+
+                                  - If edge->reverse->address != node->address, then edge->to is probably
+                                    not reachable for the nodes left of node. We do as if the indirectdata
+                                    flag is set on edge.
+                                  - If edge provides for better reachability of edge->to, update
+                                    edge->to and (re)add it to the todo_tree to (re)examine the reachability
+                                    of nodes behind it.
+                                */
+
+                               indirect = node->status.indirect || edge->options & NODE_OPTION_INDIRECT
+                                       || ((node != myself) && sockaddrcmp(&node->address, &edge->reverse->address));
+
+                               if(edge->to->status.visited && (!edge->to->status.indirect || indirect))
+                                       continue;
+
+                               edge->to->status.visited = true;
+                               edge->to->status.indirect = indirect;
+                               edge->to->nexthop = (node->nexthop == myself) ? edge->to : node->nexthop;
+                               edge->to->via = indirect ? node->via : edge->to;
+                               edge->to->options = edge->options;
+
+                               list_add_head(todo, edge->to);
+                       });
+
+                       list_del_node(todo, todonode);
+               });
+       }
+
+       list_free(todo);
+
+       /* Check reachability status. */
+
+       avl_foreach(nodes, node, {
+               if(node->status.visited != node->status.reachable) {
+                       node->status.reachable = !node->status.reachable;
+
+                       if(node->status.reachable)
+                               logger(LOG_DEBUG, _("Node %s became reachable"), node->name);
+                       else
+                               logger(LOG_DEBUG, _("Node %s became unreachable"), node->name);
+
+#if 0
+                       asprintf(&envp[0], "NETNAME=%s", netname ? : "");
+                       asprintf(&envp[1], "DEVICE=%s", device ? : "");
+                       asprintf(&envp[2], "INTERFACE=%s", iface ? : "");
+                       asprintf(&envp[3], "NODE=%s", n->name);
+                       sockaddr2str(&n->address, &address, &port);
+                       asprintf(&envp[4], "REMOTEADDRESS=%s", address);
+                       asprintf(&envp[5], "REMOTEPORT=%s", port);
+                       envp[6] = NULL;
+
+                       asprintf(&name,
+                                        n->status.reachable ? "hosts/%s-up" : "hosts/%s-down",
+                                        n->name);
+                       execute_script(name, envp);
+
+                       free(name);
+                       free(address);
+                       free(port);
+
+                       for(i = 0; i < 7; i++)
+                               free(envp[i]);
+#endif
+               }
+       });
+}
+
+void graph(void)
+{
+       mst_kruskal();
+       sssp_bfs();
+}
diff --git a/src/graph.h b/src/graph.h
new file mode 100644 (file)
index 0000000..91f58fd
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+    graph.h -- graph algorithms
+
+    Copyright (C) 2001-2004 Guus Sliepen <guus@tinc-vpn.org>,
+                  2001-2004 Ivo Timmermans <ivo@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#ifndef __GRAPH_H__
+#define __GRAPH_H__
+
+extern bool graph_changed;
+extern void graph(void);
+
+#endif /* __GRAPH_H__ */
diff --git a/src/ipv4.h b/src/ipv4.h
new file mode 100644 (file)
index 0000000..19a290b
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+    ipv4.h -- missing IPv4 related definitions
+
+    Copyright (C) 2003-2004 Ivo Timmermans <ivo@tinc-vpn.org>
+                  2003-2004 Guus Sliepen <guus@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#ifndef __IPV4_H__
+#define __IPV4_H__
+
+#ifndef AF_INET
+#define AF_INET 2
+#endif
+
+#ifndef IPPROTO_ICMP
+#define IPPROTO_ICMP 1
+#endif
+
+#ifndef ICMP_DEST_UNREACH
+#define ICMP_DEST_UNREACH 3
+#endif
+
+#ifndef ICMP_NET_UNKNOWN
+#define ICMP_NET_UNKNOWN 6
+#endif
+
+#ifndef ICMP_NET_UNREACH
+#define ICMP_NET_UNREACH 0
+#endif
+
+#ifndef IP_MSS
+#define       IP_MSS          576
+#endif
+
+#ifndef HAVE_STRUCT_IP
+struct ip {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+       unsigned int ip_hl:4;
+       unsigned int ip_v:4;
+#else
+       unsigned int ip_v:4;
+       unsigned int ip_hl:4;
+#endif
+       uint8_t ip_tos;
+       uint16_t ip_len;
+       uint16_t ip_id; 
+       uint16_t ip_off;
+#define IP_RF 0x8000
+#define IP_DF 0x4000
+#define IP_MF 0x2000
+#define IP_OFFMASK 0x1fff
+       uint8_t ip_ttl;
+       uint8_t ip_p;
+       uint16_t ip_sum;
+       struct in_addr ip_src, ip_dst;
+} __attribute__ ((__packed__));
+#endif
+
+#ifndef HAVE_STRUCT_ICMP
+struct icmp {
+       uint8_t icmp_type;
+       uint8_t icmp_code;
+       uint16_t icmp_cksum;
+       union {
+               uint8_t ih_pptr;
+               struct in_addr ih_gwaddr;
+               struct ih_idseq {
+                       uint16_t icd_id;
+                       uint16_t icd_seq;
+               } ih_idseq;
+               uint32_t ih_void;
+
+
+               struct ih_pmtu {
+                       uint16_t ipm_void;
+                       uint16_t ipm_nextmtu;
+               } ih_pmtu;
+
+               struct ih_rtradv {
+                       uint8_t irt_num_addrs;
+                       uint8_t irt_wpa;
+                       uint16_t irt_lifetime;
+               } ih_rtradv;
+       } icmp_hun;
+#define icmp_pptr icmp_hun.ih_pptr
+#define icmp_gwaddr icmp_hun.ih_gwaddr
+#define icmp_id icmp_hun.ih_idseq.icd_id
+#define icmp_seq icmp_hun.ih_idseq.icd_seq
+#define icmp_void icmp_hun.ih_void
+#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void
+#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu
+#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs
+#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa
+#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime
+       union {
+               struct {
+                       uint32_t its_otime;
+                       uint32_t its_rtime;
+                       uint32_t its_ttime;
+               } id_ts;
+               struct {
+                       struct ip idi_ip;
+               } id_ip;
+               uint32_t id_mask;
+               uint8_t id_data[1];
+       } icmp_dun;
+#define icmp_otime icmp_dun.id_ts.its_otime
+#define icmp_rtime icmp_dun.id_ts.its_rtime
+#define icmp_ttime icmp_dun.id_ts.its_ttime
+#define icmp_ip icmp_dun.id_ip.idi_ip
+#define icmp_radv icmp_dun.id_radv
+#define icmp_mask icmp_dun.id_mask
+#define icmp_data icmp_dun.id_data
+} __attribute__ ((__packed__));
+#endif
+
+#endif
diff --git a/src/ipv6.h b/src/ipv6.h
new file mode 100644 (file)
index 0000000..5de7953
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+    ipv6.h -- missing IPv6 related definitions
+
+    Copyright (C) 2003-2004 Ivo Timmermans <ivo@tinc-vpn.org>
+                  2003-2004 Guus Sliepen <guus@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#ifndef __IPV6_H__
+#define __IPV6_H__
+
+#ifndef AF_INET6
+#define AF_INET6 10
+#endif
+
+#ifndef IPPROTO_ICMPV6
+#define IPPROTO_ICMPV6 58
+#endif
+
+#ifndef HAVE_STRUCT_IN6_ADDR
+struct in6_addr {
+       union {
+               uint8_t u6_addr8[16];
+               uint16_t u6_addr16[8];
+               uint32_t u6_addr32[4];
+       } in6_u;
+} __attribute__ ((__packed__));
+#define s6_addr in6_u.u6_addr8
+#define s6_addr16 in6_u.u6_addr16
+#define s6_addr32 in6_u.u6_addr32
+#endif
+
+#ifndef HAVE_STRUCT_SOCKADDR_IN6
+struct sockaddr_in6 {
+       uint16_t sin6_family;
+       uint16_t sin6_port;
+       uint32_t sin6_flowinfo;
+       struct in6_addr sin6_addr;
+       uint32_t sin6_scope_id;
+} __attribute__ ((__packed__));
+#endif
+
+#ifndef IN6_IS_ADDR_V4MAPPED
+#define IN6_IS_ADDR_V4MAPPED(a) \
+        ((((__const uint32_t *) (a))[0] == 0) \
+        && (((__const uint32_t *) (a))[1] == 0) \
+        && (((__const uint32_t *) (a))[2] == htonl (0xffff)))
+#endif
+
+#ifndef HAVE_STRUCT_IP6_HDR
+struct ip6_hdr {
+       union {
+               struct ip6_hdrctl {
+                       uint32_t ip6_un1_flow;
+                       uint16_t ip6_un1_plen;
+                       uint8_t ip6_un1_nxt;
+                       uint8_t ip6_un1_hlim;
+               } ip6_un1;
+               uint8_t ip6_un2_vfc;
+       } ip6_ctlun;
+       struct in6_addr ip6_src;
+       struct in6_addr ip6_dst;
+} __attribute__ ((__packed__));
+#define ip6_vfc ip6_ctlun.ip6_un2_vfc
+#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow
+#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen
+#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt
+#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim
+#define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim
+#endif
+
+#ifndef HAVE_STRUCT_ICMP6_HDR
+struct icmp6_hdr {
+       uint8_t icmp6_type;
+       uint8_t icmp6_code;
+       uint16_t icmp6_cksum;
+       union {
+               uint32_t icmp6_un_data32[1];
+               uint16_t icmp6_un_data16[2];
+               uint8_t icmp6_un_data8[4];
+       } icmp6_dataun;
+} __attribute__ ((__packed__));
+#define ICMP6_DST_UNREACH_NOROUTE 0
+#define ICMP6_DST_UNREACH 1
+#define ICMP6_DST_UNREACH_ADDR 3
+#define ND_NEIGHBOR_SOLICIT 135
+#define ND_NEIGHBOR_ADVERT 136
+#define icmp6_data32 icmp6_dataun.icmp6_un_data32
+#define icmp6_data16 icmp6_dataun.icmp6_un_data16
+#define icmp6_data8 icmp6_dataun.icmp6_un_data8
+#endif
+
+#ifndef HAVE_STRUCT_ND_NEIGHBOR_SOLICIT
+struct nd_neighbor_solicit {
+       struct icmp6_hdr nd_ns_hdr;
+       struct in6_addr nd_ns_target;
+} __attribute__ ((__packed__));
+#define ND_OPT_SOURCE_LINKADDR 1
+#define ND_OPT_TARGET_LINKADDR 2
+#define nd_ns_type nd_ns_hdr.icmp6_type
+#define nd_ns_code nd_ns_hdr.icmp6_code
+#define nd_ns_cksum nd_ns_hdr.icmp6_cksum
+#define nd_ns_reserved nd_ns_hdr.icmp6_data32[0]
+#endif
+
+#ifndef HAVE_STRUCT_ND_OPT_HDR
+struct nd_opt_hdr {
+       uint8_t nd_opt_type;
+       uint8_t nd_opt_len;
+} __attribute__ ((__packed__));
+#endif
+
+#endif
diff --git a/src/list.c b/src/list.c
new file mode 100644 (file)
index 0000000..9e54ac0
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+    list.c -- linked lists
+    Copyright (C) 2000-2004 Ivo Timmermans <ivo@tinc-vpn.org>
+                  2000-2004 Guus Sliepen <guus@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id: list.c 1374 2004-03-21 14:21:22Z guus $
+*/
+
+#include "system.h"
+
+#include "support/list.h"
+#include "support/xalloc.h"
+
+list_t *list_new(list_action_t free) {
+       list_t *list;
+
+       clear(new(list));
+       list->free = free;
+
+       return list;
+}
+
+void list_free(list_t *list) {
+       free(list);
+}
+
+list_node_t *list_node_new(void) {
+       list_node_t *node;
+
+       return clear(new(node));
+}
+
+void list_node_free(list_t *list, list_node_t *node) {
+       if(node->data && list->free)
+               list->free(node->data);
+
+       free(node);
+}
+
+list_node_t *list_add_head(list_t *list, void *data) {
+       list_node_t *node;
+
+       node = list_node_new();
+
+       node->data = data;
+       node->prev = NULL;
+       node->next = list->head;
+       list->head = node;
+
+       if(node->next)
+               node->next->prev = node;
+       else
+               list->tail = node;
+
+       list->count++;
+
+       return node;
+}
+
+list_node_t *list_add_tail(list_t *list, void *data) {
+       list_node_t *node;
+
+       node = list_node_new();
+
+       node->data = data;
+       node->next = NULL;
+       node->prev = list->tail;
+       list->tail = node;
+
+       if(node->prev)
+               node->prev->next = node;
+       else
+               list->head = node;
+
+       list->count++;
+
+       return node;
+}
+
+void list_unlink_node(list_t *list, list_node_t *node) {
+       if(node->prev)
+               node->prev->next = node->next;
+       else
+               list->head = node->next;
+
+       if(node->next)
+               node->next->prev = node->prev;
+       else
+               list->tail = node->prev;
+
+       list->count--;
+}
+
+void list_del_node(list_t *list, list_node_t *node) {
+       list_unlink_node(list, node);
+       list_node_free(list, node);
+}
+
+void list_del_head(list_t *list) {
+       list_del_node(list, list->head);
+}
+
+void list_del_tail(list_t *list) {
+       list_del_node(list, list->tail);
+}
+
+void *list_get_head(const list_t *list) {
+       if(list->head)
+               return list->head->data;
+       else
+               return NULL;
+}
+
+void *list_get_tail(const list_t *list) {
+       if(list->tail)
+               return list->tail->data;
+       else
+               return NULL;
+}
+
+void list_del(list_t *list) {
+       list_node_t *node;
+
+       list_foreach_node(list, node, list_node_free(list, node));
+       list_free(list);
+}
diff --git a/src/list.h b/src/list.h
new file mode 100644 (file)
index 0000000..124d7fc
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+    list.h -- linked lists
+
+    Copyright (C) 2000-2004 Ivo Timmermans <ivo@tinc-vpn.org>
+                  2000-2004 Guus Sliepen <guus@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id: list.h 1374 2004-03-21 14:21:22Z guus $
+*/
+
+#ifndef __LIST_H__
+#define __LIST_H__
+
+typedef struct list_node {
+       struct list_node *prev;
+       struct list_node *next;
+
+       void *data;
+} list_node_t;
+
+typedef void (*list_action_t)(const void *);
+typedef void (*list_node_action_t)(const list_node_t *);
+
+typedef struct list {
+       struct list_node *head;
+       struct list_node *tail;
+       int count;
+
+       list_action_t free;
+} list_t;
+
+/* (De)constructors */
+
+extern struct list *list_new(list_action_t) __attribute__ ((__malloc__));
+extern void list_free(struct list *);
+extern struct list_node *list_node_new(void);
+extern void list_node_free(struct list *, struct list_node *);
+
+/* Insertion and deletion */
+
+extern struct list_node *list_add_head(struct list *, void *);
+extern struct list_node *list_add_tail(struct list *, void *);
+
+extern void list_unlink_node(struct list *, struct list_node *);
+extern void list_node_del(struct list *, struct list_node *);
+
+extern void list_del_head(struct list *);
+extern void list_del_tail(struct list *);
+
+/* Head/tail lookup */
+
+extern void *list_get_head(const struct list *);
+extern void *list_get_tail(const struct list *);
+
+/* Fast list deletion */
+
+extern void list_del(struct list *);
+
+/* Traversing */
+
+#define list_foreach(list, object, action) {list_node_t *_node, *_next; \
+        for(_node = (list)->head; _node; _node = _next) { \
+                _next = _node->next; \
+                (object) = _node->data; \
+                action; \
+        } \
+}
+
+#define list_foreach_node(list, node, action) {list_node_t *_next; \
+        for((node) = (list)->head; (node); (node) = _next) { \
+                _next = (node)->next; \
+                action; \
+        } \
+}
+
+#endif
diff --git a/src/log.h b/src/log.h
new file mode 100644 (file)
index 0000000..e178d69
--- /dev/null
+++ b/src/log.h
@@ -0,0 +1,77 @@
+/*
+    log.h -- logging
+
+    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#ifndef __LOGGER_H__
+#define __LOGGER_H__
+
+typedef enum debug_t {
+       DEBUG_NOTHING = 0,                      /* Quiet mode, only show starting/stopping of the daemon */
+       DEBUG_ALWAYS = 0,
+       DEBUG_CONNECTIONS = 1,          /* Show (dis)connects of other tinc daemons via TCP */
+       DEBUG_ERROR = 2,                        /* Show error messages received from other hosts */
+       DEBUG_STATUS = 2,                       /* Show status messages received from other hosts */
+       DEBUG_PROTOCOL = 3,                     /* Show the requests that are sent/received */
+       DEBUG_META = 4,                         /* Show contents of every request that is sent/received */
+       DEBUG_TRAFFIC = 5,                      /* Show network traffic information */
+       DEBUG_PACKET = 6,                       /* Show contents of each packet that is being sent/received */
+       DEBUG_SCARY_THINGS = 10         /* You have been warned */
+} debug_t;
+
+typedef enum logmode_t {
+       LOGMODE_NULL,
+       LOGMODE_STDERR,
+       LOGMODE_FILE,
+       LOGMODE_SYSLOG
+} logmode_t;
+
+#ifdef HAVE_MINGW
+#define LOG_EMERG EVENTLOG_ERROR_TYPE
+#define LOG_ALERT EVENTLOG_ERROR_TYPE
+#define LOG_CRIT EVENTLOG_ERROR_TYPE
+#define LOG_ERR EVENTLOG_ERROR_TYPE
+#define LOG_WARNING EVENTLOG_WARNING_TYPE
+#define LOG_NOTICE EVENTLOG_INFORMATION_TYPE
+#define LOG_INFO EVENTLOG_INFORMATION_TYPE
+#define LOG_DEBUG EVENTLOG_INFORMATION_TYPE
+#else
+#ifndef HAVE_SYSLOG_H
+enum {
+       LOG_EMERG,
+       LOG_ALERT,
+       LOG_CRIT,
+       LOG_ERR,
+       LOG_WARNING,
+       LOG_NOTICE,
+       LOG_INFO,
+       LOG_DEBUG,
+};
+#endif
+#endif
+
+extern debug_t debug_level;
+extern void openlogger(const char *, logmode_t);
+extern void logger(int, const char *, ...) __attribute__ ((__format__(printf, 2, 3)));
+extern void closelogger(void);
+
+#define ifdebug(l) if(debug_level >= DEBUG_##l)
+
+#endif /* __LOGGER_H__ */
diff --git a/src/logger.c b/src/logger.c
new file mode 100644 (file)
index 0000000..9bbd8fe
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+    logger.c -- logging
+
+    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#include "system.h"
+
+#include "logger/logger.h"
+
+logger_level_t logger_level = LOGGER_LEVEL_NONE;
+
+static logger_mode_t logger_mode = LOGGER_MODE_STDERR;
+static pid_t logger_pid;
+char *logger_filename;
+static FILE *logger_file = NULL;
+#ifdef HAVE_MINGW
+static HANDLE logger_handle = NULL;
+#endif
+static const char *logger_ident = NULL;
+
+bool logger_init(const char *ident, logger_mode_t mode) {
+       logger_ident = ident;
+       logger_mode = mode;
+       
+       switch(mode) {
+               case LOGGER_MODE_STDERR:
+                       logger_pid = getpid();
+                       break;
+               case LOGGER_MODE_FILE:
+                       logger_pid = getpid();
+                       logger_file = fopen(logger_filename, "a");
+                       if(!logger_file)
+                               logger_mode = LOGGER_MODE_NULL;
+                       break;
+               case LOGGER_MODE_SYSLOG:
+#ifdef HAVE_MINGW
+                       logger_handle = RegisterEventSource(NULL, logger_ident);
+                       if(!logger_handle)
+                               logger_mode = LOGGER_MODE_NULL;
+                       break;
+#else
+#ifdef HAVE_SYSLOG_H
+                       openlog(logger_ident, LOG_CONS | LOG_PID, LOG_DAEMON);
+                       break;
+#endif
+#endif
+               case LOGGER_MODE_NULL:
+                       break;
+       }
+
+       return true;
+}
+
+bool logger_exit(void) {
+       switch(logger_mode) {
+               case LOGGER_MODE_FILE:
+                       fclose(logger_file);
+                       break;
+               case LOGGER_MODE_SYSLOG:
+#ifdef HAVE_MINGW
+                       DeregisterEventSource(logger_handle);
+                       break;
+#else
+#ifdef HAVE_SYSLOG_H
+                       closelog();
+                       break;
+#endif
+#endif
+               case LOGGER_MODE_NULL:
+               case LOGGER_MODE_STDERR:
+                       break;
+                       break;
+       }
+
+       return true;
+}
+
+void logger(int priority, const char *format, ...) {
+       va_list ap;
+
+       va_start(ap, format);
+
+       switch(logger_mode) {
+               case LOGGER_MODE_STDERR:
+                       vfprintf(stderr, format, ap);
+                       fprintf(stderr, "\n");
+                       fflush(stderr);
+                       break;
+               case LOGGER_MODE_FILE:
+                       fprintf(logger_file, "%ld %s[%ld]: ", time(NULL), logger_ident, (long)logger_pid);
+                       vfprintf(logger_file, format, ap);
+                       fprintf(logger_file, "\n");
+                       fflush(logger_file);
+                       break;
+               case LOGGER_MODE_SYSLOG:
+#ifdef HAVE_MINGW
+                       {
+                               char message[4096];
+                               char *messages[] = {message};
+                               vsnprintf(message, sizeof(message), format, ap);
+                               ReportEvent(logger_handle, priority, 0, 0, NULL, 1, 0, messages, NULL);
+                       }
+#else
+#ifdef HAVE_SYSLOG_H
+#ifdef HAVE_VSYSLOG
+                       vsyslog(priority, format, ap);
+#else
+                       {
+                               char message[4096];
+                               vsnprintf(message, sizeof(message), format, ap);
+                               syslog(priority, "%s", message);
+                       }
+#endif
+                       break;
+#endif
+#endif
+               case LOGGER_MODE_NULL:
+                       break;
+       }
+
+       va_end(ap);
+}
+
+
diff --git a/src/logger.h b/src/logger.h
new file mode 100644 (file)
index 0000000..a65968e
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+    logger.h -- logging
+
+    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#ifndef __LOGGER_H__
+#define __LOGGER_H__
+
+typedef enum logger_level {
+       LOGGER_LEVEL_NONE,
+       LOGGER_LEVEL_NOTICE,
+       LOGGER_LEVEL_WARNING,
+       LOGGER_LEVEL_ERROR,
+       LOGGER_LEVEL_DEBUG,
+} logger_level_t;
+
+typedef enum logger_mode {
+       LOGGER_MODE_NULL,
+       LOGGER_MODE_STDERR,
+       LOGGER_MODE_FILE,
+       LOGGER_MODE_SYSLOG,
+} logger_mode_t;
+
+extern bool logger_init(const char *, logger_mode_t);
+extern bool logger_exit(void);
+extern void logger(int, const char *, ...) __attribute__ ((__format__(printf, 2, 3)));
+
+extern enum logger_level logger_level;
+
+#endif
diff --git a/src/node.c b/src/node.c
new file mode 100644 (file)
index 0000000..4eee529
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+    node.c -- node management
+
+    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
+                  2003-2004 Ivo Timmermans <ivo@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#include "system.h"
+
+#include "cfg/cfg.h"
+#include "logger/logger.h"
+#include "rt/node.h"
+#include "support/avl.h"
+#include "support/xalloc.h"
+#include "tincd.h"
+
+avl_tree_t *nodes;
+
+node_t *myself;
+
+static int node_compare(const node_t *a, const node_t *b) {
+       return strcmp(a->name, b->name);
+}
+
+bool node_validname(const char *name) {
+       for(; *name; name++)
+               if(!isalnum(*name) && *name != '_')
+                       return false;
+
+       return true;
+}
+
+bool node_init(void) {
+       char *cfgfilename;
+
+       nodes = avl_tree_new((avl_compare_t)node_compare, (avl_action_t)node_free);
+       myself = node_new();
+
+       if(!cfg_get_string(tinc_cfg, "Name", NULL, &myself->name) || !myself->name) {
+               logger(LOG_ERR, _("rt: name for tinc daemon required!"));
+               node_exit();
+               return false;
+       }
+
+       if(!node_validname(myself->name)) {
+               logger(LOG_ERR, _("rt: invalid name for myself!"));
+               node_exit();
+               return false;
+       }
+
+       myself->cfg = cfg_tree_new();
+
+       asprintf(&cfgfilename, "%s/hosts/%s", tinc_confbase, myself->name);
+
+       if(!cfg_read_file(myself->cfg, cfgfilename)) {
+               free(cfgfilename);
+               node_exit();
+               return false;
+       }
+
+       free(cfgfilename);
+       
+       return true;
+}
+
+bool node_exit(void) {
+       avl_tree_del(nodes);
+       return true;
+}
+
+node_t *node_new(void) {
+       node_t *node;
+
+       clear(new(node));
+       node->subnets = subnet_tree_new();
+       node->edges = edge_tree_new();
+       node->queue = avl_tree_new(NULL, (avl_action_t)free);
+
+       return node;
+}
+
+void node_free(node_t *node) {
+       if(node->queue)
+               avl_tree_free(node->queue);
+
+       if(node->subnets)
+               subnet_tree_free(node->subnets);
+
+       if(node->edges)
+               edge_tree_free(node->edges);
+
+       replace(node->name, NULL);
+
+       free(node);
+}
+
+void node_add(node_t *node) {
+       avl_add(nodes, node);
+}
+
+void node_del(node_t *node) {
+       edge_t *edge;
+       subnet_t *subnet;
+
+       avl_foreach(node->subnets, subnet, subnet_del(subnet));
+       avl_foreach(node->edges, edge, edge_del(edge));
+
+       avl_del(nodes, node);
+}
+
+node_t *node_get(char *name) {
+       node_t search = {0};
+
+       search.name = name;
+
+       return avl_get(nodes, &search);
+}
+
diff --git a/src/node.h b/src/node.h
new file mode 100644 (file)
index 0000000..acf20bc
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+    node.h -- node management
+
+    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
+                  2003-2004 Ivo Timmermans <ivo@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#ifndef __NODE_H__
+#define __NODE_H__
+
+typedef int node_options_t;
+
+#define NODE_OPTION_INDIRECT 1
+
+#include "rt/edge.h"
+#include "rt/subnet.h"
+#include "support/avl.h"
+#include "tnl/tnl.h"
+
+typedef struct node_status {
+       int active:1;
+       int visited:1;
+       int reachable:1;
+       int indirect:1;
+} node_status_t;
+
+typedef struct node {
+       char *name;
+
+       avl_tree_t *queue;
+
+       struct node *nexthop;
+       struct node *via;
+
+       avl_tree_t *subnets;
+       avl_tree_t *edges;
+
+       struct tnl *tnl;
+
+       node_status_t status;
+       node_options_t options;
+
+       struct sockaddr_storage address;
+
+       avl_tree_t *cfg;
+} node_t;
+
+extern avl_tree_t *nodes;
+extern struct node *myself;
+
+extern bool node_init(void);
+extern bool node_exit(void);
+extern struct node *node_new(void) __attribute__ ((__malloc__));
+extern void node_free(struct node *);
+extern void node_add(struct node *);
+extern void node_del(struct node *);
+extern struct node *node_get(char *);
+
+#endif
diff --git a/src/process.c b/src/process.c
new file mode 100644 (file)
index 0000000..f04f7c0
--- /dev/null
@@ -0,0 +1,565 @@
+/*
+    process.c -- process management functions
+    Copyright (C) 1999-2004 Ivo Timmermans <ivo@tinc-vpn.org>,
+                  2000-2004 Guus Sliepen <guus@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#include "system.h"
+
+#include "tincd.h"
+#include "logger/logger.h"
+
+static sigset_t emptysigset;
+
+/* Some functions the less gifted operating systems might lack... */
+
+#ifdef HAVE_MINGW
+static SC_HANDLE manager = NULL;
+static SC_HANDLE service = NULL;
+static SERVICE_STATUS status = {0};
+static SERVICE_STATUS_HANDLE statushandle = 0;
+
+bool install_service(void) {
+       char command[4096] = "\"";
+       char **argp;
+       bool space;
+       SERVICE_DESCRIPTION description = {"Virtual Private Network daemon"};
+
+       manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+       if(!manager) {
+               logger(LOG_ERR, _("Could not open service manager: %s"), winerror(GetLastError()));
+               return false;
+       }
+
+       if(!strchr(program_name, '\\')) {
+               GetCurrentDirectory(sizeof(command) - 1, command + 1);
+               strncat(command, "\\", sizeof(command));
+       }
+
+       strncat(command, program_name, sizeof(command));
+
+       strncat(command, "\"", sizeof(command));
+
+       for(argp = g_argv + 1; *argp; argp++) {
+               space = strchr(*argp, ' ');
+               strncat(command, " ", sizeof(command));
+               
+               if(space)
+                       strncat(command, "\"", sizeof(command));
+               
+               strncat(command, *argp, sizeof(command));
+
+               if(space)
+                       strncat(command, "\"", sizeof(command));
+       }
+
+       service = CreateService(manager, identname, identname,
+                       SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
+                       command, "NDIS", NULL, NULL, NULL, NULL);
+       
+       if(!service) {
+               logger(LOG_ERR, _("Could not create %s service: %s"), identname, winerror(GetLastError()));
+               return false;
+       }
+
+       ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &description);
+
+       logger(LOG_INFO, _("%s service installed"), identname);
+
+       if(!StartService(service, 0, NULL))
+               logger(LOG_WARNING, _("Could not start %s service: %s"), identname, winerror(GetLastError()));
+       else
+               logger(LOG_INFO, _("%s service started"), identname);
+
+       return true;
+}
+
+bool remove_service(void) {
+       manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+       if(!manager) {
+               logger(LOG_ERR, _("Could not open service manager: %s"), winerror(GetLastError()));
+               return false;
+       }
+
+       service = OpenService(manager, identname, SERVICE_ALL_ACCESS);
+
+       if(!service) {
+               logger(LOG_ERR, _("Could not open %s service: %s"), identname, winerror(GetLastError()));
+               return false;
+       }
+
+       if(!ControlService(service, SERVICE_CONTROL_STOP, &status))
+               logger(LOG_ERR, _("Could not stop %s service: %s"), identname, winerror(GetLastError()));
+       else
+               logger(LOG_INFO, _("%s service stopped"), identname);
+
+       if(!DeleteService(service)) {
+               logger(LOG_ERR, _("Could not remove %s service: %s"), identname, winerror(GetLastError()));
+               return false;
+       }
+
+       logger(LOG_INFO, _("%s service removed"), identname);
+
+       return true;
+}
+
+DWORD WINAPI controlhandler(DWORD request, DWORD type, LPVOID boe, LPVOID bah) {
+       switch(request) {
+               case SERVICE_CONTROL_STOP:
+                       logger(LOG_NOTICE, _("Got %s request"), "SERVICE_CONTROL_STOP");
+                       break;
+               case SERVICE_CONTROL_SHUTDOWN:
+                       logger(LOG_NOTICE, _("Got %s request"), "SERVICE_CONTROL_SHUTDOWN");
+                       break;
+               default:
+                       logger(LOG_WARNING, _("Got unexpected request %d"), request);
+                       return ERROR_CALL_NOT_IMPLEMENTED;
+       }
+
+       if(running) {
+               running = false;
+               status.dwWaitHint = 30000; 
+               status.dwCurrentState = SERVICE_STOP_PENDING; 
+               SetServiceStatus(statushandle, &status);
+               return NO_ERROR;
+       } else {
+               status.dwWaitHint = 0; 
+               status.dwCurrentState = SERVICE_STOPPED; 
+               SetServiceStatus(statushandle, &status);
+               exit(1);
+       }
+
+}
+
+VOID WINAPI run_service(DWORD argc, LPTSTR* argv)
+{
+       int err = 1;
+       extern int main2(int argc, char **argv);
+
+
+       status.dwServiceType = SERVICE_WIN32; 
+       status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
+       status.dwWin32ExitCode = 0; 
+       status.dwServiceSpecificExitCode = 0; 
+       status.dwCheckPoint = 0; 
+
+       statushandle = RegisterServiceCtrlHandlerEx(identname, controlhandler, NULL); 
+
+       if (!statushandle) {
+               logger(LOG_ERR, _("System call `%s' failed: %s"), "RegisterServiceCtrlHandlerEx", winerror(GetLastError()));
+               err = 1;
+       } else {
+               status.dwWaitHint = 30000; 
+               status.dwCurrentState = SERVICE_START_PENDING; 
+               SetServiceStatus(statushandle, &status);
+
+               status.dwWaitHint = 0; 
+               status.dwCurrentState = SERVICE_RUNNING;
+               SetServiceStatus(statushandle, &status);
+
+               err = main2(argc, argv);
+
+               status.dwWaitHint = 0;
+               status.dwCurrentState = SERVICE_STOPPED; 
+               //status.dwWin32ExitCode = err; 
+               SetServiceStatus(statushandle, &status);
+       }
+
+       return;
+}
+
+bool init_service(void) {
+       SERVICE_TABLE_ENTRY services[] = {
+               {identname, run_service},
+               {NULL, NULL}
+       };
+
+       if(!StartServiceCtrlDispatcher(services)) {
+               if(GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
+                       return false;
+               }
+               else
+                       logger(LOG_ERR, _("System call `%s' failed: %s"), "StartServiceCtrlDispatcher", winerror(GetLastError()));
+       }
+
+       return true;
+}
+#endif
+
+#ifndef HAVE_MINGW
+/*
+  check for an existing tinc for this net, and write pid to pidfile
+*/
+
+static pid_t read_pid(const char *pidfilename) {
+       FILE *pidfile;
+       long int pid = 0;
+
+       pidfile = fopen(pidfilename, "r");
+       if(!pidfile)
+               return 0;
+
+       fscanf(pidfile, "%ld", &pid);
+       fclose(pidfile);
+       
+       return pid;
+}
+
+static pid_t check_pid(const char *pidfilename) {
+       pid_t pid;
+       
+       pid = read_pid(pidfilename);
+
+       if (!pid || pid == getpid())
+               return 0;
+
+       if(kill(pid, 0) && errno == ESRCH)
+               return 0;
+
+       return pid;
+}
+
+static pid_t write_pid(const char *pidfilename) {
+       FILE *pidfile;
+       int pidfd;
+       pid_t pid;
+
+       pidfd = open(pidfilename, O_RDWR | O_CREAT);
+
+       if(pidfd == -1)
+               return 0;
+
+#ifdef HAVE_FLOCK
+       if(flock(pidfd, LOCK_EX | LOCK_NB) == -1) {
+               close(pidfd);
+               return 0;
+       }
+#endif
+
+       pidfile = fdopen(pidfd, "r+");
+
+       if(!pidfile) {
+               close(pidfd);
+               return 0;
+       }
+
+       pid = getpid();
+       fprintf(pidfile, "%ld\n", (long)pid);
+       fflush(pidfile);
+
+#ifdef HAVE_FLOCK
+       flock(pidfd, LOCK_UN);
+#endif
+
+       close(pidfd);
+
+       return pid;
+}
+
+bool remove_pid(const char *pidfilename) {
+       return unlink(pidfilename) == 0;
+}
+
+static bool write_pidfile(void)
+{
+       pid_t pid;
+
+       pid = check_pid(tinc_pidfilename);
+
+       if(pid) {
+               if(tinc_netname)
+                       fprintf(stderr, _("A tincd is already running for net `%s' with pid %ld.\n"),
+                                       tinc_netname, (long)pid);
+               else
+                       fprintf(stderr, _("A tincd is already running with pid %ld.\n"), (long)pid);
+               return false;
+       }
+
+       /* if it's locked, write-protected, or whatever */
+       if(!write_pid(tinc_pidfilename)) {
+               fprintf(stderr, _("Could write pid file %s: %s\n"), tinc_pidfilename, strerror(errno));
+               return false;
+       }
+
+       return true;
+}
+#endif
+
+/*
+  kill older tincd for this net
+*/
+bool kill_other(int signal)
+{
+#ifndef HAVE_MINGW
+       pid_t pid;
+
+       pid = read_pid(tinc_pidfilename);
+
+       if(!pid) {
+               if(tinc_netname)
+                       fprintf(stderr, _("No other tincd is running for net `%s'.\n"),
+                                       tinc_netname);
+               else
+                       fprintf(stderr, _("No other tincd is running.\n"));
+               return false;
+       }
+
+       errno = 0;                                      /* No error, sometimes errno is only changed on error */
+
+       /* ESRCH is returned when no process with that pid is found */
+       if(kill(pid, signal) && errno == ESRCH) {
+               if(tinc_netname)
+                       fprintf(stderr, _("The tincd for net `%s' is no longer running. "),
+                                       tinc_netname);
+               else
+                       fprintf(stderr, _("The tincd is no longer running. "));
+
+               fprintf(stderr, _("Removing stale lock file.\n"));
+               remove_pid(tinc_pidfilename);
+       }
+
+       return true;
+#else
+       return remove_service();
+#endif
+}
+
+/*
+  Detach from current terminal, write pidfile, kill parent
+*/
+bool detach(void) {
+#ifndef HAVE_MINGW
+       if(!write_pidfile())
+               return false;
+
+       /* If we succeeded in doing that, detach */
+
+       logger_exit();
+
+       if(daemon(0, 0)) {
+               fprintf(stderr, _("Couldn't detach from terminal: %s"),
+                               strerror(errno));
+               return false;
+       }
+
+       /* Now UPDATE the pid in the pidfile, because we changed it... */
+
+       if(!write_pid(tinc_pidfilename)) {
+               fprintf(stderr, _("Could not write pid file %s: %s\n"), tinc_pidfilename, strerror(errno));
+               return false;
+       }
+#else
+       if(!statushandle)
+               exit(install_service());
+#endif
+
+       logger_init(tinc_identname, tinc_use_logfile ? LOGGER_MODE_FILE : LOGGER_MODE_SYSLOG);
+
+       return true;
+}
+
+bool execute_script(const char *name, char **envp)
+{
+#ifdef HAVE_SYSTEM
+       int status, len;
+       struct stat s;
+       char *scriptname;
+
+#ifndef HAVE_MINGW
+       len = asprintf(&scriptname, "\"%s/%s\"", tinc_confbase, name);
+#else
+       len = asprintf(&scriptname, "\"%s/%s.bat\"", tinc_confbase, name);
+#endif
+       if(len < 0)
+               return false;
+
+       scriptname[len - 1] = '\0';
+
+       /* First check if there is a script */
+
+       if(stat(scriptname + 1, &s))
+               return true;
+
+       logger(LOG_INFO, _("Executing script %s"), name);
+
+#ifdef HAVE_PUTENV
+       /* Set environment */
+       
+       while(*envp)
+               putenv(*envp++);
+#endif
+
+       scriptname[len - 1] = '\"';
+       status = system(scriptname);
+
+       free(scriptname);
+
+       /* Unset environment? */
+
+#ifdef WEXITSTATUS
+       if(status != -1) {
+               if(WIFEXITED(status)) { /* Child exited by itself */
+                       if(WEXITSTATUS(status)) {
+                               logger(LOG_ERR, _("Script %s exited with non-zero status %d"),
+                                          name, WEXITSTATUS(status));
+                               return false;
+                       }
+               } else if(WIFSIGNALED(status)) {        /* Child was killed by a signal */
+                       logger(LOG_ERR, _("Script %s was killed by signal %d (%s)"),
+                                  name, WTERMSIG(status), strsignal(WTERMSIG(status)));
+                       return false;
+               } else {                        /* Something strange happened */
+                       logger(LOG_ERR, _("Script %s terminated abnormally"), name);
+                       return false;
+               }
+       } else {
+               logger(LOG_ERR, _("System call `%s' failed: %s"), "system", strerror(errno));
+               return false;
+       }
+#endif
+#endif
+       return true;
+}
+
+
+/*
+  Signal handlers.
+*/
+
+#ifndef HAVE_MINGW
+static RETSIGTYPE sigterm_handler(int a) {
+       logger(LOG_NOTICE, _("Got %s signal"), "TERM");
+       exit(1);
+}
+
+static RETSIGTYPE sigquit_handler(int a) {
+       logger(LOG_NOTICE, _("Got %s signal"), "QUIT");
+       exit(1);
+}
+
+static RETSIGTYPE fatal_signal_square(int a) {
+       logger(LOG_ERR, _("Got another fatal signal %d (%s): not restarting."), a,
+                  strsignal(a));
+       exit(1);
+}
+
+static RETSIGTYPE fatal_signal_handler(int a) {
+       struct sigaction act;
+       logger(LOG_ERR, _("Got fatal signal %d (%s)"), a, strsignal(a));
+       logger(LOG_NOTICE, _("Not restarting."));
+       exit(1);
+}
+
+static RETSIGTYPE sighup_handler(int a) {
+       logger(LOG_NOTICE, _("Got %s signal"), "HUP");
+//     sighup = true;
+}
+
+static RETSIGTYPE sigint_handler(int a) {
+       static logger_level_t saved_logger_level = -1;
+
+       logger(LOG_NOTICE, _("Got %s signal"), "INT");
+
+       if(saved_logger_level != -1) {
+               logger(LOG_NOTICE, _("Reverting to old debug level (%d)"),
+                       saved_logger_level);
+               logger_level = saved_logger_level;
+               saved_logger_level = -1;
+       } else {
+               logger(LOG_NOTICE,
+                       _("Temporarily setting debug level to 5.  Kill me with SIGINT again to go back to level %d."),
+                       logger_level);
+               saved_logger_level = logger_level;
+               logger_level = 5;
+       }
+}
+
+static RETSIGTYPE sigalrm_handler(int a) {
+       logger(LOG_NOTICE, _("Got %s signal"), "ALRM");
+       //sigalrm = true;
+}
+
+static RETSIGTYPE sigusr1_handler(int a) {
+}
+
+static RETSIGTYPE sigusr2_handler(int a) {
+}
+
+static RETSIGTYPE sigwinch_handler(int a) {
+       //do_purge = true;
+}
+
+static RETSIGTYPE unexpected_signal_handler(int a) {
+       logger(LOG_WARNING, _("Got unexpected signal %d (%s)"), a, strsignal(a));
+}
+
+static RETSIGTYPE ignore_signal_handler(int a) {
+       logger(LOG_DEBUG, _("Ignored signal %d (%s)"), a, strsignal(a));
+}
+
+static struct {
+       int signal;
+       void (*handler)(int);
+} sighandlers[] = {
+       {SIGHUP, sighup_handler},
+       {SIGTERM, sigterm_handler},
+       {SIGQUIT, sigquit_handler},
+       {SIGSEGV, SIG_DFL},
+       {SIGBUS, fatal_signal_handler},
+       {SIGILL, fatal_signal_handler},
+       {SIGPIPE, ignore_signal_handler},
+       {SIGINT, sigint_handler},
+       {SIGUSR1, sigusr1_handler},
+       {SIGUSR2, sigusr2_handler},
+       {SIGCHLD, ignore_signal_handler},
+       {SIGALRM, sigalrm_handler},
+       {SIGWINCH, sigwinch_handler},
+       {0, NULL}
+};
+#endif
+
+void setup_signals(void)
+{
+#ifndef HAVE_MINGW
+       int i;
+       struct sigaction act;
+
+       sigemptyset(&emptysigset);
+       act.sa_handler = NULL;
+       act.sa_mask = emptysigset;
+       act.sa_flags = 0;
+
+       /* Set a default signal handler for every signal, errors will be
+          ignored. */
+       for(i = 0; i < NSIG; i++) {
+               act.sa_handler = unexpected_signal_handler;
+               sigaction(i, &act, NULL);
+       }
+
+       /* Then, for each known signal that we want to catch, assign a
+          handler to the signal, with error checking this time. */
+       for(i = 0; sighandlers[i].signal; i++) {
+               act.sa_handler = sighandlers[i].handler;
+               if(sigaction(sighandlers[i].signal, &act, NULL) < 0)
+                       fprintf(stderr, _("Installing signal handler for signal %d (%s) failed: %s\n"),
+                                       sighandlers[i].signal, strsignal(sighandlers[i].signal),
+                                       strerror(errno));
+       }
+#endif
+}
diff --git a/src/route.c b/src/route.c
new file mode 100644 (file)
index 0000000..4721763
--- /dev/null
@@ -0,0 +1,754 @@
+/*
+    route.c -- routing
+    Copyright (C) 2000-2004 Ivo Timmermans <ivo@tinc-vpn.org>,
+                  2000-2004 Guus Sliepen <guus@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#include "system.h"
+
+#ifdef HAVE_NET_ETHERNET_H
+#include <net/ethernet.h>
+#endif
+#ifdef HAVE_NET_IF_ARP_H
+#include <net/if_arp.h>
+#endif
+#ifdef HAVE_NETINET_IP_ICMP_H
+#include <netinet/ip_icmp.h>
+#endif
+#ifdef HAVE_NETINET_ICMP6_H
+#include <netinet/icmp6.h>
+#endif
+#ifdef HAVE_NETINET_IF_ETHER_H
+#include <netinet/if_ether.h>
+#endif
+
+#include "logger/logger.h"
+#include "rt/rt.h"
+#include "rt/subnet.h"
+#include "support/avl.h"
+#include "support/ethernet.h"
+#include "support/ipv4.h"
+#include "support/ipv6.h"
+
+static mac_t mymac = {{0xFE, 0xFD, 0, 0, 0, 0}};
+
+/* Sizes of various headers */
+
+static const size_t ether_size = sizeof(struct ether_header);
+static const size_t arp_size = sizeof(struct ether_arp);
+static const size_t ip_size = sizeof(struct ip);
+static const size_t icmp_size = sizeof(struct icmp) - sizeof(struct ip);
+static const size_t ip6_size = sizeof(struct ip6_hdr);
+static const size_t icmp6_size = sizeof(struct icmp6_hdr);
+static const size_t ns_size = sizeof(struct nd_neighbor_solicit);
+static const size_t opt_size = sizeof(struct nd_opt_hdr);
+
+static struct timeval expires(int seconds) {
+       struct timeval tv;
+
+       gettimeofday(&tv, NULL);
+       tv.tv_sec += seconds;
+
+       return tv;
+}
+
+/* RFC 1071 */
+
+static __inline__ uint16_t inet_checksum(const void *data, int len, uint16_t prevsum) {
+       const uint16_t *p = data;
+       uint32_t checksum = prevsum ^ 0xFFFF;
+
+       while(len >= 2) {
+               checksum += *p++;
+               len -= 2;
+       }
+       
+       if(len)
+               checksum += *(uint8_t *)p;
+
+       while(checksum >> 16)
+               checksum = (checksum & 0xFFFF) + (checksum >> 16);
+
+       return ~checksum;
+}
+
+static __inline__ bool ratelimit(int frequency) {
+       static time_t lasttime = 0;
+       static int count = 0;
+       time_t now = time(NULL);
+       
+       if(lasttime == now) {
+               if(++count > frequency)
+                       return true;
+       } else {
+               lasttime = now;
+               count = 0;
+       }
+
+       return false;
+}
+
+static __inline__ bool checklength(node_t *source, int len, int minlen) {
+       if(len < minlen) {
+               logger(LOG_WARNING, _("Got too short packet from %s"), source->name);
+               return false;
+       } else
+               return true;
+}
+       
+static __inline__ void learn_mac(mac_t *address) {
+       subnet_t *subnet;
+       avl_node_t *node;
+
+       subnet = subnet_get_mac(address);
+
+       /* If we don't know this MAC address yet, store it */
+
+       if(!subnet) {
+               logger(LOG_INFO, _("Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx"),
+                                  address->x[0], address->x[1], address->x[2], address->x[3],
+                                  address->x[4], address->x[5]);
+
+               subnet = subnet_new();
+               subnet->type = SUBNET_TYPE_MAC;
+               subnet->expires = expires(rt_macexpire);
+               subnet->net.mac.address = *address;
+               subnet->owner = myself;
+               subnet_add(subnet);
+
+               /* And tell all other tinc daemons it's our MAC */
+
+#if 0
+               for(node = connection_tree->head; node; node = node->next) {
+                       c = node->data;
+                       if(c->status.active)
+                               send_add_subnet(c, subnet);
+               }
+#endif
+       }
+
+       if(timerisset(&subnet->expires))
+               subnet->expires = expires(rt_macexpire);
+}
+
+void age_subnets(void) {
+       subnet_t *s;
+
+#if 0
+       for(node = myself->subnet_tree->head; node; node = next) {
+               next = node->next;
+               s = node->data;
+               if(s->expires && s->expires < now) {
+                       {
+                               char netstr[MAXNETSTR];
+                               if(net2str(netstr, sizeof netstr, s))
+                                       logger(LOG_INFO, _("Subnet %s expired"), netstr);
+                       }
+
+                       for(node2 = connection_tree->head; node2; node2 = node2->next) {
+                               c = node2->data;
+                               if(c->status.active)
+                                       send_del_subnet(c, s);
+                       }
+
+                       subnet_del(myself, s);
+               }
+       }
+#endif
+}
+
+static void send_packet(node_t *dest, const uint8_t *packet, int len) {
+       if(dest == myself) {
+               rt_vnd->send(rt_vnd, packet, len);
+       } else if (dest->tnl) {
+               dest->tnl->send_packet(dest->tnl, packet, len);
+       } else {
+               logger(LOG_ERR, _("No tunnel for packet destination %s!"), dest->name);
+       }
+}
+
+static void broadcast_packet(node_t *source, const uint8_t *packet, int len) {
+       tnl_t *tnl;
+       edge_t *edge;
+
+       if(source != myself)
+               send_packet(myself, packet, len);
+       
+       avl_foreach(rt_tnls, tnl, {
+               edge = tnl->data;
+               if(edge && edge->status.mst && edge->to != source)
+                       send_packet(edge->to, packet, len);
+       });
+}
+
+static __inline__ void route_mac(node_t *source, const uint8_t *packet, int len) {
+       subnet_t *subnet;
+
+       /* Learn source address */
+
+       if(source == myself)
+               learn_mac((mac_t *)(packet + 6));
+
+       /* Lookup destination address */
+
+       subnet = subnet_get_mac((mac_t *)(packet));
+
+       if(!subnet) {
+               broadcast_packet(source, packet, len);
+               return;
+       }
+
+       if(subnet->owner == source) {
+               logger(LOG_WARNING, _("Packet looping back to %s!"), source->name);
+               return;
+       }
+
+       send_packet(subnet->owner, packet, len);
+}
+
+/* RFC 792 */
+
+static void route_ipv4_unreachable(node_t *source, const uint8_t *packet, int len, uint8_t type, uint8_t code) {
+       uint8_t reply[ether_size + IP_MSS];
+
+       struct ip ip = {0};
+       struct icmp icmp = {0};
+       
+       struct in_addr ip_src;
+       struct in_addr ip_dst;
+       uint32_t oldlen;
+
+       if(ratelimit(3))
+               return;
+       
+       /* Copy headers from packet into properly aligned structs on the stack */
+
+       memcpy(&ip, packet + ether_size, ip_size);
+
+       /* Remember original source and destination */
+       
+       ip_src = ip.ip_src;
+       ip_dst = ip.ip_dst;
+
+       oldlen = len - ether_size;
+
+       if(type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)
+               icmp.icmp_nextmtu = htons(len - ether_size);
+
+       if(oldlen >= IP_MSS - ip_size - icmp_size)
+               oldlen = IP_MSS - ip_size - icmp_size;
+       
+       /* Copy first part of original contents to ICMP message */
+       
+       memmove(reply + ether_size + ip_size + icmp_size, packet + ether_size, oldlen);
+
+       /* Fill in IPv4 header */
+       
+       ip.ip_v = 4;
+       ip.ip_hl = ip_size / 4;
+       ip.ip_tos = 0;
+       ip.ip_len = htons(ip_size + icmp_size + oldlen);
+       ip.ip_id = 0;
+       ip.ip_off = 0;
+       ip.ip_ttl = 255;
+       ip.ip_p = IPPROTO_ICMP;
+       ip.ip_sum = 0;
+       ip.ip_src = ip_dst;
+       ip.ip_dst = ip_src;
+
+       ip.ip_sum = inet_checksum(&ip, ip_size, ~0);
+       
+       /* Fill in ICMP header */
+       
+       icmp.icmp_type = type;
+       icmp.icmp_code = code;
+       icmp.icmp_cksum = 0;
+       
+       icmp.icmp_cksum = inet_checksum(&icmp, icmp_size, ~0);
+       icmp.icmp_cksum = inet_checksum(packet + ether_size + ip_size + icmp_size, oldlen, icmp.icmp_cksum);
+
+       /* Copy structs on stack back to packet */
+
+       memcpy(reply + ether_size, &ip, ip_size);
+       memcpy(reply + ether_size + ip_size, &icmp, icmp_size);
+       
+       send_packet(source, reply, ether_size + ip_size + icmp_size + oldlen);
+}
+
+/* RFC 791 */
+
+static __inline__ void fragment_ipv4_packet(node_t *dest, const uint8_t *packet, int len) {
+       struct ip ip;
+       char fragment[dest->tnl->mtu];
+       int fraglen, maxlen, todo;
+       const uint8_t *offset;
+       uint16_t ip_off, origf;
+       
+       memcpy(&ip, packet + ether_size, ip_size);
+
+       if(ip.ip_hl != ip_size / 4)
+               return;
+       
+       todo = ntohs(ip.ip_len) - ip_size;
+
+       if(ether_size + ip_size + todo != len) {
+               logger(LOG_WARNING, _("Length of packet (%d) doesn't match length in IPv4 header (%d)"), len, ether_size + ip_size + todo);
+               return;
+       }
+
+       logger(LOG_INFO, _("Fragmenting packet of %d bytes to %s"), len, dest->name);
+
+       offset = packet + ether_size + ip_size;
+       maxlen = (dest->tnl->mtu - ether_size - ip_size) & ~0x7;
+       ip_off = ntohs(ip.ip_off);
+       origf = ip_off & ~IP_OFFMASK;
+       ip_off &= IP_OFFMASK;
+       
+       while(todo) {
+               fraglen = todo > maxlen ? maxlen : todo;
+               memcpy(fragment + ether_size + ip_size, offset, fraglen);
+               todo -= fraglen;
+               offset += fraglen;
+
+               ip.ip_len = htons(ip_size + fraglen);
+               ip.ip_off = htons(ip_off | origf | (todo ? IP_MF : 0));
+               ip.ip_sum = 0;
+               ip.ip_sum = inet_checksum(&ip, ip_size, ~0);
+               memcpy(fragment, packet, ether_size);
+               memcpy(fragment + ether_size, &ip, ip_size);
+
+               send_packet(dest, fragment, ether_size + ip_size + fraglen);
+
+               ip_off += fraglen / 8;
+       }       
+}
+
+static __inline__ void route_ipv4_unicast(node_t *source, const uint8_t *packet, int len) {
+       subnet_t *subnet;
+       node_t *via;
+
+       subnet = subnet_get_ipv4((ipv4_t *)(packet + 30));
+
+       if(!subnet) {
+               logger(LOG_WARNING, _("Cannot route packet from %s: unknown IPv4 destination address %d.%d.%d.%d"),
+                               source->name,
+                               packet[30],
+                               packet[31],
+                               packet[32],
+                               packet[33]);
+
+               route_ipv4_unreachable(source, packet, len, ICMP_DEST_UNREACH, ICMP_NET_UNKNOWN);
+               return;
+       }
+       
+       if(subnet->owner == source) {
+               logger(LOG_WARNING, _("Packet looping back to %s!"), source->name);
+               return;
+       }
+
+       if(!subnet->owner->status.reachable)
+               route_ipv4_unreachable(source, packet, len, ICMP_DEST_UNREACH, ICMP_NET_UNREACH);
+
+       via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
+       
+       if(len > via->tnl->mtu && via != myself) {
+               logger(LOG_INFO, _("Packet for %s length %d larger than MTU %d"), subnet->owner->name, len, via->tnl->mtu);
+               if(packet[20] & 0x40) {
+                       len = via->tnl->mtu;
+                       route_ipv4_unreachable(source, packet, len, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED);
+               } else {
+                       fragment_ipv4_packet(via, packet, len);
+               }
+
+               return;
+       }
+
+       send_packet(subnet->owner, packet, len);
+}
+
+static __inline__ void route_ipv4(node_t *source, const uint8_t *packet, int len) {
+       if(!checklength(source, len, ether_size + ip_size))
+               return;
+
+       route_ipv4_unicast(source, packet, len);
+}
+
+/* RFC 2463 */
+
+static void route_ipv6_unreachable(node_t *source, const uint8_t *packet, int len, uint8_t type, uint8_t code) {
+       uint8_t reply[ether_size + IP_MSS];
+       struct ip6_hdr ip6;
+       struct icmp6_hdr icmp6 = {0};
+       uint16_t checksum;      
+
+       struct {
+               struct in6_addr ip6_src;        /* source address */
+               struct in6_addr ip6_dst;        /* destination address */
+               uint32_t length;
+               uint32_t next;
+       } pseudo;
+
+       if(ratelimit(3))
+               return;
+       
+       /* Copy headers from packet to structs on the stack */
+
+       memcpy(&ip6, packet + ether_size, ip6_size);
+
+       /* Remember original source and destination */
+       
+       pseudo.ip6_src = ip6.ip6_dst;
+       pseudo.ip6_dst = ip6.ip6_src;
+
+       pseudo.length = len - ether_size;
+
+       if(type == ICMP6_PACKET_TOO_BIG)
+               icmp6.icmp6_mtu = htonl(pseudo.length);
+       
+       if(pseudo.length >= IP_MSS - ip6_size - icmp6_size)
+               pseudo.length = IP_MSS - ip6_size - icmp6_size;
+       
+       /* Copy first part of original contents to ICMP message */
+       
+       memcpy(reply + ether_size + ip6_size + icmp6_size, packet + ether_size, pseudo.length);
+
+       /* Fill in IPv6 header */
+       
+       ip6.ip6_flow = htonl(0x60000000UL);
+       ip6.ip6_plen = htons(icmp6_size + pseudo.length);
+       ip6.ip6_nxt = IPPROTO_ICMPV6;
+       ip6.ip6_hlim = 255;
+       ip6.ip6_src = pseudo.ip6_src;
+       ip6.ip6_dst = pseudo.ip6_dst;
+
+       /* Fill in ICMP header */
+       
+       icmp6.icmp6_type = type;
+       icmp6.icmp6_code = code;
+       icmp6.icmp6_cksum = 0;
+
+       /* Create pseudo header */
+               
+       pseudo.length = htonl(icmp6_size + pseudo.length);
+       pseudo.next = htonl(IPPROTO_ICMPV6);
+
+       /* Generate checksum */
+       
+       checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
+       checksum = inet_checksum(&icmp6, icmp6_size, checksum);
+       checksum = inet_checksum(reply + ether_size + ip6_size + icmp6_size, ntohl(pseudo.length) - icmp6_size, checksum);
+
+       icmp6.icmp6_cksum = checksum;
+
+       /* Copy structs on stack back to packet */
+
+       memcpy(reply + ether_size, &ip6, ip6_size);
+       memcpy(reply + ether_size + ip6_size, &icmp6, icmp6_size);
+       
+       send_packet(source, reply, ether_size + ip6_size + ntohl(pseudo.length));
+}
+
+static __inline__ void route_ipv6_unicast(node_t *source, const uint8_t *packet, int len) {
+       subnet_t *subnet;
+       node_t *via;
+
+       subnet = subnet_get_ipv6((ipv6_t *)(packet + 38));
+
+       if(!subnet) {
+               logger(LOG_WARNING, _("Cannot route packet from %s: unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
+                               source->name,
+                               ntohs(*(uint16_t *)(packet + 38)),
+                               ntohs(*(uint16_t *)(packet + 40)),
+                               ntohs(*(uint16_t *)(packet + 42)),
+                               ntohs(*(uint16_t *)(packet + 44)),
+                               ntohs(*(uint16_t *)(packet + 46)),
+                               ntohs(*(uint16_t *)(packet + 48)),
+                               ntohs(*(uint16_t *)(packet + 50)),
+                               ntohs(*(uint16_t *)(packet + 52)));
+
+               route_ipv6_unreachable(source, packet, len, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR);
+               return;
+       }
+
+       if(subnet->owner == source) {
+               logger(LOG_WARNING, _("Packet looping back to %s!"), source->name);
+               return;
+       }
+
+       if(!subnet->owner->status.reachable)
+               route_ipv6_unreachable(source, packet, len, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE);
+
+       via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
+       
+       if(len > via->tnl->mtu && via != myself) {
+               logger(LOG_INFO, _("Packet for %s length %d larger than MTU %d"), subnet->owner->name, len, via->tnl->mtu);
+               len = via->tnl->mtu;
+               route_ipv6_unreachable(source, packet, len, ICMP6_PACKET_TOO_BIG, 0);
+               return;
+       }
+
+       send_packet(subnet->owner, packet, len);
+}
+
+/* RFC 2461 */
+
+static void route_neighborsol(node_t *source, const uint8_t *packet, int len) {
+       uint8_t reply[len];
+       struct ip6_hdr ip6;
+       struct nd_neighbor_solicit ns;
+       struct nd_opt_hdr opt;
+       subnet_t *subnet;
+       uint16_t checksum;
+
+       struct {
+               struct in6_addr ip6_src;        /* source address */
+               struct in6_addr ip6_dst;        /* destination address */
+               uint32_t length;
+               uint32_t next;
+       } pseudo;
+
+       if(!checklength(source, len, ether_size + ip6_size + ns_size + opt_size + ETH_ALEN))
+               return;
+       
+       if(source != myself) {
+               logger(LOG_WARNING, _("Got neighbor solicitation request from %s while in router mode!"), source->name);
+               return;
+       }
+
+       /* Copy headers from packet to structs on the stack */
+
+       memcpy(&ip6, packet + ether_size, ip6_size);
+       memcpy(&ns, packet + ether_size + ip6_size, ns_size);
+       memcpy(&opt, packet + ether_size + ip6_size + ns_size, opt_size);
+
+       /* First, snatch the source address from the neighbor solicitation packet */
+
+       if(rt_overwrite_mac)
+               memcpy(mymac.x, packet + ETH_ALEN, ETH_ALEN);
+
+       /* Check if this is a valid neighbor solicitation request */
+
+       if(ns.nd_ns_hdr.icmp6_type != ND_NEIGHBOR_SOLICIT ||
+          opt.nd_opt_type != ND_OPT_SOURCE_LINKADDR) {
+               logger(LOG_WARNING, _("Cannot route packet: received unknown type neighbor solicitation request"));
+               return;
+       }
+
+       /* Create pseudo header */
+
+       pseudo.ip6_src = ip6.ip6_src;
+       pseudo.ip6_dst = ip6.ip6_dst;
+       pseudo.length = htonl(ns_size + opt_size + ETH_ALEN);
+       pseudo.next = htonl(IPPROTO_ICMPV6);
+
+       /* Generate checksum */
+
+       checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
+       checksum = inet_checksum(&ns, ns_size, checksum);
+       checksum = inet_checksum(&opt, opt_size, checksum);
+       checksum = inet_checksum(packet + ether_size + ip6_size + ns_size + opt_size, ETH_ALEN, checksum);
+
+       if(checksum) {
+               logger(LOG_WARNING, _("Cannot route packet: checksum error for neighbor solicitation request"));
+               return;
+       }
+
+       /* Check if the IPv6 address exists on the VPN */
+
+       subnet = subnet_get_ipv6((ipv6_t *) &ns.nd_ns_target);
+
+       if(!subnet) {
+               logger(LOG_WARNING, _("Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
+                                  ntohs(((uint16_t *) &ns.nd_ns_target)[0]),
+                                  ntohs(((uint16_t *) &ns.nd_ns_target)[1]),
+                                  ntohs(((uint16_t *) &ns.nd_ns_target)[2]),
+                                  ntohs(((uint16_t *) &ns.nd_ns_target)[3]),
+                                  ntohs(((uint16_t *) &ns.nd_ns_target)[4]),
+                                  ntohs(((uint16_t *) &ns.nd_ns_target)[5]),
+                                  ntohs(((uint16_t *) &ns.nd_ns_target)[6]),
+                                  ntohs(((uint16_t *) &ns.nd_ns_target)[7]));
+
+               return;
+       }
+
+       /* Check if it is for our own subnet */
+
+       if(subnet->owner == myself)
+               return;                                 /* silently ignore */
+
+       /* Create neighbor advertation reply */
+
+       memcpy(reply, packet + ETH_ALEN, ETH_ALEN);     /* copy destination address */
+       memcpy(reply + ETH_ALEN, packet + ETH_ALEN, ETH_ALEN);  /* copy destination address */
+       reply[ETH_ALEN * 2 - 1] ^= 0xFF;        /* mangle source address so it looks like it's not from us */
+
+       ip6.ip6_dst = ip6.ip6_src;                      /* swap destination and source protocoll address */
+       ip6.ip6_src = ns.nd_ns_target;
+
+       memcpy(reply + ether_size + ip6_size + ns_size + opt_size, reply + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */
+
+       ns.nd_ns_cksum = 0;
+       ns.nd_ns_type = ND_NEIGHBOR_ADVERT;
+       ns.nd_ns_reserved = htonl(0x40000000UL);        /* Set solicited flag */
+       opt.nd_opt_type = ND_OPT_TARGET_LINKADDR;
+
+       /* Create pseudo header */
+
+       pseudo.ip6_src = ip6.ip6_src;
+       pseudo.ip6_dst = ip6.ip6_dst;
+       pseudo.length = htonl(ns_size + opt_size + ETH_ALEN);
+       pseudo.next = htonl(IPPROTO_ICMPV6);
+
+       /* Generate checksum */
+
+       checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
+       checksum = inet_checksum(&ns, ns_size, checksum);
+       checksum = inet_checksum(&opt, opt_size, checksum);
+       checksum = inet_checksum(packet + ether_size + ip6_size + ns_size + opt_size, ETH_ALEN, checksum);
+
+       ns.nd_ns_hdr.icmp6_cksum = checksum;
+
+       /* Copy structs on stack back to packet */
+
+       memcpy(reply + ether_size, &ip6, ip6_size);
+       memcpy(reply + ether_size + ip6_size, &ns, ns_size);
+       memcpy(reply + ether_size + ip6_size + ns_size, &opt, opt_size);
+
+       send_packet(source, reply, len);
+}
+
+static __inline__ void route_ipv6(node_t *source, const uint8_t *packet, int len) {
+       if(!checklength(source, len, ether_size + ip6_size))
+               return;
+
+       if(packet[20] == IPPROTO_ICMPV6 && checklength(source, len, ether_size + ip6_size + icmp6_size) && packet[54] == ND_NEIGHBOR_SOLICIT) {
+               route_neighborsol(source, packet, len);
+               return;
+       }
+
+       route_ipv6_unicast(source, packet, len);
+}
+
+/* RFC 826 */
+
+static void route_arp(node_t *source, const uint8_t *packet, int len) {
+       uint8_t reply[len];
+       struct ether_arp arp;
+       subnet_t *subnet;
+       struct in_addr addr;
+
+       if(!checklength(source, len, ether_size + arp_size))
+               return;
+
+       if(source != myself) {
+               logger(LOG_WARNING, _("Got ARP request from %s while in router mode!"), source->name);
+               return;
+       }
+
+       /* First, snatch the source address from the ARP packet */
+
+       if(rt_overwrite_mac)
+               memcpy(mymac.x, packet + ETH_ALEN, ETH_ALEN);
+
+       /* Copy headers from packet to structs on the stack */
+
+       memcpy(&arp, packet + ether_size, arp_size);
+
+       /* Check if this is a valid ARP request */
+
+       if(ntohs(arp.arp_hrd) != ARPHRD_ETHER || ntohs(arp.arp_pro) != ETH_P_IP ||
+          arp.arp_hln != ETH_ALEN || arp.arp_pln != sizeof(addr) || ntohs(arp.arp_op) != ARPOP_REQUEST) {
+               logger(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
+               return;
+       }
+
+       /* Check if the IPv4 address exists on the VPN */
+
+       subnet = subnet_get_ipv4((ipv4_t *) &arp.arp_tpa);
+
+       if(!subnet) {
+               logger(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
+                                  arp.arp_tpa[0], arp.arp_tpa[1], arp.arp_tpa[2],
+                                  arp.arp_tpa[3]);
+               return;
+       }
+
+       /* Check if it is for our own subnet */
+
+       if(subnet->owner == myself)
+               return;                                 /* silently ignore */
+
+       memcpy(reply, packet + ETH_ALEN, ETH_ALEN);     /* copy destination address */
+       memcpy(reply + ETH_ALEN, packet + ETH_ALEN, ETH_ALEN);  /* copy destination address */
+       reply[ETH_ALEN * 2 - 1] ^= 0xFF;        /* mangle source address so it looks like it's not from us */
+
+       memcpy(&addr, arp.arp_tpa, sizeof(addr));       /* save protocol addr */
+       memcpy(arp.arp_tpa, arp.arp_spa, sizeof(addr)); /* swap destination and source protocol address */
+       memcpy(arp.arp_spa, &addr, sizeof(addr));       /* ... */
+
+       memcpy(arp.arp_tha, arp.arp_sha, ETH_ALEN);     /* set target hard/proto addr */
+       memcpy(arp.arp_sha, reply + ETH_ALEN, ETH_ALEN);        /* add fake source hard addr */
+       arp.arp_op = htons(ARPOP_REPLY);
+
+       /* Copy structs on stack back to packet */
+
+       memcpy(reply + ether_size, &arp, arp_size);
+
+       send_packet(source, reply, len);
+}
+
+void route(node_t *source, const uint8_t *packet, int len) {
+       if(!checklength(source, len, ether_size))
+               return;
+
+       switch (rt_mode) {
+               case RT_MODE_ROUTER:
+                       {
+                               uint16_t type;
+
+                               type = ntohs(*((uint16_t *)(packet + 12)));
+                               switch (type) {
+                                       case ETH_P_ARP:
+                                               route_arp(source, packet, len);
+                                               break;
+
+                                       case ETH_P_IP:
+                                               route_ipv4(source, packet, len);
+                                               break;
+
+                                       case ETH_P_IPV6:
+                                               route_ipv6(source, packet, len);
+                                               break;
+
+                                       default:
+                                               logger(LOG_WARNING, _("Cannot route packet from %s: unknown type %hx"), source->name, type);
+                                               break;
+                               }
+                       }
+                       break;
+
+               case RT_MODE_SWITCH:
+                       route_mac(source, packet, len);
+                       break;
+
+               case RT_MODE_HUB:
+                       broadcast_packet(source, packet, len);
+                       break;
+       }
+}
diff --git a/src/route.h b/src/route.h
new file mode 100644 (file)
index 0000000..42c587f
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+    route.h -- routing
+
+    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
+                  2003-2004 Ivo Timmermans <ivo@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id: rt.h 1375 2004-03-22 12:30:39Z guus $
+*/
+
+#ifndef __ROUTE_H__
+#define __ROUTE_H__
+
+#include "rt/node.h"
+
+extern void route(node_t *, const uint8_t *, int);
+
+#endif
diff --git a/src/rt.c b/src/rt.c
new file mode 100644 (file)
index 0000000..43e33c6
--- /dev/null
+++ b/src/rt.c
@@ -0,0 +1,210 @@
+/*
+    rt.c -- routing
+
+    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
+                  2003-2004 Ivo Timmermans <ivo@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#include "system.h"
+
+#include "cfg/cfg.h"
+#include "rt/edge.h"
+#include "rt/node.h"
+#include "rt/rt.h"
+#include "rt/subnet.h"
+#include "support/xalloc.h"
+#include "tnl/tnl.h"
+#include "vnd/vnd.h"
+#include "tincd.h"
+
+vnd_t *rt_vnd = NULL;
+int rt_af = AF_UNSPEC;
+int rt_macexpire = 600;
+int rt_maxtimeout = 900;
+rt_mode_t rt_mode = RT_MODE_ROUTER;
+bool rt_priorityinheritance = false;
+bool rt_hostnames = false;
+bool rt_overwrite_mac = false;
+
+avl_tree_t *rt_tnls;
+avl_tree_t *rt_listeners;
+
+static bool rt_tnl_accept(tnl_t *t) {
+       
+}
+
+static bool rt_vnd_recv(vnd_t *vnd, const void *buf, int len) {
+       route(myself, buf, len);
+}
+
+static bool rt_tnl_recv_packet(tnl_t *tnl, const void *buf, int len) {
+       edge_t *edge = tnl->data;
+       route(edge->to, buf, len);
+}
+
+static bool rt_tnl_recv_meta(tnl_t *tnl, const void *buf, int len) {
+}
+
+static void rt_outgoing(char *name) {
+       tnl_t *tnl;
+
+       clear(new(tnl));
+       
+}
+
+bool rt_init(void) {
+       char *bindtoaddress = NULL;
+       char *bindtointerface = NULL;
+       char *device = NULL;
+       char *iface = NULL;
+       char *port = NULL;
+       cfg_t *cfg;
+       subnet_t *subnet;
+       struct addrinfo hint, *ai, *aip;
+       int err;
+       int listeners;
+       char *connectto = NULL;
+       
+       cfg_choice_t mode_choice[] = {
+               {"Router", RT_MODE_ROUTER},
+               {"Switch", RT_MODE_SWITCH},
+               {"Hub", RT_MODE_HUB},
+       };
+
+       cfg_choice_t af_choice[] = {
+               {"IPv4", AF_INET},
+               {"IPv6", AF_INET6},
+               {"Any", AF_UNSPEC},
+       };
+
+       logger(LOG_INFO, _("rt: initialising"));
+
+       if(!subnet_init() || !node_init() || !edge_init())
+               return false;
+
+       rt_tnls = avl_tree_new(NULL, NULL);
+       rt_listeners = avl_tree_new(NULL, NULL);
+
+       /* Read main configuration */
+
+       if(!cfg_get_choice(tinc_cfg, "AddressFamily", af_choice, AF_UNSPEC, &rt_af)
+                       || !cfg_get_string(tinc_cfg, "BindToAddress", NULL, &bindtoaddress)
+                       || !cfg_get_string(tinc_cfg, "BindToInterface", NULL, &bindtointerface)
+                       || !cfg_get_string(tinc_cfg, "Device", "/dev/net/tun", &device)
+                       || !cfg_get_bool(tinc_cfg, "Hostnames", false, &rt_hostnames)
+                       || !cfg_get_string(tinc_cfg, "Interface", tinc_netname, &iface)
+                       || !cfg_get_period(tinc_cfg, "MACExpire", 600, &rt_macexpire)
+                       || !cfg_get_period(tinc_cfg, "MaxTimeout", 3600, &rt_maxtimeout)
+                       || !cfg_get_choice(tinc_cfg, "Mode", mode_choice, RT_MODE_ROUTER, &rt_mode)
+                       || !cfg_get_bool(tinc_cfg, "PriorityInheritance", false, &rt_priorityinheritance))
+               return false;
+
+       /* Read host configuration for myself */
+       
+       if(!cfg_get_string(myself->cfg, "Port", "655", &port))
+               return false;
+
+       for(cfg = cfg_get(myself->cfg, "Subnet"); cfg; cfg = cfg_get_next(myself->cfg, cfg)) {
+               if(!cfg_subnet(cfg, &subnet))
+                       return false;
+
+               subnet->owner = myself;
+               subnet_add(subnet);
+       }
+
+       /* Open the virtual network device */
+
+       clear(new(rt_vnd));
+       
+       replace(rt_vnd->device, device);
+       replace(rt_vnd->interface, iface);
+       
+       rt_vnd->mode = (rt_mode == RT_MODE_ROUTER) ? VND_MODE_TUN : VND_MODE_TAP;
+       rt_vnd->recv = rt_vnd_recv;
+
+       if(!vnd_open(rt_vnd)) {
+               vnd_free(rt_vnd);
+               return false;
+       }
+       
+       /* Create listening sockets */
+
+       hint.ai_family = rt_af;
+       hint.ai_socktype = SOCK_STREAM;
+       hint.ai_protocol = IPPROTO_TCP;
+       hint.ai_flags = AI_PASSIVE;
+
+       err = getaddrinfo(bindtoaddress, port, &hint, &ai);
+
+       if(err || !ai) {
+               logger(LOG_ERR, _("rt: system call '%s' failed: %s"), "getaddrinfo", gai_strerror(err));
+               return false;
+       }
+
+       listeners = 0;
+
+       for(aip = ai; aip; aip = aip->ai_next) {
+               tnl_listen_t *listener;
+               
+               clear(new(listener));
+               listener->local.address = *(struct sockaddr_storage *)aip->ai_addr;
+               listener->local.id = myself->name;
+               listener->type = SOCK_STREAM;
+               listener->protocol = IPPROTO_TCP;
+               // listener->local.cred = ...;
+               listener->accept = rt_tnl_accept;
+
+               if(tnl_listen(listener))
+                       listeners++;
+       }
+
+       freeaddrinfo(ai);
+
+       if(!listeners) {
+               logger(LOG_ERR, _("rt: unable to create any listening socket!"));
+               return false;
+       }
+
+       /* Setup outgoing connections */
+
+       for(cfg = cfg_get(tinc_cfg, "ConnectTo"); cfg; cfg = cfg_get_next(tinc_cfg, cfg)) {
+               if(!cfg_string(cfg, NULL, &connectto))
+                       return false;
+
+               if(!node_validname(connectto)) {
+                       logger(LOG_ERR, _("rt: invalid name for outgoing connection in %s line %d"), cfg->file, cfg->line);
+                       free(connectto);
+                       continue;
+               }
+
+               rt_outgoing(connectto);
+       }
+
+       return true;
+}
+
+bool rt_exit(void) {
+       edge_exit();
+       node_exit();
+       subnet_exit();
+
+       logger(LOG_INFO, _("rt: exitting"));
+}
+
+
diff --git a/src/rt.h b/src/rt.h
new file mode 100644 (file)
index 0000000..dd8126d
--- /dev/null
+++ b/src/rt.h
@@ -0,0 +1,54 @@
+/*
+    route.h -- routing
+
+    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
+                  2003-2004 Ivo Timmermans <ivo@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#ifndef __RT_H__
+#define __RT_H__
+
+#include "rt/node.h"
+#include "tnl/tnl.h"
+#include "vnd/vnd.h"
+
+#define RT_PROTOCOL 0
+
+typedef enum rt_mode {
+       RT_MODE_ROUTER,
+       RT_MODE_SWITCH,
+       RT_MODE_HUB,
+} rt_mode_t;
+
+extern int rt_af;
+extern enum rt_mode rt_mode;
+extern bool rt_hostnames;
+extern bool rt_priorityinheritance;
+extern int rt_macexpire;
+extern int rt_maxtimeout;
+extern bool rt_overwrite_mac;
+
+extern node_t *myself;
+extern vnd_t *rt_vnd;
+extern avl_tree_t *rt_tnls;
+
+extern bool rt_init(void);
+extern bool rt_exit(void);
+
+#endif
diff --git a/src/sockaddr.h b/src/sockaddr.h
new file mode 100644 (file)
index 0000000..8cd1c5e
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+    sockaddr.h -- sockaddr handling
+
+    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#ifndef __SOCKADDR_H__
+#define __SOCKADDR_H__
+
+#define AF_UNKNOWN 255
+
+struct sockaddr_unknown {
+       uint16_t family;
+       uint16_t pad1;
+       uint32_t pad2;
+       char *address;
+       char *port;
+};
+
+#define sa(s) ((struct sockaddr *)(s))
+#ifdef SA_LEN
+#define sa_len(s) SA_LEN((struct sockaddr *)(s))
+#else
+#define sa_len(s) (((struct sockaddr *)(s))->sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6))
+#endif
+
+#define sa_family(s) (((struct sockaddr *)(s))->sa_family)
+
+#define sa_unmap(s) ({if(((struct sockaddr *)(s))->sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)(s))->sin6_addr)) { \
+               ((struct sockaddr_in *)(s))->sin_addr.s_addr = ((struct sockaddr_in6 *)(s))->sin6_addr.s6_addr32[3]; \
+               ((struct sockaddr *)(s))->sa_family = AF_INET; \
+} \
+s;})
+
+#endif
diff --git a/src/subnet.c b/src/subnet.c
new file mode 100644 (file)
index 0000000..ced1695
--- /dev/null
@@ -0,0 +1,441 @@
+/*
+    subnet.c -- subnet handling
+
+    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
+                  2003-2004 Ivo Timmermans <ivo@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#include "system.h"
+
+#include "cfg/cfg.h"
+#include "logger/logger.h"
+#include "rt/node.h"
+#include "rt/subnet.h"
+#include "support/avl.h"
+#include "support/xalloc.h"
+
+avl_tree_t *subnets;
+/* Subnet mask handling */
+
+static int maskcmp(const void *va, const void *vb, int masklen, int len) {
+       int i, m, result;
+       const char *a = va;
+       const char *b = vb;
+
+       for(m = masklen, i = 0; m >= 8; m -= 8, i++) {
+               result = a[i] - b[i];
+               if(result)
+                       return result;
+       }
+
+       return m ? (a[i] & (0x100 - (1 << (8 - m)))) - (b[i] & (0x100 - (1 << (8 - m)))) : 0;
+}
+
+static void mask(void *va, int masklen, int len) {
+       int i;
+       char *a = va;
+
+       i = masklen / 8;
+       masklen %= 8;
+
+       if(masklen)
+               a[i++] &= (0x100 - (1 << masklen));
+
+       for(; i < len; i++)
+               a[i] = 0;
+}
+
+static void maskcpy(void *va, const void *vb, int masklen, int len) {
+       int i, m;
+       char *a = va;
+       const char *b = vb;
+
+       for(m = masklen, i = 0; m >= 8; m -= 8, i++)
+               a[i] = b[i];
+
+       if(m) {
+               a[i] = b[i] & (0x100 - (1 << m));
+               i++;
+       }
+
+       for(; i < len; i++)
+               a[i] = 0;
+}
+
+static bool maskcheck(const void *va, int masklen, int len) {
+       int i;
+       const char *a = va;
+
+       i = masklen / 8;
+       masklen %= 8;
+
+       if(masklen && a[i++] & (0xff >> masklen))
+               return false;
+
+       for(; i < len; i++)
+               if(a[i] != 0)
+                       return false;
+
+       return true;
+}
+
+/* Cache handling */
+
+struct {
+       subnet_t key;
+       subnet_t *subnet;
+} *cache;
+
+int cache_bits;
+int cache_size;
+uint32_t cache_mask;
+
+static void cache_flush(void) {
+       memset(cache, 0, sizeof *cache * cache_size);
+}
+
+static void cache_init(void) {
+       cache_bits = 8;
+       cache_size = 1 << 8;
+       cache_mask = cache_size - 1;
+
+       dim(cache, cache_size);
+
+       cache_flush();
+}
+
+static void cache_exit(void) {
+       free(cache);
+}
+
+static uint32_t subnet_hash(const subnet_t *subnet) {
+       uint32_t hash;
+       int i;
+
+       hash = subnet->type;
+
+       for(i = 0; i < sizeof subnet->net / sizeof(uint32_t); i++)
+               hash ^= ((uint32_t *)&subnet->net)[i];
+
+       hash ^= hash >> 16;
+       hash ^= hash >> 8;
+       
+       return hash & cache_mask;
+}
+
+static subnet_t *cache_get(subnet_t *subnet) {
+       uint32_t hash = subnet_hash(subnet);
+
+       if(cache[hash].subnet && memcmp(&cache[hash].key, subnet, sizeof *subnet))
+               return cache[hash].subnet;
+       else
+               return NULL;
+}
+
+static void cache_add(subnet_t *key, subnet_t *subnet) {
+       uint32_t hash = subnet_hash(subnet);
+
+       cache[hash].key = *key;
+       cache[hash].subnet = subnet;
+}
+
+/* Subnet tree handling */
+
+static int subnet_compare_mac(const subnet_t *a, const subnet_t *b) {
+       return memcmp(&a->net.mac.address, &b->net.mac.address, sizeof(mac_t))
+               ?: (a->owner && b->owner) ? strcmp(a->owner->name, b->owner->name) : 0;
+}
+
+static int subnet_compare_ipv4(const subnet_t *a, const subnet_t *b) {
+       return memcmp(&a->net.ipv4.address, &b->net.ipv4.address, sizeof(ipv4_t))
+               ?: (a->net.ipv4.prefixlength - b->net.ipv4.prefixlength)
+               ?: (a->owner && b->owner) ? strcmp(a->owner->name, b->owner->name) : 0;
+}
+
+static int subnet_compare_ipv6(const subnet_t *a, const subnet_t *b) {
+       return memcmp(&a->net.ipv6.address, &b->net.ipv6.address, sizeof(ipv6_t))
+               ?: (a->net.ipv6.prefixlength - b->net.ipv6.prefixlength)
+               ?: (a->owner && b->owner) ? strcmp(a->owner->name, b->owner->name) : 0;
+}
+
+static int subnet_compare(const subnet_t *a, const subnet_t *b) {
+       int result;
+
+       result = a->type - b->type;
+
+       if(result)
+               return result;
+
+       switch (a->type) {
+               case SUBNET_TYPE_MAC:
+                       return subnet_compare_mac(a, b);
+               case SUBNET_TYPE_IPV4:
+                       return subnet_compare_ipv4(a, b);
+               case SUBNET_TYPE_IPV6:
+                       return subnet_compare_ipv6(a, b);
+               default:
+                       logger(LOG_ERR, _("rt: subnet_compare() was called with unknown subnet type %d, exitting!"), a->type);
+                       exit(1);
+       }
+}
+
+avl_tree_t *subnet_tree_new(void) {
+       return avl_tree_new((avl_compare_t)subnet_compare, NULL);
+}
+
+void subnet_tree_free(avl_tree_t *subnets) {
+       avl_tree_free(subnets);
+}
+
+subnet_t *subnet_new(void) {
+       subnet_t *subnet;
+
+       return clear(new(subnet));
+}
+
+void subnet_free(subnet_t *subnet) {
+       free(subnet);
+}
+
+void subnet_add(subnet_t *subnet) {
+       avl_add(subnets, subnet);
+       avl_add(subnet->owner->subnets, subnet);
+       cache_flush();
+}
+
+void subnet_del(subnet_t *subnet) {
+       avl_del(subnet->owner->subnets, subnet);
+       avl_del(subnets, subnet);
+       cache_flush();
+}
+
+bool subnet_init(void) {
+       cache_init();
+       subnets = avl_tree_new((avl_compare_t)subnet_compare, (avl_action_t)subnet_free);
+
+       return true;
+}
+
+bool subnet_exit(void) {
+       avl_tree_del(subnets);
+       cache_exit();
+
+       return true;
+}
+
+subnet_t *str2net(const char *subnetstr) {
+       int i, l;
+       subnet_t subnet = {0};
+       uint16_t x[8];
+
+       if(sscanf(subnetstr, "%hu.%hu.%hu.%hu/%d",
+                         &x[0], &x[1], &x[2], &x[3], &l) == 5) {
+               subnet.type = SUBNET_TYPE_IPV4;
+               subnet.net.ipv4.prefixlength = l;
+
+               for(i = 0; i < 4; i++)
+                       subnet.net.ipv4.address.x[i] = x[i];
+
+               return copy(&subnet);
+       }
+
+       if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%d",
+                         &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7],
+                         &l) == 9) {
+               subnet.type = SUBNET_TYPE_IPV6;
+               subnet.net.ipv6.prefixlength = l;
+
+               for(i = 0; i < 8; i++)
+                       subnet.net.ipv6.address.x[i] = htons(x[i]);
+
+               return copy(&subnet);
+       }
+
+       if(sscanf(subnetstr, "%hu.%hu.%hu.%hu", &x[0], &x[1], &x[2], &x[3]) == 4) {
+               subnet.type = SUBNET_TYPE_IPV4;
+               subnet.net.ipv4.prefixlength = 32;
+
+               for(i = 0; i < 4; i++)
+                       subnet.net.ipv4.address.x[i] = x[i];
+
+               return copy(&subnet);
+       }
+
+       if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",
+                         &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7]) == 8) {
+               subnet.type = SUBNET_TYPE_IPV6;
+               subnet.net.ipv6.prefixlength = 128;
+
+               for(i = 0; i < 8; i++)
+                       subnet.net.ipv6.address.x[i] = htons(x[i]);
+
+               return copy(&subnet);
+       }
+
+       if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx",
+                         &x[0], &x[1], &x[2], &x[3], &x[4], &x[5]) == 6) {
+               subnet.type = SUBNET_TYPE_MAC;
+
+               for(i = 0; i < 6; i++)
+                       subnet.net.mac.address.x[i] = x[i];
+
+               return copy(&subnet);
+       }
+
+       return NULL;
+}
+
+char *net2str(const subnet_t *subnet) {
+       char *netstr;
+
+       switch (subnet->type) {
+               case SUBNET_TYPE_MAC:
+                       asprintf(&netstr, "%hx:%hx:%hx:%hx:%hx:%hx",
+                                        subnet->net.mac.address.x[0],
+                                        subnet->net.mac.address.x[1],
+                                        subnet->net.mac.address.x[2],
+                                        subnet->net.mac.address.x[3],
+                                        subnet->net.mac.address.x[4],
+                                        subnet->net.mac.address.x[5]);
+                       break;
+
+               case SUBNET_TYPE_IPV4:
+                       asprintf(&netstr, "%hu.%hu.%hu.%hu/%d",
+                                        subnet->net.ipv4.address.x[0],
+                                        subnet->net.ipv4.address.x[1],
+                                        subnet->net.ipv4.address.x[2],
+                                        subnet->net.ipv4.address.x[3],
+                                        subnet->net.ipv4.prefixlength);
+                       break;
+
+               case SUBNET_TYPE_IPV6:
+                       asprintf(&netstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%d",
+                                        ntohs(subnet->net.ipv6.address.x[0]),
+                                        ntohs(subnet->net.ipv6.address.x[1]),
+                                        ntohs(subnet->net.ipv6.address.x[2]),
+                                        ntohs(subnet->net.ipv6.address.x[3]),
+                                        ntohs(subnet->net.ipv6.address.x[4]),
+                                        ntohs(subnet->net.ipv6.address.x[5]),
+                                        ntohs(subnet->net.ipv6.address.x[6]),
+                                        ntohs(subnet->net.ipv6.address.x[7]),
+                                        subnet->net.ipv6.prefixlength);
+                       break;
+
+               default:
+                       logger(LOG_ERR, _("net2str() was called with unknown subnet type %d, exiting!"), subnet->type);
+                       exit(0);
+       }
+
+       return netstr;
+}
+
+bool cfg_subnet(cfg_t *cfg, subnet_t **result) {
+       subnet_t *subnet;
+
+       subnet = str2net(cfg->value);
+
+       if(!subnet) {
+               logger(LOG_ERR, _("rt: invalid subnet for configuration variable %s in %s line %d"),
+                  cfg->variable, cfg->file, cfg->line);
+               return false;
+       }
+
+       *result = subnet;
+
+       return true;
+}
+
+subnet_t *subnet_get(const subnet_t *subnet) {
+       return subnet->owner ? avl_get(subnet->owner->subnets, subnet) : avl_get(subnets, subnet);
+}
+
+subnet_t *subnet_get_mac(const mac_t *address) {
+       subnet_t *subnet, search = {0};
+
+       search.type = SUBNET_TYPE_MAC;
+       search.net.mac.address = *address;
+
+       subnet = cache_get(&search);
+       
+       if(subnet)
+               return subnet;
+
+       subnet = avl_get(subnets, &search);
+       
+       if(subnet)
+               cache_add(&search, subnet);
+
+       return subnet;
+}
+
+subnet_t *subnet_get_ipv4(const ipv4_t *address) {
+       subnet_t *subnet, search = {0};
+
+       search.type = SUBNET_TYPE_IPV4;
+       search.net.ipv4.address = *address;
+       search.net.ipv4.prefixlength = 32;
+
+       subnet = cache_get(&search);
+       
+       if(subnet)
+               return subnet;
+
+       while(subnet = avl_get_closest_smaller(subnets, &search)) {
+               if(subnet->type != SUBNET_TYPE_IPV4)
+                       return NULL;
+
+               if(!maskcmp(address, &subnet->net.ipv4.address, subnet->net.ipv4.prefixlength, sizeof(ipv4_t))) {
+                       cache_add(&search, subnet);
+                       return subnet;
+               }
+
+               search.net.ipv4.prefixlength = subnet->net.ipv4.prefixlength - 1;
+               maskcpy(&search.net.ipv4.address, &subnet->net.ipv4.address, search.net.ipv4.prefixlength, sizeof(ipv4_t));
+       }
+
+       return NULL;
+}
+
+subnet_t *subnet_get_ipv6(const ipv6_t *address) {
+       subnet_t *subnet, search = {0};
+
+       search.type = SUBNET_TYPE_IPV6;
+       search.net.ipv6.address = *address;
+       search.net.ipv6.prefixlength = 128;
+
+       subnet = cache_get(&search);
+       
+       if(subnet)
+               return subnet;
+
+       while(subnet = avl_get_closest_smaller(subnets, &search)) {
+               if(subnet->type != SUBNET_TYPE_IPV6)
+                       return NULL;
+
+               if(!maskcmp(address, &subnet->net.ipv6.address, subnet->net.ipv6.prefixlength, sizeof(ipv6_t))) {
+                       cache_add(&search, subnet);
+                       return subnet;
+               }
+
+               search.net.ipv6.prefixlength = subnet->net.ipv6.prefixlength - 1;
+               maskcpy(&search.net.ipv6.address, &subnet->net.ipv6.address, search.net.ipv6.prefixlength, sizeof(ipv6_t));
+       }
+
+       return NULL;
+}
diff --git a/src/subnet.h b/src/subnet.h
new file mode 100644 (file)
index 0000000..5134ae2
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+    subnet.h -- subnet handling
+
+    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
+                  2003-2004 Ivo Timmermans <ivo@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#ifndef __SUBNET_H__
+#define __SUBNET_H__
+
+#include "rt/node.h"
+#include "support/avl.h"
+
+typedef struct mac {
+        uint8_t x[6];
+} mac_t;
+
+typedef struct ipv4 {
+        uint8_t x[4];
+} ipv4_t;
+
+typedef struct ipv6 {
+        uint16_t x[8];
+} ipv6_t;
+
+typedef enum subnet_type {
+       SUBNET_TYPE_MAC,
+       SUBNET_TYPE_IPV4,
+       SUBNET_TYPE_IPV6,
+} subnet_type_t;
+
+typedef struct subnet_mac {
+       mac_t address;
+} subnet_mac_t;
+
+typedef struct subnet_ipv4 {
+       ipv4_t address;
+       int prefixlength;
+} subnet_ipv4_t;
+
+typedef struct subnet_ipv6 {
+       ipv6_t address;
+       int prefixlength;
+} subnet_ipv6_t;
+
+typedef struct subnet {
+       struct node *owner;
+       struct timeval expires;
+
+       enum subnet_type type;
+
+       union net {
+               struct subnet_mac mac;
+               struct subnet_ipv4 ipv4;
+               struct subnet_ipv6 ipv6;
+       } net;
+} subnet_t;
+
+extern subnet_t *subnet_new(void) __attribute__ ((__malloc__));
+extern void subnet_free(struct subnet *);
+extern bool subnet_init(void);
+extern bool subnet_exit(void);
+extern avl_tree_t *subnet_tree_new(void) __attribute__ ((__malloc__));
+extern void subnet_tree_free(avl_tree_t *);
+extern void subnet_add(struct subnet *);
+extern void subnet_del(struct subnet *);
+extern char *net2str(const struct subnet *);
+extern struct subnet *str2net(const char *);
+extern struct subnet *subnet_get(const struct subnet *);
+extern struct subnet *subnet_get_mac(const struct mac *);
+extern struct subnet *subnet_get_ipv4(const struct ipv4 *);
+extern struct subnet *subnet_get_ipv6(const struct ipv6 *);
+
+#endif
diff --git a/src/system.h b/src/system.h
new file mode 100644 (file)
index 0000000..1e2f4aa
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+    system.h -- system headers
+
+    Copyright (C) 1998-2004 Ivo Timmermans <ivo@tinc-vpn.org>
+                       2004 Guus Sliepen <guus@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    $Id$
+*/
+
+#ifndef __TINC_SYSTEM_H__
+#define __TINC_SYSTEM_H__
+
+#include "config.h"
+
+/* Include standard headers */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#ifdef HAVE_STDBOOL_H
+#include <stdbool.h>
+#else
+typedef int bool;
+#define true 1
+#define false 0
+#endif
+
+#ifdef HAVE_TERMIOS_H
+#include <termios.h>
+#endif
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+/* Include system specific headers */
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#ifdef HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+/* SunOS really wants sys/socket.h BEFORE net/if.h,
+   and FreeBSD wants these lines below the rest. */
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_SYSTM_H
+#include <netinet/in_systm.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_NETINET_IP_H
+#include <netinet/ip.h>
+#endif
+
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+
+#ifdef HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+
+#ifdef HAVE_NETINET_IP6_H
+#include <netinet/ip6.h>
+#endif
+
+#ifdef HAVE_MINGW
+#include <windows.h>
+#include <winsock2.h>
+#endif
+
+/* Include localisation support */
+
+#include "support/gettext.h"
+
+#if 0
+
+#ifndef HAVE_STRSIGNAL
+# define strsignal(p) ""
+#endif
+
+/* Other functions */
+
+#include "dropin.h"
+
+#endif
+
+#ifndef HAVE_SOCKLEN_T
+typedef int socklen_t;
+#endif
+
+#endif /* __TINC_SYSTEM_H__ */
diff --git a/src/test.c b/src/test.c
new file mode 100644 (file)
index 0000000..65810c2
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+    test.c -- tunnel test
+
+    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id: tnl.c 1379 2004-03-27 11:59:31Z guus $
+*/
+
+#include "system.h"
+
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+#include "logger/logger.h"
+#include "support/avl.h"
+#include "support/sockaddr.h"
+#include "support/xalloc.h"
+#include "tnl/tnl.h"
+
+static const int addressfamily = AF_UNSPEC;
+static const int socktype = SOCK_STREAM;
+static const int protocol = IPPROTO_TCP;
+
+bool server_recv_meta(struct tnl *tnl, const void *buf, int len) {
+       const char *in = buf;
+       char out[len];
+
+       for(int i = 0; i < len; i++) {
+               if(isupper(in[i]))
+                       out[i] = tolower(in[i]);
+               else if(islower(in[i]))
+                       out[i] = toupper(in[i]);
+               else
+                       out[i] = in[i];
+       }
+
+       tnl->send_meta(tnl, out, len);
+
+       return true;
+}
+
+bool server_accept(struct tnl *tnl) {
+       logger(LOG_INFO, _("Got connection from %s"), tnl->remote.id);
+       tnl->recv_meta = server_recv_meta;
+       return true;
+}
+
+void server(char *port) {
+       struct addrinfo *ai, hint = {0};
+       int err;
+       tnl_listen_t *listen = clear(new(listen));
+
+       hint.ai_family = addressfamily;
+       hint.ai_socktype = socktype;
+       hint.ai_protocol = protocol;
+       hint.ai_flags = AI_PASSIVE;
+
+       err = getaddrinfo(NULL, port, &hint, &ai);
+
+       if(err || !ai) {
+               logger(LOG_WARNING, _("Error looking up port %s: %s"), port, gai_strerror(err));
+               return;
+       }
+
+       if(sizeof listen->local.address < ai->ai_addrlen) {
+               logger(LOG_ERR, "%d < %d!", sizeof listen->local.address, ai->ai_addrlen);
+               return;
+       }
+
+       memcpy(&listen->local.address, ai->ai_addr, ai->ai_addrlen);
+       listen->local.id = xstrdup("CommonA");
+       listen->type = socktype;
+       listen->protocol = protocol;
+       listen->accept = server_accept;
+
+       logger(LOG_DEBUG, "Nu ga ik iets doen hoor");
+       if(!tnl_ep_set_x509_credentials(&listen->local, "server_key", "server_cert", "trust", NULL)) {
+               logger(LOG_ERR, "Couldn't set X.509 credentials!");
+               return;
+       }
+
+       if(!tnl_listen(listen)) {
+               logger(LOG_ERR, _("Could not listen!"));
+               return;
+       }
+}
+
+bool client_stdin_handler(fd_t *fd) {
+       tnl_t *tnl = fd->data;
+       char buf[1024];
+       int len;
+
+       len = read(fd->fd, buf, sizeof buf);
+
+       if(len <= 0) {
+               gnutls_bye(tnl->session, GNUTLS_SHUT_WR);
+               fd_del(fd);
+               return false;
+       }
+       
+       tnl->send_meta(tnl, buf, len);
+
+       return true;
+}
+
+bool client_recv_meta(struct tnl *tnl, const void *buf, int len) {
+       write(1, buf, len);
+       return true;
+}
+
+bool client_error(tnl_t *tnl, int err) {
+       exit(err);
+}
+
+bool client_accept(tnl_t *tnl) {
+       fd_t *fd;
+
+       logger(LOG_INFO, _("Connected to %s"), tnl->remote.id);
+       tnl->recv_meta = client_recv_meta;
+
+       clear(new(fd));
+       fd->fd = 0;
+       fd->read = client_stdin_handler;
+       fd->data = tnl;
+       fd_add(fd);
+
+       return true;
+}
+
+void client(char *host, char *port) {
+       struct addrinfo *ai, hint = {0};
+       int err;
+       static tnl_t *tnl;
+
+       hint.ai_family = addressfamily;
+       hint.ai_socktype = socktype;
+
+       err = getaddrinfo(host, port, &hint, &ai);
+
+       if(err || !ai) {
+               logger(LOG_WARNING, _("Error looking up %s port %s: %s"), host, port, gai_strerror(err));
+               return;
+       }
+
+       clear(new(tnl));
+       memcpy(&tnl->remote.address, ai->ai_addr, ai->ai_addrlen);
+       tnl->local.id = xstrdup("CommonB");
+       tnl->remote.id = xstrdup("CommonA");
+       tnl->type = socktype;
+       tnl->protocol = protocol;
+       tnl->accept = client_accept;
+       tnl->error = client_error;
+
+       if(!tnl_ep_set_x509_credentials(&tnl->local, "client_key", "client_cert", "trust", NULL)) {
+               logger(LOG_ERR, "Couldn't set credentials!");
+               return;
+       }
+
+       if(!tnl_connect(tnl)) {
+               logger(LOG_ERR, _("Could not connect to server!"));
+               return;
+       }
+}
+
+int main(int argc, char **argv) {
+       gnutls_global_init();
+       gnutls_global_init_extra();
+
+       fd_init();
+       logger_init(argv[0], LOGGER_MODE_NULL);
+
+       if(argc > 2)
+               client(argv[1], argv[2]);
+       else if(argc > 1)
+               server(argv[1]);
+       else {
+               logger(LOG_ERR, "Usage: %s [host] port\n", argv[0]);
+               return 1;
+       }
+
+       fd_run();
+
+       return 0;
+}
diff --git a/src/tincd.c b/src/tincd.c
new file mode 100644 (file)
index 0000000..2e40152
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+    tincd.c -- the main file for tincd
+
+    Copyright (C) 2000-2004 Guus Sliepen <guus@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#include "system.h"
+
+#include <getopt.h>
+
+/* Darwin (MacOS/X) needs the following definition... */
+#ifndef _P1003_1B_VISIBLE
+#define _P1003_1B_VISIBLE
+#endif
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#include "tincd.h"
+#include "cfg/cfg.h"
+#include "fd/event.h"
+#include "fd/fd.h"
+#include "logger/logger.h"
+#include "rt/rt.h"
+#include "support/avl.h"
+#include "support/sockaddr.h"
+#include "support/xalloc.h"
+#include "tnl/tnl.h"
+#include "vnd/vnd.h"
+
+static bool show_help = false;
+static bool show_version = false;
+static int kill_tincd = 0;
+static bool bypass_security = false;
+static bool do_mlock = false;
+static bool do_detach = true;
+static int debug_level = 1;
+
+char *tinc_confbase = NULL;    
+char *tinc_netname = NULL;     
+char *tinc_identname = NULL;   
+char *tinc_pidfilename = NULL;
+char *tinc_logfilename = NULL;
+char *tinc_cfgfilename = NULL;
+
+bool tinc_use_logfile = false;
+
+int tinc_argc;
+char **tinc_argv;
+avl_tree_t *tinc_cfg;
+
+static struct option const long_options[] = {
+       {"config", required_argument, NULL, 'c'},
+       {"kill", optional_argument, NULL, 'k'},
+       {"net", required_argument, NULL, 'n'},
+       {"help", no_argument, NULL, 1},
+       {"version", no_argument, NULL, 2},
+       {"no-detach", no_argument, NULL, 'D'},
+       {"debug", optional_argument, NULL, 'd'},
+       {"bypass-security", no_argument, NULL, 3},
+       {"mlock", no_argument, NULL, 'L'},
+       {"logfile", optional_argument, NULL, 4},
+       {"pidfile", required_argument, NULL, 5},
+       {NULL, 0, NULL, 0}
+};
+
+#ifdef HAVE_MINGW
+static struct WSAData wsa_state;
+#endif
+
+static void usage(bool status) {
+       if(status)
+               fprintf(stderr, _("Try `%s --help\' for more information.\n"), tinc_argv[0]);
+       else {
+               printf(_("Usage: %s [option]...\n\n"), tinc_argv[0]);
+               printf(_("  -c, --config=DIR           Read configuration options from DIR.\n"
+                               "  -D, --no-detach            Don't fork and detach.\n"
+                               "  -d, --debug[=LEVEL]        Increase debug level or set it to LEVEL.\n"
+                               "  -k, --kill[=SIGNAL]        Attempt to kill a running tincd and exit.\n"
+                               "  -n, --net=NETNAME          Connect to net NETNAME.\n"
+                               "  -L, --mlock                Lock tinc into main memory.\n"
+                               "      --logfile[=FILENAME]   Write log entries to a logfile.\n"
+                               "      --pidfile=FILENAME     Write PID to FILENAME.\n"
+                               "      --help                 Display this help and exit.\n"
+                               "      --version              Output version information and exit.\n\n"));
+               printf(_("Report bugs to tinc@tinc-vpn.org.\n"));
+       }
+}
+
+static bool parse_options(int argc, char **argv) {
+       int result;
+       int option_index = 0;
+
+       while((result = getopt_long(argc, argv, "c:DLd::k::n:", long_options, &option_index)) != EOF) {
+               switch (result) {
+                       case 0:
+                               break;
+
+                       case 'c': /* --config */
+                               tinc_confbase = xstrdup(optarg);
+                               break;
+
+                       case 'D': /* --no-detach */
+                               do_detach = false;
+                               break;
+
+                       case 'L': /* --mlock */
+                               do_mlock = true;
+                               break;
+
+                       case 'd': /* --debug */
+                               if(optarg)
+                                       debug_level = atoi(optarg);
+                               else
+                                       debug_level++;
+                               break;
+
+                       case 'k': /* --kill */
+#ifndef HAVE_MINGW
+                               if(optarg) {
+                                       if(!strcasecmp(optarg, "HUP"))
+                                               kill_tincd = SIGHUP;
+                                       else if(!strcasecmp(optarg, "TERM"))
+                                               kill_tincd = SIGTERM;
+                                       else if(!strcasecmp(optarg, "KILL"))
+                                               kill_tincd = SIGKILL;
+                                       else if(!strcasecmp(optarg, "USR1"))
+                                               kill_tincd = SIGUSR1;
+                                       else if(!strcasecmp(optarg, "USR2"))
+                                               kill_tincd = SIGUSR2;
+                                       else if(!strcasecmp(optarg, "WINCH"))
+                                               kill_tincd = SIGWINCH;
+                                       else if(!strcasecmp(optarg, "INT"))
+                                               kill_tincd = SIGINT;
+                                       else if(!strcasecmp(optarg, "ALRM"))
+                                               kill_tincd = SIGALRM;
+                                       else {
+                                               kill_tincd = atoi(optarg);
+
+                                               if(!kill_tincd) {
+                                                       fprintf(stderr, _("Invalid argument `%s'; SIGNAL must be a number or one of HUP, TERM, KILL, USR1, USR2, WINCH, INT or ALRM.\n"),
+                                                                       optarg);
+                                                       usage(true);
+                                                       return false;
+                                               }
+                                       }
+                               } else
+                                       kill_tincd = SIGTERM;
+#else
+                                       kill_tincd = 1;
+#endif
+                               break;
+
+                       case 'n': /* --net */
+                               tinc_netname = xstrdup(optarg);
+                               break;
+
+                       case 1: /* --help */
+                               show_help = true;
+                               break;
+
+                       case 2: /* --version */
+                               show_version = true;
+                               break;
+
+                       case 3: /* --bypass-security */
+                               bypass_security = true;
+                               break;
+
+                       case 4: /* --logfile */
+                               tinc_use_logfile = true;
+                               if(optarg)
+                                       tinc_logfilename = xstrdup(optarg);
+                               break;
+
+                       case 5: /* --pidfile */
+                               tinc_pidfilename = xstrdup(optarg);
+                               break;
+
+                       case '?':
+                               usage(true);
+                               return false;
+
+                       default:
+                               break;
+               }
+       }
+
+       return true;
+}
+
+static void make_names(void)
+{
+#ifdef HAVE_MINGW
+       HKEY key;
+       char installdir[1024] = "";
+       long len = sizeof(installdir);
+#endif
+
+       if(tinc_netname)
+               asprintf(&tinc_identname, "tinc.%s", tinc_netname);
+       else
+               tinc_identname = xstrdup("tinc");
+
+#ifdef HAVE_MINGW
+       if(!RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\tinc", 0, KEY_READ, &key)) {
+               if(!RegQueryValueEx(key, NULL, 0, 0, installdir, &len)) {
+                       if(!tinc_logfilename)
+                               asprintf(&tinc_logfilename, "%s/log/%s.log", tinc_identname);
+                       if(!tinc_confbase) {
+                               if(tinc_netname)
+                                       asprintf(&tinc_confbase, "%s/%s", installdir, tinc_netname);
+                               else
+                                       asprintf(&tinc_confbase, "%s", installdir);
+                       }
+               }
+               RegCloseKey(key);
+               if(*installdir)
+                       return;
+       }
+#endif
+
+       if(!tinc_pidfilename)
+               asprintf(&tinc_pidfilename, LOCALSTATEDIR "/run/%s.pid", tinc_identname);
+
+       if(!tinc_logfilename)
+               asprintf(&tinc_logfilename, LOCALSTATEDIR "/log/%s.log", tinc_identname);
+
+       if(!tinc_confbase) {
+               if(tinc_netname)
+                       asprintf(&tinc_confbase, CONFDIR "/tinc/%s", tinc_netname);
+               else
+                       asprintf(&tinc_confbase, CONFDIR "/tinc");
+       }
+
+       asprintf(&tinc_cfgfilename, "%s/tinc.conf", tinc_confbase);
+}
+
+int main(int argc, char **argv) {
+       tinc_argc = argc;
+       tinc_argv = argv;
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       if(!parse_options(argc, argv))
+               return 1;
+       
+       make_names();
+
+       if(show_version) {
+               printf(_("%s version %s (built %s %s, protocol %d/%d)\n"), PACKAGE,
+                          VERSION, __DATE__, __TIME__, TNL_PROTOCOL, RT_PROTOCOL);
+               printf(_("Copyright (C) 1998-2004 Ivo Timmermans, Guus Sliepen and others.\n"
+                               "See the AUTHORS file for a complete list.\n\n"
+                               "tinc comes with ABSOLUTELY NO WARRANTY.  This is free software,\n"
+                               "and you are welcome to redistribute it under certain conditions;\n"
+                               "see the file COPYING for details.\n"));
+
+               return 0;
+       }
+
+       if(show_help) {
+               usage(false);
+               return 0;
+       }
+
+       if(kill_tincd)
+               return !kill_other(kill_tincd);
+
+       logger_init("tinc", tinc_use_logfile ? LOGGER_MODE_FILE : LOGGER_MODE_STDERR);
+
+       /* Lock all pages into memory if requested */
+
+       if(do_mlock)
+#ifdef HAVE_MLOCKALL
+               if(mlockall(MCL_CURRENT | MCL_FUTURE)) {
+                       logger(LOG_ERR, _("System call `%s' failed: %s"), "mlockall",
+                                  strerror(errno));
+#else
+       {
+               logger(LOG_ERR, _("mlockall() not supported on this platform!"));
+#endif
+               return -1;
+       }
+
+       tinc_cfg = cfg_tree_new();
+
+       asprintf(&tinc_cfgfilename, "%s/tinc.conf", tinc_confbase);
+       
+       if(!cfg_read_file(tinc_cfg, tinc_cfgfilename))
+               return 1;
+
+#ifdef HAVE_MINGW
+       if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) {
+               logger(LOG_ERR, _("System call `%s' failed: %s"), "WSAStartup", winerror(GetLastError()));
+               return 1;
+       }
+#endif
+
+       if(do_detach && !detach())
+               return 1;
+
+       logger(LOG_NOTICE, _("tincd %s (%s %s) starting, debug level %d"),
+                       VERSION, __DATE__, __TIME__, logger_level);
+
+       if(!fd_init() || !rt_init())
+               return 1;
+
+       fd_run();
+
+       rt_exit();
+       fd_exit();
+end:
+       logger(LOG_NOTICE, _("Terminating"));
+
+#ifndef HAVE_MINGW
+       remove_pid(tinc_pidfilename);
+#endif
+
+       logger_exit();
+       
+       return 0;
+}
diff --git a/src/tincd.h b/src/tincd.h
new file mode 100644 (file)
index 0000000..b2e6620
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+    tincd.h -- tinc specific global variables and functions
+
+    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id
+*/
+
+#ifndef __TINCD_H__
+#define __TINCD_H__
+
+#include "support/avl.h"
+
+extern char *tinc_confbase;    
+extern char *tinc_netname;     
+extern char *tinc_identname;   
+extern char *tinc_pidfilename;
+extern char *tinc_logfilename;
+extern char *tinc_cfgfilename;
+
+extern bool tinc_use_logfile;
+
+extern int tinc_argc;
+extern char **tinc_argv;
+extern avl_tree_t *tinc_cfg;
+
+extern bool remove_pid(const char *pidfilename);
+
+#endif
diff --git a/src/tnl.c b/src/tnl.c
new file mode 100644 (file)
index 0000000..75f82f7
--- /dev/null
+++ b/src/tnl.c
@@ -0,0 +1,521 @@
+/*
+    tnl.c -- tunnels
+
+    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#include "system.h"
+
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+#include "logger/logger.h"
+#include "support/avl.h"
+#include "support/sockaddr.h"
+#include "support/xalloc.h"
+#include "tnl/tnl.h"
+
+static bool tnl_send(tnl_t *tnl, const void *buf, int len) {
+       int result;
+
+       while(len) {
+               result = gnutls_record_send(tnl->session, buf, len);
+               if(result <= 0) {
+                       if(result == GNUTLS_E_INTERRUPTED || result == GNUTLS_E_AGAIN)
+                               continue;
+
+                       if(result)
+                               logger(LOG_ERR, _("tnl: error while sending: %s"), gnutls_strerror(result));
+                       else
+                               logger(LOG_INFO, _("tnl: connection closed by peer"));
+
+                       if(tnl->error)
+                               tnl->error(tnl, result);
+                       tnl->close(tnl);
+                       return !result;
+               }
+
+               buf += result;
+               len -= result;
+       }
+
+       return true;
+}
+
+static bool tnl_recv(tnl_t *tnl) {
+       tnl_record_t *record = (tnl_record_t *)tnl->buf;
+
+#if 0
+       int result = gnutls_record_recv(tnl->session, tnl->buf + tnl->bufread, sizeof tnl->buf - tnl->bufread);
+       if(result <= 0) {
+               if(result == GNUTLS_E_INTERRUPTED || result == GNUTLS_E_AGAIN)
+                       return true;
+
+               if(result)
+                       logger(LOG_ERR, _("tnl: error while receiving: %s"), gnutls_strerror(result));
+               else
+                       logger(LOG_INFO, _("tnl: connection closed by peer"));
+
+               if(tnl->error)
+                       tnl->error(tnl, result);
+               tnl->close(tnl);
+               return !result;
+       }
+
+       tnl->bufread += result;
+#endif
+
+       while(tnl->bufread >= sizeof *record && tnl->bufread - sizeof *record >= record->len) {
+               switch(record->type) {
+                       case TNL_RECORD_META:
+                               if(tnl->recv_meta)
+                                       tnl->recv_meta(tnl, record->data, record->len);
+                               break;
+
+                       case TNL_RECORD_PACKET:
+                               if(tnl->recv_packet)
+                                       tnl->recv_packet(tnl, record->data, record->len);
+                               break;
+                               
+                       default:
+                               logger(LOG_ERR, _("tnl: error while receiving: %s"), _("unknown record type"));
+                               if(tnl->error)
+                                       tnl->error(tnl, EINVAL);
+                               tnl->close(tnl);
+                               return false;
+               }
+
+               tnl->bufread -= sizeof *record + record->len;
+               memmove(tnl->buf, record->data + record->len, tnl->bufread);
+       }
+
+       return true;
+}
+
+static bool tnl_recv_handler(fd_t *fd) {
+       if(!fd)
+               abort();
+
+       tnl_t *tnl = fd->data;
+       int result;
+
+       result = gnutls_record_recv(tnl->session, tnl->buf + tnl->bufread, sizeof(tnl->buf) - tnl->bufread);
+       if(result <= 0) {
+               if(!result) {
+                       logger(LOG_DEBUG, _("tnl: connection closed by peer %s (%s)"), tnl->remote.id, tnl->remote.hostname);
+                       if(tnl->error)
+                               tnl->error(tnl, 0);
+                       tnl->close(tnl);
+                       return false;
+               }       
+                                       
+               if(gnutls_error_is_fatal(result)) {
+                       logger(LOG_DEBUG, _("tnl: reception failed: %s"), gnutls_strerror(result));
+                       if(tnl->error)
+                               tnl->error(tnl, result);
+                       tnl->close(tnl);
+                       return false;
+               }
+
+               return true;
+       }
+
+       tnl->bufread += result;
+       return tnl_recv(tnl);
+}
+
+bool tnl_ep_set_x509_credentials(tnl_ep_t *tnl_ep, const char *privkey, const char *certificate, const char *trust, const char *crl) {
+       int err;
+
+       if(tnl_ep->cred.certificate) {
+               gnutls_certificate_free_credentials(tnl_ep->cred.certificate);
+               tnl_ep->cred.certificate = NULL;
+       }
+       
+       if((err = gnutls_certificate_allocate_credentials(&tnl_ep->cred.certificate)) < 0) {
+               logger(LOG_ERR, _("Failed to allocate certificate credentials: %s"), gnutls_strerror(err));
+               return false;
+       }
+
+       if((err = gnutls_certificate_set_x509_key_file(tnl_ep->cred.certificate, certificate, privkey, GNUTLS_X509_FMT_PEM)) < 0) {
+               logger(LOG_ERR, _("Failed to load X.509 key and/or certificate: %s"), gnutls_strerror(err));
+               return false;
+       }
+
+       tnl_ep->cred.type = GNUTLS_CRD_CERTIFICATE;
+
+       if(trust && (err = gnutls_certificate_set_x509_trust_file(tnl_ep->cred.certificate, trust, GNUTLS_X509_FMT_PEM)) < 0) {
+               logger(LOG_ERR, _("Failed to set X.509 trust file: %s"), gnutls_strerror(err));
+               return false;
+       }
+       
+       if(crl && (err = gnutls_certificate_set_x509_crl_file(tnl_ep->cred.certificate, crl, GNUTLS_X509_FMT_PEM)) < 0) {
+               logger(LOG_ERR, _("Failed to set X.509 CRL file: %s"), gnutls_strerror(err));
+               return false;
+       }
+
+       //gnutls_certificate_set_verify_flags(tnl_ep->cred.certificate, GNUTLS_VERIFY_DISABLE_CA_SIGN);
+
+       return true;
+}      
+
+bool tnl_ep_set_openpgp_credentials(tnl_ep_t *tnl_ep, const char *privkey, const char *pubkey, const char *keyring, const char *trustdb) {
+       int err;
+
+       if(tnl_ep->cred.certificate) {
+               gnutls_certificate_free_credentials(tnl_ep->cred.certificate);
+               tnl_ep->cred.certificate = NULL;
+       }
+       
+       if((err = gnutls_certificate_allocate_credentials(&tnl_ep->cred.certificate)) < 0) {
+               logger(LOG_ERR, _("Failed to allocate certificate credentials: %s"), gnutls_strerror(err));
+               return false;
+       }
+
+       if((err = gnutls_certificate_set_openpgp_key_file(tnl_ep->cred.certificate, pubkey, privkey)) < 0) {
+               logger(LOG_ERR, _("Failed to load public and/or private OpenPGP key: %s"), gnutls_strerror(err));
+               return false;
+       }
+
+       tnl_ep->cred.type = GNUTLS_CRD_CERTIFICATE;
+
+       if(keyring && (err = gnutls_certificate_set_openpgp_keyring_file(tnl_ep->cred.certificate, keyring)) < 0) {
+               logger(LOG_ERR, _("Failed to set OpenPGP keyring file: %s"), gnutls_strerror(err));
+               return false;
+       }
+       
+       if(trustdb && (err = gnutls_certificate_set_openpgp_trustdb(tnl_ep->cred.certificate, trustdb)) < 0) {
+               logger(LOG_ERR, _("Failed to set OpenPGP trustdb file: %s"), gnutls_strerror(err));
+               return false;
+       }
+
+       //gnutls_certificate_set_verify_flags(tnl_ep->cred.certificate, GNUTLS_VERIFY_DISABLE_CA_SIGN);
+
+       return true;
+}              
+
+static bool tnl_authenticate_x509(tnl_t *tnl) {
+       gnutls_x509_crt cert;
+        const gnutls_datum *certs;
+        int ncerts = 0, result;
+       char name[1024];
+       int len;
+
+       certs = gnutls_certificate_get_peers(tnl->session, &ncerts);
+
+       if (!certs || !ncerts) {
+               logger(LOG_ERR, _("tnl: no certificates from %s"), tnl->remote.hostname);
+               return false;
+       }
+
+       gnutls_x509_crt_init(&cert);
+       result = gnutls_x509_crt_import(cert, certs, GNUTLS_X509_FMT_DER);
+
+       if(result) {
+               logger(LOG_ERR, _("tnl: error importing certificate from %s: %s"), tnl->remote.hostname, gnutls_strerror(result));
+               gnutls_x509_crt_deinit(cert);
+               return false;
+       }
+
+       len = sizeof name;
+       result = gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, name, &len);
+       gnutls_x509_crt_deinit(cert);
+       
+       if(result) {
+               logger(LOG_ERR, _("tnl: could not extract common name from certificate from %s: %s"), tnl->remote.hostname, gnutls_strerror(result));
+               return false;
+       }
+
+       if(len > sizeof name) {
+               logger(LOG_ERR, _("tnl: common name from certificate from %s too long"), tnl->remote.hostname);
+               return false;
+       }
+
+       if(tnl->remote.id && strcmp(tnl->remote.id, name)) {
+               logger(LOG_ERR, _("tnl: peer %s is %s instead of %s"), tnl->remote.hostname, name, tnl->remote.id);
+               return false;
+       }
+
+       replace(tnl->remote.id, xstrdup(name));
+
+       result = gnutls_certificate_verify_peers(tnl->session);
+
+       if(result < 0) {
+               logger(LOG_ERR, "tnl: error verifying certificate from %s (%s): %s", tnl->remote.id, tnl->remote.hostname, gnutls_strerror(result));
+               return false;
+       }
+
+       if(result) {
+               logger(LOG_ERR, "tnl: certificate from %s (%s) not good, verification result %x", tnl->remote.id, tnl->remote.hostname, result);
+               return false;
+       }
+
+       return true;
+}
+
+static bool tnl_authenticate(tnl_t *tnl) {
+       switch(tnl->local.cred.type) {
+               case GNUTLS_CRD_CERTIFICATE:
+                       switch(gnutls_certificate_type_get(tnl->session)) {
+                               case GNUTLS_CRT_X509:
+                                       return tnl_authenticate_x509(tnl);
+                               case GNUTLS_CRT_OPENPGP:
+                                       //return tnl_authenticate_openpgp(tnl);
+                               default:
+                                       logger(LOG_ERR, "tnl: unknown certificate type for session with %s (%s)", tnl->remote.id, tnl->remote.hostname);
+                                       return false;
+                       }
+
+               case GNUTLS_CRD_ANON:
+                       logger(LOG_ERR, "tnl: anonymous authentication not yet supported");
+                       return false;
+
+               case GNUTLS_CRD_SRP:
+                       logger(LOG_ERR, "tnl: SRP authentication not yet supported");
+                       return false;
+                               
+               default:
+                       logger(LOG_ERR, "tnl: unknown authentication type for session with %s (%s)", tnl->remote.id, tnl->remote.hostname);
+                       return false;
+       }
+}
+
+static bool tnl_handshake_handler(fd_t *fd) {
+       //char id[1024];
+       tnl_t *tnl = fd->data;
+       int result;
+
+       result = gnutls_handshake(tnl->session);
+       if(result < 0) {
+               if(gnutls_error_is_fatal(result)) {
+                       logger(LOG_ERR, "tnl: handshake error: %s", gnutls_strerror(result));
+                       tnl->close(tnl);
+                       return false;
+               }
+
+               /* check other stuff? */
+               return true;
+       }
+       
+       logger(LOG_DEBUG, _("tnl: handshake finished"));
+
+       if(!tnl_authenticate(tnl))
+               return false;
+
+       tnl->status = TNL_STATUS_UP;
+       tnl->fd.read = tnl_recv_handler;
+       if(tnl->accept)
+               tnl->accept(tnl);
+
+       return true;
+}
+
+static bool tnl_send_meta(tnl_t *tnl, const void *buf, int len) {
+       tnl_record_t record = {
+               .type = TNL_RECORD_META,
+               .len = len,
+       };
+
+       return tnl_send(tnl, &record, sizeof record) && tnl_send(tnl, buf, len);
+}
+
+static bool tnl_send_packet(tnl_t *tnl, const void *buf, int len) {
+       tnl_record_t record = {
+               .type = TNL_RECORD_PACKET,
+               .len = len,
+       };
+
+       return tnl_send(tnl, &record, sizeof record) && tnl_send(tnl, buf, len);
+}
+
+static bool tnl_close(tnl_t *tnl) {
+       if(tnl->session) {
+               gnutls_bye(tnl->session, GNUTLS_SHUT_RDWR);
+               gnutls_deinit(tnl->session);
+       }
+               
+       fd_del(&tnl->fd);
+       close(tnl->fd.fd);
+       
+       return true;
+}
+
+static bool tnl_accept_handler(fd_t *fd) {
+       tnl_listen_t *listener = fd->data;
+       tnl_t *tnl;
+       struct sockaddr_storage ss;
+       socklen_t len = sizeof ss;
+       int sock;       
+       
+       sock = accept(fd->fd, sa(&ss), &len);
+
+       if(sock == -1) {
+               logger(LOG_ERR, _("tnl: could not accept incoming connection: %s"), strerror(errno));
+               return false;
+       }
+
+       sa_unmap(&ss);
+       
+       logger(LOG_DEBUG, _("tnl: accepted incoming connection"));
+
+       clear(new(tnl));
+       tnl->local = listener->local;
+       tnl->remote.address = ss;
+       len = sizeof tnl->local.address;
+       getsockname(sock, sa(&tnl->local.address), &len);
+       sa_unmap(&tnl->local.address);
+       tnl->type = listener->type;
+       tnl->protocol = listener->protocol;
+       tnl->send_packet = tnl_send_packet;
+       tnl->send_meta = tnl_send_meta;
+       tnl->close = tnl_close;
+
+       tnl->fd.fd = sock;
+       tnl->fd.read = tnl_handshake_handler;
+       tnl->fd.data = tnl;
+
+       fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK);
+
+       tnl->status = TNL_STATUS_HANDSHAKE;
+       gnutls_init(&tnl->session, GNUTLS_SERVER);
+       //gnutls_handshake_set_private_extensions(tnl->session, 1);
+       gnutls_set_default_priority(tnl->session);
+       gnutls_credentials_set(tnl->session, tnl->local.cred.type, tnl->local.cred.certificate);
+       gnutls_certificate_server_set_request(tnl->session, GNUTLS_CERT_REQUEST);
+       gnutls_transport_set_ptr(tnl->session, (gnutls_transport_ptr)sock);
+
+       tnl->accept = listener->accept;
+       
+       fd_add(&tnl->fd);
+
+       tnl_handshake_handler(&tnl->fd);
+       
+       return true;
+}      
+
+static bool tnl_connect_handler(fd_t *fd) {
+       tnl_t *tnl = fd->data;
+       int result;
+       socklen_t len;
+
+       len = sizeof result;
+       getsockopt(fd->fd, SOL_SOCKET, SO_ERROR, &result, &len);
+       if(result) {
+               logger(LOG_ERR, "tnl: error while connecting: %s", strerror(result));
+               if(tnl->error)
+                       tnl->error(tnl, result);
+               tnl->close(tnl);
+               return false;
+       }
+       
+       logger(LOG_DEBUG, _("tnl: connected"));
+       
+       fcntl(tnl->fd.fd, F_SETFL, fcntl(tnl->fd.fd, F_GETFL) | O_NONBLOCK);
+
+       tnl->status = TNL_STATUS_HANDSHAKE;
+       gnutls_init(&tnl->session, GNUTLS_CLIENT);
+       //gnutls_handshake_set_private_extensions(tnl->session, 1);
+       gnutls_set_default_priority(tnl->session);
+       gnutls_credentials_set(tnl->session, tnl->local.cred.type, tnl->local.cred.certificate);
+       gnutls_certificate_server_set_request(tnl->session, GNUTLS_CERT_REQUEST);
+       gnutls_transport_set_ptr(tnl->session, (gnutls_transport_ptr)fd->fd);
+
+       tnl->fd.write = NULL;
+       tnl->fd.read = tnl_handshake_handler;
+       fd_mod(&tnl->fd);
+
+       tnl_handshake_handler(&tnl->fd);
+
+       return true;
+}
+
+bool tnl_connect(tnl_t *tnl) {
+       int sock;
+
+       sock = socket(sa_family(&tnl->remote.address), tnl->type, tnl->protocol);
+
+       if(sock == -1) {
+               logger(LOG_ERR, _("tnl: could not create socket: %s"), strerror(errno));
+               return false;
+       }
+       
+#if 0
+       if(sa_nonzero(&tnl->local.address) && bind(sock, sa(&tnl->local.address), sa_len(&tnl->local.address)) == -1) {
+               logger(LOG_ERR, _("tnl: could not bind socket: %s"), strerror(errno));
+               close(sock);
+               return false;
+       }
+#endif
+
+       if(connect(sock, sa(&tnl->remote.address), sa_len(&tnl->remote.address)) == -1) {
+               logger(LOG_ERR, _("tnl: could not connect: %s"), strerror(errno));
+               close(sock);
+               return false;
+       }
+
+       tnl->status = TNL_STATUS_CONNECTING;
+
+       tnl->fd.fd = sock;
+       tnl->fd.write = tnl_connect_handler;
+       tnl->fd.data = tnl;
+
+       tnl->send_packet = tnl_send_packet;
+       tnl->send_meta = tnl_send_meta;
+       tnl->close = tnl_close;
+       
+       fd_add(&tnl->fd);
+
+       return true;
+}
+
+static bool tnl_listen_close(tnl_listen_t *listener) {
+       fd_del(&listener->fd);
+       close(listener->fd.fd);
+       return true;
+}
+
+bool tnl_listen(tnl_listen_t *listener) {
+       int sock;
+
+       sock = socket(sa_family(&listener->local.address), listener->type, listener->protocol);
+
+       if(sock == -1) {
+               logger(LOG_ERR, _("tnl: could not create listener socket: %s"), strerror(errno));
+               return false;
+       }
+       
+       if(bind(sock, sa(&listener->local.address), sa_len(&listener->local.address)) == -1) {
+               logger(LOG_ERR, _("tnl: could not bind listener socket: %s"), strerror(errno));
+               return false;
+       }
+       
+       if(listen(sock, 10) == -1) {
+               logger(LOG_ERR, _("tnl: could not listen on listener socket: %s"), strerror(errno));
+               return false;
+       }
+
+       listener->fd.fd = sock;
+       listener->fd.read = tnl_accept_handler;
+       listener->fd.data = listener;
+       listener->close = tnl_listen_close;
+
+       fd_add(&listener->fd);
+
+       return true;
+}
diff --git a/src/tnl.h b/src/tnl.h
new file mode 100644 (file)
index 0000000..77a8b2a
--- /dev/null
+++ b/src/tnl.h
@@ -0,0 +1,116 @@
+/*
+    tnl.h -- tunnels
+
+    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#ifndef __TNL_H__
+#define __TNL_H__
+
+#include <gnutls/gnutls.h>
+#include <gnutls/extra.h>
+
+#include "fd/fd.h"
+
+#define TNL_PROTOCOL 0
+
+#define TNL_RECORD_PACKET 0
+#define TNL_RECORD_META 1
+#define TNL_RECORD_HELLO 2
+#define TNL_RECORD_BLA 3
+
+typedef struct tnl_record {
+       uint16_t type;
+       uint16_t len;
+       char data[];
+} tnl_record_t;
+
+typedef enum tnl_status {
+       TNL_STATUS_DOWN,
+       TNL_STATUS_CONNECTING,
+       TNL_STATUS_HANDSHAKE,
+       TNL_STATUS_UP,
+} tnl_status_t;
+
+typedef struct tnl_ep_credentials {
+       gnutls_credentials_type type;
+       union {
+               gnutls_anon_client_credentials anon_client;
+               gnutls_anon_server_credentials anon_server;
+               gnutls_srp_client_credentials srp_client;
+               gnutls_srp_server_credentials srp_server;
+               gnutls_certificate_credentials certificate;
+       };
+} tnl_ep_credentials_t;                
+
+typedef struct tnl_ep_cryptoparm {
+} tnl_ep_cryptoparm_t;
+
+typedef struct tnl_ep {
+       struct sockaddr_storage address;
+       char *id;
+       char *hostname;
+       struct tnl_ep_credentials cred;
+       struct tnl_ep_cryptoparm parm;
+} tnl_ep_t;
+
+typedef struct tnl {
+       struct tnl_ep local;
+       struct tnl_ep remote;
+       int type;
+       int protocol;
+       int mtu;
+       enum tnl_status status;
+       void *data;
+
+       bool (*send_packet)(struct tnl *tnl, const void *buf, int len);
+       bool (*send_meta)(struct tnl *tnl, const void *buf, int len);
+       bool (*close)(struct tnl *tnl);
+
+       bool (*recv_packet)(struct tnl *tnl, const void *buf, int len);
+       bool (*recv_meta)(struct tnl *tnl, const void *buf, int len);
+       bool (*accept)(struct tnl *tnl);
+       bool (*error)(struct tnl *tnl, int errnum);
+
+       /* private */
+       
+       gnutls_session session;
+       struct fd fd;
+       char buf[4096];
+       int bufread;
+} tnl_t;
+
+typedef struct tnl_listen {
+       struct tnl_ep local;
+       int type;
+       int protocol;
+
+       bool (*accept)(struct tnl *tnl);
+       bool (*close)(struct tnl_listen *listener);
+
+       struct fd fd;
+} tnl_listen_t;
+
+extern bool tnl_listen(struct tnl_listen *listener);
+extern bool tnl_connect(struct tnl *tnl);
+
+extern bool tnl_ep_set_x509_credentials(tnl_ep_t *tnl_ep, const char *key, const char *certificate, const char *trust, const char *crl);
+extern bool tnl_ep_set_openpgp_credentials(tnl_ep_t *tnl_ep, const char *privkey, const char *pubkey, const char *keyring, const char *trustdb);
+
+#endif /* __TNL_H__ */
diff --git a/src/vnd.c b/src/vnd.c
new file mode 100644 (file)
index 0000000..7eba993
--- /dev/null
+++ b/src/vnd.c
@@ -0,0 +1,150 @@
+/*
+    vnd.c -- virtual network device management
+
+    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
+                  2003-2004 Ivo Timmermans <ivo@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#include "system.h"
+
+#include <linux/if_tun.h>
+
+#include "fd/fd.h"
+#include "logger/logger.h"
+#include "support/xalloc.h"
+
+#include "vnd/vnd.h"
+
+vnd_t *vnd_new(void) {
+       vnd_t *vnd;
+
+       return clear(new(vnd));
+}
+
+void vnd_free(vnd_t *vnd) {
+       replace(vnd->device, NULL);
+       replace(vnd->interface, NULL);
+       replace(vnd->description, NULL);
+       free(vnd);
+}
+
+void vnd_set(vnd_t *vnd, char *device, char *interface, vnd_mode_t mode, vnd_handler_t recv) {
+       replace(vnd->device, device);
+       replace(vnd->interface, interface);
+       vnd->mode = mode;
+       vnd->recv = recv;
+}
+
+static bool vnd_send(vnd_t *vnd, const void *buf, int len) {
+       int result;
+
+       result = write(vnd->fd.fd, buf, len);
+
+       if(result == len || result < 0 && (errno == EINTR || errno == EAGAIN)) {
+               logger(LOG_INFO, _("vnd: wrote packet of %d bytes to %s"), len, vnd->description);
+               return true;
+       }
+
+       logger(LOG_INFO, _("vnd: error writing packet of %d bytes to %s: %s"), len, vnd->description, strerror(errno));
+
+       return false;
+}
+
+static bool vnd_recv_handler(fd_t *fd) {
+       vnd_t *vnd = fd->data;
+       char buf[vnd->mtu];
+       int len;
+
+       vnd = fd->data;
+
+       len = read(fd->fd, buf, sizeof buf);
+
+       if(len > 0) {
+               logger(LOG_INFO, _("vnd: read packet of %d bytes from %s"), len, vnd->description);
+               return vnd->recv(vnd, buf, len);
+       }
+
+       if(len < 0 && (errno == EINTR || errno == EAGAIN))
+               return true;
+
+       logger(LOG_ERR, _("vnd: error reading packet from %s: %s"), vnd->description, strerror(errno));
+
+       return false;
+}
+
+bool vnd_open(vnd_t *vnd) {
+       struct ifreq ifr = {0};
+       
+       if(!vnd->device)
+               vnd->device = xstrdup("/dev/net/tun");
+       
+       vnd->fd.fd = open(vnd->device, O_RDWR | O_NONBLOCK);
+
+       if(vnd->fd.fd < 0) {
+               logger(LOG_ERR, _("vnd: could not open %s: %s"), vnd->device, strerror(errno));
+               return false;
+       }
+
+       if(vnd->mode == VND_MODE_TUN)
+               ifr.ifr_flags = IFF_TUN;
+       else
+               ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+
+       if(vnd->interface)
+               strncpy(ifr.ifr_name, vnd->interface, IFNAMSIZ);
+
+       if(!ioctl(vnd->fd.fd, TUNSETIFF, &ifr)) {
+               if(vnd->interface)
+                       free(vnd->interface);
+               vnd->interface = xstrdup(ifr.ifr_name);
+       } else {
+               logger(LOG_ERR, _("vnd: %s is not a Linux tun/tap device"), vnd->device);
+               return false;
+       }
+
+       if(!vnd->mtu)
+               vnd->mtu = 1514;
+
+       vnd->send = vnd_send;
+       vnd->fd.read = vnd_recv_handler;
+       vnd->fd.data = vnd;
+
+       if(vnd->description)
+               free(vnd->description);
+
+       asprintf(&vnd->description, "Linux tun/tap device %s (interface %s)", vnd->device, vnd->interface);
+
+       if(!fd_add(&vnd->fd))
+               return false;
+
+       logger(LOG_INFO, _("vnd: opened %s"), vnd->description);
+
+       return true;
+}
+
+bool vnd_close(vnd_t *vnd) {
+       fd_del(&vnd->fd);
+
+       close(vnd->fd.fd);
+
+       logger(LOG_INFO, _("vnd: closed %s"), vnd->description);
+
+       return true;
+}
+
diff --git a/src/vnd.h b/src/vnd.h
new file mode 100644 (file)
index 0000000..47f8c6a
--- /dev/null
+++ b/src/vnd.h
@@ -0,0 +1,59 @@
+/*
+    vnd.c -- virtual network device management
+
+    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
+                  2003-2004 Ivo Timmermans <ivo@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#ifndef __VND_H__
+#define __VND_H__
+
+typedef enum vnd_mode{
+       VND_MODE_TUN,
+       VND_MODE_TAP,
+} vnd_mode_t;
+
+struct vnd;
+
+typedef bool (*vnd_handler_t)(struct vnd *vnd, const void *buf, int len);
+
+typedef struct vnd {
+       char *device;
+       char *interface;
+       enum vnd_mode mode;
+       int mtu;
+
+       vnd_handler_t recv;
+       vnd_handler_t send;
+
+       /* Private data */
+
+       struct fd fd;
+       char *description;
+} vnd_t;
+
+extern bool vnd_init(void);
+extern bool vnd_exit(void);
+extern struct vnd *vnd_new(void);
+extern void vnd_free(struct vnd *vnd);
+extern void vnd_set(struct vnd *vnd, char *device, char *interface, vnd_mode_t mode, vnd_handler_t recv);
+extern bool vnd_open(struct vnd *vnd);
+extern bool vnd_close(struct vnd *vnd);
+
+#endif /* __VND_H__ */
diff --git a/src/xalloc.c b/src/xalloc.c
new file mode 100644 (file)
index 0000000..80699f9
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+    xalloc.c -- safe memory allocation functions
+
+    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "xalloc.h"
+
+static void xalloc_fail(void) {
+       fprintf(stderr, "Memory exhausted\n");
+       exit(1);
+}
+
+void (*xalloc_fail_func)(void) = xalloc_fail;
+
+void *xmalloc(size_t n) {
+       void *p;
+
+       p = malloc(n);
+
+       if(!p)
+               xalloc_fail_func();
+
+       return p;
+}
+
+void *xrealloc(void *p, size_t n) {
+       p = realloc(p, n);
+
+       if(!p)
+               xalloc_fail_func();
+
+       return p;
+}
+
+void *xcalloc(size_t n, size_t s) {
+       void *p;
+
+       p = calloc(n, s);
+
+       if(!p)
+               xalloc_fail_func();
+
+       return p;
+}
+
+char *xstrdup(const char *s) {
+       char *p;
+
+       p = strdup(s);
+
+       if(!p)
+               xalloc_fail_func();
+
+       return p;
+}
+
diff --git a/src/xalloc.h b/src/xalloc.h
new file mode 100644 (file)
index 0000000..db2e531
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+    xalloc.h -- safe memory allocation functions
+
+    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#ifndef __XALLOC_H__
+#define __XALLOC_H__
+
+#define new(object) ({(object) = xmalloc(sizeof *(object));})
+#define dim(object, count) ({(object) = xmalloc(sizeof *(object) * (count));})
+#define redim(object, count) ({(object) = xrealloc((object), sizeof *(object) * (count));})
+#define copy(object) ({typeof(object) _copy; *(_copy = xmalloc(sizeof *(object))) = *(object); _copy;})
+#define clear(object) ({memset((object), 0, sizeof *(object));})
+#define replace(string, replacement) ({if(string) free(string); (string) = (replacement) ? xstrdup(replacement) : NULL;})
+
+void *xmalloc(size_t n) __attribute__ ((__malloc__));
+void *xrealloc(void *p, size_t n) __attribute__ ((__malloc__));
+char *xstrdup(const char *s) __attribute__ ((__malloc__));
+
+#endif
diff --git a/support/Makefile.am b/support/Makefile.am
deleted file mode 100644 (file)
index 8f38b94..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-noinst_LIBRARIES = libsupport.a
-
-noinst_HEADERS = avl.h ethernet.h ipv4.h ipv6.h list.h sockaddr.h xalloc.h
-
-libsupport_a_SOURCES = avl.c list.c xalloc.c
-
diff --git a/support/avl.c b/support/avl.c
deleted file mode 100644 (file)
index 96500cb..0000000
+++ /dev/null
@@ -1,675 +0,0 @@
-/*
-    avl.c -- AVL tree management
-
-    Copyright (C) 1998 Michael H. Buselli
-                  2000-2004 Ivo Timmermans <ivo@tinc-vpn.org>,
-                  2000-2004 Guus Sliepen <guus@tinc-vpn.org>
-                  2000-2004 Wessel Dankers <wsl@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    Original AVL tree library by Michael H. Buselli <cosine@cosine.org>.
-
-    Modified 2000-11-28 by Wessel Dankers <wsl@tinc-vpn.org> to use counts
-    instead of depths, to add the ->next and ->prev and to generally obfuscate
-    the code. Mail me if you found a bug.
-
-    Cleaned up and incorporated some of the ideas from the red-black tree
-    library for inclusion into tinc (http://www.tinc-vpn.org/) by
-    Guus Sliepen <guus@tinc-vpn.org>.
-
-    $Id$
-*/
-
-#include "system.h"
-
-#include "support/avl.h"
-#include "support/xalloc.h"
-
-#ifdef AVL_COUNT
-#define AVL_NODE_COUNT(n)  ((n) ? (n)->count : 0)
-#define AVL_L_COUNT(n)     (AVL_NODE_COUNT((n)->left))
-#define AVL_R_COUNT(n)     (AVL_NODE_COUNT((n)->right))
-#define AVL_CALC_COUNT(n)  (AVL_L_COUNT(n) + AVL_R_COUNT(n) + 1)
-#endif
-
-#ifdef AVL_DEPTH
-#define AVL_NODE_DEPTH(n)  ((n) ? (n)->depth : 0)
-#define L_AVL_DEPTH(n)     (AVL_NODE_DEPTH((n)->left))
-#define R_AVL_DEPTH(n)     (AVL_NODE_DEPTH((n)->right))
-#define AVL_CALC_DEPTH(n)  ((L_AVL_DEPTH(n)>R_AVL_DEPTH(n)?L_AVL_DEPTH(n):R_AVL_DEPTH(n)) + 1)
-#endif
-
-#ifndef AVL_DEPTH
-static int lg(unsigned int u) __attribute__ ((__const__));
-
-static int lg(unsigned int u) {
-       int r = 1;
-
-       if(!u)
-               return 0;
-
-       if(u & 0xffff0000) {
-               u >>= 16;
-               r += 16;
-       }
-
-       if(u & 0x0000ff00) {
-               u >>= 8;
-               r += 8;
-       }
-
-       if(u & 0x000000f0) {
-               u >>= 4;
-               r += 4;
-       }
-
-       if(u & 0x0000000c) {
-               u >>= 2;
-               r += 2;
-       }
-
-       if(u & 0x00000002)
-               r++;
-
-       return r;
-}
-#endif
-
-/* Internal helper functions */
-
-static int avl_check_balance(const avl_node_t *node) {
-#ifdef AVL_DEPTH
-       int d;
-
-       d = R_AVL_DEPTH(node) - L_AVL_DEPTH(node);
-
-       return d < -1 ? -1 : d > 1 ? 1 : 0;
-#else
-/*      int d;
- *      d = lg(AVL_R_COUNT(node)) - lg(AVL_L_COUNT(node));
- *      d = d<-1?-1:d>1?1:0;
- */
-       int pl, r;
-
-       pl = lg(AVL_L_COUNT(node));
-       r = AVL_R_COUNT(node);
-
-       if(r >> pl + 1)
-               return 1;
-
-       if(pl < 2 || r >> pl - 2)
-               return 0;
-
-       return -1;
-#endif
-}
-
-static void avl_rebalance(avl_tree_t *tree, avl_node_t *node) {
-       avl_node_t *child;
-       avl_node_t *gchild;
-       avl_node_t *parent;
-       avl_node_t **superparent;
-
-       parent = node;
-
-       while(node) {
-               parent = node->parent;
-
-               superparent =
-                       parent ? node ==
-                       parent->left ? &parent->left : &parent->right : &tree->root;
-
-               switch (avl_check_balance(node)) {
-                       case -1:
-                               child = node->left;
-#ifdef AVL_DEPTH
-                               if(L_AVL_DEPTH(child) >= R_AVL_DEPTH(child)) {
-#else
-                               if(AVL_L_COUNT(child) >= AVL_R_COUNT(child)) {
-#endif
-                                       node->left = child->right;
-                                       if(node->left)
-                                               node->left->parent = node;
-
-                                       child->right = node;
-                                       node->parent = child;
-                                       *superparent = child;
-                                       child->parent = parent;
-#ifdef AVL_COUNT
-                                       node->count = AVL_CALC_COUNT(node);
-                                       child->count = AVL_CALC_COUNT(child);
-#endif
-#ifdef AVL_DEPTH
-                                       node->depth = AVL_CALC_DEPTH(node);
-                                       child->depth = AVL_CALC_DEPTH(child);
-#endif
-                               } else {
-                                       gchild = child->right;
-                                       node->left = gchild->right;
-
-                                       if(node->left)
-                                               node->left->parent = node;
-                                       child->right = gchild->left;
-
-                                       if(child->right)
-                                               child->right->parent = child;
-                                       gchild->right = node;
-
-                                       if(gchild->right)
-                                               gchild->right->parent = gchild;
-                                       gchild->left = child;
-
-                                       if(gchild->left)
-                                               gchild->left->parent = gchild;
-                                       *superparent = gchild;
-
-                                       gchild->parent = parent;
-#ifdef AVL_COUNT
-                                       node->count = AVL_CALC_COUNT(node);
-                                       child->count = AVL_CALC_COUNT(child);
-                                       gchild->count = AVL_CALC_COUNT(gchild);
-#endif
-#ifdef AVL_DEPTH
-                                       node->depth = AVL_CALC_DEPTH(node);
-                                       child->depth = AVL_CALC_DEPTH(child);
-                                       gchild->depth = AVL_CALC_DEPTH(gchild);
-#endif
-                               }
-                               break;
-
-                       case 1:
-                               child = node->right;
-#ifdef AVL_DEPTH
-                               if(R_AVL_DEPTH(child) >= L_AVL_DEPTH(child)) {
-#else
-                               if(AVL_R_COUNT(child) >= AVL_L_COUNT(child)) {
-#endif
-                                       node->right = child->left;
-                                       if(node->right)
-                                               node->right->parent = node;
-                                       child->left = node;
-                                       node->parent = child;
-                                       *superparent = child;
-                                       child->parent = parent;
-#ifdef AVL_COUNT
-                                       node->count = AVL_CALC_COUNT(node);
-                                       child->count = AVL_CALC_COUNT(child);
-#endif
-#ifdef AVL_DEPTH
-                                       node->depth = AVL_CALC_DEPTH(node);
-                                       child->depth = AVL_CALC_DEPTH(child);
-#endif
-                               } else {
-                                       gchild = child->left;
-                                       node->right = gchild->left;
-
-                                       if(node->right)
-                                               node->right->parent = node;
-                                       child->left = gchild->right;
-
-                                       if(child->left)
-                                               child->left->parent = child;
-                                       gchild->left = node;
-
-                                       if(gchild->left)
-                                               gchild->left->parent = gchild;
-                                       gchild->right = child;
-
-                                       if(gchild->right)
-                                               gchild->right->parent = gchild;
-
-                                       *superparent = gchild;
-                                       gchild->parent = parent;
-#ifdef AVL_COUNT
-                                       node->count = AVL_CALC_COUNT(node);
-                                       child->count = AVL_CALC_COUNT(child);
-                                       gchild->count = AVL_CALC_COUNT(gchild);
-#endif
-#ifdef AVL_DEPTH
-                                       node->depth = AVL_CALC_DEPTH(node);
-                                       child->depth = AVL_CALC_DEPTH(child);
-                                       gchild->depth = AVL_CALC_DEPTH(gchild);
-#endif
-                               }
-                               break;
-
-                       default:
-#ifdef AVL_COUNT
-                               node->count = AVL_CALC_COUNT(node);
-#endif
-#ifdef AVL_DEPTH
-                               node->depth = AVL_CALC_DEPTH(node);
-#endif
-               }
-               node = parent;
-       }
-}
-
-static int avl_compare(const void *a, const void *b) {
-       return a - b;
-}
-
-/* (De)constructors */
-
-avl_tree_t *avl_tree_new(avl_compare_t compare, avl_action_t free) {
-       avl_tree_t *tree;
-
-       clear(new(tree));
-       tree->compare = compare ?: avl_compare;
-       tree->free = free;
-
-       return tree;
-}
-
-void avl_tree_free(avl_tree_t *tree) {
-       free(tree);
-}
-
-avl_node_t *avl_node_new(void) {
-       avl_node_t *node;
-
-       return clear(new(node));
-}
-
-void avl_node_free(avl_tree_t *tree, avl_node_t *node) {
-       if(node->data && tree->free)
-               tree->free(node->data);
-
-       free(node);
-}
-
-/* Searching */
-
-void *avl_get(const avl_tree_t *tree, const void *data) {
-       avl_node_t *node;
-
-       node = avl_get_node(tree, data);
-
-       return node ? node->data : NULL;
-}
-
-void *avl_get_closest(const avl_tree_t *tree, const void *data, int *result) {
-       avl_node_t *node;
-
-       node = avl_get_closest_node(tree, data, result);
-
-       return node ? node->data : NULL;
-}
-
-void *avl_get_closest_smaller(const avl_tree_t *tree, const void *data) {
-       avl_node_t *node;
-
-       node = avl_get_closest_smaller_node(tree, data);
-
-       return node ? node->data : NULL;
-}
-
-void *avl_get_closest_greater(const avl_tree_t *tree, const void *data) {
-       avl_node_t *node;
-
-       node = avl_get_closest_greater_node(tree, data);
-
-       return node ? node->data : NULL;
-}
-
-avl_node_t *avl_get_node(const avl_tree_t *tree, const void *data) {
-       avl_node_t *node;
-       int result;
-
-       node = avl_get_closest_node(tree, data, &result);
-
-       return result ? NULL : node;
-}
-
-avl_node_t *avl_get_closest_node(const avl_tree_t *tree, const void *data, int *result) {
-       avl_node_t *node;
-       int c;
-
-       node = tree->root;
-
-       if(!node) {
-               if(result)
-                       *result = 0;
-               return NULL;
-       }
-
-       for(;;) {
-               c = tree->compare(data, node->data);
-
-               if(c < 0) {
-                       if(node->left)
-                               node = node->left;
-                       else {
-                               if(result)
-                                       *result = -1;
-                               break;
-                       }
-               } else if(c > 0) {
-                       if(node->right)
-                               node = node->right;
-                       else {
-                               if(result)
-                                       *result = 1;
-                               break;
-                       }
-               } else {
-                       if(result)
-                               *result = 0;
-                       break;
-               }
-       }
-
-       return node;
-}
-
-avl_node_t *avl_get_closest_smaller_node(const avl_tree_t *tree, const void *data) {
-       avl_node_t *node;
-       int result;
-
-       node = avl_get_closest_node(tree, data, &result);
-
-       if(result < 0)
-               node = node->prev;
-
-       return node;
-}
-
-avl_node_t *avl_get_closest_greater_node(const avl_tree_t *tree, const void *data) {
-       avl_node_t *node;
-       int result;
-
-       node = avl_get_closest_node(tree, data, &result);
-
-       if(result > 0)
-               node = node->next;
-
-       return node;
-}
-
-/* Insertion and deletion */
-
-avl_node_t *avl_add(avl_tree_t *tree, void *data) {
-       avl_node_t *node, *result;
-
-       node = avl_node_new();
-       node->data = data;
-       
-       result = avl_add_node(tree, node);
-
-       if(!result)
-               free(node);
-
-       return result;
-}
-
-avl_node_t *avl_add_node(avl_tree_t *tree, avl_node_t *node) {
-       avl_node_t *closest;
-       int result;
-
-       if(!tree->root)
-               avl_add_top(tree, node);
-       else {
-               closest = avl_get_closest_node(tree, node->data, &result);
-
-               switch (result) {
-                       case -1:
-                               avl_add_before(tree, closest, node);
-                               break;
-
-                       case 1:
-                               avl_add_after(tree, closest, node);
-                               break;
-
-                       case 0:
-                               return NULL;
-               }
-       }
-
-#ifdef AVL_COUNT
-       node->count = 1;
-#endif
-#ifdef AVL_DEPTH
-       node->depth = 1;
-#endif
-
-       return node;
-}
-
-void avl_add_top(avl_tree_t *tree, avl_node_t *node) {
-       node->prev = node->next = node->parent = NULL;
-       tree->head = tree->tail = tree->root = node;
-}
-
-void avl_add_before(avl_tree_t *tree, avl_node_t *before, avl_node_t *node) {
-       if(!before) {
-               if(tree->tail)
-                       avl_add_after(tree, tree->tail, node);
-               else
-                       avl_add_top(tree, node);
-               return;
-       }
-
-       node->next = before;
-       node->parent = before;
-       node->prev = before->prev;
-
-       if(before->left) {
-               avl_add_after(tree, before->prev, node);
-               return;
-       }
-
-       if(before->prev)
-               before->prev->next = node;
-       else
-               tree->head = node;
-
-       before->prev = node;
-       before->left = node;
-
-       avl_rebalance(tree, before);
-}
-
-void avl_add_after(avl_tree_t *tree, avl_node_t *after, avl_node_t *node) {
-       if(!after) {
-               if(tree->head)
-                       avl_add_before(tree, tree->head, node);
-               else
-                       avl_add_top(tree, node);
-               return;
-       }
-
-       if(after->right) {
-               avl_add_before(tree, after->next, node);
-               return;
-       }
-
-       node->prev = after;
-       node->parent = after;
-       node->next = after->next;
-
-       if(after->next)
-               after->next->prev = node;
-       else
-               tree->tail = node;
-
-       after->next = node;
-       after->right = node;
-
-       avl_rebalance(tree, after);
-}
-
-avl_node_t *avl_unlink(avl_tree_t *tree, const void *data) {
-       avl_node_t *node;
-
-       node = avl_get_node(tree, data);
-
-       if(node)
-               avl_unlink_node(tree, node);
-
-       return node;
-}
-
-void avl_unlink_node(avl_tree_t *tree, avl_node_t *node) {
-       avl_node_t *parent;
-       avl_node_t **superparent;
-       avl_node_t *subst, *left, *right;
-       avl_node_t *balnode;
-
-       if(node->prev)
-               node->prev->next = node->next;
-       else
-               tree->head = node->next;
-       if(node->next)
-               node->next->prev = node->prev;
-       else
-               tree->tail = node->prev;
-
-       parent = node->parent;
-
-       superparent =
-               parent ? node ==
-               parent->left ? &parent->left : &parent->right : &tree->root;
-
-       left = node->left;
-       right = node->right;
-       if(!left) {
-               *superparent = right;
-
-               if(right)
-                       right->parent = parent;
-
-               balnode = parent;
-       } else if(!right) {
-               *superparent = left;
-               left->parent = parent;
-               balnode = parent;
-       } else {
-               subst = node->prev;
-
-               if(subst == left) {
-                       balnode = subst;
-               } else {
-                       balnode = subst->parent;
-                       balnode->right = subst->left;
-
-                       if(balnode->right)
-                               balnode->right->parent = balnode;
-
-                       subst->left = left;
-                       left->parent = subst;
-               }
-
-               subst->right = right;
-               subst->parent = parent;
-               right->parent = subst;
-               *superparent = subst;
-       }
-
-       avl_rebalance(tree, balnode);
-
-       node->next = node->prev = node->parent = node->left = node->right = NULL;
-
-#ifdef AVL_COUNT
-       node->count = 0;
-#endif
-#ifdef AVL_DEPTH
-       node->depth = 0;
-#endif
-}
-
-void avl_del_node(avl_tree_t *tree, avl_node_t *node) {
-       avl_unlink_node(tree, node);
-       avl_node_free(tree, node);
-}
-
-bool avl_del(avl_tree_t *tree, void *data) {
-       avl_node_t *node;
-
-       node = avl_get_node(tree, data);
-
-       if(node)
-               avl_del_node(tree, node);
-
-       return node;
-}
-
-/* Fast tree cleanup */
-
-void avl_tree_del(avl_tree_t *tree) {
-       avl_node_t *node;
-
-       avl_foreach_node(tree, node, avl_node_free(tree, node));
-       
-       avl_tree_free(tree);
-}
-
-/* Indexing */
-
-#ifdef AVL_COUNT
-avl_count_t avl_count(const avl_tree_t *tree) {
-       return AVL_NODE_COUNT(tree->root);
-}
-
-void *avl_get_indexed(const avl_tree_t *tree, avl_count_t index) {
-       avl_node_t *node;
-
-       node = avl_get_indexed_node(tree, index);
-
-       return node ? node->data : NULL;
-}
-
-avl_node_t *avl_get_indexed_node(const avl_tree_t *tree, avl_count_t index) {
-       avl_node_t *node;
-       avl_count_t c;
-
-       node = tree->root;
-
-       while(node) {
-               c = AVL_L_COUNT(node);
-
-               if(index < c) {
-                       node = node->left;
-               } else if(index > c) {
-                       node = node->right;
-                       index -= c + 1;
-               } else {
-                       return node;
-               }
-       }
-
-       return NULL;
-}
-
-avl_count_t avl_index(const avl_node_t *node) {
-       avl_node_t *next;
-       avl_count_t index;
-
-       index = AVL_L_COUNT(node);
-
-       while((next = node->parent)) {
-               if(node == next->right)
-                       index += AVL_L_COUNT(next) + 1;
-               node = next;
-       }
-
-       return index;
-}
-#endif
-#ifdef AVL_DEPTH
-avl_depth_t avl_depth(const avl_tree_t *tree) {
-       return AVL_NODE_DEPTH(tree->root);
-}
-#endif
diff --git a/support/avl.h b/support/avl.h
deleted file mode 100644 (file)
index ece7d1a..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
-    avl.h -- AVL tree management
-
-    Copyright (C) 1998 Michael H. Buselli
-                  2000-2004 Ivo Timmermans <ivo@tinc-vpn.org>,
-                  2000-2004 Guus Sliepen <guus@tinc-vpn.org>
-                  2000-2004 Wessel Dankers <wsl@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    Original AVL tree library by Michael H. Buselli <cosine@cosine.org>.
-
-    Modified 2000-11-28 by Wessel Dankers <wsl@tinc-vpn.org> to use counts
-    instead of depths, to add the ->next and ->prev and to generally obfuscate
-    the code. Mail me if you found a bug.
-
-    Cleaned up and incorporated some of the ideas from the red-black tree
-    library for inclusion into tinc (http://www.tinc-vpn.org/) by
-    Guus Sliepen <guus@tinc-vpn.org>.
-
-    $Id$
-*/
-
-
-#ifndef __AVL_H__
-#define __AVL_H__
-
-#ifndef AVL_DEPTH
-#ifndef AVL_COUNT
-#define AVL_DEPTH
-#endif
-#endif
-
-typedef uint32_t avl_count_t;
-typedef uint16_t avl_depth_t;
-
-typedef struct avl_node {
-       struct avl_node *next;
-       struct avl_node *prev;
-
-       struct avl_node *parent;
-       struct avl_node *left;
-       struct avl_node *right;
-
-#ifdef AVL_COUNT
-       avl_count_t count;
-#endif
-
-#ifdef AVL_DEPTH
-       avl_depth_t depth;
-#endif
-
-       void *data;
-} avl_node_t;
-
-typedef int (*avl_compare_t)(const void *, const void *);
-typedef void (*avl_action_t)(void *);
-typedef void (*avl_node_action_t)(struct avl_node *);
-
-typedef struct avl_tree {
-       struct avl_node *head;
-       struct avl_node *tail;
-
-       struct avl_node *root;
-
-       avl_compare_t compare;
-       avl_action_t free;
-} avl_tree_t;
-
-/* (De)constructors */
-
-extern struct avl_tree *avl_tree_new(avl_compare_t, avl_action_t);
-extern void avl_tree_free(struct avl_tree *);
-
-extern struct avl_node *avl_node_new(void);
-extern void avl_node_free(struct avl_tree *tree, struct avl_node *);
-
-/* Insertion and deletion */
-
-extern struct avl_node *avl_add(struct avl_tree *, void *);
-extern struct avl_node *avl_add_node(struct avl_tree *, struct avl_node *);
-
-extern void avl_add_top(struct avl_tree *, struct avl_node *);
-extern void avl_add_before(struct avl_tree *, struct avl_node *, struct avl_node *);
-extern void avl_add_after(struct avl_tree *, struct avl_node *, struct avl_node *);
-
-extern struct avl_node *avl_unlink(struct avl_tree *, const void *);
-extern void avl_unlink_node(struct avl_tree *tree, struct avl_node *);
-extern bool avl_del(struct avl_tree *, void *);
-extern void avl_del_node(struct avl_tree *, struct avl_node *);
-
-/* Fast tree cleanup */
-
-extern void avl_tree_del(struct avl_tree *);
-
-/* Searching */
-
-extern void *avl_get(const struct avl_tree *, const void *);
-extern void *avl_get_closest(const struct avl_tree *, const void *, int *);
-extern void *avl_get_closest_smaller(const struct avl_tree *, const void *);
-extern void *avl_get_closest_greater(const struct avl_tree *, const void *);
-
-extern struct avl_node *avl_get_node(const struct avl_tree *, const void *);
-extern struct avl_node *avl_get_closest_node(const struct avl_tree *, const void *, int *);
-extern struct avl_node *avl_get_closest_smaller_node(const struct avl_tree *, const void *);
-extern struct avl_node *avl_get_closest_greater_node(const struct avl_tree *, const void *);
-
-/* Tree walking */
-
-#define avl_foreach(tree, object, action) {avl_node_t *_node, *_next; \
-       for(_node = (tree)->head; _node; _node = _next) { \
-               _next = _node->next; \
-               (object) = _node->data; \
-               action; \
-       } \
-}
-
-#define avl_foreach_node(tree, node, action) {avl_node_t *_next; \
-       for((node) = (tree)->head; (node); (node) = _next) { \
-               _next = (node)->next; \
-               action; \
-       } \
-}
-
-/* Indexing */
-
-#ifdef AVL_COUNT
-extern avl_count_t avl_count(const struct avl_tree *);
-extern avl_count_t avl_index(const struct avl_node *);
-extern void *avl_get_indexed(const struct avl_tree *, avl_count_t);
-extern struct avl_node *avl_get_indexed_node(const struct avl_tree *, avl_count_t);
-#endif
-#ifdef AVL_DEPTH
-extern avl_depth_t avl_depth(const struct avl_tree *);
-#endif
-
-#endif
diff --git a/support/ethernet.h b/support/ethernet.h
deleted file mode 100644 (file)
index e7ad508..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
-    ethernet.h -- missing Ethernet related definitions
-    Copyright (C) 2004 Ivo Timmermans <ivo@tinc-vpn.org>
-                  2004 Guus Sliepen <guus@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#ifndef __ETHERNET_H__
-#define __ETHERNET_H__
-
-#ifndef ETH_ALEN
-#define ETH_ALEN 6
-#endif
-
-#ifndef ARPHRD_ETHER
-#define ARPHRD_ETHER 1
-#endif
-
-#ifndef ETH_P_IP
-#define ETH_P_IP 0x0800
-#endif
-
-#ifndef ETH_P_ARP
-#define ETH_P_ARP 0x0806
-#endif
-
-#ifndef ETH_P_IPV6
-#define ETH_P_IPV6 0x86DD
-#endif
-
-#ifndef HAVE_STRUCT_ETHER_HEADER
-struct ether_header {
-       uint8_t ether_dhost[ETH_ALEN];
-       uint8_t ether_shost[ETH_ALEN];
-       uint16_t ether_type;
-} __attribute__ ((__packed__));
-#endif
-
-#ifndef HAVE_STRUCT_ARPHDR
-struct arphdr {
-       uint16_t ar_hrd;
-       uint16_t ar_pro;
-       uint8_t ar_hln;
-       uint8_t ar_pln; 
-       uint16_t ar_op; 
-} __attribute__ ((__packed__));
-
-#define ARPOP_REQUEST 1 
-#define ARPOP_REPLY 2 
-#define ARPOP_RREQUEST 3 
-#define ARPOP_RREPLY 4 
-#define ARPOP_InREQUEST 8 
-#define ARPOP_InREPLY 9 
-#define ARPOP_NAK 10 
-#endif
-
-#ifndef HAVE_STRUCT_ETHER_ARP
-struct  ether_arp {
-       struct  arphdr ea_hdr;
-       uint8_t arp_sha[ETH_ALEN];
-       uint8_t arp_spa[4];
-       uint8_t arp_tha[ETH_ALEN];
-       uint8_t arp_tpa[4];
-} __attribute__ ((__packed__));
-#define arp_hrd ea_hdr.ar_hrd
-#define arp_pro ea_hdr.ar_pro
-#define arp_hln ea_hdr.ar_hln
-#define arp_pln ea_hdr.ar_pln
-#define arp_op ea_hdr.ar_op
-#endif
-
-#endif
diff --git a/support/gettext.h b/support/gettext.h
deleted file mode 100644 (file)
index a907403..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/* Convenience header for conditional use of GNU <libintl.h>.
-   Copyright (C) 1995-1998, 2000-2003 Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify it
-   under the terms of the GNU Library General Public License as published
-   by the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Library General Public License for more details.
-
-   You should have received a copy of the GNU Library General Public
-   License along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-   USA.  */
-
-#ifndef _LIBGETTEXT_H
-#define _LIBGETTEXT_H 1
-
-/* NLS can be disabled through the configure --disable-nls option.  */
-#if ENABLE_NLS
-
-/* Get declarations of GNU message catalog functions.  */
-# include <libintl.h>
-# include <locale.h>
-
-/* Shorthand notation */
-
-# define _(Text) gettext (Text)
-
-#else
-
-/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which
-   chokes if dcgettext is defined as a macro.  So include it now, to make
-   later inclusions of <locale.h> a NOP.  We don't include <libintl.h>
-   as well because people using "gettext.h" will not include <libintl.h>,
-   and also including <libintl.h> would fail on SunOS 4, whereas <locale.h>
-   is OK.  */
-#if defined(__sun)
-# include <locale.h>
-#endif
-
-/* Disabled NLS.
-   The casts to 'const char *' serve the purpose of producing warnings
-   for invalid uses of the value returned from these functions.
-   On pre-ANSI systems without 'const', the config.h file is supposed to
-   contain "#define const".  */
-# define gettext(Msgid) ((const char *) (Msgid))
-# define dgettext(Domainname, Msgid) ((const char *) (Msgid))
-# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid))
-# define ngettext(Msgid1, Msgid2, N) \
-    ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
-# define dngettext(Domainname, Msgid1, Msgid2, N) \
-    ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
-# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \
-    ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
-# define textdomain(Domainname) ((const char *) (Domainname))
-# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname))
-# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset))
-
-# define _(Text) Text
-# define setlocale(Category, Locale) ((const char *) (Locale))
-
-#endif
-
-/* A pseudo function call that serves as a marker for the automated
-   extraction of messages, but does not call gettext().  The run-time
-   translation is done at a different place in the code.
-   The argument, String, should be a literal string.  Concatenated strings
-   and other string expressions won't work.
-   The macro's expansion is not parenthesized, so that it is suitable as
-   initializer for static 'char[]' or 'const char[]' variables.  */
-#define gettext_noop(String) String
-
-#define N_(Text) Text
-
-#endif /* _LIBGETTEXT_H */
diff --git a/support/ipv4.h b/support/ipv4.h
deleted file mode 100644 (file)
index 19a290b..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
-    ipv4.h -- missing IPv4 related definitions
-
-    Copyright (C) 2003-2004 Ivo Timmermans <ivo@tinc-vpn.org>
-                  2003-2004 Guus Sliepen <guus@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#ifndef __IPV4_H__
-#define __IPV4_H__
-
-#ifndef AF_INET
-#define AF_INET 2
-#endif
-
-#ifndef IPPROTO_ICMP
-#define IPPROTO_ICMP 1
-#endif
-
-#ifndef ICMP_DEST_UNREACH
-#define ICMP_DEST_UNREACH 3
-#endif
-
-#ifndef ICMP_NET_UNKNOWN
-#define ICMP_NET_UNKNOWN 6
-#endif
-
-#ifndef ICMP_NET_UNREACH
-#define ICMP_NET_UNREACH 0
-#endif
-
-#ifndef IP_MSS
-#define       IP_MSS          576
-#endif
-
-#ifndef HAVE_STRUCT_IP
-struct ip {
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-       unsigned int ip_hl:4;
-       unsigned int ip_v:4;
-#else
-       unsigned int ip_v:4;
-       unsigned int ip_hl:4;
-#endif
-       uint8_t ip_tos;
-       uint16_t ip_len;
-       uint16_t ip_id; 
-       uint16_t ip_off;
-#define IP_RF 0x8000
-#define IP_DF 0x4000
-#define IP_MF 0x2000
-#define IP_OFFMASK 0x1fff
-       uint8_t ip_ttl;
-       uint8_t ip_p;
-       uint16_t ip_sum;
-       struct in_addr ip_src, ip_dst;
-} __attribute__ ((__packed__));
-#endif
-
-#ifndef HAVE_STRUCT_ICMP
-struct icmp {
-       uint8_t icmp_type;
-       uint8_t icmp_code;
-       uint16_t icmp_cksum;
-       union {
-               uint8_t ih_pptr;
-               struct in_addr ih_gwaddr;
-               struct ih_idseq {
-                       uint16_t icd_id;
-                       uint16_t icd_seq;
-               } ih_idseq;
-               uint32_t ih_void;
-
-
-               struct ih_pmtu {
-                       uint16_t ipm_void;
-                       uint16_t ipm_nextmtu;
-               } ih_pmtu;
-
-               struct ih_rtradv {
-                       uint8_t irt_num_addrs;
-                       uint8_t irt_wpa;
-                       uint16_t irt_lifetime;
-               } ih_rtradv;
-       } icmp_hun;
-#define icmp_pptr icmp_hun.ih_pptr
-#define icmp_gwaddr icmp_hun.ih_gwaddr
-#define icmp_id icmp_hun.ih_idseq.icd_id
-#define icmp_seq icmp_hun.ih_idseq.icd_seq
-#define icmp_void icmp_hun.ih_void
-#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void
-#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu
-#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs
-#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa
-#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime
-       union {
-               struct {
-                       uint32_t its_otime;
-                       uint32_t its_rtime;
-                       uint32_t its_ttime;
-               } id_ts;
-               struct {
-                       struct ip idi_ip;
-               } id_ip;
-               uint32_t id_mask;
-               uint8_t id_data[1];
-       } icmp_dun;
-#define icmp_otime icmp_dun.id_ts.its_otime
-#define icmp_rtime icmp_dun.id_ts.its_rtime
-#define icmp_ttime icmp_dun.id_ts.its_ttime
-#define icmp_ip icmp_dun.id_ip.idi_ip
-#define icmp_radv icmp_dun.id_radv
-#define icmp_mask icmp_dun.id_mask
-#define icmp_data icmp_dun.id_data
-} __attribute__ ((__packed__));
-#endif
-
-#endif
diff --git a/support/ipv6.h b/support/ipv6.h
deleted file mode 100644 (file)
index 5de7953..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
-    ipv6.h -- missing IPv6 related definitions
-
-    Copyright (C) 2003-2004 Ivo Timmermans <ivo@tinc-vpn.org>
-                  2003-2004 Guus Sliepen <guus@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#ifndef __IPV6_H__
-#define __IPV6_H__
-
-#ifndef AF_INET6
-#define AF_INET6 10
-#endif
-
-#ifndef IPPROTO_ICMPV6
-#define IPPROTO_ICMPV6 58
-#endif
-
-#ifndef HAVE_STRUCT_IN6_ADDR
-struct in6_addr {
-       union {
-               uint8_t u6_addr8[16];
-               uint16_t u6_addr16[8];
-               uint32_t u6_addr32[4];
-       } in6_u;
-} __attribute__ ((__packed__));
-#define s6_addr in6_u.u6_addr8
-#define s6_addr16 in6_u.u6_addr16
-#define s6_addr32 in6_u.u6_addr32
-#endif
-
-#ifndef HAVE_STRUCT_SOCKADDR_IN6
-struct sockaddr_in6 {
-       uint16_t sin6_family;
-       uint16_t sin6_port;
-       uint32_t sin6_flowinfo;
-       struct in6_addr sin6_addr;
-       uint32_t sin6_scope_id;
-} __attribute__ ((__packed__));
-#endif
-
-#ifndef IN6_IS_ADDR_V4MAPPED
-#define IN6_IS_ADDR_V4MAPPED(a) \
-        ((((__const uint32_t *) (a))[0] == 0) \
-        && (((__const uint32_t *) (a))[1] == 0) \
-        && (((__const uint32_t *) (a))[2] == htonl (0xffff)))
-#endif
-
-#ifndef HAVE_STRUCT_IP6_HDR
-struct ip6_hdr {
-       union {
-               struct ip6_hdrctl {
-                       uint32_t ip6_un1_flow;
-                       uint16_t ip6_un1_plen;
-                       uint8_t ip6_un1_nxt;
-                       uint8_t ip6_un1_hlim;
-               } ip6_un1;
-               uint8_t ip6_un2_vfc;
-       } ip6_ctlun;
-       struct in6_addr ip6_src;
-       struct in6_addr ip6_dst;
-} __attribute__ ((__packed__));
-#define ip6_vfc ip6_ctlun.ip6_un2_vfc
-#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow
-#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen
-#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt
-#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim
-#define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim
-#endif
-
-#ifndef HAVE_STRUCT_ICMP6_HDR
-struct icmp6_hdr {
-       uint8_t icmp6_type;
-       uint8_t icmp6_code;
-       uint16_t icmp6_cksum;
-       union {
-               uint32_t icmp6_un_data32[1];
-               uint16_t icmp6_un_data16[2];
-               uint8_t icmp6_un_data8[4];
-       } icmp6_dataun;
-} __attribute__ ((__packed__));
-#define ICMP6_DST_UNREACH_NOROUTE 0
-#define ICMP6_DST_UNREACH 1
-#define ICMP6_DST_UNREACH_ADDR 3
-#define ND_NEIGHBOR_SOLICIT 135
-#define ND_NEIGHBOR_ADVERT 136
-#define icmp6_data32 icmp6_dataun.icmp6_un_data32
-#define icmp6_data16 icmp6_dataun.icmp6_un_data16
-#define icmp6_data8 icmp6_dataun.icmp6_un_data8
-#endif
-
-#ifndef HAVE_STRUCT_ND_NEIGHBOR_SOLICIT
-struct nd_neighbor_solicit {
-       struct icmp6_hdr nd_ns_hdr;
-       struct in6_addr nd_ns_target;
-} __attribute__ ((__packed__));
-#define ND_OPT_SOURCE_LINKADDR 1
-#define ND_OPT_TARGET_LINKADDR 2
-#define nd_ns_type nd_ns_hdr.icmp6_type
-#define nd_ns_code nd_ns_hdr.icmp6_code
-#define nd_ns_cksum nd_ns_hdr.icmp6_cksum
-#define nd_ns_reserved nd_ns_hdr.icmp6_data32[0]
-#endif
-
-#ifndef HAVE_STRUCT_ND_OPT_HDR
-struct nd_opt_hdr {
-       uint8_t nd_opt_type;
-       uint8_t nd_opt_len;
-} __attribute__ ((__packed__));
-#endif
-
-#endif
diff --git a/support/list.c b/support/list.c
deleted file mode 100644 (file)
index 9e54ac0..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
-    list.c -- linked lists
-    Copyright (C) 2000-2004 Ivo Timmermans <ivo@tinc-vpn.org>
-                  2000-2004 Guus Sliepen <guus@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id: list.c 1374 2004-03-21 14:21:22Z guus $
-*/
-
-#include "system.h"
-
-#include "support/list.h"
-#include "support/xalloc.h"
-
-list_t *list_new(list_action_t free) {
-       list_t *list;
-
-       clear(new(list));
-       list->free = free;
-
-       return list;
-}
-
-void list_free(list_t *list) {
-       free(list);
-}
-
-list_node_t *list_node_new(void) {
-       list_node_t *node;
-
-       return clear(new(node));
-}
-
-void list_node_free(list_t *list, list_node_t *node) {
-       if(node->data && list->free)
-               list->free(node->data);
-
-       free(node);
-}
-
-list_node_t *list_add_head(list_t *list, void *data) {
-       list_node_t *node;
-
-       node = list_node_new();
-
-       node->data = data;
-       node->prev = NULL;
-       node->next = list->head;
-       list->head = node;
-
-       if(node->next)
-               node->next->prev = node;
-       else
-               list->tail = node;
-
-       list->count++;
-
-       return node;
-}
-
-list_node_t *list_add_tail(list_t *list, void *data) {
-       list_node_t *node;
-
-       node = list_node_new();
-
-       node->data = data;
-       node->next = NULL;
-       node->prev = list->tail;
-       list->tail = node;
-
-       if(node->prev)
-               node->prev->next = node;
-       else
-               list->head = node;
-
-       list->count++;
-
-       return node;
-}
-
-void list_unlink_node(list_t *list, list_node_t *node) {
-       if(node->prev)
-               node->prev->next = node->next;
-       else
-               list->head = node->next;
-
-       if(node->next)
-               node->next->prev = node->prev;
-       else
-               list->tail = node->prev;
-
-       list->count--;
-}
-
-void list_del_node(list_t *list, list_node_t *node) {
-       list_unlink_node(list, node);
-       list_node_free(list, node);
-}
-
-void list_del_head(list_t *list) {
-       list_del_node(list, list->head);
-}
-
-void list_del_tail(list_t *list) {
-       list_del_node(list, list->tail);
-}
-
-void *list_get_head(const list_t *list) {
-       if(list->head)
-               return list->head->data;
-       else
-               return NULL;
-}
-
-void *list_get_tail(const list_t *list) {
-       if(list->tail)
-               return list->tail->data;
-       else
-               return NULL;
-}
-
-void list_del(list_t *list) {
-       list_node_t *node;
-
-       list_foreach_node(list, node, list_node_free(list, node));
-       list_free(list);
-}
diff --git a/support/list.h b/support/list.h
deleted file mode 100644 (file)
index 124d7fc..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
-    list.h -- linked lists
-
-    Copyright (C) 2000-2004 Ivo Timmermans <ivo@tinc-vpn.org>
-                  2000-2004 Guus Sliepen <guus@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id: list.h 1374 2004-03-21 14:21:22Z guus $
-*/
-
-#ifndef __LIST_H__
-#define __LIST_H__
-
-typedef struct list_node {
-       struct list_node *prev;
-       struct list_node *next;
-
-       void *data;
-} list_node_t;
-
-typedef void (*list_action_t)(const void *);
-typedef void (*list_node_action_t)(const list_node_t *);
-
-typedef struct list {
-       struct list_node *head;
-       struct list_node *tail;
-       int count;
-
-       list_action_t free;
-} list_t;
-
-/* (De)constructors */
-
-extern struct list *list_new(list_action_t) __attribute__ ((__malloc__));
-extern void list_free(struct list *);
-extern struct list_node *list_node_new(void);
-extern void list_node_free(struct list *, struct list_node *);
-
-/* Insertion and deletion */
-
-extern struct list_node *list_add_head(struct list *, void *);
-extern struct list_node *list_add_tail(struct list *, void *);
-
-extern void list_unlink_node(struct list *, struct list_node *);
-extern void list_node_del(struct list *, struct list_node *);
-
-extern void list_del_head(struct list *);
-extern void list_del_tail(struct list *);
-
-/* Head/tail lookup */
-
-extern void *list_get_head(const struct list *);
-extern void *list_get_tail(const struct list *);
-
-/* Fast list deletion */
-
-extern void list_del(struct list *);
-
-/* Traversing */
-
-#define list_foreach(list, object, action) {list_node_t *_node, *_next; \
-        for(_node = (list)->head; _node; _node = _next) { \
-                _next = _node->next; \
-                (object) = _node->data; \
-                action; \
-        } \
-}
-
-#define list_foreach_node(list, node, action) {list_node_t *_next; \
-        for((node) = (list)->head; (node); (node) = _next) { \
-                _next = (node)->next; \
-                action; \
-        } \
-}
-
-#endif
diff --git a/support/sockaddr.h b/support/sockaddr.h
deleted file mode 100644 (file)
index 8cd1c5e..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
-    sockaddr.h -- sockaddr handling
-
-    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#ifndef __SOCKADDR_H__
-#define __SOCKADDR_H__
-
-#define AF_UNKNOWN 255
-
-struct sockaddr_unknown {
-       uint16_t family;
-       uint16_t pad1;
-       uint32_t pad2;
-       char *address;
-       char *port;
-};
-
-#define sa(s) ((struct sockaddr *)(s))
-#ifdef SA_LEN
-#define sa_len(s) SA_LEN((struct sockaddr *)(s))
-#else
-#define sa_len(s) (((struct sockaddr *)(s))->sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6))
-#endif
-
-#define sa_family(s) (((struct sockaddr *)(s))->sa_family)
-
-#define sa_unmap(s) ({if(((struct sockaddr *)(s))->sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)(s))->sin6_addr)) { \
-               ((struct sockaddr_in *)(s))->sin_addr.s_addr = ((struct sockaddr_in6 *)(s))->sin6_addr.s6_addr32[3]; \
-               ((struct sockaddr *)(s))->sa_family = AF_INET; \
-} \
-s;})
-
-#endif
diff --git a/support/xalloc.c b/support/xalloc.c
deleted file mode 100644 (file)
index 80699f9..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
-    xalloc.c -- safe memory allocation functions
-
-    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "xalloc.h"
-
-static void xalloc_fail(void) {
-       fprintf(stderr, "Memory exhausted\n");
-       exit(1);
-}
-
-void (*xalloc_fail_func)(void) = xalloc_fail;
-
-void *xmalloc(size_t n) {
-       void *p;
-
-       p = malloc(n);
-
-       if(!p)
-               xalloc_fail_func();
-
-       return p;
-}
-
-void *xrealloc(void *p, size_t n) {
-       p = realloc(p, n);
-
-       if(!p)
-               xalloc_fail_func();
-
-       return p;
-}
-
-void *xcalloc(size_t n, size_t s) {
-       void *p;
-
-       p = calloc(n, s);
-
-       if(!p)
-               xalloc_fail_func();
-
-       return p;
-}
-
-char *xstrdup(const char *s) {
-       char *p;
-
-       p = strdup(s);
-
-       if(!p)
-               xalloc_fail_func();
-
-       return p;
-}
-
diff --git a/support/xalloc.h b/support/xalloc.h
deleted file mode 100644 (file)
index db2e531..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-    xalloc.h -- safe memory allocation functions
-
-    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#ifndef __XALLOC_H__
-#define __XALLOC_H__
-
-#define new(object) ({(object) = xmalloc(sizeof *(object));})
-#define dim(object, count) ({(object) = xmalloc(sizeof *(object) * (count));})
-#define redim(object, count) ({(object) = xrealloc((object), sizeof *(object) * (count));})
-#define copy(object) ({typeof(object) _copy; *(_copy = xmalloc(sizeof *(object))) = *(object); _copy;})
-#define clear(object) ({memset((object), 0, sizeof *(object));})
-#define replace(string, replacement) ({if(string) free(string); (string) = (replacement) ? xstrdup(replacement) : NULL;})
-
-void *xmalloc(size_t n) __attribute__ ((__malloc__));
-void *xrealloc(void *p, size_t n) __attribute__ ((__malloc__));
-char *xstrdup(const char *s) __attribute__ ((__malloc__));
-
-#endif
diff --git a/system.h b/system.h
deleted file mode 100644 (file)
index 1e2f4aa..0000000
--- a/system.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
-    system.h -- system headers
-
-    Copyright (C) 1998-2004 Ivo Timmermans <ivo@tinc-vpn.org>
-                       2004 Guus Sliepen <guus@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-    $Id$
-*/
-
-#ifndef __TINC_SYSTEM_H__
-#define __TINC_SYSTEM_H__
-
-#include "config.h"
-
-/* Include standard headers */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <ctype.h>
-#include <signal.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#ifdef HAVE_STDBOOL_H
-#include <stdbool.h>
-#else
-typedef int bool;
-#define true 1
-#define false 0
-#endif
-
-#ifdef HAVE_TERMIOS_H
-#include <termios.h>
-#endif
-
-#ifdef HAVE_INTTYPES_H
-#include <inttypes.h>
-#endif
-
-/* Include system specific headers */
-
-#ifdef HAVE_SYSLOG_H
-#include <syslog.h>
-#endif
-
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-
-#ifdef HAVE_SYS_FILE_H
-#include <sys/file.h>
-#endif
-
-#ifdef HAVE_SYS_WAIT_H
-#include <sys/wait.h>
-#endif
-
-#ifdef HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-
-/* SunOS really wants sys/socket.h BEFORE net/if.h,
-   and FreeBSD wants these lines below the rest. */
-
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-
-#ifdef HAVE_NET_IF_H
-#include <net/if.h>
-#endif
-
-#ifdef HAVE_NETINET_IN_SYSTM_H
-#include <netinet/in_systm.h>
-#endif
-
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-
-#ifdef HAVE_NETINET_IP_H
-#include <netinet/ip.h>
-#endif
-
-#ifdef HAVE_NETINET_TCP_H
-#include <netinet/tcp.h>
-#endif
-
-#ifdef HAVE_NETINET_IN6_H
-#include <netinet/in6.h>
-#endif
-
-#ifdef HAVE_NETINET_IP6_H
-#include <netinet/ip6.h>
-#endif
-
-#ifdef HAVE_MINGW
-#include <windows.h>
-#include <winsock2.h>
-#endif
-
-/* Include localisation support */
-
-#include "support/gettext.h"
-
-#if 0
-
-#ifndef HAVE_STRSIGNAL
-# define strsignal(p) ""
-#endif
-
-/* Other functions */
-
-#include "dropin.h"
-
-#endif
-
-#ifndef HAVE_SOCKLEN_T
-typedef int socklen_t;
-#endif
-
-#endif /* __TINC_SYSTEM_H__ */
diff --git a/tincd.c b/tincd.c
deleted file mode 100644 (file)
index 2e40152..0000000
--- a/tincd.c
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
-    tincd.c -- the main file for tincd
-
-    Copyright (C) 2000-2004 Guus Sliepen <guus@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#include "system.h"
-
-#include <getopt.h>
-
-/* Darwin (MacOS/X) needs the following definition... */
-#ifndef _P1003_1B_VISIBLE
-#define _P1003_1B_VISIBLE
-#endif
-
-#ifdef HAVE_SYS_MMAN_H
-#include <sys/mman.h>
-#endif
-
-#include "tincd.h"
-#include "cfg/cfg.h"
-#include "fd/event.h"
-#include "fd/fd.h"
-#include "logger/logger.h"
-#include "rt/rt.h"
-#include "support/avl.h"
-#include "support/sockaddr.h"
-#include "support/xalloc.h"
-#include "tnl/tnl.h"
-#include "vnd/vnd.h"
-
-static bool show_help = false;
-static bool show_version = false;
-static int kill_tincd = 0;
-static bool bypass_security = false;
-static bool do_mlock = false;
-static bool do_detach = true;
-static int debug_level = 1;
-
-char *tinc_confbase = NULL;    
-char *tinc_netname = NULL;     
-char *tinc_identname = NULL;   
-char *tinc_pidfilename = NULL;
-char *tinc_logfilename = NULL;
-char *tinc_cfgfilename = NULL;
-
-bool tinc_use_logfile = false;
-
-int tinc_argc;
-char **tinc_argv;
-avl_tree_t *tinc_cfg;
-
-static struct option const long_options[] = {
-       {"config", required_argument, NULL, 'c'},
-       {"kill", optional_argument, NULL, 'k'},
-       {"net", required_argument, NULL, 'n'},
-       {"help", no_argument, NULL, 1},
-       {"version", no_argument, NULL, 2},
-       {"no-detach", no_argument, NULL, 'D'},
-       {"debug", optional_argument, NULL, 'd'},
-       {"bypass-security", no_argument, NULL, 3},
-       {"mlock", no_argument, NULL, 'L'},
-       {"logfile", optional_argument, NULL, 4},
-       {"pidfile", required_argument, NULL, 5},
-       {NULL, 0, NULL, 0}
-};
-
-#ifdef HAVE_MINGW
-static struct WSAData wsa_state;
-#endif
-
-static void usage(bool status) {
-       if(status)
-               fprintf(stderr, _("Try `%s --help\' for more information.\n"), tinc_argv[0]);
-       else {
-               printf(_("Usage: %s [option]...\n\n"), tinc_argv[0]);
-               printf(_("  -c, --config=DIR           Read configuration options from DIR.\n"
-                               "  -D, --no-detach            Don't fork and detach.\n"
-                               "  -d, --debug[=LEVEL]        Increase debug level or set it to LEVEL.\n"
-                               "  -k, --kill[=SIGNAL]        Attempt to kill a running tincd and exit.\n"
-                               "  -n, --net=NETNAME          Connect to net NETNAME.\n"
-                               "  -L, --mlock                Lock tinc into main memory.\n"
-                               "      --logfile[=FILENAME]   Write log entries to a logfile.\n"
-                               "      --pidfile=FILENAME     Write PID to FILENAME.\n"
-                               "      --help                 Display this help and exit.\n"
-                               "      --version              Output version information and exit.\n\n"));
-               printf(_("Report bugs to tinc@tinc-vpn.org.\n"));
-       }
-}
-
-static bool parse_options(int argc, char **argv) {
-       int result;
-       int option_index = 0;
-
-       while((result = getopt_long(argc, argv, "c:DLd::k::n:", long_options, &option_index)) != EOF) {
-               switch (result) {
-                       case 0:
-                               break;
-
-                       case 'c': /* --config */
-                               tinc_confbase = xstrdup(optarg);
-                               break;
-
-                       case 'D': /* --no-detach */
-                               do_detach = false;
-                               break;
-
-                       case 'L': /* --mlock */
-                               do_mlock = true;
-                               break;
-
-                       case 'd': /* --debug */
-                               if(optarg)
-                                       debug_level = atoi(optarg);
-                               else
-                                       debug_level++;
-                               break;
-
-                       case 'k': /* --kill */
-#ifndef HAVE_MINGW
-                               if(optarg) {
-                                       if(!strcasecmp(optarg, "HUP"))
-                                               kill_tincd = SIGHUP;
-                                       else if(!strcasecmp(optarg, "TERM"))
-                                               kill_tincd = SIGTERM;
-                                       else if(!strcasecmp(optarg, "KILL"))
-                                               kill_tincd = SIGKILL;
-                                       else if(!strcasecmp(optarg, "USR1"))
-                                               kill_tincd = SIGUSR1;
-                                       else if(!strcasecmp(optarg, "USR2"))
-                                               kill_tincd = SIGUSR2;
-                                       else if(!strcasecmp(optarg, "WINCH"))
-                                               kill_tincd = SIGWINCH;
-                                       else if(!strcasecmp(optarg, "INT"))
-                                               kill_tincd = SIGINT;
-                                       else if(!strcasecmp(optarg, "ALRM"))
-                                               kill_tincd = SIGALRM;
-                                       else {
-                                               kill_tincd = atoi(optarg);
-
-                                               if(!kill_tincd) {
-                                                       fprintf(stderr, _("Invalid argument `%s'; SIGNAL must be a number or one of HUP, TERM, KILL, USR1, USR2, WINCH, INT or ALRM.\n"),
-                                                                       optarg);
-                                                       usage(true);
-                                                       return false;
-                                               }
-                                       }
-                               } else
-                                       kill_tincd = SIGTERM;
-#else
-                                       kill_tincd = 1;
-#endif
-                               break;
-
-                       case 'n': /* --net */
-                               tinc_netname = xstrdup(optarg);
-                               break;
-
-                       case 1: /* --help */
-                               show_help = true;
-                               break;
-
-                       case 2: /* --version */
-                               show_version = true;
-                               break;
-
-                       case 3: /* --bypass-security */
-                               bypass_security = true;
-                               break;
-
-                       case 4: /* --logfile */
-                               tinc_use_logfile = true;
-                               if(optarg)
-                                       tinc_logfilename = xstrdup(optarg);
-                               break;
-
-                       case 5: /* --pidfile */
-                               tinc_pidfilename = xstrdup(optarg);
-                               break;
-
-                       case '?':
-                               usage(true);
-                               return false;
-
-                       default:
-                               break;
-               }
-       }
-
-       return true;
-}
-
-static void make_names(void)
-{
-#ifdef HAVE_MINGW
-       HKEY key;
-       char installdir[1024] = "";
-       long len = sizeof(installdir);
-#endif
-
-       if(tinc_netname)
-               asprintf(&tinc_identname, "tinc.%s", tinc_netname);
-       else
-               tinc_identname = xstrdup("tinc");
-
-#ifdef HAVE_MINGW
-       if(!RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\tinc", 0, KEY_READ, &key)) {
-               if(!RegQueryValueEx(key, NULL, 0, 0, installdir, &len)) {
-                       if(!tinc_logfilename)
-                               asprintf(&tinc_logfilename, "%s/log/%s.log", tinc_identname);
-                       if(!tinc_confbase) {
-                               if(tinc_netname)
-                                       asprintf(&tinc_confbase, "%s/%s", installdir, tinc_netname);
-                               else
-                                       asprintf(&tinc_confbase, "%s", installdir);
-                       }
-               }
-               RegCloseKey(key);
-               if(*installdir)
-                       return;
-       }
-#endif
-
-       if(!tinc_pidfilename)
-               asprintf(&tinc_pidfilename, LOCALSTATEDIR "/run/%s.pid", tinc_identname);
-
-       if(!tinc_logfilename)
-               asprintf(&tinc_logfilename, LOCALSTATEDIR "/log/%s.log", tinc_identname);
-
-       if(!tinc_confbase) {
-               if(tinc_netname)
-                       asprintf(&tinc_confbase, CONFDIR "/tinc/%s", tinc_netname);
-               else
-                       asprintf(&tinc_confbase, CONFDIR "/tinc");
-       }
-
-       asprintf(&tinc_cfgfilename, "%s/tinc.conf", tinc_confbase);
-}
-
-int main(int argc, char **argv) {
-       tinc_argc = argc;
-       tinc_argv = argv;
-
-       setlocale(LC_ALL, "");
-       bindtextdomain(PACKAGE, LOCALEDIR);
-       textdomain(PACKAGE);
-
-       if(!parse_options(argc, argv))
-               return 1;
-       
-       make_names();
-
-       if(show_version) {
-               printf(_("%s version %s (built %s %s, protocol %d/%d)\n"), PACKAGE,
-                          VERSION, __DATE__, __TIME__, TNL_PROTOCOL, RT_PROTOCOL);
-               printf(_("Copyright (C) 1998-2004 Ivo Timmermans, Guus Sliepen and others.\n"
-                               "See the AUTHORS file for a complete list.\n\n"
-                               "tinc comes with ABSOLUTELY NO WARRANTY.  This is free software,\n"
-                               "and you are welcome to redistribute it under certain conditions;\n"
-                               "see the file COPYING for details.\n"));
-
-               return 0;
-       }
-
-       if(show_help) {
-               usage(false);
-               return 0;
-       }
-
-       if(kill_tincd)
-               return !kill_other(kill_tincd);
-
-       logger_init("tinc", tinc_use_logfile ? LOGGER_MODE_FILE : LOGGER_MODE_STDERR);
-
-       /* Lock all pages into memory if requested */
-
-       if(do_mlock)
-#ifdef HAVE_MLOCKALL
-               if(mlockall(MCL_CURRENT | MCL_FUTURE)) {
-                       logger(LOG_ERR, _("System call `%s' failed: %s"), "mlockall",
-                                  strerror(errno));
-#else
-       {
-               logger(LOG_ERR, _("mlockall() not supported on this platform!"));
-#endif
-               return -1;
-       }
-
-       tinc_cfg = cfg_tree_new();
-
-       asprintf(&tinc_cfgfilename, "%s/tinc.conf", tinc_confbase);
-       
-       if(!cfg_read_file(tinc_cfg, tinc_cfgfilename))
-               return 1;
-
-#ifdef HAVE_MINGW
-       if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) {
-               logger(LOG_ERR, _("System call `%s' failed: %s"), "WSAStartup", winerror(GetLastError()));
-               return 1;
-       }
-#endif
-
-       if(do_detach && !detach())
-               return 1;
-
-       logger(LOG_NOTICE, _("tincd %s (%s %s) starting, debug level %d"),
-                       VERSION, __DATE__, __TIME__, logger_level);
-
-       if(!fd_init() || !rt_init())
-               return 1;
-
-       fd_run();
-
-       rt_exit();
-       fd_exit();
-end:
-       logger(LOG_NOTICE, _("Terminating"));
-
-#ifndef HAVE_MINGW
-       remove_pid(tinc_pidfilename);
-#endif
-
-       logger_exit();
-       
-       return 0;
-}
diff --git a/tincd.h b/tincd.h
deleted file mode 100644 (file)
index b2e6620..0000000
--- a/tincd.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
-    tincd.h -- tinc specific global variables and functions
-
-    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id
-*/
-
-#ifndef __TINCD_H__
-#define __TINCD_H__
-
-#include "support/avl.h"
-
-extern char *tinc_confbase;    
-extern char *tinc_netname;     
-extern char *tinc_identname;   
-extern char *tinc_pidfilename;
-extern char *tinc_logfilename;
-extern char *tinc_cfgfilename;
-
-extern bool tinc_use_logfile;
-
-extern int tinc_argc;
-extern char **tinc_argv;
-extern avl_tree_t *tinc_cfg;
-
-extern bool remove_pid(const char *pidfilename);
-
-#endif
diff --git a/tnl/Makefile.am b/tnl/Makefile.am
deleted file mode 100644 (file)
index 594838d..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-noinst_LIBRARIES = libtnl.a
-
-noinst_HEADERS = tnl.h
-
-libtnl_a_SOURCES = tnl.c
-
diff --git a/tnl/test.c b/tnl/test.c
deleted file mode 100644 (file)
index 65810c2..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
-    test.c -- tunnel test
-
-    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id: tnl.c 1379 2004-03-27 11:59:31Z guus $
-*/
-
-#include "system.h"
-
-#include <gnutls/gnutls.h>
-#include <gnutls/x509.h>
-
-#include "logger/logger.h"
-#include "support/avl.h"
-#include "support/sockaddr.h"
-#include "support/xalloc.h"
-#include "tnl/tnl.h"
-
-static const int addressfamily = AF_UNSPEC;
-static const int socktype = SOCK_STREAM;
-static const int protocol = IPPROTO_TCP;
-
-bool server_recv_meta(struct tnl *tnl, const void *buf, int len) {
-       const char *in = buf;
-       char out[len];
-
-       for(int i = 0; i < len; i++) {
-               if(isupper(in[i]))
-                       out[i] = tolower(in[i]);
-               else if(islower(in[i]))
-                       out[i] = toupper(in[i]);
-               else
-                       out[i] = in[i];
-       }
-
-       tnl->send_meta(tnl, out, len);
-
-       return true;
-}
-
-bool server_accept(struct tnl *tnl) {
-       logger(LOG_INFO, _("Got connection from %s"), tnl->remote.id);
-       tnl->recv_meta = server_recv_meta;
-       return true;
-}
-
-void server(char *port) {
-       struct addrinfo *ai, hint = {0};
-       int err;
-       tnl_listen_t *listen = clear(new(listen));
-
-       hint.ai_family = addressfamily;
-       hint.ai_socktype = socktype;
-       hint.ai_protocol = protocol;
-       hint.ai_flags = AI_PASSIVE;
-
-       err = getaddrinfo(NULL, port, &hint, &ai);
-
-       if(err || !ai) {
-               logger(LOG_WARNING, _("Error looking up port %s: %s"), port, gai_strerror(err));
-               return;
-       }
-
-       if(sizeof listen->local.address < ai->ai_addrlen) {
-               logger(LOG_ERR, "%d < %d!", sizeof listen->local.address, ai->ai_addrlen);
-               return;
-       }
-
-       memcpy(&listen->local.address, ai->ai_addr, ai->ai_addrlen);
-       listen->local.id = xstrdup("CommonA");
-       listen->type = socktype;
-       listen->protocol = protocol;
-       listen->accept = server_accept;
-
-       logger(LOG_DEBUG, "Nu ga ik iets doen hoor");
-       if(!tnl_ep_set_x509_credentials(&listen->local, "server_key", "server_cert", "trust", NULL)) {
-               logger(LOG_ERR, "Couldn't set X.509 credentials!");
-               return;
-       }
-
-       if(!tnl_listen(listen)) {
-               logger(LOG_ERR, _("Could not listen!"));
-               return;
-       }
-}
-
-bool client_stdin_handler(fd_t *fd) {
-       tnl_t *tnl = fd->data;
-       char buf[1024];
-       int len;
-
-       len = read(fd->fd, buf, sizeof buf);
-
-       if(len <= 0) {
-               gnutls_bye(tnl->session, GNUTLS_SHUT_WR);
-               fd_del(fd);
-               return false;
-       }
-       
-       tnl->send_meta(tnl, buf, len);
-
-       return true;
-}
-
-bool client_recv_meta(struct tnl *tnl, const void *buf, int len) {
-       write(1, buf, len);
-       return true;
-}
-
-bool client_error(tnl_t *tnl, int err) {
-       exit(err);
-}
-
-bool client_accept(tnl_t *tnl) {
-       fd_t *fd;
-
-       logger(LOG_INFO, _("Connected to %s"), tnl->remote.id);
-       tnl->recv_meta = client_recv_meta;
-
-       clear(new(fd));
-       fd->fd = 0;
-       fd->read = client_stdin_handler;
-       fd->data = tnl;
-       fd_add(fd);
-
-       return true;
-}
-
-void client(char *host, char *port) {
-       struct addrinfo *ai, hint = {0};
-       int err;
-       static tnl_t *tnl;
-
-       hint.ai_family = addressfamily;
-       hint.ai_socktype = socktype;
-
-       err = getaddrinfo(host, port, &hint, &ai);
-
-       if(err || !ai) {
-               logger(LOG_WARNING, _("Error looking up %s port %s: %s"), host, port, gai_strerror(err));
-               return;
-       }
-
-       clear(new(tnl));
-       memcpy(&tnl->remote.address, ai->ai_addr, ai->ai_addrlen);
-       tnl->local.id = xstrdup("CommonB");
-       tnl->remote.id = xstrdup("CommonA");
-       tnl->type = socktype;
-       tnl->protocol = protocol;
-       tnl->accept = client_accept;
-       tnl->error = client_error;
-
-       if(!tnl_ep_set_x509_credentials(&tnl->local, "client_key", "client_cert", "trust", NULL)) {
-               logger(LOG_ERR, "Couldn't set credentials!");
-               return;
-       }
-
-       if(!tnl_connect(tnl)) {
-               logger(LOG_ERR, _("Could not connect to server!"));
-               return;
-       }
-}
-
-int main(int argc, char **argv) {
-       gnutls_global_init();
-       gnutls_global_init_extra();
-
-       fd_init();
-       logger_init(argv[0], LOGGER_MODE_NULL);
-
-       if(argc > 2)
-               client(argv[1], argv[2]);
-       else if(argc > 1)
-               server(argv[1]);
-       else {
-               logger(LOG_ERR, "Usage: %s [host] port\n", argv[0]);
-               return 1;
-       }
-
-       fd_run();
-
-       return 0;
-}
diff --git a/tnl/tnl.c b/tnl/tnl.c
deleted file mode 100644 (file)
index 75f82f7..0000000
--- a/tnl/tnl.c
+++ /dev/null
@@ -1,521 +0,0 @@
-/*
-    tnl.c -- tunnels
-
-    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#include "system.h"
-
-#include <gnutls/gnutls.h>
-#include <gnutls/x509.h>
-
-#include "logger/logger.h"
-#include "support/avl.h"
-#include "support/sockaddr.h"
-#include "support/xalloc.h"
-#include "tnl/tnl.h"
-
-static bool tnl_send(tnl_t *tnl, const void *buf, int len) {
-       int result;
-
-       while(len) {
-               result = gnutls_record_send(tnl->session, buf, len);
-               if(result <= 0) {
-                       if(result == GNUTLS_E_INTERRUPTED || result == GNUTLS_E_AGAIN)
-                               continue;
-
-                       if(result)
-                               logger(LOG_ERR, _("tnl: error while sending: %s"), gnutls_strerror(result));
-                       else
-                               logger(LOG_INFO, _("tnl: connection closed by peer"));
-
-                       if(tnl->error)
-                               tnl->error(tnl, result);
-                       tnl->close(tnl);
-                       return !result;
-               }
-
-               buf += result;
-               len -= result;
-       }
-
-       return true;
-}
-
-static bool tnl_recv(tnl_t *tnl) {
-       tnl_record_t *record = (tnl_record_t *)tnl->buf;
-
-#if 0
-       int result = gnutls_record_recv(tnl->session, tnl->buf + tnl->bufread, sizeof tnl->buf - tnl->bufread);
-       if(result <= 0) {
-               if(result == GNUTLS_E_INTERRUPTED || result == GNUTLS_E_AGAIN)
-                       return true;
-
-               if(result)
-                       logger(LOG_ERR, _("tnl: error while receiving: %s"), gnutls_strerror(result));
-               else
-                       logger(LOG_INFO, _("tnl: connection closed by peer"));
-
-               if(tnl->error)
-                       tnl->error(tnl, result);
-               tnl->close(tnl);
-               return !result;
-       }
-
-       tnl->bufread += result;
-#endif
-
-       while(tnl->bufread >= sizeof *record && tnl->bufread - sizeof *record >= record->len) {
-               switch(record->type) {
-                       case TNL_RECORD_META:
-                               if(tnl->recv_meta)
-                                       tnl->recv_meta(tnl, record->data, record->len);
-                               break;
-
-                       case TNL_RECORD_PACKET:
-                               if(tnl->recv_packet)
-                                       tnl->recv_packet(tnl, record->data, record->len);
-                               break;
-                               
-                       default:
-                               logger(LOG_ERR, _("tnl: error while receiving: %s"), _("unknown record type"));
-                               if(tnl->error)
-                                       tnl->error(tnl, EINVAL);
-                               tnl->close(tnl);
-                               return false;
-               }
-
-               tnl->bufread -= sizeof *record + record->len;
-               memmove(tnl->buf, record->data + record->len, tnl->bufread);
-       }
-
-       return true;
-}
-
-static bool tnl_recv_handler(fd_t *fd) {
-       if(!fd)
-               abort();
-
-       tnl_t *tnl = fd->data;
-       int result;
-
-       result = gnutls_record_recv(tnl->session, tnl->buf + tnl->bufread, sizeof(tnl->buf) - tnl->bufread);
-       if(result <= 0) {
-               if(!result) {
-                       logger(LOG_DEBUG, _("tnl: connection closed by peer %s (%s)"), tnl->remote.id, tnl->remote.hostname);
-                       if(tnl->error)
-                               tnl->error(tnl, 0);
-                       tnl->close(tnl);
-                       return false;
-               }       
-                                       
-               if(gnutls_error_is_fatal(result)) {
-                       logger(LOG_DEBUG, _("tnl: reception failed: %s"), gnutls_strerror(result));
-                       if(tnl->error)
-                               tnl->error(tnl, result);
-                       tnl->close(tnl);
-                       return false;
-               }
-
-               return true;
-       }
-
-       tnl->bufread += result;
-       return tnl_recv(tnl);
-}
-
-bool tnl_ep_set_x509_credentials(tnl_ep_t *tnl_ep, const char *privkey, const char *certificate, const char *trust, const char *crl) {
-       int err;
-
-       if(tnl_ep->cred.certificate) {
-               gnutls_certificate_free_credentials(tnl_ep->cred.certificate);
-               tnl_ep->cred.certificate = NULL;
-       }
-       
-       if((err = gnutls_certificate_allocate_credentials(&tnl_ep->cred.certificate)) < 0) {
-               logger(LOG_ERR, _("Failed to allocate certificate credentials: %s"), gnutls_strerror(err));
-               return false;
-       }
-
-       if((err = gnutls_certificate_set_x509_key_file(tnl_ep->cred.certificate, certificate, privkey, GNUTLS_X509_FMT_PEM)) < 0) {
-               logger(LOG_ERR, _("Failed to load X.509 key and/or certificate: %s"), gnutls_strerror(err));
-               return false;
-       }
-
-       tnl_ep->cred.type = GNUTLS_CRD_CERTIFICATE;
-
-       if(trust && (err = gnutls_certificate_set_x509_trust_file(tnl_ep->cred.certificate, trust, GNUTLS_X509_FMT_PEM)) < 0) {
-               logger(LOG_ERR, _("Failed to set X.509 trust file: %s"), gnutls_strerror(err));
-               return false;
-       }
-       
-       if(crl && (err = gnutls_certificate_set_x509_crl_file(tnl_ep->cred.certificate, crl, GNUTLS_X509_FMT_PEM)) < 0) {
-               logger(LOG_ERR, _("Failed to set X.509 CRL file: %s"), gnutls_strerror(err));
-               return false;
-       }
-
-       //gnutls_certificate_set_verify_flags(tnl_ep->cred.certificate, GNUTLS_VERIFY_DISABLE_CA_SIGN);
-
-       return true;
-}      
-
-bool tnl_ep_set_openpgp_credentials(tnl_ep_t *tnl_ep, const char *privkey, const char *pubkey, const char *keyring, const char *trustdb) {
-       int err;
-
-       if(tnl_ep->cred.certificate) {
-               gnutls_certificate_free_credentials(tnl_ep->cred.certificate);
-               tnl_ep->cred.certificate = NULL;
-       }
-       
-       if((err = gnutls_certificate_allocate_credentials(&tnl_ep->cred.certificate)) < 0) {
-               logger(LOG_ERR, _("Failed to allocate certificate credentials: %s"), gnutls_strerror(err));
-               return false;
-       }
-
-       if((err = gnutls_certificate_set_openpgp_key_file(tnl_ep->cred.certificate, pubkey, privkey)) < 0) {
-               logger(LOG_ERR, _("Failed to load public and/or private OpenPGP key: %s"), gnutls_strerror(err));
-               return false;
-       }
-
-       tnl_ep->cred.type = GNUTLS_CRD_CERTIFICATE;
-
-       if(keyring && (err = gnutls_certificate_set_openpgp_keyring_file(tnl_ep->cred.certificate, keyring)) < 0) {
-               logger(LOG_ERR, _("Failed to set OpenPGP keyring file: %s"), gnutls_strerror(err));
-               return false;
-       }
-       
-       if(trustdb && (err = gnutls_certificate_set_openpgp_trustdb(tnl_ep->cred.certificate, trustdb)) < 0) {
-               logger(LOG_ERR, _("Failed to set OpenPGP trustdb file: %s"), gnutls_strerror(err));
-               return false;
-       }
-
-       //gnutls_certificate_set_verify_flags(tnl_ep->cred.certificate, GNUTLS_VERIFY_DISABLE_CA_SIGN);
-
-       return true;
-}              
-
-static bool tnl_authenticate_x509(tnl_t *tnl) {
-       gnutls_x509_crt cert;
-        const gnutls_datum *certs;
-        int ncerts = 0, result;
-       char name[1024];
-       int len;
-
-       certs = gnutls_certificate_get_peers(tnl->session, &ncerts);
-
-       if (!certs || !ncerts) {
-               logger(LOG_ERR, _("tnl: no certificates from %s"), tnl->remote.hostname);
-               return false;
-       }
-
-       gnutls_x509_crt_init(&cert);
-       result = gnutls_x509_crt_import(cert, certs, GNUTLS_X509_FMT_DER);
-
-       if(result) {
-               logger(LOG_ERR, _("tnl: error importing certificate from %s: %s"), tnl->remote.hostname, gnutls_strerror(result));
-               gnutls_x509_crt_deinit(cert);
-               return false;
-       }
-
-       len = sizeof name;
-       result = gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, name, &len);
-       gnutls_x509_crt_deinit(cert);
-       
-       if(result) {
-               logger(LOG_ERR, _("tnl: could not extract common name from certificate from %s: %s"), tnl->remote.hostname, gnutls_strerror(result));
-               return false;
-       }
-
-       if(len > sizeof name) {
-               logger(LOG_ERR, _("tnl: common name from certificate from %s too long"), tnl->remote.hostname);
-               return false;
-       }
-
-       if(tnl->remote.id && strcmp(tnl->remote.id, name)) {
-               logger(LOG_ERR, _("tnl: peer %s is %s instead of %s"), tnl->remote.hostname, name, tnl->remote.id);
-               return false;
-       }
-
-       replace(tnl->remote.id, xstrdup(name));
-
-       result = gnutls_certificate_verify_peers(tnl->session);
-
-       if(result < 0) {
-               logger(LOG_ERR, "tnl: error verifying certificate from %s (%s): %s", tnl->remote.id, tnl->remote.hostname, gnutls_strerror(result));
-               return false;
-       }
-
-       if(result) {
-               logger(LOG_ERR, "tnl: certificate from %s (%s) not good, verification result %x", tnl->remote.id, tnl->remote.hostname, result);
-               return false;
-       }
-
-       return true;
-}
-
-static bool tnl_authenticate(tnl_t *tnl) {
-       switch(tnl->local.cred.type) {
-               case GNUTLS_CRD_CERTIFICATE:
-                       switch(gnutls_certificate_type_get(tnl->session)) {
-                               case GNUTLS_CRT_X509:
-                                       return tnl_authenticate_x509(tnl);
-                               case GNUTLS_CRT_OPENPGP:
-                                       //return tnl_authenticate_openpgp(tnl);
-                               default:
-                                       logger(LOG_ERR, "tnl: unknown certificate type for session with %s (%s)", tnl->remote.id, tnl->remote.hostname);
-                                       return false;
-                       }
-
-               case GNUTLS_CRD_ANON:
-                       logger(LOG_ERR, "tnl: anonymous authentication not yet supported");
-                       return false;
-
-               case GNUTLS_CRD_SRP:
-                       logger(LOG_ERR, "tnl: SRP authentication not yet supported");
-                       return false;
-                               
-               default:
-                       logger(LOG_ERR, "tnl: unknown authentication type for session with %s (%s)", tnl->remote.id, tnl->remote.hostname);
-                       return false;
-       }
-}
-
-static bool tnl_handshake_handler(fd_t *fd) {
-       //char id[1024];
-       tnl_t *tnl = fd->data;
-       int result;
-
-       result = gnutls_handshake(tnl->session);
-       if(result < 0) {
-               if(gnutls_error_is_fatal(result)) {
-                       logger(LOG_ERR, "tnl: handshake error: %s", gnutls_strerror(result));
-                       tnl->close(tnl);
-                       return false;
-               }
-
-               /* check other stuff? */
-               return true;
-       }
-       
-       logger(LOG_DEBUG, _("tnl: handshake finished"));
-
-       if(!tnl_authenticate(tnl))
-               return false;
-
-       tnl->status = TNL_STATUS_UP;
-       tnl->fd.read = tnl_recv_handler;
-       if(tnl->accept)
-               tnl->accept(tnl);
-
-       return true;
-}
-
-static bool tnl_send_meta(tnl_t *tnl, const void *buf, int len) {
-       tnl_record_t record = {
-               .type = TNL_RECORD_META,
-               .len = len,
-       };
-
-       return tnl_send(tnl, &record, sizeof record) && tnl_send(tnl, buf, len);
-}
-
-static bool tnl_send_packet(tnl_t *tnl, const void *buf, int len) {
-       tnl_record_t record = {
-               .type = TNL_RECORD_PACKET,
-               .len = len,
-       };
-
-       return tnl_send(tnl, &record, sizeof record) && tnl_send(tnl, buf, len);
-}
-
-static bool tnl_close(tnl_t *tnl) {
-       if(tnl->session) {
-               gnutls_bye(tnl->session, GNUTLS_SHUT_RDWR);
-               gnutls_deinit(tnl->session);
-       }
-               
-       fd_del(&tnl->fd);
-       close(tnl->fd.fd);
-       
-       return true;
-}
-
-static bool tnl_accept_handler(fd_t *fd) {
-       tnl_listen_t *listener = fd->data;
-       tnl_t *tnl;
-       struct sockaddr_storage ss;
-       socklen_t len = sizeof ss;
-       int sock;       
-       
-       sock = accept(fd->fd, sa(&ss), &len);
-
-       if(sock == -1) {
-               logger(LOG_ERR, _("tnl: could not accept incoming connection: %s"), strerror(errno));
-               return false;
-       }
-
-       sa_unmap(&ss);
-       
-       logger(LOG_DEBUG, _("tnl: accepted incoming connection"));
-
-       clear(new(tnl));
-       tnl->local = listener->local;
-       tnl->remote.address = ss;
-       len = sizeof tnl->local.address;
-       getsockname(sock, sa(&tnl->local.address), &len);
-       sa_unmap(&tnl->local.address);
-       tnl->type = listener->type;
-       tnl->protocol = listener->protocol;
-       tnl->send_packet = tnl_send_packet;
-       tnl->send_meta = tnl_send_meta;
-       tnl->close = tnl_close;
-
-       tnl->fd.fd = sock;
-       tnl->fd.read = tnl_handshake_handler;
-       tnl->fd.data = tnl;
-
-       fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK);
-
-       tnl->status = TNL_STATUS_HANDSHAKE;
-       gnutls_init(&tnl->session, GNUTLS_SERVER);
-       //gnutls_handshake_set_private_extensions(tnl->session, 1);
-       gnutls_set_default_priority(tnl->session);
-       gnutls_credentials_set(tnl->session, tnl->local.cred.type, tnl->local.cred.certificate);
-       gnutls_certificate_server_set_request(tnl->session, GNUTLS_CERT_REQUEST);
-       gnutls_transport_set_ptr(tnl->session, (gnutls_transport_ptr)sock);
-
-       tnl->accept = listener->accept;
-       
-       fd_add(&tnl->fd);
-
-       tnl_handshake_handler(&tnl->fd);
-       
-       return true;
-}      
-
-static bool tnl_connect_handler(fd_t *fd) {
-       tnl_t *tnl = fd->data;
-       int result;
-       socklen_t len;
-
-       len = sizeof result;
-       getsockopt(fd->fd, SOL_SOCKET, SO_ERROR, &result, &len);
-       if(result) {
-               logger(LOG_ERR, "tnl: error while connecting: %s", strerror(result));
-               if(tnl->error)
-                       tnl->error(tnl, result);
-               tnl->close(tnl);
-               return false;
-       }
-       
-       logger(LOG_DEBUG, _("tnl: connected"));
-       
-       fcntl(tnl->fd.fd, F_SETFL, fcntl(tnl->fd.fd, F_GETFL) | O_NONBLOCK);
-
-       tnl->status = TNL_STATUS_HANDSHAKE;
-       gnutls_init(&tnl->session, GNUTLS_CLIENT);
-       //gnutls_handshake_set_private_extensions(tnl->session, 1);
-       gnutls_set_default_priority(tnl->session);
-       gnutls_credentials_set(tnl->session, tnl->local.cred.type, tnl->local.cred.certificate);
-       gnutls_certificate_server_set_request(tnl->session, GNUTLS_CERT_REQUEST);
-       gnutls_transport_set_ptr(tnl->session, (gnutls_transport_ptr)fd->fd);
-
-       tnl->fd.write = NULL;
-       tnl->fd.read = tnl_handshake_handler;
-       fd_mod(&tnl->fd);
-
-       tnl_handshake_handler(&tnl->fd);
-
-       return true;
-}
-
-bool tnl_connect(tnl_t *tnl) {
-       int sock;
-
-       sock = socket(sa_family(&tnl->remote.address), tnl->type, tnl->protocol);
-
-       if(sock == -1) {
-               logger(LOG_ERR, _("tnl: could not create socket: %s"), strerror(errno));
-               return false;
-       }
-       
-#if 0
-       if(sa_nonzero(&tnl->local.address) && bind(sock, sa(&tnl->local.address), sa_len(&tnl->local.address)) == -1) {
-               logger(LOG_ERR, _("tnl: could not bind socket: %s"), strerror(errno));
-               close(sock);
-               return false;
-       }
-#endif
-
-       if(connect(sock, sa(&tnl->remote.address), sa_len(&tnl->remote.address)) == -1) {
-               logger(LOG_ERR, _("tnl: could not connect: %s"), strerror(errno));
-               close(sock);
-               return false;
-       }
-
-       tnl->status = TNL_STATUS_CONNECTING;
-
-       tnl->fd.fd = sock;
-       tnl->fd.write = tnl_connect_handler;
-       tnl->fd.data = tnl;
-
-       tnl->send_packet = tnl_send_packet;
-       tnl->send_meta = tnl_send_meta;
-       tnl->close = tnl_close;
-       
-       fd_add(&tnl->fd);
-
-       return true;
-}
-
-static bool tnl_listen_close(tnl_listen_t *listener) {
-       fd_del(&listener->fd);
-       close(listener->fd.fd);
-       return true;
-}
-
-bool tnl_listen(tnl_listen_t *listener) {
-       int sock;
-
-       sock = socket(sa_family(&listener->local.address), listener->type, listener->protocol);
-
-       if(sock == -1) {
-               logger(LOG_ERR, _("tnl: could not create listener socket: %s"), strerror(errno));
-               return false;
-       }
-       
-       if(bind(sock, sa(&listener->local.address), sa_len(&listener->local.address)) == -1) {
-               logger(LOG_ERR, _("tnl: could not bind listener socket: %s"), strerror(errno));
-               return false;
-       }
-       
-       if(listen(sock, 10) == -1) {
-               logger(LOG_ERR, _("tnl: could not listen on listener socket: %s"), strerror(errno));
-               return false;
-       }
-
-       listener->fd.fd = sock;
-       listener->fd.read = tnl_accept_handler;
-       listener->fd.data = listener;
-       listener->close = tnl_listen_close;
-
-       fd_add(&listener->fd);
-
-       return true;
-}
diff --git a/tnl/tnl.h b/tnl/tnl.h
deleted file mode 100644 (file)
index 77a8b2a..0000000
--- a/tnl/tnl.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
-    tnl.h -- tunnels
-
-    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#ifndef __TNL_H__
-#define __TNL_H__
-
-#include <gnutls/gnutls.h>
-#include <gnutls/extra.h>
-
-#include "fd/fd.h"
-
-#define TNL_PROTOCOL 0
-
-#define TNL_RECORD_PACKET 0
-#define TNL_RECORD_META 1
-#define TNL_RECORD_HELLO 2
-#define TNL_RECORD_BLA 3
-
-typedef struct tnl_record {
-       uint16_t type;
-       uint16_t len;
-       char data[];
-} tnl_record_t;
-
-typedef enum tnl_status {
-       TNL_STATUS_DOWN,
-       TNL_STATUS_CONNECTING,
-       TNL_STATUS_HANDSHAKE,
-       TNL_STATUS_UP,
-} tnl_status_t;
-
-typedef struct tnl_ep_credentials {
-       gnutls_credentials_type type;
-       union {
-               gnutls_anon_client_credentials anon_client;
-               gnutls_anon_server_credentials anon_server;
-               gnutls_srp_client_credentials srp_client;
-               gnutls_srp_server_credentials srp_server;
-               gnutls_certificate_credentials certificate;
-       };
-} tnl_ep_credentials_t;                
-
-typedef struct tnl_ep_cryptoparm {
-} tnl_ep_cryptoparm_t;
-
-typedef struct tnl_ep {
-       struct sockaddr_storage address;
-       char *id;
-       char *hostname;
-       struct tnl_ep_credentials cred;
-       struct tnl_ep_cryptoparm parm;
-} tnl_ep_t;
-
-typedef struct tnl {
-       struct tnl_ep local;
-       struct tnl_ep remote;
-       int type;
-       int protocol;
-       int mtu;
-       enum tnl_status status;
-       void *data;
-
-       bool (*send_packet)(struct tnl *tnl, const void *buf, int len);
-       bool (*send_meta)(struct tnl *tnl, const void *buf, int len);
-       bool (*close)(struct tnl *tnl);
-
-       bool (*recv_packet)(struct tnl *tnl, const void *buf, int len);
-       bool (*recv_meta)(struct tnl *tnl, const void *buf, int len);
-       bool (*accept)(struct tnl *tnl);
-       bool (*error)(struct tnl *tnl, int errnum);
-
-       /* private */
-       
-       gnutls_session session;
-       struct fd fd;
-       char buf[4096];
-       int bufread;
-} tnl_t;
-
-typedef struct tnl_listen {
-       struct tnl_ep local;
-       int type;
-       int protocol;
-
-       bool (*accept)(struct tnl *tnl);
-       bool (*close)(struct tnl_listen *listener);
-
-       struct fd fd;
-} tnl_listen_t;
-
-extern bool tnl_listen(struct tnl_listen *listener);
-extern bool tnl_connect(struct tnl *tnl);
-
-extern bool tnl_ep_set_x509_credentials(tnl_ep_t *tnl_ep, const char *key, const char *certificate, const char *trust, const char *crl);
-extern bool tnl_ep_set_openpgp_credentials(tnl_ep_t *tnl_ep, const char *privkey, const char *pubkey, const char *keyring, const char *trustdb);
-
-#endif /* __TNL_H__ */
diff --git a/vnd/Makefile.am b/vnd/Makefile.am
deleted file mode 100644 (file)
index e542298..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-noinst_LIBRARIES = libvnd.a
-
-noinst_HEADERS = vnd.h
-
-libvnd_a_SOURCES = vnd.c
-
diff --git a/vnd/vnd.c b/vnd/vnd.c
deleted file mode 100644 (file)
index 7eba993..0000000
--- a/vnd/vnd.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
-    vnd.c -- virtual network device management
-
-    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
-                  2003-2004 Ivo Timmermans <ivo@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#include "system.h"
-
-#include <linux/if_tun.h>
-
-#include "fd/fd.h"
-#include "logger/logger.h"
-#include "support/xalloc.h"
-
-#include "vnd/vnd.h"
-
-vnd_t *vnd_new(void) {
-       vnd_t *vnd;
-
-       return clear(new(vnd));
-}
-
-void vnd_free(vnd_t *vnd) {
-       replace(vnd->device, NULL);
-       replace(vnd->interface, NULL);
-       replace(vnd->description, NULL);
-       free(vnd);
-}
-
-void vnd_set(vnd_t *vnd, char *device, char *interface, vnd_mode_t mode, vnd_handler_t recv) {
-       replace(vnd->device, device);
-       replace(vnd->interface, interface);
-       vnd->mode = mode;
-       vnd->recv = recv;
-}
-
-static bool vnd_send(vnd_t *vnd, const void *buf, int len) {
-       int result;
-
-       result = write(vnd->fd.fd, buf, len);
-
-       if(result == len || result < 0 && (errno == EINTR || errno == EAGAIN)) {
-               logger(LOG_INFO, _("vnd: wrote packet of %d bytes to %s"), len, vnd->description);
-               return true;
-       }
-
-       logger(LOG_INFO, _("vnd: error writing packet of %d bytes to %s: %s"), len, vnd->description, strerror(errno));
-
-       return false;
-}
-
-static bool vnd_recv_handler(fd_t *fd) {
-       vnd_t *vnd = fd->data;
-       char buf[vnd->mtu];
-       int len;
-
-       vnd = fd->data;
-
-       len = read(fd->fd, buf, sizeof buf);
-
-       if(len > 0) {
-               logger(LOG_INFO, _("vnd: read packet of %d bytes from %s"), len, vnd->description);
-               return vnd->recv(vnd, buf, len);
-       }
-
-       if(len < 0 && (errno == EINTR || errno == EAGAIN))
-               return true;
-
-       logger(LOG_ERR, _("vnd: error reading packet from %s: %s"), vnd->description, strerror(errno));
-
-       return false;
-}
-
-bool vnd_open(vnd_t *vnd) {
-       struct ifreq ifr = {0};
-       
-       if(!vnd->device)
-               vnd->device = xstrdup("/dev/net/tun");
-       
-       vnd->fd.fd = open(vnd->device, O_RDWR | O_NONBLOCK);
-
-       if(vnd->fd.fd < 0) {
-               logger(LOG_ERR, _("vnd: could not open %s: %s"), vnd->device, strerror(errno));
-               return false;
-       }
-
-       if(vnd->mode == VND_MODE_TUN)
-               ifr.ifr_flags = IFF_TUN;
-       else
-               ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
-
-       if(vnd->interface)
-               strncpy(ifr.ifr_name, vnd->interface, IFNAMSIZ);
-
-       if(!ioctl(vnd->fd.fd, TUNSETIFF, &ifr)) {
-               if(vnd->interface)
-                       free(vnd->interface);
-               vnd->interface = xstrdup(ifr.ifr_name);
-       } else {
-               logger(LOG_ERR, _("vnd: %s is not a Linux tun/tap device"), vnd->device);
-               return false;
-       }
-
-       if(!vnd->mtu)
-               vnd->mtu = 1514;
-
-       vnd->send = vnd_send;
-       vnd->fd.read = vnd_recv_handler;
-       vnd->fd.data = vnd;
-
-       if(vnd->description)
-               free(vnd->description);
-
-       asprintf(&vnd->description, "Linux tun/tap device %s (interface %s)", vnd->device, vnd->interface);
-
-       if(!fd_add(&vnd->fd))
-               return false;
-
-       logger(LOG_INFO, _("vnd: opened %s"), vnd->description);
-
-       return true;
-}
-
-bool vnd_close(vnd_t *vnd) {
-       fd_del(&vnd->fd);
-
-       close(vnd->fd.fd);
-
-       logger(LOG_INFO, _("vnd: closed %s"), vnd->description);
-
-       return true;
-}
-
diff --git a/vnd/vnd.h b/vnd/vnd.h
deleted file mode 100644 (file)
index 47f8c6a..0000000
--- a/vnd/vnd.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
-    vnd.c -- virtual network device management
-
-    Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
-                  2003-2004 Ivo Timmermans <ivo@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#ifndef __VND_H__
-#define __VND_H__
-
-typedef enum vnd_mode{
-       VND_MODE_TUN,
-       VND_MODE_TAP,
-} vnd_mode_t;
-
-struct vnd;
-
-typedef bool (*vnd_handler_t)(struct vnd *vnd, const void *buf, int len);
-
-typedef struct vnd {
-       char *device;
-       char *interface;
-       enum vnd_mode mode;
-       int mtu;
-
-       vnd_handler_t recv;
-       vnd_handler_t send;
-
-       /* Private data */
-
-       struct fd fd;
-       char *description;
-} vnd_t;
-
-extern bool vnd_init(void);
-extern bool vnd_exit(void);
-extern struct vnd *vnd_new(void);
-extern void vnd_free(struct vnd *vnd);
-extern void vnd_set(struct vnd *vnd, char *device, char *interface, vnd_mode_t mode, vnd_handler_t recv);
-extern bool vnd_open(struct vnd *vnd);
-extern bool vnd_close(struct vnd *vnd);
-
-#endif /* __VND_H__ */