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

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

@ -1,211 +0,0 @@
/*
edge.c -- edge tree 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: edge.c,v 1.2 2002/04/09 15:26:00 zarq Exp $
*/
#include "config.h"
#include <stdio.h>
#include <syslog.h>
#include <string.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 "xalloc.h"
#include "system.h"
avl_tree_t *edge_tree; /* Tree with all known edges (replaces active_tree) */
avl_tree_t *edge_weight_tree; /* Tree with all edges, sorted on weight */
int edge_compare(edge_t *a, edge_t *b)
{
int result;
result = strcmp(a->from.node->name, b->from.node->name);
if(result)
return result;
else
return strcmp(a->to.node->name, b->to.node->name);
}
/* Evil edge_compare() from a parallel universe ;)
int edge_compare(edge_t *a, edge_t *b)
{
int result;
return (result = strcmp(a->from.node->name, b->from.node->name)) || (result = strcmp(a->to.node->name, b->to.node->name)), result;
}
*/
int edge_name_compare(edge_t *a, edge_t *b)
{
int result;
char *name_a1, *name_a2, *name_b1, *name_b2;
if(strcmp(a->from.node->name, a->to.node->name) < 0)
name_a1 = a->from.node->name, name_a2 = a->to.node->name;
else
name_a1 = a->to.node->name, name_a2 = a->from.node->name;
if(strcmp(b->from.node->name, b->to.node->name) < 0)
name_b1 = b->from.node->name, name_b2 = b->to.node->name;
else
name_b1 = b->to.node->name, name_b2 = b->from.node->name;
result = strcmp(name_a1, name_b1);
if(result)
return result;
else
return strcmp(name_a2, name_b2);
}
int edge_weight_compare(edge_t *a, edge_t *b)
{
int result;
result = a->weight - b->weight;
if(result)
return result;
else
return edge_name_compare(a, b);
}
void init_edges(void)
{
cp
edge_tree = avl_alloc_tree((avl_compare_t)edge_compare, NULL);
edge_weight_tree = avl_alloc_tree((avl_compare_t)edge_weight_compare, NULL);
cp
}
avl_tree_t *new_edge_tree(void)
{
cp
return avl_alloc_tree((avl_compare_t)edge_name_compare, NULL);
cp
}
void free_edge_tree(avl_tree_t *edge_tree)
{
cp
avl_delete_tree(edge_tree);
cp
}
void exit_edges(void)
{
cp
avl_delete_tree(edge_tree);
cp
}
/* Creation and deletion of connection elements */
edge_t *new_edge(void)
{
edge_t *e;
cp
e = (edge_t *)xmalloc_and_zero(sizeof(*e));
cp
return e;
}
void free_edge(edge_t *e)
{
cp
free(e);
cp
}
void edge_add(edge_t *e)
{
cp
avl_insert(edge_tree, e);
avl_insert(edge_weight_tree, e);
avl_insert(e->from.node->edge_tree, e);
avl_insert(e->to.node->edge_tree, e);
cp
}
void edge_del(edge_t *e)
{
cp
avl_delete(edge_tree, e);
avl_delete(edge_weight_tree, e);
avl_delete(e->from.node->edge_tree, e);
avl_delete(e->to.node->edge_tree, e);
cp
}
edge_t *lookup_edge(node_t *from, node_t *to)
{
edge_t v, *result;
cp
v.from.node = from;
v.to.node = to;
result = avl_search(edge_tree, &v);
if(result)
return result;
cp
v.from.node = to;
v.to.node = from;
return avl_search(edge_tree, &v);
}
void dump_edges(void)
{
avl_node_t *node;
edge_t *e;
char *from_udp, *to_udp;
cp
syslog(LOG_DEBUG, _("Edges:"));
for(node = edge_tree->head; node; node = node->next)
{
e = (edge_t *)node->data;
from_udp = sockaddr2hostname(&e->from.udpaddress);
to_udp = sockaddr2hostname(&e->to.udpaddress);
syslog(LOG_DEBUG, _(" %s at %s - %s at %s options %lx weight %d"),
e->from.node->name, from_udp,
e->to.node->name, to_udp,
e->options, e->weight);
free(from_udp);
free(to_udp);
}
syslog(LOG_DEBUG, _("End of edges."));
cp
}

