Moving files, first attempt at gcrypt compatibility, more interface

abstraction
This commit is contained in:
Ivo Timmermans 2002-04-28 12:46:26 +00:00
parent b0a676988a
commit 04d33be4bd
69 changed files with 10498 additions and 536 deletions

View file

@ -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

View file

@ -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,

View file

@ -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

269
lib/conf.c Normal file
View file

@ -0,0 +1,269 @@
/*
conf.c -- configuration storage & retrieval code
Copyright (C) 1998 Robert van der Meulen
1998-2002 Ivo Timmermans <ivo@o2w.nl>
2000-2002 Guus Sliepen <guus@sliepen.warande.net>
2000 Cris van Pelt <tribbel@arise.dhs.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: conf.c,v 1.1 2002/04/28 12:46:25 zarq Exp $
*/
#include "config.h"
#include <ctype.h>
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <xalloc.h>
#include <utils.h> /* for cp */
#include <avl_tree.h>
#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;
}

65
lib/conf.h Normal file
View file

@ -0,0 +1,65 @@
/*
conf.h -- header for conf.c
Copyright (C) 1998-2002 Ivo Timmermans <itimmermans@bigfoot.com>
2000-2002 Guus Sliepen <guus@sliepen.warande.net>
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 <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <avl_tree.h>
#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__ */

126
lib/connection.c Normal file
View file

@ -0,0 +1,126 @@
/*
connection.c -- connection list management
Copyright (C) 2000-2002 Guus Sliepen <guus@sliepen.warande.net>,
2000-2002 Ivo Timmermans <itimmermans@bigfoot.com>
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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <avl_tree.h>
#include <list.h>
#include "net.h" /* Don't ask. */
#include "netutl.h"
#include "config.h"
#include "conf.h"
#include <utils.h>
#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
}

141
lib/connection.h Normal file
View file

@ -0,0 +1,141 @@
/*
connection.h -- header for connection.c
Copyright (C) 2000-2002 Guus Sliepen <guus@sliepen.warande.net>,
2000-2002 Ivo Timmermans <itimmermans@bigfoot.com>
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 <sys/time.h>
#include <avl_tree.h>
#include <list.h>
#ifdef USE_OPENSSL
# ifdef HAVE_OPENSSL_EVP_H
# include <openssl/evp.h>
# else
# include <evp.h>
# endif
# ifdef HAVE_OPENSSL_RSA_H
# include <openssl/rsa.h>
# else
# include <rsa.h>
# endif
#endif /* USE_OPENSSL */
#ifdef USE_GCRYPT
# include <gcrypt.h>
#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__ */

View file

@ -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 <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <string.h>

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: 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) */

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: 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"

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: 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__ */

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: 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__

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: netutl.c,v 1.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"

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: netutl.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__

188
lib/node.c Normal file
View file

@ -0,0 +1,188 @@
/*
node.c -- node tree management
Copyright (C) 2001-2002 Guus Sliepen <guus@sliepen.warande.net>,
2001-2002 Ivo Timmermans <itimmermans@bigfoot.com>
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 <string.h>
#include <stdlib.h>
#include <avl_tree.h>
#include "node.h"
#include "netutl.h"
#include "net.h"
#include <utils.h>
#include <xalloc.h>
#include <hooks.h>
#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
}

View file

@ -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 <gcrypt.h>
#include <avl_tree.h>
#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;

View file

@ -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 <stdio.h>
#include <syslog.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <hooks.h>
#include <utils.h>
#include <xalloc.h>
#include <avl_tree.h>
@ -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
}

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: subnet.h,v 1.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);

View file

@ -46,4 +46,6 @@ AC_DEFUN(tinc_OPENSSL,
[AC_MSG_ERROR("OpenSSL depends on libdl.")]
)
)
found_openssl=1
])

View file

@ -31,3 +31,4 @@ src/freebsd/device.c
src/solaris/device.c
src/netbsd/device.c
src/openbsd/device.c
src/pokey/pokey.translatables

320
po/nl.po
View file

@ -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 <guus@sliepen.warande.net>\n"
"Language-Team: Dutch <vertaling@nl.linux.org>\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!"

View file

@ -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

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: 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 <stdio.h>
#include "config.h"
#include <stdlib.h>
#include <string.h>
#if defined(HAVE_FREEBSD) || defined(HAVE_OPENBSD)
#include <sys/param.h>

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: meta.c,v 1.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;
}

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: 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;
}

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: 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;
}

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: 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 <sys/socket.h>
#include <net/if.h>
#ifdef USE_OPENSSL
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/rand.h>
#endif
#ifdef USE_GCRYPT
#include <gcrypt.h>
#endif
#include <utils.h>
#include <xalloc.h>
@ -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

View file

@ -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@

45
src/pokey/array.c Normal file
View file

@ -0,0 +1,45 @@
#include <stdio.h>
#include <stdlib.h>
#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);
}

18
src/pokey/array.h Normal file
View file

@ -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__ */

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: conf.h,v 1.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;

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: connection.h,v 1.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 */

