2000-03-26 00:33:07 +00:00
/*
protocol . c - - handle the meta - protocol
2000-05-29 21:01:26 +00:00
Copyright ( C ) 1999 , 2000 Ivo Timmermans < itimmermans @ bigfoot . com > ,
2000 Guus Sliepen < guus @ sliepen . warande . net >
2000-03-26 00:33:07 +00:00
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 0213 9 , USA .
2000-05-29 21:01:26 +00:00
2000-12-05 08:59:30 +00:00
$ Id : protocol . c , v 1.28 .4 .69 2000 / 12 / 05 08 : 59 : 30 zarq Exp $
2000-03-26 00:33:07 +00:00
*/
# include "config.h"
2000-05-04 23:17:02 +00:00
# include <sys/types.h>
2000-03-26 00:33:07 +00:00
# include <stdlib.h>
# include <string.h>
# include <syslog.h>
# include <sys/socket.h>
2000-04-26 17:42:55 +00:00
# include <unistd.h>
2000-05-01 18:07:12 +00:00
# include <stdio.h>
2000-11-15 13:33:27 +00:00
# include <stdarg.h>
2000-03-26 00:33:07 +00:00
# include <utils.h>
# include <xalloc.h>
2000-08-07 16:27:29 +00:00
# include <netinet/in.h>
2000-11-15 01:06:13 +00:00
# ifdef HAVE_OPENSSL_SHA_H
# include <openssl / sha.h>
# else
# include <sha.h>
# endif
# ifdef HAVE_OPENSSL_RAND_H
# include <openssl / rand.h>
# else
# include <rand.h>
# endif
# ifdef HAVE_OPENSSL_EVP_H
# include <openssl / evp.h>
# else
# include <evp.h>
# endif
2000-09-14 21:51:21 +00:00
2000-03-26 00:33:07 +00:00
# include "conf.h"
# include "net.h"
# include "netutl.h"
# include "protocol.h"
2000-09-26 14:06:11 +00:00
# include "meta.h"
2000-11-20 19:12:17 +00:00
# include "connection.h"
2000-03-26 00:33:07 +00:00
2000-05-29 21:01:26 +00:00
# include "system.h"
2000-09-15 12:58:40 +00:00
int check_id ( char * id )
{
int i ;
for ( i = 0 ; i < strlen ( id ) ; i + + )
2000-10-15 00:59:37 +00:00
if ( ! isalnum ( id [ i ] ) & & id [ i ] ! = ' _ ' )
return - 1 ;
2000-12-05 08:59:30 +00:00
2000-10-15 00:59:37 +00:00
return 0 ;
2000-09-15 12:58:40 +00:00
}
2000-12-05 08:59:30 +00:00
/* Generic request routines - takes care of logging and error
detection as well */
2000-05-01 18:07:12 +00:00
2000-11-20 19:12:17 +00:00
int send_request ( connection_t * cl , const char * format , . . . )
2000-03-26 00:33:07 +00:00
{
2000-09-10 15:18:03 +00:00
va_list args ;
2000-10-15 00:59:37 +00:00
char buffer [ MAXBUFSIZE ] ;
int len , request ;
2000-09-17 21:42:05 +00:00
2000-04-25 18:57:23 +00:00
cp
2000-12-05 08:59:30 +00:00
/* Use vsnprintf instead of vasprintf: faster, no memory
fragmentation , cleanup is automatic , and there is a limit on the
input buffer anyway */
2000-09-10 15:18:03 +00:00
2000-10-15 00:59:37 +00:00
va_start ( args , format ) ;
len = vsnprintf ( buffer , MAXBUFSIZE , format , args ) ;
request = va_arg ( args , int ) ;
2000-09-10 15:18:03 +00:00
va_end ( args ) ;
2000-03-26 00:33:07 +00:00
2000-10-15 00:59:37 +00:00
if ( len < 0 | | len > MAXBUFSIZE - 1 )
2000-09-10 15:18:03 +00:00
{
2000-09-17 21:42:05 +00:00
syslog ( LOG_ERR , _ ( " Output buffer overflow while sending %s to %s (%s) " ) , request_name [ request ] , cl - > name , cl - > hostname ) ;
2000-09-10 15:18:03 +00:00
return - 1 ;
}
2000-10-15 00:59:37 +00:00
len + + ;
2000-09-22 16:20:07 +00:00
if ( debug_lvl > = DEBUG_PROTOCOL )
2000-09-17 21:42:05 +00:00
syslog ( LOG_DEBUG , _ ( " Sending %s to %s (%s) " ) , request_name [ request ] , cl - > name , cl - > hostname ) ;
2000-10-15 00:59:37 +00:00
2000-09-22 16:20:07 +00:00
cp
2000-10-11 22:01:02 +00:00
return send_meta ( cl , buffer , len ) ;
2000-09-22 16:20:07 +00:00
}
2000-11-20 19:12:17 +00:00
int receive_request ( connection_t * cl )
2000-09-22 16:20:07 +00:00
{
2000-09-26 14:06:11 +00:00
int request ;
cp
if ( sscanf ( cl - > buffer , " %d " , & request ) = = 1 )
2000-09-10 15:18:03 +00:00
{
2000-09-26 14:06:11 +00:00
if ( ( request < 0 ) | | ( request > 255 ) | | ( request_handlers [ request ] = = NULL ) )
{
syslog ( LOG_ERR , _ ( " Unknown request from %s (%s) " ) ,
cl - > name , cl - > hostname ) ;
return - 1 ;
}
else
{
2000-10-21 11:52:08 +00:00
if ( debug_lvl > = DEBUG_PROTOCOL )
2000-09-26 14:06:11 +00:00
syslog ( LOG_DEBUG , _ ( " Got %s from %s (%s) " ) ,
request_name [ request ] , cl - > name , cl - > hostname ) ;
}
2000-10-29 00:02:20 +00:00
2000-10-29 01:08:09 +00:00
if ( ( cl - > allow_request ! = ALL ) & & ( cl - > allow_request ! = request ) )
{
syslog ( LOG_ERR , _ ( " Unauthorized request from %s (%s) " ) , cl - > name , cl - > hostname ) ;
return - 1 ;
}
2000-09-26 14:06:11 +00:00
if ( request_handlers [ request ] ( cl ) )
/* Something went wrong. Probably scriptkiddies. Terminate. */
{
syslog ( LOG_ERR , _ ( " Error while processing %s from %s (%s) " ) ,
request_name [ request ] , cl - > name , cl - > hostname ) ;
return - 1 ;
}
2000-09-10 15:18:03 +00:00
}
2000-09-26 14:06:11 +00:00
else
2000-03-26 00:33:07 +00:00
{
2000-09-26 14:06:11 +00:00
syslog ( LOG_ERR , _ ( " Bogus data received from %s (%s) " ) ,
cl - > name , cl - > hostname ) ;
2000-03-26 00:33:07 +00:00
return - 1 ;
}
2000-10-29 00:02:20 +00:00
cp
return 0 ;
2000-09-10 15:18:03 +00:00
}
/* Connection protocol:
Client Server
2000-09-14 11:54:51 +00:00
send_id ( u )
send_challenge ( R )
2000-09-17 21:42:05 +00:00
send_chal_reply ( H )
send_id ( u )
send_challenge ( R )
send_chal_reply ( H )
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2000-10-29 22:55:15 +00:00
send_metakey ( R )
send_metakey ( R )
2000-09-17 21:42:05 +00:00
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
send_ack ( u )
send_ack ( u )
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Other requests ( E ) . . .
2000-09-14 11:54:51 +00:00
( u ) Unencrypted ,
( R ) RSA ,
( H ) SHA1 ,
2000-09-17 21:42:05 +00:00
( E ) Encrypted with symmetric cipher .
2000-09-14 11:54:51 +00:00
2000-12-05 08:59:30 +00:00
Part of the challenge is directly used to set the symmetric cipher
key and the initial vector . Since a man - in - the - middle cannot
decrypt the RSA challenges , this means that he cannot get or forge
the key for the symmetric cipher .
2000-09-17 21:42:05 +00:00
*/
2000-09-10 15:18:03 +00:00
2000-11-20 19:12:17 +00:00
int send_id ( connection_t * cl )
2000-09-10 15:18:03 +00:00
{
2000-10-16 16:33:30 +00:00
cp
cl - > allow_request = CHALLENGE ;
2000-04-25 18:57:23 +00:00
cp
2000-10-16 19:04:47 +00:00
return send_request ( cl , " %d %s %d %lx %hd " , ID , myself - > name , myself - > protocol_version , myself - > options , myself - > port ) ;
2000-09-10 15:18:03 +00:00
}
2000-11-20 19:12:17 +00:00
int id_h ( connection_t * cl )
2000-09-10 15:18:03 +00:00
{
2000-11-20 19:12:17 +00:00
connection_t * old ;
2000-11-03 22:35:12 +00:00
config_t const * cfg ;
2000-11-22 19:55:53 +00:00
char name [ MAX_STRING_SIZE ] ;
2000-09-10 15:18:03 +00:00
cp
2000-11-22 19:55:53 +00:00
if ( sscanf ( cl - > buffer , " %*d " MAX_STRING " %d %lx %hd " , name , & cl - > protocol_version , & cl - > options , & cl - > port ) ! = 4 )
2000-09-10 15:18:03 +00:00
{
syslog ( LOG_ERR , _ ( " Got bad ID from %s " ) , cl - > hostname ) ;
return - 1 ;
}
2000-09-17 21:42:05 +00:00
2000-09-10 22:49:46 +00:00
/* Check if version matches */
2000-09-17 21:42:05 +00:00
2000-09-14 21:51:21 +00:00
if ( cl - > protocol_version ! = myself - > protocol_version )
2000-09-10 15:18:03 +00:00
{
2000-09-14 21:51:21 +00:00
syslog ( LOG_ERR , _ ( " Peer %s (%s) uses incompatible version %d " ) ,
2000-09-17 21:42:05 +00:00
cl - > name , cl - > hostname , cl - > protocol_version ) ;
2000-09-10 15:18:03 +00:00
return - 1 ;
}
/* Check if identity is a valid name */
2000-09-17 21:42:05 +00:00
2000-11-22 19:55:53 +00:00
if ( check_id ( name ) )
2000-09-10 15:18:03 +00:00
{
syslog ( LOG_ERR , _ ( " Peer %s uses invalid identity name " ) , cl - > hostname ) ;
return - 1 ;
}
2000-11-22 19:55:53 +00:00
/* Copy string to cl */
cl - > name = xstrdup ( name ) ;
2000-09-17 21:42:05 +00:00
2000-09-10 15:18:03 +00:00
/* Load information about peer */
2000-11-22 18:54:08 +00:00
2000-10-16 16:33:30 +00:00
if ( read_host_config ( cl ) )
2000-09-10 15:18:03 +00:00
{
2000-09-14 21:51:21 +00:00
syslog ( LOG_ERR , _ ( " Peer %s had unknown identity (%s) " ) , cl - > hostname , cl - > name ) ;
2000-09-10 15:18:03 +00:00
return - 1 ;
}
/* First check if the host we connected to is already in our
connection list . If so , we are probably making a loop , which
is not desirable .
*/
2000-11-22 18:54:08 +00:00
2000-09-10 15:18:03 +00:00
if ( cl - > status . outgoing )
{
2000-09-14 21:51:21 +00:00
if ( ( old = lookup_id ( cl - > name ) ) )
2000-09-10 15:18:03 +00:00
{
2000-10-21 11:52:08 +00:00
if ( debug_lvl > = DEBUG_CONNECTIONS )
2000-09-14 21:51:21 +00:00
syslog ( LOG_NOTICE , _ ( " Uplink %s (%s) is already in our connection list " ) , cl - > name , cl - > hostname ) ;
2000-09-10 15:18:03 +00:00
cl - > status . outgoing = 0 ;
old - > status . outgoing = 1 ;
terminate_connection ( cl ) ;
return 0 ;
}
}
2000-11-22 18:54:08 +00:00
/* Now we can add the name to the id tree */
id_add ( cl ) ;
/* Read in the public key, so that we can send a challenge */
2000-11-04 22:57:33 +00:00
if ( ( cfg = get_config_val ( cl - > config , config_publickey ) ) )
2000-10-20 15:34:38 +00:00
{
cl - > rsa_key = RSA_new ( ) ;
2000-11-30 23:18:21 +00:00
if ( read_rsa_public_key ( & ( cl - > rsa_key ) , cfg - > data . ptr ) < 0 )
return - 1 ;
2000-10-20 15:34:38 +00:00
}
2000-10-29 00:02:20 +00:00
else
{
syslog ( LOG_ERR , _ ( " No public key known for %s (%s) " ) , cl - > name , cl - > hostname ) ;
return - 1 ;
}
2000-09-10 15:18:03 +00:00
cp
return send_challenge ( cl ) ;
}
2000-11-20 19:12:17 +00:00
int send_challenge ( connection_t * cl )
2000-09-10 15:18:03 +00:00
{
2000-10-20 15:34:38 +00:00
char * buffer ;
int len , x ;
2000-09-10 15:18:03 +00:00
cp
2000-10-20 15:34:38 +00:00
len = RSA_size ( cl - > rsa_key ) ;
2000-09-22 15:06:28 +00:00
/* Allocate buffers for the challenge */
2000-09-10 15:18:03 +00:00
2000-10-20 15:34:38 +00:00
buffer = xmalloc ( len * 2 + 1 ) ;
if ( cl - > hischallenge )
free ( cl - > hischallenge ) ;
cl - > hischallenge = xmalloc ( len ) ;
2000-10-15 00:59:37 +00:00
cp
2000-09-22 15:06:28 +00:00
/* Copy random data to the buffer */
2000-09-14 11:54:51 +00:00
2000-10-20 15:34:38 +00:00
RAND_bytes ( cl - > hischallenge , len ) ;
2000-10-21 11:52:08 +00:00
cl - > hischallenge [ 0 ] & = 0x7F ; /* Somehow if the first byte is more than 0xD0 or something like that, decryption fails... */
if ( debug_lvl > = DEBUG_SCARY_THINGS )
{
bin2hex ( cl - > hischallenge , buffer , len ) ;
buffer [ len * 2 ] = ' \0 ' ;
syslog ( LOG_DEBUG , _ ( " Generated random challenge (unencrypted): %s " ) , buffer ) ;
}
2000-10-20 15:34:38 +00:00
/* Encrypt the random data */
if ( RSA_public_encrypt ( len , cl - > hischallenge , buffer , cl - > rsa_key , RSA_NO_PADDING ) ! = len ) /* NO_PADDING because the message size equals the RSA key size and it is totally random */
{
syslog ( LOG_ERR , _ ( " Error during encryption of challenge for %s (%s) " ) , cl - > name , cl - > hostname ) ;
free ( buffer ) ;
return - 1 ;
}
2000-10-15 00:59:37 +00:00
cp
2000-10-20 15:34:38 +00:00
/* Convert the encrypted random data to a hexadecimal formatted string */
2000-09-10 15:18:03 +00:00
2000-10-20 15:34:38 +00:00
bin2hex ( buffer , buffer , len ) ;
buffer [ len * 2 ] = ' \0 ' ;
2000-09-10 15:18:03 +00:00
/* Send the challenge */
2000-09-17 21:42:05 +00:00
2000-09-10 15:18:03 +00:00
cl - > allow_request = CHAL_REPLY ;
2000-10-20 15:34:38 +00:00
x = send_request ( cl , " %d %s " , CHALLENGE , buffer ) ;
free ( buffer ) ;
2000-09-10 15:18:03 +00:00
cp
2000-10-20 15:34:38 +00:00
return x ;
2000-09-10 15:18:03 +00:00
}
2000-11-20 19:12:17 +00:00
int challenge_h ( connection_t * cl )
2000-09-10 15:18:03 +00:00
{
2000-11-22 19:55:53 +00:00
char buffer [ MAX_STRING_SIZE ] ;
2000-10-20 15:34:38 +00:00
int len ;
2000-09-10 15:18:03 +00:00
cp
2000-11-22 19:55:53 +00:00
if ( sscanf ( cl - > buffer , " %*d " MAX_STRING , buffer ) ! = 1 )
2000-09-10 15:18:03 +00:00
{
2000-09-14 21:51:21 +00:00
syslog ( LOG_ERR , _ ( " Got bad CHALLENGE from %s (%s) " ) , cl - > name , cl - > hostname ) ;
2000-09-10 15:18:03 +00:00
return - 1 ;
}
2000-10-20 15:34:38 +00:00
len = RSA_size ( myself - > rsa_key ) ;
2000-09-10 15:18:03 +00:00
/* Check if the length of the challenge is all right */
2000-10-20 15:34:38 +00:00
if ( strlen ( buffer ) ! = len * 2 )
2000-09-10 15:18:03 +00:00
{
2000-09-14 21:51:21 +00:00
syslog ( LOG_ERR , _ ( " Intruder: wrong challenge length from %s (%s) " ) , cl - > name , cl - > hostname ) ;
2000-09-10 15:18:03 +00:00
return - 1 ;
}
2000-09-22 15:06:28 +00:00
/* Allocate buffers for the challenge */
2000-09-10 15:18:03 +00:00
2000-09-22 15:06:28 +00:00
if ( ! cl - > mychallenge )
2000-10-20 15:34:38 +00:00
cl - > mychallenge = xmalloc ( len ) ;
2000-09-10 15:18:03 +00:00
2000-09-22 15:06:28 +00:00
/* Convert the challenge from hexadecimal back to binary */
2000-09-10 15:18:03 +00:00
2000-10-20 15:34:38 +00:00
hex2bin ( buffer , buffer , len ) ;
/* Decrypt the challenge */
if ( RSA_private_decrypt ( len , buffer , cl - > mychallenge , myself - > rsa_key , RSA_NO_PADDING ) ! = len ) /* See challenge() */
{
syslog ( LOG_ERR , _ ( " Error during encryption of challenge for %s (%s) " ) , cl - > name , cl - > hostname ) ;
return - 1 ;
}
2000-10-21 11:52:08 +00:00
if ( debug_lvl > = DEBUG_SCARY_THINGS )
{
bin2hex ( cl - > mychallenge , buffer , len ) ;
buffer [ len * 2 ] = ' \0 ' ;
syslog ( LOG_DEBUG , _ ( " Received random challenge (unencrypted): %s " ) , buffer ) ;
}
2000-09-22 15:06:28 +00:00
/* Rest is done by send_chal_reply() */
cp
return send_chal_reply ( cl ) ;
}
2000-09-17 21:42:05 +00:00
2000-11-20 19:12:17 +00:00
int send_chal_reply ( connection_t * cl )
2000-09-22 15:06:28 +00:00
{
char hash [ SHA_DIGEST_LENGTH * 2 + 1 ] ;
cp
if ( ! cl - > mychallenge )
2000-09-14 11:54:51 +00:00
{
2000-09-22 15:06:28 +00:00
syslog ( LOG_ERR , _ ( " Trying to send CHAL_REPLY to %s (%s) without a valid CHALLENGE " ) , cl - > name , cl - > hostname ) ;
return - 1 ;
2000-09-14 11:54:51 +00:00
}
2000-09-22 15:06:28 +00:00
/* Calculate the hash from the challenge we received */
2000-09-14 11:54:51 +00:00
2000-10-20 15:34:38 +00:00
SHA1 ( cl - > mychallenge , RSA_size ( myself - > rsa_key ) , hash ) ;
2000-09-10 15:18:03 +00:00
/* Convert the hash to a hexadecimal formatted string */
2000-09-14 21:51:21 +00:00
bin2hex ( hash , hash , SHA_DIGEST_LENGTH ) ;
hash [ SHA_DIGEST_LENGTH * 2 ] = ' \0 ' ;
2000-09-10 15:18:03 +00:00
/* Send the reply */
if ( cl - > status . outgoing )
2000-09-14 21:51:21 +00:00
cl - > allow_request = ID ;
2000-09-10 15:18:03 +00:00
else
2000-10-29 22:55:15 +00:00
cl - > allow_request = METAKEY ;
2000-09-10 15:18:03 +00:00
cp
2000-09-22 15:06:28 +00:00
return send_request ( cl , " %d %s " , CHAL_REPLY , hash ) ;
2000-09-17 21:42:05 +00:00
}
2000-09-10 15:18:03 +00:00
2000-11-20 19:12:17 +00:00
int chal_reply_h ( connection_t * cl )
2000-09-10 15:18:03 +00:00
{
2000-11-22 19:55:53 +00:00
char hishash [ MAX_STRING_SIZE ] ;
2000-09-22 15:06:28 +00:00
char myhash [ SHA_DIGEST_LENGTH ] ;
2000-09-10 15:18:03 +00:00
cp
2000-11-22 19:55:53 +00:00
if ( sscanf ( cl - > buffer , " %*d " MAX_STRING , hishash ) ! = 1 )
2000-09-10 15:18:03 +00:00
{
2000-09-14 21:51:21 +00:00
syslog ( LOG_ERR , _ ( " Got bad CHAL_REPLY from %s (%s) " ) , cl - > name , cl - > hostname ) ;
2000-09-10 15:18:03 +00:00
return - 1 ;
}
/* Check if the length of the hash is all right */
2000-09-17 21:42:05 +00:00
2000-09-22 15:06:28 +00:00
if ( strlen ( hishash ) ! = SHA_DIGEST_LENGTH * 2 )
2000-09-10 15:18:03 +00:00
{
2000-09-14 21:51:21 +00:00
syslog ( LOG_ERR , _ ( " Intruder: wrong challenge reply length from %s (%s) " ) , cl - > name , cl - > hostname ) ;
2000-09-10 15:18:03 +00:00
return - 1 ;
}
2000-09-17 21:42:05 +00:00
2000-09-10 15:18:03 +00:00
/* Convert the hash to binary format */
2000-09-17 21:42:05 +00:00
2000-09-22 15:06:28 +00:00
hex2bin ( hishash , hishash , SHA_DIGEST_LENGTH ) ;
/* Calculate the hash from the challenge we sent */
2000-10-20 15:34:38 +00:00
SHA1 ( cl - > hischallenge , RSA_size ( cl - > rsa_key ) , myhash ) ;
2000-09-17 21:42:05 +00:00
2000-09-10 15:18:03 +00:00
/* Verify the incoming hash with the calculated hash */
2000-09-17 21:42:05 +00:00
2000-10-16 16:33:30 +00:00
if ( memcmp ( hishash , myhash , SHA_DIGEST_LENGTH ) )
2000-09-10 15:18:03 +00:00
{
2000-09-14 21:51:21 +00:00
syslog ( LOG_ERR , _ ( " Intruder: wrong challenge reply from %s (%s) " ) , cl - > name , cl - > hostname ) ;
2000-10-21 11:52:08 +00:00
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 ) ;
}
2000-09-10 15:18:03 +00:00
return - 1 ;
}
2000-10-21 11:52:08 +00:00
2000-09-10 15:18:03 +00:00
/* Identity has now been positively verified.
If we are accepting this new connection , then send our identity ,
if we are making this connecting , acknowledge .
*/
cp
if ( cl - > status . outgoing )
2000-10-29 22:55:15 +00:00
return send_metakey ( cl ) ;
2000-09-10 15:18:03 +00:00
else
return send_id ( cl ) ;
}
2000-11-20 19:12:17 +00:00
int send_metakey ( connection_t * cl )
2000-10-29 22:55:15 +00:00
{
char * buffer ;
int len , x ;
cp
len = RSA_size ( cl - > rsa_key ) ;
/* Allocate buffers for the meta key */
buffer = xmalloc ( len * 2 + 1 ) ;
if ( ! cl - > cipher_outkey )
cl - > cipher_outkey = xmalloc ( len ) ;
if ( ! cl - > cipher_outctx )
cl - > cipher_outctx = xmalloc ( sizeof ( * cl - > cipher_outctx ) ) ;
cp
/* Copy random data to the buffer */
RAND_bytes ( cl - > cipher_outkey , len ) ;
cl - > cipher_outkey [ 0 ] & = 0x7F ; /* FIXME: Somehow if the first byte is more than 0xD0 or something like that, decryption fails... */
if ( debug_lvl > = DEBUG_SCARY_THINGS )
{
bin2hex ( cl - > cipher_outkey , buffer , len ) ;
buffer [ len * 2 ] = ' \0 ' ;
syslog ( LOG_DEBUG , _ ( " Generated random meta key (unencrypted): %s " ) , buffer ) ;
}
/* Encrypt the random data */
if ( RSA_public_encrypt ( len , cl - > cipher_outkey , buffer , cl - > rsa_key , RSA_NO_PADDING ) ! = len ) /* NO_PADDING because the message size equals the RSA key size and it is totally random */
{
syslog ( LOG_ERR , _ ( " Error during encryption of meta key for %s (%s) " ) , cl - > name , cl - > hostname ) ;
free ( buffer ) ;
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 */
if ( cl - > status . outgoing )
cl - > allow_request = METAKEY ;
else
cl - > allow_request = ACK ;
x = send_request ( cl , " %d %s " , METAKEY , buffer ) ;
free ( buffer ) ;
EVP_EncryptInit ( cl - > cipher_outctx , EVP_bf_cfb ( ) , cl - > cipher_outkey , cl - > cipher_outkey + EVP_bf_cfb ( ) - > key_len ) ;
cp
return x ;
}
2000-11-20 19:12:17 +00:00
int metakey_h ( connection_t * cl )
2000-10-29 22:55:15 +00:00
{
2000-11-22 19:55:53 +00:00
char buffer [ MAX_STRING_SIZE ] ;
2000-10-29 22:55:15 +00:00
int len ;
cp
2000-11-22 19:55:53 +00:00
if ( sscanf ( cl - > buffer , " %*d " MAX_STRING , buffer ) ! = 1 )
2000-10-29 22:55:15 +00:00
{
syslog ( LOG_ERR , _ ( " Got bad METAKEY from %s (%s) " ) , cl - > name , cl - > hostname ) ;
return - 1 ;
}
len = RSA_size ( myself - > rsa_key ) ;
/* Check if the length of the meta key is all right */
if ( strlen ( buffer ) ! = len * 2 )
{
syslog ( LOG_ERR , _ ( " Intruder: wrong meta key length from %s (%s) " ) , cl - > name , cl - > hostname ) ;
return - 1 ;
}
/* Allocate buffers for the meta key */
if ( ! cl - > cipher_inkey )
cl - > cipher_inkey = xmalloc ( len ) ;
if ( ! cl - > cipher_inctx )
cl - > cipher_inctx = xmalloc ( sizeof ( * cl - > cipher_inctx ) ) ;
/* Convert the challenge from hexadecimal back to binary */
hex2bin ( buffer , buffer , len ) ;
/* Decrypt the meta key */
if ( RSA_private_decrypt ( len , buffer , cl - > cipher_inkey , myself - > rsa_key , RSA_NO_PADDING ) ! = len ) /* See challenge() */
{
syslog ( LOG_ERR , _ ( " Error during encryption of meta key for %s (%s) " ) , cl - > name , cl - > hostname ) ;
return - 1 ;
}
if ( debug_lvl > = DEBUG_SCARY_THINGS )
{
bin2hex ( cl - > cipher_inkey , buffer , len ) ;
buffer [ len * 2 ] = ' \0 ' ;
syslog ( LOG_DEBUG , _ ( " Received random meta key (unencrypted): %s " ) , buffer ) ;
}
EVP_DecryptInit ( cl - > cipher_inctx , EVP_bf_cfb ( ) , cl - > cipher_inkey , cl - > cipher_inkey + EVP_bf_cfb ( ) - > key_len ) ;
cp
if ( cl - > status . outgoing )
return send_ack ( cl ) ;
else
return send_metakey ( cl ) ;
}
2000-11-20 19:12:17 +00:00
int send_ack ( connection_t * cl )
2000-09-10 15:18:03 +00:00
{
2000-10-29 22:55:15 +00:00
int x ;
2000-10-16 16:33:30 +00:00
cp
2000-10-29 01:08:09 +00:00
if ( cl - > status . outgoing )
cl - > allow_request = ACK ;
2000-10-29 22:55:15 +00:00
x = send_request ( cl , " %d " , ACK ) ;
cl - > status . encryptout = 1 ;
2000-09-10 15:18:03 +00:00
cp
2000-10-29 22:55:15 +00:00
return x ;
2000-09-10 15:18:03 +00:00
}
2000-11-20 19:12:17 +00:00
int ack_h ( connection_t * cl )
2000-09-10 15:18:03 +00:00
{
2000-11-20 19:12:17 +00:00
connection_t * old , * p ;
subnet_t * subnet ;
rbl_t * rbl , * rbl2 ;
2000-09-10 15:18:03 +00:00
cp
/* Okay, before we active the connection, we check if there is another entry
2000-09-22 15:06:28 +00:00
in the connection list with the same name . If so , it presumably is an
2000-09-10 15:18:03 +00:00
old connection that has timed out but we don ' t know it yet .
*/
2000-09-17 21:42:05 +00:00
while ( ( old = lookup_id ( cl - > name ) ) )
2000-09-10 15:18:03 +00:00
{
2000-10-21 11:52:08 +00:00
if ( debug_lvl > = DEBUG_CONNECTIONS )
2000-09-10 15:18:03 +00:00
syslog ( LOG_NOTICE , _ ( " Removing old entry for %s at %s in favour of new connection from %s " ) ,
2000-09-14 21:51:21 +00:00
cl - > name , old - > hostname , cl - > hostname ) ;
2000-10-29 00:02:20 +00:00
2000-09-10 15:18:03 +00:00
terminate_connection ( old ) ;
}
/* Activate this connection */
cl - > allow_request = ALL ;
cl - > status . active = 1 ;
2000-10-29 22:55:15 +00:00
cl - > status . decryptin = 1 ;
2000-10-28 21:05:20 +00:00
cl - > nexthop = cl ;
2000-10-29 22:10:44 +00:00
cl - > cipher_pkttype = EVP_bf_cfb ( ) ;
cl - > cipher_pktkeylength = cl - > cipher_pkttype - > key_len + cl - > cipher_pkttype - > iv_len ;
2000-09-10 15:18:03 +00:00
2000-10-21 11:52:08 +00:00
if ( debug_lvl > = DEBUG_CONNECTIONS )
2000-09-14 21:51:21 +00:00
syslog ( LOG_NOTICE , _ ( " Connection with %s (%s) activated " ) , cl - > name , cl - > hostname ) ;
2000-09-10 15:18:03 +00:00
2000-10-28 21:05:20 +00:00
cp
if ( ! cl - > status . outgoing )
send_ack ( cl ) ;
2000-09-10 15:18:03 +00:00
2000-10-28 21:05:20 +00:00
/* Send him our subnets */
2000-11-20 19:12:17 +00:00
RBL_FOREACH ( myself - > subnet_tree , rbl )
{
subnet = ( subnet_t * ) rbl - > data ;
send_add_subnet ( cl , subnet ) ;
}
2000-10-29 00:02:20 +00:00
/* And send him all the hosts and their subnets we know... */
2000-11-20 19:12:17 +00:00
RBL_FOREACH ( connection_tree , rbl )
{
p = ( connection_t * ) rbl - > data ;
if ( p ! = cl & & p - > status . active )
{
/* Notify others of this connection */
2000-10-29 00:02:20 +00:00
2000-11-20 19:12:17 +00:00
if ( p - > status . meta )
send_add_host ( p , cl ) ;
2000-10-29 00:02:20 +00:00
2000-11-20 19:12:17 +00:00
/* Notify new connection of everything we know */
send_add_host ( cl , p ) ;
RBL_FOREACH ( p - > subnet_tree , rbl2 )
{
subnet = ( subnet_t * ) rbl2 - > data ;
send_add_subnet ( cl , subnet ) ;
}
}
}
2000-09-10 15:18:03 +00:00
cp
2000-10-28 21:05:20 +00:00
return 0 ;
2000-03-26 00:33:07 +00:00
}
2000-09-10 15:18:03 +00:00
/* Address and subnet information exchange */
2000-11-20 19:12:17 +00:00
int send_add_subnet ( connection_t * cl , subnet_t * subnet )
2000-09-10 16:15:35 +00:00
{
2000-09-22 15:06:28 +00:00
int x ;
char * netstr ;
cp
x = send_request ( cl , " %d %s %s " , ADD_SUBNET ,
2000-10-28 21:05:20 +00:00
subnet - > owner - > name , netstr = net2str ( subnet ) ) ;
2000-09-22 15:06:28 +00:00
free ( netstr ) ;
2000-09-10 16:15:35 +00:00
cp
2000-09-22 15:06:28 +00:00
return x ;
2000-09-10 16:15:35 +00:00
}
2000-11-20 19:12:17 +00:00
int add_subnet_h ( connection_t * cl )
2000-09-10 16:15:35 +00:00
{
2000-11-22 19:55:53 +00:00
char subnetstr [ MAX_STRING_SIZE ] ;
char name [ MAX_STRING_SIZE ] ;
2000-11-20 19:12:17 +00:00
connection_t * owner , * p ;
2000-10-29 00:02:20 +00:00
subnet_t * subnet ;
2000-11-20 19:12:17 +00:00
rbl_t * rbl ;
2000-09-17 21:42:05 +00:00
cp
2000-11-22 19:55:53 +00:00
if ( sscanf ( cl - > buffer , " %*d " MAX_STRING " " MAX_STRING , name , subnetstr ) ! = 2 )
2000-09-17 21:42:05 +00:00
{
2000-09-22 15:06:28 +00:00
syslog ( LOG_ERR , _ ( " Got bad ADD_SUBNET from %s (%s) " ) , cl - > name , cl - > hostname ) ;
return - 1 ;
2000-09-17 21:42:05 +00:00
}
/* Check if owner name is a valid */
2000-10-15 00:59:37 +00:00
if ( check_id ( name ) )
2000-09-17 21:42:05 +00:00
{
syslog ( LOG_ERR , _ ( " Got bad ADD_SUBNET from %s (%s): invalid identity name " ) , cl - > name , cl - > hostname ) ;
return - 1 ;
}
/* Check if subnet string is valid */
2000-10-11 22:01:02 +00:00
if ( ! ( subnet = str2net ( subnetstr ) ) )
2000-09-17 21:42:05 +00:00
{
syslog ( LOG_ERR , _ ( " Got bad ADD_SUBNET from %s (%s): invalid subnet string " ) , cl - > name , cl - > hostname ) ;
return - 1 ;
}
2000-09-22 15:06:28 +00:00
2000-09-17 21:42:05 +00:00
/* Check if somebody tries to add a subnet of ourself */
if ( ! strcmp ( name , myself - > name ) )
{
syslog ( LOG_ERR , _ ( " Warning: got ADD_SUBNET from %s (%s) for ourself, restarting " ) ,
cl - > name , cl - > hostname ) ;
sighup = 1 ;
return 0 ;
}
/* Check if the owner of the new subnet is in the connection list */
2000-10-11 22:01:02 +00:00
if ( ! ( owner = lookup_id ( name ) ) )
2000-09-17 21:42:05 +00:00
{
2000-09-22 15:06:28 +00:00
syslog ( LOG_ERR , _ ( " Got ADD_SUBNET for %s from %s (%s) which is not in our connection list " ) ,
2000-09-17 21:42:05 +00:00
name , cl - > name , cl - > hostname ) ;
2000-09-22 15:06:28 +00:00
return - 1 ;
2000-09-17 21:42:05 +00:00
}
2000-09-22 15:06:28 +00:00
/* If everything is correct, add the subnet to the list of the owner */
2000-10-11 22:01:02 +00:00
subnet_add ( owner , subnet ) ;
2000-10-29 00:02:20 +00:00
/* Tell the rest */
2000-11-20 19:12:17 +00:00
RBL_FOREACH ( connection_tree , rbl )
{
p = ( connection_t * ) rbl - > data ;
if ( p - > status . meta & & p - > status . active & & p ! = cl )
send_add_subnet ( p , subnet ) ;
}
2000-09-22 15:06:28 +00:00
cp
2000-10-11 22:01:02 +00:00
return 0 ;
2000-09-10 16:15:35 +00:00
}
2000-11-20 19:12:17 +00:00
int send_del_subnet ( connection_t * cl , subnet_t * subnet )
2000-09-10 16:15:35 +00:00
{
2000-10-28 21:05:20 +00:00
int x ;
char * netstr ;
2000-09-10 16:15:35 +00:00
cp
2000-10-28 21:05:20 +00:00
netstr = net2str ( subnet ) ;
x = send_request ( cl , " %d %s %s " , DEL_SUBNET , subnet - > owner - > name , netstr ) ;
free ( netstr ) ;
cp
return x ;
2000-09-10 16:15:35 +00:00
}
2000-11-20 19:12:17 +00:00
int del_subnet_h ( connection_t * cl )
2000-09-10 16:15:35 +00:00
{
2000-11-22 19:55:53 +00:00
char subnetstr [ MAX_STRING_SIZE ] ;
char name [ MAX_STRING_SIZE ] ;
2000-11-20 19:12:17 +00:00
connection_t * owner , * p ;
2000-10-29 00:02:20 +00:00
subnet_t * subnet ;
2000-11-20 19:12:17 +00:00
rbl_t * rbl ;
2000-09-17 21:42:05 +00:00
cp
2000-11-22 19:55:53 +00:00
if ( sscanf ( cl - > buffer , " %*d " MAX_STRING " " MAX_STRING , name , subnetstr ) ! = 3 )
2000-09-17 21:42:05 +00:00
{
2000-09-22 15:06:28 +00:00
syslog ( LOG_ERR , _ ( " Got bad DEL_SUBNET from %s (%s) " ) , cl - > name , cl - > hostname ) ;
return - 1 ;
2000-09-17 21:42:05 +00:00
}
/* Check if owner name is a valid */
2000-10-15 00:59:37 +00:00
if ( check_id ( name ) )
2000-09-17 21:42:05 +00:00
{
syslog ( LOG_ERR , _ ( " Got bad DEL_SUBNET from %s (%s): invalid identity name " ) , cl - > name , cl - > hostname ) ;
return - 1 ;
}
/* Check if subnet string is valid */
2000-10-11 22:01:02 +00:00
if ( ! ( subnet = str2net ( subnetstr ) ) )
2000-09-17 21:42:05 +00:00
{
syslog ( LOG_ERR , _ ( " Got bad DEL_SUBNET from %s (%s): invalid subnet string " ) , cl - > name , cl - > hostname ) ;
return - 1 ;
}
2000-09-22 15:06:28 +00:00
free ( subnetstr ) ;
/* Check if somebody tries to add a subnet of ourself */
2000-09-17 21:42:05 +00:00
if ( ! strcmp ( name , myself - > name ) )
{
syslog ( LOG_ERR , _ ( " Warning: got DEL_SUBNET from %s (%s) for ourself, restarting " ) ,
cl - > name , cl - > hostname ) ;
sighup = 1 ;
return 0 ;
}
/* Check if the owner of the new subnet is in the connection list */
2000-10-11 22:01:02 +00:00
if ( ! ( owner = lookup_id ( name ) ) )
2000-09-17 21:42:05 +00:00
{
2000-09-22 15:06:28 +00:00
syslog ( LOG_ERR , _ ( " Got DEL_SUBNET for %s from %s (%s) which is not in our connection list " ) ,
2000-09-17 21:42:05 +00:00
name , cl - > name , cl - > hostname ) ;
2000-09-22 15:06:28 +00:00
return - 1 ;
2000-09-17 21:42:05 +00:00
}
2000-09-22 15:06:28 +00:00
2000-10-11 22:01:02 +00:00
/* If everything is correct, delete the subnet from the list of the owner */
subnet_del ( subnet ) ;
2000-10-29 00:02:20 +00:00
/* Tell the rest */
2000-11-20 19:12:17 +00:00
RBL_FOREACH ( connection_tree , rbl )
{
p = ( connection_t * ) rbl - > data ;
if ( p - > status . meta & & p - > status . active & & p ! = cl )
send_del_subnet ( p , subnet ) ;
}
2000-09-22 15:06:28 +00:00
cp
2000-10-11 22:01:02 +00:00
return 0 ;
2000-09-10 16:15:35 +00:00
}
2000-09-10 15:18:03 +00:00
/* New and closed connections notification */
2000-11-20 19:12:17 +00:00
int send_add_host ( connection_t * cl , connection_t * other )
2000-09-10 16:15:35 +00:00
{
cp
2000-10-29 00:02:20 +00:00
return send_request ( cl , " %d %s %lx:%d %lx " , ADD_HOST ,
other - > name , other - > address , other - > port , other - > options ) ;
2000-09-10 16:15:35 +00:00
}
2000-11-20 19:12:17 +00:00
int add_host_h ( connection_t * cl )
2000-09-10 16:15:35 +00:00
{
2000-11-20 19:12:17 +00:00
connection_t * old , * new , * p ;
2000-11-22 19:55:53 +00:00
char name [ MAX_STRING_SIZE ] ;
2000-11-20 19:12:17 +00:00
rbl_t * rbl ;
2000-09-10 22:49:46 +00:00
cp
2000-11-20 19:12:17 +00:00
new = new_connection ( ) ;
2000-09-10 22:49:46 +00:00
2000-11-22 19:55:53 +00:00
if ( sscanf ( cl - > buffer , " %*d " MAX_STRING " %lx:%d %lx " , name , & new - > address , & new - > port , & new - > options ) ! = 4 )
2000-09-10 22:49:46 +00:00
{
2000-09-14 21:51:21 +00:00
syslog ( LOG_ERR , _ ( " Got bad ADD_HOST from %s (%s) " ) , cl - > name , cl - > hostname ) ;
2000-09-10 22:49:46 +00:00
return - 1 ;
2000-09-17 21:42:05 +00:00
}
2000-09-10 22:49:46 +00:00
/* Check if identity is a valid name */
2000-09-17 21:42:05 +00:00
2000-11-22 19:55:53 +00:00
if ( check_id ( name ) )
2000-09-10 22:49:46 +00:00
{
2000-09-14 21:51:21 +00:00
syslog ( LOG_ERR , _ ( " Got bad ADD_HOST from %s (%s): invalid identity name " ) , cl - > name , cl - > hostname ) ;
2000-11-20 19:12:17 +00:00
free_connection ( new ) ;
2000-09-10 22:49:46 +00:00
return - 1 ;
}
2000-09-17 21:42:05 +00:00
2000-09-10 22:49:46 +00:00
/* Check if somebody tries to add ourself */
2000-09-17 21:42:05 +00:00
2000-11-22 22:05:37 +00:00
if ( ! strcmp ( name , myself - > name ) )
2000-09-10 22:49:46 +00:00
{
2000-09-14 21:51:21 +00:00
syslog ( LOG_ERR , _ ( " Warning: got ADD_HOST from %s (%s) for ourself, restarting " ) , cl - > name , cl - > hostname ) ;
2000-09-10 22:49:46 +00:00
sighup = 1 ;
2000-11-20 19:12:17 +00:00
free_connection ( new ) ;
2000-09-10 22:49:46 +00:00
return 0 ;
}
2000-09-22 15:06:28 +00:00
2000-11-20 19:12:17 +00:00
/* Fill in more of the new connection structure */
2000-09-10 22:49:46 +00:00
2000-10-11 22:01:02 +00:00
new - > hostname = hostlookup ( htonl ( new - > address ) ) ;
2000-09-17 21:42:05 +00:00
2000-09-10 22:49:46 +00:00
/* Check if the new host already exists in the connnection list */
2000-11-22 19:55:53 +00:00
if ( ( old = lookup_id ( name ) ) )
2000-09-10 22:49:46 +00:00
{
2000-10-11 22:01:02 +00:00
if ( ( new - > address = = old - > address ) & & ( new - > port = = old - > port ) )
2000-09-10 22:49:46 +00:00
{
2000-10-21 11:52:08 +00:00
if ( debug_lvl > = DEBUG_CONNECTIONS )
2000-09-14 21:51:21 +00:00
syslog ( LOG_NOTICE , _ ( " Got duplicate ADD_HOST for %s (%s) from %s (%s) " ) ,
2000-11-22 19:55:53 +00:00
old - > name , old - > hostname , name , new - > hostname ) ;
2000-11-20 19:12:17 +00:00
free_connection ( new ) ;
2000-09-17 21:42:05 +00:00
return 0 ;
2000-09-10 22:49:46 +00:00
}
else
{
2000-10-21 11:52:08 +00:00
if ( debug_lvl > = DEBUG_CONNECTIONS )
2000-10-29 00:02:20 +00:00
syslog ( LOG_NOTICE , _ ( " Removing old entry for %s (%s) in favour of new connection " ) ,
2000-09-17 21:42:05 +00:00
old - > name , old - > hostname ) ;
2000-10-29 00:02:20 +00:00
2000-09-10 22:49:46 +00:00
terminate_connection ( old ) ;
}
}
2000-11-20 19:12:17 +00:00
/* Hook it up into the connection */
2000-10-29 00:02:20 +00:00
2000-11-22 19:55:53 +00:00
new - > name = xstrdup ( name ) ;
2000-11-20 19:12:17 +00:00
connection_add ( new ) ;
2000-11-22 18:54:08 +00:00
id_add ( new ) ;
2000-10-29 00:02:20 +00:00
/* Tell the rest about the new host */
2000-11-20 19:12:17 +00:00
RBL_FOREACH ( connection_tree , rbl )
{
p = ( connection_t * ) rbl - > data ;
if ( p - > status . meta & & p - > status . active & & p ! = cl )
send_add_host ( p , new ) ;
}
2000-10-29 00:02:20 +00:00
2000-11-20 19:12:17 +00:00
/* Fill in rest of connection structure */
2000-09-10 22:49:46 +00:00
2000-10-28 21:05:20 +00:00
new - > nexthop = cl ;
2000-09-10 22:49:46 +00:00
new - > status . active = 1 ;
2000-11-04 16:39:19 +00:00
new - > cipher_pkttype = EVP_bf_cfb ( ) ;
new - > cipher_pktkeylength = cl - > cipher_pkttype - > key_len + cl - > cipher_pkttype - > iv_len ;
2000-09-10 22:49:46 +00:00
cp
return 0 ;
2000-09-10 16:15:35 +00:00
}
2000-11-20 19:12:17 +00:00
int send_del_host ( connection_t * cl , connection_t * other )
2000-09-10 16:15:35 +00:00
{
2000-09-22 15:06:28 +00:00
cp
2000-10-29 00:02:20 +00:00
return send_request ( cl , " %d %s %lx:%d %lx " , DEL_HOST ,
other - > name , other - > address , other - > port , other - > options ) ;
2000-09-10 16:15:35 +00:00
}
2000-11-20 19:12:17 +00:00
int del_host_h ( connection_t * cl )
2000-09-10 16:15:35 +00:00
{
2000-11-22 19:55:53 +00:00
char name [ MAX_STRING_SIZE ] ;
2000-09-10 22:49:46 +00:00
ip_t address ;
port_t port ;
2000-10-29 00:02:20 +00:00
long int options ;
2000-11-20 19:12:17 +00:00
connection_t * old , * p ;
rbl_t * rbl ;
2000-09-10 22:49:46 +00:00
cp
2000-11-22 19:55:53 +00:00
if ( sscanf ( cl - > buffer , " %*d " MAX_STRING " %lx:%d %lx " , name , & address , & port , & options ) ! = 4 )
2000-09-10 22:49:46 +00:00
{
2000-09-14 21:51:21 +00:00
syslog ( LOG_ERR , _ ( " Got bad DEL_HOST from %s (%s) " ) ,
2000-09-17 21:42:05 +00:00
cl - > name , cl - > hostname ) ;
2000-09-14 21:51:21 +00:00
return - 1 ;
2000-09-17 21:42:05 +00:00
}
2000-09-10 22:49:46 +00:00
2000-09-22 15:06:28 +00:00
/* Check if identity is a valid name */
2000-10-29 00:02:20 +00:00
if ( check_id ( name ) )
2000-09-22 15:06:28 +00:00
{
syslog ( LOG_ERR , _ ( " Got bad DEL_HOST from %s (%s): invalid identity name " ) , cl - > name , cl - > hostname ) ;
return - 1 ;
}
2000-09-10 22:49:46 +00:00
/* Check if somebody tries to delete ourself */
2000-09-17 21:42:05 +00:00
2000-09-22 15:06:28 +00:00
if ( ! strcmp ( name , myself - > name ) )
2000-09-10 22:49:46 +00:00
{
2000-09-14 21:51:21 +00:00
syslog ( LOG_ERR , _ ( " Warning: got DEL_HOST from %s (%s) for ourself, restarting " ) ,
2000-09-17 21:42:05 +00:00
cl - > name , cl - > hostname ) ;
2000-09-22 15:06:28 +00:00
sighup = 1 ;
return 0 ;
}
2000-09-10 22:49:46 +00:00
2000-09-22 15:06:28 +00:00
/* Check if the new host already exists in the connnection list */
if ( ! ( old = lookup_id ( name ) ) )
2000-09-10 22:49:46 +00:00
{
2000-09-22 15:06:28 +00:00
syslog ( LOG_ERR , _ ( " Got DEL_HOST from %s (%s) for %s which is not in our connection list " ) ,
name , cl - > name , cl - > hostname ) ;
return - 1 ;
2000-09-10 22:49:46 +00:00
}
2000-09-22 15:06:28 +00:00
/* Check if the rest matches */
2000-10-29 00:02:20 +00:00
if ( address ! = old - > address | | port ! = old - > port | | options ! = old - > options | | cl ! = old - > nexthop )
2000-09-22 15:06:28 +00:00
{
syslog ( LOG_WARNING , _ ( " Got DEL_HOST from %s (%s) for %s which doesn't match " ) , cl - > name , cl - > hostname , old - > name ) ;
return 0 ;
}
/* Ok, since EVERYTHING seems to check out all right, delete it */
old - > status . active = 0 ;
terminate_connection ( old ) ;
2000-10-29 00:02:20 +00:00
/* Tell the rest about the new host */
2000-11-20 19:12:17 +00:00
RBL_FOREACH ( connection_tree , rbl )
{
p = ( connection_t * ) rbl - > data ;
if ( p - > status . meta & & p - > status . active & & p ! = cl )
send_del_host ( p , old ) ;
}
2000-09-10 22:49:46 +00:00
cp
return 0 ;
2000-09-10 16:15:35 +00:00
}
2000-09-10 15:18:03 +00:00
/* Status and error notification routines */
2000-11-20 19:12:17 +00:00
int send_status ( connection_t * cl , int statusno , char * statusstring )
2000-09-10 15:18:03 +00:00
{
2000-09-10 16:15:35 +00:00
cp
if ( ! statusstring )
statusstring = status_text [ statusno ] ;
2000-09-10 15:18:03 +00:00
cp
return send_request ( cl , " %d %d %s " , STATUS , statusno , statusstring ) ;
}
2000-11-20 19:12:17 +00:00
int status_h ( connection_t * cl )
2000-09-10 16:15:35 +00:00
{
int statusno ;
2000-11-22 19:55:53 +00:00
char statusstring [ MAX_STRING_SIZE ] ;
2000-09-10 16:15:35 +00:00
cp
2000-11-22 19:55:53 +00:00
if ( sscanf ( cl - > buffer , " %*d %d " MAX_STRING , & statusno , statusstring ) ! = 2 )
2000-09-10 16:15:35 +00:00
{
2000-09-15 12:58:40 +00:00
syslog ( LOG_ERR , _ ( " Got bad STATUS from %s (%s) " ) ,
2000-09-17 21:42:05 +00:00
cl - > name , cl - > hostname ) ;
2000-09-10 16:15:35 +00:00
return - 1 ;
}
2000-10-21 11:52:08 +00:00
if ( debug_lvl > = DEBUG_STATUS )
2000-09-10 16:15:35 +00:00
{
2000-09-14 21:51:21 +00:00
syslog ( LOG_NOTICE , _ ( " Status message from %s (%s): %s: %s " ) ,
2000-09-17 21:42:05 +00:00
cl - > name , cl - > hostname , status_text [ statusno ] , statusstring ) ;
2000-09-10 16:15:35 +00:00
}
cp
return 0 ;
}
2000-11-20 19:12:17 +00:00
int send_error ( connection_t * cl , int errno , char * errstring )
2000-09-10 15:18:03 +00:00
{
cp
2000-09-14 21:51:21 +00:00
if ( ! errstring )
2000-09-15 12:58:40 +00:00
errstring = strerror ( errno ) ;
2000-09-10 15:18:03 +00:00
return send_request ( cl , " %d %d %s " , ERROR , errno , errstring ) ;
}
2000-11-20 19:12:17 +00:00
int error_h ( connection_t * cl )
2000-09-10 16:15:35 +00:00
{
int errno ;
2000-11-22 19:55:53 +00:00
char errorstring [ MAX_STRING_SIZE ] ;
2000-09-10 16:15:35 +00:00
cp
2000-11-22 19:55:53 +00:00
if ( sscanf ( cl - > buffer , " %*d %d " MAX_STRING , & errno , errorstring ) ! = 2 )
2000-09-10 16:15:35 +00:00
{
2000-10-15 00:59:37 +00:00
syslog ( LOG_ERR , _ ( " Got bad ERROR from %s (%s) " ) ,
2000-09-17 21:42:05 +00:00
cl - > name , cl - > hostname ) ;
2000-09-10 16:15:35 +00:00
return - 1 ;
}
2000-10-21 11:52:08 +00:00
if ( debug_lvl > = DEBUG_ERROR )
2000-09-10 16:15:35 +00:00
{
2000-09-14 21:51:21 +00:00
syslog ( LOG_NOTICE , _ ( " Error message from %s (%s): %s: %s " ) ,
2000-09-17 21:42:05 +00:00
cl - > name , cl - > hostname , strerror ( errno ) , errorstring ) ;
2000-09-10 16:15:35 +00:00
}
2000-09-10 22:49:46 +00:00
terminate_connection ( cl ) ;
cp
2000-09-10 16:15:35 +00:00
return 0 ;
}
2000-11-20 19:12:17 +00:00
int send_termreq ( connection_t * cl )
2000-09-10 16:15:35 +00:00
{
2000-09-10 22:49:46 +00:00
cp
return send_request ( cl , " %d " , TERMREQ ) ;
2000-09-10 16:15:35 +00:00
}
2000-11-20 19:12:17 +00:00
int termreq_h ( connection_t * cl )
2000-09-10 16:15:35 +00:00
{
2000-09-10 22:49:46 +00:00
cp
terminate_connection ( cl ) ;
cp
return 0 ;
2000-09-10 16:15:35 +00:00
}
2000-09-10 22:49:46 +00:00
/* Keepalive routines - FIXME: needs a closer look */
2000-09-10 16:15:35 +00:00
2000-11-20 19:12:17 +00:00
int send_ping ( connection_t * cl )
2000-09-10 16:15:35 +00:00
{
2000-11-04 20:44:28 +00:00
cp
2000-09-10 22:49:46 +00:00
cl - > status . pinged = 1 ;
2000-11-04 20:44:28 +00:00
cl - > last_ping_time = time ( NULL ) ;
2000-09-10 16:15:35 +00:00
cp
2000-09-10 22:49:46 +00:00
return send_request ( cl , " %d " , PING ) ;
2000-09-10 16:15:35 +00:00
}
2000-11-20 19:12:17 +00:00
int ping_h ( connection_t * cl )
2000-09-10 16:15:35 +00:00
{
2000-09-10 22:49:46 +00:00
cp
return send_pong ( cl ) ;
2000-09-10 16:15:35 +00:00
}
2000-11-20 19:12:17 +00:00
int send_pong ( connection_t * cl )
2000-09-10 16:15:35 +00:00
{
cp
2000-09-10 22:49:46 +00:00
return send_request ( cl , " %d " , PONG ) ;
2000-09-10 16:15:35 +00:00
}
2000-11-20 19:12:17 +00:00
int pong_h ( connection_t * cl )
2000-09-10 16:15:35 +00:00
{
cp
2000-11-04 20:44:28 +00:00
cl - > status . pinged = 0 ;
2000-09-10 22:49:46 +00:00
cp
return 0 ;
2000-09-10 16:15:35 +00:00
}
2000-09-10 22:49:46 +00:00
/* Key exchange */
2000-09-10 16:15:35 +00:00
2000-11-20 19:12:17 +00:00
int send_key_changed ( connection_t * from , connection_t * cl )
2000-03-26 00:33:07 +00:00
{
2000-11-20 19:12:17 +00:00
connection_t * p ;
rbl_t * rbl ;
2000-04-25 18:57:23 +00:00
cp
2000-11-20 19:12:17 +00:00
RBL_FOREACH ( connection_tree , rbl )
2000-03-26 00:33:07 +00:00
{
2000-11-20 19:12:17 +00:00
p = ( connection_t * ) rbl - > data ;
if ( p ! = cl & & p - > status . meta & & p - > status . active )
send_request ( p , " %d %s " , KEY_CHANGED , from - > name ) ;
2000-03-26 00:33:07 +00:00
}
2000-04-25 18:57:23 +00:00
cp
2000-03-26 00:33:07 +00:00
return 0 ;
}
2000-11-20 19:12:17 +00:00
int key_changed_h ( connection_t * cl )
2000-03-26 00:33:07 +00:00
{
2000-11-22 19:55:53 +00:00
char from_id [ MAX_STRING_SIZE ] ;
2000-11-20 19:12:17 +00:00
connection_t * from ;
2000-04-25 18:57:23 +00:00
cp
2000-11-22 19:55:53 +00:00
if ( sscanf ( cl - > buffer , " %*d " MAX_STRING , from_id ) ! = 1 )
2000-09-10 22:49:46 +00:00
{
2000-09-14 21:51:21 +00:00
syslog ( LOG_ERR , _ ( " Got bad KEY_CHANGED from %s (%s) " ) ,
2000-09-17 21:42:05 +00:00
cl - > name , cl - > hostname ) ;
2000-09-14 21:51:21 +00:00
return - 1 ;
2000-09-17 21:42:05 +00:00
}
2000-05-01 18:07:12 +00:00
2000-09-10 22:49:46 +00:00
if ( ! ( from = lookup_id ( from_id ) ) )
2000-03-26 00:33:07 +00:00
{
2000-09-15 12:58:40 +00:00
syslog ( LOG_ERR , _ ( " Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list " ) ,
2000-09-17 21:42:05 +00:00
cl - > name , cl - > hostname , from_id ) ;
2000-03-26 00:33:07 +00:00
return - 1 ;
}
2000-09-10 23:11:37 +00:00
2000-09-10 22:49:46 +00:00
from - > status . validkey = 0 ;
from - > status . waitingforkey = 0 ;
2000-09-17 21:42:05 +00:00
2000-09-10 22:49:46 +00:00
send_key_changed ( from , cl ) ;
2000-04-25 18:57:23 +00:00
cp
2000-03-26 00:33:07 +00:00
return 0 ;
}
2000-09-17 21:42:05 +00:00
2000-11-20 19:12:17 +00:00
int send_req_key ( connection_t * from , connection_t * to )
2000-03-26 00:33:07 +00:00
{
2000-04-25 18:57:23 +00:00
cp
2000-09-15 12:58:40 +00:00
return send_request ( to - > nexthop , " %d %s %s " , REQ_KEY ,
2000-09-17 21:42:05 +00:00
from - > name , to - > name ) ;
2000-03-26 00:33:07 +00:00
}
2000-11-20 19:12:17 +00:00
int req_key_h ( connection_t * cl )
2000-08-07 14:52:16 +00:00
{
2000-11-22 19:55:53 +00:00
char from_id [ MAX_STRING_SIZE ] ;
char to_id [ MAX_STRING_SIZE ] ;
2000-11-20 19:12:17 +00:00
connection_t * from , * to ;
2000-10-29 10:39:08 +00:00
char pktkey [ 129 ] ;
2000-08-07 14:52:16 +00:00
cp
2000-11-22 19:55:53 +00:00
if ( sscanf ( cl - > buffer , " %*d " MAX_STRING " " MAX_STRING , from_id , to_id ) ! = 2 )
2000-08-07 14:52:16 +00:00
{
2000-09-15 12:58:40 +00:00
syslog ( LOG_ERR , _ ( " Got bad REQ_KEY from %s (%s) " ) ,
2000-09-17 21:42:05 +00:00
cl - > name , cl - > hostname ) ;
2000-09-10 22:49:46 +00:00
return - 1 ;
2000-09-17 21:42:05 +00:00
}
2000-09-10 22:49:46 +00:00
if ( ! ( from = lookup_id ( from_id ) ) )
2000-08-07 14:52:16 +00:00
{
2000-09-15 12:58:40 +00:00
syslog ( LOG_ERR , _ ( " Got REQ_KEY from %s (%s) origin %s which does not exist in our connection list " ) ,
2000-09-17 21:42:05 +00:00
cl - > name , cl - > hostname , from_id ) ;
2000-08-07 14:52:16 +00:00
return - 1 ;
}
2000-03-26 00:33:07 +00:00
2000-09-10 22:49:46 +00:00
/* Check if this key request is for us */
2000-05-01 18:07:12 +00:00
2000-09-15 12:58:40 +00:00
if ( ! strcmp ( to_id , myself - > name ) )
2000-03-26 00:33:07 +00:00
{
2000-10-29 22:10:44 +00:00
bin2hex ( myself - > cipher_pktkey , pktkey , myself - > cipher_pktkeylength ) ;
pktkey [ myself - > cipher_pktkeylength * 2 ] = ' \0 ' ;
2000-10-29 10:39:08 +00:00
send_ans_key ( myself , from , pktkey ) ;
2000-03-26 00:33:07 +00:00
}
2000-09-10 22:49:46 +00:00
else
{
if ( ! ( to = lookup_id ( to_id ) ) )
{
2000-09-15 12:58:40 +00:00
syslog ( LOG_ERR , _ ( " Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list " ) ,
2000-09-17 21:42:05 +00:00
cl - > name , cl - > hostname , to_id ) ;
2000-09-10 22:49:46 +00:00
return - 1 ;
}
2000-10-29 22:10:44 +00:00
if ( to - > status . validkey ) /* Proxy keys */
{
bin2hex ( to - > cipher_pktkey , pktkey , to - > cipher_pktkeylength ) ;
pktkey [ to - > cipher_pktkeylength * 2 ] = ' \0 ' ;
send_ans_key ( to , from , pktkey ) ;
}
else
send_req_key ( from , to ) ;
2000-09-10 22:49:46 +00:00
}
2000-04-25 18:57:23 +00:00
cp
2000-03-26 00:33:07 +00:00
return 0 ;
}
2000-11-20 19:12:17 +00:00
int send_ans_key ( connection_t * from , connection_t * to , char * pktkey )
2000-03-26 00:33:07 +00:00
{
2000-04-25 18:57:23 +00:00
cp
2000-09-15 12:58:40 +00:00
return send_request ( to - > nexthop , " %d %s %s %s " , ANS_KEY ,
2000-10-14 17:04:16 +00:00
from - > name , to - > name , pktkey ) ;
2000-03-26 00:33:07 +00:00
}
2000-11-20 19:12:17 +00:00
int ans_key_h ( connection_t * cl )
2000-03-26 00:33:07 +00:00
{
2000-11-22 19:55:53 +00:00
char from_id [ MAX_STRING_SIZE ] ;
char to_id [ MAX_STRING_SIZE ] ;
char pktkey [ MAX_STRING_SIZE ] ;
2000-09-10 23:11:37 +00:00
int keylength ;
2000-11-20 19:12:17 +00:00
connection_t * from , * to ;
2000-04-25 18:57:23 +00:00
cp
2000-11-22 19:55:53 +00:00
if ( sscanf ( cl - > buffer , " %*d " MAX_STRING " " MAX_STRING " " MAX_STRING , from_id , to_id , pktkey ) ! = 3 )
2000-06-23 19:27:03 +00:00
{
2000-09-15 12:58:40 +00:00
syslog ( LOG_ERR , _ ( " Got bad ANS_KEY from %s (%s) " ) ,
2000-09-17 21:42:05 +00:00
cl - > name , cl - > hostname ) ;
2000-09-10 22:49:46 +00:00
return - 1 ;
2000-09-17 21:42:05 +00:00
}
2000-05-01 18:07:12 +00:00
2000-09-10 22:49:46 +00:00
if ( ! ( from = lookup_id ( from_id ) ) )
2000-03-26 00:33:07 +00:00
{
2000-09-15 12:58:40 +00:00
syslog ( LOG_ERR , _ ( " Got ANS_KEY from %s (%s) origin %s which does not exist in our connection list " ) ,
2000-09-17 21:42:05 +00:00
cl - > name , cl - > hostname , from_id ) ;
2000-03-26 00:33:07 +00:00
return - 1 ;
}
2000-11-04 16:54:21 +00:00
/* Check correctness of packet key */
2000-05-01 18:07:12 +00:00
2000-10-29 10:39:08 +00:00
keylength = strlen ( pktkey ) ;
2000-09-17 21:42:05 +00:00
2000-10-29 22:10:44 +00:00
if ( keylength ! = from - > cipher_pktkeylength * 2 )
2000-10-29 10:39:08 +00:00
{
2000-10-29 22:10:44 +00:00
syslog ( LOG_ERR , _ ( " Got bad ANS_KEY from %s (%s) origin %s: invalid key length " ) ,
2000-10-29 10:39:08 +00:00
cl - > name , cl - > hostname , from - > name ) ;
return - 1 ;
}
2000-10-29 09:19:27 +00:00
2000-11-04 16:54:21 +00:00
/* Forward it if necessary */
2000-10-29 09:19:27 +00:00
2000-10-29 10:39:08 +00:00
if ( strcmp ( to_id , myself - > name ) )
2000-09-10 22:49:46 +00:00
{
if ( ! ( to = lookup_id ( to_id ) ) )
{
2000-09-15 12:58:40 +00:00
syslog ( LOG_ERR , _ ( " Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list " ) ,
2000-09-17 21:42:05 +00:00
cl - > name , cl - > hostname , to_id ) ;
2000-09-10 22:49:46 +00:00
return - 1 ;
}
2000-10-14 17:04:16 +00:00
send_ans_key ( from , to , pktkey ) ;
2000-03-26 00:33:07 +00:00
}
2000-09-10 22:49:46 +00:00
2000-11-04 16:54:21 +00:00
/* Update our copy of the origin's packet key */
if ( from - > cipher_pktkey )
free ( from - > cipher_pktkey ) ;
2000-11-22 19:55:53 +00:00
from - > cipher_pktkey = xstrdup ( pktkey ) ;
2000-11-04 16:54:21 +00:00
keylength / = 2 ;
2000-11-22 20:25:27 +00:00
hex2bin ( from - > cipher_pktkey , from - > cipher_pktkey , keylength ) ;
from - > cipher_pktkey [ keylength ] = ' \0 ' ;
2000-11-04 16:54:21 +00:00
from - > status . validkey = 1 ;
from - > status . waitingforkey = 0 ;
2000-04-25 18:57:23 +00:00
cp
2000-03-26 00:33:07 +00:00
return 0 ;
}
2000-09-22 16:20:07 +00:00
/* Jumptable for the request handlers */
2000-09-10 15:18:03 +00:00
2000-11-20 19:12:17 +00:00
int ( * request_handlers [ ] ) ( connection_t * ) = {
2000-10-29 22:55:15 +00:00
id_h , challenge_h , chal_reply_h , metakey_h , ack_h ,
2000-09-10 16:15:35 +00:00
status_h , error_h , termreq_h ,
ping_h , pong_h ,
2000-09-10 22:49:46 +00:00
add_host_h , del_host_h ,
add_subnet_h , del_subnet_h ,
key_changed_h , req_key_h , ans_key_h ,
2000-09-10 15:18:03 +00:00
} ;
2000-09-22 16:20:07 +00:00
/* Request names */
2000-09-10 16:15:35 +00:00
char ( * request_name [ ] ) = {
2000-10-29 22:55:15 +00:00
" ID " , " CHALLENGE " , " CHAL_REPLY " , " METAKEY " , " ACK " ,
2000-09-10 16:15:35 +00:00
" STATUS " , " ERROR " , " TERMREQ " ,
" PING " , " PONG " ,
2000-09-10 22:49:46 +00:00
" ADD_HOST " , " DEL_HOST " ,
" ADD_SUBNET " , " DEL_SUBNET " ,
" KEY_CHANGED " , " REQ_KEY " , " ANS_KEY " ,
2000-03-26 00:33:07 +00:00
} ;
2000-10-14 17:04:16 +00:00
/* Status strings */
char ( * status_text [ ] ) = {
2000-10-16 16:33:30 +00:00
" Warning " ,
2000-10-14 17:04:16 +00:00
} ;
/* Error strings */
char ( * error_text [ ] ) = {
2000-10-16 16:33:30 +00:00
" Error " ,
2000-10-14 17:04:16 +00:00
} ;