View file

@ -1,62 +0,0 @@
/*
edge.h -- header for edge.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: edge.h,v 1.2 2002/04/09 15:26:00 zarq Exp $
*/
#ifndef __TINC_EDGE_H__
#define __TINC_EDGE_H__
#include <avl_tree.h>
#include "net.h"
#include "node.h"
#include "connection.h"
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 udpaddress; /* real (internet) ip on this end of the vpn connection */
} halfconnection_t;
typedef struct edge_t {
struct halfconnection_t from;
struct halfconnection_t to;
long int options; /* options turned on for this edge */
int weight; /* weight of this edge */
struct connection_t *connection; /* connection associated with this edge, if available */
} edge_t;
extern avl_tree_t *edge_tree; /* Tree with all known edges (replaces active_tree) */
extern avl_tree_t *edge_weight_tree; /* Tree with all known edges sorted on weight */
extern void init_edges(void);
extern void exit_edges(void);
extern edge_t *new_edge(void);
extern void free_edge(edge_t *);
extern avl_tree_t *new_edge_tree(void);
extern void free_edge_tree(avl_tree_t *);
extern void edge_add(edge_t *);
extern void edge_del(edge_t *);
extern edge_t *lookup_edge(struct node_t *, struct node_t *);
extern void dump_edges(void);
#endif /* __TINC_EDGE_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: 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