36
src/pokey/device.h Normal file
View file

@ -0,0 +1,36 @@
/*
net.h -- generic header for device.c
Copyright (C) 2001-2002 Ivo Timmermans <zarq@iname.com>
2001-2002 Guus Sliepen <guus@sliepen.warande.net>
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__ */

110
src/pokey/event.c Normal file
View file

@ -0,0 +1,110 @@
/*
event.c -- event queue
Copyright (C) 2002 Guus Sliepen <guus@sliepen.warande.net>,
2002 Ivo Timmermans <itimmermans@bigfoot.com>
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 <stdlib.h>
#include <xalloc.h>
#include <string.h>
#include <utils.h>
#include <avl_tree.h>
#include <time.h>
#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;
}

48
src/pokey/event.h Normal file
View file

@ -0,0 +1,48 @@
/*
event.h -- header for event.c
Copyright (C) 2002 Guus Sliepen <guus@sliepen.warande.net>,
2002 Ivo Timmermans <itimmermans@bigfoot.com>
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 <time.h>
#include <avl_tree.h>
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__ */

283
src/pokey/graph.c Normal file
View file

@ -0,0 +1,283 @@
/*
graph.c -- graph algorithms
Copyright (C) 2001-2002 Guus Sliepen <guus@sliepen.warande.net>,
2001-2002 Ivo Timmermans <itimmermans@bigfoot.com>
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 <string.h>
#if defined(HAVE_FREEBSD) || defined(HAVE_OPENBSD)
#include <sys/param.h>
#endif
#include <netinet/in.h>
#include <avl_tree.h>
#include <hooks.h>
#include <utils.h>
#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();
}

30
src/pokey/graph.h Normal file
View file

@ -0,0 +1,30 @@
/*
graph.h -- header for graph.c
Copyright (C) 2001-2002 Guus Sliepen <guus@sliepen.warande.net>,
2001-2002 Ivo Timmermans <itimmermans@bigfoot.com>
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__ */

View file

@ -1,9 +1,35 @@
/*
interface.c -- GTK+/GNOME interface functions
Copyright (C) 2002 Guus Sliepen <guus@sliepen.warande.net>,
2002 Ivo Timmermans <ivo@o2w.nl>
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 <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#define log mathlog
#include <math.h>
#undef log
#include <gtk/gtk.h>
#include <glade/glade.h>
@ -14,10 +40,12 @@
#include <libgnomeui/gnome-canvas-util.h>
#include "node.h"
#include "connection.h"
#include "edge.h"
#include "interface.h"
#include "logging.h"
#include <hooks.h>
#include <xalloc.h>
#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);
n->data = (void*)nd;
if_node_create(n);
if_node_visible(n);
return ctn;
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;
if_node_invisible(n);
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);
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;

View file

@ -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 <gtk/gtk.h>
#include <glade/glade.h>
#include <libgnomeui/gnome-canvas.h>
#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;
struct if_subnet_data {
GnomeCanvasItem *item; /* The gnome canvas item associated with the line */
GtkCTreeNode *ctn;
};
struct if_node_data {
double x, y;
int visible;
int id;
GnomeCanvasItem *item;
GtkCTreeNode *ctn;
GladeXML *hi_xml;
};
extern int build_graph;
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 *);
void if_build_graph(void);
void if_graph_add_node(node_t *);
void if_graph_add_edge(edge_t *);
int init_interface(void);
#endif /* __TINC_INTERFACE_H__ */

103
src/pokey/logging.c Normal file
View file

@ -0,0 +1,103 @@
/*
logging.c -- log messages to e.g. syslog
Copyright (C) 2001-2002 Guus Sliepen <guus@sliepen.warande.net>,
2001-2002 Ivo Timmermans <itimmermans@bigfoot.com>
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 <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <syslog.h>
#include <avl_tree.h>
#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);
}

190
src/pokey/meta.c Normal file
View file

@ -0,0 +1,190 @@
/*
meta.c -- handle the meta communication
Copyright (C) 2000-2002 Guus Sliepen <guus@sliepen.warande.net>,
2000-2002 Ivo Timmermans <itimmermans@bigfoot.com>
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 <utils.h>
#include <avl_tree.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
/* This line must be below the rest for FreeBSD */
#include <sys/types.h>
#include <sys/socket.h>
#include <openssl/evp.h>
#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;
}

