Initial revision
This commit is contained in:
commit
1243156a5e
87 changed files with 27214 additions and 0 deletions
19
src/Makefile.am
Normal file
19
src/Makefile.am
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
## Produce this file with automake to get Makefile.in
|
||||
|
||||
sbin_PROGRAMS = tincd genauth
|
||||
|
||||
genauth_SOURCES = genauth.c
|
||||
tincd_SOURCES = conf.c encr.c net.c netutl.c protocol.c tincd.c
|
||||
|
||||
INCLUDES = -I$(top_builddir) -I$(top_srcdir)/cipher -I$(top_srcdir)/lib
|
||||
|
||||
noinst_HEADERS = conf.h encr.h net.h netutl.h protocol.h
|
||||
|
||||
LIBS = @LIBS@
|
||||
|
||||
tincd_LDADD = $(top_builddir)/cipher/libcipher.la \
|
||||
$(top_builddir)/lib/libvpn.a -ldl
|
||||
|
||||
genauth_LDADD = $(top_builddir)/lib/libvpn.a
|
||||
|
||||
CFLAGS += -DPKGLIBDIR=$(pkglibdir) -DCONFDIR=\"@sysconfdir@\"
|
||||
203
src/conf.c
Normal file
203
src/conf.c
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
conf.c -- configuration code
|
||||
Copyright (C) 1998 Emphyrio,
|
||||
Copyright (C) 1998,99 Ivo Timmermans <zarq@iname.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.
|
||||
*/
|
||||
|
||||
/* foute config read code, GPL, emphyrio 1998 */
|
||||
/* Mutilated by me -- Ivo */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <xalloc.h>
|
||||
|
||||
#include "conf.h"
|
||||
#include "netutl.h" /* for strtoip */
|
||||
|
||||
config_t *config;
|
||||
int debug_lvl = 0;
|
||||
int timeout = 0; /* seconds before timeout */
|
||||
|
||||
typedef struct internal_config_t {
|
||||
char *name;
|
||||
enum which_t which;
|
||||
int argtype;
|
||||
} internal_config_t;
|
||||
|
||||
/*
|
||||
These are all the possible configurable values
|
||||
*/
|
||||
static internal_config_t hazahaza[] = {
|
||||
{ "AllowConnect", allowconnect, TYPE_BOOL },
|
||||
{ "ConnectTo", upstreamip, TYPE_IP },
|
||||
{ "ConnectPort", upstreamport, TYPE_INT },
|
||||
{ "ListenPort", listenport, TYPE_INT },
|
||||
{ "MyOwnVPNIP", myvpnip, TYPE_IP },
|
||||
{ "MyVirtualIP", myvpnip, TYPE_IP }, /* an alias */
|
||||
{ "Passphrases", passphrasesdir, TYPE_NAME },
|
||||
{ "PingTimeout", pingtimeout, TYPE_INT },
|
||||
{ "TapDevice", tapdevice, TYPE_NAME },
|
||||
{ "KeyExpire", keyexpire, TYPE_INT },
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
Add given value to the list of configs cfg
|
||||
*/
|
||||
config_t *
|
||||
add_config_val(config_t **cfg, int argtype, char *val)
|
||||
{
|
||||
config_t *p;
|
||||
char *q;
|
||||
|
||||
p = (config_t*)xmalloc(sizeof(config_t));
|
||||
p->data.val = 0;
|
||||
|
||||
switch(argtype)
|
||||
{
|
||||
case TYPE_INT:
|
||||
p->data.val = strtol(val, &q, 0);
|
||||
if(q && *q)
|
||||
p->data.val = 0;
|
||||
break;
|
||||
case TYPE_NAME:
|
||||
p->data.ptr = xmalloc(strlen(val) + 1);
|
||||
strcpy(p->data.ptr, val);
|
||||
break;
|
||||
case TYPE_IP:
|
||||
p->data.ip = strtoip(val);
|
||||
break;
|
||||
case TYPE_BOOL:
|
||||
if(!strcasecmp("yes", val))
|
||||
p->data.val = stupid_true;
|
||||
else if(!strcasecmp("no", val))
|
||||
p->data.val = stupid_false;
|
||||
else
|
||||
p->data.val = 0;
|
||||
}
|
||||
|
||||
if(p->data.val)
|
||||
{
|
||||
p->next = *cfg;
|
||||
*cfg = p;
|
||||
return p;
|
||||
}
|
||||
|
||||
free(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
Get variable from a section in a configfile. returns -1 on failure.
|
||||
*/
|
||||
int
|
||||
readconfig(const char *fname, FILE *fp)
|
||||
{
|
||||
char line[81];
|
||||
char *p, *q;
|
||||
int i, lineno = 0;
|
||||
config_t *cfg;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
if(fgets(line, 80, fp) == NULL)
|
||||
return 0;
|
||||
lineno++;
|
||||
|
||||
if((p = strtok(line, "\t\n\r =")) == NULL)
|
||||
continue; /* no tokens on this line */
|
||||
|
||||
if(p[0] == '#')
|
||||
continue; /* comment: ignore */
|
||||
|
||||
for(i = 0; hazahaza[i].name != NULL; i++)
|
||||
if(!strcasecmp(hazahaza[i].name, p))
|
||||
break;
|
||||
|
||||
if(!hazahaza[i].name)
|
||||
{
|
||||
fprintf(stderr, "%s: %d: Invalid variable name `%s'.\n",
|
||||
fname, lineno, p);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(((q = strtok(NULL, "\t\n\r =")) == NULL) || q[0] == '#')
|
||||
{
|
||||
fprintf(stderr, "%s: %d: No value given for `%s'.\n",
|
||||
fname, lineno, hazahaza[i].name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cfg = add_config_val(&config, hazahaza[i].argtype, q);
|
||||
if(cfg == NULL)
|
||||
{
|
||||
fprintf(stderr, "%s: %d: Invalid value `%s' for variable `%s'.\n",
|
||||
fname, lineno, q, hazahaza[i].name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cfg->which = hazahaza[i].which;
|
||||
if(!config)
|
||||
config = cfg;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
wrapper function for readconfig
|
||||
*/
|
||||
int
|
||||
read_config_file(const char *fname)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
if((fp = fopen (fname, "r")) == NULL)
|
||||
{
|
||||
fprintf(stderr, "Could not open %s: %s\n", fname, sys_errlist[errno]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(readconfig(fname, fp))
|
||||
return -1;
|
||||
|
||||
fclose (fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Look up the value of the config option type
|
||||
*/
|
||||
const config_t *
|
||||
get_config_val(which_t type)
|
||||
{
|
||||
config_t *p;
|
||||
|
||||
for(p = config; p != NULL; p = p->next)
|
||||
if(p->which == type)
|
||||
return p;
|
||||
|
||||
/* Not found */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
72
src/conf.h
Normal file
72
src/conf.h
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
conf.h -- header for conf.c
|
||||
Copyright (C) 1998,99 Ivo Timmermans <zarq@iname.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.
|
||||
*/
|
||||
|
||||
#ifndef __TINC_CONF_H__
|
||||
#define __TINC_CONF_H__
|
||||
|
||||
typedef struct ip_mask_t {
|
||||
unsigned long ip;
|
||||
unsigned long mask;
|
||||
} ip_mask_t;
|
||||
|
||||
typedef union data_t {
|
||||
unsigned long val;
|
||||
void *ptr;
|
||||
ip_mask_t *ip;
|
||||
} data_t;
|
||||
|
||||
typedef enum which_t {
|
||||
passphrasesdir = 1,
|
||||
upstreamip,
|
||||
upstreamport,
|
||||
listenport,
|
||||
myvpnip,
|
||||
tapdevice,
|
||||
allowconnect,
|
||||
pingtimeout,
|
||||
keyexpire,
|
||||
} which_t;
|
||||
|
||||
typedef struct config_t {
|
||||
struct config_t *next;
|
||||
which_t which;
|
||||
data_t data;
|
||||
} config_t;
|
||||
|
||||
enum {
|
||||
stupid_false = 1,
|
||||
stupid_true
|
||||
};
|
||||
|
||||
enum {
|
||||
TYPE_NAME = 1,
|
||||
TYPE_INT,
|
||||
TYPE_IP,
|
||||
TYPE_BOOL
|
||||
};
|
||||
|
||||
extern config_t *config;
|
||||
extern int debug_lvl;
|
||||
extern int timeout;
|
||||
|
||||
extern config_t *add_config_val(config_t **, int, char *);
|
||||
extern int read_config_file(const char *);
|
||||
extern const config_t *get_config_val(which_t type);
|
||||
|
||||
#endif /* __TINC_CONF_H__ */
|
||||
325
src/encr.c
Normal file
325
src/encr.c
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
/*
|
||||
encr.c -- everything that deals with encryption
|
||||
Copyright (C) 1998,99 Ivo Timmermans <zarq@iname.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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifdef HAVE_GMP_H
|
||||
# include <gmp.h>
|
||||
#else
|
||||
# ifdef HAVE_GMP2_GMP_H
|
||||
# include <gmp2/gmp.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <utils.h>
|
||||
#include <xalloc.h>
|
||||
|
||||
#include <cipher.h>
|
||||
|
||||
#include "conf.h"
|
||||
#include "encr.h"
|
||||
#include "net.h"
|
||||
#include "protocol.h"
|
||||
|
||||
#define ENCR_GENERATOR "0xd"
|
||||
#define ENCR_PRIME "0x7fffffffffffffffffffffffffffffff" /* Mersenne :) */
|
||||
|
||||
char text_key[1000];
|
||||
char *my_public_key_base36;
|
||||
int key_inited = 0, encryption_keylen;
|
||||
mpz_t my_private_key, my_public_key, generator, shared_prime;
|
||||
int my_key_expiry = (time_t)(-1);
|
||||
|
||||
static char* mypassphrase;
|
||||
static int mypassphraselen;
|
||||
|
||||
int char_hex_to_bin(int c)
|
||||
{
|
||||
if(isdigit(c))
|
||||
return c - '0';
|
||||
else
|
||||
return tolower(c) - 'a' + 10;
|
||||
}
|
||||
|
||||
int str_hex_to_bin(unsigned char *bin, unsigned char *hex)
|
||||
{
|
||||
int i = 0, j = 0, l = strlen(hex);
|
||||
|
||||
if(l&1)
|
||||
{
|
||||
i = j = 1;
|
||||
bin[0] = char_hex_to_bin(hex[0]);
|
||||
}
|
||||
for(; i < l; i+=2, j++)
|
||||
bin[j] = (char_hex_to_bin(hex[i]) << 4) + char_hex_to_bin(hex[i+1]);
|
||||
|
||||
return j&1?j+1:j;
|
||||
}
|
||||
|
||||
int read_passphrase(char *which, char **out)
|
||||
{
|
||||
FILE *f;
|
||||
config_t const *cfg;
|
||||
char *filename;
|
||||
int size;
|
||||
extern char *confbase;
|
||||
char *pp;
|
||||
|
||||
if((cfg = get_config_val(passphrasesdir)) == NULL)
|
||||
{
|
||||
filename = xmalloc(strlen(confbase)+13+strlen(which));
|
||||
sprintf(filename, "%spassphrases/%s", confbase, which);
|
||||
}
|
||||
else
|
||||
{
|
||||
filename = xmalloc(strlen(cfg->data.ptr)+2+strlen(which));
|
||||
sprintf(filename, "%s/%s", (char*)cfg->data.ptr, which);
|
||||
}
|
||||
|
||||
if((f = fopen(filename, "rb")) == NULL)
|
||||
{
|
||||
syslog(LOG_ERR, "Could not open %s: %m", filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fscanf(f, "%d ", &size);
|
||||
size >>= 2; /* nibbles->bits */
|
||||
pp = xmalloc(size+2);
|
||||
fgets(pp, size+1, f);
|
||||
fclose(f);
|
||||
|
||||
*out = xmalloc(size);
|
||||
return str_hex_to_bin(*out, pp);
|
||||
}
|
||||
|
||||
int read_my_passphrase(void)
|
||||
{
|
||||
if((mypassphraselen = read_passphrase("local", &mypassphrase)) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int generate_private_key(void)
|
||||
{
|
||||
FILE *f;
|
||||
int i;
|
||||
char *s;
|
||||
config_t const *cfg;
|
||||
|
||||
if((cfg = get_config_val(keyexpire)) == NULL)
|
||||
my_key_expiry = (time_t)(time(NULL) + 3600);
|
||||
else
|
||||
my_key_expiry = (time_t)(time(NULL) + cfg->data.val);
|
||||
|
||||
syslog(LOG_NOTICE, "Generating %d bits keys.", PRIVATE_KEY_BITS);
|
||||
|
||||
if((f = fopen("/dev/urandom", "r")) == NULL)
|
||||
{
|
||||
syslog(LOG_ERR, "Opening /dev/urandom failed: %m");
|
||||
return -1;
|
||||
}
|
||||
|
||||
s = xmalloc((2 * PRIVATE_KEY_LENGTH) + 1);
|
||||
|
||||
for(i = 0; i < PRIVATE_KEY_LENGTH; i++)
|
||||
sprintf(&s[i << 1], "%02x", fgetc(f));
|
||||
|
||||
s[2 * PRIVATE_KEY_LENGTH] = '\0';
|
||||
|
||||
mpz_set_str(my_private_key, s, 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void calculate_public_key(void)
|
||||
{
|
||||
mpz_powm(my_public_key, generator, my_private_key, shared_prime);
|
||||
my_public_key_base36 = mpz_get_str(NULL, 36, my_public_key);
|
||||
}
|
||||
|
||||
unsigned char static_key[] = { 0x9c, 0xbf, 0x36, 0xa9, 0xce, 0x20, 0x1b, 0x8b, 0x67, 0x56, 0x21, 0x5d, 0x27, 0x1b, 0xd8, 0x7a };
|
||||
|
||||
int security_init(void)
|
||||
{
|
||||
mpz_init(my_private_key);
|
||||
mpz_init(my_public_key);
|
||||
mpz_init_set_str(shared_prime, ENCR_PRIME, 0);
|
||||
mpz_init_set_str(generator, ENCR_GENERATOR, 0);
|
||||
|
||||
if(read_my_passphrase() < 0)
|
||||
return -1;
|
||||
if(generate_private_key() < 0)
|
||||
return -1;
|
||||
|
||||
if(cipher_init(CIPHER_BLOWFISH) < 0)
|
||||
return -1;
|
||||
|
||||
calculate_public_key();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void set_shared_key(char *almost_key)
|
||||
{
|
||||
char *tmp;
|
||||
int len;
|
||||
mpz_t ak, our_shared_key;
|
||||
|
||||
mpz_init_set_str(ak, almost_key, 36);
|
||||
mpz_init(our_shared_key);
|
||||
mpz_powm(our_shared_key, ak, my_private_key, shared_prime);
|
||||
|
||||
tmp = mpz_get_str(NULL, 16, our_shared_key);
|
||||
len = str_hex_to_bin(text_key, tmp);
|
||||
|
||||
cipher_set_key(&encryption_key, len, &text_key[0]);
|
||||
key_inited = 1;
|
||||
encryption_keylen = len;
|
||||
|
||||
if(debug_lvl > 2)
|
||||
syslog(LOG_INFO, "Encryption key set to %s", tmp);
|
||||
|
||||
free(tmp);
|
||||
mpz_clear(ak);
|
||||
mpz_clear(our_shared_key);
|
||||
}
|
||||
|
||||
|
||||
void encrypt_passphrase(passphrase_t *pp)
|
||||
{
|
||||
char key[1000];
|
||||
char tmp[1000];
|
||||
int len;
|
||||
BF_KEY bf_key;
|
||||
|
||||
mpz_get_str(&tmp[0], 16, my_public_key);
|
||||
len = str_hex_to_bin(key, tmp);
|
||||
|
||||
cipher_set_key(&bf_key, len, &key[0]);
|
||||
|
||||
low_crypt_key(mypassphrase, pp->phrase, &bf_key, mypassphraselen, BF_ENCRYPT);
|
||||
pp->len = ((mypassphraselen - 1) | 7) + 5;
|
||||
|
||||
if(key_inited)
|
||||
cipher_set_key(&encryption_key, encryption_keylen, &text_key[0]);
|
||||
}
|
||||
|
||||
int verify_passphrase(conn_list_t *cl, unsigned char *his_pubkey)
|
||||
{
|
||||
char key[1000];
|
||||
char tmp[1000];
|
||||
int len;
|
||||
mpz_t pk;
|
||||
unsigned char *out;
|
||||
BF_KEY bf_key;
|
||||
char which[sizeof("123.123.123.123")+1];
|
||||
char *meuk;
|
||||
|
||||
mpz_init_set_str(pk, his_pubkey, 36);
|
||||
mpz_get_str(&tmp[0], 16, pk);
|
||||
len = str_hex_to_bin(key, tmp);
|
||||
out = xmalloc(cl->pp->len+3);
|
||||
|
||||
cipher_set_key(&bf_key, len, &key[0]);
|
||||
low_crypt_key(cl->pp->phrase, out, &bf_key, cl->pp->len, BF_DECRYPT);
|
||||
if(key_inited)
|
||||
cipher_set_key(&encryption_key, encryption_keylen, &text_key[0]);
|
||||
|
||||
sprintf(&which[0], IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
|
||||
if((len = read_passphrase(which, &meuk)) < 0)
|
||||
return -1;
|
||||
|
||||
if(memcmp(meuk, out, len))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *make_shared_key(char *pk)
|
||||
{
|
||||
mpz_t tmp, res;
|
||||
char *r;
|
||||
|
||||
mpz_init_set_str(tmp, pk, 36);
|
||||
mpz_init(res);
|
||||
mpz_powm(res, tmp, my_private_key, shared_prime);
|
||||
|
||||
r = mpz_get_str(NULL, 36, res);
|
||||
|
||||
mpz_clear(res);
|
||||
mpz_clear(tmp);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
free a key after overwriting it
|
||||
*/
|
||||
void free_key(enc_key_t *k)
|
||||
{
|
||||
if(!k)
|
||||
return;
|
||||
if(k->key)
|
||||
{
|
||||
memset(k->key, (char)(-1), k->length);
|
||||
free(k->key);
|
||||
}
|
||||
free(k);
|
||||
}
|
||||
|
||||
void recalculate_encryption_keys(void)
|
||||
{
|
||||
conn_list_t *p;
|
||||
char *ek;
|
||||
|
||||
for(p = conn_list; p != NULL; p = p->next)
|
||||
{
|
||||
if(!p->public_key || !p->public_key->key)
|
||||
continue;
|
||||
ek = make_shared_key(p->public_key->key);
|
||||
if(!p->key)
|
||||
{
|
||||
p->key = xmalloc(sizeof(enc_key_t));
|
||||
p->key->key = NULL;
|
||||
}
|
||||
if(p->key->key)
|
||||
free(p->key->key);
|
||||
p->key->length = strlen(ek);
|
||||
p->key->expiry = p->public_key->expiry;
|
||||
p->key->key = xmalloc(strlen(ek) + 1);
|
||||
strcpy(p->key->key, ek);
|
||||
}
|
||||
}
|
||||
|
||||
void regenerate_keys(void)
|
||||
{
|
||||
generate_private_key();
|
||||
calculate_public_key();
|
||||
send_key_changed2();
|
||||
recalculate_encryption_keys();
|
||||
}
|
||||
47
src/encr.h
Normal file
47
src/encr.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
encr.h -- header for encr.c
|
||||
Copyright (C) 1998,99 Ivo Timmermans <zarq@iname.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.
|
||||
*/
|
||||
|
||||
#ifndef __TINC_ENCR_H__
|
||||
#define __TINC_ENCR_H__
|
||||
|
||||
#include "net.h"
|
||||
|
||||
#define PRIVATE_KEY_BITS 128
|
||||
#define PRIVATE_KEY_LENGTH (PRIVATE_KEY_BITS >> 3)
|
||||
|
||||
extern char *my_public_key_base36;
|
||||
extern int my_key_expiry;
|
||||
|
||||
extern int security_init(void);
|
||||
|
||||
extern void do_bf_encrypt(vpn_packet_t *, real_packet_t *);
|
||||
extern void do_bf_decrypt(real_packet_t *, vpn_packet_t *);
|
||||
|
||||
extern int send_portnumbers(int);
|
||||
extern void set_shared_key(char *);
|
||||
extern int send_passphrase(conn_list_t *);
|
||||
extern int send_public_key(conn_list_t *);
|
||||
extern int verify_passphrase(conn_list_t *, unsigned char *);
|
||||
extern char *make_shared_key(char*);
|
||||
extern void encrypt_passphrase(passphrase_t *pp);
|
||||
extern void free_key(enc_key_t*);
|
||||
extern void regenerate_keys(void);
|
||||
|
||||
#endif /* __TINC_ENCR_H__ */
|
||||
|
||||
94
src/genauth.c
Normal file
94
src/genauth.c
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
genauth.c -- generate a random passphrase
|
||||
Copyright (C) 1998,99 Ivo Timmermans <zarq@iname.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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <xalloc.h>
|
||||
|
||||
#include "encr.h"
|
||||
|
||||
unsigned char initvec[] = { 0x22, 0x7b, 0xad, 0x55, 0x41, 0xf4, 0x3e, 0xf3 };
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
FILE *fp;
|
||||
int bits, c, i, bytes;
|
||||
unsigned char *p;
|
||||
|
||||
if(argc != 2)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s bits\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(!(bits = atol(argv[1])))
|
||||
{
|
||||
fprintf(stderr, "Illegal number: %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bits = ((bits - 1) | 63) + 1;
|
||||
fprintf(stderr, "Generating %d bits number", bits);
|
||||
bytes = bits >> 3;
|
||||
|
||||
if((fp = fopen("/dev/urandom", "r")) == NULL)
|
||||
{
|
||||
perror("Opening /dev/urandom");
|
||||
return 1;
|
||||
}
|
||||
|
||||
p = xmalloc(bytes);
|
||||
|
||||
setbuf(stdout, NULL);
|
||||
for(i = 0; i < 128; i++)
|
||||
{
|
||||
c = fgetc(fp);
|
||||
if(feof(fp))
|
||||
{
|
||||
puts("");
|
||||
fprintf(stderr, "File was empty!\n");
|
||||
}
|
||||
p[i] = c;
|
||||
}
|
||||
|
||||
for(i = 0; i < (bytes); i++)
|
||||
{
|
||||
c = fgetc(fp);
|
||||
if(feof(fp))
|
||||
{
|
||||
puts("");
|
||||
fprintf(stderr, "File was empty!\n");
|
||||
}
|
||||
p[i] = c;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
printf("%d ", bits);
|
||||
for(i = 0; i < bytes; i++)
|
||||
printf("%02x", p[i]);
|
||||
puts("");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
139
src/net.h
Normal file
139
src/net.h
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
net.h -- header for net.c
|
||||
Copyright (C) 1998,99 Ivo Timmermans <zarq@iname.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.
|
||||
*/
|
||||
|
||||
#ifndef __TINC_NET_H__
|
||||
#define __TINC_NET_H__
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "conf.h"
|
||||
|
||||
#define MAXSIZE 1700 /* should be a bit more than the MTU for the tapdevice */
|
||||
#define MTU 1600
|
||||
|
||||
#define MAX_PASSPHRASE_SIZE 2000 /* 2kb is really waaaay too much. nobody's
|
||||
gonna need a 16 kbit passphrase */
|
||||
|
||||
#define MAC_ADDR_S "%02x:%02x:%02x:%02x:%02x:%02x"
|
||||
#define MAC_ADDR_V(x) ((unsigned char*)&(x))[0],((unsigned char*)&(x))[1], \
|
||||
((unsigned char*)&(x))[2],((unsigned char*)&(x))[3], \
|
||||
((unsigned char*)&(x))[4],((unsigned char*)&(x))[5]
|
||||
|
||||
#define IP_ADDR_S "%d.%d.%d.%d"
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
# define IP_ADDR_V(x) ((unsigned char*)&(x))[0],((unsigned char*)&(x))[1], \
|
||||
((unsigned char*)&(x))[2],((unsigned char*)&(x))[3]
|
||||
#else
|
||||
# define IP_ADDR_V(x) ((unsigned char*)&(x))[3],((unsigned char*)&(x))[2], \
|
||||
((unsigned char*)&(x))[1],((unsigned char*)&(x))[0]
|
||||
#endif
|
||||
|
||||
typedef unsigned long ip_t;
|
||||
typedef short length_t;
|
||||
|
||||
typedef struct vpn_packet_t {
|
||||
length_t len; /* the actual number of bytes in the `data' field */
|
||||
unsigned char data[MAXSIZE];
|
||||
} vpn_packet_t;
|
||||
|
||||
typedef struct real_packet_t {
|
||||
length_t len; /* the length of the entire packet */
|
||||
ip_t from; /* where the packet came from */
|
||||
vpn_packet_t data; /* encrypted vpn_packet_t */
|
||||
} real_packet_t;
|
||||
|
||||
typedef struct passphrase_t {
|
||||
unsigned char type;
|
||||
unsigned short len;
|
||||
unsigned char phrase[MAX_PASSPHRASE_SIZE];
|
||||
} passphrase_t;
|
||||
|
||||
typedef struct status_bits_t {
|
||||
int pinged:1; /* sent ping */
|
||||
int got_pong:1; /* received pong */
|
||||
int meta:1; /* meta connection exists */
|
||||
int active:1; /* 1 if active.. */
|
||||
int outgoing:1; /* I myself asked for this conn */
|
||||
int termreq:1; /* the termination of this connection was requested */
|
||||
int remove:1; /* Set to 1 if you want this connection removed */
|
||||
int timeout:1; /* 1 if gotten timeout */
|
||||
int validkey:1; /* 1 if we currently have a valid key for him */
|
||||
int waitingforkey:1; /* 1 if we already sent out a request */
|
||||
int dataopen:1; /* 1 if we have a valid UDP connection open */
|
||||
int unused:22;
|
||||
} status_bits_t;
|
||||
|
||||
typedef struct queue_element_t {
|
||||
void *packet;
|
||||
struct queue_element_t *next;
|
||||
} queue_element_t;
|
||||
|
||||
typedef struct packet_queue_t {
|
||||
queue_element_t *head;
|
||||
queue_element_t *tail;
|
||||
} packet_queue_t;
|
||||
|
||||
typedef struct enc_key_t {
|
||||
int length;
|
||||
char *key;
|
||||
time_t expiry;
|
||||
} enc_key_t;
|
||||
|
||||
typedef struct conn_list_t {
|
||||
ip_t vpn_ip; /* his vpn ip */
|
||||
ip_t vpn_mask; /* his vpn network address */
|
||||
ip_t real_ip; /* his real (internet) ip */
|
||||
char *hostname; /* the hostname of its real ip */
|
||||
short int port; /* his portnumber */
|
||||
int socket; /* our udp vpn socket */
|
||||
int meta_socket; /* our tcp meta socket */
|
||||
unsigned char protocol_version; /* used protocol */
|
||||
status_bits_t status; /* status info */
|
||||
passphrase_t *pp; /* encoded passphrase */
|
||||
packet_queue_t *sq; /* pending outgoing packets */
|
||||
packet_queue_t *rq; /* pending incoming packets (they have no
|
||||
valid key to be decrypted with) */
|
||||
enc_key_t *public_key; /* the other party's public key */
|
||||
enc_key_t *key; /* encrypt with this key */
|
||||
struct conn_list_t *nexthop; /* nearest meta-hop in this direction */
|
||||
struct conn_list_t *next; /* after all, it's a list of connections */
|
||||
} conn_list_t;
|
||||
|
||||
extern int tap_fd;
|
||||
|
||||
extern int total_tap_in;
|
||||
extern int total_tap_out;
|
||||
extern int total_socket_in;
|
||||
extern int total_socket_out;
|
||||
|
||||
extern conn_list_t *conn_list;
|
||||
extern conn_list_t *myself;
|
||||
|
||||
extern int send_packet(ip_t, vpn_packet_t *);
|
||||
extern int send_broadcast(conn_list_t *, vpn_packet_t *);
|
||||
extern int setup_network_connections(void);
|
||||
extern void close_network_connections(void);
|
||||
extern void main_loop(void);
|
||||
extern int setup_vpn_connection(conn_list_t *);
|
||||
extern void terminate_connection(conn_list_t *);
|
||||
extern void flush_queues(conn_list_t*);
|
||||
|
||||
#endif /* __TINC_NET_H__ */
|
||||
232
src/netutl.c
Normal file
232
src/netutl.c
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
netutl.c -- some supporting network utility code
|
||||
Copyright (C) 1998,99 Ivo Timmermans <zarq@iname.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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include <utils.h>
|
||||
#include <xalloc.h>
|
||||
|
||||
#include "encr.h"
|
||||
#include "net.h"
|
||||
#include "netutl.h"
|
||||
|
||||
/*
|
||||
look for a connection associated with the given vpn ip,
|
||||
return its connection structure
|
||||
*/
|
||||
conn_list_t *lookup_conn(ip_t ip)
|
||||
{
|
||||
conn_list_t *p = conn_list;
|
||||
|
||||
/* Exact match suggested by James B. MacLean */
|
||||
for(p = conn_list; p != NULL; p = p->next)
|
||||
if(ip == p->vpn_ip)
|
||||
return p;
|
||||
for(p = conn_list; p != NULL; p = p->next)
|
||||
if((ip & p->vpn_mask) == (p->vpn_ip & p->vpn_mask))
|
||||
return p;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
free a queue and all of its elements
|
||||
*/
|
||||
void destroy_queue(packet_queue_t *pq)
|
||||
{
|
||||
queue_element_t *p, *q;
|
||||
|
||||
for(p = pq->head; p != NULL; p = q)
|
||||
{
|
||||
q = p->next;
|
||||
if(p->packet)
|
||||
free(p->packet);
|
||||
free(p);
|
||||
}
|
||||
|
||||
free(pq);
|
||||
}
|
||||
|
||||
/*
|
||||
free a conn_list_t element and all its pointers
|
||||
*/
|
||||
void free_conn_element(conn_list_t *p)
|
||||
{
|
||||
if(p->hostname)
|
||||
free(p->hostname);
|
||||
if(p->pp)
|
||||
free(p->pp);
|
||||
if(p->sq)
|
||||
destroy_queue(p->sq);
|
||||
if(p->rq)
|
||||
destroy_queue(p->rq);
|
||||
free_key(p->public_key);
|
||||
free_key(p->key);
|
||||
free(p);
|
||||
}
|
||||
|
||||
/*
|
||||
remove all marked connections
|
||||
*/
|
||||
void prune_conn_list(void)
|
||||
{
|
||||
conn_list_t *p, *prev = NULL, *next = NULL;
|
||||
|
||||
for(p = conn_list; p != NULL; )
|
||||
{
|
||||
next = p->next;
|
||||
|
||||
if(p->status.remove)
|
||||
{
|
||||
if(prev)
|
||||
prev->next = next;
|
||||
else
|
||||
conn_list = next;
|
||||
|
||||
free_conn_element(p);
|
||||
}
|
||||
else
|
||||
prev = p;
|
||||
|
||||
p = next;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
creates new conn_list element, and initializes it
|
||||
*/
|
||||
conn_list_t *new_conn_list(void)
|
||||
{
|
||||
conn_list_t *p = xmalloc(sizeof(conn_list_t));
|
||||
|
||||
/* initialise all those stupid pointers at once */
|
||||
memset(p, '\0', sizeof(conn_list_t));
|
||||
p->nexthop = p;
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
free all elements of conn_list
|
||||
*/
|
||||
void destroy_conn_list(void)
|
||||
{
|
||||
conn_list_t *p, *next;
|
||||
cp
|
||||
|
||||
for(p = conn_list; p != NULL; )
|
||||
{
|
||||
next = p->next;
|
||||
free_conn_element(p);
|
||||
p = next;
|
||||
}
|
||||
cp
|
||||
|
||||
conn_list = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
look up the name associated with the ip
|
||||
address `addr'
|
||||
*/
|
||||
char *hostlookup(unsigned long addr)
|
||||
{
|
||||
char *name;
|
||||
struct hostent *host = NULL;
|
||||
struct in_addr in;
|
||||
|
||||
in.s_addr = addr;
|
||||
|
||||
host = gethostbyaddr((char *)&in, sizeof(in), AF_INET);
|
||||
|
||||
if(host)
|
||||
{
|
||||
name = xmalloc(strlen(host->h_name)+20);
|
||||
sprintf(name, "%s (%s)", host->h_name, inet_ntoa(in));
|
||||
}
|
||||
else
|
||||
{
|
||||
name = xmalloc(20);
|
||||
sprintf(name, "%s", inet_ntoa(in));
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/*
|
||||
Turn a string into an IP addy with netmask
|
||||
return NULL on failure
|
||||
*/
|
||||
ip_mask_t *strtoip(char *str)
|
||||
{
|
||||
ip_mask_t *ip;
|
||||
int masker;
|
||||
char *q, *p;
|
||||
struct hostent *h;
|
||||
|
||||
p = str;
|
||||
if((q = strchr(p, '/')))
|
||||
{
|
||||
*q = '\0';
|
||||
q++; /* q now points to netmask part, or NULL if no mask */
|
||||
}
|
||||
|
||||
if(!(h = gethostbyname(p)))
|
||||
{
|
||||
fprintf(stderr, "Error looking up `%s': %s\n", p, sys_errlist[h_errno]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
masker = 0;
|
||||
if(q)
|
||||
{
|
||||
masker = strtol(q, &p, 10);
|
||||
if(q == p || (*p))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ip = xmalloc(sizeof(ip_mask_t));
|
||||
ip->ip = ntohl(*((ip_t*)(h->h_addr_list[0])));
|
||||
|
||||
ip->mask = masker ? ~((1 << (32 - masker)) - 1) : 0;
|
||||
|
||||
return ip;
|
||||
}
|
||||
|
||||
void dump_conn_list(void)
|
||||
{
|
||||
conn_list_t *p;
|
||||
|
||||
syslog(LOG_DEBUG, "Connection list:");
|
||||
|
||||
for(p = conn_list; p != NULL; p = p->next)
|
||||
{
|
||||
syslog(LOG_DEBUG, " " IP_ADDR_S "/" IP_ADDR_S ": %04x (%d|%d)",
|
||||
IP_ADDR_V(p->vpn_ip), IP_ADDR_V(p->vpn_mask), p->status,
|
||||
p->socket, p->meta_socket);
|
||||
}
|
||||
}
|
||||
35
src/netutl.h
Normal file
35
src/netutl.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
netutl.h -- header file for netutl.c
|
||||
Copyright (C) 1998,99 Ivo Timmermans <zarq@iname.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.
|
||||
*/
|
||||
|
||||
#ifndef __TINC_NETUTL_H__
|
||||
#define __TINC_NETUTL_H__
|
||||
|
||||
#include "net.h"
|
||||
|
||||
extern conn_list_t *lookup_conn(ip_t);
|
||||
extern void free_conn_element(conn_list_t *);
|
||||
extern void free_conn_list(conn_list_t*);
|
||||
extern void prune_conn_list(void);
|
||||
extern conn_list_t *new_conn_list(void);
|
||||
extern void destroy_conn_list(void);
|
||||
extern char *hostlookup(unsigned long);
|
||||
extern ip_mask_t *strtoip(char*);
|
||||
extern void dump_conn_list(void);
|
||||
|
||||
#endif /* __TINC_NETUTL_H__ */
|
||||
739
src/protocol.c
Normal file
739
src/protocol.c
Normal file
|
|
@ -0,0 +1,739 @@
|
|||
/*
|
||||
protocol.c -- handle the meta-protocol
|
||||
Copyright (C) 1999 Ivo Timmermans <zarq@iname.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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <utils.h>
|
||||
#include <xalloc.h>
|
||||
|
||||
#include "conf.h"
|
||||
#include "encr.h"
|
||||
#include "net.h"
|
||||
#include "netutl.h"
|
||||
#include "protocol.h"
|
||||
|
||||
int send_ack(conn_list_t *cl)
|
||||
{
|
||||
unsigned char tmp = ACK;
|
||||
|
||||
if(debug_lvl > 2)
|
||||
syslog(LOG_DEBUG, "Send ACK to %s", cl->hostname);
|
||||
|
||||
syslog(LOG_NOTICE, "Connection with %s activated.", cl->hostname);
|
||||
if((send(cl->meta_socket, &tmp, sizeof(tmp), 0)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "send failed: %d:%d: %m", __FILE__, __LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int send_termreq(conn_list_t *cl)
|
||||
{
|
||||
termreq_t tmp;
|
||||
|
||||
tmp.type = TERMREQ;
|
||||
tmp.vpn_ip = myself->vpn_ip;
|
||||
|
||||
if(debug_lvl > 2)
|
||||
syslog(LOG_DEBUG, "Send TERMREQ(" IP_ADDR_S ") to " IP_ADDR_S, IP_ADDR_V(tmp.vpn_ip),
|
||||
IP_ADDR_V(cl->vpn_ip));
|
||||
|
||||
if((send(cl->meta_socket, &tmp, sizeof(tmp), 0)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int send_timeout(conn_list_t *cl)
|
||||
{
|
||||
termreq_t tmp;
|
||||
|
||||
tmp.type = PINGTIMEOUT;
|
||||
tmp.vpn_ip = myself->vpn_ip;
|
||||
|
||||
if(debug_lvl > 2)
|
||||
syslog(LOG_DEBUG, "Send TIMEOUT(" IP_ADDR_S ") to " IP_ADDR_S, IP_ADDR_V(tmp.vpn_ip),
|
||||
IP_ADDR_V(cl->vpn_ip));
|
||||
|
||||
if((send(cl->meta_socket, &tmp, sizeof(tmp), 0)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int send_del_host(conn_list_t *cl, conn_list_t *new_host)
|
||||
{
|
||||
del_host_t tmp;
|
||||
|
||||
tmp.type = DEL_HOST;
|
||||
tmp.vpn_ip = new_host->vpn_ip;
|
||||
|
||||
if(debug_lvl > 2)
|
||||
syslog(LOG_DEBUG, "Sending delete host %lx to " IP_ADDR_S,
|
||||
tmp.vpn_ip, IP_ADDR_V(cl->vpn_ip));
|
||||
|
||||
if((send(cl->meta_socket, (unsigned char*)&tmp, sizeof(del_host_t), 0)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int send_ping(conn_list_t *cl)
|
||||
{
|
||||
unsigned char tmp = PING;
|
||||
|
||||
if(debug_lvl > 3)
|
||||
syslog(LOG_DEBUG, "pinging " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
|
||||
|
||||
if((send(cl->meta_socket, &tmp, sizeof(tmp), 0)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int send_pong(conn_list_t *cl)
|
||||
{
|
||||
unsigned char tmp = PONG;
|
||||
|
||||
if((send(cl->meta_socket, &tmp, sizeof(tmp), 0)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int send_add_host(conn_list_t *cl, conn_list_t *new_host)
|
||||
{
|
||||
add_host_t tmp;
|
||||
|
||||
tmp.type = ADD_HOST;
|
||||
tmp.real_ip = new_host->real_ip;
|
||||
tmp.vpn_ip = new_host->vpn_ip;
|
||||
tmp.vpn_mask = new_host->vpn_mask;
|
||||
tmp.portnr = new_host->port;
|
||||
|
||||
if(debug_lvl > 2)
|
||||
syslog(LOG_DEBUG, "Sending add host (%lx/%lx %lx:%hd) to " IP_ADDR_S,
|
||||
tmp.vpn_ip, tmp.vpn_mask, tmp.real_ip, tmp.portnr,
|
||||
IP_ADDR_V(cl->vpn_ip));
|
||||
|
||||
if((send(cl->meta_socket, (unsigned char*)&tmp, sizeof(add_host_t), 0)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int send_key_changed(conn_list_t *cl, conn_list_t *src)
|
||||
{
|
||||
key_changed_t tmp;
|
||||
|
||||
tmp.type = KEY_CHANGED;
|
||||
tmp.from = src->vpn_ip;
|
||||
|
||||
if(debug_lvl > 2)
|
||||
syslog(LOG_DEBUG, "Sending KEY_CHANGED (%lx) to " IP_ADDR_S,
|
||||
tmp.from, IP_ADDR_V(cl->vpn_ip));
|
||||
|
||||
if((send(cl->meta_socket, (unsigned char*)&tmp, sizeof(key_changed_t), 0)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void send_key_changed2(void)
|
||||
{
|
||||
conn_list_t *p;
|
||||
|
||||
for(p = conn_list; p != NULL; p = p->next)
|
||||
if(p->status.meta && p->protocol_version > PROT_3)
|
||||
send_key_changed(p, myself);
|
||||
}
|
||||
|
||||
int send_basic_info(conn_list_t *cl)
|
||||
{
|
||||
basic_info_t tmp;
|
||||
|
||||
tmp.type = BASIC_INFO;
|
||||
tmp.protocol = PROT_CURRENT;
|
||||
|
||||
tmp.portnr = myself->port;
|
||||
tmp.vpn_ip = myself->vpn_ip;
|
||||
tmp.vpn_mask = myself->vpn_mask;
|
||||
|
||||
if(debug_lvl > 2)
|
||||
syslog(LOG_DEBUG, "Send BASIC_INFO(%d,%hd," IP_ADDR_S "," IP_ADDR_S ") to " IP_ADDR_S,
|
||||
tmp.protocol, tmp.portnr, IP_ADDR_V(tmp.vpn_ip), IP_ADDR_V(tmp.vpn_mask),
|
||||
IP_ADDR_V(cl->real_ip));
|
||||
|
||||
if((send(cl->meta_socket, &tmp, sizeof(tmp), 0)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int send_passphrase(conn_list_t *cl)
|
||||
{
|
||||
passphrase_t tmp;
|
||||
|
||||
tmp.type = PASSPHRASE;
|
||||
encrypt_passphrase(&tmp);
|
||||
|
||||
if(debug_lvl > 2)
|
||||
syslog(LOG_DEBUG, "Send PASSPHRASE(%hd,...) to " IP_ADDR_S, tmp.len,
|
||||
IP_ADDR_V(cl->vpn_ip));
|
||||
|
||||
if((send(cl->meta_socket, &tmp, tmp.len+3, 0)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int send_public_key(conn_list_t *cl)
|
||||
{
|
||||
public_key_t *tmp;
|
||||
|
||||
tmp = (public_key_t*)xmalloc(strlen(my_public_key_base36)+sizeof(public_key_t));
|
||||
tmp->type = PUBLIC_KEY;
|
||||
tmp->len = strlen(my_public_key_base36);
|
||||
strcpy(&tmp->key, my_public_key_base36);
|
||||
|
||||
if(debug_lvl > 2)
|
||||
syslog(LOG_DEBUG, "Send PUBLIC_KEY(%hd,%s) to " IP_ADDR_S, tmp->len, &tmp->key,
|
||||
IP_ADDR_V(cl->vpn_ip));
|
||||
|
||||
if((send(cl->meta_socket, tmp, tmp->len+sizeof(public_key_t), 0)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int send_calculate(conn_list_t *cl, char *k)
|
||||
{
|
||||
calculate_t *tmp;
|
||||
|
||||
tmp = xmalloc(strlen(k)+sizeof(calculate_t));
|
||||
tmp->type = CALCULATE;
|
||||
tmp->len = strlen(k);
|
||||
strcpy(&tmp->key, k);
|
||||
|
||||
if(send(cl->meta_socket, tmp, tmp->len+4, 0) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int send_key_request(ip_t to)
|
||||
{
|
||||
key_req_t *tmp;
|
||||
conn_list_t *fw;
|
||||
|
||||
tmp = xmalloc(sizeof(key_req_t));
|
||||
tmp->type = REQ_KEY;
|
||||
tmp->to = to;
|
||||
tmp->from = myself->vpn_ip;
|
||||
tmp->len = 0;
|
||||
|
||||
fw = lookup_conn(to);
|
||||
if(!fw)
|
||||
{
|
||||
syslog(LOG_ERR, "Attempting to send key request to " IP_ADDR_S ", which does not exist?",
|
||||
IP_ADDR_V(to));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(debug_lvl > 2)
|
||||
syslog(LOG_DEBUG, "Sending out request for public key to " IP_ADDR_S,
|
||||
IP_ADDR_V(fw->nexthop->vpn_ip));
|
||||
if(send(fw->nexthop->meta_socket, tmp, sizeof(key_req_t), 0) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
|
||||
return -1;
|
||||
}
|
||||
fw->status.waitingforkey = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int send_key_answer(conn_list_t *cl, ip_t to)
|
||||
{
|
||||
key_req_t *tmp;
|
||||
conn_list_t *fw;
|
||||
|
||||
tmp = xmalloc(sizeof(key_req_t)+strlen(my_public_key_base36));
|
||||
tmp->type = ANS_KEY;
|
||||
tmp->to = to;
|
||||
tmp->from = myself->vpn_ip;
|
||||
tmp->expiry = my_key_expiry;
|
||||
tmp->len = strlen(my_public_key_base36);
|
||||
strcpy(&tmp->key, my_public_key_base36);
|
||||
|
||||
fw = lookup_conn(to);
|
||||
if(debug_lvl > 2)
|
||||
syslog(LOG_DEBUG, "Sending public key to " IP_ADDR_S,
|
||||
IP_ADDR_V(fw->nexthop->vpn_ip));
|
||||
if(send(fw->nexthop->meta_socket, tmp, sizeof(key_req_t)+tmp->len, 0) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
notify all my direct connections of a new host
|
||||
that was added to the vpn, with the exception
|
||||
of the source of the announcement.
|
||||
*/
|
||||
int notify_others(conn_list_t *new, conn_list_t *source,
|
||||
int (*function)(conn_list_t*, conn_list_t*))
|
||||
{
|
||||
conn_list_t *p;
|
||||
|
||||
for(p = conn_list; p != NULL; p = p->next)
|
||||
if(p != new && p != source && p->status.meta && p->protocol_version > PROT_3)
|
||||
function(p, new);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
notify one connection of everything
|
||||
i have connected
|
||||
*/
|
||||
int notify_one(conn_list_t *new)
|
||||
{
|
||||
conn_list_t *p;
|
||||
|
||||
for(p = conn_list; p != NULL; p = p->next)
|
||||
if(p != new && p->protocol_version > PROT_3)
|
||||
send_add_host(new, p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
The incoming request handlers
|
||||
*/
|
||||
|
||||
int basic_info_h(conn_list_t *cl, unsigned char *d, int len)
|
||||
{
|
||||
basic_info_t *tmp = (basic_info_t*)d;
|
||||
|
||||
cl->protocol_version = tmp->protocol;
|
||||
cl->port = tmp->portnr;
|
||||
cl->vpn_ip = tmp->vpn_ip;
|
||||
cl->vpn_mask = tmp->vpn_mask;
|
||||
|
||||
if(cl->protocol_version < PROT_CURRENT)
|
||||
{
|
||||
syslog(LOG_ERR, "Peer uses protocol version %d which is too old.",
|
||||
cl->protocol_version);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(debug_lvl > 2)
|
||||
syslog(LOG_DEBUG, "got BASIC_INFO(%hd," IP_ADDR_S "," IP_ADDR_S ")", cl->port,
|
||||
IP_ADDR_V(cl->vpn_ip), IP_ADDR_V(cl->vpn_mask));
|
||||
if(debug_lvl > 1)
|
||||
syslog(LOG_DEBUG, "Peer uses protocol version %d",
|
||||
cl->protocol_version);
|
||||
|
||||
if(cl->status.outgoing)
|
||||
{
|
||||
if(setup_vpn_connection(cl) < 0)
|
||||
return -1;
|
||||
send_basic_info(cl);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(setup_vpn_connection(cl) < 0)
|
||||
return -1;
|
||||
send_passphrase(cl);
|
||||
}
|
||||
|
||||
cl->status.active = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int passphrase_h(conn_list_t *cl, unsigned char *d, int len)
|
||||
{
|
||||
passphrase_t *tmp = (passphrase_t*)d;
|
||||
|
||||
cl->pp = xmalloc(tmp->len+3);
|
||||
memcpy(cl->pp, tmp, tmp->len+3);
|
||||
|
||||
if(debug_lvl > 2)
|
||||
syslog(LOG_DEBUG, "got PASSPHRASE(%hd,...)", cl->pp->len);
|
||||
|
||||
if(cl->status.outgoing)
|
||||
send_passphrase(cl);
|
||||
else
|
||||
send_public_key(cl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int public_key_h(conn_list_t *cl, unsigned char *d, int len)
|
||||
{
|
||||
char *g_n;
|
||||
public_key_t *tmp = (public_key_t*)d;
|
||||
|
||||
if(debug_lvl > 2)
|
||||
syslog(LOG_DEBUG, "got PUBLIC_KEY(%hd,%s)", tmp->len, &tmp->key);
|
||||
|
||||
g_n = xmalloc(tmp->len+1);
|
||||
strcpy(g_n, &tmp->key);
|
||||
|
||||
if(verify_passphrase(cl, g_n))
|
||||
{
|
||||
/* intruder! */
|
||||
syslog(LOG_ERR, "Intruder: passphrase does not match.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(debug_lvl > 2)
|
||||
syslog(LOG_INFO, "Passphrase OK");
|
||||
|
||||
if(cl->status.outgoing)
|
||||
send_public_key(cl);
|
||||
else
|
||||
send_ack(cl);
|
||||
|
||||
cl->status.active = 1;
|
||||
notify_others(cl, NULL, send_add_host);
|
||||
notify_one(cl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ack_h(conn_list_t *cl, unsigned char *d, int len)
|
||||
{
|
||||
if(debug_lvl > 2)
|
||||
syslog(LOG_DEBUG, "got ACK");
|
||||
|
||||
cl->status.active = 1;
|
||||
syslog(LOG_NOTICE, "Connection with %s activated.", cl->hostname);
|
||||
|
||||
/*
|
||||
Now I'm going to cheat. The meta protocol is actually
|
||||
a stream of requests, that may come in in the same TCP
|
||||
packet. This is the only place that it will happen,
|
||||
though.
|
||||
I may change it in the future, if it appears that this
|
||||
is not retainable.
|
||||
*/
|
||||
if(len > 1) /* An ADD_HOST follows */
|
||||
{
|
||||
if(request_handlers[d[1]] == NULL)
|
||||
syslog(LOG_ERR, "Unknown request %d.", d[1]);
|
||||
if(request_handlers[d[1]](cl, d, len - 1) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int termreq_h(conn_list_t *cl, unsigned char *d, int len)
|
||||
{
|
||||
syslog(LOG_NOTICE, IP_ADDR_S " wants to quit", IP_ADDR_V(cl->vpn_ip));
|
||||
cl->status.termreq = 1;
|
||||
terminate_connection(cl);
|
||||
|
||||
notify_others(cl, NULL, send_del_host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int timeout_h(conn_list_t *cl, unsigned char *d, int len)
|
||||
{
|
||||
syslog(LOG_NOTICE, IP_ADDR_S " says it's gotten a timeout from us", IP_ADDR_V(cl->vpn_ip));
|
||||
cl->status.termreq = 1;
|
||||
terminate_connection(cl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int del_host_h(conn_list_t *cl, unsigned char *d, int len)
|
||||
{
|
||||
del_host_t *tmp = (del_host_t*)d;
|
||||
conn_list_t *fw;
|
||||
|
||||
if(debug_lvl > 2)
|
||||
syslog(LOG_DEBUG, "got DEL_HOST for " IP_ADDR_S,
|
||||
IP_ADDR_V(tmp->vpn_ip));
|
||||
|
||||
if(!(fw = lookup_conn(tmp->vpn_ip)))
|
||||
{
|
||||
syslog(LOG_ERR, "Somebody wanted to delete " IP_ADDR_S " which does not exist?",
|
||||
IP_ADDR_V(tmp->vpn_ip));
|
||||
return 0;
|
||||
}
|
||||
|
||||
notify_others(cl, fw, send_del_host);
|
||||
|
||||
fw->status.termreq = 1;
|
||||
terminate_connection(fw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ping_h(conn_list_t *cl, unsigned char *d, int len)
|
||||
{
|
||||
if(debug_lvl > 3)
|
||||
syslog(LOG_DEBUG, "responding to ping from " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
|
||||
cl->status.pinged = 0;
|
||||
cl->status.got_pong = 1;
|
||||
|
||||
send_pong(cl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pong_h(conn_list_t *cl, unsigned char *d, int len)
|
||||
{
|
||||
if(debug_lvl > 3)
|
||||
syslog(LOG_DEBUG, "ok, got pong from " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
|
||||
cl->status.got_pong = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int add_host_h(conn_list_t *cl, unsigned char *d, int len)
|
||||
{
|
||||
add_host_t *tmp = (add_host_t*)d;
|
||||
conn_list_t *ncn, *fw;
|
||||
|
||||
if(debug_lvl > 2)
|
||||
syslog(LOG_DEBUG, "Add host request from " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
|
||||
if(debug_lvl > 3)
|
||||
syslog(LOG_DEBUG, "got ADD_HOST(" IP_ADDR_S "," IP_ADDR_S ",%hd)",
|
||||
IP_ADDR_V(tmp->vpn_ip), IP_ADDR_V(tmp->vpn_mask), tmp->portnr);
|
||||
|
||||
/*
|
||||
Suggestion of Hans Bayle
|
||||
*/
|
||||
if((fw = lookup_conn(tmp->vpn_ip)))
|
||||
{
|
||||
notify_others(fw, cl, send_add_host);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ncn = new_conn_list();
|
||||
ncn->real_ip = tmp->real_ip;
|
||||
ncn->vpn_ip = tmp->vpn_ip;
|
||||
ncn->vpn_mask = tmp->vpn_mask;
|
||||
ncn->port = tmp->portnr;
|
||||
ncn->hostname = hostlookup(tmp->real_ip);
|
||||
ncn->nexthop = cl;
|
||||
ncn->next = conn_list;
|
||||
conn_list = ncn;
|
||||
ncn->status.active = 1;
|
||||
notify_others(ncn, cl, send_add_host);
|
||||
|
||||
/*
|
||||
again, i'm cheating here. see the comment in ack_h.
|
||||
*/
|
||||
if(len > sizeof(add_host_t)) /* Another ADD_HOST follows */
|
||||
{
|
||||
if(request_handlers[d[sizeof(add_host_t)]] == NULL)
|
||||
syslog(LOG_ERR, "Unknown request %d.", d[sizeof(add_host_t)]);
|
||||
if(request_handlers[d[sizeof(add_host_t)]](cl, d, len - sizeof(add_host_t)) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int req_key_h(conn_list_t *cl, unsigned char *d, int len)
|
||||
{
|
||||
key_req_t *tmp = (key_req_t*)d;
|
||||
conn_list_t *fw;
|
||||
|
||||
if(debug_lvl > 2)
|
||||
syslog(LOG_DEBUG, "got REQ_KEY from " IP_ADDR_S " for " IP_ADDR_S,
|
||||
IP_ADDR_V(tmp->from), IP_ADDR_V(tmp->to));
|
||||
|
||||
if((tmp->to & myself->vpn_mask) == (myself->vpn_ip & myself->vpn_mask))
|
||||
{ /* hey! they want something from ME! :) */
|
||||
send_key_answer(cl, tmp->from);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fw = lookup_conn(tmp->to);
|
||||
if(debug_lvl > 3)
|
||||
syslog(LOG_DEBUG, "Forwarding request for public key to " IP_ADDR_S,
|
||||
IP_ADDR_V(fw->nexthop->vpn_ip));
|
||||
if(send(fw->nexthop->meta_socket, tmp, sizeof(key_req_t), 0) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void set_keys(conn_list_t *cl, key_req_t *k)
|
||||
{
|
||||
char *ek;
|
||||
|
||||
if(!cl->public_key)
|
||||
{
|
||||
cl->public_key = xmalloc(sizeof(enc_key_t));
|
||||
cl->public_key->key = NULL;
|
||||
}
|
||||
if(cl->public_key->key)
|
||||
free(cl->public_key->key);
|
||||
cl->public_key->length = k->len;
|
||||
cl->public_key->expiry = k->expiry;
|
||||
cl->public_key->key = xmalloc(k->len + 1);
|
||||
strcpy(cl->public_key->key, &(k->key));
|
||||
|
||||
ek = make_shared_key(&(k->key));
|
||||
if(!cl->key)
|
||||
{
|
||||
cl->key = xmalloc(sizeof(enc_key_t));
|
||||
cl->key->key = NULL;
|
||||
}
|
||||
if(cl->key->key)
|
||||
free(cl->key->key);
|
||||
cl->key->length = strlen(ek);
|
||||
cl->key->expiry = k->expiry;
|
||||
cl->key->key = xmalloc(strlen(ek) + 1);
|
||||
strcpy(cl->key->key, ek);
|
||||
}
|
||||
|
||||
int ans_key_h(conn_list_t *cl, unsigned char *d, int len)
|
||||
{
|
||||
key_req_t *tmp = (key_req_t*)d;
|
||||
conn_list_t *fw, *gk;
|
||||
|
||||
if(debug_lvl > 3)
|
||||
syslog(LOG_DEBUG, "got ANS_KEY from " IP_ADDR_S " for " IP_ADDR_S,
|
||||
IP_ADDR_V(tmp->from), IP_ADDR_V(tmp->to));
|
||||
|
||||
if(tmp->to == myself->vpn_ip)
|
||||
{ /* hey! that key's for ME! :) */
|
||||
if(debug_lvl > 2)
|
||||
syslog(LOG_DEBUG, "Yeah! key arrived. Now do something with it.");
|
||||
gk = lookup_conn(tmp->from);
|
||||
set_keys(gk, tmp);
|
||||
gk->status.validkey = 1;
|
||||
gk->status.waitingforkey = 0;
|
||||
flush_queues(gk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fw = lookup_conn(tmp->to);
|
||||
if(debug_lvl > 2)
|
||||
syslog(LOG_DEBUG, "Forwarding public key to " IP_ADDR_S,
|
||||
IP_ADDR_V(fw->nexthop->vpn_ip));
|
||||
if(send(fw->nexthop->meta_socket, tmp, sizeof(key_req_t)+tmp->len, 0) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int key_changed_h(conn_list_t *cl, unsigned char *d, int len)
|
||||
{
|
||||
key_changed_t *tmp = (key_changed_t*)d;
|
||||
conn_list_t *ik;
|
||||
|
||||
if(debug_lvl > 2)
|
||||
syslog(LOG_DEBUG, "got KEY_CHANGED from " IP_ADDR_S,
|
||||
IP_ADDR_V(tmp->from));
|
||||
|
||||
ik = lookup_conn(tmp->from);
|
||||
ik->status.validkey = 0;
|
||||
ik->status.waitingforkey = 0;
|
||||
|
||||
if(debug_lvl > 3)
|
||||
syslog(LOG_DEBUG, "Forwarding key invalidation request");
|
||||
|
||||
notify_others(cl, ik, send_key_changed);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int (*request_handlers[256])(conn_list_t*, unsigned char*, int) = {
|
||||
0, ack_h, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
termreq_h, timeout_h, del_host_h, 0, 0, 0, 0, 0, 0, 0,
|
||||
ping_h, pong_h, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
add_host_h, basic_info_h, passphrase_h, public_key_h, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
req_key_h, ans_key_h, key_changed_h, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
124
src/protocol.h
Normal file
124
src/protocol.h
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
protocol.h -- header for protocol.c
|
||||
Copyright (C) 1999 Ivo Timmermans <zarq@iname.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.
|
||||
*/
|
||||
|
||||
#ifndef __TINC_PROTOCOL_H__
|
||||
#define __TINC_PROTOCOL_H__
|
||||
|
||||
#include "net.h"
|
||||
|
||||
enum {
|
||||
PROT_RESERVED = 0, /* reserved: do not use. */
|
||||
PROT_NOT_IN_USE,
|
||||
PROT_TOO_OLD = 2,
|
||||
PROT_3,
|
||||
PROT_CURRENT, /* protocol currently in use */
|
||||
};
|
||||
|
||||
enum {
|
||||
ACK = 1, /* acknowledged */
|
||||
AUTH_S_INIT = 10, /* initiate authentication */
|
||||
AUTH_C_INIT,
|
||||
AUTH_S_SPP, /* send passphrase */
|
||||
AUTH_C_SPP,
|
||||
AUTH_S_SKEY, /* send g^k */
|
||||
AUTH_C_SKEY,
|
||||
AUTH_S_SACK, /* send ack */
|
||||
AUTH_C_RACK, /* waiting for ack */
|
||||
TERMREQ = 30, /* terminate connection */
|
||||
PINGTIMEOUT, /* terminate due to ping t.o. */
|
||||
DEL_HOST, /* forward a termreq to others */
|
||||
PING = 40, /* ping */
|
||||
PONG,
|
||||
ADD_HOST = 60, /* Add new given host to connection list */
|
||||
BASIC_INFO, /* some basic info follows */
|
||||
PASSPHRASE, /* encrypted passphrase */
|
||||
PUBLIC_KEY, /* public key in base-36 */
|
||||
HOLD = 80, /* don't send any data */
|
||||
RESUME, /* resume dataflow with new encryption key */
|
||||
CALCULATE = 100, /* calculate the following numer^privkey and send me the result */
|
||||
CALC_RES, /* result of the above */
|
||||
ALMOST_KEY, /* this number^privkey is the shared key */
|
||||
REQ_KEY = 160, /* request public key */
|
||||
ANS_KEY, /* answer to such request */
|
||||
KEY_CHANGED, /* public key has changed */
|
||||
};
|
||||
|
||||
typedef struct add_host_t {
|
||||
unsigned char type;
|
||||
ip_t real_ip;
|
||||
ip_t vpn_ip;
|
||||
ip_t vpn_mask;
|
||||
unsigned short portnr;
|
||||
} add_host_t;
|
||||
|
||||
typedef struct termreq_t {
|
||||
unsigned char type;
|
||||
ip_t vpn_ip;
|
||||
} termreq_t;
|
||||
|
||||
typedef struct basic_info_t {
|
||||
unsigned char type;
|
||||
unsigned char protocol;
|
||||
unsigned short portnr;
|
||||
ip_t vpn_ip;
|
||||
ip_t vpn_mask;
|
||||
} basic_info_t;
|
||||
|
||||
typedef struct calculate_t {
|
||||
unsigned char type;
|
||||
unsigned short len;
|
||||
char key;
|
||||
} calculate_t;
|
||||
|
||||
typedef struct public_key_t {
|
||||
unsigned char type;
|
||||
unsigned short len;
|
||||
char key;
|
||||
} public_key_t;
|
||||
|
||||
typedef struct key_req_t {
|
||||
unsigned char type;
|
||||
ip_t from;
|
||||
ip_t to;
|
||||
time_t expiry;
|
||||
short int len; /* 0 if requesting */
|
||||
char key;
|
||||
} key_req_t;
|
||||
|
||||
typedef struct key_changed_t {
|
||||
unsigned char type;
|
||||
ip_t from;
|
||||
} key_changed_t;
|
||||
|
||||
typedef struct del_host_t {
|
||||
unsigned char type;
|
||||
ip_t vpn_ip;
|
||||
} del_host_t;
|
||||
|
||||
extern int (*request_handlers[256])(conn_list_t*, unsigned char*, int);
|
||||
|
||||
extern int send_ping(conn_list_t*);
|
||||
extern int send_basic_info(conn_list_t *);
|
||||
extern int send_termreq(conn_list_t *);
|
||||
extern int send_timeout(conn_list_t *);
|
||||
extern int send_key_request(ip_t);
|
||||
extern void send_key_changed2(void);
|
||||
|
||||
#endif /* __TINC_PROTOCOL_H__ */
|
||||
|
||||
468
src/tincd.c
Normal file
468
src/tincd.c
Normal file
|
|
@ -0,0 +1,468 @@
|
|||
/*
|
||||
tincd.c -- the main file for tincd
|
||||
Copyright (C) 1998,99 Ivo Timmermans <zarq@iname.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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
# include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#include <pidfile.h>
|
||||
#include <utils.h>
|
||||
#include <xalloc.h>
|
||||
|
||||
#include "conf.h"
|
||||
#include "encr.h"
|
||||
#include "net.h"
|
||||
#include "netutl.h"
|
||||
|
||||
/* The name this program was run with. */
|
||||
char *program_name;
|
||||
|
||||
/* If nonzero, display usage information and exit. */
|
||||
static int show_help;
|
||||
|
||||
/* If nonzero, print the version on standard output and exit. */
|
||||
static int show_version;
|
||||
|
||||
/* If nonzero, it will attempt to kill a running tincd and exit. */
|
||||
static int kill_tincd = 0;
|
||||
|
||||
char *confbase = NULL; /* directory in which all config files are */
|
||||
char *configfilename = NULL; /* configuration file name */
|
||||
char *identname; /* program name for syslog */
|
||||
char *netname = NULL; /* name of the vpn network */
|
||||
char *pidfilename; /* pid file location */
|
||||
static pid_t ppid; /* pid of non-detached part */
|
||||
char **g_argv; /* a copy of the cmdline arguments */
|
||||
|
||||
void cleanup_and_exit(int);
|
||||
int detach(void);
|
||||
int kill_other(void);
|
||||
void make_names(void);
|
||||
RETSIGTYPE parent_exit(int a);
|
||||
void setup_signals(void);
|
||||
int write_pidfile(void);
|
||||
|
||||
static struct option const long_options[] =
|
||||
{
|
||||
{ "kill", no_argument, NULL, 'k' },
|
||||
{ "net", required_argument, NULL, 'n' },
|
||||
{ "timeout", required_argument, NULL, 'p' },
|
||||
{ "help", no_argument, &show_help, 1 },
|
||||
{ "version", no_argument, &show_version, 1 },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
static void
|
||||
usage(int status)
|
||||
{
|
||||
if(status != 0)
|
||||
fprintf(stderr, "Try `%s --help\' for more information.\n", program_name);
|
||||
else
|
||||
{
|
||||
printf("Usage: %s [option]...\n\n", program_name);
|
||||
printf(" -c, --config=FILE Read configuration options from FILE.\n"
|
||||
" -d Increase debug level.\n"
|
||||
" -k, --kill Attempt to kill a running tincd and exit.\n"
|
||||
" -n, --net=NETNAME Connect to net NETNAME.\n"
|
||||
" -t, --timeout=TIMEOUT Seconds to wait before giving a timeout.\n");
|
||||
printf(" --help Display this help and exit.\n"
|
||||
" --version Output version information and exit.\n\n");
|
||||
printf("Report bugs to zarq@iname.com.\n");
|
||||
}
|
||||
exit(status);
|
||||
}
|
||||
|
||||
void
|
||||
parse_options(int argc, char **argv, char **envp)
|
||||
{
|
||||
int r;
|
||||
int option_index = 0;
|
||||
config_t *p;
|
||||
|
||||
while((r = getopt_long(argc, argv, "c:dkn:t:", long_options, &option_index)) != EOF)
|
||||
{
|
||||
switch(r)
|
||||
{
|
||||
case 0: /* long option */
|
||||
break;
|
||||
case 'c': /* config file */
|
||||
configfilename = xmalloc(strlen(optarg)+1);
|
||||
strcpy(configfilename, optarg);
|
||||
break;
|
||||
case 'd': /* inc debug level */
|
||||
debug_lvl++;
|
||||
break;
|
||||
case 'k': /* kill old tincds */
|
||||
kill_tincd = 1;
|
||||
break;
|
||||
case 'n': /* net name given */
|
||||
netname = xmalloc(strlen(optarg)+1);
|
||||
strcpy(netname, optarg);
|
||||
break;
|
||||
case 't': /* timeout */
|
||||
if(!(p = add_config_val(&config, TYPE_INT, optarg)))
|
||||
{
|
||||
printf("Invalid timeout value `%s'.\n", optarg);
|
||||
usage(1);
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
usage(1);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void memory_full(void)
|
||||
{
|
||||
syslog(LOG_ERR, "Memory exhausted; exiting.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
Detach from current terminal, write pidfile, kill parent
|
||||
*/
|
||||
int detach(void)
|
||||
{
|
||||
int fd;
|
||||
pid_t pid;
|
||||
|
||||
ppid = getpid();
|
||||
if((pid = fork()) < 0)
|
||||
{
|
||||
perror("fork");
|
||||
return -1;
|
||||
}
|
||||
if(pid) /* parent process */
|
||||
{
|
||||
signal(SIGTERM, parent_exit);
|
||||
sleep(600); /* wait 10 minutes */
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(write_pidfile())
|
||||
return -1;
|
||||
|
||||
if((fd = open("/dev/tty", O_RDWR)) >= 0)
|
||||
{
|
||||
if(ioctl(fd, TIOCNOTTY, NULL))
|
||||
{
|
||||
perror("ioctl");
|
||||
return -1;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
kill(ppid, SIGTERM);
|
||||
|
||||
if(setsid() < 0)
|
||||
return -1;
|
||||
chdir("/"); /* avoid keeping a mointpoint busy */
|
||||
|
||||
openlog(identname, LOG_CONS | LOG_PID, LOG_DAEMON);
|
||||
|
||||
if(debug_lvl > 1)
|
||||
syslog(LOG_NOTICE, "tincd %s (%s %s) starting, debug level %d.",
|
||||
VERSION, __DATE__, __TIME__, debug_lvl);
|
||||
else
|
||||
syslog(LOG_NOTICE, "tincd %s starting, debug level %d.", VERSION, debug_lvl);
|
||||
|
||||
xalloc_fail_func = memory_full;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Close network connections, and terminate neatly
|
||||
*/
|
||||
void cleanup_and_exit(int c)
|
||||
{
|
||||
close_network_connections();
|
||||
|
||||
if(debug_lvl > 0)
|
||||
syslog(LOG_INFO, "Total bytes written: tap %d, socket %d; bytes read: tap %d, socket %d.",
|
||||
total_tap_out, total_socket_out, total_tap_in, total_socket_in);
|
||||
|
||||
closelog();
|
||||
kill(ppid, SIGTERM);
|
||||
exit(c);
|
||||
}
|
||||
|
||||
/*
|
||||
check for an existing tinc for this net, and write pid to pidfile
|
||||
*/
|
||||
int write_pidfile(void)
|
||||
{
|
||||
int pid;
|
||||
|
||||
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;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
kill older tincd for this net
|
||||
*/
|
||||
int kill_other(void)
|
||||
{
|
||||
int pid;
|
||||
|
||||
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, SIGTERM) && errno == ESRCH)
|
||||
fprintf(stderr, "Removing stale lock file.\n");
|
||||
remove_pid(pidfilename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Set all files and paths according to netname
|
||||
*/
|
||||
void make_names(void)
|
||||
{
|
||||
if(!configfilename)
|
||||
{
|
||||
if(netname)
|
||||
{
|
||||
configfilename = xmalloc(strlen(netname)+18+strlen(CONFDIR));
|
||||
sprintf(configfilename, "%s/tinc/%s/tincd.conf", CONFDIR, netname);
|
||||
}
|
||||
else
|
||||
{
|
||||
configfilename = xmalloc(17+strlen(CONFDIR));
|
||||
sprintf(configfilename, "%s/tinc/tincd.conf", CONFDIR);
|
||||
}
|
||||
}
|
||||
|
||||
if(netname)
|
||||
{
|
||||
pidfilename = xmalloc(strlen(netname)+20);
|
||||
sprintf(pidfilename, "/var/run/tincd.%s.pid", netname);
|
||||
confbase = xmalloc(strlen(netname)+8+strlen(CONFDIR));
|
||||
sprintf(confbase, "%s/tinc/%s/", CONFDIR, netname);
|
||||
identname = xmalloc(strlen(netname)+7);
|
||||
sprintf(identname, "tincd.%s", netname);
|
||||
}
|
||||
else
|
||||
{
|
||||
pidfilename = "/var/run/tincd.pid";
|
||||
confbase = xmalloc(7+strlen(CONFDIR));
|
||||
sprintf(confbase, "%s/tinc/", CONFDIR);
|
||||
identname = "tincd";
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv, char **envp)
|
||||
{
|
||||
program_name = argv[0];
|
||||
|
||||
parse_options(argc, argv, envp);
|
||||
|
||||
if(show_version)
|
||||
{
|
||||
printf("%s version %s\nCopyright (C) 1998,99 Ivo Timmermans and others,\n"
|
||||
"see the AUTHORS file for a complete list.\n\n"
|
||||
"tinc comes with ABSOLUTELY NO WARRANTY. This is free software,\n"
|
||||
"and you are welcome to redistribute it under certain conditions;\n"
|
||||
"see the file COPYING for details.\n\n", PACKAGE, VERSION);
|
||||
printf("This product includes software developed by Eric Young (eay@mincom.oz.au)\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(show_help)
|
||||
usage(0);
|
||||
|
||||
if(geteuid())
|
||||
{
|
||||
fprintf(stderr, "You must be root to run this program. sorry.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
g_argv = argv;
|
||||
|
||||
make_names();
|
||||
|
||||
if(kill_tincd)
|
||||
exit(kill_other());
|
||||
|
||||
if(read_config_file(configfilename))
|
||||
return 1;
|
||||
|
||||
setup_signals();
|
||||
|
||||
if(detach())
|
||||
cleanup_and_exit(1);
|
||||
|
||||
if(security_init())
|
||||
return 1;
|
||||
|
||||
if(setup_network_connections())
|
||||
cleanup_and_exit(1);
|
||||
|
||||
main_loop();
|
||||
|
||||
cleanup_and_exit(1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
RETSIGTYPE
|
||||
sigterm_handler(int a)
|
||||
{
|
||||
if(debug_lvl > 0)
|
||||
syslog(LOG_NOTICE, "Got TERM signal");
|
||||
cleanup_and_exit(0);
|
||||
}
|
||||
|
||||
RETSIGTYPE
|
||||
sigquit_handler(int a)
|
||||
{
|
||||
if(debug_lvl > 0)
|
||||
syslog(LOG_NOTICE, "Got QUIT signal");
|
||||
cleanup_and_exit(0);
|
||||
}
|
||||
|
||||
RETSIGTYPE
|
||||
sigsegv_square(int a)
|
||||
{
|
||||
syslog(LOG_NOTICE, "Got another SEGV signal: not restarting");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
RETSIGTYPE
|
||||
sigsegv_handler(int a)
|
||||
{
|
||||
if(cp_file)
|
||||
syslog(LOG_NOTICE, "Got SEGV signal after %s line %d. Trying to re-execute.",
|
||||
cp_file, cp_line);
|
||||
else
|
||||
syslog(LOG_NOTICE, "Got SEGV signal; trying to re-execute.");
|
||||
|
||||
signal(SIGSEGV, sigsegv_square);
|
||||
|
||||
close_network_connections();
|
||||
remove_pid(pidfilename);
|
||||
execvp(g_argv[0], g_argv);
|
||||
}
|
||||
|
||||
RETSIGTYPE
|
||||
sighup_handler(int a)
|
||||
{
|
||||
if(debug_lvl > 0)
|
||||
syslog(LOG_NOTICE, "Got HUP signal");
|
||||
close_network_connections();
|
||||
setup_network_connections();
|
||||
/* FIXME: read config-file and re-establish network connections */
|
||||
}
|
||||
|
||||
RETSIGTYPE
|
||||
sigint_handler(int a)
|
||||
{
|
||||
if(debug_lvl > 0)
|
||||
syslog(LOG_NOTICE, "Got INT signal");
|
||||
cleanup_and_exit(0);
|
||||
}
|
||||
|
||||
RETSIGTYPE
|
||||
sigusr1_handler(int a)
|
||||
{
|
||||
dump_conn_list();
|
||||
}
|
||||
|
||||
RETSIGTYPE
|
||||
sigusr2_handler(int a)
|
||||
{
|
||||
if(debug_lvl > 1)
|
||||
syslog(LOG_NOTICE, "Forcing new keys");
|
||||
regenerate_keys();
|
||||
}
|
||||
|
||||
RETSIGTYPE
|
||||
sighuh(int a)
|
||||
{
|
||||
if(cp_file)
|
||||
syslog(LOG_NOTICE, "Got unexpected signal after %s line %d.",
|
||||
cp_file, cp_line);
|
||||
else
|
||||
syslog(LOG_NOTICE, "Got unexpected signal.");
|
||||
}
|
||||
|
||||
void
|
||||
setup_signals(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0;i<32;i++)
|
||||
signal(i,sighuh);
|
||||
|
||||
if(signal(SIGTERM, SIG_IGN) != SIG_ERR)
|
||||
signal(SIGTERM, sigterm_handler);
|
||||
if(signal(SIGQUIT, SIG_IGN) != SIG_ERR)
|
||||
signal(SIGQUIT, sigquit_handler);
|
||||
if(signal(SIGSEGV, SIG_IGN) != SIG_ERR)
|
||||
signal(SIGSEGV, sigsegv_handler);
|
||||
if(signal(SIGHUP, SIG_IGN) != SIG_ERR)
|
||||
signal(SIGHUP, sighup_handler);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
if(signal(SIGINT, SIG_IGN) != SIG_ERR)
|
||||
signal(SIGINT, sigint_handler);
|
||||
signal(SIGUSR1, sigusr1_handler);
|
||||
signal(SIGUSR2, sigusr2_handler);
|
||||
}
|
||||
|
||||
RETSIGTYPE parent_exit(int a)
|
||||
{
|
||||
exit(0);
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue