From 04d33be4bd102de67bb6dba5c449e12fea0db4d2 Mon Sep 17 00:00:00 2001 From: Ivo Timmermans Date: Sun, 28 Apr 2002 12:46:26 +0000 Subject: [PATCH] Moving files, first attempt at gcrypt compatibility, more interface abstraction --- acconfig.h | 14 + configure.in | 51 +- lib/Makefile.am | 8 +- lib/conf.c | 269 +++++ lib/conf.h | 65 ++ lib/connection.c | 126 +++ lib/connection.h | 141 +++ {src => lib}/edge.c | 3 +- {src => lib}/edge.h | 6 +- {src => lib}/logging.c | 2 +- {src => lib}/logging.h | 4 +- {src => lib}/net.h | 2 +- {src => lib}/netutl.c | 2 +- {src => lib}/netutl.h | 2 +- lib/node.c | 188 ++++ {src => lib}/node.h | 20 +- {src => lib}/subnet.c | 9 +- {src => lib}/subnet.h | 4 +- m4/openssl.m4 | 2 + po/POTFILES.in | 1 + po/nl.po | 320 ++++-- src/Makefile.am | 14 +- src/graph.c | 4 +- src/meta.c | 12 +- src/net.c | 4 +- src/net_packet.c | 47 +- src/net_setup.c | 123 ++- src/pokey/Makefile.am | 14 +- src/pokey/array.c | 45 + src/pokey/array.h | 18 + src/{ => pokey}/conf.h | 3 +- src/{ => pokey}/connection.h | 3 +- src/pokey/device.h | 36 + src/pokey/event.c | 110 ++ src/pokey/event.h | 48 + src/pokey/graph.c | 283 +++++ src/pokey/graph.h | 30 + src/pokey/interface.c | 647 ++++++++--- src/pokey/interface.h | 31 +- src/pokey/logging.c | 103 ++ src/pokey/meta.c | 190 ++++ src/pokey/meta.h | 32 + src/pokey/net.c | 467 ++++++++ src/pokey/net.h | 153 +++ src/pokey/net_packet.c | 429 ++++++++ src/pokey/net_setup.c | 546 +++++++++ src/pokey/net_socket.c | 491 +++++++++ src/pokey/netutl.c | 250 +++++ src/pokey/netutl.h | 46 + src/pokey/pokey.c | 23 +- src/pokey/pokey.glade | 2013 ++++++++++++++++++++++++++++++---- src/pokey/pokey2.xpm | 56 + src/pokey/process.c | 469 ++++++++ src/pokey/process.h | 36 + src/pokey/protocol.c | 245 +++++ src/pokey/protocol.h | 120 ++ src/pokey/protocol_auth.c | 609 ++++++++++ src/pokey/protocol_edge.c | 311 ++++++ src/pokey/protocol_key.c | 285 +++++ src/pokey/protocol_misc.c | 182 +++ src/pokey/protocol_subnet.c | 238 ++++ src/pokey/route.c | 377 +++++++ src/pokey/route.h | 41 + src/protocol.h | 12 +- src/protocol_auth.c | 49 +- src/protocol_key.c | 12 +- src/read_conf.c | 411 +++++++ src/read_conf.h | 31 + src/tincd.c | 12 +- 69 files changed, 10456 insertions(+), 494 deletions(-) create mode 100644 lib/conf.c create mode 100644 lib/conf.h create mode 100644 lib/connection.c create mode 100644 lib/connection.h rename {src => lib}/edge.c (98%) rename {src => lib}/edge.h (91%) rename {src => lib}/logging.c (97%) rename {src => lib}/logging.h (96%) rename {src => lib}/net.h (98%) rename {src => lib}/netutl.c (98%) rename {src => lib}/netutl.h (96%) create mode 100644 lib/node.c rename {src => lib}/node.h (90%) rename {src => lib}/subnet.c (98%) rename {src => lib}/subnet.h (95%) create mode 100644 src/pokey/array.c create mode 100644 src/pokey/array.h rename src/{ => pokey}/conf.h (96%) rename src/{ => pokey}/connection.h (97%) create mode 100644 src/pokey/device.h create mode 100644 src/pokey/event.c create mode 100644 src/pokey/event.h create mode 100644 src/pokey/graph.c create mode 100644 src/pokey/graph.h create mode 100644 src/pokey/logging.c create mode 100644 src/pokey/meta.c create mode 100644 src/pokey/meta.h create mode 100644 src/pokey/net.c create mode 100644 src/pokey/net.h create mode 100644 src/pokey/net_packet.c create mode 100644 src/pokey/net_setup.c create mode 100644 src/pokey/net_socket.c create mode 100644 src/pokey/netutl.c create mode 100644 src/pokey/netutl.h create mode 100644 src/pokey/pokey2.xpm create mode 100644 src/pokey/process.c create mode 100644 src/pokey/process.h create mode 100644 src/pokey/protocol.c create mode 100644 src/pokey/protocol.h create mode 100644 src/pokey/protocol_auth.c create mode 100644 src/pokey/protocol_edge.c create mode 100644 src/pokey/protocol_key.c create mode 100644 src/pokey/protocol_misc.c create mode 100644 src/pokey/protocol_subnet.c create mode 100644 src/pokey/route.c create mode 100644 src/pokey/route.h create mode 100644 src/read_conf.c create mode 100644 src/read_conf.h diff --git a/acconfig.h b/acconfig.h index 41fdb995..ff033262 100644 --- a/acconfig.h +++ b/acconfig.h @@ -75,3 +75,17 @@ /* Define to enable use of old SSLeay_add_all_algorithms() function */ #undef HAVE_SSLEAY_ADD_ALL_ALGORITHMS + +/* Define to 1 if you want to include GCRYPT support */ +#undef USE_GCRYPT + +/* Define to 1 if you want to include OpenSSL support */ +#undef USE_OPENSSL + +#if defined(USE_GCRYPT) && defined(USE_OPENSSL) +# error You can only define one of USE_GCRYPT and USE_OPENSSL +#endif + +#if !defined(USE_GCRYPT) && !defined(USE_OPENSSL) +# error You must define exactly one of USE_GCRYPT and USE_OPENSSL +#endif diff --git a/configure.in b/configure.in index 6a308604..1073df9e 100644 --- a/configure.in +++ b/configure.in @@ -1,6 +1,6 @@ dnl Process this file with autoconf to produce a configure script. -dnl $Id: configure.in,v 1.18 2002/04/11 20:17:33 zarq Exp $ +dnl $Id: configure.in,v 1.19 2002/04/28 12:46:25 zarq Exp $ AC_INIT(src/tincd.c) AM_INIT_AUTOMAKE(tinc, 1.0-cvs) @@ -97,8 +97,53 @@ AC_CACHE_SAVE dnl These are defined in files in m4/ tinc_TUNTAP -tinc_OPENSSL -tinc_ZLIB + + use_gcrypt=0 + use_openssl=0 + + AC_ARG_WITH(gcrypt, + [ --with-gcrypt Use GCRYPT for all cryptographic functions], + [ + if test "x$withval" = "xyes" ; then + use_gcrypt=1 + else + use_gcrypt=0 + fi + ], + [use_gcrypt=0]) + + AC_ARG_WITH(openssl, + [ --with-openssl Use OpenSSL for all cryptographic functions], + [ + if test "x$withval" = "xyes" ; then + use_openssl=1 + else + use_openssl=0 + fi + ], + [use_openssl=0]) + + if test \( $use_gcrypt -eq 0 -a $use_openssl -eq 0 \) \ + -o \( $use_gcrypt -eq 1 -a $use_openssl -eq 1 \) ; then + cat << EOM +Error: You must select exactly one of GCRYPT or OpenSSL. +EOM + echo use_openssl=$use_openssl, use_gcrypt=$use_gcrypt + exit 1 + fi + + if test $use_gcrypt -eq 1 ; then + AC_MSG_RESULT([Selecting GCRYPT for crypto]) + tinc_GCRYPT + AC_DEFINE(USE_GCRYPT) + fi + if test $use_openssl -eq 1 ; then + AC_MSG_RESULT([Selecting OpenSSL for crypto]) + tinc_OPENSSL + AC_DEFINE(USE_OPENSSL) + fi + + tinc_ZLIB dnl Check if support for jumbograms is requested AC_ARG_ENABLE(jumbograms, diff --git a/lib/Makefile.am b/lib/Makefile.am index 03483ddf..c49b613d 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,15 +1,17 @@ ## Process this file with automake to produce Makefile.in -# $Id: Makefile.am,v 1.6 2002/04/13 11:23:19 zarq Exp $ +# $Id: Makefile.am,v 1.7 2002/04/28 12:46:25 zarq Exp $ noinst_LIBRARIES = libtinc.a INCLUDES = @INCLUDES@ -I. -I$(top_builddir) -I$(top_srcdir)/intl -libtinc_a_SOURCES = xmalloc.c pidfile.c utils.c getopt.c getopt1.c list.c avl_tree.c dropin.c +libtinc_a_SOURCES = xmalloc.c pidfile.c utils.c getopt.c getopt1.c \ + list.c avl_tree.c hooks.c dropin.c edge.c conf.c netutl.c logging.c connection.c subnet.c node.c libtinc_a_LIBADD = @LIBOBJS@ @ALLOCA@ libtinc_a_DEPENDENCIES = $(libvpn_a_LIBADD) -noinst_HEADERS = xalloc.h pidfile.h utils.h getopt.h list.h avl_tree.h dropin.h +noinst_HEADERS = xalloc.h pidfile.h utils.h getopt.h list.h avl_tree.h \ + hooks.h dropin.h edge.h net.h conf.h netutl.h logging.h connection.h subnet.h node.h EXTRA_DIST = README diff --git a/lib/conf.c b/lib/conf.c new file mode 100644 index 00000000..c3b55223 --- /dev/null +++ b/lib/conf.c @@ -0,0 +1,269 @@ +/* + conf.c -- configuration storage & retrieval code + Copyright (C) 1998 Robert van der Meulen + 1998-2002 Ivo Timmermans + 2000-2002 Guus Sliepen + 2000 Cris van Pelt + + 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: conf.c,v 1.1 2002/04/28 12:46:25 zarq Exp $ +*/ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include /* for cp */ +#include + +#include "conf.h" +#include "netutl.h" /* for str2address */ +#include "logging.h" + +#include "system.h" + +avl_tree_t *config_tree; + +int pingtimeout = 0; /* seconds before timeout */ +char *confbase = NULL; /* directory in which all config files are */ +char *netname = NULL; /* name of the vpn network */ + +int config_compare(config_t *a, config_t *b) +{ + int result; + + result = strcasecmp(a->variable, b->variable); + + if(result) + return result; + + result = a->line - b->line; + + if(result) + return result; + else + return strcmp(a->file, b->file); +} + +void init_configuration(avl_tree_t **config_tree) +{ +cp + *config_tree = avl_alloc_tree((avl_compare_t)config_compare, (avl_action_t)free_config); +cp +} + +void exit_configuration(avl_tree_t **config_tree) +{ +cp + avl_delete_tree(*config_tree); + *config_tree = NULL; +cp +} + +config_t *new_config(void) +{ + config_t *cfg; +cp + cfg = (config_t *)xmalloc_and_zero(sizeof(*cfg)); + + return cfg; +} + +void free_config(config_t *cfg) +{ +cp + if(cfg->variable) + free(cfg->variable); + if(cfg->value) + free(cfg->value); + if(cfg->file) + free(cfg->file); + free(cfg); +cp +} + +void config_add(avl_tree_t *config_tree, config_t *cfg) +{ +cp + avl_insert(config_tree, cfg); +cp +} + +config_t *lookup_config(avl_tree_t *config_tree, char *variable) +{ + config_t cfg, *found; +cp + cfg.variable = variable; + cfg.file = ""; + cfg.line = 0; + + found = avl_search_closest_greater(config_tree, &cfg); + + if(!found) + return NULL; + + if(strcasecmp(found->variable, variable)) + return NULL; + + return found; +} + +config_t *lookup_config_next(avl_tree_t *config_tree, config_t *cfg) +{ + avl_node_t *node; + config_t *found; +cp + node = avl_search_node(config_tree, cfg); + + if(node) + { + if(node->next) + { + found = (config_t *)node->next->data; + if(!strcasecmp(found->variable, cfg->variable)) + return found; + } + } + + return NULL; +} + +int get_config_bool(config_t *cfg, int *result) +{ +cp + if(!cfg) + return 0; + + if(!strcasecmp(cfg->value, "yes")) + { + *result = 1; + return 1; + } + else if(!strcasecmp(cfg->value, "no")) + { + *result = 0; + return 1; + } + + syslog(LOG_ERR, _("\"yes\" or \"no\" expected for configuration variable %s in %s line %d"), + cfg->variable, cfg->file, cfg->line); + + return 0; +} + +int get_config_int(config_t *cfg, int *result) +{ +cp + if(!cfg) + return 0; + + if(sscanf(cfg->value, "%d", result) == 1) + return 1; + + syslog(LOG_ERR, _("Integer expected for configuration variable %s in %s line %d"), + cfg->variable, cfg->file, cfg->line); + return 0; +} + +int get_config_string(config_t *cfg, char **result) +{ +cp + if(!cfg) + return 0; + + *result = xstrdup(cfg->value); + return 1; +} + +int get_config_address(config_t *cfg, struct addrinfo **result) +{ + struct addrinfo *ai; +cp + if(!cfg) + return 0; + + ai = str2addrinfo(cfg->value, NULL, 0); + + if(ai) + { + *result = ai; + return 1; + } + + syslog(LOG_ERR, _("Hostname or IP address expected for configuration variable %s in %s line %d"), + cfg->variable, cfg->file, cfg->line); + return 0; +} + +int get_config_port(config_t *cfg, port_t *result) +{ +cp + if(!cfg) + return 0; + + if(sscanf(cfg->value, "%hu", result) == 1) + { + *result = htons(*result); + return 1; + } + + syslog(LOG_ERR, _("Port number expected for configuration variable %s in %s line %d"), + cfg->variable, cfg->file, cfg->line); + return 0; +} + +int get_config_subnet(config_t *cfg, subnet_t **result) +{ + subnet_t *subnet; +cp + if(!cfg) + return 0; + + subnet = str2net(cfg->value); + + if(!subnet) + { + syslog(LOG_ERR, _("Subnet expected for configuration variable %s in %s line %d"), + cfg->variable, cfg->file, cfg->line); + return 0; + } + + /* Teach newbies what subnets are... */ + + if(((subnet->type == SUBNET_IPV4) && maskcheck((char *)&subnet->net.ipv4.address, subnet->net.ipv4.prefixlength, sizeof(ipv4_t))) + || ((subnet->type == SUBNET_IPV6) && maskcheck((char *)&subnet->net.ipv6.address, subnet->net.ipv6.prefixlength, sizeof(ipv6_t)))) + { + syslog(LOG_ERR, _("Network address and prefix length do not match for configuration variable %s in %s line %d"), + cfg->variable, cfg->file, cfg->line); + free(subnet); + return 0; + } + + *result = subnet; + + return 1; +} + diff --git a/lib/conf.h b/lib/conf.h new file mode 100644 index 00000000..49a7e531 --- /dev/null +++ b/lib/conf.h @@ -0,0 +1,65 @@ +/* + conf.h -- header for conf.c + Copyright (C) 1998-2002 Ivo Timmermans + 2000-2002 Guus Sliepen + + 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: conf.h,v 1.1 2002/04/28 12:46:25 zarq Exp $ +*/ + +#ifndef __TINC_CONF_H__ +#define __TINC_CONF_H__ + +#include +#include +#include +#include + +#include +#include "net.h" +#include "subnet.h" + +typedef struct config_t { + char *variable; + char *value; + char *file; + int line; +} config_t; + +extern avl_tree_t *config_tree; + +extern int pingtimeout; +extern int maxtimeout; +extern int bypass_security; +extern char *confbase; +extern char *netname; + +extern void init_configuration(avl_tree_t **); +extern void exit_configuration(avl_tree_t **); +extern config_t *new_config(void); +extern void free_config(config_t *); +extern void config_add(avl_tree_t *, config_t *); +extern config_t *lookup_config(avl_tree_t *, char *); +extern config_t *lookup_config_next(avl_tree_t *, config_t *); +extern int get_config_bool(config_t *, int *); +extern int get_config_int(config_t *, int *); +extern int get_config_port(config_t *, port_t *); +extern int get_config_string(config_t *, char **); +extern int get_config_address(config_t *, struct addrinfo **); +struct subnet_t; /* Needed for next line. */ +extern int get_config_subnet(config_t *, struct subnet_t **); + +#endif /* __TINC_CONF_H__ */ diff --git a/lib/connection.c b/lib/connection.c new file mode 100644 index 00000000..279ac345 --- /dev/null +++ b/lib/connection.c @@ -0,0 +1,126 @@ +/* + connection.c -- connection list management + Copyright (C) 2000-2002 Guus Sliepen , + 2000-2002 Ivo Timmermans + + 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: connection.c,v 1.1 2002/04/28 12:46:25 zarq Exp $ +*/ + +#include "config.h" + +#include +#include +#include +#include + +#include +#include + +#include "net.h" /* Don't ask. */ +#include "netutl.h" +#include "config.h" +#include "conf.h" +#include +#include "subnet.h" +#include "logging.h" + +#include "xalloc.h" +#include "system.h" + +avl_tree_t *connection_tree; /* Meta connections */ + +int connection_compare(connection_t *a, connection_t *b) +{ + return a - b; +} + +void init_connections(void) +{ +cp + connection_tree = avl_alloc_tree((avl_compare_t)connection_compare, NULL); +cp +} + +void exit_connections(void) +{ +cp + avl_delete_tree(connection_tree); +cp +} + +connection_t *new_connection(void) +{ + connection_t *c; +cp + c = (connection_t *)xmalloc_and_zero(sizeof(connection_t)); + + if(!c) + return NULL; + + gettimeofday(&c->start, NULL); +cp + return c; +} + +void free_connection(connection_t *c) +{ +cp + if(c->hostname) + free(c->hostname); + if(c->inkey) + free(c->inkey); + if(c->outkey) + free(c->outkey); + if(c->mychallenge) + free(c->mychallenge); + if(c->hischallenge) + free(c->hischallenge); + free(c); +cp +} + +void connection_add(connection_t *c) +{ +cp + avl_insert(connection_tree, c); +cp +} + +void connection_del(connection_t *c) +{ +cp + avl_delete(connection_tree, c); +cp +} + +void dump_connections(void) +{ + avl_node_t *node; + connection_t *c; +cp + syslog(LOG_DEBUG, _("Connections:")); + + for(node = connection_tree->head; node; node = node->next) + { + c = (connection_t *)node->data; + syslog(LOG_DEBUG, _(" %s at %s options %lx socket %d status %04x"), + c->name, c->hostname, c->options, c->socket, c->status); + } + + syslog(LOG_DEBUG, _("End of connections.")); +cp +} diff --git a/lib/connection.h b/lib/connection.h new file mode 100644 index 00000000..6ce7f879 --- /dev/null +++ b/lib/connection.h @@ -0,0 +1,141 @@ +/* + connection.h -- header for connection.c + Copyright (C) 2000-2002 Guus Sliepen , + 2000-2002 Ivo Timmermans + + 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: connection.h,v 1.1 2002/04/28 12:46:25 zarq Exp $ +*/ + +#ifndef __TINC_CONNECTION_H__ +#define __TINC_CONNECTION_H__ + +#include + +#include +#include + +#ifdef USE_OPENSSL +# ifdef HAVE_OPENSSL_EVP_H +# include +# else +# include +# endif + +# ifdef HAVE_OPENSSL_RSA_H +# include +# else +# include +# endif +#endif /* USE_OPENSSL */ + +#ifdef USE_GCRYPT +# include +#endif + +#include "net.h" +#include "conf.h" + +#include "node.h" +#include "edge.h" + +#define OPTION_INDIRECT 0x0001 +#define OPTION_TCPONLY 0x0002 + +typedef struct connection_status_t { + int pinged:1; /* sent ping */ + int active:1; /* 1 if active.. */ + int connecting:1; /* 1 if we are waiting for a non-blocking connect() to finish */ + int termreq:1; /* the termination of this connection was requested */ + int remove:1; /* Set to 1 if you want this connection removed */ + int timeout:1; /* 1 if gotten timeout */ + int encryptout:1; /* 1 if we can encrypt outgoing traffic */ + int decryptin:1; /* 1 if we have to decrypt incoming traffic */ + int mst:1; /* 1 if this connection is part of a minimum spanning tree */ + int unused:18; +} connection_status_t; + +typedef struct connection_t { + char *name; /* name he claims to have */ + + sockaddr_t address; /* his real (internet) ip */ + char *hostname; /* the hostname of its real ip */ + int protocol_version; /* used protocol */ + + int socket; /* socket used for this connection */ + long int options; /* options for this connection */ + struct connection_status_t status; /* status info */ + int estimated_weight; /* estimation for the weight of the edge for this connection */ + struct timeval start; /* time this connection was started, used for above estimation */ + struct outgoing_t *outgoing; /* used to keep track of outgoing connections */ + + struct node_t *node; /* node associated with the other end */ + struct edge_t *edge; /* edge associated with this connection */ + +#ifdef USE_OPENSSL + RSA *rsa_key; /* his public/private key */ + const EVP_CIPHER *incipher; /* Cipher he will use to send data to us */ + const EVP_CIPHER *outcipher; /* Cipher we will use to send data to him */ + EVP_CIPHER_CTX *inctx; /* Context of encrypted meta data that will come from him to us */ + EVP_CIPHER_CTX *outctx; /* Context of encrypted meta data that will be sent from us to him */ + const EVP_MD *indigest; + const EVP_MD *outdigest; +#endif + +#ifdef USE_GCRYPT + GCRY_SEXP rsa_key; + GCRY_CIPHER_HD incipher; + GCRY_CIPHER_HD outcipher; + GCRY_CIPHER_HD inctx; + GCRY_CIPHER_HD outctx; + GCRY_MD_HD indigest; + GCRY_MD_HD outdigest; + /* FIXME */ +#endif + + char *inkey; /* His symmetric meta key + iv */ + char *outkey; /* Our symmetric meta key + iv */ + int inkeylength; /* Length of his key + iv */ + int outkeylength; /* Length of our key + iv */ + int inmaclength; + int outmaclength; + int incompression; + int outcompression; + char *mychallenge; /* challenge we received from him */ + char *hischallenge; /* challenge we sent to him */ + + char buffer[MAXBUFSIZE]; /* metadata input buffer */ + int buflen; /* bytes read into buffer */ + int tcplen; /* length of incoming TCPpacket */ + int allow_request; /* defined if there's only one request possible */ + + time_t last_ping_time; /* last time we saw some activity from the other end */ + + avl_tree_t *config_tree; /* Pointer to configuration tree belonging to him */ +} connection_t; + +extern avl_tree_t *connection_tree; + +extern void init_connections(void); +extern void exit_connections(void); +extern connection_t *new_connection(void); +extern void free_connection(connection_t *); +extern void connection_add(connection_t *); +extern void connection_del(connection_t *); +extern void dump_connections(void); +extern int read_connection_config(connection_t *); + +#endif /* __TINC_CONNECTION_H__ */ diff --git a/src/edge.c b/lib/edge.c similarity index 98% rename from src/edge.c rename to lib/edge.c index 6ceec61d..d959d514 100644 --- a/src/edge.c +++ b/lib/edge.c @@ -17,12 +17,13 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: edge.c,v 1.2 2002/04/09 15:26:00 zarq Exp $ + $Id: edge.c,v 1.1 2002/04/28 12:46:25 zarq Exp $ */ #include "config.h" #include +#include #include #include diff --git a/src/edge.h b/lib/edge.h similarity index 91% rename from src/edge.h rename to lib/edge.h index f50b3349..c2b2956e 100644 --- a/src/edge.h +++ b/lib/edge.h @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: edge.h,v 1.2 2002/04/09 15:26:00 zarq Exp $ + $Id: edge.h,v 1.1 2002/04/28 12:46:25 zarq Exp $ */ #ifndef __TINC_EDGE_H__ @@ -31,7 +31,7 @@ typedef struct halfconnection_t { struct node_t *node; /* node associated with this end of the connection */ -// sockaddr_t tcpaddress; /* real (internet) ip on this end of the meta connection */ +/* sockaddr_t tcpaddress; */ /* real (internet) ip on this end of the meta connection */ sockaddr_t udpaddress; /* real (internet) ip on this end of the vpn connection */ } halfconnection_t; @@ -43,6 +43,8 @@ typedef struct edge_t { int weight; /* weight of this edge */ struct connection_t *connection; /* connection associated with this edge, if available */ + + void *if_data; /* Interface data */ } edge_t; extern avl_tree_t *edge_tree; /* Tree with all known edges (replaces active_tree) */ diff --git a/src/logging.c b/lib/logging.c similarity index 97% rename from src/logging.c rename to lib/logging.c index 26f8dddd..b8206839 100644 --- a/src/logging.c +++ b/lib/logging.c @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: logging.c,v 1.5 2002/04/13 18:01:58 zarq Exp $ + $Id: logging.c,v 1.1 2002/04/28 12:46:25 zarq Exp $ */ #include "config.h" diff --git a/src/logging.h b/lib/logging.h similarity index 96% rename from src/logging.h rename to lib/logging.h index fa6accb7..60a48aa1 100644 --- a/src/logging.h +++ b/lib/logging.h @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: logging.h,v 1.7 2002/04/13 11:00:41 zarq Exp $ + $Id: logging.h,v 1.1 2002/04/28 12:46:25 zarq Exp $ */ #ifndef __TINC_LOGGING_H__ @@ -67,6 +67,8 @@ extern void tinc_syslog(int, char *, ...); #define LOG_NOTICE 5 /* normal but significant condition */ #define LOG_INFO 6 /* informational */ #define LOG_DEBUG 7 /* debug-level messages */ +#else +# warning dont include syslog! #endif #endif /* __TINC_LOGGING_H__ */ diff --git a/src/net.h b/lib/net.h similarity index 98% rename from src/net.h rename to lib/net.h index 0de53384..2d5dae08 100644 --- a/src/net.h +++ b/lib/net.h @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: net.h,v 1.11 2002/04/09 15:26:00 zarq Exp $ + $Id: net.h,v 1.1 2002/04/28 12:46:25 zarq Exp $ */ #ifndef __TINC_NET_H__ diff --git a/src/netutl.c b/lib/netutl.c similarity index 98% rename from src/netutl.c rename to lib/netutl.c index 9b9ca314..2ce34410 100644 --- a/src/netutl.c +++ b/lib/netutl.c @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: netutl.c,v 1.15 2002/04/13 11:07:12 zarq Exp $ + $Id: netutl.c,v 1.1 2002/04/28 12:46:25 zarq Exp $ */ #include "config.h" diff --git a/src/netutl.h b/lib/netutl.h similarity index 96% rename from src/netutl.h rename to lib/netutl.h index d30fca57..924f304b 100644 --- a/src/netutl.h +++ b/lib/netutl.h @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: netutl.h,v 1.4 2002/04/09 15:26:00 zarq Exp $ + $Id: netutl.h,v 1.1 2002/04/28 12:46:25 zarq Exp $ */ #ifndef __TINC_NETUTL_H__ diff --git a/lib/node.c b/lib/node.c new file mode 100644 index 00000000..47d346dc --- /dev/null +++ b/lib/node.c @@ -0,0 +1,188 @@ +/* + node.c -- node tree management + Copyright (C) 2001-2002 Guus Sliepen , + 2001-2002 Ivo Timmermans + + 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: node.c,v 1.1 2002/04/28 12:46:25 zarq Exp $ +*/ + +#include "config.h" + +#include +#include + +#include +#include "node.h" +#include "netutl.h" +#include "net.h" +#include +#include +#include + +#include "logging.h" + +#include "system.h" + +avl_tree_t *node_tree; /* Known nodes, sorted by name */ +avl_tree_t *node_udp_tree; /* Known nodes, sorted by address and port */ + +node_t *myself; + +int node_compare(node_t *a, node_t *b) +{ + return strcmp(a->name, b->name); +} + +int node_udp_compare(node_t *a, node_t *b) +{ + int result; +cp + result = sockaddrcmp(&a->address, &b->address); + + if(result) + return result; + + return (a->name && b->name)?strcmp(a->name, b->name):0; +} + +void init_nodes(void) +{ +cp + node_tree = avl_alloc_tree((avl_compare_t)node_compare, NULL); + node_udp_tree = avl_alloc_tree((avl_compare_t)node_udp_compare, NULL); +cp +} + +void exit_nodes(void) +{ +cp + avl_delete_tree(node_tree); + avl_delete_tree(node_udp_tree); +cp +} + +node_t *new_node(void) +{ + node_t *n = (node_t *)xmalloc_and_zero(sizeof(*n)); +cp + n->subnet_tree = new_subnet_tree(); + n->edge_tree = new_edge_tree(); + n->queue = list_alloc((list_action_t)free); +cp + return n; +} + +void free_node(node_t *n) +{ +cp + if(n->queue) + list_delete_list(n->queue); + if(n->name) + free(n->name); + if(n->hostname) + free(n->hostname); + if(n->key) + free(n->key); + if(n->subnet_tree) + free_subnet_tree(n->subnet_tree); + if(n->edge_tree) + free_edge_tree(n->edge_tree); + free(n); +cp +} + +void node_add(node_t *n) +{ +cp + avl_insert(node_tree, n); + avl_insert(node_udp_tree, n); + + run_hooks("node-add", n); +cp +} + +void node_del(node_t *n) +{ + avl_node_t *node, *next; + edge_t *e; + subnet_t *s; +cp + for(node = n->subnet_tree->head; node; node = next) + { + next = node->next; + s = (subnet_t *)node->data; + subnet_del(n, s); + } + + for(node = n->subnet_tree->head; node; node = next) + { + next = node->next; + e = (edge_t *)node->data; + edge_del(e); + } +cp + avl_delete(node_tree, n); + avl_delete(node_udp_tree, n); + + run_hooks("node-del", n); +cp +} + +node_t *lookup_node(char *name) +{ + node_t n; +cp + n.name = name; + return avl_search(node_tree, &n); +} + +node_t *lookup_node_udp(sockaddr_t *sa) +{ + node_t n; +cp + n.address = *sa; + n.name = NULL; + + return avl_search(node_udp_tree, &n); +} + +void dump_nodes(void) +{ + avl_node_t *node; + node_t *n; +cp + log(0, TLOG_DEBUG, + _("Nodes:")); + + for(node = node_tree->head; node; node = node->next) + { + n = (node_t *)node->data; +#ifdef USE_OPENSSL + syslog(LOG_DEBUG, _(" %s at %s cipher %d digest %d maclength %d compression %d options %lx status %04x nexthop %s via %s"), + n->name, n->hostname, n->cipher?n->cipher->nid:0, n->digest?n->digest->type:0, n->maclength, n->compression, n->options, + n->status, n->nexthop?n->nexthop->name:"-", n->via?n->via->name:"-"); +#endif +#ifdef USE_GCRYPT + syslog(LOG_DEBUG, _(" %s at %s cipher %d digest %d maclength %d compression %d options %lx status %04x nexthop %s via %s"), + n->name, n->hostname, n->cipher?-1:0, n->digest?-1:0, n->maclength, n->compression, n->options, + n->status, n->nexthop?n->nexthop->name:"-", n->via?n->via->name:"-"); +#endif + } + + syslog(LOG_DEBUG, _("End of nodes.")); +cp +} diff --git a/src/node.h b/lib/node.h similarity index 90% rename from src/node.h rename to lib/node.h index 0b615447..b43c2b46 100644 --- a/src/node.h +++ b/lib/node.h @@ -17,12 +17,14 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: node.h,v 1.2 2002/04/09 15:26:00 zarq Exp $ + $Id: node.h,v 1.1 2002/04/28 12:46:26 zarq Exp $ */ #ifndef __TINC_NODE_H__ #define __TINC_NODE_H__ +#include + #include #include "subnet.h" @@ -47,11 +49,23 @@ typedef struct node_t { struct node_status_t status; - const EVP_CIPHER *cipher; /* Cipher type for UDP packets */ +#ifdef USE_OPENSSL + const EVP_CIPHER *cipher; /* Cipher type for UDP packets */ +#endif +#ifdef USE_GCRYPT + GCRY_CIPHER_HD cipher; /* Cipher type for UDP packets */ +#endif + char *key; /* Cipher key and iv */ int keylength; /* Cipher key and iv length*/ +#ifdef USE_OPENSSL const EVP_MD *digest; /* Digest type for MAC */ +#endif +#ifdef USE_GCRYPT + GCRY_MD_HD digest; /* Digest type for MAC */ +#endif + int maclength; /* Length of MAC */ int compression; /* Compressionlevel, 0 = no compression */ @@ -69,6 +83,8 @@ typedef struct node_t { unsigned int sent_seqno; /* Sequence number last sent to this node */ unsigned int received_seqno; /* Sequence number last received from this node */ + + void *data; /* Interface details */ } node_t; extern struct node_t *myself; diff --git a/src/subnet.c b/lib/subnet.c similarity index 98% rename from src/subnet.c rename to lib/subnet.c index 5f649b51..fade7547 100644 --- a/src/subnet.c +++ b/lib/subnet.c @@ -17,19 +17,19 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: subnet.c,v 1.2 2002/04/09 15:26:01 zarq Exp $ + $Id: subnet.c,v 1.1 2002/04/28 12:46:26 zarq Exp $ */ #include "config.h" #include -#include #include #include #include #include #include +#include #include #include #include @@ -39,6 +39,7 @@ #include "node.h" #include "subnet.h" #include "netutl.h" +#include "logging.h" #include "system.h" @@ -158,6 +159,8 @@ cp avl_insert(subnet_tree, subnet); cp avl_insert(n->subnet_tree, subnet); + + run_hooks("subnet-add", subnet); cp } @@ -167,6 +170,8 @@ cp avl_delete(n->subnet_tree, subnet); cp avl_delete(subnet_tree, subnet); + + run_hooks("subnet-del", subnet); cp } diff --git a/src/subnet.h b/lib/subnet.h similarity index 95% rename from src/subnet.h rename to lib/subnet.h index 2369f4d7..7b20217b 100644 --- a/src/subnet.h +++ b/lib/subnet.h @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: subnet.h,v 1.2 2002/04/09 15:26:01 zarq Exp $ + $Id: subnet.h,v 1.1 2002/04/28 12:46:26 zarq Exp $ */ #ifndef __TINC_SUBNET_H__ @@ -67,6 +67,8 @@ typedef struct subnet_t { subnet_ipv4_t ipv4; subnet_ipv6_t ipv6; } net; + + void *data; /* Interface details */ } subnet_t; extern subnet_t *new_subnet(void); diff --git a/m4/openssl.m4 b/m4/openssl.m4 index e5c09395..991f22f2 100644 --- a/m4/openssl.m4 +++ b/m4/openssl.m4 @@ -46,4 +46,6 @@ AC_DEFUN(tinc_OPENSSL, [AC_MSG_ERROR("OpenSSL depends on libdl.")] ) ) + + found_openssl=1 ]) diff --git a/po/POTFILES.in b/po/POTFILES.in index 4e52a3ae..9b229b86 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -31,3 +31,4 @@ src/freebsd/device.c src/solaris/device.c src/netbsd/device.c src/openbsd/device.c +src/pokey/pokey.translatables diff --git a/po/nl.po b/po/nl.po index 0f37900c..d112fb25 100644 --- a/po/nl.po +++ b/po/nl.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: tinc 1.0-cvs\n" -"POT-Creation-Date: 2002-04-09 13:41+0200\n" +"POT-Creation-Date: 2002-04-14 21:41+0200\n" "PO-Revision-Date: 2002-03-27 16:59+0100\n" "Last-Translator: Guus Sliepen \n" "Language-Team: Dutch \n" @@ -13,35 +13,35 @@ msgstr "" "Content-Type: text/plain; charset=iso-8859-1\n" "Content-Transfer-Encoding: 8bit\n" -#: src/conf.c:173 +#: src/conf.c:171 #, c-format msgid "\"yes\" or \"no\" expected for configuration variable %s in %s line %d" msgstr "" "\"ja\" of \"nee\" verwacht voor configuratievariabele %s in %s regel %d" -#: src/conf.c:188 +#: src/conf.c:186 #, c-format msgid "Integer expected for configuration variable %s in %s line %d" msgstr "Geheel getal verwacht voor configuratievariabele %s in %s regel %d" -#: src/conf.c:218 +#: src/conf.c:216 #, c-format msgid "" "Hostname or IP address expected for configuration variable %s in %s line %d" msgstr "" "Hostnaam of IP adres verwacht voor configuratievariabele %s in %s regel %d" -#: src/conf.c:235 +#: src/conf.c:233 #, c-format msgid "Port number expected for configuration variable %s in %s line %d" msgstr "Poortnummer verwacht voor configuratievariabele %s in %s regel %d" -#: src/conf.c:251 +#: src/conf.c:249 #, c-format msgid "Subnet expected for configuration variable %s in %s line %d" msgstr "Subnet verwacht voor configuratievariabele %s in %s regel %d" -#: src/conf.c:261 +#: src/conf.c:259 #, c-format msgid "" "Network address and prefix length do not match for configuration variable %s " @@ -50,71 +50,71 @@ msgstr "" "Netwerk adres en prefix lengte komen niet overeen bij configuratievariabele %" "s in %s regel %d" -#: src/conf.c:369 +#: src/conf.c:367 #, c-format msgid "Cannot open config file %s: %s" msgstr "Kan configuratie bestand %s niet openen: %s" -#: src/conf.c:405 +#: src/conf.c:403 #, c-format msgid "No value for variable `%s' on line %d while reading config file %s" msgstr "" "Geen waarde voor variabele `%s' op regel %d tijdens het lezen van " "configuratie bestand %s" -#: src/conf.c:438 +#: src/conf.c:436 #, c-format msgid "Failed to read `%s': %s" msgstr "Lezen van `%s' mislukte: %s" -#: src/conf.c:465 +#: src/conf.c:463 #, c-format msgid "`%s' is not an absolute path" msgstr "`%s' is geen absoluut pad" -#: src/conf.c:481 src/conf.c:513 +#: src/conf.c:479 src/conf.c:511 #, c-format msgid "Couldn't stat `%s': %s" msgstr "Kon `%s' niet statten: %s" -#: src/conf.c:487 src/conf.c:522 +#: src/conf.c:485 src/conf.c:520 #, c-format msgid "`%s' is owned by UID %d instead of %d" msgstr "`%s' is eigendom van UID %d in plaats van %d" -#: src/conf.c:494 src/conf.c:529 +#: src/conf.c:492 src/conf.c:527 #, c-format msgid "Warning: `%s' is a symlink" msgstr "Waarschuwing: `%s' is een symbolische link" -#: src/conf.c:499 src/conf.c:534 +#: src/conf.c:497 src/conf.c:532 #, c-format msgid "Unable to read symbolic link `%s': %s" msgstr "Kan symbolische link `%s' niet lezen: %s" #. Accessible by others -#: src/conf.c:545 +#: src/conf.c:543 #, c-format msgid "`%s' has unsecure permissions" msgstr "`%s' heeft onveilige permissies" #. Ask for a file and/or directory name. -#: src/conf.c:570 +#: src/conf.c:568 #, c-format msgid "Please enter a file to save %s to [%s]: " msgstr "Geef een bestand om de %s naar de schrijven [%s]: " -#: src/conf.c:576 +#: src/conf.c:574 #, c-format msgid "Error while reading stdin: %s\n" msgstr "Fout tijdens lezen van standaardinvoer: %s\n" -#: src/conf.c:602 +#: src/conf.c:600 #, c-format msgid "Error opening file `%s': %s\n" msgstr "Fout bij het openen van het bestand `%s': %s\n" -#: src/conf.c:612 +#: src/conf.c:610 #, c-format msgid "" "The file `%s' (or any of the leading directories) has unsafe permissions.\n" @@ -260,8 +260,8 @@ msgstr "Instellen prioriteit uitgaand pakket op %d" #. SO_PRIORITY doesn't seem to work #: src/net_packet.c:290 src/net_setup.c:450 src/net_socket.c:98 -#: src/net_socket.c:144 src/net_socket.c:171 src/process.c:273 -#: src/process.c:310 +#: src/net_socket.c:144 src/net_socket.c:171 src/process.c:278 +#: src/process.c:315 #, c-format msgid "System call `%s' failed: %s" msgstr "Systeemaanroep `%s' mislukte: %s" @@ -499,27 +499,27 @@ msgstr "Verbinding van %s" msgid "Invalid name for outgoing connection in %s line %d" msgstr "Ongeldige naam voor uitgaande verbinding in %s regel %d" -#: src/netutl.c:65 src/netutl.c:88 +#: src/netutl.c:66 src/netutl.c:89 #, c-format msgid "Error looking up %s port %s: %s\n" msgstr "Fout bij het opzoeken van %s poort %s: %s\n" -#: src/netutl.c:109 +#: src/netutl.c:110 #, c-format msgid "Error while translating addresses: %s" msgstr "Fout tijdens vertalen adressen: %s" -#: src/netutl.c:134 +#: src/netutl.c:135 #, c-format msgid "Error while looking up hostname: %s" msgstr "Fout bij het opzoeken van hostnaam: %s" -#: src/netutl.c:137 +#: src/netutl.c:138 #, c-format msgid "%s port %s" msgstr "%s poort %s" -#: src/netutl.c:166 +#: src/netutl.c:167 #, c-format msgid "sockaddrcmp() was called with unknown address family %d, exitting!" msgstr "" @@ -909,127 +909,127 @@ msgstr "" "en je bent welkom om het te distribueren onder bepaalde voorwaarden;\n" "zie het bestand COPYING voor details.\n" -#: src/tincd.c:386 +#: src/tincd.c:382 msgid "Unrecoverable error" msgstr "Onherstelbare fout" -#: src/tincd.c:391 +#: src/tincd.c:387 #, c-format msgid "Restarting in %d seconds!" msgstr "Herstart in %d seconden!" -#: src/process.c:373 src/tincd.c:396 +#: src/process.c:378 src/tincd.c:392 msgid "Not restarting." msgstr "Geen herstart." -#: src/process.c:69 +#: src/process.c:71 #, c-format msgid "Memory exhausted (couldn't allocate %d bytes), exitting." msgstr "Geheugen uitgeput (kon geen %d bytes reserveren), beëindigen." -#: src/process.c:100 +#: src/process.c:103 msgid "Terminating" msgstr "Beëindigen" -#: src/process.c:116 +#: src/process.c:119 #, c-format msgid "A tincd is already running for net `%s' with pid %d.\n" msgstr "Een tincd draait al voor net `%s' met pid %d.\n" -#: src/process.c:119 +#: src/process.c:122 #, c-format msgid "A tincd is already running with pid %d.\n" msgstr "Een tincd draait al met pid %d.\n" -#: src/process.c:140 +#: src/process.c:143 #, c-format msgid "No other tincd is running for net `%s'.\n" msgstr "Geen andere tincd draait voor net `%s'.\n" -#: src/process.c:142 +#: src/process.c:145 msgid "No other tincd is running.\n" msgstr "Geen andere tincd draait.\n" -#: src/process.c:151 +#: src/process.c:154 #, c-format msgid "The tincd for net `%s' is no longer running. " msgstr "De tincd voor net `%s' draait niet meer. " -#: src/process.c:153 +#: src/process.c:156 msgid "The tincd is no longer running. " msgstr "De tincd draait niet meer. " -#: src/process.c:155 +#: src/process.c:158 msgid "Removing stale lock file.\n" msgstr "Verwijdering oud vergrendelingsbestand.\n" -#: src/process.c:183 +#: src/process.c:186 #, c-format msgid "Couldn't detach from terminal: %s" msgstr "Kon niet ontkoppelen van terminal: %s" -#: src/process.c:196 +#: src/process.c:201 #, c-format msgid "tincd %s (%s %s) starting, debug level %d" msgstr "tincd %s (%s %s) start, debug niveau %d" -#: src/process.c:199 +#: src/process.c:204 #, c-format msgid "tincd %s starting" msgstr "tincd %s wordt gestart" -#: src/process.c:280 +#: src/process.c:285 #, c-format msgid "Executing script %s" msgstr "Uitvoeren script %s" -#: src/process.c:290 +#: src/process.c:295 #, c-format msgid "Process %d (%s) exited with non-zero status %d" msgstr "Proces %d (%s) beëindigde met status %d" -#: src/process.c:298 +#: src/process.c:303 #, c-format msgid "Process %d (%s) was killed by signal %d (%s)" msgstr "Proces %d (%s) was gestopt door signaal %d (%s)" -#: src/process.c:304 +#: src/process.c:309 #, c-format msgid "Process %d (%s) terminated abnormally" msgstr "Proces %d (%s) abnormaal beëindigd" -#: src/process.c:329 +#: src/process.c:334 msgid "Got TERM signal" msgstr "Kreeg TERM signaal" -#: src/process.c:338 +#: src/process.c:343 msgid "Got QUIT signal" msgstr "Kreeg QUIT signaal" -#: src/process.c:345 +#: src/process.c:350 #, c-format msgid "Got another fatal signal %d (%s): not restarting." msgstr "Kreeg nog een fataal signaal %s (%s): geen herstart." -#: src/process.c:354 +#: src/process.c:359 #, c-format msgid "Got fatal signal %d (%s)" msgstr "Kreeg fataal signaal %d (%s)" -#: src/process.c:359 +#: src/process.c:364 msgid "Trying to re-execute in 5 seconds..." msgstr "Poging tot herstarten over 5 seconden..." -#: src/process.c:382 +#: src/process.c:387 msgid "Got HUP signal" msgstr "Kreeg HUP signaal" -#: src/process.c:391 +#: src/process.c:396 #, c-format msgid "Reverting to old debug level (%d)" msgstr "Herstellen van oud debug niveau (%d)" -#: src/process.c:398 +#: src/process.c:403 #, c-format msgid "" "Temporarily setting debug level to 5. Kill me with SIGINT again to go back " @@ -1038,21 +1038,21 @@ msgstr "" "Tijdelijk instellen debug niveau op 5. Zend nog een SIGINT signaal om niveau " "%d te herstellen." -#: src/process.c:409 +#: src/process.c:414 msgid "Got ALRM signal" msgstr "Kreeg ALRM signaal" -#: src/process.c:438 +#: src/process.c:443 #, c-format msgid "Got unexpected signal %d (%s)" msgstr "Kreeg onverwacht signaal %d (%s)" -#: src/process.c:447 +#: src/process.c:452 #, c-format msgid "Ignored signal %d (%s)" msgstr "Signaal %d (%s) genegeerd" -#: src/process.c:504 +#: src/process.c:509 #, c-format msgid "Installing signal handler for signal %d (%s) failed: %s\n" msgstr "Installeren van signaal afhandelaar voor signaal %d (%s) faalde: %s\n" @@ -1116,11 +1116,11 @@ msgstr "Kan pakket niet routeren: ARP verzoek voor onbekend adres %d.%d.%d.%d" msgid "Cannot route packet: unknown type %hx" msgstr "Kan pakket niet routeren: onbekend type %hx" -#: src/node.c:161 +#: src/node.c:160 msgid "Nodes:" msgstr "Nodes:" -#: src/node.c:166 +#: src/node.c:165 #, c-format msgid "" " %s at %s cipher %d digest %d maclength %d compression %d options %lx status " @@ -1129,7 +1129,7 @@ msgstr "" " %s op %s cipher %d digest %d maclengte %d compressie %d opties %lx status %" "04x nexthop %s via %s" -#: src/node.c:171 +#: src/node.c:170 msgid "End of nodes." msgstr "Einde van nodes." @@ -1284,5 +1284,203 @@ msgstr "Onbekende adresfamilie tijdens lezen pakket van %s %s" msgid "Unknown address family %d while writing packet to %s %s" msgstr "Onbekende adresfamilie tijdens schrijven pakket naar %s %s" +#. +#. * Vertaalbare teksten bestand gegenereerd door Glade. +#. * Voeg dit bestand toe aan uw project's bestand POTFILES.in. +#. * Compileer dit NIET als onderdeel van uw applicatie. +#. +#: src/pokey/pokey.translatables:7 +msgid "window1" +msgstr "" + +#: src/pokey/pokey.translatables:8 +msgid "_Network" +msgstr "_Netwerk" + +#: src/pokey/pokey.translatables:9 +msgid "_New network" +msgstr "_Nieuw netwerk" + +#: src/pokey/pokey.translatables:10 +msgid "label1" +msgstr "" + +#: src/pokey/pokey.translatables:11 +msgid "Information about host" +msgstr "Informatie over computer" + +#: src/pokey/pokey.translatables:12 src/pokey/pokey.translatables:30 +msgid "Name" +msgstr "Naam" + +#: src/pokey/pokey.translatables:13 src/pokey/pokey.translatables:31 +msgid "Hostname" +msgstr "Hostnaam" + +#: src/pokey/pokey.translatables:14 +msgid "Port" +msgstr "Poort" + +#: src/pokey/pokey.translatables:15 +msgid "Version" +msgstr "Versie" + +#: src/pokey/pokey.translatables:16 +msgid "Status" +msgstr "Status" + +#: src/pokey/pokey.translatables:17 +msgid "Only TCP packets" +msgstr "Alleen TCP pakketten" + +#: src/pokey/pokey.translatables:18 +msgid "Send data indirectly" +msgstr "Stuur data indirect" + +#: src/pokey/pokey.translatables:19 +msgid "Active" +msgstr "Actief" + +#: src/pokey/pokey.translatables:20 +msgid "Valid key" +msgstr "Geldige sleutel" + +#: src/pokey/pokey.translatables:21 +msgid "Waiting for key" +msgstr "Wachten op sleutel" + +#: src/pokey/pokey.translatables:22 +msgid "Visited" +msgstr "Bezocht" + +#: src/pokey/pokey.translatables:23 +msgid "Reachable" +msgstr "Bereikbaar" + +#: src/pokey/pokey.translatables:24 +msgid "Indirect" +msgstr "Indirect" + +#: src/pokey/pokey.translatables:25 +msgid "Visible" +msgstr "Zichtbaar" + +#: src/pokey/pokey.translatables:26 +msgid "Force Key Regeneration" +msgstr "Forceer Nieuwe Sleutel" + +#: src/pokey/pokey.translatables:27 +msgid "Host Info" +msgstr "Host Informatie" + +#: src/pokey/pokey.translatables:28 +msgid "label5" +msgstr "" + +#: src/pokey/pokey.translatables:29 +msgid "Information about connection" +msgstr "Informatie over verbinding" + +#: src/pokey/pokey.translatables:32 +msgid "Protocol version" +msgstr "Protocolversie" + +#: src/pokey/pokey.translatables:33 +msgid "Active since" +msgstr "Actief sinds" + +#: src/pokey/pokey.translatables:34 +msgid "Options" +msgstr "Opties" + +#: src/pokey/pokey.translatables:35 +msgid "label13" +msgstr "" + +#: src/pokey/pokey.translatables:36 +msgid "Force Disconnect" +msgstr "Forceer Ontkoppeling" + +#: src/pokey/pokey.translatables:37 +msgid "Force Reconnect" +msgstr "Forceer Opnieuw Verbinden" + +#: src/pokey/pokey.translatables:38 +msgid "Force Connect" +msgstr "Forceer Verbinding" + +#: src/pokey/pokey.translatables:39 +msgid "Connections" +msgstr "Verbindingen" + +#: src/pokey/pokey.translatables:40 +msgid "label4" +msgstr "" + +#: src/pokey/pokey.translatables:41 +msgid "Clear" +msgstr "Leegmaken" + +#: src/pokey/pokey.translatables:42 +msgid "Follow" +msgstr "Volgen" + +#: src/pokey/pokey.translatables:43 +msgid "Keep drawing" +msgstr "Blijf tekenen" + +#: src/pokey/pokey.translatables:44 +msgid "Shuffle" +msgstr "Willekeurig" + +#: src/pokey/pokey.translatables:45 +msgid "Zoom" +msgstr "Zoomen" + +#: src/pokey/pokey.translatables:46 +#, c-format +msgid "-50%" +msgstr "-50%" + +#: src/pokey/pokey.translatables:47 +#, c-format +msgid "-25%" +msgstr "-25%" + +#: src/pokey/pokey.translatables:48 +#, c-format +msgid "-10%" +msgstr "-10%" + +#: src/pokey/pokey.translatables:49 +msgid "Default" +msgstr "Standaard" + +#: src/pokey/pokey.translatables:50 +#, c-format +msgid "+10%" +msgstr "+10%" + +#: src/pokey/pokey.translatables:51 +#, c-format +msgid "+25%" +msgstr "+25%" + +#: src/pokey/pokey.translatables:52 +#, c-format +msgid "+50%" +msgstr "+50%" + +#: src/pokey/pokey.translatables:53 +msgid "Copyright 1998-2002" +msgstr "Copyright 1998-2002" + +#: src/pokey/pokey.translatables:54 +msgid "" +"tinc comes with ABSOLUTELY NO WARRANTY. This is free software, and you are " +"welcome to distribute it under certain conditions; see the file COPYING for " +"details." +msgstr "tinc wordt gedistribueerd ZONDER ENIGE GARANTIE. Dit is vrije programmatuur, en je bent welkom om het te distribueren onder bepaalde voorwaarden; zie het bestand COPYING voor details." + #~ msgid "Invalid public/private keypair!" #~ msgstr "Ongeldig publiek/privé sleutelpaar!" diff --git a/src/Makefile.am b/src/Makefile.am index 1de79b25..fbf98387 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,5 +1,5 @@ ## Produce this file with automake to get Makefile.in -# $Id: Makefile.am,v 1.9 2002/04/13 11:23:46 zarq Exp $ +# $Id: Makefile.am,v 1.10 2002/04/28 12:46:26 zarq Exp $ SUBDIRS = pokey @@ -7,19 +7,19 @@ sbin_PROGRAMS = tincd EXTRA_DIST = linux/device.c freebsd/device.c openbsd/device.c solaris/device.c -tincd_SOURCES = conf.c connection.c device.c edge.c event.c graph.c logging.c meta.c net.c net_packet.c net_setup.c \ - net_socket.c netutl.c node.c process.c protocol.c protocol_auth.c protocol_edge.c protocol_misc.c \ - protocol_key.c protocol_subnet.c route.c subnet.c tincd.c +tincd_SOURCES = read_conf.c device.c event.c graph.c meta.c net_packet.c net_setup.c \ + net_socket.c process.c protocol.c protocol_auth.c protocol_edge.c protocol_misc.c \ + protocol_key.c protocol_subnet.c route.c tincd.c net.c INCLUDES = @INCLUDES@ -I$(top_builddir) -I$(top_srcdir)/lib -I$(top_srcdir)/intl -noinst_HEADERS = conf.h connection.h device.h edge.h event.h graph.h logging.h meta.h net.h netutl.h node.h process.h \ - protocol.h route.h subnet.h +noinst_HEADERS = read_conf.h device.h event.h graph.h meta.h process.h \ + protocol.h route.h LIBS = @LIBS@ @INTLLIBS@ tincd_LDADD = \ - $(top_builddir)/lib/libtinc.a + $(top_builddir)/lib/libtinc.a -lgcrypt localedir = $(datadir)/locale diff --git a/src/graph.c b/src/graph.c index 1f370cd9..e8e8baf4 100644 --- a/src/graph.c +++ b/src/graph.c @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: graph.c,v 1.3 2002/04/13 11:07:12 zarq Exp $ + $Id: graph.c,v 1.4 2002/04/28 12:46:26 zarq Exp $ */ /* We need to generate two trees from the graph: @@ -47,7 +47,7 @@ #include "config.h" #include -#include "config.h" +#include #include #if defined(HAVE_FREEBSD) || defined(HAVE_OPENBSD) #include diff --git a/src/meta.c b/src/meta.c index c0367829..2c4b734f 100644 --- a/src/meta.c +++ b/src/meta.c @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: meta.c,v 1.3 2002/04/13 11:07:12 zarq Exp $ + $Id: meta.c,v 1.4 2002/04/28 12:46:26 zarq Exp $ */ #include "config.h" @@ -51,7 +51,12 @@ cp if(c->status.encryptout) { +#ifdef USE_OPENSSL EVP_EncryptUpdate(c->outctx, outbuf, &outlen, buffer, length); +#endif +#ifdef USE_GCRYPT + outlen = gcry_cipher_encrypt(c->outctx, outbuf, sizeof(outbuf), buffer, length); +#endif bufp = outbuf; length = outlen; } @@ -140,7 +145,12 @@ cp if(c->status.decryptin && !decrypted) { +#ifdef USE_OPENSSL EVP_DecryptUpdate(c->inctx, inbuf, &lenin, c->buffer + oldlen, lenin); +#endif +#ifdef USE_GCRYPT + lenin = gcry_cipher_decrypt(c->inctx, inbuf, sizeof(inbuf), c->buffer + oldlen, lenin); +#endif memcpy(c->buffer + oldlen, inbuf, lenin); decrypted = 1; } diff --git a/src/net.c b/src/net.c index cb060bf2..67a94909 100644 --- a/src/net.c +++ b/src/net.c @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: net.c,v 1.38 2002/04/13 11:07:12 zarq Exp $ + $Id: net.c,v 1.39 2002/04/28 12:46:26 zarq Exp $ */ #include "config.h" @@ -396,7 +396,9 @@ cp if(debug_lvl >= DEBUG_STATUS) syslog(LOG_INFO, _("Regenerating symmetric key")); +#ifdef USE_OPENSSL RAND_pseudo_bytes(myself->key, myself->keylength); +#endif send_key_changed(myself->connection, myself); keyexpires = now + keylifetime; } diff --git a/src/net_packet.c b/src/net_packet.c index 45c4a338..04b29789 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: net_packet.c,v 1.3 2002/04/13 11:07:12 zarq Exp $ + $Id: net_packet.c,v 1.4 2002/04/28 12:46:26 zarq Exp $ */ #include "config.h" @@ -92,15 +92,29 @@ void receive_udppacket(node_t *n, vpn_packet_t *inpkt) vpn_packet_t *outpkt = pkt[0]; int outlen, outpad; long int complen = MTU + 12; + +#ifdef USE_OPENSSL EVP_CIPHER_CTX ctx; char hmac[EVP_MAX_MD_SIZE]; +#endif +#ifdef USE_GCRYPT + char *hmac; +#endif + cp /* Check the message authentication code */ if(myself->digest && myself->maclength) { inpkt->len -= myself->maclength; +#ifdef USE_OPENSSL HMAC(myself->digest, myself->key, myself->keylength, (char *)&inpkt->seqno, inpkt->len, hmac, NULL); +#endif +#ifdef USE_GCRYPT + hmac = xmalloc(gcry_md_get_algo_dlen(0)); /* myself->digest type */ + gcry_md_hash_buffer(0, hmac, (char *)&inpkt->seqno, inpkt->len); + /* FIXME */ +#endif if(memcmp(hmac, (char *)&inpkt->seqno + inpkt->len, myself->maclength)) { if(debug_lvl >= DEBUG_TRAFFIC) @@ -115,9 +129,14 @@ cp { outpkt = pkt[nextpkt++]; +#ifdef USE_OPENSSL EVP_DecryptInit(&ctx, myself->cipher, myself->key, myself->key + myself->cipher->key_len); EVP_DecryptUpdate(&ctx, (char *)&outpkt->seqno, &outlen, (char *)&inpkt->seqno, inpkt->len); EVP_DecryptFinal(&ctx, (char *)&outpkt->seqno + outlen, &outpad); +#endif +#ifdef USE_GCRYPT + /* FIXME */ +#endif outpkt->len = outlen + outpad; inpkt = outpkt; @@ -190,11 +209,15 @@ void send_udppacket(node_t *n, vpn_packet_t *inpkt) int origlen; int outlen, outpad; long int complen = MTU + 12; - EVP_CIPHER_CTX ctx; vpn_packet_t *copy; static int priority = 0; int origpriority; int sock; + +#ifdef USE_OPENSSL + EVP_CIPHER_CTX ctx; +#endif + cp /* Make sure we have a valid key */ @@ -253,9 +276,18 @@ cp { outpkt = pkt[nextpkt++]; +#ifdef USE_OPENSSL EVP_EncryptInit(&ctx, n->cipher, n->key, n->key + n->cipher->key_len); EVP_EncryptUpdate(&ctx, (char *)&outpkt->seqno, &outlen, (char *)&inpkt->seqno, inpkt->len); EVP_EncryptFinal(&ctx, (char *)&outpkt->seqno + outlen, &outpad); +#endif +#ifdef USE_GCRYPT + gcry_cipher_ctl(n->cipher, GCRYCTL_SET_IV, n->key + n->keylength, n->keylength); + gcry_cipher_ctl(n->cipher, GCRYCTL_SET_KEY, n->key, n->keylength); + outlen = inpkt->len; + gcry_cipher_encrypt(n->cipher, (char *)&outpkt->seqno, outlen, (char *)&inpkt->seqno, inpkt->len); + /* FIXME */ +#endif outpkt->len = outlen + outpad; inpkt = outpkt; @@ -265,7 +297,18 @@ cp if(n->digest && n->maclength) { +#ifdef USE_OPENSSL HMAC(n->digest, n->key, n->keylength, (char *)&inpkt->seqno, inpkt->len, (char *)&inpkt->seqno + inpkt->len, &outlen); +#endif +#ifdef USE_GCRYPT + char *hmac; + outlen = gcry_md_get_algo_dlen(0); + hmac = xmalloc(outlen); /* myself->digest type */ + gcry_md_ctl(n->digest, GCRYCTL_SET_KEY, n->key, n->keylength); + gcry_md_hash_buffer(0, hmac, (char *)&inpkt->seqno, inpkt->len); + memcpy((char *)&inpkt->seqno, hmac, outlen); + /* FIXME */ +#endif inpkt->len += n->maclength; } diff --git a/src/net_setup.c b/src/net_setup.c index 2726aa25..8a8c0bc9 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: net_setup.c,v 1.3 2002/04/13 11:07:12 zarq Exp $ + $Id: net_setup.c,v 1.4 2002/04/28 12:46:26 zarq Exp $ */ #include "config.h" @@ -44,9 +44,15 @@ #include #include +#ifdef USE_OPENSSL #include #include #include +#endif + +#ifdef USE_GCRYPT +#include +#endif #include #include @@ -74,23 +80,39 @@ char *myport; int read_rsa_public_key(connection_t *c) { + char *key; +#ifdef USE_OPENSSL FILE *fp; char *fname; - char *key; cp if(!c->rsa_key) c->rsa_key = RSA_new(); - +#endif +cp + /* First, check for simple PublicKey statement */ if(get_config_string(lookup_config(c->config_tree, "PublicKey"), &key)) { +#ifdef USE_OPENSSL BN_hex2bn(&c->rsa_key->n, key); BN_hex2bn(&c->rsa_key->e, "FFFF"); +#endif +#ifdef USE_GCRYPT + int rc = gcry_sexp_build(&c->rsa_key, NULL, "(public-key(rsa(n%s)(e%s)))", + key, "FFFF"); + if(!rc) + { + syslog(LOG_ERR, _("gcry_sexp_build error: %d (%s)"), + rc, gcry_strerror(-1)); + return -1; + } +#endif free(key); return 0; } +#ifdef USE_OPENSSL /* Else, check for PublicKeyFile statement and read it */ if(get_config_string(lookup_config(c->config_tree, "PublicKeyFile"), &fname)) @@ -140,22 +162,44 @@ cp syslog(LOG_ERR, _("No public key for %s specified!"), c->name); return -1; } +#endif +#ifdef USE_GCRYPT + syslog(LOG_ERR, _("Only PublicKey statements are supported when using gcrypt for now.")); + return -1; +#endif } int read_rsa_private_key(void) { +#ifdef USE_OPENSSL FILE *fp; - char *fname, *key; + char *fname; +#endif + char *key; cp if(get_config_string(lookup_config(config_tree, "PrivateKey"), &key)) { +#ifdef USE_OPENSSL myself->connection->rsa_key = RSA_new(); BN_hex2bn(&myself->connection->rsa_key->d, key); BN_hex2bn(&myself->connection->rsa_key->e, "FFFF"); +#endif +#ifdef USE_GCRYPT + int rc = gcry_sexp_build(&myself->connection->rsa_key, NULL, + "(public-key(rsa(n%s)(e%s)))", + key, "FFFF"); + if(!rc) + { + syslog(LOG_ERR, _("gcry_sexp_build error: %d (%s)"), + rc, gcry_strerror(-1)); + return -1; + } +#endif free(key); return 0; } +#ifdef USE_OPENSSL if(!get_config_string(lookup_config(config_tree, "PrivateKeyFile"), &fname)) asprintf(&fname, "%s/rsa_key.priv", confbase); @@ -182,6 +226,11 @@ cp free(fname); return -1; +#endif +#ifdef USE_GCRYPT + syslog(LOG_ERR, _("Only PrivateKey statements are supported when using gcrypt for now.")); + return -1; +#endif } /* @@ -338,11 +387,23 @@ cp { if(!strcasecmp(cipher, "none")) { +#ifdef USE_OPENSSL myself->cipher = NULL; +#endif +#ifdef USE_GCRYPT + myself->cipher = gcry_cipher_open(GCRY_CIPHER_NONE, GCRY_CIPHER_MODE_NONE, 0); +#endif } else { +#ifdef USE_OPENSSL if(!(myself->cipher = EVP_get_cipherbyname(cipher))) +#endif +#ifdef USE_GCRYPT + /* FIXME */ + myself->cipher = gcry_cipher_open(GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC, 0); + if(0) +#endif { syslog(LOG_ERR, _("Unrecognized cipher type!")); return -1; @@ -350,17 +411,42 @@ cp } } else - myself->cipher = EVP_bf_cbc(); + { +#ifdef USE_OPENSSL + myself->cipher = EVP_bf_cbc(); +#endif +#ifdef USE_GCRYPT + myself->cipher = gcry_cipher_open(GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC, 0); +#endif + } +#ifdef USE_OPENSSL if(myself->cipher) myself->keylength = myself->cipher->key_len + myself->cipher->iv_len; +#endif +#ifdef USE_GCRYPT + if(myself->cipher) + myself->keylength = 16; /* FIXME */ +#endif else myself->keylength = 1; +#ifdef USE_OPENSSL myself->connection->outcipher = EVP_bf_ofb(); +#endif +#ifdef USE_GCRYPT + /* FIXME: CHANGE this to something like aes - but openssl + compatibility mode for now */ + myself->connection->outcipher = gcry_cipher_open(GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_OFB, 0); +#endif +#ifdef USE_OPENSSL myself->key = (char *)xmalloc(myself->keylength); RAND_pseudo_bytes(myself->key, myself->keylength); +#endif +#ifdef USE_GCYRPT + myself->key = gcry_random_bytes(myself->keylength, GCRY_WEAK_RANDOM); +#endif if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime)) keylifetime = 3600; @@ -373,11 +459,22 @@ cp { if(!strcasecmp(digest, "none")) { +#ifdef USE_OPENSSL myself->digest = NULL; +#endif +#ifdef USE_GCRYPT + myself->digest = gcry_md_open(GCRY_MD_NONE, GCRY_MD_FLAG_HMAC); +#endif } else { +#ifdef USE_OPENSSL if(!(myself->digest = EVP_get_digestbyname(digest))) +#endif +#ifdef USE_GCRYPT + /* FIXME */ + if(!(myself->digest = gcry_md_open(GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC))) +#endif { syslog(LOG_ERR, _("Unrecognized digest type!")); return -1; @@ -385,14 +482,25 @@ cp } } else +#ifdef USE_OPENSSL myself->digest = EVP_sha1(); +#endif +#ifdef USE_GCRYPT + myself->digest = gcry_md_open(GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC); +#endif +#ifdef USE_OPENSSL myself->connection->outdigest = EVP_sha1(); +#endif +#ifdef USE_GCRYPT + myself->connection->outdigest = gcry_md_open(GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC); +#endif if(get_config_int(lookup_config(myself->connection->config_tree, "MACLength"), &myself->maclength)) { if(myself->digest) { +#ifdef USE_OPENSSL if(myself->maclength > myself->digest->md_size) { syslog(LOG_ERR, _("MAC length exceeds size of digest!")); @@ -403,6 +511,11 @@ cp syslog(LOG_ERR, _("Bogus MAC length!")); return -1; } +#endif +#ifdef USE_GCRYPT + /* FIXME */ + myself->maclength = 12; +#endif } } else diff --git a/src/pokey/Makefile.am b/src/pokey/Makefile.am index 28a787d3..021ba0a2 100644 --- a/src/pokey/Makefile.am +++ b/src/pokey/Makefile.am @@ -1,18 +1,18 @@ ## Produce this file with automake to get Makefile.in -# $Id: Makefile.am,v 1.1 2002/04/13 11:24:25 zarq Exp $ +# $Id: Makefile.am,v 1.2 2002/04/28 12:46:26 zarq Exp $ sbin_PROGRAMS = pokey -pokey_SOURCES = conf.c connection.c edge.c event.c graph.c \ - interface.c meta.c net.c net_packet.c net_setup.c net_socket.c netutl.c \ - node.c process.c protocol.c protocol_auth.c protocol_edge.c \ +pokey_SOURCES = event.c graph.c \ + interface.c logging.c meta.c net.c net_packet.c net_setup.c net_socket.c netutl.c \ + process.c protocol.c protocol_auth.c protocol_edge.c \ protocol_misc.c protocol_key.c protocol_subnet.c route.c \ - subnet.c pokey.c + pokey.c INCLUDES = @INCLUDES@ -I$(top_builddir) -I$(top_srcdir)/lib -I$(top_srcdir)/intl -I$(top_srcdir)/src -I/usr/include/gtk-1.2 -I/usr/include/glib-1.2 -I/usr/lib/glib/include -I/usr/include/libglade-1.0 -I/usr/include/gnome-1.0 -I/usr/include/gnome-xml -I/usr/include/libglade-1.0 -I/usr/include/gnome-1.0 -DNEED_GNOMESUPPORT_H -I/usr/lib/gnome-libs/include -I/usr/include/glib-1.2 -I/usr/lib/glib/include -I/usr/include/orbit-1.0 -I/usr/include/gtk-1.2 -I/usr/X11R6/include -noinst_HEADERS = conf.h connection.h device.h edge.h event.h graph.h meta.h net.h netutl.h node.h process.h \ - protocol.h route.h subnet.h +noinst_HEADERS = device.h event.h graph.h meta.h net.h netutl.h process.h \ + protocol.h route.h LIBS = @LIBS@ @INTLLIBS@ diff --git a/src/pokey/array.c b/src/pokey/array.c new file mode 100644 index 00000000..9946ad17 --- /dev/null +++ b/src/pokey/array.c @@ -0,0 +1,45 @@ +#include +#include + +#include "myalloc.h" +#include "array.h" + +void *array_add(array_t *array, void *element) +{ + if(!array) + return NULL; + + if(array->allocated == 0) + { + array->allocated = 4; + array->data = xcalloc(array->allocated, sizeof(void*)); + array->elements = 0; + } + + if(array->elements >= array->allocated - 1) + { + int newalloc; + + newalloc = array->allocated << 1; + array->data = xrealloc(array->data, newalloc * sizeof(void*)); + array->allocated = newalloc; + } + + array->data[array->elements] = element; + array->elements++; + return element; +} + +array_t *array_create(void) +{ + array_t *r; + + r = xcalloc(1, sizeof(*r)); + return r; +} + +void array_free(array_t *array) +{ + free(array->data); + free(array); +} diff --git a/src/pokey/array.h b/src/pokey/array.h new file mode 100644 index 00000000..a1a81c4b --- /dev/null +++ b/src/pokey/array.h @@ -0,0 +1,18 @@ +#ifndef __ARRAY_H__ +#define __ARRAY_H__ + +typedef struct array_t { + void **data; + int allocated; + int elements; +} array_t; + +#define array_get_ptr(array) ((array)->data) +#define array_get_nelts(array) ((array)->elements) +#define array_get_element(array, index) ((array)->data[(index)]) + +void *array_add(array_t *array, void *element); +array_t *array_create(void); +void array_free(array_t *array); + +#endif /* __ARRAY_H__ */ diff --git a/src/conf.h b/src/pokey/conf.h similarity index 96% rename from src/conf.h rename to src/pokey/conf.h index 95e5b764..cb1247b0 100644 --- a/src/conf.h +++ b/src/pokey/conf.h @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: conf.h,v 1.9 2002/04/13 10:04:46 zarq Exp $ + $Id: conf.h,v 1.1 2002/04/28 12:46:26 zarq Exp $ */ #ifndef __TINC_CONF_H__ @@ -40,6 +40,7 @@ typedef struct config_t { extern avl_tree_t *config_tree; +extern int debug_lvl; extern int pingtimeout; extern int maxtimeout; extern int bypass_security; diff --git a/src/connection.h b/src/pokey/connection.h similarity index 97% rename from src/connection.h rename to src/pokey/connection.h index bd37aea0..8f436969 100644 --- a/src/connection.h +++ b/src/pokey/connection.h @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: connection.h,v 1.2 2002/04/09 15:26:00 zarq Exp $ + $Id: connection.h,v 1.1 2002/04/28 12:46:26 zarq Exp $ */ #ifndef __TINC_CONNECTION_H__ @@ -99,7 +99,6 @@ typedef struct connection_t { char buffer[MAXBUFSIZE]; /* metadata input buffer */ int buflen; /* bytes read into buffer */ - int tcplen; /* length of incoming TCPpacket */ int allow_request; /* defined if there's only one request possible */ time_t last_ping_time; /* last time we saw some activity from the other end */ diff --git a/src/pokey/device.h b/src/pokey/device.h new file mode 100644 index 00000000..f705e3d0 --- /dev/null +++ b/src/pokey/device.h @@ -0,0 +1,36 @@ +/* + net.h -- generic header for device.c + Copyright (C) 2001-2002 Ivo Timmermans + 2001-2002 Guus Sliepen + + 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: device.h,v 1.1 2002/04/28 12:46:26 zarq Exp $ +*/ + +#ifndef __TINC_DEVICE_H__ +#define __TINC_DEVICE_H__ + +extern int device_fd; +extern char *device; +extern char *interface; + +extern int setup_device(void); +extern void close_device(void); +extern int read_packet(vpn_packet_t *); +extern int write_packet(vpn_packet_t *); +extern void dump_device_stats(void); + +#endif /* __TINC_DEVICE_H__ */ diff --git a/src/pokey/event.c b/src/pokey/event.c new file mode 100644 index 00000000..87a1c8ae --- /dev/null +++ b/src/pokey/event.c @@ -0,0 +1,110 @@ +/* + event.c -- event queue + Copyright (C) 2002 Guus Sliepen , + 2002 Ivo Timmermans + + 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: event.c,v 1.1 2002/04/28 12:46:26 zarq Exp $ +*/ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "event.h" + +#include "system.h" + +avl_tree_t *event_tree; +extern time_t now; + +int id; + +int event_compare(event_t *a, event_t *b) +{ + if(a->time > b->time) + return 1; + if(a->time < b->time) + return -1; + return a->id - b->id; +} + +void init_events(void) +{ +cp + event_tree = avl_alloc_tree((avl_compare_t)event_compare, NULL); +cp +} + +void exit_events(void) +{ +cp + avl_delete_tree(event_tree); +cp +} + +event_t *new_event(void) +{ + event_t *event; +cp + event = (event_t *)xmalloc_and_zero(sizeof(*event)); +cp + return event; +} + +void free_event(event_t *event) +{ +cp + free(event); +cp +} + +void event_add(event_t *event) +{ +cp + event->id = ++id; + avl_insert(event_tree, event); +cp +} + +void event_del(event_t *event) +{ +cp + avl_delete(event_tree, event); +cp +} + +event_t *get_expired_event(void) +{ + event_t *event; +cp + if(event_tree->head) + { + event = (event_t *)event_tree->head->data; + if(event->time < now) + { + avl_delete(event_tree, event); + return event; + } + } +cp + return NULL; +} diff --git a/src/pokey/event.h b/src/pokey/event.h new file mode 100644 index 00000000..989cc07e --- /dev/null +++ b/src/pokey/event.h @@ -0,0 +1,48 @@ +/* + event.h -- header for event.c + Copyright (C) 2002 Guus Sliepen , + 2002 Ivo Timmermans + + 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: event.h,v 1.1 2002/04/28 12:46:26 zarq Exp $ +*/ + +#ifndef __TINC_EVENT_H__ +#define __TINC_EVENT_H__ + +#include +#include + +avl_tree_t *event_tree; + +typedef void (*event_handler_t)(void *); + +typedef struct { + time_t time; + int id; + event_handler_t handler; + void *data; +} event_t; + +extern void init_events(void); +extern void exit_events(void); +extern event_t *new_event(void); +extern void free_event(event_t *); +extern void event_add(event_t *); +extern void event_del(event_t *); +extern event_t *get_expired_event(void); + +#endif /* __TINC_EVENT_H__ */ diff --git a/src/pokey/graph.c b/src/pokey/graph.c new file mode 100644 index 00000000..25b4a0ed --- /dev/null +++ b/src/pokey/graph.c @@ -0,0 +1,283 @@ +/* + graph.c -- graph algorithms + Copyright (C) 2001-2002 Guus Sliepen , + 2001-2002 Ivo Timmermans + + 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: graph.c,v 1.1 2002/04/28 12:46:26 zarq Exp $ +*/ + +/* We need to generate two trees from the graph: + + 1. A minimum spanning tree for broadcasts, + 2. A single-source shortest path tree for unicasts. + + Actually, the first one alone would suffice but would make unicast packets + take longer routes than necessary. + + For the MST algorithm we can choose from Prim's or Kruskal's. I personally + favour Kruskal's, because we make an extra AVL tree of edges sorted on + weights (metric). That tree only has to be updated when an edge is added or + removed, and during the MST algorithm we just have go linearly through that + tree, adding safe edges until #edges = #nodes - 1. The implementation here + however is not so fast, because I tried to avoid having to make a forest and + merge trees. + + For the SSSP algorithm Dijkstra's seems to be a nice choice. Currently a + simple breadth-first search is presented here. + + The SSSP algorithm will also be used to determine whether nodes are directly, + indirectly or not reachable from the source. It will also set the correct + destination address and port of a node if possible. +*/ + +#include "config.h" +#include +#if defined(HAVE_FREEBSD) || defined(HAVE_OPENBSD) + #include +#endif +#include + +#include +#include +#include + +#include "interface.h" +#include "netutl.h" +#include "node.h" +#include "edge.h" +#include "connection.h" +#include "logging.h" + +#include "system.h" + +/* Implementation of Kruskal's algorithm. + Running time: O(EN) + Please note that sorting on weight is already done by add_edge(). +*/ + +void mst_kruskal(void) +{ + avl_node_t *node, *next; + edge_t *e; + node_t *n; + connection_t *c; + int nodes = 0; + int safe_edges = 0; + int skipped; + + /* Clear MST status on connections */ + + for(node = connection_tree->head; node; node = node->next) + { + c = (connection_t *)node->data; + c->status.mst = 0; + } + + /* Do we have something to do at all? */ + + if(!edge_weight_tree->head) + return; + + log(DEBUG_SCARY_THINGS, TLOG_DEBUG, + _("Running Kruskal's algorithm:")); + + /* Clear visited status on nodes */ + + for(node = node_tree->head; node; node = node->next) + { + n = (node_t *)node->data; + n->status.visited = 0; + nodes++; + } + + /* Starting point */ + + ((edge_t *)edge_weight_tree->head->data)->from.node->status.visited = 1; + + /* Add safe edges */ + + for(skipped = 0, node = edge_weight_tree->head; node; node = next) + { + next = node->next; + e = (edge_t *)node->data; + + if(e->from.node->status.visited == e->to.node->status.visited) + { + skipped = 1; + continue; + } + + e->from.node->status.visited = 1; + e->to.node->status.visited = 1; + if(e->connection) + e->connection->status.mst = 1; + + safe_edges++; + + if(debug_lvl >= DEBUG_SCARY_THINGS) + syslog(LOG_DEBUG, " Adding edge %s - %s weight %d", e->from.node->name, e->to.node->name, e->weight); + + if(skipped) + { + next = edge_weight_tree->head; + continue; + } + } + + if(debug_lvl >= DEBUG_SCARY_THINGS) + syslog(LOG_DEBUG, "Done, counted %d nodes and %d safe edges.", nodes, safe_edges); +} + +/* Implementation of a simple breadth-first search algorithm. + Running time: O(E) +*/ + +void sssp_bfs(void) +{ + avl_node_t *node, *from, *next, *to; + edge_t *e; + node_t *n; + halfconnection_t to_hc, from_hc; + avl_tree_t *todo_tree; + int indirect; + + todo_tree = avl_alloc_tree(NULL, NULL); + + /* Clear visited status on nodes */ + + for(node = node_tree->head; node; node = node->next) + { + n = (node_t *)node->data; + n->status.visited = 0; + n->status.indirect = 1; + } + + /* Begin with myself */ + + myself->status.visited = 1; + myself->status.indirect = 0; + myself->nexthop = myself; + myself->via = myself; + node = avl_alloc_node(); + node->data = myself; + avl_insert_top(todo_tree, node); + + /* Loop while todo_tree is filled */ + + while(todo_tree->head) + { + for(from = todo_tree->head; from; from = next) /* "from" is the node from which we start */ + { + next = from->next; + n = (node_t *)from->data; + + for(to = n->edge_tree->head; to; to = to->next) /* "to" is the edge connected to "from" */ + { + e = (edge_t *)to->data; + + if(e->from.node == n) /* "from_hc" is the halfconnection with .node == from */ + to_hc = e->to, from_hc = e->from; + else + to_hc = e->from, from_hc = e->to; + + /* Situation: + + / + / + ------(n)from_hc-----to_hc + \ + \ + + n->address is set to the to_hc.udpaddress of the edge left of n. + We are currently examining the edge right of n: + + - If from_hc.udpaddress != n->address, then to_hc.node is probably + not reachable for the nodes left of n. We do as if the indirectdata + flag is set on edge e. + - If edge e provides for better reachability of to_hc.node, update + to_hc.node and (re)add it to the todo_tree to (re)examine the reachability + of nodes behind it. + */ + + indirect = n->status.indirect || e->options & OPTION_INDIRECT || ((n != myself) && sockaddrcmp(&n->address, &from_hc.udpaddress)); + + if(to_hc.node->status.visited && (!to_hc.node->status.indirect || indirect)) + continue; + + to_hc.node->status.visited = 1; + to_hc.node->status.indirect = indirect; + to_hc.node->nexthop = (n->nexthop == myself) ? to_hc.node : n->nexthop; + to_hc.node->via = indirect ? n->via : to_hc.node; + to_hc.node->options = e->options; + if(sockaddrcmp(&to_hc.node->address, &to_hc.udpaddress)) + { + node = avl_unlink(node_udp_tree, to_hc.node); + to_hc.node->address = to_hc.udpaddress; + if(to_hc.node->hostname) + free(to_hc.node->hostname); + to_hc.node->hostname = sockaddr2hostname(&to_hc.udpaddress); + avl_insert_node(node_udp_tree, node); + } + node = avl_alloc_node(); + node->data = to_hc.node; + avl_insert_before(todo_tree, from, node); + } + + avl_delete_node(todo_tree, from); + } + } + + avl_free_tree(todo_tree); + + /* Check reachability status. */ + + for(node = node_tree->head; node; node = next) + { + next = node->next; + n = (node_t *)node->data; + + if(n->status.visited) + { + if(!n->status.reachable) + { + if(debug_lvl >= DEBUG_TRAFFIC) + syslog(LOG_ERR, _("Node %s (%s) became reachable"), n->name, n->hostname); + n->status.reachable = 1; + run_hooks("node-visible", n); + } + } + else + { + if(n->status.reachable) + { + if(debug_lvl >= DEBUG_TRAFFIC) + syslog(LOG_DEBUG, _("Node %s (%s) became unreachable"), n->name, n->hostname); + n->status.reachable = 0; + n->status.validkey = 0; + n->status.waitingforkey = 0; + n->sent_seqno = 0; + run_hooks("node-invisible", n); + } + } + } +} + +void graph(void) +{ + mst_kruskal(); + sssp_bfs(); +} diff --git a/src/pokey/graph.h b/src/pokey/graph.h new file mode 100644 index 00000000..ec0ead69 --- /dev/null +++ b/src/pokey/graph.h @@ -0,0 +1,30 @@ +/* + graph.h -- header for graph.c + Copyright (C) 2001-2002 Guus Sliepen , + 2001-2002 Ivo Timmermans + + 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: graph.h,v 1.1 2002/04/28 12:46:26 zarq Exp $ +*/ + +#ifndef __TINC_GRAPH_H__ +#define __TINC_GRAPH_H__ + +extern void graph(void); +extern void mst_kruskal(void); +extern void sssp_bfs(void); + +#endif /* __TINC_GRAPH_H__ */ diff --git a/src/pokey/interface.c b/src/pokey/interface.c index 0364dc52..950f6596 100644 --- a/src/pokey/interface.c +++ b/src/pokey/interface.c @@ -1,9 +1,35 @@ +/* + interface.c -- GTK+/GNOME interface functions + Copyright (C) 2002 Guus Sliepen , + 2002 Ivo Timmermans + + 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: interface.c,v 1.4 2002/04/28 12:46:26 zarq Exp $ +*/ + #include "config.h" +#include #include #include #include + +#define log mathlog #include +#undef log #include #include @@ -14,10 +40,12 @@ #include #include "node.h" +#include "connection.h" #include "edge.h" #include "interface.h" #include "logging.h" +#include #include #include "system.h" @@ -56,7 +84,7 @@ static int inited = 0; static int number_of_nodes = 0; static GtkWidget *nodetree; -static GtkCTreeNode *subnets_ctn, *hosts_ctn, *conns_ctn; +static GtkCTreeNode *hosts_ctn; static GnomeCanvasGroup *edge_group = NULL; @@ -65,28 +93,34 @@ static int canvas_height; static GtkWidget *canvas = NULL; +static int log_inited = 0; +static int follow_log = 1; + +static int keep_drawing = 1; + +static GtkCList *connlist = NULL; + +static double canvas_zoom = 1.00; + +void if_node_add(const char *hooktype, va_list ap); +void if_node_del(const char *hooktype, va_list ap); +void if_subnet_add(const char *hooktype, va_list ap); +void if_subnet_del(const char *hooktype, va_list ap); +void if_edge_add(const char *hooktype, va_list ap); +void if_edge_del(const char *hooktype, va_list ap); +void if_node_visible(const char *hooktype, va_list ap); +void if_node_invisible(const char *hooktype, va_list ap); + GtkWidget *create_canvas(void) { - GtkWidget *w; - - gtk_widget_push_visual(gdk_rgb_get_visual()); - gtk_widget_push_colormap(gdk_rgb_get_cmap()); - - canvas = gnome_canvas_new_aa(); - - gtk_widget_pop_visual(); - gtk_widget_pop_colormap(); - - gnome_canvas_set_scroll_region(GNOME_CANVAS(canvas), -00.0, -00.0, 700, 500); - - w = glade_xml_get_widget(xml, "scrolledwindow3"); - if(!w) + canvas = glade_xml_get_widget(xml, "canvas1"); + if(!canvas) { - fprintf(stderr, "Could not find widget `scrolledwindow3'\n"); + fprintf(stderr, "Could not find widget `canvas1'\n"); return NULL; } - gtk_container_add(GTK_CONTAINER(w), canvas); - gtk_widget_show_all(w); + + gnome_canvas_set_scroll_region(GNOME_CANVAS(canvas), -00.0, -00.0, 700, 500); canvas_width = 300.0; canvas_height = 500.0; @@ -103,7 +137,6 @@ void log_gtk(int level, int priority, char *fmt, va_list ap) char *p; struct tm *tm; time_t t; - static int inited = 0; if(!xml) return; @@ -141,56 +174,383 @@ void log_gtk(int level, int priority, char *fmt, va_list ap) gtk_text_freeze(GTK_TEXT(w)); - if(inited) + if(log_inited) gtk_text_insert(GTK_TEXT(w), NULL, NULL, NULL, "\n", 1); gtk_text_insert(GTK_TEXT(w), NULL, &timecolor, NULL, buffer2, strlen(buffer2)); gtk_text_insert(GTK_TEXT(w), NULL, NULL, NULL, buffer1, len); gtk_text_thaw(GTK_TEXT(w)); - inited = 1; + log_inited = 1; + if(follow_log) +/* gtk_text_set_point(GTK_TEXT(w), -1); */ + gtk_editable_set_position(GTK_EDITABLE(w), gtk_text_get_length(GTK_TEXT(w))); +} + +void if_hostinfoclosebutton_clicked(GtkWidget *w, gpointer data) +{ + gtk_widget_destroy(GTK_WIDGET(data)); +} + +void update_hostinfo_dialog(GladeXML *x, node_t *n) +{ + GtkWidget *w; + char s[100]; + avl_node_t *avlnode; + char *l[1]; + + w = glade_xml_get_widget(x, "HostInfoNameEntry"); + if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoNameEntry"); return; } + gtk_entry_set_text(GTK_ENTRY(w), n->name); + + w = glade_xml_get_widget(x, "HostInfoHostnameEntry"); + if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoHostnameEntry"); return; } + gtk_entry_set_text(GTK_ENTRY(w), n->hostname); + + w = glade_xml_get_widget(x, "HostInfoPortEntry"); + if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoPortEntry"); return; } +/* snprintf(s, sizeof(s)-1, "%hd", "0"); */ + gtk_entry_set_text(GTK_ENTRY(w), "port"); + + w = glade_xml_get_widget(x, "HostInfoVersionEntry"); + if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoVersionEntry"); return; } + gtk_entry_set_text(GTK_ENTRY(w), n->name); + + w = glade_xml_get_widget(x, "HostInfoStatusEntry"); + if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoStatusEntry"); return; } +/* snprintf(s, sizeof(s)-1, "%x", n->status); */ + gtk_entry_set_text(GTK_ENTRY(w), "0"); + + w = glade_xml_get_widget(x, "HostInfoActiveCheckbutton"); + if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoActiveCheckbutton"); return; } + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n->status.active); + + w = glade_xml_get_widget(x, "HostInfoValidkeyCheckbutton"); + if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoValidkeyCheckbutton"); return; } + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n->status.validkey); + + w = glade_xml_get_widget(x, "HostInfoWaitingforkeyCheckbutton"); + if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoWaitingforkeyCheckbutton"); return; } + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n->status.waitingforkey); + + w = glade_xml_get_widget(x, "HostInfoVisitedCheckbutton"); + if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoVisitedCheckbutton"); return; } + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n->status.visited); + + w = glade_xml_get_widget(x, "HostInfoReachableCheckbutton"); + if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoReachableCheckbutton"); return; } + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n->status.reachable); + + w = glade_xml_get_widget(x, "HostInfoIndirectCheckbutton"); + if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoIndirectCheckbutton"); return; } + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n->status.indirect); + + w = glade_xml_get_widget(x, "HostInfoVisibleCheckbutton"); + if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoVisibleCheckbutton"); return; } +/* gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n->status.visible); */ + + w = glade_xml_get_widget(x, "HostInfoTCPOnlyCheckbutton"); + if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoTCPOnlyCheckbutton"); return; } + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), (n->options & OPTION_TCPONLY) != 0); + + w = glade_xml_get_widget(x, "HostInfoIndirectdataCheckbutton"); + if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoIndirectdataCheckbutton"); return; } + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), (n->options & OPTION_INDIRECT) != 0); + +/* w = glade_xml_get_widget(x, "HostInfoWindow"); */ +/* if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostInfoWindow"); return; } */ +/* glade_xml_signal_connect_data(x, "on_HostInfoCloseButton_clicked", if_hostinfoclosebutton_clicked, (gpointer)w); */ + w = glade_xml_get_widget(x, "HostConnectionsCList"); + if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "HostConnectionsCList"); return; } + for(avlnode = n->edge_tree->head; avlnode; avlnode = avlnode->next) + { + if(((edge_t*)(avlnode->data))->to.node == n) + l[0] = ((edge_t*)(avlnode->data))->from.node->name; + else + l[0] = ((edge_t*)(avlnode->data))->to.node->name; + gtk_clist_append(GTK_CLIST(w), l); + } +} + +void on_settings1_activate(GtkMenuItem *mi, gpointer data) +{ + GtkWidget *w; + GladeXML *x; + + x = glade_xml_new(INTERFACE_FILE, "PropertyBox"); + if(x == NULL) + { + log(0, TLOG_ERROR, + _("Could not find widget `%s'"), + "PropertyBox"); + return; + } + + w = glade_xml_get_widget(x, "PropertyBox"); + if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "PropertyBox"); return; } + glade_xml_signal_autoconnect(x); +} + +void on_logcontext_clear_activate(GtkMenuItem *mi, gpointer data) +{ + GtkWidget *l = glade_xml_get_widget(xml, "Messages"); + if(!l) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "Messages"); return; } + gtk_editable_delete_text(GTK_EDITABLE(l), 0, -1); /* Delete from 0 to end of buffer */ + log_inited = 0; +} + +void on_logcontext_follow_activate(GtkMenuItem *mi, gpointer data) +{ + follow_log = !follow_log; +} + +void on_messages_button_press_event(GtkWidget *w, GdkEventButton *event, gpointer data) +{ + GladeXML *x; + GtkWidget *menu; + + if (event->button == 3) + { + x = glade_xml_new(INTERFACE_FILE, "LogContextMenu"); + if(x == NULL) + { + log(0, TLOG_ERROR, + _("Could not find widget `%s'"), + "LogContextMenu"); + return; + } + + menu = glade_xml_get_widget(x, "LogContextMenu"); + if(!menu) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "LogContextMenu"); return; } + + glade_xml_signal_connect_data(x, "on_logcontext_clear_activate", on_logcontext_clear_activate, (gpointer)x); + glade_xml_signal_connect_data(x, "on_logcontext_follow_activate", on_logcontext_follow_activate, (gpointer)x); + w = glade_xml_get_widget(x, "LogContextFollow"); + if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "LogContextFollow"); return; } + GTK_CHECK_MENU_ITEM(w)->active = follow_log; + gnome_popup_menu_do_popup_modal(menu, NULL, NULL, event, NULL); + gtk_widget_destroy(menu); + } +} + +void on_canvascontext_shuffle_activate(GtkMenuItem *mi, gpointer data) +{ + avl_node_t *avlnode; + double newx, newy; + + for(avlnode = node_tree->head; avlnode; avlnode = avlnode->next) + { + newx = ((double)random()) / ((double)RAND_MAX) * 500.0; + newy = ((double)random()) / ((double)RAND_MAX) * 300.0; + ((struct if_node_data*)((node_t *)(avlnode->data))->data)->x = newx; + ((struct if_node_data*)((node_t *)(avlnode->data))->data)->y = newy; + + if(!((struct if_node_data*)((node_t*)(avlnode->data)))->visible) + continue; + + x[((struct if_node_data*)((node_t*)(avlnode->data))->data)->id] = newx; + y[((struct if_node_data*)((node_t*)(avlnode->data))->data)->id] = newy; + } + inited = 0; + build_graph = 1; +} + +void on_canvascontext_keep_drawing_activate(GtkMenuItem *mi, gpointer data) +{ + keep_drawing = !keep_drawing; +} + +void on_canvascontext_minus50_activate(GtkMenuItem *mi, gpointer data) +{ + canvas_zoom *= 0.50; + gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), canvas_zoom); +} + +void on_canvascontext_minus25_activate(GtkMenuItem *mi, gpointer data) +{ + canvas_zoom *= 0.75; + gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), canvas_zoom); +} + +void on_canvascontext_minus10_activate(GtkMenuItem *mi, gpointer data) +{ + canvas_zoom *= 0.90; + gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), canvas_zoom); +} + +void on_canvascontext_default_activate(GtkMenuItem *mi, gpointer data) +{ + canvas_zoom = 1.00; + gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), 1.00); +} + +void on_canvascontext_plus10_activate(GtkMenuItem *mi, gpointer data) +{ + canvas_zoom *= 1.10; + gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), canvas_zoom); +} + +void on_canvascontext_plus25_activate(GtkMenuItem *mi, gpointer data) +{ + canvas_zoom *= 1.25; + gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), canvas_zoom); +} + +void on_canvascontext_plus50_activate(GtkMenuItem *mi, gpointer data) +{ + canvas_zoom *= 1.50; + gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), canvas_zoom); +} + +void on_canvas_button_press_event(GtkWidget *w, GdkEventButton *event, gpointer data) +{ + GladeXML *x; + GtkWidget *menu; + + if (event->button == 3) + { + x = glade_xml_new(INTERFACE_FILE, "CanvasContextMenu"); + if(x == NULL) + { + log(0, TLOG_ERROR, + _("Could not find widget `%s'"), + "CanvasContextMenu"); + return; + } + + menu = glade_xml_get_widget(x, "CanvasContextMenu"); + if(!menu) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "CanvasContextMenu"); return; } + + glade_xml_signal_autoconnect(x); + glade_xml_signal_connect_data(x, "on_canvascontext_shuffle_activate", on_canvascontext_shuffle_activate, (gpointer)x); + glade_xml_signal_connect_data(x, "on_canvascontext_keep_drawing_activate", on_canvascontext_keep_drawing_activate, (gpointer)x); + w = glade_xml_get_widget(x, "CanvasContextKeepDrawing"); + if(!w) { log(0, TLOG_ERROR, _("Couldn't find widget `%s'"), "CanvasContextKeepDrawing"); return; } + GTK_CHECK_MENU_ITEM(w)->active = keep_drawing; + gnome_popup_menu_do_popup_modal(menu, NULL, NULL, event, NULL); + gtk_widget_destroy(menu); + } +} + +void on_nodetree_button_press_event(GtkWidget *w, GdkEventButton *event, gpointer data) +{ + GtkCTreeNode *node; + int row, col; + gpointer lt; + GladeXML *x; + + gtk_clist_get_selection_info(GTK_CLIST(w), event->x, event->y, + &row, &col); + + node = gtk_ctree_node_nth(GTK_CTREE(w), row); + if(node == NULL) + return; + lt = gtk_ctree_node_get_row_data(GTK_CTREE(w), node); + if(event->type == GDK_2BUTTON_PRESS && event->button == 1) + { + /* Double left click on an item */ + if(lt == NULL) + /* this is only a branch, double click wil (un)expand. */ + return; + + if(GTK_CTREE_ROW(node)->parent == hosts_ctn) + { + x = ((struct if_node_data*)(((node_t*)lt)->data))->hi_xml = glade_xml_new(INTERFACE_FILE, "HostInfoWindow"); + if(x == NULL) + { + log(0, TLOG_ERROR, + _("Could not find widget `%s'"), + "HostInfoWindow"); + return; + } + glade_xml_signal_autoconnect(x); + update_hostinfo_dialog(x, (node_t*)lt); + } + else + { + log(0, TLOG_ERROR, + "WHERE did you click?!"); + } + /* so now we have access to all the data we want. */ +/* gldap_show_details(lt); */ + return; + } +/* else */ +/* if (event->button == 3) */ +/* { */ +/* GtkWidget *temp_menu; */ +/* temp_menu = gnome_popup_menu_new(data); */ +/* gnome_popup_menu_do_popup_modal(temp_menu, NULL, NULL, event, NULL); */ +/* gtk_widget_destroy(temp_menu); */ +/* } */ +} + +void on_exit1_activate(GtkMenuItem *mi, gpointer data) +{ + close_network_connections(); + gtk_exit(0); +} + +void on_info1_activate(GtkMenuItem *mi, gpointer data) +{ + GladeXML *x; + x = glade_xml_new(INTERFACE_FILE, "AboutWindow"); + if(x == NULL) + { + log(0, TLOG_ERROR, + _("Could not find widget `%s'"), + "AboutWindow"); + return; + } } int init_interface(void) { char *l[1]; + glade_gnome_init(); + + xml = glade_xml_new("pokey.glade", "AppWindow"); + if(!xml) - return -1; + { + log(0, TLOG_ERROR, + _("Something bad happened while creating the interface.\n")); + return -1; + } nodetree = glade_xml_get_widget(xml, "NodeTree"); if(!nodetree) { - fprintf(stderr, _("Could not find widget `NodeTree'\n")); + log(0, TLOG_ERROR, + _("Could not find widget `%s'"), + "NodeTree"); return -1; } gtk_clist_freeze(GTK_CLIST(nodetree)); - l[0] = _("Hosts"); hosts_ctn = gtk_ctree_insert_node(GTK_CTREE(nodetree), NULL, NULL, l, 1, NULL, NULL, NULL, NULL, FALSE, TRUE); - l[0] = _("Subnets"); - subnets_ctn = gtk_ctree_insert_node(GTK_CTREE(nodetree), - NULL, NULL, l, 1, - NULL, NULL, NULL, NULL, - FALSE, TRUE); - l[0] = _("Connections"); - conns_ctn = gtk_ctree_insert_node(GTK_CTREE(nodetree), - NULL, NULL, l, 1, - NULL, NULL, NULL, NULL, - FALSE, TRUE); - gtk_clist_thaw(GTK_CLIST(nodetree)); create_canvas(); - gtk_signal_connect(GTK_OBJECT(nodetree), "button_press_event", if_nodetree_button_press_event, NULL); + glade_xml_signal_autoconnect(xml); log_add_hook(log_gtk); log_del_hook(log_default); + + add_hook("node-add", if_node_add); + add_hook("node-del", if_node_del); + add_hook("subnet-add", if_subnet_add); + add_hook("subnet-del", if_subnet_del); + add_hook("edge-add", if_edge_add); + add_hook("edge-del", if_edge_del); + add_hook("node-visible", if_node_visible); + add_hook("node-invisible", if_node_invisible); return 0; } @@ -241,10 +601,10 @@ static gint item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) gnome_canvas_item_ungrab(item, event->button.time); dragging = FALSE; n = (node_t *)gtk_object_get_user_data(GTK_OBJECT(item)); - n->x = item_x; - n->y = item_y; - x[n->id] = item_x; - y[n->id] = item_y; + ((struct if_node_data*)(n->data))->x = item_x; + ((struct if_node_data*)(n->data))->y = item_y; + x[((struct if_node_data*)(n->data))->id] = item_x; + y[((struct if_node_data*)(n->data))->id] = item_y; build_graph = 1; break; @@ -270,7 +630,7 @@ void if_node_create(node_t *n) "y1", -08.0, "x2", 30.0, "y2", 08.0, - "fill_color_rgba", 0x5f9ea0ff, + "fill_color_rgba", 0x5f9ea080, "outline_color", "black", "width_pixels", 0, NULL); @@ -285,47 +645,48 @@ void if_node_create(node_t *n) "font", "-*-verdana-medium-r-*-*-10-*-*-*-*-*-iso8859-1", NULL); - n->item = GNOME_CANVAS_ITEM(group); - n->x = n->y = 0.0; + ((struct if_node_data*)(n->data))->item = GNOME_CANVAS_ITEM(group); + ((struct if_node_data*)(n->data))->x = ((struct if_node_data*)(n->data))->y = 0.0; gtk_object_set_user_data(GTK_OBJECT(group), (gpointer)n); - gtk_signal_connect(GTK_OBJECT(n->item), "event", (GtkSignalFunc) item_event, NULL); + gtk_signal_connect(GTK_OBJECT(((struct if_node_data*)(n->data))->item), "event", (GtkSignalFunc) item_event, NULL); - gnome_canvas_item_hide(GNOME_CANVAS_ITEM(n->item)); + gnome_canvas_item_hide(GNOME_CANVAS_ITEM(((struct if_node_data*)(n->data))->item)); } -void if_node_visible(node_t *n) +void if_node_visible(const char *hooktype, va_list ap) { int i; avl_node_t *avlnode; double newx, newy; + node_t *n = va_arg(ap, node_t*); - if(!n->item) + if(!((struct if_node_data*)(n->data))->item) return; - if(n->status.visible) + if(((struct if_node_data*)(n->data))->visible) /* This node is already shown */ return; - n->status.visible = 1; + ((struct if_node_data*)(n->data))->visible = 1; newx = 250.0 + 200.0 * sin(number_of_nodes / 10.0 * M_PI); newy = 150.0 - 100.0 * cos(number_of_nodes / 10.0 * M_PI); - gnome_canvas_item_move(GNOME_CANVAS_ITEM(n->item), newx - n->x, newy - n->y); - n->x = newx; - n->y = newy; + gnome_canvas_item_move(GNOME_CANVAS_ITEM(((struct if_node_data*)(n->data))->item), newx - ((struct if_node_data*)(n->data))->x, newy - ((struct if_node_data*)(n->data))->y); + ((struct if_node_data*)(n->data))->x = newx; + ((struct if_node_data*)(n->data))->y = newy; for(i = 0, avlnode = node_tree->head; avlnode; avlnode = avlnode->next, i++) { - if(!((node_t*)(avlnode->data))->status.visible) + if(!((struct if_node_data*)(((node_t*)(avlnode->data))->data))->visible) continue; nodes[i] = (node_t *)(avlnode->data); - nodes[i]->id = i; + ((struct if_node_data*)(nodes[i]->data))->id = i; } number_of_nodes = i; - gnome_canvas_item_show(GNOME_CANVAS_ITEM(n->item)); + gnome_canvas_item_show(GNOME_CANVAS_ITEM(((struct if_node_data*)(n->data))->item)); gnome_canvas_update_now(GNOME_CANVAS(canvas)); /* (Re)start calculations */ @@ -333,31 +694,32 @@ void if_node_visible(node_t *n) build_graph = 1; } -void if_node_invisible(node_t *n) +void if_node_invisible(const char *hooktype, va_list ap) { int i; avl_node_t *avlnode; + node_t *n = va_arg(ap, node_t*); - if(!n->item) + if(!((struct if_node_data*)(n->data))->item) return; - if(!n->status.visible) + if(!((struct if_node_data*)(n->data))->visible) /* This node is already invisible */ return; - n->status.visible = 0; + ((struct if_node_data*)(n->data))->visible = 0; for(i = 0, avlnode = node_tree->head; avlnode; avlnode = avlnode->next, i++) { - if(!((node_t*)(avlnode->data))->status.visible) + if(!((struct if_node_data*)((node_t*)(avlnode->data))->data)->visible) continue; nodes[i] = (node_t *)(avlnode->data); - nodes[i]->id = i; + ((struct if_node_data*)(nodes[i]->data))->id = i; } number_of_nodes = i; - gnome_canvas_item_hide(GNOME_CANVAS_ITEM(n->item)); + gnome_canvas_item_hide(GNOME_CANVAS_ITEM(((struct if_node_data*)(n->data))->item)); gnome_canvas_update_now(GNOME_CANVAS(canvas)); /* (Re)start calculations */ @@ -365,57 +727,89 @@ void if_node_invisible(node_t *n) build_graph = 1; } -GtkCTreeNode *if_node_add(node_t *n) +void if_node_add(const char *hooktype, va_list ap) { + node_t *n = va_arg(ap, node_t*); char *l[1]; - GtkCTreeNode *ctn; + struct if_node_data *nd; if(!xml) - return NULL; + return; + nd = xmalloc(sizeof(*nd)); l[0] = n->name; gtk_clist_freeze(GTK_CLIST(nodetree)); - n->host_ctn = gtk_ctree_insert_node(GTK_CTREE(nodetree), - hosts_ctn, NULL, l, 1, - NULL, NULL, NULL, NULL, - FALSE, FALSE); + nd->ctn = gtk_ctree_insert_node(GTK_CTREE(nodetree), + hosts_ctn, NULL, l, 1, + NULL, NULL, NULL, NULL, + FALSE, FALSE); gtk_clist_thaw(GTK_CLIST(nodetree)); + gtk_ctree_node_set_row_data(GTK_CTREE(nodetree), nd->ctn, n); - if_node_create(n); - if_node_visible(n); + n->data = (void*)nd; - return ctn; + if_node_create(n); + if_node_visible(hooktype, ap); } -void if_node_del(node_t *n) +void if_node_del(const char *hooktype, va_list ap) { - gtk_clist_freeze(GTK_CLIST(nodetree)); - if(n->host_ctn) - gtk_ctree_remove_node(GTK_CTREE(nodetree), n->host_ctn); - if(n->conn_ctn) - gtk_ctree_remove_node(GTK_CTREE(nodetree), n->conn_ctn); - if(n->subnet_ctn) - gtk_ctree_remove_node(GTK_CTREE(nodetree), n->subnet_ctn); - gtk_clist_thaw(GTK_CLIST(nodetree)); + node_t *n = va_arg(ap, node_t*); + struct if_node_data *nd; + + nd = (struct if_node_data*)(n->data); + if(nd &&nd->ctn) + { + gtk_clist_freeze(GTK_CLIST(nodetree)); + gtk_ctree_remove_node(GTK_CTREE(nodetree), nd->ctn); + gtk_clist_thaw(GTK_CLIST(nodetree)); + } + + if_node_invisible(hooktype, ap); - if_node_invisible(n); + free(nd); + n->data = NULL; } -void if_subnet_add(subnet_t *subnet) +void if_subnet_add(const char *hooktype, va_list ap) { char *l[1]; - + subnet_t *subnet = va_arg(ap, subnet_t*); + struct if_subnet_data *sd; + GtkCTreeNode *parent; + + sd = xmalloc(sizeof(*sd)); l[0] = net2str(subnet); + parent = subnet->owner->data ? + ((struct if_subnet_data*)(subnet->owner->data))->ctn + : NULL; + gtk_clist_freeze(GTK_CLIST(nodetree)); - gtk_ctree_insert_node(GTK_CTREE(nodetree), - subnets_ctn, NULL, l, 1, - NULL, NULL, NULL, NULL, - TRUE, FALSE); + sd->ctn = gtk_ctree_insert_node(GTK_CTREE(nodetree), + parent, NULL, l, 1, + NULL, NULL, NULL, NULL, + TRUE, FALSE); gtk_clist_thaw(GTK_CLIST(nodetree)); + gtk_ctree_node_set_row_data(GTK_CTREE(nodetree), sd->ctn, subnet); + + subnet->data = (void*)sd; } -void if_subnet_del(subnet_t *subnet) +void if_subnet_del(const char *hooktype, va_list ap) { + subnet_t *subnet = va_arg(ap, subnet_t*); + struct if_subnet_data *sd; + + sd = (struct if_subnet_data*)(subnet->data); + if(sd && sd->ctn) + { + gtk_clist_freeze(GTK_CLIST(nodetree)); + gtk_ctree_remove_node(GTK_CTREE(nodetree), sd->ctn); + gtk_clist_thaw(GTK_CLIST(nodetree)); + } + + free(sd); + subnet->data = NULL; } void redraw_edges(void) @@ -424,6 +818,7 @@ void redraw_edges(void) GnomeCanvasPoints *points; avl_node_t *avlnode; edge_t *e; + struct if_node_data *fd, *td; if(edge_group) gtk_object_destroy(GTK_OBJECT(edge_group)); @@ -438,22 +833,24 @@ void redraw_edges(void) for(avlnode = edge_tree->head; avlnode; avlnode = avlnode->next) { e = (edge_t *)avlnode->data; + fd = (struct if_node_data*)(e->from.node->data); + td = (struct if_node_data*)(e->to.node->data); - if(!e->from.node->status.visible || - !e->to.node->status.visible) - /* We shouldn't draw this line */ - continue; +/* if(!e->from.node->status.visible || */ +/* !e->to.node->status.visible) */ +/* /\* We shouldn't draw this line *\/ */ +/* continue; */ points = gnome_canvas_points_new(2); - points->coords[0] = e->from.node->x; - points->coords[1] = e->from.node->y; - points->coords[2] = e->to.node->x; - points->coords[3] = e->to.node->y; + points->coords[0] = fd->x; + points->coords[1] = fd->y; + points->coords[2] = td->x; + points->coords[3] = td->y; gnome_canvas_item_new(group, gnome_canvas_line_get_type(), "points", points, - "fill_color_rgba", 0xe080c0ff, + "fill_color_rgba", 0xe080c080, "width_pixels", 2, NULL); gnome_canvas_points_unref(points); @@ -464,7 +861,7 @@ void redraw_edges(void) edge_group = group; } -void if_edge_add(edge_t *e) +void if_edge_add(const char *hooktype, va_list ap) { redraw_edges(); @@ -472,7 +869,7 @@ void if_edge_add(edge_t *e) build_graph = 1; } -void if_edge_del(edge_t *e) +void if_edge_del(const char *hooktype, va_list ap) { redraw_edges(); @@ -484,11 +881,11 @@ void if_move_node(node_t *n, double dx, double dy) { double newx, newy; - newx = n->x + dx; - newy = n->y + dy; - gnome_canvas_item_move(GNOME_CANVAS_ITEM(n->item), newx - n->x, newy - n->y); - n->x = newx; - n->y = newy; + newx = ((struct if_node_data*)(n->data))->x + dx; + newy = ((struct if_node_data*)(n->data))->y + dy; + gnome_canvas_item_move(GNOME_CANVAS_ITEM(((struct if_node_data*)(n->data))->item), newx - ((struct if_node_data*)(n->data))->x, newy - ((struct if_node_data*)(n->data))->y); + ((struct if_node_data*)(n->data))->x = newx; + ((struct if_node_data*)(n->data))->y = newy; } #define X_MARGIN 50.0 @@ -505,17 +902,17 @@ void set_zooming(void) minx = miny = maxx = maxy = 0.0; for(i = 0; i < number_of_nodes; i++) { - if(nodes[i]->x < minx) - minx = nodes[i]->x; + if(((struct if_node_data*)(nodes[i]->data))->x < minx) + minx = ((struct if_node_data*)(nodes[i]->data))->x; else - if(nodes[i]->x > maxx) - maxx = nodes[i]->x; + if(((struct if_node_data*)(nodes[i]->data))->x > maxx) + maxx = ((struct if_node_data*)(nodes[i]->data))->x; - if(nodes[i]->y < miny) - miny = nodes[i]->y; + if(((struct if_node_data*)(nodes[i]->data))->y < miny) + miny = ((struct if_node_data*)(nodes[i]->data))->y; else - if(nodes[i]->y > maxy) - maxy = nodes[i]->y; + if(((struct if_node_data*)(nodes[i]->data))->y > maxy) + maxy = ((struct if_node_data*)(nodes[i]->data))->y; } if(minx > ominx - X_MARGIN_BUFFER && ominx > minx) @@ -595,15 +992,18 @@ void if_build_graph(void) { int i, j, p, max_i; double delta_m, max_delta_m; - double dx, dy, s, L, max_d, old_x, old_y; + double dx, dy, s, L, min_d, old_x, old_y; edge_t *e; + if(!keep_drawing) + return; + if(!inited) { for(i = 0; i < number_of_nodes; i++) { - x[i] = nodes[i]->x; - y[i] = nodes[i]->y; + x[i] = ((struct if_node_data*)(nodes[i]->data))->x; + y[i] = ((struct if_node_data*)(nodes[i]->data))->y; } /* Initialize Floyd */ @@ -645,19 +1045,19 @@ void if_build_graph(void) } } - max_d = 0.0; + min_d = 0.0; for(i = 0; i < number_of_nodes; i++) for(j = i + 1; j < number_of_nodes; j++) - if(d[i][j] > max_d && d[i][j] < INFINITY) - max_d = d[i][j]; + if(d[i][j] < min_d && d[i][j] > 0) + min_d = d[i][j]; - L = 300.0 / log(max_d); + L = 5.0 / sqrt(min_d + 1.0); for(i = 0; i < number_of_nodes; i++) { for(j = i + 1; j < number_of_nodes; j++) { - d[i][j] = d[j][i] = log(d[i][j]+1.0); + d[i][j] = d[j][i] = sqrt(d[i][j]+1.0); l[i][j] = l[j][i] = L * d[i][j]; k[i][j] = k[j][i] = K / (d[i][j] * d[i][j]); } @@ -679,7 +1079,10 @@ void if_build_graph(void) } if(max_delta_m <= epsilon) - build_graph = 0; + { + fprintf(stderr, "Graph building is done; max_delta_m = %f\n", max_delta_m); + build_graph = 0; + } else { int iter = 0, maxiter = 20; diff --git a/src/pokey/interface.h b/src/pokey/interface.h index 199ca516..3720b227 100644 --- a/src/pokey/interface.h +++ b/src/pokey/interface.h @@ -17,17 +17,21 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: interface.h,v 1.1 2002/04/11 14:23:56 zarq Exp $ + $Id: interface.h,v 1.2 2002/04/28 12:46:26 zarq Exp $ */ #ifndef __TINC_INTERFACE_H__ #define __TINC_INTERFACE_H__ #include +#include +#include #include "node.h" #include "edge.h" +#define INTERFACE_FILE "pokey.glade" + typedef struct graph_t { struct graph_t *attractors[20]; struct graph_t *repellors[20]; @@ -36,20 +40,23 @@ typedef struct graph_t { node_t *node; } graph_t; -extern int build_graph; +struct if_subnet_data { + GnomeCanvasItem *item; /* The gnome canvas item associated with the line */ + GtkCTreeNode *ctn; +}; -void log_message(int, const char *, ...); -GtkCTreeNode *if_node_add(node_t *); -void if_node_del(node_t *); -void if_subnet_add(subnet_t *); -void if_subnet_del(subnet_t *); -void if_edge_add(edge_t *); -void if_edge_del(edge_t *); +struct if_node_data { + double x, y; + int visible; + int id; + GnomeCanvasItem *item; + GtkCTreeNode *ctn; + GladeXML *hi_xml; +}; -void if_build_graph(void); -void if_graph_add_node(node_t *); -void if_graph_add_edge(edge_t *); +extern int build_graph; +void if_build_graph(void); int init_interface(void); #endif /* __TINC_INTERFACE_H__ */ diff --git a/src/pokey/logging.c b/src/pokey/logging.c new file mode 100644 index 00000000..81a4fda2 --- /dev/null +++ b/src/pokey/logging.c @@ -0,0 +1,103 @@ +/* + logging.c -- log messages to e.g. syslog + Copyright (C) 2001-2002 Guus Sliepen , + 2001-2002 Ivo Timmermans + + 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: logging.c,v 1.1 2002/04/28 12:46:26 zarq Exp $ +*/ + +#include "config.h" + +#include +#include +#include +#include + +#include + +#include "logging.h" + +avl_tree_t *log_hooks_tree = NULL; + +int debug_lvl = 0; + +int log_compare(const void *a, const void *b) +{ + if(a < b) + return -1; + if(a > b) + return 1; + return 0; +} + +void log(int level, int priority, char *fmt, ...) +{ + avl_node_t *avlnode; + va_list args; + + va_start(args, fmt); + for(avlnode = log_hooks_tree->head; avlnode; avlnode = avlnode->next) + { + assert(avlnode->data); + ((log_function_t*)(avlnode->data))(level, priority, fmt, args); + } + va_end(args); +} + +void log_add_hook(log_function_t *fn) +{ + if(!log_hooks_tree) + log_hooks_tree = avl_alloc_tree(log_compare, NULL); + + avl_insert(log_hooks_tree, (void*)fn); +} + +void log_del_hook(log_function_t *fn) +{ + avl_delete(log_hooks_tree, (void*)fn); +} + +void log_default(int level, int priority, char *fmt, va_list ap) +{ + if(debug_lvl >= level) + vfprintf(stderr, fmt, ap); +} + +void log_syslog(int level, int priority, char *fmt, va_list ap) +{ + const int priorities[] = { LOG_DEBUG, LOG_INFO, LOG_NOTICE, LOG_ERR, LOG_CRIT }; + + if(debug_lvl >= level) + vsyslog(priorities[priority], fmt, ap); +} + +void tinc_syslog(int priority, char *fmt, ...) +{ + /* Mapping syslog prio -> tinc prio */ + const int priorities[] = { TLOG_CRITICAL, TLOG_CRITICAL, TLOG_CRITICAL, TLOG_ERROR, + TLOG_NOTICE, TLOG_NOTICE, TLOG_INFO, TLOG_DEBUG }; + avl_node_t *avlnode; + va_list args; + + va_start(args, fmt); + for(avlnode = log_hooks_tree->head; avlnode; avlnode = avlnode->next) + { + assert(avlnode->data); + ((log_function_t*)(avlnode->data))(0, priorities[priority], fmt, args); + } + va_end(args); +} diff --git a/src/pokey/meta.c b/src/pokey/meta.c new file mode 100644 index 00000000..c3138e3a --- /dev/null +++ b/src/pokey/meta.c @@ -0,0 +1,190 @@ +/* + meta.c -- handle the meta communication + Copyright (C) 2000-2002 Guus Sliepen , + 2000-2002 Ivo Timmermans + + 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: meta.c,v 1.1 2002/04/28 12:46:26 zarq Exp $ +*/ + +#include "config.h" +#include +#include + +#include +#include +#include +/* This line must be below the rest for FreeBSD */ +#include +#include + +#include + +#include "net.h" +#include "connection.h" +#include "interface.h" +#include "system.h" +#include "protocol.h" +#include "logging.h" + +int send_meta(connection_t *c, char *buffer, int length) +{ + char *bufp; + int outlen; + char outbuf[MAXBUFSIZE]; +cp + log(DEBUG_META, TLOG_DEBUG, + _("Sending %d bytes of metadata to %s (%s)"), + length, c->name, c->hostname); + + if(c->status.encryptout) + { + EVP_EncryptUpdate(c->outctx, outbuf, &outlen, buffer, length); + bufp = outbuf; + length = outlen; + } + else + bufp = buffer; + + if(write(c->socket, bufp, length) < 0) + { + syslog(LOG_ERR, _("Sending meta data to %s (%s) failed: %s"), c->name, c->hostname, strerror(errno)); + return -1; + } +cp + return 0; +} + +void broadcast_meta(connection_t *from, char *buffer, int length) +{ + avl_node_t *node; + connection_t *c; +cp + for(node = connection_tree->head; node; node = node->next) + { + c = (connection_t *)node->data; + if(c != from && c->status.active) + send_meta(c, buffer, length); + } +cp +} + +int receive_meta(connection_t *c) +{ + int x, l = sizeof(x); + int oldlen, i; + int lenin, reqlen; + int decrypted = 0; + char inbuf[MAXBUFSIZE]; +cp + if(getsockopt(c->socket, SOL_SOCKET, SO_ERROR, &x, &l) < 0) + { + syslog(LOG_ERR, _("This is a bug: %s:%d: %d:%s %s (%s)"), __FILE__, __LINE__, c->socket, strerror(errno), + c->name, c->hostname); + return -1; + } + if(x) + { + syslog(LOG_ERR, _("Metadata socket error for %s (%s): %s"), + c->name, c->hostname, strerror(x)); + return -1; + } + + /* Strategy: + - Read as much as possible from the TCP socket in one go. + - Decrypt it. + - Check if a full request is in the input buffer. + - If yes, process request and remove it from the buffer, + then check again. + - If not, keep stuff in buffer and exit. + */ + + lenin = read(c->socket, c->buffer + c->buflen, MAXBUFSIZE - c->buflen); + + if(lenin<=0) + { + if(lenin==0) + { + if(debug_lvl >= DEBUG_CONNECTIONS) + syslog(LOG_NOTICE, _("Connection closed by %s (%s)"), + c->name, c->hostname); + } + else + if(errno==EINTR) + return 0; + else + syslog(LOG_ERR, _("Metadata socket read error for %s (%s): %s"), + c->name, c->hostname, strerror(errno)); + + return -1; + } + + oldlen = c->buflen; + c->buflen += lenin; + + while(lenin) + { + /* Decrypt */ + + if(c->status.decryptin && !decrypted) + { + EVP_DecryptUpdate(c->inctx, inbuf, &lenin, c->buffer + oldlen, lenin); + memcpy(c->buffer + oldlen, inbuf, lenin); + decrypted = 1; + } + + /* Otherwise we are waiting for a request */ + + reqlen = 0; + + for(i = oldlen; i < c->buflen; i++) + { + if(c->buffer[i] == '\n') + { + c->buffer[i] = '\0'; /* replace end-of-line by end-of-string so we can use sscanf */ + reqlen = i + 1; + break; + } + } + + if(reqlen) + { + if(receive_request(c)) + return -1; + + c->buflen -= reqlen; + lenin -= reqlen; + memmove(c->buffer, c->buffer + reqlen, c->buflen); + oldlen = 0; + continue; + } + else + { + break; + } + } + + if(c->buflen >= MAXBUFSIZE) + { + syslog(LOG_ERR, _("Metadata read buffer overflow for %s (%s)"), + c->name, c->hostname); + return -1; + } + + c->last_ping_time = now; +cp + return 0; +} diff --git a/src/pokey/meta.h b/src/pokey/meta.h new file mode 100644 index 00000000..367cecfd --- /dev/null +++ b/src/pokey/meta.h @@ -0,0 +1,32 @@ +/* + meta.h -- header for meta.c + Copyright (C) 2000-2002 Guus Sliepen , + 2000-2002 Ivo Timmermans + + 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: meta.h,v 1.1 2002/04/28 12:46:26 zarq Exp $ +*/ + +#ifndef __TINC_META_H__ +#define __TINC_META_H__ + +#include "connection.h" + +extern int send_meta(connection_t *, const char *, int); +extern int broadcast_meta(connection_t *, const char *, int); +extern int receive_meta(connection_t *); + +#endif /* __TINC_META_H__ */ diff --git a/src/pokey/net.c b/src/pokey/net.c new file mode 100644 index 00000000..6ada741b --- /dev/null +++ b/src/pokey/net.c @@ -0,0 +1,467 @@ +/* + net.c -- most of the network code + Copyright (C) 1998-2002 Ivo Timmermans , + 2000-2002 Guus Sliepen + + 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: net.c,v 1.1 2002/04/28 12:46:26 zarq Exp $ +*/ + +#include "config.h" + +#include +#include +#include +#include +#ifdef HAVE_LINUX + #include + #include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +/* SunOS really wants sys/socket.h BEFORE net/if.h, + and FreeBSD wants these lines below the rest. */ +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +#include "conf.h" +#include "interface.h" +#include "connection.h" +#include "meta.h" +#include "net.h" +#include "netutl.h" +#include "process.h" +#include "protocol.h" +#include "subnet.h" +#include "graph.h" +#include "process.h" +#include "route.h" +#include "device.h" +#include "event.h" +#include "logging.h" + +#include "system.h" + +int do_prune = 0; +int do_purge = 0; +int sighup = 0; +int sigalrm = 0; + +time_t now = 0; + +/* + put all file descriptors in an fd_set array +*/ +void build_fdset(fd_set *fs) +{ + avl_node_t *node; + connection_t *c; + int i; +cp + FD_ZERO(fs); + + for(node = connection_tree->head; node; node = node->next) + { + c = (connection_t *)node->data; + FD_SET(c->socket, fs); + } + + for(i = 0; i < listen_sockets; i++) + { + FD_SET(listen_socket[i].tcp, fs); + FD_SET(listen_socket[i].udp, fs); + } +cp +} + +/* Purge edges and subnets of unreachable nodes. Use carefully. */ + +void purge(void) +{ + avl_node_t *nnode, *nnext, *enode, *enext, *snode, *snext, *cnode; + node_t *n; + edge_t *e; + subnet_t *s; + connection_t *c; +cp + log(DEBUG_PROTOCOL, TLOG_DEBUG, + _("Purging unreachable nodes")); + + for(nnode = node_tree->head; nnode; nnode = nnext) + { + nnext = nnode->next; + n = (node_t *)nnode->data; + + if(!n->status.reachable) + { + if(debug_lvl >= DEBUG_SCARY_THINGS) + syslog(LOG_DEBUG, _("Purging node %s (%s)"), n->name, n->hostname); + + for(snode = n->subnet_tree->head; snode; snode = snext) + { + snext = snode->next; + s = (subnet_t *)snode->data; + + for(cnode = connection_tree->head; cnode; cnode = cnode->next) + { + c = (connection_t *)cnode->data; + if(c->status.active) + send_del_subnet(c, s); + } + + subnet_del(n, s); + } + + for(enode = n->edge_tree->head; enode; enode = enext) + { + enext = enode->next; + e = (edge_t *)enode->data; + + for(cnode = connection_tree->head; cnode; cnode = cnode->next) + { + c = (connection_t *)cnode->data; + if(c->status.active) + send_del_edge(c, e); + } + + edge_del(e); + } + + node_del(n); + } + } +cp +} + +/* + Terminate a connection: + - Close the socket + - Remove associated edge and tell other connections about it if report = 1 + - Check if we need to retry making an outgoing connection + - Deactivate the host +*/ +void terminate_connection(connection_t *c, int report) +{ + avl_node_t *node; + connection_t *other; +cp + if(c->status.remove) + return; + + if(debug_lvl >= DEBUG_CONNECTIONS) + syslog(LOG_NOTICE, _("Closing connection with %s (%s)"), + c->name, c->hostname); + + c->status.remove = 1; + + if(c->socket) + close(c->socket); + + if(c->edge) + { + if(report) + { + for(node = connection_tree->head; node; node = node->next) + { + other = (connection_t *)node->data; + if(other->status.active && other != c) + send_del_edge(other, c->edge); + } + } + + edge_del(c->edge); + + /* Run MST and SSSP algorithms */ + + graph(); + } + + /* Check if this was our outgoing connection */ + + if(c->outgoing) + { + retry_outgoing(c->outgoing); + c->outgoing = NULL; + } + + /* Deactivate */ + + c->status.active = 0; + if(c->node) + c->node->connection = NULL; + do_prune = 1; +cp +} + +/* + Check if the other end is active. + If we have sent packets, but didn't receive any, + then possibly the other end is dead. We send a + PING request over the meta connection. If the other + end does not reply in time, we consider them dead + and close the connection. +*/ +void check_dead_connections(void) +{ + avl_node_t *node, *next; + connection_t *c; +cp + for(node = connection_tree->head; node; node = next) + { + next = node->next; + c = (connection_t *)node->data; + if(c->last_ping_time + pingtimeout < now) + { + if(c->status.active) + { + if(c->status.pinged) + { + if(debug_lvl >= DEBUG_PROTOCOL) + syslog(LOG_INFO, _("%s (%s) didn't respond to PING"), + c->name, c->hostname); + c->status.timeout = 1; + terminate_connection(c, 1); + } + else + { + send_ping(c); + } + } + else + { + if(debug_lvl >= DEBUG_CONNECTIONS) + syslog(LOG_WARNING, _("Timeout from %s (%s) during authentication"), + c->name, c->hostname); + terminate_connection(c, 0); + } + } + } +cp +} + +/* + check all connections to see if anything + happened on their sockets +*/ +void check_network_activity(fd_set *f) +{ + connection_t *c; + avl_node_t *node; + int result, i; + int len = sizeof(result); +cp + for(i = 0; i < listen_sockets; i++) + { + if(FD_ISSET(listen_socket[i].tcp, f)) + handle_new_meta_connection(listen_socket[i].tcp); + } + + for(node = connection_tree->head; node; node = node->next) + { + c = (connection_t *)node->data; + + if(c->status.remove) + return; + + if(FD_ISSET(c->socket, f)) + { + if(c->status.connecting) + { + c->status.connecting = 0; + getsockopt(c->socket, SOL_SOCKET, SO_ERROR, &result, &len); + if(!result) + finish_connecting(c); + else + { + if(debug_lvl >= DEBUG_CONNECTIONS) + syslog(LOG_DEBUG, _("Error while connecting to %s (%s): %s"), c->name, c->hostname, strerror(result)); + close(c->socket); + do_outgoing_connection(c); + continue; + } + } + if(receive_meta(c) < 0) + { + terminate_connection(c, c->status.active); + return; + } + } + } +cp +} + +void prune_connections(void) +{ + connection_t *c; + avl_node_t *node, *next; +cp + for(node = connection_tree->head; node; node = next) + { + next = node->next; + c = (connection_t *)node->data; + + if(c->status.remove) + connection_del(c); + } + + if(!connection_tree->head) + purge(); +cp +} + +/* + this is where it all happens... +*/ +void main_loop(void) +{ + fd_set fset; + struct timeval tv; + int r; + time_t last_ping_check; + event_t *event; +cp + last_ping_check = now; + + srand(now); + + for(;;) + { + now = time(NULL); + +/* tv.tv_sec = 1 + (rand() & 7); /\* Approx. 5 seconds, randomized to prevent global synchronisation effects *\/ */ +/* tv.tv_usec = 0; */ + tv.tv_sec = 0; + tv.tv_usec = 50000; + + if(do_prune) + { + prune_connections(); + do_prune = 0; + } + + build_fdset(&fset); + + while(gtk_events_pending()) + if(gtk_main_iteration() == FALSE) + return; + + if((r = select(FD_SETSIZE, &fset, NULL, NULL, &tv)) < 0) + { + if(errno != EINTR) /* because of a signal */ + { + syslog(LOG_ERR, _("Error while waiting for input: %s"), strerror(errno)); + return; + } + } + + if(r > 0) + check_network_activity(&fset); + + if(do_purge) + { + purge(); + do_purge = 0; + } + + /* Let's check if everybody is still alive */ + + if(last_ping_check + pingtimeout < now) + { + check_dead_connections(); + last_ping_check = now; + + if(routing_mode== RMODE_SWITCH) + age_mac(); + + age_past_requests(); + + /* Should we regenerate our key? */ + + if(keyexpires < now) + { + if(debug_lvl >= DEBUG_STATUS) + syslog(LOG_INFO, _("Regenerating symmetric key")); + + RAND_pseudo_bytes(myself->key, myself->keylength); + send_key_changed(myself->connection, myself); + keyexpires = now + keylifetime; + } + } + + + while((event = get_expired_event())) + { + event->handler(event->data); + free(event); + } + + if(sigalrm) + { + syslog(LOG_INFO, _("Flushing event queue")); + + while(event_tree->head) + { + event = (event_t *)event_tree->head->data; + event->handler(event->data); + event_del(event); + } + sigalrm = 0; + } + + if(sighup) + { + sighup = 0; + close_network_connections(); + exit_configuration(&config_tree); + + syslog(LOG_INFO, _("Rereading configuration file and restarting in 5 seconds...")); + sleep(5); + + init_configuration(&config_tree); + + if(read_server_config()) + { + syslog(LOG_ERR, _("Unable to reread configuration file, exitting.")); + exit(1); + } + + if(setup_network_connections()) + return; + + continue; + } + + if(build_graph) + if_build_graph(); + } +cp +} diff --git a/src/pokey/net.h b/src/pokey/net.h new file mode 100644 index 00000000..e80126d4 --- /dev/null +++ b/src/pokey/net.h @@ -0,0 +1,153 @@ +/* + net.h -- header for net.c + Copyright (C) 1998-2002 Ivo Timmermans + 2000-2002 Guus Sliepen + + 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: net.h,v 1.1 2002/04/28 12:46:26 zarq Exp $ +*/ + +#ifndef __TINC_NET_H__ +#define __TINC_NET_H__ + +#include +#include +#include +#include + +#include "config.h" + +#ifdef ENABLE_JUMBOGRAMS + #define MTU 9014 /* 9000 bytes payload + 14 bytes ethernet header */ + #define MAXSIZE 9100 /* MTU + header (seqno) and trailer (CBC padding and HMAC) */ + #define MAXBUFSIZE 9100 /* Must support TCP packets of length 9000. */ +#else + #define MTU 1514 /* 1500 bytes payload + 14 bytes ethernet header */ + #define MAXSIZE 1600 /* MTU + header (seqno) and trailer (CBC padding and HMAC) */ + #define MAXBUFSIZE 2100 /* Quite large but needed for support of keys up to 8192 bits. */ +#endif + +#define MAXSOCKETS 128 /* Overkill... */ + +#define MAXQUEUELENGTH 8 + +typedef struct mac_t +{ + unsigned char x[6]; +} mac_t; + +typedef struct ipv4_t +{ + unsigned char x[4]; +} ipv4_t; + +typedef struct ip_mask_t { + ipv4_t address; + ipv4_t mask; +} ip_mask_t; + +typedef struct ipv6_t +{ + unsigned short x[8]; +} ipv6_t; + +typedef unsigned short port_t; + +typedef short length_t; + +typedef union { + struct sockaddr sa; + struct sockaddr_in in; + struct sockaddr_in6 in6; +} sockaddr_t; + +#ifdef SA_LEN +#define SALEN(s) SA_LEN(&s) +#else +#define SALEN(s) (s.sa_family==AF_INET?sizeof(struct sockaddr_in):sizeof(struct sockaddr_in6)) +#endif + +typedef struct vpn_packet_t { + length_t len; /* the actual number of bytes in the `data' field */ + int priority; /* priority or TOS */ + unsigned int seqno; /* 32 bits sequence number (network byte order of course) */ + unsigned char data[MAXSIZE]; +} vpn_packet_t; + +typedef struct queue_element_t { + void *packet; + struct queue_element_t *prev; + struct queue_element_t *next; +} queue_element_t; + +typedef struct packet_queue_t { + queue_element_t *head; + queue_element_t *tail; +} packet_queue_t; + +typedef struct outgoing_t { + char *name; + int timeout; + struct config_t *cfg; + struct addrinfo *ai; + struct addrinfo *aip; +} outgoing_t; + +typedef struct listen_socket_t { + int tcp; + int udp; + sockaddr_t sa; +} listen_socket_t; + +extern int maxtimeout; +extern int seconds_till_retry; +extern int addressfamily; + +extern char *request_name[]; +extern char *status_text[]; + +#include "connection.h" /* Yes, very strange placement indeed, but otherwise the typedefs get all tangled up */ + +extern listen_socket_t listen_socket[MAXSOCKETS]; +extern int listen_sockets; +extern int keyexpires; +extern int keylifetime; +extern int do_prune; +extern int do_purge; +extern char *myport; +extern time_t now; + +extern void retry_outgoing(outgoing_t *); +extern void handle_incoming_vpn_data(int); +extern void finish_connecting(connection_t *); +extern void do_outgoing_connection(connection_t *); +extern int handle_new_meta_connection(int); +extern int setup_listen_socket(sockaddr_t *); +extern int setup_vpn_in_socket(sockaddr_t *); +extern void send_packet(struct node_t *, vpn_packet_t *); +extern void receive_packet(struct node_t *, vpn_packet_t *); +extern void receive_tcppacket(struct connection_t *, char *, int); +extern void broadcast_packet(struct node_t *, vpn_packet_t *); +extern int setup_network_connections(void); +extern void setup_outgoing_connection(struct outgoing_t *); +extern void try_outgoing_connections(void); +extern void close_network_connections(void); +extern void main_loop(void); +extern void terminate_connection(connection_t *, int); +extern void flush_queue(struct node_t *); +extern int read_rsa_public_key(struct connection_t *); + +#endif /* __TINC_NET_H__ */ diff --git a/src/pokey/net_packet.c b/src/pokey/net_packet.c new file mode 100644 index 00000000..4d9c07e1 --- /dev/null +++ b/src/pokey/net_packet.c @@ -0,0 +1,429 @@ +/* + net_packet.c -- Handles in- and outgoing VPN packets + Copyright (C) 1998-2002 Ivo Timmermans , + 2000-2002 Guus Sliepen + + 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: net_packet.c,v 1.1 2002/04/28 12:46:26 zarq Exp $ +*/ + +#include "config.h" + +#include +#include +#include +#include +#ifdef HAVE_LINUX + #include + #include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +/* SunOS really wants sys/socket.h BEFORE net/if.h, + and FreeBSD wants these lines below the rest. */ +#include +#include +#include + +#include +#include +#include +#include + +#ifndef HAVE_RAND_PSEUDO_BYTES +#define RAND_pseudo_bytes RAND_bytes +#endif + +#include + +#include +#include +#include +#include + +#include "conf.h" +#include "connection.h" +#include "meta.h" +#include "net.h" +#include "netutl.h" +#include "process.h" +#include "protocol.h" +#include "subnet.h" +#include "graph.h" +#include "process.h" +#include "route.h" +#include "device.h" +#include "event.h" +#include "logging.h" + +#include "system.h" + +int keylifetime = 0; +int keyexpires = 0; + +#define MAX_SEQNO 1073741824 + +/* VPN packet I/O */ + +void receive_udppacket(node_t *n, vpn_packet_t *inpkt) +{ + vpn_packet_t pkt1, pkt2; + vpn_packet_t *pkt[] = {&pkt1, &pkt2, &pkt1, &pkt2}; + int nextpkt = 0; + vpn_packet_t *outpkt = pkt[0]; + int outlen, outpad; + long int complen = MTU + 12; + EVP_CIPHER_CTX ctx; + char hmac[EVP_MAX_MD_SIZE]; +cp + /* Check the message authentication code */ + + if(myself->digest && myself->maclength) + { + inpkt->len -= myself->maclength; + HMAC(myself->digest, myself->key, myself->keylength, (char *)&inpkt->seqno, inpkt->len, hmac, NULL); + if(memcmp(hmac, (char *)&inpkt->seqno + inpkt->len, myself->maclength)) + { + if(debug_lvl >= DEBUG_TRAFFIC) + syslog(LOG_DEBUG, _("Got unauthenticated packet from %s (%s)"), n->name, n->hostname); + return; + } + } + + /* Decrypt the packet */ + + if(myself->cipher) + { + outpkt = pkt[nextpkt++]; + + EVP_DecryptInit(&ctx, myself->cipher, myself->key, myself->key + myself->cipher->key_len); + EVP_DecryptUpdate(&ctx, (char *)&outpkt->seqno, &outlen, (char *)&inpkt->seqno, inpkt->len); + EVP_DecryptFinal(&ctx, (char *)&outpkt->seqno + outlen, &outpad); + + outpkt->len = outlen + outpad; + inpkt = outpkt; + } + + /* Check the sequence number */ + + inpkt->len -= sizeof(inpkt->seqno); + inpkt->seqno = ntohl(inpkt->seqno); + + if(inpkt->seqno <= n->received_seqno) + { + if(debug_lvl >= DEBUG_TRAFFIC) + syslog(LOG_DEBUG, _("Got late or replayed packet from %s (%s), seqno %d"), n->name, n->hostname, inpkt->seqno); + return; + } + + n->received_seqno = inpkt->seqno; + + if(n->received_seqno > MAX_SEQNO) + keyexpires = 0; + + /* Decompress the packet */ + + if(myself->compression) + { + outpkt = pkt[nextpkt++]; + + if(uncompress(outpkt->data, &complen, inpkt->data, inpkt->len) != Z_OK) + { + syslog(LOG_ERR, _("Error while uncompressing packet from %s (%s)"), n->name, n->hostname); + return; + } + + outpkt->len = complen; + inpkt = outpkt; + } + + receive_packet(n, inpkt); +cp +} + +void receive_tcppacket(connection_t *c, char *buffer, int len) +{ + vpn_packet_t outpkt; +cp + outpkt.len = len; + memcpy(outpkt.data, buffer, len); + + receive_packet(c->node, &outpkt); +cp +} + +void receive_packet(node_t *n, vpn_packet_t *packet) +{ +cp + if(debug_lvl >= DEBUG_TRAFFIC) + syslog(LOG_DEBUG, _("Received packet of %d bytes from %s (%s)"), packet->len, n->name, n->hostname); +cp +} + +void send_udppacket(node_t *n, vpn_packet_t *inpkt) +{ + vpn_packet_t pkt1, pkt2; + vpn_packet_t *pkt[] = {&pkt1, &pkt2, &pkt1, &pkt2}; + int nextpkt = 0; + vpn_packet_t *outpkt; + int origlen; + int outlen, outpad; + long int complen = MTU + 12; + EVP_CIPHER_CTX ctx; + vpn_packet_t *copy; + static int priority = 0; + int origpriority; + int sock; +cp + /* Make sure we have a valid key */ + + if(!n->status.validkey) + { + if(debug_lvl >= DEBUG_TRAFFIC) + syslog(LOG_INFO, _("No valid key known yet for %s (%s), queueing packet"), + n->name, n->hostname); + + /* Since packet is on the stack of handle_tap_input(), + we have to make a copy of it first. */ + + copy = xmalloc(sizeof(vpn_packet_t)); + memcpy(copy, inpkt, sizeof(vpn_packet_t)); + + list_insert_tail(n->queue, copy); + + if(n->queue->count > MAXQUEUELENGTH) + list_delete_head(n->queue); + + if(!n->status.waitingforkey) + send_req_key(n->nexthop->connection, myself, n); + + n->status.waitingforkey = 1; + + return; + } + + origlen = inpkt->len; + origpriority = inpkt->priority; + + /* Compress the packet */ + + if(n->compression) + { + outpkt = pkt[nextpkt++]; + + if(compress2(outpkt->data, &complen, inpkt->data, inpkt->len, n->compression) != Z_OK) + { + syslog(LOG_ERR, _("Error while compressing packet to %s (%s)"), n->name, n->hostname); + return; + } + + outpkt->len = complen; + inpkt = outpkt; + } + + /* Add sequence number */ + + inpkt->seqno = htonl(++(n->sent_seqno)); + inpkt->len += sizeof(inpkt->seqno); + + /* Encrypt the packet */ + + if(n->cipher) + { + outpkt = pkt[nextpkt++]; + + EVP_EncryptInit(&ctx, n->cipher, n->key, n->key + n->cipher->key_len); + EVP_EncryptUpdate(&ctx, (char *)&outpkt->seqno, &outlen, (char *)&inpkt->seqno, inpkt->len); + EVP_EncryptFinal(&ctx, (char *)&outpkt->seqno + outlen, &outpad); + + outpkt->len = outlen + outpad; + inpkt = outpkt; + } + + /* Add the message authentication code */ + + if(n->digest && n->maclength) + { + HMAC(n->digest, n->key, n->keylength, (char *)&inpkt->seqno, inpkt->len, (char *)&inpkt->seqno + inpkt->len, &outlen); + inpkt->len += n->maclength; + } + + /* Determine which socket we have to use */ + + for(sock = 0; sock < listen_sockets; sock++) + if(n->address.sa.sa_family == listen_socket[sock].sa.sa.sa_family) + break; + + if(sock >= listen_sockets) + sock = 0; /* If none is available, just use the first and hope for the best. */ + + /* Send the packet */ + +#if defined(SOL_IP) && defined(IP_TOS) + if(priorityinheritance && origpriority != priority && listen_socket[sock].sa.sa.sa_family == AF_INET) + { + priority = origpriority; + if(debug_lvl >= DEBUG_TRAFFIC) + syslog(LOG_DEBUG, _("Setting outgoing packet priority to %d"), priority); + if(setsockopt(sock, SOL_IP, IP_TOS, &priority, sizeof(priority))) /* SO_PRIORITY doesn't seem to work */ + syslog(LOG_ERR, _("System call `%s' failed: %s"), "setsockopt", strerror(errno)); + } +#endif + + if((sendto(listen_socket[sock].udp, (char *)&inpkt->seqno, inpkt->len, 0, &(n->address.sa), SALEN(n->address.sa))) < 0) + { + syslog(LOG_ERR, _("Error sending packet to %s (%s): %s"), + n->name, n->hostname, strerror(errno)); + return; + } + + inpkt->len = origlen; +cp +} + +/* + send a packet to the given vpn ip. +*/ +void send_packet(node_t *n, vpn_packet_t *packet) +{ + node_t *via; +cp + if(debug_lvl >= DEBUG_TRAFFIC) + syslog(LOG_ERR, _("Sending packet of %d bytes to %s (%s)"), + packet->len, n->name, n->hostname); + + if(n == myself) + { + if(debug_lvl >= DEBUG_TRAFFIC) + { + syslog(LOG_NOTICE, _("Packet is looping back to us!")); + } + + return; + } + + if(!n->status.reachable) + { + if(debug_lvl >= DEBUG_TRAFFIC) + syslog(LOG_INFO, _("Node %s (%s) is not reachable"), + n->name, n->hostname); + return; + } + + via = (n->via == myself)?n->nexthop:n->via; + + if(via != n && debug_lvl >= DEBUG_TRAFFIC) + syslog(LOG_ERR, _("Sending packet to %s via %s (%s)"), + n->name, via->name, n->via->hostname); + + if((myself->options | via->options) & OPTION_TCPONLY) + { + if(send_tcppacket(via->connection, packet)) + terminate_connection(via->connection, 1); + } + else + send_udppacket(via, packet); +} + +/* Broadcast a packet using the minimum spanning tree */ + +void broadcast_packet(node_t *from, vpn_packet_t *packet) +{ + avl_node_t *node; + connection_t *c; +cp + if(debug_lvl >= DEBUG_TRAFFIC) + syslog(LOG_INFO, _("Broadcasting packet of %d bytes from %s (%s)"), + packet->len, from->name, from->hostname); + + for(node = connection_tree->head; node; node = node->next) + { + c = (connection_t *)node->data; + if(c->status.active && c->status.mst && c != from->nexthop->connection) + send_packet(c->node, packet); + } +cp +} + +void flush_queue(node_t *n) +{ + list_node_t *node, *next; +cp + if(debug_lvl >= DEBUG_TRAFFIC) + syslog(LOG_INFO, _("Flushing queue for %s (%s)"), n->name, n->hostname); + + for(node = n->queue->head; node; node = next) + { + next = node->next; + send_udppacket(n, (vpn_packet_t *)node->data); + list_delete_node(n->queue, node); + } +cp +} + +void handle_incoming_vpn_data(int sock) +{ + vpn_packet_t pkt; + int x, l = sizeof(x); + char *hostname; + sockaddr_t from; + socklen_t fromlen = sizeof(from); + node_t *n; +cp + if(getsockopt(sock, SOL_SOCKET, SO_ERROR, &x, &l) < 0) + { + syslog(LOG_ERR, _("This is a bug: %s:%d: %d:%s"), + __FILE__, __LINE__, sock, strerror(errno)); + cp_trace(); + exit(1); + } + if(x) + { + syslog(LOG_ERR, _("Incoming data socket error: %s"), strerror(x)); + return; + } + + if((pkt.len = recvfrom(sock, (char *)&pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen)) <= 0) + { + syslog(LOG_ERR, _("Receiving packet failed: %s"), strerror(errno)); + return; + } + + sockaddrunmap(&from); /* Some braindead IPv6 implementations do stupid things. */ + + n = lookup_node_udp(&from); + + if(!n) + { + hostname = sockaddr2hostname(&from); + syslog(LOG_WARNING, _("Received UDP packet from unknown source %s"), hostname); + free(hostname); + return; + } + + if(n->connection) + n->connection->last_ping_time = now; + + receive_udppacket(n, &pkt); +cp +} + diff --git a/src/pokey/net_setup.c b/src/pokey/net_setup.c new file mode 100644 index 00000000..c44d2a95 --- /dev/null +++ b/src/pokey/net_setup.c @@ -0,0 +1,546 @@ +/* + net_setup.c -- Setup. + Copyright (C) 1998-2002 Ivo Timmermans , + 2000-2002 Guus Sliepen + + 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: net_setup.c,v 1.1 2002/04/28 12:46:26 zarq Exp $ +*/ + +#include "config.h" + +#include +#include +#include +#include +#ifdef HAVE_LINUX + #include + #include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +/* SunOS really wants sys/socket.h BEFORE net/if.h, + and FreeBSD wants these lines below the rest. */ +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "conf.h" +#include "interface.h" +#include "connection.h" +#include "meta.h" +#include "net.h" +#include "netutl.h" +#include "process.h" +#include "protocol.h" +#include "subnet.h" +#include "graph.h" +#include "process.h" +#include "route.h" +#include "device.h" +#include "event.h" +#include "logging.h" + +#include "system.h" + +char *myport; + +int read_rsa_public_key(connection_t *c) +{ + FILE *fp; + char *fname; + char *key; +cp + if(!c->rsa_key) + c->rsa_key = RSA_new(); + + /* First, check for simple PublicKey statement */ + + if(get_config_string(lookup_config(c->config_tree, "PublicKey"), &key)) + { + BN_hex2bn(&c->rsa_key->n, key); + BN_hex2bn(&c->rsa_key->e, "FFFF"); + free(key); + return 0; + } + + /* Else, check for PublicKeyFile statement and read it */ + + if(get_config_string(lookup_config(c->config_tree, "PublicKeyFile"), &fname)) + { + if(is_safe_path(fname)) + { + if((fp = fopen(fname, "r")) == NULL) + { + log(0, TLOG_ERROR, + _("Error reading RSA public key file `%s': %s"), + fname, strerror(errno)); + free(fname); + return -1; + } + free(fname); + c->rsa_key = PEM_read_RSAPublicKey(fp, &c->rsa_key, NULL, NULL); + fclose(fp); + if(!c->rsa_key) + { + syslog(LOG_ERR, _("Reading RSA public key file `%s' failed: %s"), + fname, strerror(errno)); + return -1; + } + return 0; + } + else + { + free(fname); + return -1; + } + } + + /* Else, check if a harnessed public key is in the config file */ + + asprintf(&fname, "%s/hosts/%s", confbase, c->name); + if((fp = fopen(fname, "r"))) + { + c->rsa_key = PEM_read_RSAPublicKey(fp, &c->rsa_key, NULL, NULL); + fclose(fp); + } + + free(fname); + + if(c->rsa_key) + return 0; + else + { + syslog(LOG_ERR, _("No public key for %s specified!"), c->name); + return -1; + } +} + +int read_rsa_private_key(void) +{ + FILE *fp; + char *fname, *key; +cp + if(get_config_string(lookup_config(config_tree, "PrivateKey"), &key)) + { + myself->connection->rsa_key = RSA_new(); + BN_hex2bn(&myself->connection->rsa_key->d, key); + BN_hex2bn(&myself->connection->rsa_key->e, "FFFF"); + free(key); + return 0; + } + + if(!get_config_string(lookup_config(config_tree, "PrivateKeyFile"), &fname)) + asprintf(&fname, "%s/rsa_key.priv", confbase); + + if(is_safe_path(fname)) + { + if((fp = fopen(fname, "r")) == NULL) + { + syslog(LOG_ERR, _("Error reading RSA private key file `%s': %s"), + fname, strerror(errno)); + free(fname); + return -1; + } + free(fname); + myself->connection->rsa_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL); + fclose(fp); + if(!myself->connection->rsa_key) + { + syslog(LOG_ERR, _("Reading RSA private key file `%s' failed: %s"), + fname, strerror(errno)); + return -1; + } + return 0; + } + + free(fname); + return -1; +} + +int check_rsa_key(RSA *rsa_key) +{ + char *test1, *test2, *test3; +cp + if(rsa_key->p && rsa_key->q) + { + if(RSA_check_key(rsa_key) != 1) + return -1; + } + else + { + test1 = xmalloc(RSA_size(rsa_key)); + test2 = xmalloc(RSA_size(rsa_key)); + test3 = xmalloc(RSA_size(rsa_key)); + + if(RSA_public_encrypt(RSA_size(rsa_key), test1, test2, rsa_key, RSA_NO_PADDING) != RSA_size(rsa_key)) + return -1; + + if(RSA_private_decrypt(RSA_size(rsa_key), test2, test3, rsa_key, RSA_NO_PADDING) != RSA_size(rsa_key)) + return -1; + + if(memcmp(test1, test3, RSA_size(rsa_key))) + return -1; + } +cp + return 0; +} + +/* + Configure node_t myself and set up the local sockets (listen only) +*/ +int setup_myself(void) +{ + config_t *cfg; + subnet_t *subnet; + char *name, *mode, *afname, *cipher, *digest; + int choice; +cp + myself = new_node(); + myself->connection = new_connection(); + init_configuration(&myself->connection->config_tree); + + asprintf(&myself->hostname, _("MYSELF")); + asprintf(&myself->connection->hostname, _("MYSELF")); + + myself->connection->options = 0; + myself->connection->protocol_version = PROT_CURRENT; + + if(!get_config_string(lookup_config(config_tree, "Name"), &name)) /* Not acceptable */ + { + syslog(LOG_ERR, _("Name for tinc daemon required!")); + return -1; + } + + if(check_id(name)) + { + syslog(LOG_ERR, _("Invalid name for myself!")); + free(name); + return -1; + } + + myself->name = name; + myself->connection->name = xstrdup(name); + +cp + if(read_rsa_private_key()) + return -1; + + if(read_connection_config(myself->connection)) + { + syslog(LOG_ERR, _("Cannot open host configuration file for myself!")); + return -1; + } + + if(read_rsa_public_key(myself->connection)) + return -1; +cp + + if(check_rsa_key(myself->connection->rsa_key)) + { + syslog(LOG_ERR, _("Invalid public/private keypair!")); + return -1; + } + + if(!get_config_string(lookup_config(myself->connection->config_tree, "Port"), &myport)) + asprintf(&myport, "655"); + +/* Read in all the subnets specified in the host configuration file */ + + cfg = lookup_config(myself->connection->config_tree, "Subnet"); + + while(cfg) + { + if(!get_config_subnet(cfg, &subnet)) + return -1; + + subnet_add(myself, subnet); + + cfg = lookup_config_next(myself->connection->config_tree, cfg); + } + +cp + /* Check some options */ + + if(get_config_bool(lookup_config(config_tree, "IndirectData"), &choice)) + if(choice) + myself->options |= OPTION_INDIRECT; + + if(get_config_bool(lookup_config(config_tree, "TCPOnly"), &choice)) + if(choice) + myself->options |= OPTION_TCPONLY; + + if(get_config_bool(lookup_config(myself->connection->config_tree, "IndirectData"), &choice)) + if(choice) + myself->options |= OPTION_INDIRECT; + + if(get_config_bool(lookup_config(myself->connection->config_tree, "TCPOnly"), &choice)) + if(choice) + myself->options |= OPTION_TCPONLY; + + if(myself->options & OPTION_TCPONLY) + myself->options |= OPTION_INDIRECT; + + if(get_config_string(lookup_config(config_tree, "Mode"), &mode)) + { + if(!strcasecmp(mode, "router")) + routing_mode = RMODE_ROUTER; + else if (!strcasecmp(mode, "switch")) + routing_mode = RMODE_SWITCH; + else if (!strcasecmp(mode, "hub")) + routing_mode = RMODE_HUB; + else + { + syslog(LOG_ERR, _("Invalid routing mode!")); + return -1; + } + free(mode); + } + else + routing_mode = RMODE_ROUTER; + + get_config_bool(lookup_config(config_tree, "PriorityInheritance"), &priorityinheritance); +#if !defined(SOL_IP) || !defined(IP_TOS) + if(priorityinheritance) + syslog(LOG_WARNING, _("PriorityInheritance not supported on this platform")); +#endif + + if(!get_config_int(lookup_config(config_tree, "MACExpire"), &macexpire)) + macexpire= 600; + + if(get_config_int(lookup_config(myself->connection->config_tree, "MaxTimeout"), &maxtimeout)) + { + if(maxtimeout <= 0) + { + syslog(LOG_ERR, _("Bogus maximum timeout!")); + return -1; + } + } + else + maxtimeout = 900; + + if(get_config_string(lookup_config(config_tree, "AddressFamily"), &afname)) + { + if(!strcasecmp(afname, "IPv4")) + addressfamily = AF_INET; + else if (!strcasecmp(afname, "IPv6")) + addressfamily = AF_INET6; + else if (!strcasecmp(afname, "any")) + addressfamily = AF_UNSPEC; + else + { + syslog(LOG_ERR, _("Invalid address family!")); + return -1; + } + free(afname); + } + else + addressfamily = AF_INET; + + get_config_bool(lookup_config(config_tree, "Hostnames"), &hostnames); +cp + /* Generate packet encryption key */ + + if(get_config_string(lookup_config(myself->connection->config_tree, "Cipher"), &cipher)) + { + if(!strcasecmp(cipher, "none")) + { + myself->cipher = NULL; + } + else + { + if(!(myself->cipher = EVP_get_cipherbyname(cipher))) + { + syslog(LOG_ERR, _("Unrecognized cipher type!")); + return -1; + } + } + } + else + myself->cipher = EVP_bf_cbc(); + + if(myself->cipher) + myself->keylength = myself->cipher->key_len + myself->cipher->iv_len; + else + myself->keylength = 1; + + myself->connection->outcipher = EVP_bf_ofb(); + + myself->key = (char *)xmalloc(myself->keylength); + RAND_pseudo_bytes(myself->key, myself->keylength); + + if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime)) + keylifetime = 3600; + + keyexpires = now + keylifetime; + + /* Check if we want to use message authentication codes... */ + + if(get_config_string(lookup_config(myself->connection->config_tree, "Digest"), &digest)) + { + if(!strcasecmp(digest, "none")) + { + myself->digest = NULL; + } + else + { + if(!(myself->digest = EVP_get_digestbyname(digest))) + { + syslog(LOG_ERR, _("Unrecognized digest type!")); + return -1; + } + } + } + else + myself->digest = EVP_sha1(); + + myself->connection->outdigest = EVP_sha1(); + + if(get_config_int(lookup_config(myself->connection->config_tree, "MACLength"), &myself->maclength)) + { + if(myself->digest) + { + if(myself->maclength > myself->digest->md_size) + { + syslog(LOG_ERR, _("MAC length exceeds size of digest!")); + return -1; + } + else if (myself->maclength < 0) + { + syslog(LOG_ERR, _("Bogus MAC length!")); + return -1; + } + } + } + else + myself->maclength = 4; + + myself->connection->outmaclength = 0; + + /* Compression */ + + if(get_config_int(lookup_config(myself->connection->config_tree, "Compression"), &myself->compression)) + { + if(myself->compression < 0 || myself->compression > 9) + { + syslog(LOG_ERR, _("Bogus compression level!")); + return -1; + } + } + else + myself->compression = 0; + + myself->connection->outcompression = 0; +cp + /* Done */ + + myself->nexthop = myself; + myself->via = myself; + myself->status.active = 1; + node_add(myself); + + graph(); + + syslog(LOG_NOTICE, _("Ready")); +cp + return 0; +} + +/* + setup all initial network connections +*/ +int setup_network_connections(void) +{ +cp + now = time(NULL); + + init_connections(); + init_subnets(); + init_nodes(); + init_edges(); + init_events(); + init_requests(); + + if(get_config_int(lookup_config(config_tree, "PingTimeout"), &pingtimeout)) + { + if(pingtimeout < 1) + { + pingtimeout = 86400; + } + } + else + pingtimeout = 60; + + if(setup_myself() < 0) + return -1; + + try_outgoing_connections(); +cp + return 0; +} + +/* + close all open network connections +*/ +void close_network_connections(void) +{ + avl_node_t *node, *next; + connection_t *c; + int i; +cp + for(node = connection_tree->head; node; node = next) + { + next = node->next; + c = (connection_t *)node->data; + if(c->outgoing) + free(c->outgoing->name), free(c->outgoing), c->outgoing = NULL; + terminate_connection(c, 0); + } + + if(myself && myself->connection) + terminate_connection(myself->connection, 0); + + for(i = 0; i < listen_sockets; i++) + { + close(listen_socket[i].tcp); + close(listen_socket[i].udp); + } + + exit_requests(); + exit_events(); + exit_edges(); + exit_subnets(); + exit_nodes(); + exit_connections(); + +cp + return; +} diff --git a/src/pokey/net_socket.c b/src/pokey/net_socket.c new file mode 100644 index 00000000..81084f56 --- /dev/null +++ b/src/pokey/net_socket.c @@ -0,0 +1,491 @@ +/* + net_socket.c -- Handle various kinds of sockets. + Copyright (C) 1998-2002 Ivo Timmermans , + 2000-2002 Guus Sliepen + + 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: net_socket.c,v 1.1 2002/04/28 12:46:26 zarq Exp $ +*/ + +#include "config.h" + +#include +#include +#include +#include +#ifdef HAVE_LINUX + #include + #include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +/* SunOS really wants sys/socket.h BEFORE net/if.h, + and FreeBSD wants these lines below the rest. */ +#include +#include +#include + +#include +#include +#include +#include + +#include "conf.h" +#include "interface.h" +#include "connection.h" +#include "meta.h" +#include "net.h" +#include "netutl.h" +#include "process.h" +#include "protocol.h" +#include "subnet.h" +#include "graph.h" +#include "process.h" +#include "route.h" +#include "device.h" +#include "event.h" +#include "logging.h" + +#include "system.h" + +int addressfamily = AF_INET; +int maxtimeout = 900; +int seconds_till_retry = 5; + +listen_socket_t listen_socket[MAXSOCKETS]; +int listen_sockets = 0; + +/* Setup sockets */ + +int setup_listen_socket(sockaddr_t *sa) +{ + int nfd, flags; + char *addrstr; + int option; +#if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE) + char *interface; + struct ifreq ifr; +#endif +cp + if((nfd = socket(sa->sa.sa_family, SOCK_STREAM, IPPROTO_TCP)) < 0) + { + log(0, TLOG_ERROR, + _("Creating metasocket failed: %s"), + strerror(errno)); + return -1; + } + + flags = fcntl(nfd, F_GETFL); + if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) + { + close(nfd); + syslog(LOG_ERR, _("System call `%s' failed: %s"), "fcntl", strerror(errno)); + return -1; + } + + /* Optimize TCP settings */ + + option = 1; + setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option)); + +#if defined(SOL_TCP) && defined(TCP_NODELAY) + setsockopt(nfd, SOL_TCP, TCP_NODELAY, &option, sizeof(option)); +#endif + +#if defined(SOL_IP) && defined(IP_TOS) && defined(IPTOS_LOWDELAY) + option = IPTOS_LOWDELAY; + setsockopt(nfd, SOL_IP, IP_TOS, &option, sizeof(option)); +#endif + + if(get_config_string(lookup_config(config_tree, "BindToInterface"), &interface)) + { +#if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE) + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, interface, IFNAMSIZ); + if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr))) + { + close(nfd); + syslog(LOG_ERR, _("Can't bind to interface %s: %s"), interface, strerror(errno)); + return -1; + } +#else + syslog(LOG_WARNING, _("BindToDevice not supported on this platform")); +#endif + } + + if(bind(nfd, &sa->sa, SALEN(sa->sa))) + { + close(nfd); + addrstr = sockaddr2hostname(sa); + syslog(LOG_ERR, _("Can't bind to %s/tcp: %s"), addrstr, strerror(errno)); + free(addrstr); + return -1; + } + + if(listen(nfd, 3)) + { + close(nfd); + syslog(LOG_ERR, _("System call `%s' failed: %s"), "listen", strerror(errno)); + return -1; + } +cp + return nfd; +} + +int setup_vpn_in_socket(sockaddr_t *sa) +{ + int nfd, flags; + char *addrstr; + int option; +#if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE) + char *interface; + struct ifreq ifr; +#endif +cp + if((nfd = socket(sa->sa.sa_family, SOCK_DGRAM, IPPROTO_UDP)) < 0) + { + syslog(LOG_ERR, _("Creating UDP socket failed: %s"), strerror(errno)); + return -1; + } + + flags = fcntl(nfd, F_GETFL); + if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) + { + close(nfd); + syslog(LOG_ERR, _("System call `%s' failed: %s"), "fcntl", strerror(errno)); + return -1; + } + + option = 1; + setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option)); + +#if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE) + if(get_config_string(lookup_config(config_tree, "BindToInterface"), &interface)) + { + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, interface, IFNAMSIZ); + if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr))) + { + close(nfd); + syslog(LOG_ERR, _("Can't bind to interface %s: %s"), interface, strerror(errno)); + return -1; + } + } +#endif + + if(bind(nfd, &sa->sa, SALEN(sa->sa))) + { + close(nfd); + addrstr = sockaddr2hostname(sa); + syslog(LOG_ERR, _("Can't bind to %s/udp: %s"), addrstr, strerror(errno)); + free(addrstr); + return -1; + } +cp + return nfd; +} + +void retry_outgoing(outgoing_t *outgoing) +{ + event_t *event; +cp + outgoing->timeout += 5; + if(outgoing->timeout > maxtimeout) + outgoing->timeout = maxtimeout; + + event = new_event(); + event->handler = (event_handler_t)setup_outgoing_connection; + event->time = now + outgoing->timeout; + event->data = outgoing; + event_add(event); + + if(debug_lvl >= DEBUG_CONNECTIONS) + syslog(LOG_NOTICE, _("Trying to re-establish outgoing connection in %d seconds"), outgoing->timeout); +cp +} + +int setup_outgoing_socket(connection_t *c) +{ + int option; +cp + if(debug_lvl >= DEBUG_CONNECTIONS) + syslog(LOG_INFO, _("Trying to connect to %s (%s)"), c->name, c->hostname); + + c->socket = socket(c->address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP); + + if(c->socket == -1) + { + syslog(LOG_ERR, _("Creating socket for %s failed: %s"), c->hostname, strerror(errno)); + return -1; + } + + /* Optimize TCP settings */ + +#ifdef HAVE_LINUX + option = 1; + setsockopt(c->socket, SOL_TCP, TCP_NODELAY, &option, sizeof(option)); + + option = IPTOS_LOWDELAY; + setsockopt(c->socket, SOL_IP, IP_TOS, &option, sizeof(option)); +#endif + + /* Connect */ + + if(connect(c->socket, &c->address.sa, SALEN(c->address.sa)) == -1) + { + close(c->socket); + syslog(LOG_ERR, _("Error while connecting to %s (%s): %s"), c->name, c->hostname, strerror(errno)); + return -1; + } + + if(debug_lvl >= DEBUG_CONNECTIONS) + syslog(LOG_INFO, _("Connected to %s (%s)"), c->name, c->hostname); +cp + return 0; +} + + +void finish_connecting(connection_t *c) +{ +cp + if(debug_lvl >= DEBUG_CONNECTIONS) + syslog(LOG_INFO, _("Connected to %s (%s)"), c->name, c->hostname); + + c->last_ping_time = now; + + send_id(c); +cp +} + +void do_outgoing_connection(connection_t *c) +{ + char *address, *port; + int option, result, flags; +cp +begin: + if(!c->outgoing->ai) + { + if(!c->outgoing->cfg) + { + log(DEBUG_CONNECTIONS, TLOG_ERROR, + _("Could not set up a meta connection to %s"), + c->name); + c->status.remove = 1; + do_prune = 1; + retry_outgoing(c->outgoing); + return; + } + + get_config_string(c->outgoing->cfg, &address); + + if(!get_config_string(lookup_config(c->config_tree, "Port"), &port)) + asprintf(&port, "655"); + + c->outgoing->ai = str2addrinfo(address, port, SOCK_STREAM); + free(address); + free(port); + + c->outgoing->aip = c->outgoing->ai; + c->outgoing->cfg = lookup_config_next(c->config_tree, c->outgoing->cfg); + } + + if(!c->outgoing->aip) + { + freeaddrinfo(c->outgoing->ai); + c->outgoing->ai = NULL; + goto begin; + } + + memcpy(&c->address, c->outgoing->aip->ai_addr, c->outgoing->aip->ai_addrlen); + c->outgoing->aip = c->outgoing->aip->ai_next; + + if(c->hostname) + free(c->hostname); + + c->hostname = sockaddr2hostname(&c->address); + + if(debug_lvl >= DEBUG_CONNECTIONS) + syslog(LOG_INFO, _("Trying to connect to %s (%s)"), c->name, c->hostname); + + c->socket = socket(c->address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP); + + if(c->socket == -1) + { + if(debug_lvl >= DEBUG_CONNECTIONS) + syslog(LOG_ERR, _("Creating socket for %s failed: %s"), c->hostname, strerror(errno)); + + goto begin; + } + + /* Optimize TCP settings */ + +#ifdef HAVE_LINUX + option = 1; + setsockopt(c->socket, SOL_TCP, TCP_NODELAY, &option, sizeof(option)); + + option = IPTOS_LOWDELAY; + setsockopt(c->socket, SOL_IP, IP_TOS, &option, sizeof(option)); +#endif + + /* Non-blocking */ + + flags = fcntl(c->socket, F_GETFL); + + if(fcntl(c->socket, F_SETFL, flags | O_NONBLOCK) < 0) + { + syslog(LOG_ERR, _("fcntl for %s: %s"), c->hostname, strerror(errno)); + } + + /* Connect */ + + result = connect(c->socket, &c->address.sa, SALEN(c->address.sa)); + + if(result == -1) + { + if(errno == EINPROGRESS) + { + c->status.connecting = 1; + return; + } + + close(c->socket); + + if(debug_lvl >= DEBUG_CONNECTIONS) + syslog(LOG_ERR, _("%s: %s"), c->hostname, strerror(errno)); + + goto begin; + } + + finish_connecting(c); + return; +cp +} + +void setup_outgoing_connection(outgoing_t *outgoing) +{ + connection_t *c; + node_t *n; +cp + n = lookup_node(outgoing->name); + + if(n) + if(n->connection) + { + log(DEBUG_CONNECTIONS, TLOG_INFO, + _("Already connected to %s"), + outgoing->name); + n->connection->outgoing = outgoing; + return; + } + + c = new_connection(); + c->name = xstrdup(outgoing->name); + c->outcipher = myself->connection->outcipher; + c->outdigest = myself->connection->outdigest; + c->outmaclength = myself->connection->outmaclength; + c->outcompression = myself->connection->outcompression; + + init_configuration(&c->config_tree); + read_connection_config(c); + + outgoing->cfg = lookup_config(c->config_tree, "Address"); + + if(!outgoing->cfg) + { + syslog(LOG_ERR, _("No address specified for %s"), c->name); + free_connection(c); + free(outgoing->name); + free(outgoing); + return; + } + + c->outgoing = outgoing; + c->last_ping_time = now; + + connection_add(c); + + do_outgoing_connection(c); +} + +/* + accept a new tcp connect and create a + new connection +*/ +int handle_new_meta_connection(int sock) +{ + connection_t *c; + sockaddr_t sa; + int fd, len = sizeof(sa); +cp + if((fd = accept(sock, &sa.sa, &len)) < 0) + { + syslog(LOG_ERR, _("Accepting a new connection failed: %s"), strerror(errno)); + return -1; + } + + sockaddrunmap(&sa); + + c = new_connection(); + c->outcipher = myself->connection->outcipher; + c->outdigest = myself->connection->outdigest; + c->outmaclength = myself->connection->outmaclength; + c->outcompression = myself->connection->outcompression; + + c->address = sa; + c->hostname = sockaddr2hostname(&sa); + c->socket = fd; + c->last_ping_time = now; + + log(DEBUG_CONNECTIONS, TLOG_NOTICE, + _("Connection from %s"), + c->hostname); + + connection_add(c); + + c->allow_request = ID; + send_id(c); +cp + return 0; +} + +void try_outgoing_connections(void) +{ + static config_t *cfg = NULL; + char *name; + outgoing_t *outgoing; +cp + for(cfg = lookup_config(config_tree, "ConnectTo"); cfg; cfg = lookup_config_next(config_tree, cfg)) + { + get_config_string(cfg, &name); + + if(check_id(name)) + { + syslog(LOG_ERR, _("Invalid name for outgoing connection in %s line %d"), cfg->file, cfg->line); + free(name); + continue; + } + + outgoing = xmalloc_and_zero(sizeof(*outgoing)); + outgoing->name = name; + setup_outgoing_connection(outgoing); + } +} diff --git a/src/pokey/netutl.c b/src/pokey/netutl.c new file mode 100644 index 00000000..cb23574e --- /dev/null +++ b/src/pokey/netutl.c @@ -0,0 +1,250 @@ +/* + netutl.c -- some supporting network utility code + Copyright (C) 1998-2002 Ivo Timmermans + 2000-2002 Guus Sliepen + + 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: netutl.c,v 1.1 2002/04/28 12:46:26 zarq Exp $ +*/ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "errno.h" +#include "interface.h" +#include "conf.h" +#include "net.h" +#include "netutl.h" +#include "logging.h" + +#include "system.h" + +int hostnames = 0; + +/* + Turn a string into a struct addrinfo. + Return NULL on failure. +*/ +struct addrinfo *str2addrinfo(char *address, char *service, int socktype) +{ + struct addrinfo hint, *ai; + int err; +cp + memset(&hint, 0, sizeof(hint)); + + hint.ai_family = addressfamily; + hint.ai_socktype = socktype; + + if((err = getaddrinfo(address, service, &hint, &ai))) + { + log(DEBUG_ERROR, LOG_WARNING, + _("Error looking up %s port %s: %s\n"), + address, service, gai_strerror(err)); + cp_trace(); + return NULL; + } + +cp + return ai; +} + +sockaddr_t str2sockaddr(char *address, char *port) +{ + struct addrinfo hint, *ai; + sockaddr_t result; + int err; +cp + memset(&hint, 0, sizeof(hint)); + + hint.ai_family = AF_UNSPEC; + hint.ai_flags = AI_NUMERICHOST; + hint.ai_socktype = SOCK_STREAM; + + if((err = getaddrinfo(address, port, &hint, &ai) || !ai)) + { + log(0, TLOG_ERROR, + _("Error looking up %s port %s: %s\n"), + address, port, gai_strerror(err)); + cp_trace(); + raise(SIGFPE); + exit(0); + } + + result = *(sockaddr_t *)ai->ai_addr; + freeaddrinfo(ai); +cp + return result; +} + +void sockaddr2str(sockaddr_t *sa, char **addrstr, char **portstr) +{ + char address[NI_MAXHOST]; + char port[NI_MAXSERV]; + char *scopeid; + int err; +cp + if((err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof(address), port, sizeof(port), NI_NUMERICHOST|NI_NUMERICSERV))) + { + syslog(LOG_ERR, _("Error while translating addresses: %s"), gai_strerror(err)); + cp_trace(); + raise(SIGFPE); + exit(0); + } + +#ifdef HAVE_LINUX + if((scopeid = strchr(address, '%'))) + *scopeid = '\0'; /* Descope. */ +#endif + + *addrstr = xstrdup(address); + *portstr = xstrdup(port); +cp +} + +char *sockaddr2hostname(sockaddr_t *sa) +{ + char *str; + char address[NI_MAXHOST] = "unknown"; + char port[NI_MAXSERV] = "unknown"; + int err; +cp + if((err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof(address), port, sizeof(port), hostnames?0:(NI_NUMERICHOST|NI_NUMERICSERV)))) + { + syslog(LOG_ERR, _("Error while looking up hostname: %s"), gai_strerror(err)); + } + + asprintf(&str, _("%s port %s"), address, port); +cp + return str; +} + +int sockaddrcmp(sockaddr_t *a, sockaddr_t *b) +{ + int result; +cp + result = a->sa.sa_family - b->sa.sa_family; + + if(result) + return result; + + switch(a->sa.sa_family) + { + case AF_UNSPEC: + return 0; + case AF_INET: + result = memcmp(&a->in.sin_addr, &b->in.sin_addr, sizeof(a->in.sin_addr)); + if(result) + return result; + return memcmp(&a->in.sin_port, &b->in.sin_port, sizeof(a->in.sin_port)); + case AF_INET6: + result = memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr)); + if(result) + return result; + return memcmp(&a->in6.sin6_port, &b->in6.sin6_port, sizeof(a->in6.sin6_port)); + default: + syslog(LOG_ERR, _("sockaddrcmp() was called with unknown address family %d, exitting!"), a->sa.sa_family); + cp_trace(); + raise(SIGFPE); + exit(0); + } +cp +} + +void sockaddrunmap(sockaddr_t *sa) +{ + if(sa->sa.sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sa->in6.sin6_addr)) + { + sa->in.sin_addr.s_addr = ((uint32_t *)&sa->in6.sin6_addr)[3]; + sa->in.sin_family = AF_INET; + } +} + +/* Subnet mask handling */ + +int maskcmp(char *a, char *b, int masklen, int len) +{ + int i, m, result; +cp + for(m = masklen, i = 0; m >= 8; m -= 8, i++) + if((result = a[i] - b[i])) + return result; + + if(m) + return (a[i] & (0x100 - (m << 1))) - (b[i] & (0x100 - (m << 1))); + + return 0; +} + +void mask(char *a, int masklen, int len) +{ + int i; +cp + i = masklen / 8; + masklen %= 8; + + if(masklen) + a[i++] &= (0x100 - (masklen << 1)); + + for(; i < len; i++) + a[i] = 0; +} + +void maskcpy(char *a, char *b, int masklen, int len) +{ + int i, m; +cp + for(m = masklen, i = 0; m >= 8; m -= 8, i++) + a[i] = b[i]; + + if(m) + { + a[i] = b[i] & (0x100 - (m << 1)); + i++; + } + + for(; i < len; i++) + a[i] = 0; +} + +int maskcheck(char *a, int masklen, int len) +{ + int i; +cp + i = masklen / 8; + masklen %= 8; + + if(masklen) + if(a[i++] & ~(0x100 - (masklen << 1))) + return -1; + + for(; i < len; i++) + if(a[i] != 0) + return -1; + + return 0; +} diff --git a/src/pokey/netutl.h b/src/pokey/netutl.h new file mode 100644 index 00000000..7df29b9c --- /dev/null +++ b/src/pokey/netutl.h @@ -0,0 +1,46 @@ +/* + netutl.h -- header file for netutl.c + Copyright (C) 1998-2002 Ivo Timmermans + 2000-2002 Guus Sliepen + + 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: netutl.h,v 1.1 2002/04/28 12:46:26 zarq Exp $ +*/ + +#ifndef __TINC_NETUTL_H__ +#define __TINC_NETUTL_H__ + +#include +#include +#include + +#include "net.h" + +extern int hostnames; + +extern char *hostlookup(unsigned long); +extern struct addrinfo *str2addrinfo(char *, char *, int); +extern sockaddr_t str2sockaddr(char *, char *); +extern void sockaddr2str(sockaddr_t *, char **, char **); +extern char *sockaddr2hostname(sockaddr_t *); +extern int sockaddrcmp(sockaddr_t *, sockaddr_t *); +extern void sockaddrunmap(sockaddr_t *); +extern int maskcmp(char *, char *, int, int); +extern void maskcpy(char *, char *, int, int); +extern void mask(char *, int, int); +extern int maskcheck(char *, int, int); + +#endif /* __TINC_NETUTL_H__ */ diff --git a/src/pokey/pokey.c b/src/pokey/pokey.c index d312d43d..7e61c26e 100644 --- a/src/pokey/pokey.c +++ b/src/pokey/pokey.c @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: pokey.c,v 1.2 2002/04/13 11:21:01 zarq Exp $ + $Id: pokey.c,v 1.3 2002/04/28 12:46:26 zarq Exp $ */ #include "config.h" @@ -323,16 +323,6 @@ main(int argc, char **argv, char **envp) gnome_init("Pokey", "0.0", 1, fake_argv); - glade_init(); - - xml = glade_xml_new("pokey.glade", "MainWindow"); - - if (!xml) - { - fprintf(stderr, _("Something bad happened while creating the interface.\n")); - exit(1); - } - g_argv = argv; make_names(); @@ -356,7 +346,8 @@ cp if(init_interface()) { - fprintf(stderr, _("Could not setup all necessary interface elements.\n")); + log(0, TLOG_ERROR, + _("Could not setup all necessary interface elements.\n")); exit(1); } @@ -365,9 +356,11 @@ cp main_loop(); cleanup_and_exit(1); } - - log(0, LOG_ERR, - _("Unrecoverable error")); + + log_add_hook(log_default); + + log(0, TLOG_ERROR, + _("Could not set up network connections")); cp_trace(); return 1; diff --git a/src/pokey/pokey.glade b/src/pokey/pokey.glade index 5d70a85e..403637f3 100644 --- a/src/pokey/pokey.glade +++ b/src/pokey/pokey.glade @@ -2,8 +2,8 @@ - Tincctl - tincctl + Pokey + pokey src pixmaps @@ -11,12 +11,14 @@ True True True + True + pokey.translatables GtkWindow - MainWindow - window1 + HostInfoWindow + Information about host GTK_WINDOW_TOPLEVEL GTK_WIN_POS_NONE False @@ -26,345 +28,1902 @@ GtkVBox - vbox1 + vbox2 False 0 - GtkMenuBar - menubar1 - GTK_SHADOW_OUT + GtkNotebook + notebook1 + True + True + True + GTK_POS_TOP + False + 2 + 2 + False 0 - False - False + True + True - GtkMenuItem - file1 - - False + GtkVBox + vbox4 + False + 0 - GtkMenu - file1_menu + GtkHBox + hbox2 + False + 0 + + 0 + True + True + - GtkMenuItem - close1 - - activate - on_close1_activate - Sun, 24 Mar 2002 20:42:33 GMT - - - False + GtkTable + table3 + 7 + 2 + False + 0 + 0 + + 0 + True + True + + + + GtkLabel + label14 + + GTK_JUSTIFY_CENTER + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 0 + 1 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + label15 + + GTK_JUSTIFY_CENTER + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 1 + 2 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + label16 + + GTK_JUSTIFY_CENTER + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 2 + 3 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + label17 + + GTK_JUSTIFY_CENTER + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 3 + 4 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + label18 + + GTK_JUSTIFY_CENTER + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 4 + 5 + 0 + 0 + False + False + False + False + True + False + + + + + GtkEntry + HostInfoNameEntry + True + False + True + 0 + + + 1 + 2 + 0 + 1 + 0 + 0 + True + False + False + False + True + False + + + + + GtkEntry + HostInfoHostnameEntry + True + False + True + 0 + + + 1 + 2 + 1 + 2 + 0 + 0 + True + False + False + False + True + False + + + + + GtkEntry + HostInfoPortEntry + True + False + True + 0 + + + 1 + 2 + 2 + 3 + 0 + 0 + True + False + False + False + True + False + + + + + GtkEntry + HostInfoVersionEntry + True + False + True + 0 + + + 1 + 2 + 3 + 4 + 0 + 0 + True + False + False + False + True + False + + + + + GtkEntry + HostInfoStatusEntry + True + False + True + 0 + + + 1 + 2 + 4 + 5 + 0 + 0 + True + False + False + False + True + False + + + + + GtkCheckButton + HostInfoTCPOnlyCheckbutton + True + + False + True + + 1 + 2 + 5 + 6 + 0 + 0 + False + False + False + False + True + False + + + + + GtkCheckButton + HostInfoIndirectdataCheckbutton + True + + False + True + + 1 + 2 + 6 + 7 + 0 + 0 + False + False + False + False + True + False + + - GtkMenuItem - exit1 - - activate - on_exit1_activate - Sun, 24 Mar 2002 20:42:33 GMT - - - False + GtkVBox + vbox5 + False + 0 + + 0 + True + True + + + + GtkCheckButton + HostInfoActiveCheckbutton + False + True + + False + True + + 0 + False + False + + + + + GtkCheckButton + HostInfoValidkeyCheckbutton + False + True + + False + True + + 0 + False + False + + + + + GtkCheckButton + HostInfoWaitingforkeyCheckbutton + False + True + + False + True + + 0 + False + False + + + + + GtkCheckButton + HostInfoVisitedCheckbutton + False + True + + False + True + + 0 + False + False + + + + + GtkCheckButton + HostInfoReachableCheckbutton + False + True + + False + True + + 0 + False + False + + + + + GtkCheckButton + HostInfoIndirectCheckbutton + False + True + + False + True + + 0 + False + False + + + + + GtkCheckButton + HostInfoVisibleCheckbutton + False + True + + False + True + + 0 + False + False + + - - - - GtkMenuItem - network1 - - False - GtkMenu - network1_menu + GtkHButtonBox + hbuttonbox3 + GTK_BUTTONBOX_SPREAD + 30 + 85 + 27 + 7 + 0 + + 0 + True + True + - GtkMenuItem - new_network1 - - activate - on_new_network1_activate - Sun, 24 Mar 2002 16:44:38 GMT - - - False + GtkButton + KeyRegenButton + True + True + + GTK_RELIEF_NORMAL - GtkMenuItem - settings1 - - False + GtkLabel + Notebook:tab + label2 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkHPaned + hpaned2 + 10 + 10 - GtkMenu - settings1_menu + GtkScrolledWindow + scrolledwindow4 + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_UPDATE_CONTINUOUS + GTK_UPDATE_CONTINUOUS + + True + False + - GtkMenuItem - settings1 - - activate - on_settings1_activate - Sun, 24 Mar 2002 20:42:33 GMT - - - False + GtkCList + HostConnectionsCList + 150 + True + 1 + 80 + GTK_SELECTION_SINGLE + False + GTK_SHADOW_IN + + + GtkLabel + CList:title + label5 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + - - - - GtkMenuItem - windows2 - - False - GtkMenu - windows2_menu + GtkVBox + vbox3 + False + 0 + + True + True + - GtkMenuItem - new_window1 - - activate - on_new_window1_activate - Sun, 24 Mar 2002 20:42:33 GMT - - - False + GtkFrame + InformationFrame + + 0 + GTK_SHADOW_ETCHED_IN + + 0 + True + True + + + + GtkTable + table1 + 6 + 2 + False + 0 + 0 + + + GtkLabel + label8 + + GTK_JUSTIFY_CENTER + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 0 + 1 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + label9 + + GTK_JUSTIFY_CENTER + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 1 + 2 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + label10 + + GTK_JUSTIFY_CENTER + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 2 + 3 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + label11 + + GTK_JUSTIFY_CENTER + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 3 + 4 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + label12 + + GTK_JUSTIFY_CENTER + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 4 + 5 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + label13 + + GTK_JUSTIFY_CENTER + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 5 + 6 + 0 + 0 + False + False + False + False + True + False + + + + + GtkEntry + entry4 + True + True + True + 0 + + + 1 + 2 + 0 + 1 + 0 + 0 + True + False + False + False + True + False + + + + + GtkEntry + entry5 + True + True + True + 0 + + + 1 + 2 + 1 + 2 + 0 + 0 + True + False + False + False + True + False + + + + + GtkEntry + entry6 + True + True + True + 0 + + + 1 + 2 + 2 + 3 + 0 + 0 + True + False + False + False + True + False + + + + + GtkEntry + entry7 + True + True + True + 0 + + + 1 + 2 + 4 + 5 + 0 + 0 + True + False + False + False + True + False + + + + + GtkEntry + entry8 + True + True + True + 0 + + + 1 + 2 + 3 + 4 + 0 + 0 + True + False + False + False + True + False + + + + + GtkEntry + entry9 + True + True + True + 0 + + + 1 + 2 + 5 + 6 + 0 + 0 + True + False + False + False + True + False + + + - GtkMenuItem - close_window1 - - activate - on_close_window1_activate - Sun, 24 Mar 2002 20:42:33 GMT - - - False + Placeholder - - - - GtkMenuItem - help1 - - False + + Placeholder + - - GtkMenu - help1_menu + + Placeholder + - GtkMenuItem - info1 - - activate - on_info1_activate - Sun, 24 Mar 2002 16:41:32 GMT - - - False + Placeholder + + + + GtkHButtonBox + hbuttonbox2 + GTK_BUTTONBOX_SPREAD + 30 + 85 + 27 + 7 + 0 + + 0 + True + True + + + + GtkButton + button9 + True + True + + GTK_RELIEF_NORMAL + + + + GtkButton + button10 + True + True + + GTK_RELIEF_NORMAL + + + + GtkButton + button16 + True + True + + GTK_RELIEF_NORMAL + + + + GtkLabel + Notebook:tab + label3 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + Placeholder + + + + GtkLabel + Notebook:tab + label4 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + - GtkHPaned - hpaned1 - 10 - 10 + GtkHButtonBox + hbuttonbox1 + GTK_BUTTONBOX_END + 30 + 85 + 27 + 7 + 0 0 - True + False True - GtkScrolledWindow - scrolledwindow1 - 250 - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_UPDATE_CONTINUOUS - GTK_UPDATE_CONTINUOUS + GtkButton + HostInfoCloseButton + True + True + + clicked + gtk_widget_destroy + True + Sun, 14 Apr 2002 20:33:19 GMT + + GNOME_STOCK_BUTTON_CLOSE + GTK_RELIEF_NORMAL + + + + + + + GtkMenu + LogContextMenu + + + GtkPixmapMenuItem + LogContextClear + + activate + on_logcontext_clear_activate + Sun, 14 Apr 2002 15:09:39 GMT + + + False + GNOME_STOCK_MENU_TRASH + + + + GtkCheckMenuItem + LogContextFollow + + activate + on_logcontext_follow_activate + Sun, 14 Apr 2002 15:09:39 GMT + + + True + True + + + + GtkPixmapMenuItem + sluiten1 + + activate + on_logcontext_close_activate + Sat, 27 Apr 2002 17:28:04 GMT + + GNOMEUIINFO_MENU_CLOSE_ITEM + + + + + GtkMenu + CanvasContextMenu + + + GtkCheckMenuItem + CanvasContextKeepDrawing + + activate + on_canvascontext_keep_drawing_activate + Sun, 14 Apr 2002 16:50:37 GMT + + + True + True + + + + GtkMenuItem + CanvasContextShuffle + + activate + on_canvascontext_shuffle_activate + Sun, 14 Apr 2002 16:50:37 GMT + + + False + + + + GtkMenuItem + zoom1 + + False + + + GtkMenu + zoom1_menu + + + GtkMenuItem + -50%1 + + activate + on_canvascontext_minus50_activate + Mon, 15 Apr 2002 21:13:24 GMT + + + False + + + + GtkMenuItem + -25%1 + + activate + on_canvascontext_minus25_activate + Mon, 15 Apr 2002 21:13:24 GMT + + + False + + + + GtkMenuItem + -10%1 + + activate + on_canvascontext_minus10_activate + Mon, 15 Apr 2002 21:13:24 GMT + + + False + + + + GtkMenuItem + default1 + + activate + on_canvascontext_default_activate + Mon, 15 Apr 2002 21:13:25 GMT + + + False + + + + GtkMenuItem + +10%1 + + activate + on_canvascontext_plus10_activate + Mon, 15 Apr 2002 21:13:25 GMT + + + False + + + + GtkMenuItem + +25%1 + + activate + on_canvascontext_plus25_activate + Mon, 15 Apr 2002 21:13:25 GMT + + + False + + + + GtkMenuItem + +50%1 + + activate + on_canvascontext_plus50_activate + Mon, 15 Apr 2002 21:13:25 GMT + + + False + + + + + + GtkPixmapMenuItem + sluiten2 + + activate + on_canvascontext_close_activate + Sat, 27 Apr 2002 17:27:44 GMT + + GNOMEUIINFO_MENU_CLOSE_ITEM + + + + + GnomeAbout + AboutWindow + True + pokey2.xpm + Copyright 1998-2002 + Guus Sliepen <guus@sliepen.warande.net> +Ivo Timmermans <ivo@o2w.nl> + + tinc comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to distribute it under certain conditions; see the file COPYING for details. + + + + GnomePropertyBox + PropertyBox + GTK_WIN_POS_NONE + False + False + False + False + + + GtkNotebook + GnomePropertyBox:notebook + notebook2 + True + True + True + GTK_POS_TOP + False + 2 + 2 + False + + 0 + True + True + + + + Placeholder + + + + GtkLabel + Notebook:tab + label19 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkVBox + vbox6 + False + 0 + + + GtkFrame + frame1 + + 0 + GTK_SHADOW_ETCHED_IN - False - True + 0 + True + True - GtkCTree - NodeTree - True - 1 - 80 - GTK_SELECTION_SINGLE - False - GTK_SHADOW_IN + GtkHBox + hbox3 + True + 0 GtkLabel - CTree:title - label1 - - GTK_JUSTIFY_CENTER + label26 + + GTK_JUSTIFY_LEFT False 0.5 0.5 0 0 + + 0 + True + True + + + + + GnomeColorPicker + LineColorPicker + True + + color_set + on_LineColorPicker_color_set + Tue, 16 Apr 2002 06:56:38 GMT + + True + False + Kies een kleur + + 0 + True + True + - GtkVPaned - vpaned1 - 10 - 10 + GtkFrame + frame2 + + 0 + GTK_SHADOW_ETCHED_IN - True - True + 0 + True + True - GtkScrolledWindow - scrolledwindow3 - 500 - 300 - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_UPDATE_CONTINUOUS - GTK_UPDATE_CONTINUOUS - - True - True - - + GtkTable + table5 + 3 + 2 + True + 0 + 0 - - GtkScrolledWindow - scrolledwindow2 - 500 - 200 - GTK_POLICY_NEVER - GTK_POLICY_ALWAYS - GTK_UPDATE_CONTINUOUS - GTK_UPDATE_CONTINUOUS - - True - True - + + GtkLabel + label29 + + GTK_JUSTIFY_LEFT + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 0 + 1 + 0 + 0 + True + False + True + False + True + False + + + + + GtkLabel + label30 + + GTK_JUSTIFY_LEFT + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 1 + 2 + 0 + 0 + True + False + True + False + True + False + + + + + GtkLabel + label31 + + GTK_JUSTIFY_LEFT + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 2 + 3 + 0 + 0 + True + False + True + False + True + False + + + + + GnomeFontPicker + LabelFontPicker + True + + font_set + on_LabelFontPicker_font_set + Tue, 16 Apr 2002 06:56:46 GMT + + Selecteer een lettertype + AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz + GNOME_FONT_PICKER_MODE_PIXMAP + True + False + 14 + + 1 + 2 + 0 + 1 + 0 + 0 + True + False + True + False + True + False + + + + + GnomeColorPicker + LabelColorPicker + True + + color_set + on_LabelColorPicker_color_set + Tue, 16 Apr 2002 06:56:51 GMT + + True + False + Kies een kleur + + 1 + 2 + 1 + 2 + 0 + 0 + True + False + True + False + True + False + + - GtkText - Messages - 500 - 300 - False - + GnomeColorPicker + LabelBackgroundPicker + True + + color_set + on_LabelBackgroundPicker_color_set + Tue, 16 Apr 2002 06:56:58 GMT + + True + False + Kies een kleur + + 1 + 2 + 2 + 3 + 0 + 0 + True + False + True + False + True + False + - GtkStatusbar - statusbar1 - - 0 - False - False - + GtkLabel + Notebook:tab + label20 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + Placeholder + + + + GtkLabel + Notebook:tab + label21 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 - GnomeDialog - dialog1 + GnomeApp + AppWindow + Pokey GTK_WINDOW_TOPLEVEL GTK_WIN_POS_NONE False False - False + True False - False - False + True - GtkVBox - GnomeDialog:vbox - dialog-vbox1 - False - 8 + GnomeDock + GnomeApp:dock + dock1 + True - 4 + 0 True True - GtkHButtonBox - GnomeDialog:action_area - dialog-action_area1 - GTK_BUTTONBOX_END - 8 - 85 - 27 - 7 - 0 - - 0 - False - True - GTK_PACK_END - + GnomeDockItem + dockitem1 + GNOME_DOCK_TOP + 0 + 0 + 0 + True + True + False + True + False + GTK_SHADOW_NONE - GtkButton - button6 - True - True - GNOME_STOCK_BUTTON_OK - + GtkMenuBar + menubar2 + GTK_SHADOW_NONE - - GtkButton - button7 - True - True - GNOME_STOCK_BUTTON_APPLY + + GtkMenuItem + file2 + GNOMEUIINFO_MENU_FILE_TREE + + + GtkMenu + file2_menu + + + GtkPixmapMenuItem + new_file1 + + activate + on_new_file1_activate + Sat, 27 Apr 2002 17:23:31 GMT + + GNOMEUIINFO_MENU_NEW_ITEM + + + + + GtkPixmapMenuItem + open1 + + activate + on_open1_activate + Sat, 27 Apr 2002 17:23:31 GMT + + GNOMEUIINFO_MENU_OPEN_ITEM + + + + GtkPixmapMenuItem + save1 + + activate + on_save1_activate + Sat, 27 Apr 2002 17:23:31 GMT + + GNOMEUIINFO_MENU_SAVE_ITEM + + + + GtkPixmapMenuItem + save_as1 + + activate + on_save_as1_activate + Sat, 27 Apr 2002 17:23:31 GMT + + GNOMEUIINFO_MENU_SAVE_AS_ITEM + + + + GtkMenuItem + separator1 + False + + + + GtkPixmapMenuItem + exit2 + + activate + on_exit2_activate + Sat, 27 Apr 2002 17:23:31 GMT + + GNOMEUIINFO_MENU_EXIT_ITEM + + + + + + GtkMenuItem + edit1 + GNOMEUIINFO_MENU_EDIT_TREE + + + GtkMenu + edit1_menu + + + GtkPixmapMenuItem + cut1 + + activate + on_cut1_activate + Sat, 27 Apr 2002 17:23:31 GMT + + GNOMEUIINFO_MENU_CUT_ITEM + + + + GtkPixmapMenuItem + copy1 + + activate + on_copy1_activate + Sat, 27 Apr 2002 17:23:31 GMT + + GNOMEUIINFO_MENU_COPY_ITEM + + + + GtkPixmapMenuItem + paste1 + + activate + on_paste1_activate + Sat, 27 Apr 2002 17:23:31 GMT + + GNOMEUIINFO_MENU_PASTE_ITEM + + + + GtkPixmapMenuItem + clear1 + + activate + on_clear1_activate + Sat, 27 Apr 2002 17:23:31 GMT + + GNOMEUIINFO_MENU_CLEAR_ITEM + + + + GtkMenuItem + separator2 + False + + + + GtkPixmapMenuItem + properties1 + + activate + on_properties1_activate + Sat, 27 Apr 2002 17:23:31 GMT + + GNOMEUIINFO_MENU_PROPERTIES_ITEM + + + + + + GtkMenuItem + view1 + GNOMEUIINFO_MENU_VIEW_TREE + + + GtkMenu + view1_menu + + + + + GtkMenuItem + settings2 + GNOMEUIINFO_MENU_SETTINGS_TREE + + + GtkMenu + settings2_menu + + + GtkPixmapMenuItem + preferences1 + + activate + on_preferences1_activate + Sat, 27 Apr 2002 17:23:31 GMT + + GNOMEUIINFO_MENU_PREFERENCES_ITEM + + + + + + GtkMenuItem + help2 + GNOMEUIINFO_MENU_HELP_TREE + + + GtkMenu + help2_menu + + + GtkPixmapMenuItem + about1 + + activate + on_about1_activate + Sat, 27 Apr 2002 17:23:31 GMT + + GNOMEUIINFO_MENU_ABOUT_ITEM + + + + + + + GtkScrolledWindow + GnomeDock:contents + scrolledwindow1 + 250 + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_UPDATE_CONTINUOUS + GTK_UPDATE_CONTINUOUS - GtkButton - button8 - True + GtkCTree + NodeTree True - GNOME_STOCK_BUTTON_CANCEL + + button_press_event + on_nodetree_button_press_event + Sun, 14 Apr 2002 19:34:40 GMT + + 1 + 80 + GTK_SELECTION_SINGLE + False + GTK_SHADOW_IN + + + GtkLabel + CTree:title + label1 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + + GnomeAppBar + GnomeApp:appbar + appbar2 + True + True + + 0 + True + True + + + + + + GtkWindow + LogWindow + Log + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + False + True + False + + + GtkScrolledWindow + scrolledwindow2 + GTK_POLICY_NEVER + GTK_POLICY_ALWAYS + GTK_UPDATE_CONTINUOUS + GTK_UPDATE_CONTINUOUS - Placeholder + GtkText + Messages + 500 + 300 + + button_press_event + on_messages_button_press_event + Sun, 14 Apr 2002 19:34:28 GMT + + False + + + + + + + GtkWindow + GraphWindow + Graph + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + False + True + False + + + GtkScrolledWindow + scrolledwindow3 + GTK_POLICY_ALWAYS + GTK_POLICY_ALWAYS + GTK_UPDATE_CONTINUOUS + GTK_UPDATE_CONTINUOUS + + + GnomeCanvas + canvas1 + 500 + 300 + True + + button_press_event + on_canvas_button_press_event + Sun, 14 Apr 2002 15:21:11 GMT + + True + 0 + 0 + 100 + 100 + 1 diff --git a/src/pokey/pokey2.xpm b/src/pokey/pokey2.xpm new file mode 100644 index 00000000..b847f7fa --- /dev/null +++ b/src/pokey/pokey2.xpm @@ -0,0 +1,56 @@ +/* XPM */ +static char * pokey2_xpm[] = { +"36 49 4 1", +" c None", +". c #000000", +"+ c #FFFFFF", +"@ c #E9A500", +" .......... ", +" ............. ", +" ................ ", +" ................. ", +" .................. ", +" ................... ", +" ..................... ", +" ........++............. ", +" .........++.............. ", +" ..+....+..++................ ", +" .++++++...+................. ", +" ....+.+...................... ", +" ..@@@@@@.++..................... ", +" .@@@@@@@@.+++..................... ", +"...........++++.................... ", +" .@@@@@@@@.++++.....................", +" .....@@@.++++.....................", +" .....+++++....................", +" .++++++++++...................", +" .++++++++++++..................", +" .++++++++++++..................", +" .+++++++++++++..................", +" .+++++++++++++..................", +" .+++++++++++++................. ", +" .+++++++++++++................. ", +" .+++++++++++++.....+........... ", +" .+++++++++++++.....+........... ", +" .++++++++++++++....+........... ", +" .++++++++++++++................ ", +" .++++++++++++++...+............ ", +" .++++++++++++++...+........... ", +" .++++++++++++++...+........... ", +" .++++++++++++++..++........... ", +" .++++++++++++++++++........... ", +" .++++++++++++++++++........... ", +" .++++++++++++++++++.......... ", +" .+++++++++++++++++.......... ", +" .++++++++++++++++........... ", +" .++++++++++++++++........... ", +" .++++++++++++++++........... ", +" .+++++++++++++++........... ", +" ..+++++++++++............. ", +" . .++++++++............... ", +" ..+++++.+............. ", +" ....+.++............ ", +" ................... ", +" .................... ", +" .............. .. ", +" . .. "}; diff --git a/src/pokey/process.c b/src/pokey/process.c new file mode 100644 index 00000000..ef426cb6 --- /dev/null +++ b/src/pokey/process.c @@ -0,0 +1,469 @@ +/* + process.c -- process management functions + Copyright (C) 1999-2002 Ivo Timmermans , + 2000-2002 Guus Sliepen + + 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: process.c,v 1.1 2002/04/28 12:46:26 zarq Exp $ +*/ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "conf.h" +#include "interface.h" +#include "process.h" +#include "subnet.h" +#include "connection.h" +#include "logging.h" + +#include "system.h" + +/* If zero, don't detach from the terminal. */ +int do_detach = 1; + +extern char *identname; +extern char *pidfilename; +extern char **g_argv; + +sigset_t emptysigset; + +static int saved_debug_lvl = 0; + +extern int sighup; +extern int sigalrm; +extern int do_purge; + +void memory_full(int size) +{ + log(0, TLOG_ERROR, + _("Memory exhausted (couldn't allocate %d bytes), exitting."), + size); + cp_trace(); + exit(1); +} + +/* Some functions the less gifted operating systems might lack... */ + +#ifndef HAVE_FCLOSEALL +int fcloseall(void) +{ + fflush(stdin); + fflush(stdout); + fflush(stderr); + fclose(stdin); + fclose(stdout); + fclose(stderr); + return 0; +} +#endif + +/* + Close network connections, and terminate neatly +*/ +void cleanup_and_exit(int c) +{ +cp + close_network_connections(); + + syslog(LOG_NOTICE, _("Terminating")); + + closelog(); + exit(c); +} + +/* + check for an existing tinc for this net, and write pid to pidfile +*/ +int write_pidfile(void) +{ + int pid; +cp + if((pid = check_pid(pidfilename))) + { + if(netname) + fprintf(stderr, _("A tincd is already running for net `%s' with pid %d.\n"), + netname, pid); + else + fprintf(stderr, _("A tincd is already running with pid %d.\n"), pid); + return 1; + } + + /* if it's locked, write-protected, or whatever */ + if(!write_pid(pidfilename)) + return 1; +cp + return 0; +} + +/* + kill older tincd for this net +*/ +int kill_other(int signal) +{ + int pid; +cp + if(!(pid = read_pid(pidfilename))) + { + if(netname) + fprintf(stderr, _("No other tincd is running for net `%s'.\n"), netname); + else + fprintf(stderr, _("No other tincd is running.\n")); + return 1; + } + + errno = 0; /* No error, sometimes errno is only changed on error */ + /* ESRCH is returned when no process with that pid is found */ + if(kill(pid, signal) && errno == ESRCH) + { + if(netname) + fprintf(stderr, _("The tincd for net `%s' is no longer running. "), netname); + else + fprintf(stderr, _("The tincd is no longer running. ")); + + fprintf(stderr, _("Removing stale lock file.\n")); + remove_pid(pidfilename); + } +cp + return 0; +} + +/* + Detach from current terminal, write pidfile, kill parent +*/ +int detach(void) +{ +cp + setup_signals(); + + /* First check if we can open a fresh new pidfile */ + + if(write_pidfile()) + return -1; + + /* If we succeeded in doing that, detach */ + + closelog(); + + if(do_detach) + { + if(daemon(0, 0) < 0) + { + fprintf(stderr, _("Couldn't detach from terminal: %s"), strerror(errno)); + return -1; + } + + /* Now UPDATE the pid in the pidfile, because we changed it... */ + + if(!write_pid(pidfilename)) + return -1; + } + + openlog(identname, LOG_CONS | LOG_PID, LOG_DAEMON); + + if(debug_lvl > DEBUG_NOTHING) + log(0, TLOG_NOTICE, + _("tincd %s (%s %s) starting, debug level %d"), + VERSION, __DATE__, __TIME__, debug_lvl); + else + log(DEBUG_NOTHING, TLOG_NOTICE, + _("tincd %s starting"), + VERSION); + + xalloc_fail_func = memory_full; +cp + return 0; +} + +/* + Execute the program name, with sane environment. All output will be + redirected to syslog. +*/ +void _execute_script(const char *name) __attribute__ ((noreturn)); +void _execute_script(const char *name) +{ + char *scriptname; + char *s; +cp +#ifdef HAVE_UNSETENV + unsetenv("NETNAME"); + unsetenv("INTERFACE"); +#endif + + if(netname) + { + asprintf(&s, "NETNAME=%s", netname); + putenv(s); /* Don't free s! see man 3 putenv */ + } + + chdir("/"); + + asprintf(&scriptname, "%s/%s", confbase, name); + + /* Close all file descriptors */ + closelog(); /* <- this means we cannot use syslog() here anymore! */ + fcloseall(); + + execl(scriptname, NULL); + /* No return on success */ + + if(errno != ENOENT) /* Ignore if the file does not exist */ + exit(1); /* Some error while trying execl(). */ + else + exit(0); +} + +/* + Fork and execute the program pointed to by name. +*/ +int execute_script(const char *name) +{ + pid_t pid; + int status; +cp + if((pid = fork()) < 0) + { + syslog(LOG_ERR, _("System call `%s' failed: %s"), "fork", strerror(errno)); + return -1; + } + + if(pid) + { + log(DEBUG_STATUS, TLOG_INFO, + _("Executing script %s"), + name); + + if(waitpid(pid, &status, 0) == pid) + { + if(WIFEXITED(status)) /* Child exited by itself */ + { + if(WEXITSTATUS(status)) + { + syslog(LOG_ERR, _("Process %d (%s) exited with non-zero status %d"), pid, name, WEXITSTATUS(status)); + return -1; + } + else + return 0; + } + else if(WIFSIGNALED(status)) /* Child was killed by a signal */ + { + syslog(LOG_ERR, _("Process %d (%s) was killed by signal %d (%s)"), + pid, name, WTERMSIG(status), strsignal(WTERMSIG(status))); + return -1; + } + else /* Something strange happened */ + { + syslog(LOG_ERR, _("Process %d (%s) terminated abnormally"), pid, name); + return -1; + } + } + else + { + syslog(LOG_ERR, _("System call `%s' failed: %s"), "waitpid", strerror(errno)); + return -1; + } + } +cp + /* Child here */ + + _execute_script(name); +} + + +/* + Signal handlers. +*/ + +RETSIGTYPE +sigterm_handler(int a) +{ + log(DEBUG_NOTHING, TLOG_NOTICE, + _("Got TERM signal")); + + cleanup_and_exit(0); +} + +RETSIGTYPE +sigquit_handler(int a) +{ + log(DEBUG_NOTHING, TLOG_NOTICE, + _("Got QUIT signal")); + cleanup_and_exit(0); +} + +RETSIGTYPE +fatal_signal_square(int a) +{ + syslog(LOG_ERR, _("Got another fatal signal %d (%s): not restarting."), a, strsignal(a)); + cp_trace(); + exit(1); +} + +RETSIGTYPE +fatal_signal_handler(int a) +{ + syslog(LOG_ERR, _("Got fatal signal %d (%s)"), a, strsignal(a)); + cp_trace(); + + syslog(LOG_NOTICE, _("Not restarting.")); + exit(1); +} + +RETSIGTYPE +sighup_handler(int a) +{ + if(debug_lvl > DEBUG_NOTHING) + syslog(LOG_NOTICE, _("Got HUP signal")); + sighup = 1; +} + +RETSIGTYPE +sigint_handler(int a) +{ + if(saved_debug_lvl) + { + syslog(LOG_NOTICE, _("Reverting to old debug level (%d)"), + saved_debug_lvl); + debug_lvl = saved_debug_lvl; + saved_debug_lvl = 0; + } + else + { + syslog(LOG_NOTICE, _("Temporarily setting debug level to 5. Kill me with SIGINT again to go back to level %d."), + debug_lvl); + saved_debug_lvl = debug_lvl; + debug_lvl = 5; + } +} + +RETSIGTYPE +sigalrm_handler(int a) +{ + if(debug_lvl > DEBUG_NOTHING) + syslog(LOG_NOTICE, _("Got ALRM signal")); + sigalrm = 1; +} + +RETSIGTYPE +sigusr1_handler(int a) +{ + dump_connections(); +} + +RETSIGTYPE +sigusr2_handler(int a) +{ + dump_nodes(); + dump_edges(); + dump_subnets(); +} + +RETSIGTYPE +sigwinch_handler(int a) +{ + extern int do_purge; + do_purge = 1; +} + +RETSIGTYPE +unexpected_signal_handler(int a) +{ + syslog(LOG_WARNING, _("Got unexpected signal %d (%s)"), a, strsignal(a)); + cp_trace(); +} + +RETSIGTYPE +ignore_signal_handler(int a) +{ + if(debug_lvl >= DEBUG_SCARY_THINGS) + { + syslog(LOG_DEBUG, _("Ignored signal %d (%s)"), a, strsignal(a)); + cp_trace(); + } +} + +struct { + int signal; + void (*handler)(int); +} sighandlers[] = { + { SIGHUP, sighup_handler }, + { SIGTERM, sigterm_handler }, + { SIGQUIT, sigquit_handler }, + { SIGSEGV, fatal_signal_handler }, + { SIGBUS, fatal_signal_handler }, + { SIGILL, fatal_signal_handler }, + { SIGPIPE, ignore_signal_handler }, + { SIGINT, sigint_handler }, + { SIGUSR1, sigusr1_handler }, + { SIGUSR2, sigusr2_handler }, + { SIGCHLD, ignore_signal_handler }, + { SIGALRM, sigalrm_handler }, + { SIGWINCH, sigwinch_handler }, + { 0, NULL } +}; + +void +setup_signals(void) +{ + int i; + struct sigaction act; + + sigemptyset(&emptysigset); + act.sa_handler = NULL; + act.sa_mask = emptysigset; + act.sa_flags = 0; + + /* Set a default signal handler for every signal, errors will be + ignored. */ + for(i = 0; i < NSIG; i++) + { + if(!do_detach) + act.sa_handler = SIG_DFL; + else + act.sa_handler = unexpected_signal_handler; + sigaction(i, &act, NULL); + } + + /* If we didn't detach, allow coredumps */ + if(!do_detach) + sighandlers[3].handler = SIG_DFL; + + /* Then, for each known signal that we want to catch, assign a + handler to the signal, with error checking this time. */ + for(i = 0; sighandlers[i].signal; i++) + { + act.sa_handler = sighandlers[i].handler; + if(sigaction(sighandlers[i].signal, &act, NULL) < 0) + fprintf(stderr, _("Installing signal handler for signal %d (%s) failed: %s\n"), + sighandlers[i].signal, strsignal(sighandlers[i].signal), strerror(errno)); + } +} diff --git a/src/pokey/process.h b/src/pokey/process.h new file mode 100644 index 00000000..251da686 --- /dev/null +++ b/src/pokey/process.h @@ -0,0 +1,36 @@ +/* + process.h -- header file for process.c + Copyright (C) 1999-2002 Ivo Timmermans , + 2000-2002 Guus Sliepen + + 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: process.h,v 1.1 2002/04/28 12:46:26 zarq Exp $ +*/ + +#ifndef __TINC_PROCESS_H__ +#define __TINC_PROCESS_H__ + +#include "config.h" + +extern int do_detach; + +extern void setup_signals(void); +extern int execute_script(const char *); +extern int detach(void); +extern int kill_other(int); +extern void cleanup_and_exit(int); + +#endif /* __TINC_PROCESS_H__ */ diff --git a/src/pokey/protocol.c b/src/pokey/protocol.c new file mode 100644 index 00000000..e60598cb --- /dev/null +++ b/src/pokey/protocol.c @@ -0,0 +1,245 @@ +/* + protocol.c -- handle the meta-protocol, basic functions + Copyright (C) 1999-2001 Ivo Timmermans , + 2000,2001 Guus Sliepen + + 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: protocol.c,v 1.1 2002/04/28 12:46:26 zarq Exp $ +*/ + +#include "config.h" + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "conf.h" +#include "protocol.h" +#include "meta.h" +#include "connection.h" +#include "interface.h" +#include "logging.h" + +#include "system.h" + +avl_tree_t *past_request_tree; + +int check_id(char *id) +{ + int i; + + for (i = 0; i < strlen(id); i++) + if(!isalnum(id[i]) && id[i] != '_') + return -1; + + return 0; +} + +/* Generic request routines - takes care of logging and error + detection as well */ + +int send_request(connection_t *c, const char *format, ...) +{ + va_list args; + char buffer[MAXBUFSIZE]; + int len, request; + +cp + /* Use vsnprintf instead of vasprintf: faster, no memory + fragmentation, cleanup is automatic, and there is a limit on the + input buffer anyway */ + + va_start(args, format); + len = vsnprintf(buffer, MAXBUFSIZE, format, args); + va_end(args); + + if(len < 0 || len > MAXBUFSIZE-1) + { + syslog(LOG_ERR, _("Output buffer overflow while sending request to %s (%s)"), c->name, c->hostname); + return -1; + } + + if(debug_lvl >= DEBUG_PROTOCOL) + { + sscanf(buffer, "%d", &request); + if(debug_lvl >= DEBUG_META) + syslog(LOG_DEBUG, _("Sending %s to %s (%s): %s"), request_name[request], c->name, c->hostname, buffer); + else + syslog(LOG_DEBUG, _("Sending %s to %s (%s)"), request_name[request], c->name, c->hostname); + } + + buffer[len++] = '\n'; +cp + return send_meta(c, buffer, len); +} + +int receive_request(connection_t *c) +{ + int request; +cp + if(sscanf(c->buffer, "%d", &request) == 1) + { + if((request < 0) || (request >= LAST) || (request_handlers[request] == NULL)) + { + if(debug_lvl >= DEBUG_META) + syslog(LOG_DEBUG, _("Unknown request from %s (%s): %s"), + c->name, c->hostname, c->buffer); + else + syslog(LOG_ERR, _("Unknown request from %s (%s)"), + c->name, c->hostname); + + return -1; + } + else + { + if(debug_lvl >= DEBUG_PROTOCOL) + { + if(debug_lvl >= DEBUG_META) + syslog(LOG_DEBUG, _("Got %s from %s (%s): %s"), + request_name[request], c->name, c->hostname, c->buffer); + else + syslog(LOG_DEBUG, _("Got %s from %s (%s)"), + request_name[request], c->name, c->hostname); + } + } + + if((c->allow_request != ALL) && (c->allow_request != request)) + { + syslog(LOG_ERR, _("Unauthorized request from %s (%s)"), c->name, c->hostname); + return -1; + } + + if(request_handlers[request](c)) + /* Something went wrong. Probably scriptkiddies. Terminate. */ + { + syslog(LOG_ERR, _("Error while processing %s from %s (%s)"), + request_name[request], c->name, c->hostname); + return -1; + } + } + else + { + syslog(LOG_ERR, _("Bogus data received from %s (%s)"), + c->name, c->hostname); + return -1; + } +cp + return 0; +} + +int past_request_compare(past_request_t *a, past_request_t *b) +{ +cp + return strcmp(a->request, b->request); +} + +void free_past_request(past_request_t *r) +{ +cp + if(r->request) + free(r->request); + free(r); +cp +} + +void init_requests(void) +{ +cp + past_request_tree = avl_alloc_tree((avl_compare_t)past_request_compare, (avl_action_t)free_past_request); +cp +} + +void exit_requests(void) +{ +cp + avl_delete_tree(past_request_tree); +cp +} + +int seen_request(char *request) +{ + past_request_t p, *new; +cp + p.request = request; + + if(avl_search(past_request_tree, &p)) + { + if(debug_lvl >= DEBUG_SCARY_THINGS) + syslog(LOG_DEBUG, _("Already seen request")); + return 1; + } + else + { + new = (past_request_t *)xmalloc(sizeof(*new)); + new->request = xstrdup(request); + new->firstseen = now; + avl_insert(past_request_tree, new); + return 0; + } +cp +} + +void age_past_requests(void) +{ + avl_node_t *node, *next; + past_request_t *p; + int left = 0, deleted = 0; +cp + for(node = past_request_tree->head; node; node = next) + { + next = node->next; + p = (past_request_t *)node->data; + if(p->firstseen + pingtimeout < now) + avl_delete_node(past_request_tree, node), deleted++; + else + left++; + } + + if(debug_lvl >= DEBUG_SCARY_THINGS && left + deleted) + syslog(LOG_DEBUG, _("Aging past requests: deleted %d, left %d\n"), deleted, left); +cp +} + +/* Jumptable for the request handlers */ + +int (*request_handlers[])(connection_t*) = { + id_h, metakey_h, challenge_h, chal_reply_h, ack_h, + status_h, error_h, termreq_h, + ping_h, pong_h, +// add_node_h, del_node_h, + add_subnet_h, del_subnet_h, + add_edge_h, del_edge_h, + key_changed_h, req_key_h, ans_key_h, +}; + +/* Request names */ + +char (*request_name[]) = { + "ID", "METAKEY", "CHALLENGE", "CHAL_REPLY", "ACK", + "STATUS", "ERROR", "TERMREQ", + "PING", "PONG", +// "ADD_NODE", "DEL_NODE", + "ADD_SUBNET", "DEL_SUBNET", + "ADD_EDGE", "DEL_EDGE", + "KEY_CHANGED", "REQ_KEY", "ANS_KEY", +}; diff --git a/src/pokey/protocol.h b/src/pokey/protocol.h new file mode 100644 index 00000000..9e4c09ea --- /dev/null +++ b/src/pokey/protocol.h @@ -0,0 +1,120 @@ +/* + protocol.h -- header for protocol.c + Copyright (C) 1999-2001 Ivo Timmermans , + 2000,2001 Guus Sliepen + + 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: protocol.h,v 1.1 2002/04/28 12:46:26 zarq Exp $ +*/ + +#ifndef __TINC_PROTOCOL_H__ +#define __TINC_PROTOCOL_H__ + +#include "net.h" +#include "node.h" +#include "subnet.h" + +/* Protocol version. Different versions are incompatible, + incompatible version have different protocols. + */ + +#define PROT_CURRENT 14 + +/* Request numbers */ + +enum { + ALL = -1, /* Guardian for allow_request */ + ID = 0, METAKEY, CHALLENGE, CHAL_REPLY, ACK, + STATUS, ERROR, TERMREQ, + PING, PONG, +// ADD_NODE, DEL_NODE, + ADD_SUBNET, DEL_SUBNET, + ADD_EDGE, DEL_EDGE, + KEY_CHANGED, REQ_KEY, ANS_KEY, + PACKET, + LAST /* Guardian for the highest request number */ +}; + +typedef struct past_request_t { + char *request; + time_t firstseen; +} past_request_t; + +/* Maximum size of strings in a request */ + +#define MAX_STRING_SIZE 2048 +#define MAX_STRING "%2048s" + +/* Basic functions */ + +extern int send_request(connection_t*, const char*, ...); +extern int receive_request(connection_t *); +extern int check_id(char *); + +extern void init_requests(void); +extern void exit_requests(void); +extern int seen_request(char *); +extern void age_past_requests(void); + +/* Requests */ + +extern int send_id(connection_t *); +extern int send_metakey(connection_t *); +extern int send_challenge(connection_t *); +extern int send_chal_reply(connection_t *); +extern int send_ack(connection_t *); +extern int send_status(connection_t *, int, char *); +extern int send_error(connection_t *, int, char *); +extern int send_termreq(connection_t *); +extern int send_ping(connection_t *); +extern int send_pong(connection_t *); +// extern int send_add_node(connection_t *, node_t *); +// extern int send_del_node(connection_t *, node_t *); +extern int send_add_subnet(connection_t *, subnet_t *); +extern int send_del_subnet(connection_t *, subnet_t *); +extern int send_add_edge(connection_t *, edge_t *); +extern int send_del_edge(connection_t *, edge_t *); +extern int send_key_changed(connection_t *, node_t *); +extern int send_req_key(connection_t *, node_t *, node_t *); +extern int send_ans_key(connection_t *, node_t *, node_t *); +extern int send_tcppacket(connection_t *, vpn_packet_t *); + +/* Request handlers */ + +extern int (*request_handlers[])(connection_t *); + +extern int id_h(connection_t *); +extern int metakey_h(connection_t *); +extern int challenge_h(connection_t *); +extern int chal_reply_h(connection_t *); +extern int ack_h(connection_t *); +extern int status_h(connection_t *); +extern int error_h(connection_t *); +extern int termreq_h(connection_t *); +extern int ping_h(connection_t *); +extern int pong_h(connection_t *); +// extern int add_node_h(connection_t *); +// extern int del_node_h(connection_t *); +extern int add_subnet_h(connection_t *); +extern int del_subnet_h(connection_t *); +extern int add_edge_h(connection_t *); +extern int del_edge_h(connection_t *); +extern int key_changed_h(connection_t *); +extern int req_key_h(connection_t *); +extern int ans_key_h(connection_t *); +extern int tcppacket_h(connection_t *); + +#endif /* __TINC_PROTOCOL_H__ */ diff --git a/src/pokey/protocol_auth.c b/src/pokey/protocol_auth.c new file mode 100644 index 00000000..f45a4634 --- /dev/null +++ b/src/pokey/protocol_auth.c @@ -0,0 +1,609 @@ +/* + protocol_auth.c -- handle the meta-protocol, authentication + Copyright (C) 1999-2002 Ivo Timmermans , + 2000-2002 Guus Sliepen + + 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: protocol_auth.c,v 1.1 2002/04/28 12:46:26 zarq Exp $ +*/ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#ifndef HAVE_RAND_PSEUDO_BYTES +#define RAND_pseudo_bytes RAND_bytes +#endif + +#include "conf.h" +#include "interface.h" +#include "net.h" +#include "netutl.h" +#include "protocol.h" +#include "meta.h" +#include "connection.h" +#include "node.h" +#include "edge.h" +#include "graph.h" +#include "logging.h" + +#include "system.h" + +int send_id(connection_t *c) +{ +cp + return send_request(c, "%d %s %d", ID, myself->connection->name, myself->connection->protocol_version); +} + +int id_h(connection_t *c) +{ + char name[MAX_STRING_SIZE]; + int bla; +cp + if(sscanf(c->buffer, "%*d "MAX_STRING" %d", name, &c->protocol_version) != 2) + { + syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "ID", c->name, c->hostname); + return -1; + } + + /* Check if identity is a valid name */ + + if(check_id(name)) + { + syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ID", c->name, c->hostname, "invalid name"); + return -1; + } + + /* If we set c->name in advance, make sure we are connected to the right host */ + + if(c->name) + { + if(strcmp(c->name, name)) + { + syslog(LOG_ERR, _("Peer %s is %s instead of %s"), c->hostname, name, c->name); + return -1; + } + } + else + c->name = xstrdup(name); + + /* Check if version matches */ + + if(c->protocol_version != myself->connection->protocol_version) + { + syslog(LOG_ERR, _("Peer %s (%s) uses incompatible version %d"), + c->name, c->hostname, c->protocol_version); + return -1; + } + + if(bypass_security) + { + if(!c->config_tree) + init_configuration(&c->config_tree); + c->allow_request = ACK; + return send_ack(c); + } + + if(!c->config_tree) + { + init_configuration(&c->config_tree); + + if((bla = read_connection_config(c))) + { + syslog(LOG_ERR, _("Peer %s had unknown identity (%s)"), c->hostname, c->name); + return -1; + } + } + + if(read_rsa_public_key(c)) + { + return -1; + } + + /* Check some options */ + + if((get_config_bool(lookup_config(c->config_tree, "IndirectData"), &bla) && bla) || myself->options & OPTION_INDIRECT) + c->options |= OPTION_INDIRECT; + + if((get_config_bool(lookup_config(c->config_tree, "TCPOnly"), &bla) && bla) || myself->options & OPTION_TCPONLY) + c->options |= OPTION_TCPONLY | OPTION_INDIRECT; + + c->allow_request = METAKEY; +cp + return send_metakey(c); +} + +int send_metakey(connection_t *c) +{ + char buffer[MAX_STRING_SIZE]; + int len, x; +cp + len = RSA_size(c->rsa_key); + + /* Allocate buffers for the meta key */ + + if(!c->outkey) + c->outkey = xmalloc(len); + + if(!c->outctx) + c->outctx = xmalloc(sizeof(*c->outctx)); +cp + /* Copy random data to the buffer */ + + RAND_bytes(c->outkey, len); + + /* The message we send must be smaller than the modulus of the RSA key. + By definition, for a key of k bits, the following formula holds: + + 2^(k-1) <= modulus < 2^(k) + + Where ^ means "to the power of", not "xor". + This means that to be sure, we must choose our message < 2^(k-1). + This can be done by setting the most significant bit to zero. + */ + + c->outkey[0] &= 0x7F; + + if(debug_lvl >= DEBUG_SCARY_THINGS) + { + bin2hex(c->outkey, buffer, len); + buffer[len*2] = '\0'; + syslog(LOG_DEBUG, _("Generated random meta key (unencrypted): %s"), buffer); + } + + /* Encrypt the random data + + We do not use one of the PKCS padding schemes here. + This is allowed, because we encrypt a totally random string + with a length equal to that of the modulus of the RSA key. + */ + + if(RSA_public_encrypt(len, c->outkey, buffer, c->rsa_key, RSA_NO_PADDING) != len) + { + syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), c->name, c->hostname); + return -1; + } +cp + /* Convert the encrypted random data to a hexadecimal formatted string */ + + bin2hex(buffer, buffer, len); + buffer[len*2] = '\0'; + + /* Send the meta key */ + + x = send_request(c, "%d %d %d %d %d %s", METAKEY, + c->outcipher?c->outcipher->nid:0, c->outdigest?c->outdigest->type:0, + c->outmaclength, c->outcompression, buffer); + + /* Further outgoing requests are encrypted with the key we just generated */ + + if(c->outcipher) + { + EVP_EncryptInit(c->outctx, c->outcipher, + c->outkey + len - c->outcipher->key_len, + c->outkey + len - c->outcipher->key_len - c->outcipher->iv_len); + + c->status.encryptout = 1; + } +cp + return x; +} + +int metakey_h(connection_t *c) +{ + char buffer[MAX_STRING_SIZE]; + int cipher, digest, maclength, compression; + int len; +cp + if(sscanf(c->buffer, "%*d %d %d %d %d "MAX_STRING, &cipher, &digest, &maclength, &compression, buffer) != 5) + { + syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "METAKEY", c->name, c->hostname); + return -1; + } +cp + len = RSA_size(myself->connection->rsa_key); + + /* Check if the length of the meta key is all right */ + + if(strlen(buffer) != len*2) + { + syslog(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, "wrong keylength"); + return -1; + } + + /* Allocate buffers for the meta key */ +cp + if(!c->inkey) + c->inkey = xmalloc(len); + + if(!c->inctx) + c->inctx = xmalloc(sizeof(*c->inctx)); + + /* Convert the challenge from hexadecimal back to binary */ +cp + hex2bin(buffer,buffer,len); + + /* Decrypt the meta key */ +cp + if(RSA_private_decrypt(len, buffer, c->inkey, myself->connection->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */ + { + syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), c->name, c->hostname); + return -1; + } + + if(debug_lvl >= DEBUG_SCARY_THINGS) + { + bin2hex(c->inkey, buffer, len); + buffer[len*2] = '\0'; + syslog(LOG_DEBUG, _("Received random meta key (unencrypted): %s"), buffer); + } + + /* All incoming requests will now be encrypted. */ +cp + /* Check and lookup cipher and digest algorithms */ + + if(cipher) + { + c->incipher = EVP_get_cipherbynid(cipher); + if(!c->incipher) + { + syslog(LOG_ERR, _("%s (%s) uses unknown cipher!"), c->name, c->hostname); + return -1; + } + + EVP_DecryptInit(c->inctx, c->incipher, + c->inkey + len - c->incipher->key_len, + c->inkey + len - c->incipher->key_len - c->incipher->iv_len); + + c->status.decryptin = 1; + } + else + { + c->incipher = NULL; + } + + c->inmaclength = maclength; + + if(digest) + { + c->indigest = EVP_get_digestbynid(digest); + if(!c->indigest) + { + syslog(LOG_ERR, _("Node %s (%s) uses unknown digest!"), c->name, c->hostname); + return -1; + } + + if(c->inmaclength > c->indigest->md_size || c->inmaclength < 0) + { + syslog(LOG_ERR, _("%s (%s) uses bogus MAC length!"), c->name, c->hostname); + return -1; + } + } + else + { + c->indigest = NULL; + } + + c->incompression = compression; + + c->allow_request = CHALLENGE; +cp + return send_challenge(c); +} + +int send_challenge(connection_t *c) +{ + char buffer[MAX_STRING_SIZE]; + int len, x; +cp + /* CHECKME: what is most reasonable value for len? */ + + len = RSA_size(c->rsa_key); + + /* Allocate buffers for the challenge */ + + if(!c->hischallenge) + c->hischallenge = xmalloc(len); +cp + /* Copy random data to the buffer */ + + RAND_bytes(c->hischallenge, len); + +cp + /* Convert to hex */ + + bin2hex(c->hischallenge, buffer, len); + buffer[len*2] = '\0'; + +cp + /* Send the challenge */ + + x = send_request(c, "%d %s", CHALLENGE, buffer); +cp + return x; +} + +int challenge_h(connection_t *c) +{ + char buffer[MAX_STRING_SIZE]; + int len; +cp + if(sscanf(c->buffer, "%*d "MAX_STRING, buffer) != 1) + { + syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "CHALLENGE", c->name, c->hostname); + return -1; + } + + len = RSA_size(myself->connection->rsa_key); + + /* Check if the length of the challenge is all right */ + + if(strlen(buffer) != len*2) + { + syslog(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, "wrong challenge length"); + return -1; + } + + /* Allocate buffers for the challenge */ + + if(!c->mychallenge) + c->mychallenge = xmalloc(len); + + /* Convert the challenge from hexadecimal back to binary */ + + hex2bin(buffer,c->mychallenge,len); + + c->allow_request = CHAL_REPLY; + + /* Rest is done by send_chal_reply() */ +cp + return send_chal_reply(c); +} + +int send_chal_reply(connection_t *c) +{ + char hash[EVP_MAX_MD_SIZE*2+1]; + EVP_MD_CTX ctx; +cp + /* Calculate the hash from the challenge we received */ + + EVP_DigestInit(&ctx, c->indigest); + EVP_DigestUpdate(&ctx, c->mychallenge, RSA_size(myself->connection->rsa_key)); + EVP_DigestFinal(&ctx, hash, NULL); + + /* Convert the hash to a hexadecimal formatted string */ + + bin2hex(hash,hash,c->indigest->md_size); + hash[c->indigest->md_size*2] = '\0'; + + /* Send the reply */ + +cp + return send_request(c, "%d %s", CHAL_REPLY, hash); +} + +int chal_reply_h(connection_t *c) +{ + char hishash[MAX_STRING_SIZE]; + char myhash[EVP_MAX_MD_SIZE]; + EVP_MD_CTX ctx; +cp + if(sscanf(c->buffer, "%*d "MAX_STRING, hishash) != 1) + { + syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "CHAL_REPLY", c->name, c->hostname); + return -1; + } + + /* Check if the length of the hash is all right */ + + if(strlen(hishash) != c->outdigest->md_size*2) + { + syslog(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, _("wrong challenge reply length")); + return -1; + } + + /* Convert the hash to binary format */ + + hex2bin(hishash, hishash, c->outdigest->md_size); + + /* Calculate the hash from the challenge we sent */ + + EVP_DigestInit(&ctx, c->outdigest); + EVP_DigestUpdate(&ctx, c->hischallenge, RSA_size(c->rsa_key)); + EVP_DigestFinal(&ctx, myhash, NULL); + + /* Verify the incoming hash with the calculated hash */ + + if(memcmp(hishash, myhash, c->outdigest->md_size)) + { + syslog(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, _("wrong challenge reply")); + if(debug_lvl >= DEBUG_SCARY_THINGS) + { + bin2hex(myhash, hishash, SHA_DIGEST_LENGTH); + hishash[SHA_DIGEST_LENGTH*2] = '\0'; + syslog(LOG_DEBUG, _("Expected challenge reply: %s"), hishash); + } + return -1; + } + + /* Identity has now been positively verified. + Send an acknowledgement with the rest of the information needed. + */ + + c->allow_request = ACK; +cp + return send_ack(c); +} + +int send_ack(connection_t *c) +{ + /* ACK message contains rest of the information the other end needs + to create node_t and edge_t structures. */ + + int x; + char *address, *port; + struct timeval now; +cp + /* Estimate weight */ + + gettimeofday(&now, NULL); + c->estimated_weight = (now.tv_sec - c->start.tv_sec) * 1000 + (now.tv_usec - c->start.tv_usec) / 1000; + sockaddr2str(&c->address, &address, &port); + x = send_request(c, "%d %s %s %d %lx", ACK, myport, address, c->estimated_weight, c->options); + free(address); + free(port); +cp + return x; +} + +void send_everything(connection_t *c) +{ + avl_node_t *node, *node2; + node_t *n; + subnet_t *s; + edge_t *e; + + /* Send all known subnets */ + + for(node = node_tree->head; node; node = node->next) + { + n = (node_t *)node->data; + + for(node2 = n->subnet_tree->head; node2; node2 = node2->next) + { + s = (subnet_t *)node2->data; + send_add_subnet(c, s); + } + } + + /* Send all known edges */ + + for(node = edge_tree->head; node; node = node->next) + { + e = (edge_t *)node->data; + + if(e == c->edge) + continue; + + send_add_edge(c, e); + } +} + +int ack_h(connection_t *c) +{ + char myaddress[MAX_STRING_SIZE]; + char hisport[MAX_STRING_SIZE]; + char *hisaddress, *dummy; + int weight; + long int options; + node_t *n; + connection_t *other; + avl_node_t *node; +cp + if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING" %d %lx", hisport, myaddress, &weight, &options) != 4) + { + syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "ACK", c->name, c->hostname); + return -1; + } + + /* Check if we already have a node_t for him */ + + n = lookup_node(c->name); + + if(!n) + { + n = new_node(); + n->name = xstrdup(c->name); + node_add(n); + } + else + { + if(n->connection) + { + /* Oh dear, we already have a connection to this node. */ + log(DEBUG_CONNECTIONS, TLOG_DEBUG, + _("Established a second connection with %s (%s), closing old connection"), + n->name, n->hostname); + terminate_connection(n->connection, 0); + } + + /* FIXME: check if information in existing node matches that of the other end of this connection */ + } + + n->connection = c; + c->node = n; + c->options |= options; + + /* Create an edge_t for this connection */ + + c->edge = new_edge(); +cp + c->edge->from.node = myself; +// c->edge->from.tcpaddress = str2sockaddr(address, port); + c->edge->from.udpaddress = str2sockaddr(myaddress, myport); + c->edge->to.node = n; +// c->edge->to.tcpaddress = c->address; + sockaddr2str(&c->address, &hisaddress, &dummy); + c->edge->to.udpaddress = str2sockaddr(hisaddress, hisport); + free(hisaddress); + free(dummy); + c->edge->weight = (weight + c->estimated_weight) / 2; + c->edge->connection = c; + c->edge->options = c->options; +cp + edge_add(c->edge); + + /* Activate this connection */ + + c->allow_request = ALL; + c->status.active = 1; + + if(debug_lvl >= DEBUG_CONNECTIONS) + syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), c->name, c->hostname); + +cp + /* Send him everything we know */ + + send_everything(c); + + /* Notify others of this connection */ + + for(node = connection_tree->head; node; node = node->next) + { + other = (connection_t *)node->data; + + if(other->status.active && other != c) + send_add_edge(other, c->edge); + } + + /* Run MST and SSSP algorithms */ + + graph(); +cp + return 0; +} diff --git a/src/pokey/protocol_edge.c b/src/pokey/protocol_edge.c new file mode 100644 index 00000000..89dd6f44 --- /dev/null +++ b/src/pokey/protocol_edge.c @@ -0,0 +1,311 @@ +/* + protocol_edge.c -- handle the meta-protocol, edges + Copyright (C) 1999-2002 Ivo Timmermans , + 2000-2002 Guus Sliepen + + 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: protocol_edge.c,v 1.1 2002/04/28 12:46:26 zarq Exp $ +*/ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "conf.h" +#include "interface.h" +#include "net.h" +#include "netutl.h" +#include "protocol.h" +#include "meta.h" +#include "connection.h" +#include "node.h" +#include "edge.h" +#include "graph.h" +#include "logging.h" + +#include "system.h" + +int send_add_edge(connection_t *c, edge_t *e) +{ + int x; + char *from_udpaddress, *from_udpport; + char *to_udpaddress, *to_udpport; +cp +// sockaddr2str(&e->from.tcpaddress, &from_tcpaddress, &from_tcpport); + sockaddr2str(&e->from.udpaddress, &from_udpaddress, &from_udpport); +// sockaddr2str(&e->to.tcpaddress, &to_tcpaddress, &to_tcpport); + sockaddr2str(&e->to.udpaddress, &to_udpaddress, &to_udpport); + x = send_request(c, "%d %lx %s %s %s %s %s %s %lx %d", ADD_EDGE, random(), + e->from.node->name, from_udpaddress, from_udpport, + e->to.node->name, to_udpaddress, to_udpport, + e->options, e->weight); +// free(from_tcpaddress); +// free(from_tcpport); + free(from_udpaddress); + free(from_udpport); +// free(to_tcpaddress); +// free(to_tcpport); + free(to_udpaddress); + free(to_udpport); +cp + return x; +} + +int add_edge_h(connection_t *c) +{ + connection_t *other; + edge_t *e; + node_t *from, *to; + char from_name[MAX_STRING_SIZE]; + char to_name[MAX_STRING_SIZE]; + char from_address[MAX_STRING_SIZE]; +// char from_tcpport[MAX_STRING_SIZE]; + char from_udpport[MAX_STRING_SIZE]; + char to_address[MAX_STRING_SIZE]; +// char to_tcpport[MAX_STRING_SIZE]; + char to_udpport[MAX_STRING_SIZE]; + sockaddr_t from_udpaddress; + sockaddr_t to_udpaddress; + long int options; + int weight; + avl_node_t *node; +cp + if(sscanf(c->buffer, "%*d %*x "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %lx %d", + from_name, from_address, from_udpport, + to_name, to_address, to_udpport, + &options, &weight) != 8) + { + syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "ADD_EDGE", c->name, c->hostname); + return -1; + } + + /* Check if names are valid */ + + if(check_id(from_name)) + { + syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ADD_EDGE", c->name, c->hostname, _("invalid name")); + return -1; + } + + if(check_id(to_name)) + { + syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ADD_EDGE", c->name, c->hostname, _("invalid name")); + return -1; + } + + if(seen_request(c->buffer)) + return 0; + + /* Lookup nodes */ + + from = lookup_node(from_name); + + if(!from) + { + from = new_node(); + from->name = xstrdup(from_name); + node_add(from); + } + + to = lookup_node(to_name); + + if(!to) + { + to = new_node(); + to->name = xstrdup(to_name); + node_add(to); + } + + /* Convert addresses */ + +// from_tcpaddress = str2sockaddr(from_address, from_tcpport); + from_udpaddress = str2sockaddr(from_address, from_udpport); +// to_tcpaddress = str2sockaddr(to_address, to_tcpport); + to_udpaddress = str2sockaddr(to_address, to_udpport); + + /* Check if edge already exists */ + + e = lookup_edge(from, to); + + if(e) + { + if(e->weight != weight || e->options != options + || ((e->from.node == from) && (sockaddrcmp(&e->from.udpaddress, &from_udpaddress)|| sockaddrcmp(&e->to.udpaddress, &to_udpaddress))) + || ((e->from.node == to) && (sockaddrcmp(&e->from.udpaddress, &to_udpaddress) || sockaddrcmp(&e->to.udpaddress, &from_udpaddress))) + ) + { + if(from == myself || to == myself) + { + if(debug_lvl >= DEBUG_PROTOCOL) + syslog(LOG_WARNING, _("Got %s from %s (%s) for ourself which does not match existing entry"), "ADD_EDGE", c->name, c->hostname); + send_add_edge(c, e); + return 0; + } + else + { + if(debug_lvl >= DEBUG_PROTOCOL) + syslog(LOG_WARNING, _("Got %s from %s (%s) which does not match existing entry"), "ADD_EDGE", c->name, c->hostname); + edge_del(e); + } + } + else + return 0; + } + else if(from == myself || to == myself) + { + if(debug_lvl >= DEBUG_PROTOCOL) + syslog(LOG_WARNING, _("Got %s from %s (%s) for ourself which does not exist"), "ADD_EDGE", c->name, c->hostname); + e = new_edge(); + e->from.node = from; + e->to.node = to; + send_del_edge(c, e); + free_edge(e); + return 0; + } + + e = new_edge(); + e->from.node = from; +// e->from.tcpaddress = from_tcpaddress; + e->from.udpaddress = from_udpaddress; + e->to.node = to; +// e->to.tcpaddress = to_tcpaddress; + e->to.udpaddress = to_udpaddress; + e->options = options; + e->weight = weight; + edge_add(e); + + /* Tell the rest about the new edge */ + + for(node = connection_tree->head; node; node = node->next) + { + other = (connection_t *)node->data; + if(other->status.active && other != c) + send_request(other, "%s", c->buffer); + } + + /* Run MST before or after we tell the rest? */ + + graph(); +cp + return 0; +} + +int send_del_edge(connection_t *c, edge_t *e) +{ +cp + return send_request(c, "%d %lx %s %s", DEL_EDGE, random(), + e->from.node->name, e->to.node->name); +} + +int del_edge_h(connection_t *c) +{ + edge_t *e; + char from_name[MAX_STRING_SIZE]; + char to_name[MAX_STRING_SIZE]; + node_t *from, *to; + connection_t *other; + avl_node_t *node; +cp + if(sscanf(c->buffer, "%*d %*x "MAX_STRING" "MAX_STRING"", from_name, to_name) != 2) + { + syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "DEL_EDGE", + c->name, c->hostname); + return -1; + } + + /* Check if names are valid */ + + if(check_id(from_name)) + { + syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_EDGE", c->name, c->hostname, _("invalid name")); + return -1; + } + + if(check_id(to_name)) + { + syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_EDGE", c->name, c->hostname, _("invalid name")); + return -1; + } + + if(seen_request(c->buffer)) + return 0; + + /* Lookup nodes */ + + from = lookup_node(from_name); + + if(!from) + { + if(debug_lvl >= DEBUG_PROTOCOL) + syslog(LOG_ERR, _("Got %s from %s (%s) which does not appear in the edge tree"), "DEL_EDGE", c->name, c->hostname); + return 0; + } + + to = lookup_node(to_name); + + if(!to) + { + if(debug_lvl >= DEBUG_PROTOCOL) + syslog(LOG_ERR, _("Got %s from %s (%s) which does not appear in the edge tree"), "DEL_EDGE", c->name, c->hostname); + return 0; + } + + /* Check if edge exists */ + + e = lookup_edge(from, to); + + if(!e) + { + if(debug_lvl >= DEBUG_PROTOCOL) + syslog(LOG_WARNING, _("Got %s from %s (%s) which does not appear in the edge tree"), "DEL_EDGE", c->name, c->hostname); + return 0; + } + + if(e->from.node == myself || e->to.node == myself) + { + if(debug_lvl >= DEBUG_PROTOCOL) + syslog(LOG_WARNING, _("Got %s from %s (%s) for ourself"), "DEL_EDGE", c->name, c->hostname); + send_add_edge(c, e); /* Send back a correction */ + return 0; + } + + /* Tell the rest about the deleted edge */ + + for(node = connection_tree->head; node; node = node->next) + { + other = (connection_t *)node->data; + if(other->status.active && other != c) + send_request(other, "%s", c->buffer); + } + + /* Delete the edge */ + + edge_del(e); + + /* Run MST before or after we tell the rest? */ + + graph(); +cp + return 0; +} diff --git a/src/pokey/protocol_key.c b/src/pokey/protocol_key.c new file mode 100644 index 00000000..6ccf3664 --- /dev/null +++ b/src/pokey/protocol_key.c @@ -0,0 +1,285 @@ +/* + protocol_key.c -- handle the meta-protocol, key exchange + Copyright (C) 1999-2002 Ivo Timmermans , + 2000-2002 Guus Sliepen + + 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: protocol_key.c,v 1.1 2002/04/28 12:46:26 zarq Exp $ +*/ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "conf.h" +#include "interface.h" +#include "net.h" +#include "netutl.h" +#include "protocol.h" +#include "meta.h" +#include "connection.h" +#include "node.h" +#include "edge.h" +#include "logging.h" + +#include "system.h" + +int mykeyused = 0; + +int send_key_changed(connection_t *c, node_t *n) +{ + connection_t *other; + avl_node_t *node; +cp + /* Only send this message if some other daemon requested our key previously. + This reduces unnecessary key_changed broadcasts. + */ + + if(n == myself && !mykeyused) + return 0; + + for(node = connection_tree->head; node; node = node->next) + { + other = (connection_t *)node->data; + if(other->status.active && other != c) + send_request(other, "%d %lx %s", KEY_CHANGED, random(), n->name); + } +cp + return 0; +} + +int key_changed_h(connection_t *c) +{ + char name[MAX_STRING_SIZE]; + avl_node_t *node; + connection_t *other; + node_t *n; +cp + if(sscanf(c->buffer, "%*d %*x "MAX_STRING, name) != 1) + { + syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "KEY_CHANGED", + c->name, c->hostname); + return -1; + } + + if(seen_request(c->buffer)) + return 0; + + n = lookup_node(name); + + if(!n) + { + syslog(LOG_ERR, _("Got %s from %s (%s) origin %s which does not exist"), "KEY_CHANGED", + c->name, c->hostname, name); + return -1; + } + + n->status.validkey = 0; + n->status.waitingforkey = 0; + n->sent_seqno = 0; + + /* Tell the others */ + + for(node = connection_tree->head; node; node = node->next) + { + other = (connection_t *)node->data; + if(other->status.active && other != c) + send_request(other, "%s", c->buffer); + } +cp + return 0; +} + +int send_req_key(connection_t *c, node_t *from, node_t *to) +{ +cp + return send_request(c, "%d %s %s", REQ_KEY, + from->name, to->name); +} + +int req_key_h(connection_t *c) +{ + char from_name[MAX_STRING_SIZE]; + char to_name[MAX_STRING_SIZE]; + node_t *from, *to; +cp + if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING, from_name, to_name) != 2) + { + syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "REQ_KEY", + c->name, c->hostname); + return -1; + } + + from = lookup_node(from_name); + + if(!from) + { + syslog(LOG_ERR, _("Got %s from %s (%s) origin %s which does not exist in our connection list"), "REQ_KEY", + c->name, c->hostname, from_name); + return -1; + } + + to = lookup_node(to_name); + + if(!to) + { + syslog(LOG_ERR, _("Got %s from %s (%s) destination %s which does not exist in our connection list"), "REQ_KEY", + c->name, c->hostname, to_name); + return -1; + } + + /* Check if this key request is for us */ + + if(to == myself) /* Yes, send our own key back */ + { + mykeyused = 1; + from->received_seqno = 0; + send_ans_key(c, myself, from); + } + else + { +/* Proxy keys + if(to->status.validkey) + { + send_ans_key(c, to, from); + } + else +*/ + send_req_key(to->nexthop->connection, from, to); + } + +cp + return 0; +} + +int send_ans_key(connection_t *c, node_t *from, node_t *to) +{ + char key[MAX_STRING_SIZE]; +cp + bin2hex(from->key, key, from->keylength); + key[from->keylength * 2] = '\0'; +cp + return send_request(c, "%d %s %s %s %d %d %d %d", ANS_KEY, + from->name, to->name, key, from->cipher?from->cipher->nid:0, from->digest?from->digest->type:0, from->maclength, from->compression); +} + +int ans_key_h(connection_t *c) +{ + char from_name[MAX_STRING_SIZE]; + char to_name[MAX_STRING_SIZE]; + char key[MAX_STRING_SIZE]; + int cipher, digest, maclength, compression; + node_t *from, *to; +cp + if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d %d %d", from_name, to_name, key, &cipher, &digest, &maclength, &compression) != 7) + { + syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "ANS_KEY", + c->name, c->hostname); + return -1; + } + + from = lookup_node(from_name); + + if(!from) + { + syslog(LOG_ERR, _("Got %s from %s (%s) origin %s which does not exist in our connection list"), "ANS_KEY", + c->name, c->hostname, from_name); + return -1; + } + + to = lookup_node(to_name); + + if(!to) + { + syslog(LOG_ERR, _("Got %s from %s (%s) destination %s which does not exist in our connection list"), "ANS_KEY", + c->name, c->hostname, to_name); + return -1; + } + + /* Forward it if necessary */ + + if(to != myself) + { + return send_request(to->nexthop->connection, "%s", c->buffer); + } + + /* Update our copy of the origin's packet key */ + + if(from->key) + free(from->key); + + from->key = xstrdup(key); + from->keylength = strlen(key) / 2; + hex2bin(from->key, from->key, from->keylength); + from->key[from->keylength] = '\0'; + + from->status.validkey = 1; + from->status.waitingforkey = 0; + + /* Check and lookup cipher and digest algorithms */ + + if(cipher) + { + from->cipher = EVP_get_cipherbynid(cipher); + if(!from->cipher) + { + syslog(LOG_ERR, _("Node %s (%s) uses unknown cipher!"), from->name, from->hostname); + return -1; + } + if(from->keylength != from->cipher->key_len + from->cipher->iv_len) + { + syslog(LOG_ERR, _("Node %s (%s) uses wrong keylength!"), from->name, from->hostname); + return -1; + } + } + else + { + from->cipher = NULL; + } + + from->maclength = maclength; + + if(digest) + { + from->digest = EVP_get_digestbynid(digest); + if(!from->digest) + { + syslog(LOG_ERR, _("Node %s (%s) uses unknown digest!"), from->name, from->hostname); + return -1; + } + if(from->maclength > from->digest->md_size || from->maclength < 0) + { + syslog(LOG_ERR, _("Node %s (%s) uses bogus MAC length!"), from->name, from->hostname); + return -1; + } + } + else + { + from->digest = NULL; + } + + from->compression = compression; +cp + return 0; +} diff --git a/src/pokey/protocol_misc.c b/src/pokey/protocol_misc.c new file mode 100644 index 00000000..40fdc621 --- /dev/null +++ b/src/pokey/protocol_misc.c @@ -0,0 +1,182 @@ +/* + protocol_misc.c -- handle the meta-protocol, miscellaneous functions + Copyright (C) 1999-2002 Ivo Timmermans , + 2000-2002 Guus Sliepen + + 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: protocol_misc.c,v 1.1 2002/04/28 12:46:26 zarq Exp $ +*/ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include + +#include "conf.h" +#include "interface.h" +#include "net.h" +#include "netutl.h" +#include "protocol.h" +#include "meta.h" +#include "connection.h" +#include "logging.h" + +#include "system.h" + +/* Status and error notification routines */ + +int send_status(connection_t *c, int statusno, char *statusstring) +{ +cp + if(!statusstring) + statusstring = status_text[statusno]; +cp + return send_request(c, "%d %d %s", STATUS, statusno, statusstring); +} + +int status_h(connection_t *c) +{ + int statusno; + char statusstring[MAX_STRING_SIZE]; +cp + if(sscanf(c->buffer, "%*d %d "MAX_STRING, &statusno, statusstring) != 2) + { + syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "STATUS", + c->name, c->hostname); + return -1; + } + + if(debug_lvl >= DEBUG_STATUS) + { + syslog(LOG_NOTICE, _("Status message from %s (%s): %s: %s"), + c->name, c->hostname, status_text[statusno], statusstring); + } + +cp + return 0; +} + +int send_error(connection_t *c, int err, char *errstring) +{ +cp + if(!errstring) + errstring = strerror(err); + return send_request(c, "%d %d %s", ERROR, err, errstring); +} + +int error_h(connection_t *c) +{ + int err; + char errorstring[MAX_STRING_SIZE]; +cp + if(sscanf(c->buffer, "%*d %d "MAX_STRING, &err, errorstring) != 2) + { + syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "ERROR", + c->name, c->hostname); + return -1; + } + + if(debug_lvl >= DEBUG_ERROR) + { + syslog(LOG_NOTICE, _("Error message from %s (%s): %s: %s"), + c->name, c->hostname, strerror(err), errorstring); + } + + terminate_connection(c, c->status.active); +cp + return 0; +} + +int send_termreq(connection_t *c) +{ +cp + return send_request(c, "%d", TERMREQ); +} + +int termreq_h(connection_t *c) +{ +cp + terminate_connection(c, c->status.active); +cp + return 0; +} + +int send_ping(connection_t *c) +{ +cp + c->status.pinged = 1; + c->last_ping_time = now; +cp + return send_request(c, "%d", PING); +} + +int ping_h(connection_t *c) +{ +cp + return send_pong(c); +} + +int send_pong(connection_t *c) +{ +cp + return send_request(c, "%d", PONG); +} + +int pong_h(connection_t *c) +{ +cp + c->status.pinged = 0; + + /* Succesful connection, reset timeout if this is an outgoing connection. */ + + if(c->outgoing) + c->outgoing->timeout = 0; +cp + return 0; +} + +/* Sending and receiving packets via TCP */ + +int send_tcppacket(connection_t *c, vpn_packet_t *packet) +{ + int x; +cp + /* Evil hack. */ + + x = send_request(c, "%d %hd", PACKET, packet->len); + + if(x) + return x; +cp + return send_meta(c, packet->data, packet->len); +} + +/* Status strings */ + +char (*status_text[]) = { + "Warning", +}; + +/* Error strings */ + +char (*error_text[]) = { + "Error", +}; diff --git a/src/pokey/protocol_subnet.c b/src/pokey/protocol_subnet.c new file mode 100644 index 00000000..3cdc760c --- /dev/null +++ b/src/pokey/protocol_subnet.c @@ -0,0 +1,238 @@ +/* + protocol_subnet.c -- handle the meta-protocol, subnets + Copyright (C) 1999-2002 Ivo Timmermans , + 2000-2002 Guus Sliepen + + 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: protocol_subnet.c,v 1.1 2002/04/28 12:46:26 zarq Exp $ +*/ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "conf.h" +#include "interface.h" +#include "net.h" +#include "netutl.h" +#include "protocol.h" +#include "meta.h" +#include "connection.h" +#include "node.h" +#include "edge.h" +#include "graph.h" +#include "logging.h" + +#include "system.h" + +int send_add_subnet(connection_t *c, subnet_t *subnet) +{ + int x; + char *netstr; +cp + x = send_request(c, "%d %lx %s %s", ADD_SUBNET, random(), + subnet->owner->name, netstr = net2str(subnet)); + free(netstr); +cp + return x; +} + +int add_subnet_h(connection_t *c) +{ + char subnetstr[MAX_STRING_SIZE]; + char name[MAX_STRING_SIZE]; + node_t *owner; + connection_t *other; + subnet_t *s; + avl_node_t *node; +cp + if(sscanf(c->buffer, "%*d %*x "MAX_STRING" "MAX_STRING, name, subnetstr) != 2) + { + syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "ADD_SUBNET", c->name, c->hostname); + return -1; + } + + /* Check if owner name is a valid */ + + if(check_id(name)) + { + syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ADD_SUBNET", c->name, c->hostname, _("invalid name")); + return -1; + } + + /* Check if subnet string is valid */ + + if(!(s = str2net(subnetstr))) + { + syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ADD_SUBNET", c->name, c->hostname, _("invalid subnet string")); + return -1; + } + + if(seen_request(c->buffer)) + return 0; + + /* Check if the owner of the new subnet is in the connection list */ + + owner = lookup_node(name); + + if(!owner) + { + owner = new_node(); + owner->name = xstrdup(name); + node_add(owner); + } + + /* Check if we already know this subnet */ + + if(lookup_subnet(owner, s)) + { + free_subnet(s); + return 0; + } + + /* If we don't know this subnet, but we are the owner, retaliate with a DEL_SUBNET */ + + if(owner == myself) + { + if(debug_lvl >= DEBUG_PROTOCOL) + syslog(LOG_WARNING, _("Got %s from %s (%s) for ourself"), "ADD_SUBNET", c->name, c->hostname); + s->owner = myself; + send_del_subnet(c, s); + return 0; + } + + /* If everything is correct, add the subnet to the list of the owner */ + + subnet_add(owner, s); + + /* Tell the rest */ + + for(node = connection_tree->head; node; node = node->next) + { + other = (connection_t *)node->data; + if(other->status.active && other != c) + send_request(other, "%s", c->buffer); + } +cp + return 0; +} + +int send_del_subnet(connection_t *c, subnet_t *s) +{ + int x; + char *netstr; +cp + netstr = net2str(s); + x = send_request(c, "%d %lx %s %s", DEL_SUBNET, random(), s->owner->name, netstr); + free(netstr); +cp + return x; +} + +int del_subnet_h(connection_t *c) +{ + char subnetstr[MAX_STRING_SIZE]; + char name[MAX_STRING_SIZE]; + node_t *owner; + connection_t *other; + subnet_t *s, *find; + avl_node_t *node; +cp + if(sscanf(c->buffer, "%*d %*x "MAX_STRING" "MAX_STRING, name, subnetstr) != 2) + { + syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "DEL_SUBNET", c->name, c->hostname); + return -1; + } + + /* Check if owner name is a valid */ + + if(check_id(name)) + { + syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_SUBNET", c->name, c->hostname, _("invalid name")); + return -1; + } + + /* Check if the owner of the new subnet is in the connection list */ + + if(!(owner = lookup_node(name))) + { + if(debug_lvl >= DEBUG_PROTOCOL) + syslog(LOG_WARNING, _("Got %s from %s (%s) for %s which is not in our node tree"), + "DEL_SUBNET", c->name, c->hostname, name); + return 0; + } + + /* Check if subnet string is valid */ + + if(!(s = str2net(subnetstr))) + { + syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_SUBNET", c->name, c->hostname, _("invalid subnet string")); + return -1; + } + + if(seen_request(c->buffer)) + return 0; + + /* If everything is correct, delete the subnet from the list of the owner */ + + s->owner = owner; + + find = lookup_subnet(owner, s); + + free_subnet(s); + + if(!find) + { + if(debug_lvl >= DEBUG_PROTOCOL) + syslog(LOG_WARNING, _("Got %s from %s (%s) for %s which does not appear in his subnet tree"), + "DEL_SUBNET", c->name, c->hostname, name); + return 0; + } + + /* If we are the owner of this subnet, retaliate with an ADD_SUBNET */ + + if(owner == myself) + { + if(debug_lvl >= DEBUG_PROTOCOL) + syslog(LOG_WARNING, _("Got %s from %s (%s) for ourself"), "DEL_SUBNET", c->name, c->hostname); + send_add_subnet(c, find); + return 0; + } + + /* Tell the rest */ + + for(node = connection_tree->head; node; node = node->next) + { + other = (connection_t *)node->data; + if(other->status.active && other != c) + send_request(other, "%s", c->buffer); + } + + /* Finally, delete it. */ + + subnet_del(owner, find); + +cp + return 0; +} diff --git a/src/pokey/route.c b/src/pokey/route.c new file mode 100644 index 00000000..cd5946ce --- /dev/null +++ b/src/pokey/route.c @@ -0,0 +1,377 @@ +/* + route.c -- routing + Copyright (C) 2000-2002 Ivo Timmermans , + 2000-2002 Guus Sliepen + + 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: route.c,v 1.1 2002/04/28 12:46:26 zarq Exp $ +*/ + +#include "config.h" + +#if defined(HAVE_FREEBSD) || defined(HAVE_OPENBSD) + #include +#endif +#include +#include +#if defined(HAVE_SOLARIS) || defined(HAVE_OPENBSD) + #include + #define ETHER_ADDR_LEN 6 +#else + #include +#endif +#include +#include +#include +#include +#include +#include + +#include + +#include "net.h" +#include "interface.h" +#include "connection.h" +#include "subnet.h" +#include "route.h" +#include "protocol.h" +#include "device.h" +#include "logging.h" + +#include "system.h" + +int routing_mode = RMODE_ROUTER; +int priorityinheritance = 0; +int macexpire = 600; +subnet_t mymac; + +void learn_mac(mac_t *address) +{ + subnet_t *subnet; + avl_node_t *node; + connection_t *c; +cp + subnet = lookup_subnet_mac(address); + + /* If we don't know this MAC address yet, store it */ + + if(!subnet || subnet->owner!=myself) + { + if(debug_lvl >= DEBUG_TRAFFIC) + syslog(LOG_INFO, _("Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx"), + address->x[0], address->x[1], address->x[2], address->x[3], address->x[4], address->x[5]); + + subnet = new_subnet(); + subnet->type = SUBNET_MAC; + memcpy(&subnet->net.mac.address, address, sizeof(mac_t)); + subnet_add(myself, subnet); + + /* And tell all other tinc daemons it's our MAC */ + + for(node = connection_tree->head; node; node = node->next) + { + c = (connection_t *)node->data; + if(c->status.active) + send_add_subnet(c, subnet); + } + } + + subnet->net.mac.lastseen = now; +} + +void age_mac(void) +{ + subnet_t *s; + connection_t *c; + avl_node_t *node, *next, *node2; +cp + for(node = myself->subnet_tree->head; node; node = next) + { + next = node->next; + s = (subnet_t *)node->data; + if(s->type == SUBNET_MAC && s->net.mac.lastseen && s->net.mac.lastseen + macexpire < now) + { + if(debug_lvl >= DEBUG_TRAFFIC) + syslog(LOG_INFO, _("MAC address %hx:%hx:%hx:%hx:%hx:%hx expired"), + s->net.mac.address.x[0], s->net.mac.address.x[1], s->net.mac.address.x[2], s->net.mac.address.x[3], s->net.mac.address.x[4], s->net.mac.address.x[5]); + for(node2 = connection_tree->head; node2; node2 = node2->next) + { + c = (connection_t *)node2->data; + if(c->status.active) + send_del_subnet(c, s); + } + subnet_del(myself, s); + } + } +cp +} + +node_t *route_mac(vpn_packet_t *packet) +{ + subnet_t *subnet; +cp + /* Learn source address */ + + learn_mac((mac_t *)(&packet->data[6])); + + /* Lookup destination address */ + + subnet = lookup_subnet_mac((mac_t *)(&packet->data[0])); + + if(subnet) + return subnet->owner; + else + return NULL; +} + +node_t *route_ipv4(vpn_packet_t *packet) +{ + subnet_t *subnet; +cp + if(priorityinheritance) + packet->priority = packet->data[15]; + + subnet = lookup_subnet_ipv4((ipv4_t *)&packet->data[30]); +cp + if(!subnet) + { + if(debug_lvl >= DEBUG_TRAFFIC) + { + syslog(LOG_WARNING, _("Cannot route packet: unknown IPv4 destination address %d.%d.%d.%d"), + packet->data[30], packet->data[31], packet->data[32], packet->data[33]); + } + + return NULL; + } +cp + return subnet->owner; +} + +node_t *route_ipv6(vpn_packet_t *packet) +{ + subnet_t *subnet; +cp + subnet = lookup_subnet_ipv6((ipv6_t *)&packet->data[38]); +cp + if(!subnet) + { + if(debug_lvl >= DEBUG_TRAFFIC) + { + syslog(LOG_WARNING, _("Cannot route packet: unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"), + ntohs(*(short unsigned int *)&packet->data[38]), + ntohs(*(short unsigned int *)&packet->data[40]), + ntohs(*(short unsigned int *)&packet->data[42]), + ntohs(*(short unsigned int *)&packet->data[44]), + ntohs(*(short unsigned int *)&packet->data[46]), + ntohs(*(short unsigned int *)&packet->data[48]), + ntohs(*(short unsigned int *)&packet->data[50]), + ntohs(*(short unsigned int *)&packet->data[52])); + } + + return NULL; + } +cp + return subnet->owner; +} + +unsigned short int inet_checksum(unsigned short int *data, int len, unsigned short int prevsum) +{ + unsigned long int checksum = prevsum ^ 0xFFFF; + + while(len--) + checksum += ntohs(*data++); + + while(checksum >> 16) + checksum = (checksum & 0xFFFF) + (checksum >> 16); + + return checksum ^ 0xFFFF; +} + +void route_neighborsol(vpn_packet_t *packet) +{ + struct ip6_hdr *hdr; + struct nd_neighbor_solicit *ns; + struct nd_opt_hdr *opt; + subnet_t *subnet; + short unsigned int checksum; + + struct { + struct in6_addr ip6_src; /* source address */ + struct in6_addr ip6_dst; /* destination address */ + uint32_t length; + uint8_t junk[4]; + } pseudo; + +cp + hdr = (struct ip6_hdr *)(packet->data + 14); + ns = (struct nd_neighbor_solicit *)(packet->data + 14 + sizeof(*hdr)); + opt = (struct nd_opt_hdr *)(packet->data + 14 + sizeof(*hdr) + sizeof(*ns)); + + /* First, snatch the source address from the neighbor solicitation packet */ + + memcpy(mymac.net.mac.address.x, packet->data + 6, 6); + + /* Check if this is a valid neighbor solicitation request */ + + if(ns->nd_ns_hdr.icmp6_type != ND_NEIGHBOR_SOLICIT || + opt->nd_opt_type != ND_OPT_SOURCE_LINKADDR) + { + if(debug_lvl > DEBUG_TRAFFIC) + { + syslog(LOG_WARNING, _("Cannot route packet: received unknown type neighbor solicitation request")); + } + return; + } + + /* Create pseudo header */ + + memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16); + memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16); + pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6); + pseudo.junk[0] = pseudo.junk[1] = pseudo.junk[2] = 0; + pseudo.junk[3] = IPPROTO_ICMPV6; + + /* Generate checksum */ + + checksum = inet_checksum((unsigned short int *)&pseudo, sizeof(pseudo)/2, ~0); + checksum = inet_checksum((unsigned short int *)ns, sizeof(*ns)/2 + 4, checksum); + + if(checksum) + { + if(debug_lvl >= DEBUG_TRAFFIC) + syslog(LOG_WARNING, _("Cannot route packet: checksum error for neighbor solicitation request")); + return; + } + + /* Check if the IPv6 address exists on the VPN */ + + subnet = lookup_subnet_ipv6((ipv6_t *)&ns->nd_ns_target); + + if(!subnet) + { + if(debug_lvl >= DEBUG_TRAFFIC) + { + syslog(LOG_WARNING, _("Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"), + ntohs(((uint16_t *)&ns->nd_ns_target)[0]), ntohs(((uint16_t *)&ns->nd_ns_target)[1]), ntohs(((uint16_t *)&ns->nd_ns_target)[2]), ntohs(((uint16_t *)&ns->nd_ns_target)[3]), + ntohs(((uint16_t *)&ns->nd_ns_target)[4]), ntohs(((uint16_t *)&ns->nd_ns_target)[5]), ntohs(((uint16_t *)&ns->nd_ns_target)[6]), ntohs(((uint16_t *)&ns->nd_ns_target)[7])); + } + + return; + } + + /* Check if it is for our own subnet */ + + if(subnet->owner == myself) + return; /* silently ignore */ + + /* Create neighbor advertation reply */ + + memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */ + packet->data[ETHER_ADDR_LEN*2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */ + + memcpy(&hdr->ip6_dst, &hdr->ip6_src, 16); /* swap destination and source protocol address */ + memcpy(&hdr->ip6_src, &ns->nd_ns_target, 16); /* ... */ + + memcpy((char *)opt + sizeof(*opt), packet->data + ETHER_ADDR_LEN, 6); /* add fake source hard addr */ + + ns->nd_ns_hdr.icmp6_cksum = 0; + ns->nd_ns_hdr.icmp6_type = ND_NEIGHBOR_ADVERT; + ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[0] = 0x40; /* Set solicited flag */ + ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[1] = ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[2] = ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[3] = 0; + opt->nd_opt_type = ND_OPT_TARGET_LINKADDR; + + /* Create pseudo header */ + + memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16); + memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16); + pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6); + pseudo.junk[0] = pseudo.junk[1] = pseudo.junk[2] = 0; + pseudo.junk[3] = IPPROTO_ICMPV6; + + /* Generate checksum */ + + checksum = inet_checksum((unsigned short int *)&pseudo, sizeof(pseudo)/2, ~0); + checksum = inet_checksum((unsigned short int *)ns, sizeof(*ns)/2 + 4, checksum); + + ns->nd_ns_hdr.icmp6_cksum = htons(checksum); +cp +} + +void route_arp(vpn_packet_t *packet) +{ + struct ether_arp *arp; + subnet_t *subnet; + unsigned char ipbuf[4]; +cp + /* First, snatch the source address from the ARP packet */ + + memcpy(mymac.net.mac.address.x, packet->data + 6, 6); + + /* This routine generates replies to ARP requests. + You don't need to set NOARP flag on the interface anymore (which is broken on FreeBSD). + Most of the code here is taken from choparp.c by Takamichi Tateoka (tree@mma.club.uec.ac.jp) + */ + + arp = (struct ether_arp *)(packet->data + 14); + + /* Check if this is a valid ARP request */ + + if(ntohs(arp->arp_hrd) != ARPHRD_ETHER || + ntohs(arp->arp_pro) != ETHERTYPE_IP || + (int) (arp->arp_hln) != ETHER_ADDR_LEN || + (int) (arp->arp_pln) != 4 || + ntohs(arp->arp_op) != ARPOP_REQUEST ) + { + if(debug_lvl > DEBUG_TRAFFIC) + { + syslog(LOG_WARNING, _("Cannot route packet: received unknown type ARP request")); + } + return; + } + + /* Check if the IPv4 address exists on the VPN */ + + subnet = lookup_subnet_ipv4((ipv4_t *)arp->arp_tpa); + + if(!subnet) + { + if(debug_lvl >= DEBUG_TRAFFIC) + { + syslog(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"), + arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2], arp->arp_tpa[3]); + } + + return; + } + + /* Check if it is for our own subnet */ + + if(subnet->owner == myself) + return; /* silently ignore */ + + memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */ + packet->data[ETHER_ADDR_LEN*2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */ + + memcpy(ipbuf, arp->arp_tpa, 4); /* save protocol addr */ + memcpy(arp->arp_tpa, arp->arp_spa, 4); /* swap destination and source protocol address */ + memcpy(arp->arp_spa, ipbuf, 4); /* ... */ + + memcpy(arp->arp_tha, arp->arp_sha, 10); /* set target hard/proto addr */ + memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* add fake source hard addr */ + arp->arp_op = htons(ARPOP_REPLY); +cp +} + diff --git a/src/pokey/route.h b/src/pokey/route.h new file mode 100644 index 00000000..af4ff7ab --- /dev/null +++ b/src/pokey/route.h @@ -0,0 +1,41 @@ +/* + route.h -- header file for route.c + Copyright (C) 2000-2002 Ivo Timmermans + 2000-2002 Guus Sliepen + + 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: route.h,v 1.1 2002/04/28 12:46:26 zarq Exp $ +*/ + +#ifndef __TINC_ROUTE_H__ +#define __TINC_ROUTE_H__ + +enum +{ + RMODE_HUB = 0, + RMODE_SWITCH, + RMODE_ROUTER, +}; + +extern int routing_mode; +extern int priorityinheritance; +extern int macexpire; + +extern void age_mac(void); +extern void route_incoming(node_t *, vpn_packet_t *); +extern void route_outgoing(vpn_packet_t *); + +#endif /* __TINC_ROUTE_H__ */ diff --git a/src/protocol.h b/src/protocol.h index 4b112440..58267918 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: protocol.h,v 1.7 2002/04/09 15:26:00 zarq Exp $ + $Id: protocol.h,v 1.8 2002/04/28 12:46:26 zarq Exp $ */ #ifndef __TINC_PROTOCOL_H__ @@ -40,7 +40,7 @@ enum { ID = 0, METAKEY, CHALLENGE, CHAL_REPLY, ACK, STATUS, ERROR, TERMREQ, PING, PONG, -// ADD_NODE, DEL_NODE, + /* ADD_NODE, DEL_NODE, */ ADD_SUBNET, DEL_SUBNET, ADD_EDGE, DEL_EDGE, KEY_CHANGED, REQ_KEY, ANS_KEY, @@ -81,8 +81,8 @@ extern int send_error(connection_t *, int, char *); extern int send_termreq(connection_t *); extern int send_ping(connection_t *); extern int send_pong(connection_t *); -// extern int send_add_node(connection_t *, node_t *); -// extern int send_del_node(connection_t *, node_t *); +/* extern int send_add_node(connection_t *, node_t *); */ +/* extern int send_del_node(connection_t *, node_t *); */ extern int send_add_subnet(connection_t *, subnet_t *); extern int send_del_subnet(connection_t *, subnet_t *); extern int send_add_edge(connection_t *, edge_t *); @@ -106,8 +106,8 @@ extern int error_h(connection_t *); extern int termreq_h(connection_t *); extern int ping_h(connection_t *); extern int pong_h(connection_t *); -// extern int add_node_h(connection_t *); -// extern int del_node_h(connection_t *); +/* extern int add_node_h(connection_t *); */ +/* extern int del_node_h(connection_t *); */ extern int add_subnet_h(connection_t *); extern int del_subnet_h(connection_t *); extern int add_edge_h(connection_t *); diff --git a/src/protocol_auth.c b/src/protocol_auth.c index b9f845b6..4359fb54 100644 --- a/src/protocol_auth.c +++ b/src/protocol_auth.c @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: protocol_auth.c,v 1.3 2002/04/13 11:07:12 zarq Exp $ + $Id: protocol_auth.c,v 1.4 2002/04/28 12:46:26 zarq Exp $ */ #include "config.h" @@ -32,9 +32,15 @@ #include #include +#ifdef USE_OPENSSL #include #include #include +#endif + +#ifdef USE_GCRYPT +#include +#endif #ifndef HAVE_RAND_PSEUDO_BYTES #define RAND_pseudo_bytes RAND_bytes @@ -142,6 +148,7 @@ int send_metakey(connection_t *c) char buffer[MAX_STRING_SIZE]; int len, x; cp +#ifdef USE_OPENSSL len = RSA_size(c->rsa_key); /* Allocate buffers for the meta key */ @@ -155,6 +162,12 @@ cp /* Copy random data to the buffer */ RAND_bytes(c->outkey, len); +#endif + +#ifdef USE_GCRYPT + len = 123; /* FIXME: RSA key length */ + c->outkey = gcry_random_bytes(len, GCRY_WEAK_RANDOM); +#endif /* The message we send must be smaller than the modulus of the RSA key. By definition, for a key of k bits, the following formula holds: @@ -182,25 +195,32 @@ cp with a length equal to that of the modulus of the RSA key. */ +#ifdef USE_OPENSSL if(RSA_public_encrypt(len, c->outkey, buffer, c->rsa_key, RSA_NO_PADDING) != len) { syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), c->name, c->hostname); return -1; } +#endif cp /* Convert the encrypted random data to a hexadecimal formatted string */ +#ifdef USE_OPENSSL bin2hex(buffer, buffer, len); +#endif buffer[len*2] = '\0'; /* Send the meta key */ +#ifdef USE_OPENSSL x = send_request(c, "%d %d %d %d %d %s", METAKEY, c->outcipher?c->outcipher->nid:0, c->outdigest?c->outdigest->type:0, c->outmaclength, c->outcompression, buffer); +#endif /* Further outgoing requests are encrypted with the key we just generated */ +#ifdef USE_OPENSSL if(c->outcipher) { EVP_EncryptInit(c->outctx, c->outcipher, @@ -209,6 +229,7 @@ cp c->status.encryptout = 1; } +#endif cp return x; } @@ -225,7 +246,9 @@ cp return -1; } cp +#ifdef USE_OPENSSL len = RSA_size(myself->connection->rsa_key); +#endif /* Check if the length of the meta key is all right */ @@ -240,20 +263,24 @@ cp if(!c->inkey) c->inkey = xmalloc(len); +#ifdef USE_OPENSSL if(!c->inctx) c->inctx = xmalloc(sizeof(*c->inctx)); +#endif /* Convert the challenge from hexadecimal back to binary */ cp hex2bin(buffer,buffer,len); /* Decrypt the meta key */ -cp +cp +#ifdef USE_OPENSSL if(RSA_private_decrypt(len, buffer, c->inkey, myself->connection->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */ { syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), c->name, c->hostname); return -1; } +#endif if(debug_lvl >= DEBUG_SCARY_THINGS) { @@ -268,6 +295,7 @@ cp if(cipher) { +#ifdef USE_OPENSSL c->incipher = EVP_get_cipherbynid(cipher); if(!c->incipher) { @@ -280,6 +308,7 @@ cp c->inkey + len - c->incipher->key_len - c->incipher->iv_len); c->status.decryptin = 1; +#endif } else { @@ -290,6 +319,7 @@ cp if(digest) { +#ifdef USE_OPENSSL c->indigest = EVP_get_digestbynid(digest); if(!c->indigest) { @@ -302,6 +332,7 @@ cp syslog(LOG_ERR, _("%s (%s) uses bogus MAC length!"), c->name, c->hostname); return -1; } +#endif } else { @@ -322,7 +353,9 @@ int send_challenge(connection_t *c) cp /* CHECKME: what is most reasonable value for len? */ +#ifdef USE_OPENSSL len = RSA_size(c->rsa_key); +#endif /* Allocate buffers for the challenge */ @@ -331,7 +364,9 @@ cp cp /* Copy random data to the buffer */ +#ifdef USE_OPENSSL RAND_bytes(c->hischallenge, len); +#endif cp /* Convert to hex */ @@ -358,7 +393,9 @@ cp return -1; } +#ifdef USE_OPENSSL len = RSA_size(myself->connection->rsa_key); +#endif /* Check if the length of the challenge is all right */ @@ -386,6 +423,7 @@ cp int send_chal_reply(connection_t *c) { +#ifdef USE_OPENSSL char hash[EVP_MAX_MD_SIZE*2+1]; EVP_MD_CTX ctx; cp @@ -404,10 +442,15 @@ cp cp return send_request(c, "%d %s", CHAL_REPLY, hash); +#endif +#ifdef USE_GCRYPT + return 0; +#endif } int chal_reply_h(connection_t *c) { +#ifdef USE_OPENSSL char hishash[MAX_STRING_SIZE]; char myhash[EVP_MAX_MD_SIZE]; EVP_MD_CTX ctx; @@ -454,6 +497,8 @@ cp Send an acknowledgement with the rest of the information needed. */ +#endif + c->allow_request = ACK; cp return send_ack(c); diff --git a/src/protocol_key.c b/src/protocol_key.c index 0fa37b9b..1798edeb 100644 --- a/src/protocol_key.c +++ b/src/protocol_key.c @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: protocol_key.c,v 1.2 2002/04/09 15:26:01 zarq Exp $ + $Id: protocol_key.c,v 1.3 2002/04/28 12:46:26 zarq Exp $ */ #include "config.h" @@ -179,8 +179,14 @@ cp bin2hex(from->key, key, from->keylength); key[from->keylength * 2] = '\0'; cp +#ifdef USE_OPENSSL return send_request(c, "%d %s %s %s %d %d %d %d", ANS_KEY, from->name, to->name, key, from->cipher?from->cipher->nid:0, from->digest?from->digest->type:0, from->maclength, from->compression); +#endif +#ifdef USE_GCRYPT + return send_request(c, "%d %s %s %s %d %d %d %d", ANS_KEY, + from->name, to->name, key, from->cipher?-1:0, from->digest?-1:0, from->maclength, from->compression); +#endif } int ans_key_h(connection_t *c) @@ -240,6 +246,7 @@ cp if(cipher) { +#ifdef USE_OPENSSL from->cipher = EVP_get_cipherbynid(cipher); if(!from->cipher) { @@ -251,6 +258,7 @@ cp syslog(LOG_ERR, _("Node %s (%s) uses wrong keylength!"), from->name, from->hostname); return -1; } +#endif } else { @@ -261,6 +269,7 @@ cp if(digest) { +#ifdef USE_OPENSSL from->digest = EVP_get_digestbynid(digest); if(!from->digest) { @@ -272,6 +281,7 @@ cp syslog(LOG_ERR, _("Node %s (%s) uses bogus MAC length!"), from->name, from->hostname); return -1; } +#endif } else { diff --git a/src/read_conf.c b/src/read_conf.c new file mode 100644 index 00000000..c41fff01 --- /dev/null +++ b/src/read_conf.c @@ -0,0 +1,411 @@ +/* + read_conf.c -- read the configuration files + Copyright (C) 1998 Robert van der Meulen + 1998-2002 Ivo Timmermans + 2000-2002 Guus Sliepen + 2000 Cris van Pelt + + 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: read_conf.c,v 1.1 2002/04/28 12:46:26 zarq Exp $ +*/ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include /* for cp */ +#include + +#include "conf.h" +#include "netutl.h" /* for str2address */ +#include "logging.h" + +#include "system.h" + +/* + Read exactly one line and strip the trailing newline if any. If the + file was on EOF, return NULL. Otherwise, return all the data in a + dynamically allocated buffer. + + If line is non-NULL, it will be used as an initial buffer, to avoid + unnecessary mallocing each time this function is called. If buf is + given, and buf needs to be expanded, the var pointed to by buflen + will be increased. +*/ +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 != NULL) && (buflen != NULL)) + { + size = *buflen; + line = *buf; + } + else + { + size = 100; + line = xmalloc(size); + } + + maxlen = size; + idx = line; + *idx = 0; + for(;;) + { + errno = 0; + p = fgets(idx, maxlen, fp); + if(p == NULL) /* EOF or error */ + { + if(feof(fp)) + break; + + /* otherwise: error; let the calling function print an error + message if applicable */ + free(line); + return NULL; + } + + newline = strchr(p, '\n'); + if(newline == NULL) + /* We haven't yet read everything to the end of the line */ + { + newsize = size << 1; + line = xrealloc(line, newsize); + idx = &line[size - 1]; + maxlen = newsize - size + 1; + size = newsize; + } + else + { + *newline = '\0'; /* kill newline */ + break; /* yay */ + } + } + + if((buf != NULL) && (buflen != NULL)) + { + *buflen = size; + *buf = line; + } + return line; +} + +/* + Parse a configuration file and put the results in the configuration tree + starting at *base. +*/ +int read_config_file(avl_tree_t *config_tree, const char *fname) +{ + int err = -2; /* Parse error */ + FILE *fp; + char *buffer, *line; + char *variable, *value; + int lineno = 0, ignore = 0; + config_t *cfg; + size_t bufsize; + +cp + if((fp = fopen (fname, "r")) == NULL) + { + syslog(LOG_ERR, _("Cannot open config file %s: %s"), fname, strerror(errno)); + return -3; + } + + bufsize = 100; + buffer = xmalloc(bufsize); + + for(;;) + { + if((line = readline(fp, &buffer, &bufsize)) == NULL) + { + err = -1; + break; + } + + if(feof(fp)) + { + err = 0; + break; + } + + lineno++; + + if((variable = strtok(line, "\t =")) == NULL) + continue; /* no tokens on this line */ + + if(variable[0] == '#') + continue; /* comment: ignore */ + + if(!strcmp(variable, "-----BEGIN")) + ignore = 1; + + if(!ignore) + { + if(((value = strtok(NULL, "\t\n\r =")) == NULL) || value[0] == '#') + { + syslog(LOG_ERR, _("No value for variable `%s' on line %d while reading config file %s"), + variable, lineno, fname); + break; + } + + cfg = new_config(); + cfg->variable = xstrdup(variable); + cfg->value = xstrdup(value); + cfg->file = xstrdup(fname); + cfg->line = lineno; + + config_add(config_tree, cfg); + } + + if(!strcmp(variable, "-----END")) + ignore = 0; + } + + free(buffer); + fclose (fp); +cp + return err; +} + +int read_server_config() +{ + char *fname; + int x; +cp + asprintf(&fname, "%s/tinc.conf", confbase); + x = read_config_file(config_tree, fname); + if(x == -1) /* System error: complain */ + { + syslog(LOG_ERR, _("Failed to read `%s': %s"), fname, strerror(errno)); + } + free(fname); +cp + return x; +} + +int isadir(const char* f) +{ + struct stat s; + + if(stat(f, &s) < 0) + return 0; + else + return S_ISDIR(s.st_mode); +} + +int is_safe_path(const char *file) +{ + char *p; + const char *f; + char x; + struct stat s; + char l[MAXBUFSIZE]; + + if(*file != '/') + { + syslog(LOG_ERR, _("`%s' is not an absolute path"), file); + return 0; + } + + p = strrchr(file, '/'); + + if(p == file) /* It's in the root */ + p++; + + x = *p; + *p = '\0'; + + f = file; +check1: + if(lstat(f, &s) < 0) + { + syslog(LOG_ERR, _("Couldn't stat `%s': %s"), f, strerror(errno)); + return 0; + } + + if(s.st_uid != geteuid()) + { + syslog(LOG_ERR, _("`%s' is owned by UID %d instead of %d"), + f, s.st_uid, geteuid()); + return 0; + } + + if(S_ISLNK(s.st_mode)) + { + syslog(LOG_WARNING, _("Warning: `%s' is a symlink"), + f); + + if(readlink(f, l, MAXBUFSIZE) < 0) + { + syslog(LOG_ERR, _("Unable to read symbolic link `%s': %s"), f, strerror(errno)); + return 0; + } + + f = l; + goto check1; + } + + *p = x; + f = file; + +check2: + if(lstat(f, &s) < 0 && errno != ENOENT) + { + syslog(LOG_ERR, _("Couldn't stat `%s': %s"), f, strerror(errno)); + return 0; + } + + if(errno == ENOENT) + return 1; + + if(s.st_uid != geteuid()) + { + syslog(LOG_ERR, _("`%s' is owned by UID %d instead of %d"), + f, s.st_uid, geteuid()); + return 0; + } + + if(S_ISLNK(s.st_mode)) + { + syslog(LOG_WARNING, _("Warning: `%s' is a symlink"), + f); + + if(readlink(f, l, MAXBUFSIZE) < 0) + { + syslog(LOG_ERR, _("Unable to read symbolic link `%s': %s"), f, strerror(errno)); + return 0; + } + + f = l; + goto check2; + } + + if(s.st_mode & 0007) + { + /* Accessible by others */ + syslog(LOG_ERR, _("`%s' has unsecure permissions"), + f); + return 0; + } + + return 1; +} + +FILE *ask_and_safe_open(const char* filename, const char* what, const char* mode) +{ + FILE *r; + char *directory; + char *fn; + + /* Check stdin and stdout */ + if(!isatty(0) || !isatty(1)) + { + /* Argh, they are running us from a script or something. Write + the files to the current directory and let them burn in hell + for ever. */ + fn = xstrdup(filename); + } + else + { + /* Ask for a file and/or directory name. */ + fprintf(stdout, _("Please enter a file to save %s to [%s]: "), + what, filename); + fflush(stdout); + + if((fn = readline(stdin, NULL, NULL)) == NULL) + { + fprintf(stderr, _("Error while reading stdin: %s\n"), strerror(errno)); + return NULL; + } + + if(strlen(fn) == 0) + /* User just pressed enter. */ + fn = xstrdup(filename); + } + + if((strchr(fn, '/') == NULL) || (fn[0] != '/')) + { + /* The directory is a relative path or a filename. */ + char *p; + + directory = get_current_dir_name(); + asprintf(&p, "%s/%s", directory, fn); + free(fn); + free(directory); + fn = p; + } + + umask(0077); /* Disallow everything for group and other */ + + /* Open it first to keep the inode busy */ + if((r = fopen(fn, mode)) == NULL) + { + fprintf(stderr, _("Error opening file `%s': %s\n"), + fn, strerror(errno)); + free(fn); + return NULL; + } + + /* Then check the file for nasty attacks */ + if(!is_safe_path(fn)) /* Do not permit any directories that are + readable or writeable by other users. */ + { + fprintf(stderr, _("The file `%s' (or any of the leading directories) has unsafe permissions.\n" + "I will not create or overwrite this file.\n"), + fn); + fclose(r); + free(fn); + return NULL; + } + + free(fn); + + return r; +} + +int read_connection_config(connection_t *c) +{ + char *fname; + int x; +cp + asprintf(&fname, "%s/hosts/%s", confbase, c->name); + x = read_config_file(c->config_tree, fname); + free(fname); +cp + return x; +} diff --git a/src/read_conf.h b/src/read_conf.h new file mode 100644 index 00000000..e6e26d68 --- /dev/null +++ b/src/read_conf.h @@ -0,0 +1,31 @@ +/* + conf.h -- header for conf.c + Copyright (C) 1998-2002 Ivo Timmermans + 2000-2002 Guus Sliepen + + 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: read_conf.h,v 1.1 2002/04/28 12:46:26 zarq Exp $ +*/ + +#ifndef __TINC_READ_CONF_H__ +#define __TINC_READ_CONF_H__ + +extern int read_config_file(avl_tree_t *, const char *); +extern int read_server_config(void); +extern FILE *ask_and_safe_open(const char*, const char*, const char *); +extern int is_safe_path(const char *); + +#endif /* __TINC_READ_CONF_H__ */ diff --git a/src/tincd.c b/src/tincd.c index 4e766a8c..0f518372 100644 --- a/src/tincd.c +++ b/src/tincd.c @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: tincd.c,v 1.14 2002/04/13 11:07:12 zarq Exp $ + $Id: tincd.c,v 1.15 2002/04/28 12:46:26 zarq Exp $ */ #include "config.h" @@ -37,10 +37,16 @@ # include #endif +#ifdef USE_OPENSSL #include #include #include #include +#endif + +#ifdef USE_GCRYPT +#include +#endif #include #include @@ -231,6 +237,7 @@ void indicator(int a, int b, void *p) } } +#ifdef USE_OPENSSL /* Generate a public/private RSA keypair, and ask for a file to store them in. @@ -283,6 +290,7 @@ int keygen(int bits) return 0; } +#endif /* Set all files and paths according to netname @@ -347,6 +355,7 @@ main(int argc, char **argv, char **envp) /* Slllluuuuuuurrrrp! */ cp +#ifdef USE_OPENSSL RAND_load_file("/dev/urandom", 1024); #ifdef HAVE_SSLEAY_ADD_ALL_ALGORITHMS @@ -361,6 +370,7 @@ cp read_server_config(); exit(keygen(generate_keys)); } +#endif if(kill_tincd) exit(kill_other(kill_tincd)); -- 2.20.1