32
src/pokey/meta.h Normal file
View file

@ -0,0 +1,32 @@
/*
meta.h -- header for meta.c
Copyright (C) 2000-2002 Guus Sliepen <guus@sliepen.warande.net>,
2000-2002 Ivo Timmermans <itimmermans@bigfoot.com>
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__ */

467
src/pokey/net.c Normal file
View file

@ -0,0 +1,467 @@
/*
net.c -- most of the network code
Copyright (C) 1998-2002 Ivo Timmermans <itimmermans@bigfoot.com>,
2000-2002 Guus Sliepen <guus@sliepen.warande.net>
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 <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#ifdef HAVE_LINUX
#include <netinet/ip.h>
#include <netinet/tcp.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/ioctl.h>
/* SunOS really wants sys/socket.h BEFORE net/if.h,
and FreeBSD wants these lines below the rest. */
#include <arpa/inet.h>
#include <sys/socket.h>
#include <net/if.h>
#include <openssl/rand.h>
#include <gtk/gtk.h>
#include <utils.h>
#include <xalloc.h>
#include <avl_tree.h>
#include <list.h>
#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
}

153
src/pokey/net.h Normal file
View file

@ -0,0 +1,153 @@
/*
net.h -- header for net.c
Copyright (C) 1998-2002 Ivo Timmermans <zarq@iname.com>
2000-2002 Guus Sliepen <guus@sliepen.warande.net>
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 <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#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__ */

429
src/pokey/net_packet.c Normal file
View file

@ -0,0 +1,429 @@
/*
net_packet.c -- Handles in- and outgoing VPN packets
Copyright (C) 1998-2002 Ivo Timmermans <itimmermans@bigfoot.com>,
2000-2002 Guus Sliepen <guus@sliepen.warande.net>
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 <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#ifdef HAVE_LINUX
#include <netinet/ip.h>
#include <netinet/tcp.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/ioctl.h>
/* SunOS really wants sys/socket.h BEFORE net/if.h,
and FreeBSD wants these lines below the rest. */
#include <arpa/inet.h>
#include <sys/socket.h>
#include <net/if.h>
#include <openssl/rand.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/hmac.h>
#ifndef HAVE_RAND_PSEUDO_BYTES
#define RAND_pseudo_bytes RAND_bytes
#endif
#include <zlib.h>
#include <utils.h>
#include <xalloc.h>
#include <avl_tree.h>
#include <list.h>
#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
}

546
src/pokey/net_setup.c Normal file
View file

@ -0,0 +1,546 @@
/*
net_setup.c -- Setup.
Copyright (C) 1998-2002 Ivo Timmermans <itimmermans@bigfoot.com>,
2000-2002 Guus Sliepen <guus@sliepen.warande.net>
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 <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#ifdef HAVE_LINUX
#include <netinet/ip.h>
#include <netinet/tcp.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/ioctl.h>
/* SunOS really wants sys/socket.h BEFORE net/if.h,
and FreeBSD wants these lines below the rest. */
#include <arpa/inet.h>
#include <sys/socket.h>
#include <net/if.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/rand.h>
#include <utils.h>
#include <xalloc.h>
#include <avl_tree.h>
#include <list.h>
#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;
}

491
src/pokey/net_socket.c Normal file
View file

@ -0,0 +1,491 @@
/*
net_socket.c -- Handle various kinds of sockets.
Copyright (C) 1998-2002 Ivo Timmermans <itimmermans@bigfoot.com>,
2000-2002 Guus Sliepen <guus@sliepen.warande.net>
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 <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#ifdef HAVE_LINUX
#include <netinet/ip.h>
#include <netinet/tcp.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/ioctl.h>
/* SunOS really wants sys/socket.h BEFORE net/if.h,
and FreeBSD wants these lines below the rest. */
#include <arpa/inet.h>
#include <sys/socket.h>
#include <net/if.h>
#include <utils.h>
#include <xalloc.h>
#include <avl_tree.h>
#include <list.h>
#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);
}
}

250
src/pokey/netutl.c Normal file
View file

