+++ /dev/null
-noinst_LIBRARIES = libcfg.a
-
-noinst_HEADERS = cfg.h
-
-libcfg_a_SOURCES = cfg.c
-
+++ /dev/null
-/*
- 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;
-}
+++ /dev/null
-/*
- 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
+++ /dev/null
-noinst_LIBRARIES = liblogger.a
-
-noinst_HEADERS = logger.h
-
-liblogger_a_SOURCES = logger.c
-
+++ /dev/null
-/*
- 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__ */
+++ /dev/null
-/*
- 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);
-}
-
-
+++ /dev/null
-/*
- 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
+++ /dev/null
-/*
- 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
-}
+++ /dev/null
-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
-
+++ /dev/null
-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.
-
+++ /dev/null
-/*
- 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);
-}
-
+++ /dev/null
-/*
- 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
+++ /dev/null
-/*
- 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();
-}
+++ /dev/null
-/*
- 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__ */
+++ /dev/null
-/*
- 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);
-}
-
+++ /dev/null
-/*
- 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
+++ /dev/null
-/*
- 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;
- }
-}
+++ /dev/null
-/*
- 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
+++ /dev/null
-/*
- 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"));
-}
-
-
+++ /dev/null
-/*
- 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
+++ /dev/null
-/*
- 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;
-}
+++ /dev/null
-/*
- 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
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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);
+}
+
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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
--- /dev/null
+/* 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 */
--- /dev/null
+/*
+ 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();
+}
--- /dev/null
+/*
+ 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__ */
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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);
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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__ */
--- /dev/null
+/*
+ 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);
+}
+
+
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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);
+}
+
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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
+}
--- /dev/null
+/*
+ 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;
+ }
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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"));
+}
+
+
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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__ */
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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__ */
--- /dev/null
+/*
+ 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;
+}
+
--- /dev/null
+/*
+ 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__ */
--- /dev/null
+/*
+ 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;
+}
+
--- /dev/null
+/*
+ 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
+++ /dev/null
-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
-
+++ /dev/null
-/*
- 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
+++ /dev/null
-/*
- 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
+++ /dev/null
-/*
- 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
+++ /dev/null
-/* 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 */
+++ /dev/null
-/*
- 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
+++ /dev/null
-/*
- 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
+++ /dev/null
-/*
- 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);
-}
+++ /dev/null
-/*
- 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
+++ /dev/null
-/*
- 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
+++ /dev/null
-/*
- 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;
-}
-
+++ /dev/null
-/*
- 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
+++ /dev/null
-/*
- 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__ */
+++ /dev/null
-/*
- 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;
-}
+++ /dev/null
-/*
- 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
+++ /dev/null
-noinst_LIBRARIES = libtnl.a
-
-noinst_HEADERS = tnl.h
-
-libtnl_a_SOURCES = tnl.c
-
+++ /dev/null
-/*
- 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;
-}
+++ /dev/null
-/*
- 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;
-}
+++ /dev/null
-/*
- 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__ */
+++ /dev/null
-noinst_LIBRARIES = libvnd.a
-
-noinst_HEADERS = vnd.h
-
-libvnd_a_SOURCES = vnd.c
-
+++ /dev/null
-/*
- 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;
-}
-
+++ /dev/null
-/*
- 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__ */