2004-11-07 02:33:06 +01:00
/* Copyright 2001 Matej Pfajfar.
* Copyright 2001 - 2004 Roger Dingledine .
2005-04-01 22:15:56 +02:00
* Copyright 2004 - 2005 Roger Dingledine , Nick Mathewson . */
2003-12-06 06:54:04 +01:00
/* See LICENSE for licensing information */
/* $Id$ */
2004-11-29 23:25:31 +01:00
const char router_c_id [ ] = " $Id$ " ;
2003-12-06 06:54:04 +01:00
# include "or.h"
2004-05-09 18:47:25 +02:00
/**
* \ file router . c
* \ brief OR functionality , including key maintenance , generating
2004-05-05 02:30:43 +02:00
* and uploading server descriptors , retrying OR connections .
2004-05-09 18:47:25 +02:00
* */
2004-05-05 02:30:43 +02:00
2005-01-10 06:10:22 +01:00
extern long stats_n_seconds_working ;
2003-12-06 06:54:04 +01:00
2005-05-17 19:01:36 +02:00
/* Exposed for test.c. */ void get_platform_str ( char * platform , size_t len ) ;
2004-04-07 23:36:03 +02:00
2003-12-06 06:54:04 +01:00
/************************************************************/
2004-05-04 20:17:45 +02:00
/*****
* Key management : ORs only .
* * * * */
2004-05-09 18:47:25 +02:00
/** Private keys for this OR. There is also an SSL key managed by tortls.c.
2004-05-04 20:17:45 +02:00
*/
2004-06-05 03:50:35 +02:00
static tor_mutex_t * key_lock = NULL ;
2004-05-04 20:17:45 +02:00
static time_t onionkey_set_at = 0 ; /* When was onionkey last changed? */
2003-12-06 06:54:04 +01:00
static crypto_pk_env_t * onionkey = NULL ;
2004-04-25 00:17:50 +02:00
static crypto_pk_env_t * lastonionkey = NULL ;
2003-12-06 06:54:04 +01:00
static crypto_pk_env_t * identitykey = NULL ;
2004-05-10 06:34:48 +02:00
/** Replace the current onion key with <b>k</b>. Does not affect lastonionkey;
2004-05-04 20:17:45 +02:00
* to update onionkey correctly , call rotate_onion_key ( ) .
*/
2005-06-11 20:52:12 +02:00
void
set_onion_key ( crypto_pk_env_t * k )
{
2004-06-05 03:50:35 +02:00
tor_mutex_acquire ( key_lock ) ;
2003-12-06 06:54:04 +01:00
onionkey = k ;
2004-04-25 00:17:50 +02:00
onionkey_set_at = time ( NULL ) ;
2004-06-05 03:50:35 +02:00
tor_mutex_release ( key_lock ) ;
2004-11-13 17:53:48 +01:00
mark_my_descriptor_dirty ( ) ;
2003-12-06 06:54:04 +01:00
}
2004-05-09 18:47:25 +02:00
/** Return the current onion key. Requires that the onion key has been
2004-05-04 20:17:45 +02:00
* loaded or generated . */
2005-06-11 20:52:12 +02:00
crypto_pk_env_t *
get_onion_key ( void )
{
2004-04-25 22:37:37 +02:00
tor_assert ( onionkey ) ;
2003-12-06 06:54:04 +01:00
return onionkey ;
}
2004-05-09 18:47:25 +02:00
/** Return the onion key that was current before the most recent onion
2004-05-04 20:17:45 +02:00
* key rotation . If no rotation has been performed since this process
* started , return NULL .
*/
2005-06-11 20:52:12 +02:00
crypto_pk_env_t *
get_previous_onion_key ( void )
{
2004-04-25 00:17:50 +02:00
return lastonionkey ;
2003-12-06 06:54:04 +01:00
}
2005-03-17 13:38:37 +01:00
/** Store a copy of the current onion key into *<b>key</b>, and a copy
* of the most recent onion key into * < b > last < / b > .
*/
2005-06-11 20:52:12 +02:00
void
dup_onion_keys ( crypto_pk_env_t * * key , crypto_pk_env_t * * last )
2004-06-05 03:50:35 +02:00
{
2004-10-17 00:14:52 +02:00
tor_assert ( key ) ;
tor_assert ( last ) ;
2004-06-05 03:50:35 +02:00
tor_mutex_acquire ( key_lock ) ;
* key = crypto_pk_dup_key ( onionkey ) ;
if ( lastonionkey )
2004-06-05 03:56:54 +02:00
* last = crypto_pk_dup_key ( lastonionkey ) ;
2004-06-05 03:50:35 +02:00
else
* last = NULL ;
tor_mutex_release ( key_lock ) ;
}
2004-05-09 18:47:25 +02:00
/** Return the time when the onion key was last set. This is either the time
2004-05-04 20:17:45 +02:00
* when the process launched , or the time of the most recent key rotation since
* the process launched .
*/
2005-06-11 20:52:12 +02:00
time_t
get_onion_key_set_at ( void )
{
2004-04-25 00:17:50 +02:00
return onionkey_set_at ;
2003-12-06 06:54:04 +01:00
}
2004-05-09 18:47:25 +02:00
/** Set the current identity key to k.
2004-05-04 20:17:45 +02:00
*/
2005-06-11 20:52:12 +02:00
void
set_identity_key ( crypto_pk_env_t * k )
{
2005-09-30 08:03:04 +02:00
if ( identitykey )
crypto_free_pk_env ( identitykey ) ;
2003-12-06 06:54:04 +01:00
identitykey = k ;
}
2004-05-09 18:47:25 +02:00
/** Returns the current identity key; requires that the identity key has been
2004-05-04 20:17:45 +02:00
* set .
*/
2005-06-11 20:52:12 +02:00
crypto_pk_env_t *
get_identity_key ( void )
{
2004-04-25 22:37:37 +02:00
tor_assert ( identitykey ) ;
2003-12-06 06:54:04 +01:00
return identitykey ;
}
2004-11-21 06:06:22 +01:00
/** Return true iff the identity key has been set. */
2005-06-11 20:52:12 +02:00
int
identity_key_is_set ( void )
{
2004-11-21 05:19:04 +01:00
return identitykey ! = NULL ;
}
2004-05-09 18:47:25 +02:00
/** Replace the previous onion key with the current onion key, and generate
2004-04-25 00:17:50 +02:00
* a new previous onion key . Immediately after calling this function ,
* the OR should :
2004-05-09 18:47:25 +02:00
* - schedule all previous cpuworkers to shut down _after_ processing
* pending work . ( This will cause fresh cpuworkers to be generated . )
* - generate and upload a fresh routerinfo .
2004-04-25 00:17:50 +02:00
*/
2005-06-11 20:52:12 +02:00
void
rotate_onion_key ( void )
2004-04-25 00:17:50 +02:00
{
char fname [ 512 ] ;
2004-08-09 06:27:13 +02:00
char fname_prev [ 512 ] ;
2004-04-25 00:17:50 +02:00
crypto_pk_env_t * prkey ;
2004-10-27 08:37:34 +02:00
tor_snprintf ( fname , sizeof ( fname ) ,
2004-11-09 08:05:53 +01:00
" %s/keys/secret_onion_key " , get_options ( ) - > DataDirectory ) ;
2004-10-27 08:37:34 +02:00
tor_snprintf ( fname_prev , sizeof ( fname_prev ) ,
2004-11-09 08:05:53 +01:00
" %s/keys/secret_onion_key.old " , get_options ( ) - > DataDirectory ) ;
2004-04-25 00:17:50 +02:00
if ( ! ( prkey = crypto_new_pk_env ( ) ) ) {
log ( LOG_ERR , " Error creating crypto environment. " ) ;
goto error ;
}
2004-04-25 05:38:19 +02:00
if ( crypto_pk_generate_key ( prkey ) ) {
2004-04-26 20:09:50 +02:00
log ( LOG_ERR , " Error generating onion key " ) ;
2004-04-25 00:17:50 +02:00
goto error ;
}
2004-08-09 06:27:13 +02:00
if ( file_status ( fname ) = = FN_FILE ) {
if ( replace_file ( fname , fname_prev ) )
goto error ;
}
2004-04-25 00:17:50 +02:00
if ( crypto_pk_write_private_key_to_filename ( prkey , fname ) ) {
2005-08-26 20:44:26 +02:00
log ( LOG_ERR , " Couldn't write generated key to \" %s \" . " , fname ) ;
2004-04-25 00:17:50 +02:00
goto error ;
}
2005-02-11 08:56:10 +01:00
log_fn ( LOG_INFO , " Rotating onion key " ) ;
2004-06-05 03:50:35 +02:00
tor_mutex_acquire ( key_lock ) ;
2004-04-25 00:17:50 +02:00
if ( lastonionkey )
crypto_free_pk_env ( lastonionkey ) ;
lastonionkey = onionkey ;
2005-02-11 08:56:10 +01:00
onionkey = prkey ;
onionkey_set_at = time ( NULL ) ;
2004-06-05 03:50:35 +02:00
tor_mutex_release ( key_lock ) ;
2005-02-11 08:56:10 +01:00
mark_my_descriptor_dirty ( ) ;
2004-04-25 00:17:50 +02:00
return ;
error :
log_fn ( LOG_WARN , " Couldn't rotate onion key. " ) ;
}
2004-07-13 20:23:40 +02:00
/* Read an RSA secret key key from a file that was once named fname_old,
* but is now named fname_new . Rename the file from old to new as needed .
*/
2004-07-22 08:03:53 +02:00
static crypto_pk_env_t *
init_key_from_file_name_changed ( const char * fname_old ,
const char * fname_new )
2004-07-13 20:23:40 +02:00
{
2004-08-09 06:27:13 +02:00
if ( file_status ( fname_new ) = = FN_FILE | | file_status ( fname_old ) ! = FN_FILE )
/* The new filename is there, or both are, or neither is. */
2004-07-13 20:23:40 +02:00
return init_key_from_file ( fname_new ) ;
/* The old filename exists, and the new one doesn't. Rename and load. */
if ( rename ( fname_old , fname_new ) < 0 ) {
2005-08-26 20:44:26 +02:00
log_fn ( LOG_ERR , " Couldn't rename \" %s \" to \" %s \" : %s " , fname_old , fname_new ,
2004-07-13 20:23:40 +02:00
strerror ( errno ) ) ;
return NULL ;
}
return init_key_from_file ( fname_new ) ;
}
2004-05-10 06:34:48 +02:00
/** Try to read an RSA key from <b>fname</b>. If <b>fname</b> doesn't exist,
* create a new RSA key and save it in < b > fname < / b > . Return the read / created
* key , or NULL on error .
2004-03-31 23:35:23 +02:00
*/
2005-06-11 20:52:12 +02:00
crypto_pk_env_t *
init_key_from_file ( const char * fname )
2003-12-06 06:54:04 +01:00
{
crypto_pk_env_t * prkey = NULL ;
FILE * file = NULL ;
2004-04-03 04:40:30 +02:00
if ( ! ( prkey = crypto_new_pk_env ( ) ) ) {
2003-12-06 06:54:04 +01:00
log ( LOG_ERR , " Error creating crypto environment. " ) ;
goto error ;
}
2004-11-28 10:05:49 +01:00
switch ( file_status ( fname ) ) {
2004-11-28 12:39:53 +01:00
case FN_DIR :
case FN_ERROR :
2005-08-26 20:44:26 +02:00
log ( LOG_ERR , " Can't read key from \" %s \" " , fname ) ;
2003-12-06 06:54:04 +01:00
goto error ;
2004-11-28 12:39:53 +01:00
case FN_NOENT :
2005-08-26 20:44:26 +02:00
log ( LOG_INFO , " No key found in \" %s \" ; generating fresh key. " , fname ) ;
2004-11-28 12:39:53 +01:00
if ( crypto_pk_generate_key ( prkey ) ) {
log ( LOG_ERR , " Error generating onion key " ) ;
goto error ;
}
if ( crypto_pk_check_key ( prkey ) < = 0 ) {
log ( LOG_ERR , " Generated key seems invalid " ) ;
goto error ;
}
log ( LOG_INFO , " Generated key seems valid " ) ;
if ( crypto_pk_write_private_key_to_filename ( prkey , fname ) ) {
2005-08-26 20:44:26 +02:00
log ( LOG_ERR , " Couldn't write generated key to \" %s \" . " , fname ) ;
2004-11-28 12:39:53 +01:00
goto error ;
}
return prkey ;
case FN_FILE :
if ( crypto_pk_read_private_key_from_filename ( prkey , fname ) ) {
log ( LOG_ERR , " Error loading private key. " ) ;
goto error ;
}
return prkey ;
default :
tor_assert ( 0 ) ;
2003-12-06 06:54:04 +01:00
}
error :
if ( prkey )
crypto_free_pk_env ( prkey ) ;
if ( file )
fclose ( file ) ;
return NULL ;
}
2004-05-09 18:47:25 +02:00
/** Initialize all OR private keys, and the TLS context, as necessary.
2004-05-04 20:17:45 +02:00
* On OPs , this only initializes the tls context .
*/
2005-06-11 20:52:12 +02:00
int
init_keys ( void )
{
2004-11-21 05:19:04 +01:00
/* XXX009 Two problems with how this is called:
* 1. It should be idempotent for servers , so we can call init_keys
* as much as we need to .
*/
2003-12-06 06:54:04 +01:00
char keydir [ 512 ] ;
2004-07-13 20:23:40 +02:00
char keydir2 [ 512 ] ;
2005-01-03 18:53:20 +01:00
char fingerprint [ FINGERPRINT_LEN + 1 ] ;
char fingerprint_line [ FINGERPRINT_LEN + MAX_NICKNAME_LEN + 3 ] ; /*nickname fp\n\0 */
2003-12-06 06:54:04 +01:00
char * cp ;
2005-09-08 07:37:22 +02:00
const char * mydesc , * datadir ;
2003-12-06 06:54:04 +01:00
crypto_pk_env_t * prkey ;
2004-10-14 03:44:32 +02:00
char digest [ 20 ] ;
2004-11-06 06:18:11 +01:00
or_options_t * options = get_options ( ) ;
2003-12-06 06:54:04 +01:00
2004-06-05 03:50:35 +02:00
if ( ! key_lock )
2004-06-05 03:56:54 +02:00
key_lock = tor_mutex_new ( ) ;
2004-06-05 03:50:35 +02:00
2004-11-09 08:29:05 +01:00
/* OP's don't need persistent keys; just make up an identity and
2004-07-18 23:47:04 +02:00
* initialize the TLS context . */
2004-11-06 06:18:11 +01:00
if ( ! server_mode ( options ) ) {
2004-07-18 23:47:04 +02:00
if ( ! ( prkey = crypto_new_pk_env ( ) ) )
return - 1 ;
if ( crypto_pk_generate_key ( prkey ) )
return - 1 ;
set_identity_key ( prkey ) ;
2004-11-09 19:22:17 +01:00
/* Create a TLS context; default the client nickname to "client". */
2004-11-06 06:18:11 +01:00
if ( tor_tls_context_new ( get_identity_key ( ) , 1 ,
options - > Nickname ? options - > Nickname : " client " ,
2004-07-18 23:47:04 +02:00
MAX_SSL_KEY_LIFETIME ) < 0 ) {
log_fn ( LOG_ERR , " Error creating TLS context for OP. " ) ;
return - 1 ;
}
2003-12-06 06:54:04 +01:00
return 0 ;
}
2004-05-04 20:17:45 +02:00
/* Make sure DataDirectory exists, and is private. */
2004-11-09 08:05:53 +01:00
datadir = options - > DataDirectory ;
2004-11-09 08:12:31 +01:00
if ( check_private_dir ( datadir , CPD_CREATE ) ) {
2003-12-06 06:54:04 +01:00
return - 1 ;
}
2004-05-04 20:17:45 +02:00
/* Check the key directory. */
2004-10-27 08:37:34 +02:00
tor_snprintf ( keydir , sizeof ( keydir ) , " %s/keys " , datadir ) ;
2004-11-09 08:12:31 +01:00
if ( check_private_dir ( keydir , CPD_CREATE ) ) {
2003-12-06 06:54:04 +01:00
return - 1 ;
}
cp = keydir + strlen ( keydir ) ; /* End of string. */
/* 1. Read identity key. Make it if none is found. */
2004-10-27 08:37:34 +02:00
tor_snprintf ( keydir , sizeof ( keydir ) , " %s/keys/identity.key " , datadir ) ;
tor_snprintf ( keydir2 , sizeof ( keydir2 ) , " %s/keys/secret_id_key " , datadir ) ;
2005-08-26 20:44:26 +02:00
log_fn ( LOG_INFO , " Reading/making identity key \" %s \" ... " , keydir2 ) ;
2004-07-13 20:23:40 +02:00
prkey = init_key_from_file_name_changed ( keydir , keydir2 ) ;
2003-12-06 06:54:04 +01:00
if ( ! prkey ) return - 1 ;
set_identity_key ( prkey ) ;
/* 2. Read onion key. Make it if none is found. */
2004-10-27 08:37:34 +02:00
tor_snprintf ( keydir , sizeof ( keydir ) , " %s/keys/onion.key " , datadir ) ;
tor_snprintf ( keydir2 , sizeof ( keydir2 ) , " %s/keys/secret_onion_key " , datadir ) ;
2005-08-26 20:44:26 +02:00
log_fn ( LOG_INFO , " Reading/making onion key \" %s \" ... " , keydir2 ) ;
2004-07-13 20:23:40 +02:00
prkey = init_key_from_file_name_changed ( keydir , keydir2 ) ;
2003-12-06 06:54:04 +01:00
if ( ! prkey ) return - 1 ;
set_onion_key ( prkey ) ;
2004-10-27 08:37:34 +02:00
tor_snprintf ( keydir , sizeof ( keydir ) , " %s/keys/secret_onion_key.old " , datadir ) ;
2004-08-09 06:27:13 +02:00
if ( file_status ( keydir ) = = FN_FILE ) {
prkey = init_key_from_file ( keydir ) ;
if ( prkey )
lastonionkey = prkey ;
}
2003-12-06 06:54:04 +01:00
/* 3. Initialize link key and TLS context. */
2004-11-06 06:18:11 +01:00
if ( tor_tls_context_new ( get_identity_key ( ) , 1 , options - > Nickname ,
2004-04-25 00:17:50 +02:00
MAX_SSL_KEY_LIFETIME ) < 0 ) {
2003-12-06 06:54:04 +01:00
log_fn ( LOG_ERR , " Error initializing TLS context " ) ;
return - 1 ;
}
/* 4. Dump router descriptor to 'router.desc' */
/* Must be called after keys are initialized. */
2005-09-08 07:37:22 +02:00
mydesc = router_get_my_descriptor ( ) ;
2004-07-20 12:17:43 +02:00
if ( ! mydesc ) {
2003-12-06 06:54:04 +01:00
log_fn ( LOG_ERR , " Error initializing descriptor. " ) ;
return - 1 ;
}
2004-11-28 10:05:49 +01:00
if ( authdir_mode ( options ) ) {
2005-01-20 21:18:32 +01:00
const char * m ;
2004-07-20 12:17:43 +02:00
/* We need to add our own fingerprint so it gets recognized. */
2004-11-06 06:18:11 +01:00
if ( dirserv_add_own_fingerprint ( options - > Nickname , get_identity_key ( ) ) ) {
2004-07-20 12:17:43 +02:00
log_fn ( LOG_ERR , " Error adding own fingerprint to approved set " ) ;
return - 1 ;
}
2005-09-08 07:37:22 +02:00
if ( dirserv_add_descriptor ( mydesc , & m ) < 0 ) {
2005-01-20 21:18:32 +01:00
log ( LOG_ERR , " Unable to add own descriptor to directory: %s " ,
m ? m : " <unknown error> " ) ;
2004-07-20 12:17:43 +02:00
return - 1 ;
}
2003-12-06 06:54:04 +01:00
}
2004-07-20 12:17:43 +02:00
2004-10-27 08:37:34 +02:00
tor_snprintf ( keydir , sizeof ( keydir ) , " %s/router.desc " , datadir ) ;
2005-08-26 20:44:26 +02:00
log_fn ( LOG_INFO , " Dumping descriptor to \" %s \" ... " , keydir ) ;
2004-09-08 09:16:34 +02:00
if ( write_str_to_file ( keydir , mydesc , 0 ) ) {
2003-12-06 06:54:04 +01:00
return - 1 ;
}
/* 5. Dump fingerprint to 'fingerprint' */
2004-10-27 08:37:34 +02:00
tor_snprintf ( keydir , sizeof ( keydir ) , " %s/fingerprint " , datadir ) ;
2005-08-26 20:44:26 +02:00
log_fn ( LOG_INFO , " Dumping fingerprint to \" %s \" ... " , keydir ) ;
2005-01-03 18:53:20 +01:00
if ( crypto_pk_get_fingerprint ( get_identity_key ( ) , fingerprint , 1 ) < 0 ) {
2003-12-06 06:54:04 +01:00
log_fn ( LOG_ERR , " Error computing fingerprint " ) ;
return - 1 ;
}
2005-01-03 18:53:20 +01:00
tor_assert ( strlen ( options - > Nickname ) < = MAX_NICKNAME_LEN ) ;
if ( tor_snprintf ( fingerprint_line , sizeof ( fingerprint_line ) ,
" %s %s \n " , options - > Nickname , fingerprint ) < 0 ) {
log_fn ( LOG_ERR , " Error writing fingerprint line " ) ;
return - 1 ;
}
if ( write_str_to_file ( keydir , fingerprint_line , 0 ) )
2003-12-06 06:54:04 +01:00
return - 1 ;
2004-11-28 10:05:49 +01:00
if ( ! authdir_mode ( options ) )
2003-12-06 06:54:04 +01:00
return 0 ;
2004-07-20 12:17:43 +02:00
/* 6. [authdirserver only] load approved-routers file */
2004-10-27 08:37:34 +02:00
tor_snprintf ( keydir , sizeof ( keydir ) , " %s/approved-routers " , datadir ) ;
2005-08-26 20:44:26 +02:00
log_fn ( LOG_INFO , " Loading approved fingerprints from \" %s \" ... " , keydir ) ;
2004-11-28 10:05:49 +01:00
if ( dirserv_parse_fingerprint_file ( keydir ) < 0 ) {
2003-12-06 06:54:04 +01:00
log_fn ( LOG_ERR , " Error loading fingerprints " ) ;
return - 1 ;
}
2004-10-14 03:44:32 +02:00
/* 6b. [authdirserver only] add own key to approved directories. */
crypto_pk_get_digest ( get_identity_key ( ) , digest ) ;
if ( ! router_digest_is_trusted_dir ( digest ) ) {
2005-10-04 23:21:09 +02:00
add_trusted_dir_server ( options - > Nickname , NULL ,
( uint16_t ) options - > DirPort , digest ,
2005-09-07 18:42:53 +02:00
options - > V1AuthoritativeDir ) ;
2004-10-14 03:44:32 +02:00
}
2003-12-06 06:54:04 +01:00
/* success */
return 0 ;
}
2005-02-27 10:47:01 +01:00
/* Keep track of whether we should upload our server descriptor,
* and what type of server we are .
*/
/** Whether we can reach our ORPort from the outside. */
2005-03-15 02:44:46 +01:00
static int can_reach_or_port = 0 ;
2005-02-27 10:47:01 +01:00
/** Whether we can reach our DirPort from the outside. */
2005-03-15 02:44:46 +01:00
static int can_reach_dir_port = 0 ;
2005-02-27 10:47:01 +01:00
2005-03-31 21:26:33 +02:00
/** Return 1 if or port is known reachable; else return 0. */
2005-06-11 20:52:12 +02:00
int
check_whether_orport_reachable ( void )
{
2005-08-26 09:41:19 +02:00
or_options_t * options = get_options ( ) ;
return clique_mode ( options ) | |
options - > AssumeReachable | |
can_reach_or_port ;
2005-03-31 21:26:33 +02:00
}
2005-06-11 20:52:12 +02:00
2005-03-31 21:26:33 +02:00
/** Return 1 if we don't have a dirport configured, or if it's reachable. */
2005-06-11 20:52:12 +02:00
int
check_whether_dirport_reachable ( void )
{
2005-08-26 09:41:19 +02:00
or_options_t * options = get_options ( ) ;
2005-10-12 06:07:10 +02:00
routerinfo_t * ri = router_get_my_routerinfo ( ) ;
2005-08-26 09:41:19 +02:00
return ! options - > DirPort | |
options - > AssumeReachable | |
2005-10-12 06:07:10 +02:00
( ri & & ! ri - > dir_port ) | |
2005-08-26 09:41:19 +02:00
can_reach_dir_port ;
2005-03-26 02:43:39 +01:00
}
2005-09-29 08:45:03 +02:00
/** Look at a variety of factors, and return 0 if we don't want to
* advertise the fact that we have a DirPort open . Else return the
* DirPort we want to advertise . */
static int
decide_to_advertise_dirport ( or_options_t * options , routerinfo_t * router )
{
if ( ! router - > dir_port ) /* short circuit the rest of the function */
return 0 ;
if ( authdir_mode ( options ) ) /* always publish */
return router - > dir_port ;
if ( we_are_hibernating ( ) )
return 0 ;
if ( ! check_whether_dirport_reachable ( ) )
return 0 ;
if ( router - > bandwidthcapacity > = router - > bandwidthrate ) {
/* check if we might potentially hibernate. */
if ( options - > AccountingMax ! = 0 )
return 0 ;
/* also check if we're advertising a small amount, and have
a " boring " DirPort . */
if ( router - > bandwidthrate < 50000 & & router - > dir_port > 1024 )
return 0 ;
}
/* Sounds like a great idea. Let's publish it. */
return router - > dir_port ;
}
2005-09-30 02:43:40 +02:00
/** Some time has passed, or we just got new directory information.
* See if we currently believe our ORPort or DirPort to be
* unreachable . If so , launch a new test for it .
*
* For ORPort , we simply try making a circuit that ends at ourselves .
* Success is noticed in onionskin_answer ( ) .
*
* For DirPort , we make a connection via Tor to our DirPort and ask
* for our own server descriptor .
* Success is noticed in connection_dir_client_reached_eof ( ) .
*/
2005-06-11 20:52:12 +02:00
void
consider_testing_reachability ( void )
{
2005-02-27 10:47:01 +01:00
routerinfo_t * me = router_get_my_routerinfo ( ) ;
2005-03-27 13:52:15 +02:00
if ( ! me ) {
log_fn ( LOG_WARN , " Bug: router_get_my_routerinfo() did not find my routerinfo? " ) ;
return ;
}
2005-02-27 10:47:01 +01:00
2005-03-31 21:26:33 +02:00
if ( ! check_whether_orport_reachable ( ) ) {
circuit_launch_by_router ( CIRCUIT_PURPOSE_TESTING , me , 0 , 1 , 1 ) ;
2005-02-27 10:47:01 +01:00
}
2005-03-31 21:26:33 +02:00
if ( ! check_whether_dirport_reachable ( ) ) {
2005-09-30 01:04:01 +02:00
/* ask myself, via tor, for my server descriptor. */
directory_initiate_command_router ( me , DIR_PURPOSE_FETCH_SERVERDESC ,
1 , " authority " , NULL , 0 ) ;
2005-02-27 10:47:01 +01:00
}
}
/** Annotate that we found our ORPort reachable. */
2005-06-11 20:52:12 +02:00
void
router_orport_found_reachable ( void )
{
2005-03-20 00:04:15 +01:00
if ( ! can_reach_or_port ) {
2005-04-01 09:09:18 +02:00
if ( ! clique_mode ( get_options ( ) ) )
2005-09-13 23:39:42 +02:00
log ( LOG_NOTICE , " Self-testing indicates your ORPort is reachable from the outside. Excellent.%s " ,
2005-06-09 23:23:54 +02:00
get_options ( ) - > NoPublish ? " " : " Publishing server descriptor. " ) ;
2005-03-20 00:04:15 +01:00
can_reach_or_port = 1 ;
2005-08-22 05:10:53 +02:00
mark_my_descriptor_dirty ( ) ;
2005-04-01 11:28:14 +02:00
consider_publishable_server ( time ( NULL ) , 1 ) ;
2005-03-20 00:04:15 +01:00
}
2005-02-27 10:47:01 +01:00
}
/** Annotate that we found our DirPort reachable. */
2005-06-11 20:52:12 +02:00
void
router_dirport_found_reachable ( void )
{
2005-03-20 00:04:15 +01:00
if ( ! can_reach_dir_port ) {
2005-09-13 23:39:42 +02:00
log ( LOG_NOTICE , " Self-testing indicates your DirPort is reachable from the outside. Excellent. " ) ;
2005-03-20 00:04:15 +01:00
can_reach_dir_port = 1 ;
}
2005-02-27 10:47:01 +01:00
}
/** Our router has just moved to a new IP. Reset stats. */
2005-06-11 20:52:12 +02:00
void
server_has_changed_ip ( void )
{
2005-02-27 10:47:01 +01:00
stats_n_seconds_working = 0 ;
2005-03-15 02:44:46 +01:00
can_reach_or_port = 0 ;
can_reach_dir_port = 0 ;
2005-02-27 10:47:01 +01:00
mark_my_descriptor_dirty ( ) ;
}
/** Return true iff we believe ourselves to be an authoritative
* directory server .
*/
2005-06-11 20:52:12 +02:00
int
authdir_mode ( or_options_t * options )
{
2005-02-27 10:47:01 +01:00
return options - > AuthoritativeDir ! = 0 ;
}
/** Return true iff we try to stay connected to all ORs at once.
*/
2005-06-11 20:52:12 +02:00
int
clique_mode ( or_options_t * options )
{
2005-02-27 10:47:01 +01:00
return authdir_mode ( options ) ;
}
/** Return true iff we are trying to be a server.
*/
2005-06-11 20:52:12 +02:00
int
server_mode ( or_options_t * options )
{
2005-06-09 10:54:42 +02:00
if ( options - > ClientOnly ) return 0 ;
2005-10-17 05:17:29 +02:00
return ( options - > ORPort ! = 0 | | options - > ORListenAddress ) ;
2005-02-27 10:47:01 +01:00
}
/** Remember if we've advertised ourselves to the dirservers. */
static int server_is_advertised = 0 ;
/** Return true iff we have published our descriptor lately.
*/
2005-06-11 20:52:12 +02:00
int
advertised_server_mode ( void )
{
2005-02-27 10:47:01 +01:00
return server_is_advertised ;
}
2005-06-11 20:52:12 +02:00
/**
* Called with a boolean : set whether we have recently published our descriptor .
*/
static void
set_server_advertised ( int s )
{
2005-02-27 10:47:01 +01:00
server_is_advertised = s ;
}
/** Return true iff we are trying to be a socks proxy. */
2005-06-11 20:52:12 +02:00
int
proxy_mode ( or_options_t * options )
{
2005-10-17 05:17:29 +02:00
return ( options - > SocksPort ! = 0 | | options - > SocksListenAddress ) ;
2005-02-27 10:47:01 +01:00
}
2005-04-21 12:40:48 +02:00
/** Decide if we're a publishable server. We are a publishable server if:
* - We don ' t have the ClientOnly option set
* and
* - We don ' t have the NoPublish option set
* and
* - We have ORPort set
* and
* - We believe we are reachable from the outside ; or
2005-02-27 10:47:01 +01:00
* - We have the AuthoritativeDirectory option set .
*/
2005-06-11 20:52:12 +02:00
static int
decide_if_publishable_server ( time_t now )
{
2005-02-27 10:47:01 +01:00
or_options_t * options = get_options ( ) ;
if ( options - > ClientOnly )
return 0 ;
2005-04-21 12:40:48 +02:00
if ( options - > NoPublish )
return 0 ;
2005-02-27 10:47:01 +01:00
if ( ! server_mode ( options ) )
return 0 ;
if ( options - > AuthoritativeDir )
return 1 ;
2005-03-31 21:26:33 +02:00
return check_whether_orport_reachable ( ) ;
2005-02-27 10:47:01 +01:00
}
2005-06-11 20:52:12 +02:00
/** Initiate server descriptor upload as reasonable (if server is publishable,
* etc ) . < b > force < / b > is as for router_upload_dir_desc_to_dirservers .
*/
void
consider_publishable_server ( time_t now , int force )
{
2005-02-27 10:47:01 +01:00
if ( decide_if_publishable_server ( now ) ) {
set_server_advertised ( 1 ) ;
2005-08-22 05:10:53 +02:00
if ( router_rebuild_descriptor ( 0 ) = = 0 )
2005-06-08 21:45:17 +02:00
router_upload_dir_desc_to_dirservers ( force ) ;
2005-02-27 10:47:01 +01:00
} else {
set_server_advertised ( 0 ) ;
}
}
2004-05-10 06:34:48 +02:00
/*
2004-05-04 20:17:45 +02:00
* Clique maintenance
2004-05-10 06:34:48 +02:00
*/
2003-12-06 06:54:04 +01:00
2004-07-22 01:43:47 +02:00
/** OR only: if in clique mode, try to open connections to all of the
* other ORs we know about . Otherwise , open connections to those we
2005-08-24 04:31:02 +02:00
* think are in clique mode . o
*
* If < b > force < / b > is zero , only open the connection if we don ' t already
* have one .
2004-05-04 20:17:45 +02:00
*/
2005-06-11 20:52:12 +02:00
void
2005-08-24 04:31:02 +02:00
router_retry_connections ( int force )
2005-06-11 20:52:12 +02:00
{
2003-12-06 06:54:04 +01:00
int i ;
2005-08-24 16:31:32 +02:00
time_t now = time ( NULL ) ;
2003-12-06 06:54:04 +01:00
routerinfo_t * router ;
routerlist_t * rl ;
2004-11-06 06:18:11 +01:00
or_options_t * options = get_options ( ) ;
2003-12-06 06:54:04 +01:00
2004-11-06 06:18:11 +01:00
tor_assert ( server_mode ( options ) ) ;
2004-07-22 01:43:47 +02:00
2003-12-06 06:54:04 +01:00
router_get_routerlist ( & rl ) ;
2004-10-14 05:44:45 +02:00
if ( ! rl ) return ;
2004-04-07 21:46:27 +02:00
for ( i = 0 ; i < smartlist_len ( rl - > routers ) ; i + + ) {
router = smartlist_get ( rl - > routers , i ) ;
2004-11-28 10:05:49 +01:00
if ( router_is_me ( router ) )
2004-04-07 21:46:27 +02:00
continue ;
2004-11-28 10:05:49 +01:00
if ( ! clique_mode ( options ) & & ! router_is_clique_mode ( router ) )
2004-07-22 01:43:47 +02:00
continue ;
2005-08-24 04:31:02 +02:00
if ( force | |
! connection_get_by_identity_digest ( router - > identity_digest ,
2004-11-28 12:39:53 +01:00
CONN_TYPE_OR ) ) {
2005-08-24 04:31:02 +02:00
log_fn ( LOG_INFO , " %sconnecting to %s at %s:%u. " ,
clique_mode ( options ) ? " (forced) " : " " ,
router - > nickname , router - > address , router - > or_port ) ;
2005-08-30 08:43:07 +02:00
/* Remember when we started trying to determine reachability */
if ( ! router - > testing_since )
router - > testing_since = now ;
2004-07-02 11:29:01 +02:00
connection_or_connect ( router - > addr , router - > or_port , router - > identity_digest ) ;
2003-12-06 06:54:04 +01:00
}
}
}
2005-03-17 13:38:37 +01:00
/** Return true iff this OR should try to keep connections open to all
* other ORs . */
2005-06-11 20:52:12 +02:00
int
router_is_clique_mode ( routerinfo_t * router )
{
2004-11-28 10:05:49 +01:00
if ( router_digest_is_trusted_dir ( router - > identity_digest ) )
2004-07-20 21:45:29 +02:00
return 1 ;
return 0 ;
}
2004-05-10 06:34:48 +02:00
/*
2004-05-04 20:17:45 +02:00
* OR descriptor generation .
2004-05-10 06:34:48 +02:00
*/
2004-05-04 20:17:45 +02:00
2004-05-10 12:27:54 +02:00
/** My routerinfo. */
2004-05-04 20:17:45 +02:00
static routerinfo_t * desc_routerinfo = NULL ;
2005-08-22 05:10:53 +02:00
/** Since when has our descriptor been "clean"? 0 if we need to regenerate it
* now . */
static time_t desc_clean_since = 0 ;
2004-11-13 17:53:48 +01:00
/** Boolean: do we need to regenerate the above? */
static int desc_needs_upload = 0 ;
2004-05-04 20:17:45 +02:00
2005-03-17 13:38:37 +01:00
/** OR only: If <b>force</b> is true, or we haven't uploaded this
* descriptor successfully yet , try to upload our signed descriptor to
* all the directory servers we know about .
2004-05-04 20:17:45 +02:00
*/
2005-06-11 20:52:12 +02:00
void
router_upload_dir_desc_to_dirservers ( int force )
{
2004-03-31 00:57:49 +02:00
const char * s ;
2003-12-06 06:54:04 +01:00
2004-03-31 00:57:49 +02:00
s = router_get_my_descriptor ( ) ;
if ( ! s ) {
2003-12-06 06:54:04 +01:00
log_fn ( LOG_WARN , " No descriptor; skipping upload " ) ;
return ;
}
2005-08-23 02:47:44 +02:00
if ( ! force & & ! desc_needs_upload )
2004-11-13 17:53:48 +01:00
return ;
desc_needs_upload = 0 ;
2004-05-13 01:48:57 +02:00
directory_post_to_dirservers ( DIR_PURPOSE_UPLOAD_DIR , s , strlen ( s ) ) ;
2003-12-06 06:54:04 +01:00
}
2005-03-19 07:57:16 +01:00
/** OR only: Check whether my exit policy says to allow connection to
2005-07-01 04:01:21 +02:00
* conn . Return 0 if we accept ; non - 0 if we reject .
2003-12-06 06:54:04 +01:00
*/
2005-06-11 20:52:12 +02:00
int
router_compare_to_my_exit_policy ( connection_t * conn )
2004-04-07 21:46:27 +02:00
{
2004-04-25 22:37:37 +02:00
tor_assert ( desc_routerinfo ) ;
2004-07-07 21:49:48 +02:00
/* make sure it's resolved to something. this way we can't get a
' maybe ' below . */
if ( ! conn - > addr )
return - 1 ;
2004-11-12 20:39:13 +01:00
return router_compare_addr_to_addr_policy ( conn - > addr , conn - > port ,
2005-03-19 07:57:16 +01:00
desc_routerinfo - > exit_policy ) ! = ADDR_POLICY_ACCEPTED ;
2003-12-06 06:54:04 +01:00
}
2005-05-23 07:20:52 +02:00
/** Return true iff I'm a server and <b>digest</b> is equal to
* my identity digest . */
2005-06-11 20:52:12 +02:00
int
router_digest_is_me ( const char * digest )
2004-04-07 21:46:27 +02:00
{
2004-07-22 10:08:25 +02:00
routerinfo_t * me = router_get_my_routerinfo ( ) ;
2005-05-23 07:20:52 +02:00
if ( ! me | | memcmp ( me - > identity_digest , digest , DIGEST_LEN ) )
2004-07-22 10:08:25 +02:00
return 0 ;
return 1 ;
2004-04-07 21:46:27 +02:00
}
2005-05-23 07:20:52 +02:00
/** A wrapper around router_digest_is_me(). */
2005-06-11 20:52:12 +02:00
int
router_is_me ( routerinfo_t * router )
2005-05-23 07:20:52 +02:00
{
return router_digest_is_me ( router - > identity_digest ) ;
}
2005-09-08 22:18:15 +02:00
/** Return true iff <b>fp</b> is a hex fingerprint of my identity digest. */
int
router_fingerprint_is_me ( const char * fp )
{
char digest [ DIGEST_LEN ] ;
if ( strlen ( fp ) = = HEX_DIGEST_LEN & &
base16_decode ( digest , sizeof ( digest ) , fp , HEX_DIGEST_LEN ) = = 0 )
return router_digest_is_me ( digest ) ;
return 0 ;
}
2004-05-09 18:47:25 +02:00
/** Return a routerinfo for this OR, rebuilding a fresh one if
2004-05-04 20:17:45 +02:00
* necessary . Return NULL on error , or if called on an OP . */
2005-06-11 20:52:12 +02:00
routerinfo_t *
router_get_my_routerinfo ( void )
2004-04-06 00:22:42 +02:00
{
2004-11-06 06:18:11 +01:00
if ( ! server_mode ( get_options ( ) ) )
2004-04-06 00:22:42 +02:00
return NULL ;
if ( ! desc_routerinfo ) {
2004-11-13 17:53:48 +01:00
if ( router_rebuild_descriptor ( 1 ) )
2004-04-06 00:22:42 +02:00
return NULL ;
}
return desc_routerinfo ;
}
2004-05-09 18:47:25 +02:00
/** OR only: Return a signed server descriptor for this OR, rebuilding a fresh
2004-05-04 20:17:45 +02:00
* one if necessary . Return NULL on error .
*/
2005-06-11 20:52:12 +02:00
const char *
router_get_my_descriptor ( void )
{
2003-12-06 06:54:04 +01:00
if ( ! desc_routerinfo ) {
2004-11-13 17:53:48 +01:00
if ( router_rebuild_descriptor ( 1 ) )
2003-12-06 06:54:04 +01:00
return NULL ;
}
2005-02-25 21:46:13 +01:00
log_fn ( LOG_DEBUG , " my desc is '%s' " , desc_routerinfo - > signed_descriptor ) ;
return desc_routerinfo - > signed_descriptor ;
2003-12-06 06:54:04 +01:00
}
2005-10-06 01:20:45 +02:00
/*DOCDOC*/
static smartlist_t * warned_nonexistent_family = NULL ;
2005-03-17 13:38:37 +01:00
/** If <b>force</b> is true, or our descriptor is out-of-date, rebuild
* a fresh routerinfo and signed server descriptor for this OR .
* Return 0 on success , - 1 on error .
2004-05-04 20:17:45 +02:00
*/
2005-06-11 20:52:12 +02:00
int
router_rebuild_descriptor ( int force )
{
2003-12-06 06:54:04 +01:00
routerinfo_t * ri ;
2004-08-16 13:43:18 +02:00
uint32_t addr ;
2004-04-07 23:36:03 +02:00
char platform [ 256 ] ;
2004-12-12 00:53:59 +01:00
int hibernating = we_are_hibernating ( ) ;
2004-11-06 06:18:11 +01:00
or_options_t * options = get_options ( ) ;
2004-08-16 13:43:18 +02:00
2005-08-22 05:10:53 +02:00
if ( desc_clean_since & & ! force )
2004-11-13 17:53:48 +01:00
return 0 ;
2005-08-25 22:33:17 +02:00
if ( resolve_my_address ( options , & addr , NULL ) < 0 ) {
2004-11-06 06:18:11 +01:00
log_fn ( LOG_WARN , " options->Address didn't resolve into an IP. " ) ;
2004-04-07 00:23:12 +02:00
return - 1 ;
}
2003-12-06 06:54:04 +01:00
2004-03-04 02:53:56 +01:00
ri = tor_malloc_zero ( sizeof ( routerinfo_t ) ) ;
2005-08-26 09:41:19 +02:00
ri - > address = tor_dup_addr ( addr ) ;
2004-11-06 06:18:11 +01:00
ri - > nickname = tor_strdup ( options - > Nickname ) ;
2004-08-16 13:43:18 +02:00
ri - > addr = addr ;
2004-12-13 20:42:46 +01:00
ri - > or_port = options - > ORPort ;
2005-09-29 08:45:03 +02:00
ri - > dir_port = options - > DirPort ;
2003-12-06 06:54:04 +01:00
ri - > published_on = time ( NULL ) ;
2004-06-05 03:50:35 +02:00
ri - > onion_pkey = crypto_pk_dup_key ( get_onion_key ( ) ) ; /* must invoke from main thread */
2003-12-06 06:54:04 +01:00
ri - > identity_pkey = crypto_pk_dup_key ( get_identity_key ( ) ) ;
2004-07-01 03:16:59 +02:00
if ( crypto_pk_get_digest ( ri - > identity_pkey , ri - > identity_digest ) < 0 ) {
routerinfo_free ( ri ) ;
return - 1 ;
}
2004-04-07 23:36:03 +02:00
get_platform_str ( platform , sizeof ( platform ) ) ;
ri - > platform = tor_strdup ( platform ) ;
2004-11-22 23:24:10 +01:00
ri - > bandwidthrate = ( int ) options - > BandwidthRate ;
ri - > bandwidthburst = ( int ) options - > BandwidthBurst ;
2005-02-27 10:47:01 +01:00
ri - > bandwidthcapacity = hibernating ? 0 : rep_hist_bandwidth_assess ( ) ;
2005-03-22 20:01:46 +01:00
if ( options - > BandwidthRate > options - > MaxAdvertisedBandwidth )
ri - > bandwidthrate = ( int ) options - > MaxAdvertisedBandwidth ;
2005-08-08 23:58:48 +02:00
config_parse_addr_policy ( get_options ( ) - > ExitPolicy , & ri - > exit_policy , - 1 ) ;
2005-07-23 03:58:05 +02:00
options_append_default_exit_policy ( & ri - > exit_policy ) ;
2005-05-14 02:13:17 +02:00
2005-09-12 08:56:42 +02:00
if ( desc_routerinfo ) { /* inherit values */
2004-07-22 08:03:53 +02:00
ri - > is_verified = desc_routerinfo - > is_verified ;
2005-09-12 08:56:42 +02:00
ri - > is_running = desc_routerinfo - > is_running ;
ri - > is_named = desc_routerinfo - > is_named ;
}
2005-09-04 01:10:28 +02:00
if ( authdir_mode ( options ) )
2005-09-12 08:56:42 +02:00
ri - > is_verified = ri - > is_named = 1 ; /* believe in yourself */
2004-11-06 06:18:11 +01:00
if ( options - > MyFamily ) {
2005-10-07 20:56:21 +02:00
smartlist_t * family ;
2005-10-06 01:20:45 +02:00
if ( ! warned_nonexistent_family )
warned_nonexistent_family = smartlist_create ( ) ;
2005-10-07 20:56:21 +02:00
family = smartlist_create ( ) ;
2004-10-15 03:58:11 +02:00
ri - > declared_family = smartlist_create ( ) ;
2005-10-05 00:23:31 +02:00
smartlist_split_string ( family , options - > MyFamily , " , " ,
2004-10-15 03:58:11 +02:00
SPLIT_SKIP_SPACE | SPLIT_IGNORE_BLANK , 0 ) ;
2005-10-05 00:23:31 +02:00
SMARTLIST_FOREACH ( family , char * , name ,
{
routerinfo_t * member ;
if ( ! strcasecmp ( name , options - > Nickname ) )
member = ri ;
else
member = router_get_by_nickname ( name , 1 ) ;
if ( ! member ) {
2005-10-06 01:20:45 +02:00
if ( ! smartlist_string_isin ( warned_nonexistent_family , name ) ) {
log_fn ( LOG_WARN , " I have no descriptor for the router named \" %s \" "
" in my declared family; I'll use the nickname as is, but "
" this may confuse clients. " , name ) ;
smartlist_add ( warned_nonexistent_family , tor_strdup ( name ) ) ;
}
2005-10-05 00:23:31 +02:00
smartlist_add ( ri - > declared_family , name ) ;
name = NULL ;
} else {
char * fp = tor_malloc ( HEX_DIGEST_LEN + 2 ) ;
fp [ 0 ] = ' $ ' ;
base16_encode ( fp + 1 , HEX_DIGEST_LEN + 1 ,
member - > identity_digest , DIGEST_LEN ) ;
smartlist_add ( ri - > declared_family , fp ) ;
2005-10-06 01:20:45 +02:00
if ( smartlist_string_isin ( warned_nonexistent_family , name ) )
smartlist_string_remove ( warned_nonexistent_family , name ) ;
2005-10-05 00:23:31 +02:00
}
tor_free ( name ) ;
} ) ;
smartlist_free ( family ) ;
2004-10-15 03:58:11 +02:00
}
2005-02-25 21:46:13 +01:00
ri - > signed_descriptor = tor_malloc ( 8192 ) ;
if ( router_dump_router_to_string ( ri - > signed_descriptor , 8192 ,
ri , get_identity_key ( ) ) < 0 ) {
2005-09-23 10:29:58 +02:00
log_fn ( LOG_WARN , " Couldn't allocate string for descriptor. " ) ;
2005-02-25 21:46:13 +01:00
return - 1 ;
}
2005-08-25 22:33:17 +02:00
ri - > signed_descriptor_len = strlen ( ri - > signed_descriptor ) ;
crypto_digest ( ri - > signed_descriptor_digest ,
ri - > signed_descriptor , ri - > signed_descriptor_len ) ;
2004-07-22 08:03:53 +02:00
2003-12-06 06:54:04 +01:00
if ( desc_routerinfo )
routerinfo_free ( desc_routerinfo ) ;
desc_routerinfo = ri ;
2005-02-25 21:46:13 +01:00
2005-08-22 05:10:53 +02:00
desc_clean_since = time ( NULL ) ;
2004-11-13 17:53:48 +01:00
desc_needs_upload = 1 ;
2003-12-06 06:54:04 +01:00
return 0 ;
}
2005-08-22 05:10:53 +02:00
/** Mark descriptor out of date if it's older than <b>when</b> */
void
mark_my_descriptor_dirty_if_older_than ( time_t when )
{
if ( desc_clean_since < when )
mark_my_descriptor_dirty ( ) ;
}
2005-03-17 13:38:37 +01:00
/** Call when the current descriptor is out of date. */
2004-11-13 17:53:48 +01:00
void
mark_my_descriptor_dirty ( void )
{
2005-08-22 05:10:53 +02:00
desc_clean_since = 0 ;
}
2005-08-22 23:53:12 +02:00
# define MAX_BANDWIDTH_CHANGE_FREQ 20*60
2005-08-22 05:10:53 +02:00
/** Check whether bandwidth has changed a lot since the last time we announced
* bandwidth . If so , mark our descriptor dirty . */
void
check_descriptor_bandwidth_changed ( time_t now )
{
static time_t last_changed = 0 ;
uint64_t prev , cur ;
if ( ! desc_routerinfo )
return ;
prev = desc_routerinfo - > bandwidthcapacity ;
cur = we_are_hibernating ( ) ? 0 : rep_hist_bandwidth_assess ( ) ;
if ( ( prev ! = cur & & ( ! prev | | ! cur ) ) | |
cur > prev * 2 | |
cur < prev / 2 ) {
if ( last_changed + MAX_BANDWIDTH_CHANGE_FREQ < now ) {
log_fn ( LOG_INFO , " Measured bandwidth has changed; rebuilding descriptor. " ) ;
mark_my_descriptor_dirty ( ) ;
last_changed = now ;
}
}
2004-11-13 17:53:48 +01:00
}
2005-10-13 00:41:16 +02:00
# define MAX_IPADDRESS_CHANGE_FREQ 60*60
/** Check whether our own address as defined by the Address configuration
* has changed . This is for routers that get their address from a service
* like dyndns . If our address has changed , mark our descriptor dirty . */
void
check_descriptor_ipaddress_changed ( time_t now )
{
static time_t last_changed = 0 ;
static time_t last_warned_lastchangetime = 0 ;
uint32_t prev , cur ;
or_options_t * options = get_options ( ) ;
if ( ! desc_routerinfo )
return ;
prev = desc_routerinfo - > addr ;
if ( resolve_my_address ( options , & cur , NULL ) < 0 ) {
log_fn ( LOG_WARN , " options->Address didn't resolve into an IP. " ) ;
return ;
}
if ( prev ! = cur ) {
char addrbuf_prev [ INET_NTOA_BUF_LEN ] ;
char addrbuf_cur [ INET_NTOA_BUF_LEN ] ;
struct in_addr in_prev ;
struct in_addr in_cur ;
in_prev . s_addr = htonl ( prev ) ;
tor_inet_ntoa ( & in_prev , addrbuf_prev , sizeof ( addrbuf_prev ) ) ;
in_cur . s_addr = htonl ( cur ) ;
tor_inet_ntoa ( & in_cur , addrbuf_cur , sizeof ( addrbuf_cur ) ) ;
if ( last_changed + MAX_IPADDRESS_CHANGE_FREQ < now ) {
log_fn ( LOG_INFO , " Our IP Address has changed from %s to %s; rebuilding descriptor. " , addrbuf_prev , addrbuf_cur ) ;
mark_my_descriptor_dirty ( ) ;
last_changed = now ;
last_warned_lastchangetime = 0 ;
}
else
{
if ( last_warned_lastchangetime ! = last_changed ) {
log_fn ( LOG_WARN , " Our IP Address seems to be flapping. It has changed twice within one hour (from %s to %s this time). Ignoring for now. " , addrbuf_prev , addrbuf_cur ) ;
last_warned_lastchangetime = last_changed ;
}
}
}
}
2004-05-10 06:34:48 +02:00
/** Set <b>platform</b> (max length <b>len</b>) to a NUL-terminated short
* string describing the version of Tor and the operating system we ' re
2004-05-04 20:17:45 +02:00
* currently running on .
*/
2005-06-11 20:52:12 +02:00
void
get_platform_str ( char * platform , size_t len )
2003-12-06 06:54:04 +01:00
{
2004-12-02 05:16:18 +01:00
tor_snprintf ( platform , len , " Tor %s on %s " ,
2004-07-20 23:13:11 +02:00
VERSION , get_uname ( ) ) ;
2003-12-06 06:54:04 +01:00
return ;
}
/* XXX need to audit this thing and count fenceposts. maybe
* refactor so we don ' t have to keep asking if we ' re
* near the end of maxlen ?
*/
# define DEBUG_ROUTER_DUMP_ROUTER_TO_STRING
2004-05-04 20:17:45 +02:00
2004-05-10 06:34:48 +02:00
/** OR only: Given a routerinfo for this router, and an identity key to sign
* with , encode the routerinfo as a signed server descriptor and write the
* result into < b > s < / b > , using at most < b > maxlen < / b > bytes . Return - 1 on
* failure , and the number of bytes used on success .
2004-05-04 20:17:45 +02:00
*/
2005-06-11 20:52:12 +02:00
int
router_dump_router_to_string ( char * s , size_t maxlen , routerinfo_t * router ,
crypto_pk_env_t * ident_key )
{
2004-05-04 20:17:45 +02:00
char * onion_pkey ; /* Onion key, PEM-encoded. */
char * identity_pkey ; /* Identity key, PEM-encoded. */
2005-08-26 17:34:53 +02:00
char digest [ DIGEST_LEN ] ;
char published [ ISO_TIME_LEN + 1 ] ;
2004-07-22 08:22:04 +02:00
char fingerprint [ FINGERPRINT_LEN + 1 ] ;
2004-05-04 20:17:45 +02:00
struct in_addr in ;
2005-02-22 09:18:36 +01:00
char addrbuf [ INET_NTOA_BUF_LEN ] ;
2004-10-14 04:47:09 +02:00
size_t onion_pkeylen , identity_pkeylen ;
size_t written ;
2003-12-06 06:54:04 +01:00
int result = 0 ;
2004-12-04 02:14:36 +01:00
addr_policy_t * tmpe ;
2004-08-07 04:46:16 +02:00
char * bandwidth_usage ;
2004-10-15 03:58:11 +02:00
char * family_line ;
2003-12-06 06:54:04 +01:00
# ifdef DEBUG_ROUTER_DUMP_ROUTER_TO_STRING
2003-12-17 22:09:31 +01:00
char * s_tmp , * s_dup ;
2003-12-09 00:45:37 +01:00
const char * cp ;
2003-12-06 06:54:04 +01:00
routerinfo_t * ri_tmp ;
# endif
2005-07-15 20:49:35 +02:00
or_options_t * options = get_options ( ) ;
2003-12-17 22:09:31 +01:00
2004-05-04 20:17:45 +02:00
/* Make sure the identity key matches the one in the routerinfo. */
2003-12-06 06:54:04 +01:00
if ( crypto_pk_cmp_keys ( ident_key , router - > identity_pkey ) ) {
log_fn ( LOG_WARN , " Tried to sign a router with a private key that didn't match router's public key! " ) ;
return - 1 ;
}
2004-07-22 08:22:04 +02:00
/* record our fingerprint, so we can include it in the descriptor */
2004-10-06 15:31:48 +02:00
if ( crypto_pk_get_fingerprint ( router - > identity_pkey , fingerprint , 1 ) < 0 ) {
2004-07-22 08:22:04 +02:00
log_fn ( LOG_ERR , " Error computing fingerprint " ) ;
return - 1 ;
}
2004-05-04 20:17:45 +02:00
/* PEM-encode the onion key */
2004-11-28 10:05:49 +01:00
if ( crypto_pk_write_public_key_to_string ( router - > onion_pkey ,
2004-11-28 12:39:53 +01:00
& onion_pkey , & onion_pkeylen ) < 0 ) {
2003-12-06 06:54:04 +01:00
log_fn ( LOG_WARN , " write onion_pkey to string failed! " ) ;
return - 1 ;
}
2004-05-04 20:17:45 +02:00
/* PEM-encode the identity key key */
2004-11-28 10:05:49 +01:00
if ( crypto_pk_write_public_key_to_string ( router - > identity_pkey ,
2004-11-28 12:39:53 +01:00
& identity_pkey , & identity_pkeylen ) < 0 ) {
2003-12-06 06:54:04 +01:00
log_fn ( LOG_WARN , " write identity_pkey to string failed! " ) ;
2004-05-04 20:17:45 +02:00
tor_free ( onion_pkey ) ;
2003-12-06 06:54:04 +01:00
return - 1 ;
}
2004-05-04 20:17:45 +02:00
/* Encode the publication time. */
2004-08-07 04:46:16 +02:00
format_iso_time ( published , router - > published_on ) ;
2003-12-17 22:09:31 +01:00
2004-08-07 04:46:16 +02:00
/* How busy have we been? */
bandwidth_usage = rep_hist_get_bandwidth_lines ( ) ;
2004-08-09 06:27:13 +02:00
2004-10-15 03:58:11 +02:00
if ( router - > declared_family & & smartlist_len ( router - > declared_family ) ) {
2004-11-03 19:33:07 +01:00
size_t n ;
char * s = smartlist_join_strings ( router - > declared_family , " " , 0 , & n ) ;
2005-05-02 23:22:31 +02:00
n + = strlen ( " family " ) + 2 ; /* 1 for \n, 1 for \0. */
2004-10-15 03:58:11 +02:00
family_line = tor_malloc ( n ) ;
2005-05-02 23:22:31 +02:00
tor_snprintf ( family_line , n , " family %s \n " , s ) ;
2004-10-15 03:58:11 +02:00
tor_free ( s ) ;
} else {
family_line = tor_strdup ( " " ) ;
}
2004-05-04 20:17:45 +02:00
/* Generate the easy portion of the router descriptor. */
2004-10-27 08:37:34 +02:00
result = tor_snprintf ( s , maxlen ,
2005-01-04 06:46:54 +01:00
" router %s %s %d 0 %d \n "
2003-12-06 06:54:04 +01:00
" platform %s \n "
" published %s \n "
2004-07-22 08:22:04 +02:00
" opt fingerprint %s \n "
2005-05-02 23:22:31 +02:00
" uptime %ld \n "
2004-07-12 20:02:54 +02:00
" bandwidth %d %d %d \n "
2003-12-06 06:54:04 +01:00
" onion-key \n %s "
2005-03-22 07:08:28 +01:00
" signing-key \n %s%s%s%s " ,
2003-12-06 06:54:04 +01:00
router - > nickname ,
router - > address ,
router - > or_port ,
2005-09-29 08:45:03 +02:00
decide_to_advertise_dirport ( options , router ) ,
2004-04-07 23:36:03 +02:00
router - > platform ,
2003-12-06 06:54:04 +01:00
published ,
2004-07-22 08:22:04 +02:00
fingerprint ,
2005-01-10 06:10:22 +01:00
stats_n_seconds_working ,
2004-04-25 00:17:50 +02:00
( int ) router - > bandwidthrate ,
( int ) router - > bandwidthburst ,
2004-08-15 10:15:12 +02:00
( int ) router - > bandwidthcapacity ,
2004-08-07 04:46:16 +02:00
onion_pkey , identity_pkey ,
2005-03-22 07:08:28 +01:00
family_line , bandwidth_usage ,
we_are_hibernating ( ) ? " opt hibernating 1 \n " : " " ) ;
2004-10-16 22:38:57 +02:00
tor_free ( family_line ) ;
2004-05-04 20:17:45 +02:00
tor_free ( onion_pkey ) ;
tor_free ( identity_pkey ) ;
2004-08-07 04:59:46 +02:00
tor_free ( bandwidth_usage ) ;
2003-12-06 06:54:04 +01:00
2004-12-02 05:31:52 +01:00
if ( result < 0 )
2003-12-06 06:54:04 +01:00
return - 1 ;
2004-05-04 20:17:45 +02:00
/* From now on, we use 'written' to remember the current length of 's'. */
2003-12-06 06:54:04 +01:00
written = result ;
2005-07-15 20:49:35 +02:00
if ( options - > ContactInfo & & strlen ( options - > ContactInfo ) ) {
2005-05-02 23:22:31 +02:00
result = tor_snprintf ( s + written , maxlen - written , " contact %s \n " ,
2005-07-15 20:49:35 +02:00
options - > ContactInfo ) ;
2004-12-02 05:31:52 +01:00
if ( result < 0 )
2004-06-21 06:37:27 +02:00
return - 1 ;
written + = result ;
}
2004-05-04 20:17:45 +02:00
/* Write the exit policy to the end of 's'. */
2004-11-28 10:05:49 +01:00
for ( tmpe = router - > exit_policy ; tmpe ; tmpe = tmpe - > next ) {
2004-05-04 20:17:45 +02:00
/* Write: "accept 1.2.3.4" */
2005-04-02 10:55:31 +02:00
in . s_addr = htonl ( tmpe - > addr ) ;
2005-02-22 09:18:36 +01:00
tor_inet_ntoa ( & in , addrbuf , sizeof ( addrbuf ) ) ;
2004-10-27 08:37:34 +02:00
result = tor_snprintf ( s + written , maxlen - written , " %s %s " ,
2004-11-12 20:39:13 +01:00
tmpe - > policy_type = = ADDR_POLICY_ACCEPT ? " accept " : " reject " ,
2005-02-22 09:18:36 +01:00
tmpe - > msk = = 0 ? " * " : addrbuf ) ;
2004-12-02 05:31:52 +01:00
if ( result < 0 )
2003-12-06 06:54:04 +01:00
return - 1 ;
written + = result ;
if ( tmpe - > msk ! = 0xFFFFFFFFu & & tmpe - > msk ! = 0 ) {
2004-05-04 20:17:45 +02:00
/* Write "/255.255.0.0" */
2003-12-06 06:54:04 +01:00
in . s_addr = htonl ( tmpe - > msk ) ;
2005-04-02 10:55:31 +02:00
tor_inet_ntoa ( & in , addrbuf , sizeof ( addrbuf ) ) ;
2005-02-22 09:18:36 +01:00
result = tor_snprintf ( s + written , maxlen - written , " /%s " , addrbuf ) ;
2004-12-02 05:31:52 +01:00
if ( result < 0 )
2003-12-06 06:54:04 +01:00
return - 1 ;
written + = result ;
}
2004-10-13 03:25:42 +02:00
if ( tmpe - > prt_min < = 1 & & tmpe - > prt_max = = 65535 ) {
2004-05-04 20:17:45 +02:00
/* There is no port set; write ":*" */
2004-12-02 05:31:52 +01:00
if ( written + 4 > maxlen )
2003-12-13 03:44:02 +01:00
return - 1 ;
2004-10-27 08:25:29 +02:00
strlcat ( s + written , " :* \n " , maxlen - written ) ;
2003-12-13 03:44:02 +01:00
written + = 3 ;
} else if ( tmpe - > prt_min = = tmpe - > prt_max ) {
2004-05-04 20:17:45 +02:00
/* There is only one port; write ":80". */
2004-10-27 08:37:34 +02:00
result = tor_snprintf ( s + written , maxlen - written , " :%d \n " , tmpe - > prt_min ) ;
2004-12-02 05:31:52 +01:00
if ( result < 0 )
2003-12-06 06:54:04 +01:00
return - 1 ;
written + = result ;
} else {
2004-05-04 20:17:45 +02:00
/* There is a range of ports; write ":79-80". */
2004-10-27 08:37:34 +02:00
result = tor_snprintf ( s + written , maxlen - written , " :%d-%d \n " , tmpe - > prt_min ,
2003-12-13 03:44:02 +01:00
tmpe - > prt_max ) ;
2004-12-02 05:31:52 +01:00
if ( result < 0 )
2003-12-06 06:54:04 +01:00
return - 1 ;
2003-12-13 03:44:02 +01:00
written + = result ;
2003-12-06 06:54:04 +01:00
}
2004-10-13 03:25:42 +02:00
if ( tmpe - > msk = = 0 & & tmpe - > prt_min < = 1 & & tmpe - > prt_max = = 65535 )
/* This was a catch-all rule, so future rules are irrelevant. */
break ;
2003-12-06 06:54:04 +01:00
} /* end for */
2004-12-02 05:31:52 +01:00
if ( written + 256 > maxlen ) /* Not enough room for signature. */
2003-12-06 06:54:04 +01:00
return - 1 ;
2004-05-04 20:17:45 +02:00
/* Sign the directory */
2004-10-27 08:25:29 +02:00
strlcat ( s + written , " router-signature \n " , maxlen - written ) ;
2003-12-06 06:54:04 +01:00
written + = strlen ( s + written ) ;
s [ written ] = ' \0 ' ;
if ( router_get_router_hash ( s , digest ) < 0 )
return - 1 ;
2005-08-26 17:34:53 +02:00
if ( router_append_dirobj_signature ( s + written , maxlen - written ,
digest , ident_key ) < 0 ) {
log_fn ( LOG_WARN , " Couldn't sign router descriptor " ) ;
2003-12-06 06:54:04 +01:00
return - 1 ;
}
written + = strlen ( s + written ) ;
2003-12-17 22:09:31 +01:00
2004-12-02 05:31:52 +01:00
if ( written + 2 > maxlen )
2003-12-06 06:54:04 +01:00
return - 1 ;
/* include a last '\n' */
s [ written ] = ' \n ' ;
s [ written + 1 ] = 0 ;
# ifdef DEBUG_ROUTER_DUMP_ROUTER_TO_STRING
2003-12-09 00:45:37 +01:00
cp = s_tmp = s_dup = tor_strdup ( s ) ;
2004-05-10 19:30:51 +02:00
ri_tmp = router_parse_entry_from_string ( cp , NULL ) ;
2003-12-06 06:54:04 +01:00
if ( ! ri_tmp ) {
2003-12-17 22:09:31 +01:00
log_fn ( LOG_ERR , " We just generated a router descriptor we can't parse: <<%s>> " ,
2003-12-06 06:54:04 +01:00
s ) ;
return - 1 ;
}
2004-09-29 08:52:36 +02:00
tor_free ( s_dup ) ;
2003-12-06 06:54:04 +01:00
routerinfo_free ( ri_tmp ) ;
# endif
return written + 1 ;
}
2005-03-17 13:38:37 +01:00
/** Return true iff <b>s</b> is a legally valid server nickname. */
2005-06-11 20:52:12 +02:00
int
is_legal_nickname ( const char * s )
2004-08-18 06:44:24 +02:00
{
size_t len ;
tor_assert ( s ) ;
len = strlen ( s ) ;
return len > 0 & & len < = MAX_NICKNAME_LEN & &
strspn ( s , LEGAL_NICKNAME_CHARACTERS ) = = len ;
}
2005-03-17 13:38:37 +01:00
/** Return true iff <b>s</b> is a legally valid server nickname or
* hex - encoded identity - key digest . */
2005-06-11 20:52:12 +02:00
int
is_legal_nickname_or_hexdigest ( const char * s )
2004-08-18 06:44:24 +02:00
{
size_t len ;
tor_assert ( s ) ;
if ( * s ! = ' $ ' )
return is_legal_nickname ( s ) ;
len = strlen ( s ) ;
return len = = HEX_DIGEST_LEN + 1 & & strspn ( s + 1 , HEX_CHARACTERS ) = = len - 1 ;
}
2005-10-06 01:20:45 +02:00
/** Forget that we have issued any router-related warnings, so that we'll
* warn again if we see the same errors . */
void
router_reset_warnings ( void )
{
if ( warned_nonexistent_family ) {
SMARTLIST_FOREACH ( warned_nonexistent_family , char * , cp , tor_free ( cp ) ) ;
smartlist_clear ( warned_nonexistent_family ) ;
}
}
/** Release all static resources held in router.c */
2005-06-11 20:52:12 +02:00
void
2005-10-06 01:20:45 +02:00
router_free_all ( void )
2005-02-11 02:26:47 +01:00
{
if ( onionkey )
crypto_free_pk_env ( onionkey ) ;
if ( lastonionkey )
crypto_free_pk_env ( lastonionkey ) ;
if ( identitykey )
crypto_free_pk_env ( identitykey ) ;
if ( key_lock )
tor_mutex_free ( key_lock ) ;
if ( desc_routerinfo )
routerinfo_free ( desc_routerinfo ) ;
2005-10-06 01:20:45 +02:00
if ( warned_nonexistent_family ) {
SMARTLIST_FOREACH ( warned_nonexistent_family , char * , cp , tor_free ( cp ) ) ;
smartlist_free ( warned_nonexistent_family ) ;
}
2005-02-11 02:26:47 +01:00
}
2005-10-06 06:33:40 +02:00