@ -0,0 +1,250 @@
/*
netutl.c -- some supporting network utility code
Copyright (C) 1998-2002 Ivo Timmermans <itimmermans@bigfoot.com>
2000-2002 Guus Sliepen <guus@sliepen.warande.net>
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 <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <utils.h>
#include <xalloc.h>
#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;
}

46
src/pokey/netutl.h Normal file
View file

@ -0,0 +1,46 @@
/*
netutl.h -- header file for netutl.c
Copyright (C) 1998-2002 Ivo Timmermans <zarq@iname.com>
2000-2002 Guus Sliepen <guus@sliepen.warande.net>
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 <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#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__ */

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: 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;

File diff suppressed because it is too large Load diff

56
src/pokey/pokey2.xpm Normal file
View file

@ -0,0 +1,56 @@
/* XPM */
static char * pokey2_xpm[] = {
"36 49 4 1",
" c None",
". c #000000",
"+ c #FFFFFF",
"@ c #E9A500",
" .......... ",
" ............. ",
" ................ ",
" ................. ",
" .................. ",
" ................... ",
" ..................... ",
" ........++............. ",
" .........++.............. ",
" ..+....+..++................ ",
" .++++++...+................. ",
" ....+.+...................... ",
" ..@@@@@@.++..................... ",
" .@@@@@@@@.+++..................... ",
"...........++++.................... ",
" .@@@@@@@@.++++.....................",
" .....@@@.++++.....................",
" .....+++++....................",
" .++++++++++...................",
" .++++++++++++..................",
" .++++++++++++..................",
" .+++++++++++++..................",
" .+++++++++++++..................",
" .+++++++++++++................. ",
" .+++++++++++++................. ",
" .+++++++++++++.....+........... ",
" .+++++++++++++.....+........... ",
" .++++++++++++++....+........... ",
" .++++++++++++++................ ",
" .++++++++++++++...+............ ",
" .++++++++++++++...+........... ",
" .++++++++++++++...+........... ",
" .++++++++++++++..++........... ",
" .++++++++++++++++++........... ",
" .++++++++++++++++++........... ",
" .++++++++++++++++++.......... ",
" .+++++++++++++++++.......... ",
" .++++++++++++++++........... ",
" .++++++++++++++++........... ",
" .++++++++++++++++........... ",
" .+++++++++++++++........... ",
" ..+++++++++++............. ",
" . .++++++++............... ",
" ..+++++.+............. ",
" ....+.++............ ",
" ................... ",
" .................... ",
" .............. .. ",
" . .. "};

469
src/pokey/process.c Normal file
View file

@ -0,0 +1,469 @@
/*
process.c -- process management functions
Copyright (C) 1999-2002 Ivo Timmermans <itimmermans@bigfoot.com>,
2000-2002 Guus Sliepen <guus@sliepen.warande.net>
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 <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>
#include <pidfile.h>
#include <utils.h>
#include <xalloc.h>
#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));
}
}

36
src/pokey/process.h Normal file
View file

@ -0,0 +1,36 @@
/*
process.h -- header file for process.c
Copyright (C) 1999-2002 Ivo Timmermans <itimmermans@bigfoot.com>,
2000-2002 Guus Sliepen <guus@sliepen.warande.net>
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__ */

245
src/pokey/protocol.c Normal file
View file

@ -0,0 +1,245 @@
/*
protocol.c -- handle the meta-protocol, basic functions
Copyright (C) 1999-2001 Ivo Timmermans <itimmermans@bigfoot.com>,
2000,2001 Guus Sliepen <guus@sliepen.warande.net>
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 <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <errno.h>
#include <utils.h>
#include <xalloc.h>
#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",
};

120
src/pokey/protocol.h Normal file
View file

@ -0,0 +1,120 @@
/*
protocol.h -- header for protocol.c
Copyright (C) 1999-2001 Ivo Timmermans <itimmermans@bigfoot.com>,
2000,2001 Guus Sliepen <guus@sliepen.warande.net>
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__ */

609
src/pokey/protocol_auth.c Normal file
View file

