--- /dev/null
+AUTOMAKE_OPTIONS = gnu
+
+EXTRA_DIST = config.rpath mkinstalldirs system.h depcomp
+
+SUBDIRS = cfg fd logger support tnl vnd
+
+sbin_PROGRAMS = tincd
+
+tincd_SOURCES = tincd.c
+
+tincd_LDADD = cfg/libcfg.a fd/libfd.a logger/liblogger.a support/libsupport.a tnl/libtnl.a vnd/libvnd.a -lgnutls
+
+ACLOCAL_AMFLAGS = -I m4
+
+ChangeLog:
+ svn log > ChangeLog
+
+svn-clean: maintainer-clean
+ svn status --no-ignore | sed -n 's/^[?I] \+//p' | tr '\012' '\0' | xargs -r0 rm -rf
+
+release:
+ rm -f ChangeLog
+ $(MAKE) ChangeLog
+ echo "Please edit the NEWS file now..."
+ /usr/bin/editor NEWS
+ $(MAKE) dist
--- /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
+AC_PREREQ(2.59)
+AC_INIT
+AC_CONFIG_SRCDIR([tincd.c])
+AM_INIT_AUTOMAKE(tinc, 2.0-svn)
+AC_CONFIG_HEADERS([config.h])
+AM_MAINTAINER_MODE
+
+dnl Include the macros from the m4/ directory
+dnl AM_ACLOCAL_INCLUDE(m4)
+
+dnl AM_GNU_GETTEXT([external])
+dnl AM_GNU_GETTEXT_VERSION(0.14.1)
+
+AC_DEFINE([_GNU_SOURCE], 1, [Enable GNU extenstions])
+AC_DEFINE([__USE_BSD], 1, [Enable BSD extensions])
+
+dnl ALL_LINGUAS="nl"
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_PROG_CPP
+AC_PROG_GCC_TRADITIONAL
+AC_PROG_AWK
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+AC_PROG_RANLIB
+
+AC_ISC_POSIX
+
+dnl Check and set OS
+
+AC_CANONICAL_HOST
+
+case $host_os in
+ *linux*)
+ AC_DEFINE(HAVE_LINUX, 1, [Linux])
+ ;;
+ *freebsd*)
+ AC_DEFINE(HAVE_FREEBSD, 1, [FreeBSD])
+ ;;
+ *darwin*)
+ AC_DEFINE(HAVE_DARWIN, 1, [Darwin (MacOS/X)])
+ ;;
+ *solaris*)
+ AC_DEFINE(HAVE_SOLARIS, 1, [Solaris/SunOS])
+ ;;
+ *openbsd*)
+ AC_DEFINE(HAVE_OPENBSD, 1, [OpenBSD])
+ ;;
+ *netbsd*)
+ AC_DEFINE(HAVE_NETBSD, 1, [NetBSD])
+ ;;
+ *cygwin*)
+ AC_DEFINE(HAVE_CYGWIN, 1, [Cygwin])
+ ;;
+ *mingw*)
+ AC_DEFINE(HAVE_MINGW, 1, [MinGW])
+ LIBS="$LIBS -lws2_32"
+ ;;
+ *)
+ AC_MSG_ERROR("Unknown operating system.")
+ ;;
+esac
+
+AC_CACHE_SAVE
+
+if test -d /sw/include ; then
+ CPPFLAGS="$CPPFLAGS -I/sw/include"
+fi
+if test -d /sw/lib ; then
+ LIBS="$LIBS -L/sw/lib"
+fi
+
+dnl Checks for libraries.
+
+dnl Checks for header files.
+dnl We do this in multiple stages, because unlike Linux all the other operating systems really suck and don't include their own dependencies.
+
+AC_HEADER_STDC
+AC_CHECK_HEADERS([stdbool.h syslog.h sys/file.h sys/ioctl.h sys/param.h sys/time.h sys/socket.h sys/wait.h sys/mman.h netdb.h arpa/inet.h])
+AC_CHECK_HEADERS([net/if.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h],
+ [], [],
+ [#ifdef HAVE_SYS_TYPES_H
+ #include <sys/types.h>
+ #endif
+ #ifdef HAVE_NETDB_H
+ #include <netdb.h>
+ #endif
+ #ifdef HAVE_ARPA_INET_H
+ #include <arpa/inet.h>
+ #endif
+ #ifdef HAVE_SYS_SOCKET_H
+ #include <sys/socket.h>
+ #endif
+ ]
+)
+AC_CHECK_HEADERS([netinet/if_ether.h netinet/ip.h netinet/ip6.h],
+ [], [],
+ [#ifdef HAVE_SYS_TYPES_H
+ #include <sys/types.h>
+ #endif
+ #ifdef HAVE_NETDB_H
+ #include <netdb.h>
+ #endif
+ #ifdef HAVE_ARPA_INET_H
+ #include <arpa/inet.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_NETINET_IN6_H
+ #include <netinet/in6.h>
+ #endif
+ #ifdef HAVE_NET_ETHERNET_H
+ #include <net/ethernet.h>
+ #endif
+ #ifdef HAVE_NET_IF_ARP_H
+ #include <net/if_arp.h>
+ #endif
+ ]
+)
+AC_CHECK_HEADERS([netinet/tcp.h netinet/ip_icmp.h netinet/icmp6.h],
+ [], [],
+ [#ifdef HAVE_SYS_TYPES_H
+ #include <sys/types.h>
+ #endif
+ #ifdef HAVE_NETDB_H
+ #include <netdb.h>
+ #endif
+ #ifdef HAVE_ARPA_INET_H
+ #include <arpa/inet.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_NETINET_IP_H
+ #include <netinet/ip.h>
+ #endif
+ #ifdef HAVE_NETINET_IN6_H
+ #include <netinet/in6.h>
+ #endif
+ #ifdef HAVE_NETINET_IP6_H
+ #include <netinet/ip6.h>
+ #endif
+ #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_IF_ETHER_H
+ #include <netinet/if_ether.h>
+ #endif
+ ]
+)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_C_VOLATILE
+AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+AC_HEADER_TIME
+AC_STRUCT_TM
+
+dnl tinc_ATTRIBUTE(__malloc__)
+
+AC_CHECK_TYPES([socklen_t, struct ether_header, struct arphdr, struct ether_arp, struct in_addr, struct addrinfo, struct ip, struct icmp, struct in6_addr, struct sockaddr_in6, struct ip6_hdr, struct icmp6_hdr, struct nd_neighbor_solicit, struct nd_opt_hdr], , ,
+ [#ifdef HAVE_SYS_TYPES_H
+ #include <sys/types.h>
+ #endif
+ #ifdef HAVE_NETDB_H
+ #include <netdb.h>
+ #endif
+ #ifdef HAVE_ARPA_INET_H
+ #include <arpa/inet.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_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_NET_ETHERNET_H
+ #include <net/ethernet.h>
+ #endif
+ #ifdef HAVE_NET_IF_ARP_H
+ #include <net/if_arp.h>
+ #endif
+ #ifdef HAVE_NETINET_IF_ETHER_H
+ #include <netinet/if_ether.h>
+ #endif
+ #ifdef HAVE_NETINET_IP_ICMP_H
+ #include <netinet/ip_icmp.h>
+ #endif
+ #ifdef HAVE_NETINET_ICMP6_H
+ #include <netinet/icmp6.h>
+ #endif
+ ]
+)
+
+dnl Checks for library functions.
+AC_FUNC_MEMCMP
+AC_FUNC_ALLOCA
+AC_TYPE_SIGNAL
+AC_CHECK_FUNCS([asprintf daemon fchmod flock ftime fork get_current_dir_name gettimeofday mlockall putenv random select strdup strerror strsignal strtol system unsetenv vsyslog])
+dnl jm_FUNC_MALLOC
+dnl jm_FUNC_REALLOC
+
+dnl Support for SunOS
+
+AC_CHECK_FUNC(socket, [], [
+ AC_CHECK_LIB(socket, connect)
+])
+AC_CHECK_FUNC(gethostbyname, [], [
+ AC_CHECK_LIB(nsl, gethostbyname)
+])
+
+AC_CHECK_FUNCS([freeaddrinfo gai_strerror getaddrinfo getnameinfo inet_aton])
+
+AC_CACHE_SAVE
+
+dnl These are defined in files in m4/
+
+dnl case $host_os in
+dnl *linux*)
+dnl tinc_TUNTAP
+dnl ;;
+dnl esac
+
+dnl tinc_OPENSSL
+dnl tinc_ZLIB
+dnl tinc_LZO
+
+AM_PATH_LIBGNUTLS([1.0.4], [], [AC_MSG_ERROR([GNUTLS library not found.]); break])
+
+dnl Check if support for jumbograms is requested
+dnl AC_ARG_ENABLE(jumbograms,
+dnl AS_HELP_STRING(--enable-jumbograms,enable support for jumbograms (packets up to 9000 bytes)),
+dnl [ AC_DEFINE(ENABLE_JUMBOGRAMS, 1, [Support for jumbograms (packets up to 9000 bytes)]) ]
+dnl )
+
+dnl Check if checkpoint tracing has to be enabled
+dnl AC_ARG_ENABLE(tracing,
+dnl AS_HELP_STRING(--enable-tracing,enable checkpoint tracing (debugging only)),
+dnl [ AC_DEFINE(ENABLE_TRACING, 1, [Checkpoint tracing]) ]
+dnl )
+
+dnl AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile doc/tincd.8 doc/tinc.conf.5 doc/tincinclude.texi lib/Makefile po/Makefile.in m4/Makefile])
+AC_CONFIG_FILES([Makefile cfg/Makefile fd/Makefile logger/Makefile rt/Makefile support/Makefile tnl/Makefile vnd/Makefile])
+
+AC_OUTPUT
--- /dev/null
+noinst_LIBRARIES = libfd.a
+
+noinst_HEADERS = event.h fd.h
+
+libfd_a_SOURCES = event.c fd.c
+
--- /dev/null
+/*
+ event.c -- event queue
+
+ 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 "support/avl.h"
+#include "support/xalloc.h"
+#include "fd/event.h"
+
+avl_tree_t *events;
+
+static event_id_t id;
+
+static int timevalcmp(struct timeval a, struct timeval b) {
+ return a.tv_sec - b.tv_sec ?: a.tv_usec - b.tv_usec;
+}
+
+static int event_compare(const event_t *a, const event_t *b) {
+ return timevalcmp(a->tv, b->tv) ?: a->id - b->id;
+}
+
+bool event_init(void) {
+ events = avl_tree_new((avl_compare_t)event_compare, (avl_action_t)event_free);
+
+ return true;
+}
+
+bool event_exit(void) {
+ avl_tree_del(events);
+
+ return true;
+}
+
+event_t *event_new(void) {
+ event_t *event;
+
+ return clear(new(event));
+}
+
+void event_free(event_t *event) {
+ free(event);
+}
+
+void event_set(event_t *event, struct timeval timeout, event_handler_t handler, void *data) {
+ gettimeofday(&event->tv, NULL);
+ event_update(event, timeout);
+ event->interval = timeout;
+ event->handler = handler;
+ event->data = data;
+}
+
+void event_update(event_t *event, struct timeval timeout) {
+ event->tv.tv_sec += timeout.tv_sec;
+ event->tv.tv_usec += timeout.tv_usec;
+ event->tv.tv_sec += event->tv.tv_usec / 1000000;
+ event->tv.tv_usec %= 1000000;
+}
+
+bool event_add(event_t *event) {
+ event->id = ++id;
+ return avl_add(events, event);
+}
+
+bool event_del(event_t *event) {
+ return avl_del(events, event);
+}
+
+void event_handle(void) {
+ struct timeval now;
+ event_t *event;
+ avl_node_t *avl;
+
+ gettimeofday(&now, NULL);
+
+ avl_foreach_node(events, avl, {
+ event = avl->data;
+
+ if(timercmp(&event->tv, &now, <)) {
+ avl_unlink_node(events, avl);
+ if(event->handler(event))
+ avl_add_node(events, avl);
+ else
+ avl_node_free(events, avl);
+ } else {
+ break;
+ }
+ });
+}
+
+struct timeval event_timeout(void) {
+ struct timeval tv, now;
+ event_t *event;
+
+ gettimeofday(&now, NULL);
+
+ if(events->head) {
+ event = events->head->data;
+
+ tv.tv_sec = event->tv.tv_sec - now.tv_sec;
+ tv.tv_usec = event->tv.tv_usec - now.tv_usec;
+
+ if(tv.tv_usec < 0) {
+ tv.tv_usec += 1e6;
+ tv.tv_sec--;
+ }
+
+ if(tv.tv_sec < 0) {
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ }
+ } else {
+ tv.tv_sec = -1;
+ tv.tv_usec = -1;
+ }
+
+ return tv;
+}
--- /dev/null
+/*
+ event.h -- event queue
+
+ 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 __EVENT_H__
+#define __EVENT_H__
+
+typedef int event_id_t;
+
+struct event;
+
+typedef bool (*event_handler_t)(struct event *event);
+
+typedef struct event {
+ struct timeval tv;
+ struct timeval interval;
+ event_id_t id;
+ event_handler_t handler;
+ void *data;
+} event_t;
+
+extern bool event_init(void);
+extern bool event_exit(void);
+extern bool event_add(struct event *event);
+extern bool event_del(struct event *event);
+extern struct event *event_new(void);
+extern void event_free(struct event *);
+extern void event_set(struct event *, struct timeval, event_handler_t, void *);
+extern void event_update(struct event *, struct timeval);
+extern void event_handle(void);
+extern struct timeval event_timeout(void);
+
+#endif /* __EVENT_H__ */
--- /dev/null
+/*
+ fd.c -- I/O and event multiplexing
+
+ 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 "support/avl.h"
+#include "support/xalloc.h"
+#include "fd/event.h"
+#include "fd/fd.h"
+
+static fd_set fd_sets[FD_MODES];
+static int max_fd;
+static avl_tree_t *fds;
+
+volatile bool fd_running = false;
+
+int fd_compare(struct fd *a, struct fd *b) {
+ return (a->fd - b->fd) ?: (a->mode - b->mode);
+};
+
+bool fd_init(void) {
+ int i;
+
+ for(i = 0; i < FD_MODES; i++)
+ FD_ZERO(&fd_sets[i]);
+
+ fds = avl_tree_new((avl_compare_t)fd_compare, NULL);
+
+ event_init();
+}
+
+bool fd_exit(void) {
+ event_exit();
+
+ avl_tree_del(fds);
+}
+
+bool fd_add(struct fd *fd) {
+ if(!avl_add(fds, fd))
+ return false;
+
+ FD_SET(fd->fd, &fd_sets[fd->mode]);
+
+ if(fd->fd > max_fd)
+ max_fd = fd->fd;
+
+ return true;
+};
+
+bool fd_del(struct fd *fd) {
+ FD_CLR(fd->fd, &fd_sets[fd->mode]);
+
+ if(fd->fd >= max_fd)
+ max_fd = ((struct fd *)fds->tail)->fd;
+
+ return avl_del(fds, fd);
+};
+
+bool fd_run(void) {
+ struct timeval tv;
+ int result;
+ fd_set fd_cur[FD_MODES];
+
+ fd_running = true;
+
+ logger(LOG_INFO, "fd: running");
+
+ while(fd_running) {
+ memcpy(fd_cur, fd_sets, sizeof(fd_cur));
+ tv = event_timeout();
+
+ result = select(max_fd + 1, &fd_cur[0], &fd_cur[1], &fd_cur[2], tv.tv_sec >= 0 ? &tv : NULL);
+
+ if(result < 0) {
+ if(errno != EINTR && errno != EAGAIN) {
+ logger(LOG_ERR, _("fd: error while waiting for input: %s"), strerror(errno));
+ return false;
+ }
+
+ continue;
+ }
+
+ if(result) {
+ struct fd *fd;
+
+ avl_foreach(fds, fd, {
+ if(FD_ISSET(fd->fd, &fd_cur[fd->mode]))
+ fd->handler(fd);
+ });
+ } else {
+ event_handle();
+ }
+ }
+
+ logger(LOG_INFO, "fd: stopping");
+
+ return true;
+}
+
+void fd_stop(void) {
+ fd_running = false;
+}
--- /dev/null
+/*
+ fd.h -- I/O and event multiplexing
+
+ 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 __FD_H__
+#define __FD_H__
+
+enum fd_mode {
+ FD_MODE_READ = 0,
+ FD_MODE_WRITE,
+ FD_MODE_EXCEPT,
+ FD_MODES,
+} fd_mode_t;
+
+struct fd;
+
+typedef bool (*fd_handler_t)(struct fd *);
+
+typedef struct fd {
+ int fd;
+ enum fd_mode mode;
+ fd_handler_t handler;
+ void *data;
+} fd_t;
+
+extern bool fd_init(void);
+extern bool fd_exit(void);
+extern bool fd_add(struct fd *fd);
+extern bool fd_del(struct fd *fd);
+extern bool fd_run(void);
+extern void fd_stop(void);
+
+#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)));
+
+#endif
--- /dev/null
+noinst_LIBRARIES = librt.a
+
+noinst_HEADERS = edge.h graph.h node.h rt.h subnet.h
+
+librt_a_SOURCES = edge.c graph.c node.c rt.c subnet.c
+
--- /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"
+
+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;
+
+ 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.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) {
+ 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;
+ }
+
+ 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_OPTIONS_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
+/*
+ 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;
+
+static bool rt_tnl_accept(tnl_t *t) {
+}
+
+static bool rt_vnd_recv(vnd_t *vnd, const char *buf, int len) {
+ route(myself, buf, len);
+}
+
+static bool rt_tnl_recv_packet(tnl_t *tnl, const char *buf, int len) {
+ route(tnl->data, buf, len);
+}
+
+static bool rt_tnl_recv_meta(tnl_t *tnl, const char *buf, int len) {
+ //route(tnl->data, buf, len);
+}
+
+static void rt_outgoing(char *wft) {
+}
+
+static void route(node_t *node, char *buf, int len) {
+}
+
+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;
+
+ /* 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 */
+
+ if(!cfg_get_string(tinc_cfg, "Device", "/dev/net/tun", &rt_vnd->device)
+ || !cfg_get_string(tinc_cfg, "Interface", tinc_netname, &rt_vnd->interface)
+ || !cfg_get_choice(tinc_cfg, "Mode", mode_choice, RT_MODE_ROUTER, rt_mode)) {
+ vnd_free(rt_vnd);
+ return false;
+ }
+
+ 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;
+ // listener->local.cred = ...;
+
+ 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 "tnl/tnl.h"
+#include "vnd/vnd.h"
+
+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_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
+noinst_LIBRARIES = libsupport.a
+
+noinst_HEADERS = avl.h ipv4.h ipv6.h sockaddr.h xalloc.h
+
+libsupport_a_SOURCES = avl.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;
+
+#if 0
+ for(node = tree->root; node; node = next) {
+ next = node->next;
+ avl_free_node(tree, node);
+ }
+#endif
+ avl_foreach_node(tree, node, avl_node_free(tree, node));
+
+ avl_tree_free(tree);
+}
+
+/* Tree walking */
+
+#if 0
+void avl_foreach(avl_tree_t *tree, avl_action_t action) {
+ avl_node_t *node, *next;
+
+ for(node = tree->head; node; node = next) {
+ next = node->next;
+ action(node->data);
+ }
+}
+
+void avl_foreach_node(avl_tree_t *tree, avl_node_action_t action) {
+ avl_node_t *node, *next;
+
+ for(node = tree->head; node; node = next) {
+ next = node->next;
+ action(node);
+ }
+}
+#endif
+
+/* 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; \
+ } \
+}
+
+#if 0
+extern void avl_foreach(struct avl_tree *, avl_action_t);
+extern void avl_foreach_node(struct avl_tree *, avl_node_action_t);
+#endif
+
+/* 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
+/*
+ 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
+/*
+ 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 */
+
+#if 0
+
+#include "gettext.h"
+
+#ifndef HAVE_STRSIGNAL
+# define strsignal(p) ""
+#endif
+
+/* Other functions */
+
+#include "dropin.h"
+
+#endif
+
+#define _(a) a
+
+#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 "cfg/cfg.h"
+#include "fd/event.h"
+#include "fd/fd.h"
+#include "logger/logger.h"
+#include "support/avl.h"
+#include "support/sockaddr.h"
+#include "support/xalloc.h"
+#include "tnl/tnl.h"
+#include "vnd/vnd.h"
+
+static bool vnd_recv(struct vnd *vnd, char *buf, int len) {
+ static int p = 0;
+ char b[4];
+ logger(LOG_DEBUG, _("Read packet of %d bytes from vnd %p"), len, vnd);
+ memcpy(b, buf + 16, 4);
+ memcpy(buf + 16, buf + 20, 4);
+ memcpy(buf + 20, b, 4);
+ vnd->send(vnd, buf, len);
+ return true;
+}
+
+static bool vnd_stop(event_t *event) {
+ static int i = 0;
+
+ logger(LOG_DEBUG, "i = %d", i++);
+
+ if(i > 5) {
+ fd_stop();
+ return false;
+ }
+
+ event_update(event, event->interval);
+ return true;
+}
+
+int test(int argc, char **argv) {
+ vnd_t *vnd;
+ event_t *stop;
+ tnl_listen_t *listener;
+
+ //vnd_init();
+ if(fd_init() && tnl_init()) {
+ vnd = vnd_new();
+ vnd_set(vnd, "/dev/tun", "test", VND_MODE_TUN, vnd_recv);
+
+ stop = event_new();
+ event_set(stop, (struct timeval){5, 0}, vnd_stop, NULL);
+ event_add(stop);
+
+ clear(new(listener));
+ listener->type = SOCK_STREAM;
+ listener->protocol = IPPROTO_TCP;
+ sa(&listener->local.address)->sa_family = AF_INET;
+
+ if(tnl_listen(listener) && vnd_open(vnd)) {
+ fd_run();
+ vnd_close(vnd);
+ listener->close(listener);
+ }
+
+ vnd_free(vnd);
+
+ tnl_exit();
+ fd_exit();
+ }
+ //vnd_exit();
+}
+
+avl_tree_t *tinc_cfg = NULL;
+char *tinc_netname = NULL;
+
+int main(int argc, char **argv) {
+ tnl_listen_t *listener;
+
+ logger_init("tinc", LOGGER_MODE_STDERR);
+
+ tinc_cfg = cfg_tree_new();
+
+ if(!cfg_read_file(tinc_cfg, "tinc.conf"))
+ return 1;
+
+ if(fd_init() && tnl_init()) {
+ clear(new(listener));
+ listener->type = SOCK_STREAM;
+ listener->protocol = IPPROTO_TCP;
+ sa(&listener->local.address)->sa_family = AF_INET;
+ ((struct sockaddr_in *) &listener->local.address)->sin_port = htons(655);
+ if(tnl_listen(listener)) {
+ fd_run();
+ listener->close(listener);
+ }
+ tnl_exit() && fd_exit();
+ }
+
+ return 0;
+}
+
--- /dev/null
+noinst_LIBRARIES = libtnl.a
+
+noinst_HEADERS = tnl.h
+
+libtnl_a_SOURCES = tnl.c
+
--- /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 "support/avl.h"
+#include "support/sockaddr.h"
+#include "support/xalloc.h"
+#include "tnl/tnl.h"
+
+static avl_tree_t *tnls, *listeners;
+
+bool tnl_init(void) {
+ tnls = avl_tree_new(NULL, (avl_action_t)free);
+ listeners = avl_tree_new(NULL, (avl_action_t)free);
+
+ return true;
+}
+
+bool tnl_exit(void) {
+ avl_tree_del(listeners);
+ avl_tree_del(tnls);
+
+ return true;
+}
+
+#define tnl_add(t) avl_add(tnls, t)
+#define tnl_del(t) avl_del(tnls, t)
+#define tnl_listen_add(l) avl_add(listeners, l)
+#define tnl_listen_del(l) avl_del(listeners, l)
+
+static bool tnl_send(tnl_t *tnl, const char *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"));
+
+ tnl->error(tnl, result);
+ tnl->close(tnl);
+ return !result;
+ }
+
+ buf += result;
+ len -= result;
+ }
+
+ return true;
+}
+
+static bool tnl_recv(tnl_t *tnl) {
+ int result;
+ tnl_record_t *record = (tnl_record_t *)tnl->buf;
+
+ 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"));
+
+ tnl->error(tnl, result);
+ tnl->close(tnl);
+ return !result;
+ }
+
+ tnl->bufread += result;
+
+ while(tnl->bufread >= sizeof *record && tnl->bufread - sizeof *record >= record->len) {
+ switch(record->type) {
+ case TNL_RECORD_META:
+ tnl->recv_meta(tnl, record->data, record->len);
+ break;
+
+ case TNL_RECORD_PACKET:
+ tnl->recv_packet(tnl, record->data, record->len);
+ break;
+
+ default:
+ logger(LOG_ERR, _("tnl: error while receiving: %s"), _("unknown record type"));
+ tnl->error(tnl, EINVAL);
+ tnl->close(tnl);
+ return false;
+ }
+
+ tnl->bufread -= sizeof *record + record->len;
+ memmove(tnl->buf, record->data + record->len, tnl->bufread);
+ }
+}
+
+static bool tnl_recv_handler(fd_t *fd) {
+ 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(gnutls_error_is_fatal(result)) {
+ logger(LOG_DEBUG, _("tnl: reception failed: %s\n"), gnutls_strerror(result));
+ tnl->error(tnl, result);
+ tnl->close(tnl);
+ return false;
+ }
+
+ return true;
+ }
+
+ tnl->bufread += result;
+ return tnl_recv(tnl);
+}
+
+static bool tnl_handshake_handler(fd_t *fd) {
+ 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\n", gnutls_strerror(result));
+ tnl->close(tnl);
+ return false;
+ }
+
+ /* check other stuff? */
+ return true;
+ }
+
+ logger(LOG_DEBUG, _("tnl: handshake finished"));
+
+ result = gnutls_certificate_verify_peers(tnl->session);
+ if(result < 0) {
+ logger(LOG_ERR, "tnl: certificate error: %s\n", gnutls_strerror(result));
+ tnl->close(tnl);
+ return false;
+ }
+
+ if(result) {
+ logger(LOG_ERR, "tnl: certificate not good, verification result %x", result);
+ tnl->close(tnl);
+ return false;
+ }
+
+ tnl->status == TNL_STATUS_UP;
+ tnl->fd.handler = tnl_recv_handler;
+ tnl->accept(tnl);
+ return true;
+}
+
+static bool tnl_send_meta(tnl_t *tnl, const char *buf, int len) {
+ tnl_record_t record = {
+ .type = TNL_RECORD_META,
+ .len = len,
+ };
+
+ return tnl_send(tnl, (char *)&record, sizeof(record)) && tnl_send(tnl, buf, len);
+}
+
+static bool tnl_send_packet(tnl_t *tnl, const char *buf, int len) {
+ tnl_record_t record = {
+ .type = TNL_RECORD_PACKET,
+ .len = len,
+ };
+
+ return tnl_send(tnl, (char *)&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);
+
+ tnl_del(tnl);
+
+ return true;
+}
+
+static bool tnl_accept_error(tnl_t *tnl, int errnum) {
+ logger(LOG_ERR, _("tnl: error %d on accepted tunnel"));
+ 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;
+ }
+
+ logger(LOG_DEBUG, _("tnl: accepted incoming connection"));
+
+ sa_unmap(&ss);
+
+ 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->status = TNL_STATUS_CONNECTING;
+ tnl->error = tnl_accept_error;
+ tnl->close = tnl_close;
+
+ tnl->fd.fd = sock;
+ tnl->fd.mode = FD_MODE_READ;
+ tnl->fd.handler = tnl_handshake_handler;
+ tnl->fd.data = tnl;
+
+ fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK);
+
+ tnl_add(tnl);
+
+ 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, GNUTLS_CRD_CERTIFICATE, tnl->local.cred);
+ gnutls_certificate_server_set_request(tnl->session, GNUTLS_CERT_REQUEST);
+ gnutls_transport_set_ptr(tnl->session, (gnutls_transport_ptr)sock);
+ gnutls_handshake(tnl->session);
+
+ tnl->accept = listener->accept;
+
+ fd_add(&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));
+ tnl->error(tnl, result);
+ tnl->close(tnl);
+ return false;
+ }
+
+ fd_del(&tnl->fd);
+
+ 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, GNUTLS_CRD_CERTIFICATE, tnl->local.cred);
+ gnutls_certificate_server_set_request(tnl->session, GNUTLS_CERT_REQUEST);
+ gnutls_transport_set_ptr(tnl->session, (gnutls_transport_ptr)fd->fd);
+ gnutls_handshake(tnl->session);
+
+ tnl->fd.mode = FD_MODE_READ;
+ tnl->fd.handler = tnl_handshake_handler;
+ fd_add(&tnl->fd);
+
+ logger(LOG_DEBUG, _("tnl: connected"));
+
+ 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.mode = FD_MODE_WRITE;
+ tnl->fd.handler = tnl_connect_handler;
+ tnl->fd.data = tnl;
+
+ tnl->send_packet = tnl_send_packet;
+ tnl->send_meta = tnl_send_meta;
+ tnl->close = tnl_close;
+
+ tnl_add(tnl);
+
+
+ fd_add(&tnl->fd);
+
+ return true;
+}
+
+static bool tnl_listen_close(tnl_listen_t *listener) {
+ fd_del(&listener->fd);
+ close(listener->fd.fd);
+ tnl_listen_del(listener);
+ 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.mode = FD_MODE_READ;
+ listener->fd.handler = tnl_accept_handler;
+ listener->fd.data = listener;
+ listener->close = tnl_listen_close;
+
+ tnl_listen_add(listener);
+ 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 "fd/fd.h"
+
+#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 {
+ struct sockaddr_storage address;
+ struct tnl_ep_identity *id;
+ 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 char *buf, int len);
+ bool (*send_meta)(struct tnl *tnl, const char *buf, int len);
+ bool (*close)(struct tnl *tnl);
+
+ bool (*recv_packet)(struct tnl *tnl, const char *buf, int len);
+ bool (*recv_meta)(struct tnl *tnl, const char *buf, int len);
+ bool (*accept)(struct tnl *tnl);
+ bool (*error)(struct tnl *tnl, int errnum);
+
+ /* private */
+
+ struct fd fd;
+ gnutls_session session;
+ 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_init(void);
+extern bool tnl_exit(void);
+extern bool tnl_listen(struct tnl_listen *listener);
+extern bool tnl_connect(struct tnl *tnl);
+
+extern bool tnl_credentials_sprint(const char *buf, int len, const struct tnl_ep_credentials *cred);
+extern bool tnl_credentials_sscan(const char *buf, struct tnl_ep_credentials *cred);
+extern bool tnl_cryptoparm_sprint(const char *buf, int len, const struct tnl_ep_cryptoparm *parm);
+extern bool tnl_cryptoparm_sscan(const char *buf, struct tnl_ep_cryptoparm *parm);
+extern bool tnl_credentials_fprint(FILE *stream, const struct tnl_ep_credentials *cred);
+extern bool tnl_credentials_fscan(FILE *stream, struct tnl_ep_credentials *cred);
+
+#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, char *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.mode = FD_MODE_READ;
+ vnd->fd.handler = 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, char *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__ */