@ -1,72 +0,0 @@
/*
logging.h -- header for logging.c
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: logging.h,v 1.7 2002/04/13 11:00:41 zarq Exp $
*/
#ifndef __TINC_LOGGING_H__
#define __TINC_LOGGING_H__
#include <stdarg.h>
enum {
TLOG_DEBUG,
TLOG_INFO,
TLOG_NOTICE,
TLOG_ERROR,
TLOG_CRITICAL
};
enum {
DEBUG_NOTHING = 0, /* Quiet mode, only show starting/stopping of the daemon */
DEBUG_CONNECTIONS = 1, /* Show (dis)connects of other tinc daemons via TCP */
DEBUG_ERROR = 2, /* Show error messages received from other hosts */
DEBUG_STATUS = 2, /* Show status messages received from other hosts */
DEBUG_PROTOCOL = 3, /* Show the requests that are sent/received */
DEBUG_META = 4, /* Show contents of every request that is sent/received */
DEBUG_TRAFFIC = 5, /* Show network traffic information */
DEBUG_PACKET = 6, /* Show contents of each packet that is being sent/received */
DEBUG_SCARY_THINGS = 10 /* You have been warned */
};
typedef void (log_function_t)(int,int,char*,va_list);
extern int debug_lvl;
extern avl_tree_t *log_hooks_tree;
extern void log(int, int, char *, ...);
extern void log_add_hook(log_function_t *);
extern void log_del_hook(log_function_t *);
extern log_function_t log_default;
extern log_function_t log_syslog;
extern void tinc_syslog(int, char *, ...);
#ifndef LOG_ERR /* Something from syslog.h */
# define syslog tinc_syslog
#define LOG_EMERG 0 /* system is unusable */
#define LOG_ALERT 1 /* action must be taken immediately */
#define LOG_CRIT 2 /* critical conditions */
#define LOG_ERR 3 /* error conditions */
#define LOG_WARNING 4 /* warning conditions */
#define LOG_NOTICE 5 /* normal but significant condition */
#define LOG_INFO 6 /* informational */
#define LOG_DEBUG 7 /* debug-level messages */
#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: 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,88 +0,0 @@
/*
node.h -- header for node.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: node.h,v 1.2 2002/04/09 15:26:00 zarq Exp $
*/
#ifndef __TINC_NODE_H__
#define __TINC_NODE_H__
#include <avl_tree.h>
#include "subnet.h"
#include "connection.h"
typedef struct node_status_t {
int active:1; /* 1 if active.. */
int validkey:1; /* 1 if we currently have a valid key for him */
int waitingforkey:1; /* 1 if we already sent out a request */
int visited:1; /* 1 if this node has been visited by one of the graph algorithms */
int reachable:1; /* 1 if this node is reachable in the graph */
int indirect:1; /* 1 if this node is not directly reachable by us */
int unused:26;
} node_status_t;
typedef struct node_t {
char *name; /* name of this node */
long int options; /* options turned on for this node */
sockaddr_t address; /* his real (internet) ip to send UDP packets to */
char *hostname; /* the hostname of its real ip */
struct node_status_t status;
const EVP_CIPHER *cipher; /* Cipher type for UDP packets */
char *key; /* Cipher key and iv */
int keylength; /* Cipher key and iv length*/
const EVP_MD *digest; /* Digest type for MAC */
int maclength; /* Length of MAC */
int compression; /* Compressionlevel, 0 = no compression */
list_t *queue; /* Queue for packets awaiting to be encrypted */
struct node_t *nexthop; /* nearest node from us to him */
struct node_t *via; /* next hop for UDP packets */
avl_tree_t *subnet_tree; /* Pointer to a tree of subnets belonging to this node */
avl_tree_t *edge_tree; /* Edges with this node as one of the endpoints */
struct connection_t *connection; /* Connection associated with this node (if a direct connection exists) */
unsigned int sent_seqno; /* Sequence number last sent to this node */
unsigned int received_seqno; /* Sequence number last received from this node */
} node_t;
extern struct node_t *myself;
extern avl_tree_t *node_tree;
extern avl_tree_t *node_udp_tree;
extern void init_nodes(void);
extern void exit_nodes(void);
extern node_t *new_node(void);
extern void free_node(node_t *);
extern void node_add(node_t *);
extern void node_del(node_t *);
extern node_t *lookup_node(char *);
extern node_t *lookup_node_udp(sockaddr_t *);
extern void dump_nodes(void);
#endif /* __TINC_NODE_H__ */

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

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:26 zarq Exp $
*/
#include "config.h"
@ -74,10 +74,7 @@ void log_del_hook(log_function_t *fn)
void log_default(int level, int priority, char *fmt, va_list ap)
{
if(debug_lvl >= level)
{
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
}
vfprintf(stderr, fmt, ap);
}
void log_syslog(int level, int priority, char *fmt, va_list ap)

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
}

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:26 zarq Exp $
*/
#ifndef __TINC_NET_H__
@ -42,7 +42,7 @@
#define MAXSOCKETS 128 /* Overkill... */
#define MAXQUEUELENGTH 8 /* Maximum number of packats in a single queue */
#define MAXQUEUELENGTH 8
typedef struct mac_t
{

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);
}
}

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:26 zarq Exp $
*/
#include "config.h"
@ -30,13 +30,13 @@
#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"
@ -62,8 +62,9 @@ cp
if((err = getaddrinfo(address, service, &hint, &ai)))
{
if(debug_lvl >= DEBUG_ERROR)
syslog(LOG_WARNING, _("Error looking up %s port %s: %s\n"), address, service, gai_strerror(err));
log(DEBUG_ERROR, LOG_WARNING,
_("Error looking up %s port %s: %s\n"),
address, service, gai_strerror(err));
cp_trace();
return NULL;
}
@ -86,7 +87,9 @@ cp
if((err = getaddrinfo(address, port, &hint, &ai) || !ai))
{
syslog(LOG_ERR, _("Error looking up %s port %s: %s\n"), address, port, gai_strerror(err));
log(0, TLOG_ERROR,
_("Error looking up %s port %s: %s\n"),
address, port, gai_strerror(err));
cp_trace();
raise(SIGFPE);
exit(0);
@ -192,7 +195,7 @@ cp
return result;
if(m)
return (a[i] & (0x100 - (1 << (8 - m)))) - (b[i] & (0x100 - (1 << (8 - m))));
return (a[i] & (0x100 - (m << 1))) - (b[i] & (0x100 - (m << 1)));
return 0;
}
@ -205,7 +208,7 @@ cp
masklen %= 8;
if(masklen)
a[i++] &= (0x100 - (1 << masklen));
a[i++] &= (0x100 - (masklen << 1));
for(; i < len; i++)
a[i] = 0;
@ -220,7 +223,7 @@ cp
if(m)
{
a[i] = b[i] & (0x100 - (1 << m));
a[i] = b[i] & (0x100 - (m << 1));
i++;
}
@ -236,7 +239,7 @@ cp
masklen %= 8;
if(masklen)
if(a[i++] & (char)~(0x100 - (1 << masklen)))
if(a[i++] & ~(0x100 - (masklen << 1)))
return -1;
for(; i < len; i++)

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:26 zarq Exp $
*/
#ifndef __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