@ -0,0 +1,609 @@
/*
protocol_auth.c -- handle the meta-protocol, authentication
Copyright (C) 1999-2002 Ivo Timmermans <itimmermans@bigfoot.com>,
2000-2002 Guus Sliepen <guus@sliepen.warande.net>
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 <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <errno.h>
#include <utils.h>
#include <xalloc.h>
#include <avl_tree.h>
#include <openssl/sha.h>
#include <openssl/rand.h>
#include <openssl/evp.h>
#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;
}

311
src/pokey/protocol_edge.c Normal file
View file

@ -0,0 +1,311 @@
/*
protocol_edge.c -- handle the meta-protocol, edges
Copyright (C) 1999-2002 Ivo Timmermans <itimmermans@bigfoot.com>,
2000-2002 Guus Sliepen <guus@sliepen.warande.net>
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 <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <errno.h>
#include <utils.h>
#include <xalloc.h>
#include <avl_tree.h>
#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;
}

285
src/pokey/protocol_key.c Normal file
View file

@ -0,0 +1,285 @@
/*
protocol_key.c -- handle the meta-protocol, key exchange
Copyright (C) 1999-2002 Ivo Timmermans <itimmermans@bigfoot.com>,
2000-2002 Guus Sliepen <guus@sliepen.warande.net>
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 <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <errno.h>
#include <utils.h>
#include <xalloc.h>
#include <avl_tree.h>
#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;
}

182
src/pokey/protocol_misc.c Normal file
View file

@ -0,0 +1,182 @@
/*
protocol_misc.c -- handle the meta-protocol, miscellaneous functions
Copyright (C) 1999-2002 Ivo Timmermans <itimmermans@bigfoot.com>,
2000-2002 Guus Sliepen <guus@sliepen.warande.net>
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 <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <errno.h>
#include <utils.h>
#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",
};

238
src/pokey/protocol_subnet.c Normal file
View file

@ -0,0 +1,238 @@
/*
protocol_subnet.c -- handle the meta-protocol, subnets
Copyright (C) 1999-2002 Ivo Timmermans <itimmermans@bigfoot.com>,
2000-2002 Guus Sliepen <guus@sliepen.warande.net>
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 <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <errno.h>
#include <utils.h>
#include <xalloc.h>
#include <avl_tree.h>
#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;
}

377
src/pokey/route.c Normal file
View file

@ -0,0 +1,377 @@
/*
route.c -- routing
Copyright (C) 2000-2002 Ivo Timmermans <itimmermans@bigfoot.com>,
2000-2002 Guus Sliepen <guus@sliepen.warande.net>
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 <sys/param.h>
#endif
#include <sys/socket.h>
#include <netinet/in.h>
#if defined(HAVE_SOLARIS) || defined(HAVE_OPENBSD)
#include <net/if.h>
#define ETHER_ADDR_LEN 6
#else
#include <net/ethernet.h>
#endif
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
#include <netinet/if_ether.h>
#include <utils.h>
#include <xalloc.h>
#include <string.h>
#include <avl_tree.h>
#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
}

41
src/pokey/route.h Normal file
View file

@ -0,0 +1,41 @@
/*
route.h -- header file for route.c
Copyright (C) 2000-2002 Ivo Timmermans <zarq@iname.com>
2000-2002 Guus Sliepen <guus@sliepen.warande.net>
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__ */

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: protocol.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 *);

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: protocol_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 <xalloc.h>
#include <avl_tree.h>
#ifdef USE_OPENSSL
#include <openssl/sha.h>
#include <openssl/rand.h>
#include <openssl/evp.h>
#endif
#ifdef USE_GCRYPT
#include <gcrypt.h>
#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);

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: protocol_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
{

411
src/read_conf.c Normal file
View file

@ -0,0 +1,411 @@
/*
read_conf.c -- read the configuration files
Copyright (C) 1998 Robert van der Meulen
1998-2002 Ivo Timmermans <ivo@o2w.nl>
2000-2002 Guus Sliepen <guus@sliepen.warande.net>
2000 Cris van Pelt <tribbel@arise.dhs.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: read_conf.c,v 1.1 2002/04/28 12:46:26 zarq Exp $
*/
#include "config.h"
#include <ctype.h>
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <xalloc.h>
#include <utils.h> /* for cp */
#include <avl_tree.h>
#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;
}

31
src/read_conf.h Normal file
View file

@ -0,0 +1,31 @@
/*
conf.h -- header for conf.c
Copyright (C) 1998-2002 Ivo Timmermans <itimmermans@bigfoot.com>
2000-2002 Guus Sliepen <guus@sliepen.warande.net>
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__ */

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: tincd.c,v 1.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 <sys/ioctl.h>
#endif
#ifdef USE_OPENSSL
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/evp.h>
#endif
#ifdef USE_GCRYPT
#include <gcrypt.h>
#endif
#include <utils.h>
#include <xalloc.h>
@ -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));