2002-02-11 10:05:58 +00:00
/*
protocol_auth . c - - handle the meta - protocol , authentication
2006-04-26 13:52:58 +00:00
Copyright ( C ) 1999 - 2005 Ivo Timmermans ,
2010-02-02 21:49:21 +00:00
2000 - 2010 Guus Sliepen < guus @ tinc - vpn . org >
2002-02-11 10:05:58 +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 .
2009-09-24 22:01:00 +00:00
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 . ,
51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
2002-02-11 10:05:58 +00:00
*/
2003-07-17 15:06:27 +00:00
# include "system.h"
2002-02-11 10:05:58 +00:00
2007-05-18 10:05:26 +00:00
# include "splay_tree.h"
2002-02-11 10:05:58 +00:00
# include "conf.h"
# include "connection.h"
2009-11-07 22:43:25 +00:00
# include "control.h"
# include "control_common.h"
2011-07-07 20:30:55 +00:00
# include "cipher.h"
2008-12-11 14:44:44 +00:00
# include "crypto.h"
2011-07-07 20:30:55 +00:00
# include "digest.h"
2002-09-04 13:48:52 +00:00
# include "edge.h"
# include "graph.h"
2003-07-06 22:11:37 +00:00
# include "logger.h"
2003-07-17 15:06:27 +00:00
# include "net.h"
# include "netutl.h"
# include "node.h"
2011-07-07 20:30:55 +00:00
# include "prf.h"
2003-07-17 15:06:27 +00:00
# include "protocol.h"
2008-12-11 14:44:44 +00:00
# include "rsa.h"
2003-07-17 15:06:27 +00:00
# include "utils.h"
# include "xalloc.h"
2002-02-11 10:05:58 +00:00
2007-05-18 10:00:00 +00:00
bool send_id ( connection_t * c ) {
2007-10-19 18:53:48 +00:00
gettimeofday ( & c - > start , NULL ) ;
2011-07-11 19:54:01 +00:00
int minor = 0 ;
2011-07-10 20:34:17 +00:00
2011-07-11 19:54:01 +00:00
if ( experimental ) {
if ( c - > config_tree & & ! read_ecdsa_public_key ( c ) )
minor = 1 ;
else
minor = myself - > connection - > protocol_minor ;
}
return send_request ( c , " %d %s %d.%d " , ID , myself - > connection - > name , myself - > connection - > protocol_major , minor ) ;
2002-02-11 10:05:58 +00:00
}
2007-05-19 22:23:02 +00:00
bool id_h ( connection_t * c , char * request ) {
2002-09-09 21:25:28 +00:00
char name [ MAX_STRING_SIZE ] ;
2011-07-05 19:19:48 +00:00
if ( sscanf ( request , " %*d " MAX_STRING " %d.%d " , name , & c - > protocol_major , & c - > protocol_minor ) < 2 ) {
2009-09-24 22:54:07 +00:00
logger ( LOG_ERR , " Got bad %s from %s (%s) " , " ID " , c - > name ,
2002-09-09 21:25:28 +00:00
c - > hostname ) ;
2003-07-22 20:55:21 +00:00
return false ;
2002-09-09 21:25:28 +00:00
}
2009-11-07 22:43:25 +00:00
/* Check if this is a control connection */
if ( name [ 0 ] = = ' ^ ' & & ! strcmp ( name + 1 , controlcookie ) ) {
c - > status . control = true ;
c - > allow_request = CONTROL ;
c - > last_ping_time = time ( NULL ) + 3600 ;
return send_request ( c , " %d %d %d " , ACK , TINC_CTL_VERSION_CURRENT , getpid ( ) ) ;
}
2002-09-09 21:25:28 +00:00
/* Check if identity is a valid name */
2003-07-22 20:55:21 +00:00
if ( ! check_id ( name ) ) {
2009-09-24 22:54:07 +00:00
logger ( LOG_ERR , " Got bad %s from %s (%s): %s " , " ID " , c - > name ,
2002-09-09 21:25:28 +00:00
c - > hostname , " invalid name " ) ;
2003-07-22 20:55:21 +00:00
return false ;
2002-09-09 21:25:28 +00:00
}
2007-05-17 19:15:48 +00:00
/* If this is an outgoing connection, make sure we are connected to the right host */
2002-09-09 21:25:28 +00:00
2007-05-17 19:15:48 +00:00
if ( c - > outgoing ) {
2002-09-09 21:25:28 +00:00
if ( strcmp ( c - > name , name ) ) {
2009-09-24 22:54:07 +00:00
logger ( LOG_ERR , " Peer %s is %s instead of %s " , c - > hostname , name ,
2002-09-09 21:25:28 +00:00
c - > name ) ;
2003-07-22 20:55:21 +00:00
return false ;
2002-09-09 21:25:28 +00:00
}
2005-05-04 15:51:45 +00:00
} else {
if ( c - > name )
free ( c - > name ) ;
2002-09-09 21:25:28 +00:00
c - > name = xstrdup ( name ) ;
2005-05-04 15:51:45 +00:00
}
2002-09-09 21:25:28 +00:00
/* Check if version matches */
2011-07-05 19:19:48 +00:00
if ( c - > protocol_major ! = myself - > connection - > protocol_major ) {
logger ( LOG_ERR , " Peer %s (%s) uses incompatible version %d.%d " ,
c - > name , c - > hostname , c - > protocol_major , c - > protocol_minor ) ;
2003-07-22 20:55:21 +00:00
return false ;
2002-09-09 21:25:28 +00:00
}
if ( bypass_security ) {
if ( ! c - > config_tree )
init_configuration ( & c - > config_tree ) ;
c - > allow_request = ACK ;
return send_ack ( c ) ;
}
if ( ! c - > config_tree ) {
init_configuration ( & c - > config_tree ) ;
2003-07-22 20:55:21 +00:00
if ( ! read_connection_config ( c ) ) {
2009-09-24 22:54:07 +00:00
logger ( LOG_ERR , " Peer %s had unknown identity (%s) " , c - > hostname ,
2002-09-09 21:25:28 +00:00
c - > name ) ;
2003-07-22 20:55:21 +00:00
return false ;
2002-09-09 21:25:28 +00:00
}
2011-07-10 20:34:17 +00:00
2011-07-11 19:54:01 +00:00
if ( experimental & & c - > protocol_minor > = 2 )
2011-07-10 20:34:17 +00:00
if ( ! read_ecdsa_public_key ( c ) )
return false ;
} else {
if ( ! ecdsa_active ( & c - > ecdsa ) )
c - > protocol_minor = 1 ;
2002-09-09 21:25:28 +00:00
}
2011-07-11 19:54:01 +00:00
if ( ! experimental )
c - > protocol_minor = 0 ;
2011-07-07 20:30:55 +00:00
c - > allow_request = METAKEY ;
if ( c - > protocol_minor > = 2 )
return send_metakey_ec ( c ) ;
else
return send_metakey ( c ) ;
}
bool send_metakey_ec ( connection_t * c ) {
logger ( LOG_DEBUG , " Sending ECDH metakey to %s " , c - > name ) ;
size_t siglen = ecdsa_size ( & myself - > connection - > ecdsa ) ;
2011-07-12 21:43:12 +00:00
char key [ ( ECDH_SIZE + siglen ) * 2 + 1 ] ;
2002-09-09 21:25:28 +00:00
2011-07-07 20:30:55 +00:00
// TODO: include nonce? Use relevant parts of SSH or TLS protocol
if ( ! ecdh_generate_public ( & c - > ecdh , key ) )
return false ;
2011-07-12 21:43:12 +00:00
if ( ! ecdsa_sign ( & myself - > connection - > ecdsa , key , ECDH_SIZE , key + ECDH_SIZE ) )
2011-07-07 20:30:55 +00:00
return false ;
2011-07-12 21:43:12 +00:00
b64encode ( key , key , ECDH_SIZE + siglen ) ;
2011-07-07 20:30:55 +00:00
2011-07-13 20:52:52 +00:00
return send_request ( c , " %d %s " , METAKEY , key ) ;
2002-02-11 10:05:58 +00:00
}
2007-05-18 10:00:00 +00:00
bool send_metakey ( connection_t * c ) {
2011-07-07 20:30:55 +00:00
if ( ! read_rsa_public_key ( c ) )
return false ;
2008-12-11 14:44:44 +00:00
if ( ! cipher_open_blowfish_ofb ( & c - > outcipher ) )
return false ;
2005-06-03 10:16:03 +00:00
2009-06-06 17:04:04 +00:00
if ( ! digest_open_sha1 ( & c - > outdigest , - 1 ) )
2008-12-11 14:44:44 +00:00
return false ;
2002-09-09 21:25:28 +00:00
2011-07-10 20:34:17 +00:00
size_t len = rsa_size ( & c - > rsa ) ;
char key [ len ] ;
char enckey [ len ] ;
char hexkey [ 2 * len + 1 ] ;
2008-12-11 14:44:44 +00:00
/* Create a random key */
2002-09-09 21:25:28 +00:00
2008-12-11 14:44:44 +00:00
randomize ( key , len ) ;
2002-09-09 21:25:28 +00:00
/* The message we send must be smaller than the modulus of the RSA key.
By definition , for a key of k bits , the following formula holds :
2 ^ ( k - 1 ) < = modulus < 2 ^ ( k )
Where ^ means " to the power of " , not " xor " .
This means that to be sure , we must choose our message < 2 ^ ( k - 1 ) .
This can be done by setting the most significant bit to zero .
*/
2008-12-11 14:44:44 +00:00
key [ 0 ] & = 0x7F ;
cipher_set_key_from_rsa ( & c - > outcipher , key , len , true ) ;
2002-09-09 21:25:28 +00:00
2003-07-12 17:41:48 +00:00
ifdebug ( SCARY_THINGS ) {
2008-12-11 14:44:44 +00:00
bin2hex ( key , hexkey , len ) ;
2009-09-29 12:55:29 +00:00
logger ( LOG_DEBUG , " Generated random meta key (unencrypted): %s " , hexkey ) ;
2002-09-09 21:25:28 +00:00
}
/* Encrypt the random data
We do not use one of the PKCS padding schemes here .
This is allowed , because we encrypt a totally random string
with a length equal to that of the modulus of the RSA key .
*/
2008-12-11 14:44:44 +00:00
if ( ! rsa_public_encrypt ( & c - > rsa , key , len , enckey ) ) {
2009-09-29 12:55:29 +00:00
logger ( LOG_ERR , " Error during encryption of meta key for %s (%s) " , c - > name , c - > hostname ) ;
2003-07-22 20:55:21 +00:00
return false ;
2002-09-09 21:25:28 +00:00
}
/* Convert the encrypted random data to a hexadecimal formatted string */
2008-12-11 14:44:44 +00:00
bin2hex ( enckey , hexkey , len ) ;
2002-09-09 21:25:28 +00:00
/* Send the meta key */
2008-12-11 14:44:44 +00:00
bool result = send_request ( c , " %d %d %d %d %d %s " , METAKEY ,
cipher_get_nid ( & c - > outcipher ) ,
digest_get_nid ( & c - > outdigest ) , c - > outmaclength ,
c - > outcompression , hexkey ) ;
c - > status . encryptout = true ;
return result ;
2002-02-11 10:05:58 +00:00
}
2011-07-07 20:30:55 +00:00
static bool metakey_ec_h ( connection_t * c , const char * request ) {
size_t siglen = ecdsa_size ( & c - > ecdsa ) ;
char key [ MAX_STRING_SIZE ] ;
char sig [ siglen ] ;
logger ( LOG_DEBUG , " Got ECDH metakey from %s " , c - > name ) ;
2011-07-12 21:43:12 +00:00
if ( sscanf ( request , " %*d " MAX_STRING , key ) ! = 1 ) {
2011-07-07 20:30:55 +00:00
logger ( LOG_ERR , " Got bad %s from %s (%s) " , " METAKEY " , c - > name , c - > hostname ) ;
return false ;
}
2011-07-12 21:43:12 +00:00
int inlen = b64decode ( key , key , sizeof key ) ;
if ( inlen ! = ( ECDH_SIZE + siglen ) ) {
logger ( LOG_ERR , " Possible intruder %s (%s): %s " , c - > name , c - > hostname , " wrong keylength " ) ;
2011-07-07 20:30:55 +00:00
return false ;
}
2011-07-12 21:43:12 +00:00
if ( ! ecdsa_verify ( & c - > ecdsa , key , ECDH_SIZE , key + ECDH_SIZE ) ) {
2011-07-07 20:30:55 +00:00
logger ( LOG_ERR , " Possible intruder %s (%s): %s " , c - > name , c - > hostname , " invalid ECDSA signature " ) ;
return false ;
}
2011-07-12 21:43:12 +00:00
char shared [ ECDH_SHARED_SIZE ] ;
2011-07-07 20:30:55 +00:00
if ( ! ecdh_compute_shared ( & c - > ecdh , key , shared ) )
return false ;
/* Update our crypto end */
if ( ! cipher_open_by_name ( & c - > incipher , " aes-256-ofb " ) )
return false ;
if ( ! digest_open_by_name ( & c - > indigest , " sha512 " , - 1 ) )
return false ;
if ( ! cipher_open_by_name ( & c - > outcipher , " aes-256-ofb " ) )
return false ;
if ( ! digest_open_by_name ( & c - > outdigest , " sha512 " , - 1 ) )
return false ;
size_t mykeylen = cipher_keylength ( & c - > incipher ) ;
size_t hiskeylen = cipher_keylength ( & c - > outcipher ) ;
char * mykey ;
char * hiskey ;
char * seed ;
if ( strcmp ( myself - > name , c - > name ) < 0 ) {
mykey = key ;
hiskey = key + mykeylen * 2 ;
xasprintf ( & seed , " tinc TCP key expansion %s %s " , myself - > name , c - > name ) ;
} else {
mykey = key + hiskeylen * 2 ;
hiskey = key ;
xasprintf ( & seed , " tinc TCP key expansion %s %s " , c - > name , myself - > name ) ;
}
if ( ! prf ( shared , ECDH_SHARED_SIZE , seed , strlen ( seed ) , key , hiskeylen * 2 + mykeylen * 2 ) )
return false ;
free ( seed ) ;
cipher_set_key ( & c - > incipher , mykey , true ) ;
digest_set_key ( & c - > indigest , mykey + mykeylen , mykeylen ) ;
cipher_set_key ( & c - > outcipher , hiskey , false ) ;
digest_set_key ( & c - > outdigest , hiskey + hiskeylen , hiskeylen ) ;
c - > status . decryptin = true ;
c - > status . encryptout = true ;
c - > allow_request = CHALLENGE ;
return send_challenge ( c ) ;
}
2007-05-19 22:23:02 +00:00
bool metakey_h ( connection_t * c , char * request ) {
2011-07-07 20:30:55 +00:00
if ( c - > protocol_minor > = 2 )
return metakey_ec_h ( c , request ) ;
2008-12-11 14:44:44 +00:00
char hexkey [ MAX_STRING_SIZE ] ;
2002-09-09 21:25:28 +00:00
int cipher , digest , maclength , compression ;
2008-12-11 14:44:44 +00:00
size_t len = rsa_size ( & myself - > connection - > rsa ) ;
char enckey [ len ] ;
char key [ len ] ;
2002-09-09 21:25:28 +00:00
2008-12-11 14:44:44 +00:00
if ( sscanf ( request , " %*d %d %d %d %d " MAX_STRING , & cipher , & digest , & maclength , & compression , hexkey ) ! = 5 ) {
2009-09-29 12:55:29 +00:00
logger ( LOG_ERR , " Got bad %s from %s (%s) " , " METAKEY " , c - > name , c - > hostname ) ;
2003-07-22 20:55:21 +00:00
return false ;
2002-09-09 21:25:28 +00:00
}
2011-07-12 21:43:12 +00:00
/* Convert the challenge from hexadecimal back to binary */
int inlen = hex2bin ( hexkey , enckey , sizeof enckey ) ;
2002-09-09 21:25:28 +00:00
/* Check if the length of the meta key is all right */
2011-07-12 21:43:12 +00:00
if ( inlen ! = len ) {
2009-09-24 22:54:07 +00:00
logger ( LOG_ERR , " Possible intruder %s (%s): %s " , c - > name , c - > hostname , " wrong keylength " ) ;
2003-07-22 20:55:21 +00:00
return false ;
2002-09-09 21:25:28 +00:00
}
/* Decrypt the meta key */
2008-12-11 14:44:44 +00:00
if ( ! rsa_private_decrypt ( & myself - > connection - > rsa , enckey , len , key ) ) {
2009-09-29 12:55:29 +00:00
logger ( LOG_ERR , " Error during decryption of meta key for %s (%s) " , c - > name , c - > hostname ) ;
2003-07-22 20:55:21 +00:00
return false ;
2002-09-09 21:25:28 +00:00
}
2003-07-12 17:41:48 +00:00
ifdebug ( SCARY_THINGS ) {
2008-12-11 14:44:44 +00:00
bin2hex ( key , hexkey , len ) ;
2009-09-29 12:55:29 +00:00
logger ( LOG_DEBUG , " Received random meta key (unencrypted): %s " , hexkey ) ;
2002-02-20 19:25:09 +00:00
}
2002-09-09 21:25:28 +00:00
/* Check and lookup cipher and digest algorithms */
2008-12-11 14:44:44 +00:00
if ( ! cipher_open_by_nid ( & c - > incipher , cipher ) | | ! cipher_set_key_from_rsa ( & c - > incipher , key , len , false ) ) {
2009-09-29 12:55:29 +00:00
logger ( LOG_ERR , " Error during initialisation of cipher from %s (%s) " , c - > name , c - > hostname ) ;
2008-12-11 14:44:44 +00:00
return false ;
2002-02-20 19:25:09 +00:00
}
2002-09-09 21:25:28 +00:00
2009-06-06 17:04:04 +00:00
if ( ! digest_open_by_nid ( & c - > indigest , digest , - 1 ) ) {
2009-09-29 12:55:29 +00:00
logger ( LOG_ERR , " Error during initialisation of digest from %s (%s) " , c - > name , c - > hostname ) ;
2008-12-11 14:44:44 +00:00
return false ;
2002-02-20 19:25:09 +00:00
}
2008-12-11 14:44:44 +00:00
c - > status . decryptin = true ;
2002-09-09 21:25:28 +00:00
c - > allow_request = CHALLENGE ;
2002-02-11 10:05:58 +00:00
2002-09-09 21:25:28 +00:00
return send_challenge ( c ) ;
2002-02-11 10:05:58 +00:00
}
2007-05-18 10:00:00 +00:00
bool send_challenge ( connection_t * c ) {
2011-07-07 20:30:55 +00:00
size_t len = c - > protocol_minor > = 2 ? ECDH_SIZE : rsa_size ( & c - > rsa ) ;
2008-12-11 14:44:44 +00:00
char buffer [ len * 2 + 1 ] ;
2002-02-11 10:05:58 +00:00
2002-09-09 21:25:28 +00:00
if ( ! c - > hischallenge )
2009-06-05 21:03:28 +00:00
c - > hischallenge = xrealloc ( c - > hischallenge , len ) ;
2002-02-11 10:05:58 +00:00
2002-09-09 21:25:28 +00:00
/* Copy random data to the buffer */
2002-02-11 10:05:58 +00:00
2008-12-11 14:44:44 +00:00
randomize ( c - > hischallenge , len ) ;
2002-02-11 10:05:58 +00:00
2002-09-09 21:25:28 +00:00
/* Convert to hex */
bin2hex ( c - > hischallenge , buffer , len ) ;
/* Send the challenge */
2003-07-22 20:55:21 +00:00
return send_request ( c , " %d %s " , CHALLENGE , buffer ) ;
2002-02-11 10:05:58 +00:00
}
2007-05-19 22:23:02 +00:00
bool challenge_h ( connection_t * c , char * request ) {
2002-09-09 21:25:28 +00:00
char buffer [ MAX_STRING_SIZE ] ;
2011-07-07 20:30:55 +00:00
size_t len = c - > protocol_minor > = 2 ? ECDH_SIZE : rsa_size ( & myself - > connection - > rsa ) ;
2010-04-30 21:11:48 +00:00
size_t digestlen = digest_length ( & c - > indigest ) ;
2008-12-11 14:44:44 +00:00
char digest [ digestlen ] ;
2002-02-11 10:05:58 +00:00
2007-05-19 22:23:02 +00:00
if ( sscanf ( request , " %*d " MAX_STRING , buffer ) ! = 1 ) {
2009-09-29 12:55:29 +00:00
logger ( LOG_ERR , " Got bad %s from %s (%s) " , " CHALLENGE " , c - > name , c - > hostname ) ;
2003-07-22 20:55:21 +00:00
return false ;
2002-09-09 21:25:28 +00:00
}
2011-07-12 21:43:12 +00:00
/* Convert the challenge from hexadecimal back to binary */
int inlen = hex2bin ( buffer , buffer , sizeof buffer ) ;
2002-09-09 21:25:28 +00:00
/* Check if the length of the challenge is all right */
2011-07-12 21:43:12 +00:00
if ( inlen ! = len ) {
2009-09-29 12:55:29 +00:00
logger ( LOG_ERR , " Possible intruder %s (%s): %s " , c - > name , c - > hostname , " wrong challenge length " ) ;
2003-07-22 20:55:21 +00:00
return false ;
2002-09-09 21:25:28 +00:00
}
2002-02-11 10:05:58 +00:00
2002-09-09 21:25:28 +00:00
c - > allow_request = CHAL_REPLY ;
2002-02-11 10:05:58 +00:00
2002-09-09 21:25:28 +00:00
/* Calculate the hash from the challenge we received */
2002-02-11 10:05:58 +00:00
2008-12-11 14:44:44 +00:00
digest_create ( & c - > indigest , buffer , len , digest ) ;
2002-02-11 10:05:58 +00:00
2002-09-09 21:25:28 +00:00
/* Convert the hash to a hexadecimal formatted string */
2002-02-11 10:05:58 +00:00
2008-12-11 14:44:44 +00:00
bin2hex ( digest , buffer , digestlen ) ;
2002-02-11 10:05:58 +00:00
2002-09-09 21:25:28 +00:00
/* Send the reply */
2008-12-11 14:44:44 +00:00
return send_request ( c , " %d %s " , CHAL_REPLY , buffer ) ;
2002-02-11 10:05:58 +00:00
}
2007-05-19 22:23:02 +00:00
bool chal_reply_h ( connection_t * c , char * request ) {
2002-09-09 21:25:28 +00:00
char hishash [ MAX_STRING_SIZE ] ;
2007-05-19 22:23:02 +00:00
if ( sscanf ( request , " %*d " MAX_STRING , hishash ) ! = 1 ) {
2009-09-24 22:54:07 +00:00
logger ( LOG_ERR , " Got bad %s from %s (%s) " , " CHAL_REPLY " , c - > name ,
2002-09-09 21:25:28 +00:00
c - > hostname ) ;
2003-07-22 20:55:21 +00:00
return false ;
2002-09-09 21:25:28 +00:00
}
2011-07-12 21:43:12 +00:00
/* Convert the hash to binary format */
int inlen = hex2bin ( hishash , hishash , sizeof hishash ) ;
2002-09-09 21:25:28 +00:00
/* Check if the length of the hash is all right */
2011-07-12 21:43:12 +00:00
if ( inlen ! = digest_length ( & c - > outdigest ) ) {
2009-09-29 13:19:55 +00:00
logger ( LOG_ERR , " Possible intruder %s (%s): %s " , c - > name , c - > hostname , " wrong challenge reply length " ) ;
2003-07-22 20:55:21 +00:00
return false ;
2002-09-09 21:25:28 +00:00
}
2008-12-11 14:44:44 +00:00
/* Verify the hash */
2002-09-09 21:25:28 +00:00
2011-07-07 20:30:55 +00:00
if ( ! digest_verify ( & c - > outdigest , c - > hischallenge , c - > protocol_minor > = 2 ? ECDH_SIZE : rsa_size ( & c - > rsa ) , hishash ) ) {
2009-09-29 13:19:55 +00:00
logger ( LOG_ERR , " Possible intruder %s (%s): %s " , c - > name , c - > hostname , " wrong challenge reply " ) ;
2003-07-22 20:55:21 +00:00
return false ;
2002-09-09 21:25:28 +00:00
}
/* Identity has now been positively verified.
Send an acknowledgement with the rest of the information needed .
*/
2008-12-11 14:44:44 +00:00
free ( c - > hischallenge ) ;
c - > hischallenge = NULL ;
2002-09-09 21:25:28 +00:00
c - > allow_request = ACK ;
return send_ack ( c ) ;
2002-02-11 10:05:58 +00:00
}
2011-07-10 20:34:17 +00:00
static bool send_upgrade ( connection_t * c ) {
/* Special case when protocol_minor is 1: the other end is ECDSA capable,
* but doesn ' t know our key yet . So send it now . */
char * pubkey = ecdsa_get_base64_public_key ( & myself - > connection - > ecdsa ) ;
if ( ! pubkey )
return false ;
bool result = send_request ( c , " %d %s " , ACK , pubkey ) ;
free ( pubkey ) ;
return result ;
}
2007-05-18 10:00:00 +00:00
bool send_ack ( connection_t * c ) {
2011-07-10 20:34:17 +00:00
if ( c - > protocol_minor = = 1 )
return send_upgrade ( c ) ;
2002-09-09 21:25:28 +00:00
/* ACK message contains rest of the information the other end needs
to create node_t and edge_t structures . */
struct timeval now ;
2003-11-10 22:31:53 +00:00
bool choice ;
2002-09-09 21:25:28 +00:00
/* Estimate weight */
gettimeofday ( & now , NULL ) ;
2003-07-22 20:55:21 +00:00
c - > estimated_weight = ( now . tv_sec - c - > start . tv_sec ) * 1000 + ( now . tv_usec - c - > start . tv_usec ) / 1000 ;
2002-09-09 21:25:28 +00:00
2003-11-10 22:31:53 +00:00
/* Check some options */
if ( ( get_config_bool ( lookup_config ( c - > config_tree , " IndirectData " ) , & choice ) & & choice ) | | myself - > options & OPTION_INDIRECT )
c - > options | = OPTION_INDIRECT ;
if ( ( get_config_bool ( lookup_config ( c - > config_tree , " TCPOnly " ) , & choice ) & & choice ) | | myself - > options & OPTION_TCPONLY )
c - > options | = OPTION_TCPONLY | OPTION_INDIRECT ;
2009-03-09 12:48:54 +00:00
if ( myself - > options & OPTION_PMTU_DISCOVERY )
2003-12-20 21:25:17 +00:00
c - > options | = OPTION_PMTU_DISCOVERY ;
2003-12-20 19:47:53 +00:00
2010-01-16 19:16:33 +00:00
choice = myself - > options & OPTION_CLAMP_MSS ;
get_config_bool ( lookup_config ( c - > config_tree , " ClampMSS " ) , & choice ) ;
if ( choice )
c - > options | = OPTION_CLAMP_MSS ;
2003-12-22 11:04:17 +00:00
get_config_int ( lookup_config ( c - > config_tree , " Weight " ) , & c - > estimated_weight ) ;
2009-10-24 14:15:24 +00:00
return send_request ( c , " %d %s %d %x " , ACK , myport , c - > estimated_weight , c - > options ) ;
2002-02-11 10:05:58 +00:00
}
2007-05-18 10:00:00 +00:00
static void send_everything ( connection_t * c ) {
2007-05-18 10:05:26 +00:00
splay_node_t * node , * node2 ;
2002-09-09 21:25:28 +00:00
node_t * n ;
subnet_t * s ;
edge_t * e ;
/* Send all known subnets and edges */
2003-11-17 15:30:18 +00:00
if ( tunnelserver ) {
for ( node = myself - > subnet_tree - > head ; node ; node = node - > next ) {
s = node - > data ;
send_add_subnet ( c , s ) ;
}
return ;
}
2002-09-09 21:25:28 +00:00
for ( node = node_tree - > head ; node ; node = node - > next ) {
2003-08-28 21:05:11 +00:00
n = node - > data ;
2002-09-09 21:25:28 +00:00
for ( node2 = n - > subnet_tree - > head ; node2 ; node2 = node2 - > next ) {
2003-08-28 21:05:11 +00:00
s = node2 - > data ;
2002-09-09 21:25:28 +00:00
send_add_subnet ( c , s ) ;
}
for ( node2 = n - > edge_tree - > head ; node2 ; node2 = node2 - > next ) {
2003-08-28 21:05:11 +00:00
e = node2 - > data ;
2002-09-09 21:25:28 +00:00
send_add_edge ( c , e ) ;
}
}
2002-02-11 10:05:58 +00:00
}
2011-07-10 20:34:17 +00:00
static bool upgrade_h ( connection_t * c , char * request ) {
char pubkey [ MAX_STRING_SIZE ] ;
if ( sscanf ( request , " %*d " MAX_STRING , pubkey ) ! = 1 ) {
logger ( LOG_ERR , " Got bad %s from %s (%s) " , " ACK " , c - > name , c - > hostname ) ;
return false ;
}
if ( ecdsa_active ( & c - > ecdsa ) | | read_ecdsa_public_key ( c ) ) {
logger ( LOG_INFO , " Already have ECDSA public key from %s (%s), not upgrading. " , c - > name , c - > hostname ) ;
return false ;
}
logger ( LOG_INFO , " Got ECDSA public key from %s (%s), upgrading! " , c - > name , c - > hostname ) ;
append_connection_config ( c , " ECDSAPublicKey " , pubkey ) ;
c - > allow_request = TERMREQ ;
return send_termreq ( c ) ;
}
2007-05-19 22:23:02 +00:00
bool ack_h ( connection_t * c , char * request ) {
2011-07-10 20:34:17 +00:00
if ( c - > protocol_minor = = 1 )
return upgrade_h ( c , request ) ;
2002-09-09 21:25:28 +00:00
char hisport [ MAX_STRING_SIZE ] ;
2010-04-03 08:46:45 +00:00
char * hisaddress ;
2003-12-22 11:04:17 +00:00
int weight , mtu ;
2009-10-24 14:15:24 +00:00
uint32_t options ;
2002-09-09 21:25:28 +00:00
node_t * n ;
2010-01-16 19:16:33 +00:00
bool choice ;
2002-09-09 21:25:28 +00:00
2009-11-02 13:24:27 +00:00
if ( sscanf ( request , " %*d " MAX_STRING " %d %x " , hisport , & weight , & options ) ! = 3 ) {
2009-09-24 22:54:07 +00:00
logger ( LOG_ERR , " Got bad %s from %s (%s) " , " ACK " , c - > name ,
2002-09-09 21:25:28 +00:00
c - > hostname ) ;
2003-07-22 20:55:21 +00:00
return false ;
2002-09-09 21:25:28 +00:00
}
/* Check if we already have a node_t for him */
n = lookup_node ( c - > name ) ;
if ( ! n ) {
n = new_node ( ) ;
n - > name = xstrdup ( c - > name ) ;
node_add ( n ) ;
} else {
if ( n - > connection ) {
/* Oh dear, we already have a connection to this node. */
2009-09-29 12:55:29 +00:00
ifdebug ( CONNECTIONS ) logger ( LOG_DEBUG , " Established a second connection with %s (%s), closing old connection " , n - > connection - > name , n - > connection - > hostname ) ;
2007-05-18 10:29:10 +00:00
if ( n - > connection - > outgoing ) {
if ( c - > outgoing )
2009-09-29 12:55:29 +00:00
logger ( LOG_WARNING , " Two outgoing connections to the same node! " ) ;
2007-05-18 10:29:10 +00:00
else
c - > outgoing = n - > connection - > outgoing ;
n - > connection - > outgoing = NULL ;
}
2003-07-22 20:55:21 +00:00
terminate_connection ( n - > connection , false ) ;
2003-01-12 17:02:23 +00:00
/* Run graph algorithm to purge key and make sure up/down scripts are rerun with new IP addresses and stuff */
graph ( ) ;
2002-09-09 21:25:28 +00:00
}
}
n - > connection = c ;
c - > node = n ;
2009-03-09 12:48:54 +00:00
if ( ! ( c - > options & options & OPTION_PMTU_DISCOVERY ) ) {
c - > options & = ~ OPTION_PMTU_DISCOVERY ;
options & = ~ OPTION_PMTU_DISCOVERY ;
}
2002-09-09 21:25:28 +00:00
c - > options | = options ;
2003-12-22 11:04:17 +00:00
if ( get_config_int ( lookup_config ( c - > config_tree , " PMTU " ) , & mtu ) & & mtu < n - > mtu )
n - > mtu = mtu ;
2010-10-22 10:47:12 +00:00
if ( get_config_int ( lookup_config ( config_tree , " PMTU " ) , & mtu ) & & mtu < n - > mtu )
2003-12-22 11:04:17 +00:00
n - > mtu = mtu ;
2010-01-16 19:16:33 +00:00
if ( get_config_bool ( lookup_config ( c - > config_tree , " ClampMSS " ) , & choice ) ) {
if ( choice )
c - > options | = OPTION_CLAMP_MSS ;
else
c - > options & = ~ OPTION_CLAMP_MSS ;
}
2011-07-05 19:29:31 +00:00
if ( c - > protocol_minor > 0 )
c - > node - > status . ecdh = true ;
2002-09-09 21:25:28 +00:00
/* Activate this connection */
c - > allow_request = ALL ;
2003-07-22 20:55:21 +00:00
c - > status . active = true ;
2002-09-09 21:25:28 +00:00
2009-09-24 22:54:07 +00:00
ifdebug ( CONNECTIONS ) logger ( LOG_NOTICE , " Connection with %s (%s) activated " , c - > name ,
2002-09-09 21:25:28 +00:00
c - > hostname ) ;
/* Send him everything we know */
2003-11-17 15:30:18 +00:00
send_everything ( c ) ;
2002-09-09 21:25:28 +00:00
/* Create an edge_t for this connection */
c - > edge = new_edge ( ) ;
c - > edge - > from = myself ;
c - > edge - > to = n ;
2010-04-03 08:46:45 +00:00
sockaddr2str ( & c - > address , & hisaddress , NULL ) ;
2002-09-09 21:25:28 +00:00
c - > edge - > address = str2sockaddr ( hisaddress , hisport ) ;
free ( hisaddress ) ;
c - > edge - > weight = ( weight + c - > estimated_weight ) / 2 ;
c - > edge - > connection = c ;
c - > edge - > options = c - > options ;
edge_add ( c - > edge ) ;
/* Notify everyone of the new edge */
2003-11-17 15:30:18 +00:00
if ( tunnelserver )
2003-11-10 22:31:53 +00:00
send_add_edge ( c , c - > edge ) ;
2003-11-17 15:30:18 +00:00
else
send_add_edge ( broadcast , c - > edge ) ;
2002-09-09 21:25:28 +00:00
/* Run MST and SSSP algorithms */
graph ( ) ;
2003-07-22 20:55:21 +00:00
return true ;
2002-02-11 10:05:58 +00:00
}