@ -1,394 +0,0 @@
/*
subnet.c -- handle subnet lookups and lists
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: subnet.c,v 1.2 2002/04/09 15:26:01 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 <utils.h>
#include <xalloc.h>
#include <avl_tree.h>
#include "conf.h"
#include "net.h"
#include "node.h"
#include "subnet.h"
#include "netutl.h"
#include "system.h"
/* lists type of subnet */
avl_tree_t *subnet_tree;
/* Subnet comparison */
int subnet_compare_mac(subnet_t *a, subnet_t *b)
{
cp
return memcmp(&a->net.mac.address, &b->net.mac.address, sizeof(mac_t));
}
int subnet_compare_ipv4(subnet_t *a, subnet_t *b)
{
int result;
cp
result = memcmp(&a->net.ipv4.address, &b->net.ipv4.address, sizeof(ipv4_t));
if(result)
return result;
return a->net.ipv4.prefixlength - b->net.ipv4.prefixlength;
}
int subnet_compare_ipv6(subnet_t *a, subnet_t *b)
{
int result;
cp
result = memcmp(&a->net.ipv6.address, &b->net.ipv6.address, sizeof(ipv6_t));
if(result)
return result;
return a->net.ipv6.prefixlength - b->net.ipv6.prefixlength;
}
int subnet_compare(subnet_t *a, subnet_t *b)
{
int result;
cp
result = a->type - b->type;
if(result)
return result;
switch(a->type)
{
case SUBNET_MAC:
return subnet_compare_mac(a, b);
case SUBNET_IPV4:
return subnet_compare_ipv4(a, b);
case SUBNET_IPV6:
return subnet_compare_ipv6(a, b);
default:
syslog(LOG_ERR, _("subnet_compare() was called with unknown subnet type %d, exitting!"), a->type);
cp_trace();
exit(0);
}
return 0;
}
/* Initialising trees */
void init_subnets(void)
{
cp
subnet_tree = avl_alloc_tree((avl_compare_t)subnet_compare, (avl_action_t)free_subnet);
cp
}
void exit_subnets(void)
{
cp
avl_delete_tree(subnet_tree);
cp
}
avl_tree_t *new_subnet_tree(void)
{
cp
return avl_alloc_tree((avl_compare_t)subnet_compare, NULL);
cp
}
void free_subnet_tree(avl_tree_t *subnet_tree)
{
cp
avl_delete_tree(subnet_tree);
cp
}
/* Allocating and freeing space for subnets */
subnet_t *new_subnet(void)
{
cp
return (subnet_t *)xmalloc(sizeof(subnet_t));
}
void free_subnet(subnet_t *subnet)
{
cp
free(subnet);
}
/* Adding and removing subnets */
void subnet_add(node_t *n, subnet_t *subnet)
{
cp
subnet->owner = n;
avl_insert(subnet_tree, subnet);
cp
avl_insert(n->subnet_tree, subnet);
cp
}
void subnet_del(node_t *n, subnet_t *subnet)
{
cp
avl_delete(n->subnet_tree, subnet);
cp
avl_delete(subnet_tree, subnet);
cp
}
/* Ascii representation of subnets */
subnet_t *str2net(char *subnetstr)
{
int i, l;
subnet_t *subnet;
unsigned short int x[8];
cp
subnet = new_subnet();
cp
if(sscanf(subnetstr, "%hu.%hu.%hu.%hu/%d",
&x[0], &x[1], &x[2], &x[3],
&l) == 5)
{
subnet->type = SUBNET_IPV4;
subnet->net.ipv4.prefixlength = l;
for(i = 0; i < 4; i++)
subnet->net.ipv4.address.x[i] = x[i];
return subnet;
}
if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%d",
&x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7],
&l) == 9)
{
subnet->type = SUBNET_IPV6;
subnet->net.ipv6.prefixlength = l;
for(i = 0; i < 8; i++)
subnet->net.ipv6.address.x[i] = htons(x[i]);
return subnet;
}
if(sscanf(subnetstr, "%hu.%hu.%hu.%hu",
&x[0], &x[1], &x[2], &x[3]) == 4)
{
subnet->type = SUBNET_IPV4;
subnet->net.ipv4.prefixlength = 32;
for(i = 0; i < 4; i++)
subnet->net.ipv4.address.x[i] = x[i];
return subnet;
}
if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",
&x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7]) == 8)
{
subnet->type = SUBNET_IPV6;
subnet->net.ipv6.prefixlength = 128;
for(i = 0; i < 8; i++)
subnet->net.ipv6.address.x[i] = htons(x[i]);
return subnet;
}
if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx",
&x[0], &x[1], &x[2], &x[3], &x[4], &x[5]) == 6)
{
subnet->type = SUBNET_MAC;
for(i = 0; i < 6; i++)
subnet->net.mac.address.x[i] = x[i];
return subnet;
}
free(subnet);
return NULL;
}
char *net2str(subnet_t *subnet)
{
char *netstr;
cp
switch(subnet->type)
{
case SUBNET_MAC:
asprintf(&netstr, "%hx:%hx:%hx:%hx:%hx:%hx",
subnet->net.mac.address.x[0],
subnet->net.mac.address.x[1],
subnet->net.mac.address.x[2],
subnet->net.mac.address.x[3],
subnet->net.mac.address.x[4],
subnet->net.mac.address.x[5]);
break;
case SUBNET_IPV4:
asprintf(&netstr, "%hu.%hu.%hu.%hu/%d",
subnet->net.ipv4.address.x[0],
subnet->net.ipv4.address.x[1],
subnet->net.ipv4.address.x[2],
subnet->net.ipv4.address.x[3],
subnet->net.ipv4.prefixlength);
break;
case SUBNET_IPV6:
asprintf(&netstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%d",
ntohs(subnet->net.ipv6.address.x[0]),
ntohs(subnet->net.ipv6.address.x[1]),
ntohs(subnet->net.ipv6.address.x[2]),
ntohs(subnet->net.ipv6.address.x[3]),
ntohs(subnet->net.ipv6.address.x[4]),
ntohs(subnet->net.ipv6.address.x[5]),
ntohs(subnet->net.ipv6.address.x[6]),
ntohs(subnet->net.ipv6.address.x[7]),
subnet->net.ipv6.prefixlength);
break;
default:
syslog(LOG_ERR, _("net2str() was called with unknown subnet type %d, exitting!"), subnet->type);
cp_trace();
exit(0);
}
cp
return netstr;
}
/* Subnet lookup routines */
subnet_t *lookup_subnet(node_t *owner, subnet_t *subnet)
{
cp
return avl_search(owner->subnet_tree, subnet);
}
subnet_t *lookup_subnet_mac(mac_t *address)
{
subnet_t subnet, *p;
cp
subnet.type = SUBNET_MAC;
memcpy(&subnet.net.mac.address, address, sizeof(mac_t));
p = (subnet_t *)avl_search(subnet_tree, &subnet);
cp
return p;
}
subnet_t *lookup_subnet_ipv4(ipv4_t *address)
{
subnet_t subnet, *p;
cp
subnet.type = SUBNET_IPV4;
memcpy(&subnet.net.ipv4.address, address, sizeof(ipv4_t));
subnet.net.ipv4.prefixlength = 32;
do
{
/* Go find subnet */
p = (subnet_t *)avl_search_closest_smaller(subnet_tree, &subnet);
/* Check if the found subnet REALLY matches */
cp
if(p)
{
if(p->type != SUBNET_IPV4)
{
p = NULL;
break;
}
if (!maskcmp((char *)address, (char *)&p->net.ipv4.address, p->net.ipv4.prefixlength, sizeof(ipv4_t)))
break;
else
{
/* Otherwise, see if there is a bigger enclosing subnet */
subnet.net.ipv4.prefixlength = p->net.ipv4.prefixlength - 1;
maskcpy((char *)&subnet.net.ipv4.address, (char *)&p->net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof(ipv4_t));
}
}
} while (p);
cp
return p;
}
subnet_t *lookup_subnet_ipv6(ipv6_t *address)
{
subnet_t subnet, *p;
cp
subnet.type = SUBNET_IPV6;
memcpy(&subnet.net.ipv6.address, address, sizeof(ipv6_t));
subnet.net.ipv6.prefixlength = 128;
do
{
/* Go find subnet */
p = (subnet_t *)avl_search_closest_smaller(subnet_tree, &subnet);
/* Check if the found subnet REALLY matches */
cp
if(p)
{
if(p->type != SUBNET_IPV6)
return NULL;
if (!maskcmp((char *)address, (char *)&p->net.ipv6.address, p->net.ipv6.prefixlength, sizeof(ipv6_t)))
break;
else
{
/* Otherwise, see if there is a bigger enclosing subnet */
subnet.net.ipv6.prefixlength = p->net.ipv6.prefixlength - 1;
maskcpy((char *)&subnet.net.ipv6.address, (char *)&p->net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof(ipv6_t));
}
}
} while (p);
cp
return p;
}
void dump_subnets(void)
{
char *netstr;
subnet_t *subnet;
avl_node_t *node;
cp
syslog(LOG_DEBUG, _("Subnet list:"));
for(node = subnet_tree->head; node; node = node->next)
{
subnet = (subnet_t *)node->data;
netstr = net2str(subnet);
syslog(LOG_DEBUG, _(" %s owner %s"), netstr, subnet->owner->name);
free(netstr);
}
syslog(LOG_DEBUG, _("End of subnet list."));
cp
}

View file

@ -1,88 +0,0 @@
/*
subnet.h -- header for subnet.c
Copyright (C) 2000,2001 Guus Sliepen <guus@sliepen.warande.net>,
2000,2001 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: subnet.h,v 1.2 2002/04/09 15:26:01 zarq Exp $
*/
#ifndef __TINC_SUBNET_H__
#define __TINC_SUBNET_H__
#include "net.h"
enum
{
SUBNET_MAC = 0,
SUBNET_IPV4,
SUBNET_IPV6,
SUBNET_TYPES /* Guardian */
};
typedef struct subnet_mac_t
{
mac_t address;
time_t lastseen;
} subnet_mac_t;
typedef struct subnet_ipv4_t
{
ipv4_t address;
int prefixlength;
} subnet_ipv4_t;
typedef struct subnet_ipv6_t
{
ipv6_t address;
int prefixlength;
} subnet_ipv6_t;
#include "node.h"
typedef struct subnet_t {
struct node_t *owner; /* the owner of this subnet */
struct node_t *uplink; /* the uplink which we should send packets to for this subnet */
int type; /* subnet type (IPv4? IPv6? MAC? something even weirder?) */
/* And now for the actual subnet: */
union net
{
subnet_mac_t mac;
subnet_ipv4_t ipv4;
subnet_ipv6_t ipv6;
} net;
} subnet_t;
extern subnet_t *new_subnet(void);
extern void free_subnet(subnet_t *);
extern void init_subnets(void);
extern void exit_subnets(void);
extern avl_tree_t *new_subnet_tree(void);
extern void free_subnet_tree(avl_tree_t *);
extern void subnet_add(struct node_t *, subnet_t *);
extern void subnet_del(struct node_t *, subnet_t *);
extern char *net2str(subnet_t *);
extern subnet_t *str2net(char *);
extern subnet_t *lookup_subnet(struct node_t *, subnet_t *);
extern subnet_t *lookup_subnet_mac(mac_t *);
extern subnet_t *lookup_subnet_ipv4(ipv4_t *);
extern subnet_t *lookup_subnet_ipv6(ipv6_t *);
extern void dump_subnets(void);
#endif /* __TINC_SUBNET_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));