2004-11-07 02:33:06 +01:00
/* Copyright 2001-2004 Roger Dingledine.
2005-04-01 22:15:56 +02:00
* Copyright 2004 - 2005 Roger Dingledine , Nick Mathewson . */
2003-09-27 23:30:10 +02:00
/* See LICENSE for licensing information */
/* $Id$ */
2004-11-29 23:25:31 +01:00
const char dirserv_c_id [ ] = " $Id$ " ;
2003-09-27 23:30:10 +02:00
# include "or.h"
2004-05-09 18:47:25 +02:00
/**
* \ file dirserv . c
* \ brief Directory server core implementation .
2004-05-10 06:34:48 +02:00
* */
2004-05-05 02:30:43 +02:00
2004-05-09 18:47:25 +02:00
/** How far in the future do we allow a router to get? (seconds) */
2005-04-07 23:01:00 +02:00
# define ROUTER_ALLOW_SKEW (60*60*12) /* 12 hours */
2004-09-23 21:58:44 +02:00
/** How many seconds do we wait before regenerating the directory? */
2005-04-27 02:48:05 +02:00
# define DIR_REGEN_SLACK_TIME 5
2003-10-22 18:41:35 +02:00
2004-05-09 18:47:25 +02:00
/** Do we need to regenerate the directory when someone asks for it? */
2003-09-27 23:30:10 +02:00
static int the_directory_is_dirty = 1 ;
2004-06-25 02:29:31 +02:00
static int runningrouters_is_dirty = 1 ;
2003-09-27 23:30:10 +02:00
2004-04-13 22:06:08 +02:00
static void directory_remove_unrecognized ( void ) ;
2004-09-02 20:57:09 +02:00
static int dirserv_regenerate_directory ( void ) ;
2004-11-02 04:02:17 +01:00
/* Should be static; exposed for testing */
void add_fingerprint_to_dir ( const char * nickname , const char * fp ) ;
2003-10-01 02:43:34 +02:00
2003-09-29 09:50:08 +02:00
/************** Fingerprint handling code ************/
2003-09-27 23:30:10 +02:00
typedef struct fingerprint_entry_t {
char * nickname ;
2004-10-06 15:31:48 +02:00
char * fingerprint ; /**< Stored as HEX_DIGEST_LEN characters, followed by a NUL */
2003-09-27 23:30:10 +02:00
} fingerprint_entry_t ;
2004-05-10 06:34:48 +02:00
/** List of nickname-\>identity fingerprint mappings for all the routers
2004-05-05 02:30:43 +02:00
* that we recognize . Used to prevent Sybil attacks . */
2004-05-18 19:41:40 +02:00
static smartlist_t * fingerprint_list = NULL ;
2003-09-27 23:30:10 +02:00
2004-05-10 06:34:48 +02:00
/** Add the fingerprint <b>fp</b> for the nickname <b>nickname</b> to
* the global list of recognized identity key fingerprints .
2004-05-05 02:30:43 +02:00
*/
2004-03-29 21:50:59 +02:00
void /* Should be static; exposed for testing */
2003-09-30 21:27:54 +02:00
add_fingerprint_to_dir ( const char * nickname , const char * fp )
{
int i ;
2004-05-18 19:41:40 +02:00
fingerprint_entry_t * ent ;
if ( ! fingerprint_list )
fingerprint_list = smartlist_create ( ) ;
for ( i = 0 ; i < smartlist_len ( fingerprint_list ) ; + + i ) {
ent = smartlist_get ( fingerprint_list , i ) ;
if ( ! strcasecmp ( ent - > nickname , nickname ) ) {
tor_free ( ent - > fingerprint ) ;
ent - > fingerprint = tor_strdup ( fp ) ;
2003-09-30 21:27:54 +02:00
return ;
}
}
2004-05-18 19:41:40 +02:00
ent = tor_malloc ( sizeof ( fingerprint_entry_t ) ) ;
ent - > nickname = tor_strdup ( nickname ) ;
ent - > fingerprint = tor_strdup ( fp ) ;
2004-10-06 15:31:48 +02:00
tor_strstrip ( ent - > fingerprint , " " ) ;
2004-05-18 19:41:40 +02:00
smartlist_add ( fingerprint_list , ent ) ;
2003-09-30 21:27:54 +02:00
}
2004-05-09 18:47:25 +02:00
/** Add the nickname and fingerprint for this OR to the recognized list.
2004-05-05 02:30:43 +02:00
*/
2003-09-30 21:27:54 +02:00
int
dirserv_add_own_fingerprint ( const char * nickname , crypto_pk_env_t * pk )
{
char fp [ FINGERPRINT_LEN + 1 ] ;
2004-10-06 15:31:48 +02:00
if ( crypto_pk_get_fingerprint ( pk , fp , 0 ) < 0 ) {
2003-09-30 21:27:54 +02:00
log_fn ( LOG_ERR , " Error computing fingerprint " ) ;
return - 1 ;
}
add_fingerprint_to_dir ( nickname , fp ) ;
return 0 ;
}
2004-05-10 06:34:48 +02:00
/** Parse the nickname-\>fingerprint mappings stored in the file named
* < b > fname < / b > . The file format is line - based , with each non - blank
2004-05-05 02:30:43 +02:00
* holding one nickname , some space , and a fingerprint for that
* nickname . On success , replace the current fingerprint list with
2004-05-10 06:34:48 +02:00
* the contents of < b > fname < / b > and return 0. On failure , leave the
2004-05-05 02:30:43 +02:00
* current fingerprint list untouched , and return - 1. */
2003-12-14 07:03:46 +01:00
int
2003-09-27 23:30:10 +02:00
dirserv_parse_fingerprint_file ( const char * fname )
{
2004-11-06 06:18:11 +01:00
char * cf ;
2003-09-29 09:50:08 +02:00
char * nickname , * fingerprint ;
2004-05-18 19:41:40 +02:00
smartlist_t * fingerprint_list_new ;
2003-09-29 09:50:08 +02:00
int i , result ;
2004-05-18 19:41:40 +02:00
fingerprint_entry_t * ent ;
2004-11-06 06:18:11 +01:00
struct config_line_t * front = NULL , * list ;
2003-09-29 09:50:08 +02:00
2004-11-06 06:18:11 +01:00
cf = read_file_to_str ( fname , 0 ) ;
if ( ! cf ) {
2003-10-10 03:48:32 +02:00
log_fn ( LOG_WARN , " Cannot open fingerprint file %s " , fname ) ;
2003-09-29 09:50:08 +02:00
return - 1 ;
2003-09-27 23:30:10 +02:00
}
2004-11-06 06:18:11 +01:00
result = config_get_lines ( cf , & front ) ;
tor_free ( cf ) ;
if ( result < 0 ) {
log_fn ( LOG_WARN , " Error reading from fingerprint file " ) ;
return - 1 ;
}
2004-05-18 19:41:40 +02:00
fingerprint_list_new = smartlist_create ( ) ;
2004-11-06 06:18:11 +01:00
2004-11-28 10:05:49 +01:00
for ( list = front ; list ; list = list - > next ) {
2004-11-06 06:18:11 +01:00
nickname = list - > key ; fingerprint = list - > value ;
2003-09-27 23:30:10 +02:00
if ( strlen ( nickname ) > MAX_NICKNAME_LEN ) {
2004-12-13 01:44:39 +01:00
log ( LOG_NOTICE , " Nickname '%s' too long in fingerprint file. Skipping. " , nickname ) ;
2003-09-29 09:50:08 +02:00
continue ;
2003-09-27 23:30:10 +02:00
}
2004-11-28 10:05:49 +01:00
if ( strlen ( fingerprint ) ! = FINGERPRINT_LEN | |
2004-11-28 12:39:53 +01:00
! crypto_pk_check_fingerprint_syntax ( fingerprint ) ) {
2004-12-13 01:44:39 +01:00
log_fn ( LOG_NOTICE , " Invalid fingerprint (nickname '%s', fingerprint %s). Skipping. " ,
2003-09-29 09:50:08 +02:00
nickname , fingerprint ) ;
continue ;
2003-09-27 23:30:10 +02:00
}
2004-11-09 21:04:00 +01:00
if ( 0 = = strcasecmp ( nickname , DEFAULT_CLIENT_NICKNAME ) ) {
2004-11-09 19:22:17 +01:00
/* If you approved an OR called "client", then clients who use
* the default nickname could all be rejected . That ' s no good . */
2004-12-13 01:44:39 +01:00
log ( LOG_NOTICE ,
2004-11-09 19:22:17 +01:00
" Authorizing a nickname '%s' would break many clients; skipping. " ,
DEFAULT_CLIENT_NICKNAME ) ;
continue ;
}
2004-05-18 19:41:40 +02:00
for ( i = 0 ; i < smartlist_len ( fingerprint_list_new ) ; + + i ) {
ent = smartlist_get ( fingerprint_list_new , i ) ;
if ( 0 = = strcasecmp ( ent - > nickname , nickname ) ) {
2004-12-13 01:44:39 +01:00
log ( LOG_NOTICE , " Duplicate nickname '%s'. Skipping. " , nickname ) ;
2003-09-29 09:50:08 +02:00
break ; /* out of the for. the 'if' below means skip to the next line. */
2003-09-27 23:30:10 +02:00
}
}
2004-11-28 10:05:49 +01:00
if ( i = = smartlist_len ( fingerprint_list_new ) ) { /* not a duplicate */
2004-05-18 19:41:40 +02:00
ent = tor_malloc ( sizeof ( fingerprint_entry_t ) ) ;
ent - > nickname = tor_strdup ( nickname ) ;
ent - > fingerprint = tor_strdup ( fingerprint ) ;
2004-10-06 15:31:48 +02:00
tor_strstrip ( ent - > fingerprint , " " ) ;
2004-05-18 19:41:40 +02:00
smartlist_add ( fingerprint_list_new , ent ) ;
2003-09-29 09:50:08 +02:00
}
2003-09-27 23:30:10 +02:00
}
2004-11-06 06:18:11 +01:00
config_free_lines ( front ) ;
dirserv_free_fingerprint_list ( ) ;
fingerprint_list = fingerprint_list_new ;
/* Delete any routers whose fingerprints we no longer recognize */
directory_remove_unrecognized ( ) ;
return 0 ;
2003-12-14 06:25:23 +01:00
}
2003-09-27 23:30:10 +02:00
2004-05-10 06:34:48 +02:00
/** Check whether <b>router</b> has a nickname/identity key combination that
2004-05-05 02:30:43 +02:00
* we recognize from the fingerprint list . Return 1 if router ' s
* identity and nickname match , - 1 if we recognize the nickname but
* the identity key is wrong , and 0 if the nickname is not known . */
2003-09-27 23:30:10 +02:00
int
dirserv_router_fingerprint_is_known ( const routerinfo_t * router )
{
2004-05-18 19:41:40 +02:00
int i , found = 0 ;
2003-09-27 23:30:10 +02:00
fingerprint_entry_t * ent = NULL ;
char fp [ FINGERPRINT_LEN + 1 ] ;
2004-05-18 19:41:40 +02:00
if ( ! fingerprint_list )
fingerprint_list = smartlist_create ( ) ;
log_fn ( LOG_DEBUG , " %d fingerprints known. " , smartlist_len ( fingerprint_list ) ) ;
for ( i = 0 ; i < smartlist_len ( fingerprint_list ) ; + + i ) {
ent = smartlist_get ( fingerprint_list , i ) ;
log_fn ( LOG_DEBUG , " %s vs %s " , router - > nickname , ent - > nickname ) ;
if ( ! strcasecmp ( router - > nickname , ent - > nickname ) ) {
found = 1 ;
2003-09-27 23:30:10 +02:00
break ;
}
}
2003-12-13 23:53:17 +01:00
2004-05-18 19:41:40 +02:00
if ( ! found ) { /* No such server known */
2004-11-25 05:20:10 +01:00
log_fn ( LOG_INFO , " no fingerprint found for '%s' " , router - > nickname ) ;
2003-09-27 23:30:10 +02:00
return 0 ;
}
2004-10-06 15:31:48 +02:00
if ( crypto_pk_get_fingerprint ( router - > identity_pkey , fp , 0 ) ) {
2003-10-10 03:48:32 +02:00
log_fn ( LOG_WARN , " error computing fingerprint " ) ;
2003-11-12 06:12:51 +01:00
return - 1 ;
2003-09-27 23:30:10 +02:00
}
if ( 0 = = strcasecmp ( ent - > fingerprint , fp ) ) {
2004-11-25 05:20:10 +01:00
log_fn ( LOG_DEBUG , " good fingerprint for '%s' " , router - > nickname ) ;
2003-09-29 09:50:08 +02:00
return 1 ; /* Right fingerprint. */
2003-09-27 23:30:10 +02:00
} else {
2004-11-25 05:20:10 +01:00
log_fn ( LOG_WARN , " mismatched fingerprint for '%s' " , router - > nickname ) ;
2003-11-12 06:12:51 +01:00
return - 1 ; /* Wrong fingerprint. */
2003-09-27 23:30:10 +02:00
}
}
2004-09-29 01:27:41 +02:00
/** If we are an authoritative dirserver, and the list of approved
2004-09-29 00:24:56 +02:00
* servers contains one whose identity key digest is < b > digest < / b > ,
* return that router ' s nickname . Otherwise return NULL . */
const char * dirserv_get_nickname_by_digest ( const char * digest )
2004-05-05 06:55:00 +02:00
{
2004-10-13 21:17:27 +02:00
char hexdigest [ HEX_DIGEST_LEN + 1 ] ;
2004-05-18 19:41:40 +02:00
if ( ! fingerprint_list )
2004-09-29 00:24:56 +02:00
return NULL ;
tor_assert ( digest ) ;
2004-10-13 21:17:27 +02:00
base16_encode ( hexdigest , HEX_DIGEST_LEN + 1 , digest , DIGEST_LEN ) ;
2004-09-29 00:24:56 +02:00
SMARTLIST_FOREACH ( fingerprint_list , fingerprint_entry_t * , ent ,
2004-10-13 21:17:27 +02:00
{ if ( ! strcasecmp ( hexdigest , ent - > fingerprint ) )
2004-09-29 00:24:56 +02:00
return ent - > nickname ; } ) ;
return NULL ;
}
2004-10-13 22:17:45 +02:00
#if 0
2004-09-29 00:24:56 +02:00
/** Return true iff any router named <b>nickname</b> with <b>digest</b>
* is in the verified fingerprint list . */
static int
router_nickname_is_approved ( const char * nickname , const char * digest )
{
const char * n ;
n = dirserv_get_nickname_by_digest ( digest ) ;
if ( n & & ! strcasecmp ( n , nickname ) )
return 1 ;
else
return 0 ;
2004-05-05 06:55:00 +02:00
}
2004-10-13 22:17:45 +02:00
# endif
2004-05-05 06:55:00 +02:00
2004-05-09 18:47:25 +02:00
/** Clear the current fingerprint list. */
2003-12-17 22:09:31 +01:00
void
2003-09-27 23:30:10 +02:00
dirserv_free_fingerprint_list ( )
{
int i ;
2004-05-18 19:41:40 +02:00
fingerprint_entry_t * ent ;
if ( ! fingerprint_list )
return ;
for ( i = 0 ; i < smartlist_len ( fingerprint_list ) ; + + i ) {
ent = smartlist_get ( fingerprint_list , i ) ;
tor_free ( ent - > nickname ) ;
tor_free ( ent - > fingerprint ) ;
tor_free ( ent ) ;
2003-09-27 23:30:10 +02:00
}
2004-05-18 19:41:40 +02:00
smartlist_free ( fingerprint_list ) ;
fingerprint_list = NULL ;
2003-09-27 23:30:10 +02:00
}
/*
* Descriptor list
*/
2004-05-05 02:30:43 +02:00
2005-02-25 21:46:13 +01:00
/** List of routerinfo_t for all server descriptors that this dirserv
* is holding .
* XXXX This should eventually get coalesced into routerlist . c
*/
2004-05-18 19:41:40 +02:00
static smartlist_t * descriptor_list = NULL ;
2003-09-27 23:30:10 +02:00
2004-05-09 18:47:25 +02:00
/** Release all storage that the dirserv is holding for server
2004-05-05 02:30:43 +02:00
* descriptors . */
2003-12-14 07:03:46 +01:00
void
2003-09-27 23:30:10 +02:00
dirserv_free_descriptors ( )
{
2004-05-18 19:41:40 +02:00
if ( ! descriptor_list )
return ;
2005-02-25 21:46:13 +01:00
SMARTLIST_FOREACH ( descriptor_list , routerinfo_t * , ri ,
routerinfo_free ( ri ) ) ;
2004-05-18 19:41:40 +02:00
smartlist_clear ( descriptor_list ) ;
2003-09-27 23:30:10 +02:00
}
2005-01-06 22:03:27 +01:00
/** Return -1 if <b>ri</b> has a private or otherwise bad address,
* unless we ' re configured to not care . Return 0 if all ok . */
static int
dirserv_router_has_valid_address ( routerinfo_t * ri )
{
struct in_addr iaddr ;
if ( get_options ( ) - > DirAllowPrivateAddresses )
return 0 ; /* whatever it is, we're fine with it */
if ( ! tor_inet_aton ( ri - > address , & iaddr ) ) {
log_fn ( LOG_INFO , " Router '%s' published non-IP address '%s'. Refusing. " ,
ri - > nickname , ri - > address ) ;
return - 1 ;
}
if ( is_internal_IP ( ntohl ( iaddr . s_addr ) ) ) {
log_fn ( LOG_INFO , " Router '%s' published internal IP address '%s'. Refusing. " ,
ri - > nickname , ri - > address ) ;
return - 1 ; /* it's a private IP, we should reject it */
}
return 0 ;
}
2004-05-09 18:47:25 +02:00
/** Parse the server descriptor at *desc and maybe insert it into the
2004-08-08 13:15:38 +02:00
* list of server descriptors , and ( if the descriptor is well - formed )
2005-01-20 21:18:32 +01:00
* advance * desc immediately past the descriptor ' s end . Set msg to a
* message that should be passed back to the origin of this descriptor , or
* to NULL .
2004-03-12 13:43:13 +01:00
*
2004-05-05 02:30:43 +02:00
* Return 1 if descriptor is well - formed and accepted ;
2005-05-02 23:48:54 +02:00
* 0 if well - formed and server is unapproved but accepted ;
* - 1 if it looks vaguely like a router descriptor but rejected ;
* - 2 if we can ' t find a router descriptor in * desc .
2003-11-12 06:12:51 +01:00
*/
2003-09-27 23:30:10 +02:00
int
2005-01-20 21:18:32 +01:00
dirserv_add_descriptor ( const char * * desc , const char * * msg )
2003-09-27 23:30:10 +02:00
{
2005-02-25 21:46:13 +01:00
routerinfo_t * ri = NULL , * ri_old = NULL ;
2004-05-18 19:41:40 +02:00
int i , r , found = - 1 ;
2003-09-27 23:30:10 +02:00
char * start , * end ;
2003-12-09 00:45:37 +01:00
char * desc_tmp = NULL ;
2003-09-27 23:30:10 +02:00
size_t desc_len ;
2004-03-29 21:28:16 +02:00
time_t now ;
2004-07-21 11:13:12 +02:00
int verified = 1 ; /* whether we knew its fingerprint already */
2005-01-20 21:18:32 +01:00
tor_assert ( msg ) ;
* msg = NULL ;
2004-05-18 19:41:40 +02:00
if ( ! descriptor_list )
descriptor_list = smartlist_create ( ) ;
2003-09-27 23:30:10 +02:00
start = strstr ( * desc , " router " ) ;
if ( ! start ) {
2004-04-05 02:47:48 +02:00
log_fn ( LOG_WARN , " no 'router' line found. This is not a descriptor. " ) ;
2005-01-29 12:23:34 +01:00
return - 2 ;
2003-09-27 23:30:10 +02:00
}
2003-09-30 22:04:40 +02:00
if ( ( end = strstr ( start + 6 , " \n router " ) ) ) {
2003-09-27 23:30:10 +02:00
+ + end ; /* Include NL. */
2003-09-30 22:04:40 +02:00
} else if ( ( end = strstr ( start + 6 , " \n directory-signature " ) ) ) {
+ + end ;
2003-09-27 23:30:10 +02:00
} else {
end = start + strlen ( start ) ;
}
desc_len = end - start ;
2005-02-25 21:46:13 +01:00
desc_tmp = tor_strndup ( start , desc_len ) ; /* Is this strndup still needed???*/
2003-09-27 23:30:10 +02:00
/* Check: is the descriptor syntactically valid? */
2005-02-25 21:46:13 +01:00
ri = router_parse_entry_from_string ( desc_tmp , NULL ) ;
2004-03-12 13:43:13 +01:00
tor_free ( desc_tmp ) ;
2003-09-27 23:30:10 +02:00
if ( ! ri ) {
2003-10-10 03:48:32 +02:00
log ( LOG_WARN , " Couldn't parse descriptor " ) ;
2005-01-20 21:18:32 +01:00
* msg = " Rejected: Couldn't parse server descriptor. " ;
2004-03-12 13:43:13 +01:00
return - 1 ;
2003-09-27 23:30:10 +02:00
}
/* Okay. Now check whether the fingerprint is recognized. */
2003-11-12 06:12:51 +01:00
r = dirserv_router_fingerprint_is_known ( ri ) ;
2004-11-28 10:05:49 +01:00
if ( r = = - 1 ) {
2005-05-03 00:06:04 +02:00
log_fn ( LOG_WARN , " Known nickname '%s', wrong fingerprint. Not adding (ContactInfo '%s', platform '%s'). " ,
ri - > nickname , ri - > contact_info ? ri - > contact_info : " " ,
ri - > platform ? ri - > platform : " " ) ;
2005-01-20 21:18:32 +01:00
* msg = " Rejected: There is already a verified server with this nickname and a different fingerprint. " ;
2003-11-12 06:12:51 +01:00
routerinfo_free ( ri ) ;
* desc = end ;
2005-01-20 21:18:32 +01:00
return - 1 ;
2005-04-06 02:01:35 +02:00
} else if ( r = = 0 ) {
2004-07-21 11:13:12 +02:00
char fp [ FINGERPRINT_LEN + 1 ] ;
2005-01-06 22:03:27 +01:00
log_fn ( LOG_INFO , " Unknown nickname '%s' (%s:%d). Will try to add. " ,
2004-07-21 11:13:12 +02:00
ri - > nickname , ri - > address , ri - > or_port ) ;
2004-10-06 15:31:48 +02:00
if ( crypto_pk_get_fingerprint ( ri - > identity_pkey , fp , 1 ) < 0 ) {
2004-11-25 05:20:10 +01:00
log_fn ( LOG_WARN , " Error computing fingerprint for '%s' " , ri - > nickname ) ;
2004-07-21 11:13:12 +02:00
} else {
2004-07-22 08:04:13 +02:00
log_fn ( LOG_INFO , " Fingerprint line: %s %s " , ri - > nickname , fp ) ;
2004-07-21 11:13:12 +02:00
}
verified = 0 ;
}
2003-10-22 18:41:35 +02:00
/* Is there too much clock skew? */
2004-03-29 21:28:16 +02:00
now = time ( NULL ) ;
if ( ri - > published_on > now + ROUTER_ALLOW_SKEW ) {
2005-05-03 00:06:04 +02:00
log_fn ( LOG_NOTICE , " Publication time for nickname '%s' is too far (%d minutes) in the future; possible clock skew. Not adding (ContactInfo '%s', platform '%s'). " ,
2005-05-02 23:54:16 +02:00
ri - > nickname , ( int ) ( ( ri - > published_on - now ) / 60 ) ,
2005-05-03 00:06:04 +02:00
ri - > contact_info ? ri - > contact_info : " " ,
ri - > platform ? ri - > platform : " " ) ;
2005-01-20 21:18:32 +01:00
* msg = " Rejected: Your clock is set too far in the future, or your timezone is not correct. " ;
2003-11-12 06:12:51 +01:00
routerinfo_free ( ri ) ;
* desc = end ;
2005-01-20 21:18:32 +01:00
return - 1 ;
2003-09-27 23:30:10 +02:00
}
2004-03-29 21:28:16 +02:00
if ( ri - > published_on < now - ROUTER_MAX_AGE ) {
2005-05-03 00:06:04 +02:00
log_fn ( LOG_NOTICE , " Publication time for router with nickname '%s' is too far (%d minutes) in the past. Not adding (ContactInfo '%s', platform '%s'). " ,
2005-05-02 23:54:16 +02:00
ri - > nickname , ( int ) ( ( now - ri - > published_on ) / 60 ) ,
2005-05-03 00:06:04 +02:00
ri - > contact_info ? ri - > contact_info : " " ,
ri - > platform ? ri - > platform : " " ) ;
2005-01-20 21:18:32 +01:00
* msg = " Rejected: Server is expired, or your clock is too far in the past, or your timezone is not correct. " ;
2004-03-29 21:28:16 +02:00
routerinfo_free ( ri ) ;
* desc = end ;
2005-01-20 21:18:32 +01:00
return - 1 ;
2004-03-29 21:28:16 +02:00
}
2005-01-06 22:03:27 +01:00
if ( dirserv_router_has_valid_address ( ri ) < 0 ) {
2005-05-03 00:06:04 +02:00
log_fn ( LOG_NOTICE , " Router with nickname '%s' has invalid address '%s'. Not adding (ContactInfo '%s', platform '%s'). " ,
ri - > nickname , ri - > address ,
ri - > contact_info ? ri - > contact_info : " " ,
ri - > platform ? ri - > platform : " " ) ;
2005-01-20 21:18:32 +01:00
* msg = " Rejected: Address is not an IP, or IP is a private address. " ;
2005-01-06 22:03:27 +01:00
routerinfo_free ( ri ) ;
* desc = end ;
2005-01-20 21:18:32 +01:00
return - 1 ;
2005-01-06 22:03:27 +01:00
}
2004-03-29 21:28:16 +02:00
2003-09-27 23:30:10 +02:00
/* Do we already have an entry for this router? */
2004-05-18 19:41:40 +02:00
for ( i = 0 ; i < smartlist_len ( descriptor_list ) ; + + i ) {
2005-02-25 21:46:13 +01:00
ri_old = smartlist_get ( descriptor_list , i ) ;
2005-04-06 02:01:35 +02:00
if ( ! memcmp ( ri - > identity_digest , ri_old - > identity_digest , DIGEST_LEN ) ) {
2004-05-18 19:41:40 +02:00
found = i ;
2003-09-27 23:30:10 +02:00
break ;
}
}
2004-05-18 19:41:40 +02:00
if ( found > = 0 ) {
2005-04-06 02:01:35 +02:00
char hex_digest [ HEX_DIGEST_LEN + 1 ] ;
base16_encode ( hex_digest , HEX_DIGEST_LEN + 1 , ri - > identity_digest , DIGEST_LEN ) ;
2003-09-27 23:30:10 +02:00
/* if so, decide whether to update it. */
2005-02-25 21:46:13 +01:00
if ( ri_old - > published_on > = ri - > published_on ) {
2004-08-08 13:15:38 +02:00
/* We already have a newer or equal-time descriptor */
2005-04-06 02:53:13 +02:00
log_fn ( LOG_INFO , " We already have a new enough desc for server %s (nickname '%s'). Not adding. " , hex_digest , ri - > nickname ) ;
2005-01-20 21:18:32 +01:00
* msg = " We already have a newer descriptor. " ;
2004-03-12 13:43:13 +01:00
/* This isn't really an error; return success. */
2003-11-12 06:12:51 +01:00
routerinfo_free ( ri ) ;
2003-09-30 21:27:54 +02:00
* desc = end ;
2005-01-03 18:47:32 +01:00
return verified ;
2003-09-27 23:30:10 +02:00
}
2005-02-25 21:46:13 +01:00
/* We don't alrady have a newer one; we'll update this one. */
2005-04-06 02:01:35 +02:00
log_fn ( LOG_INFO , " Dirserv updating desc for server %s (nickname '%s') " , hex_digest , ri - > nickname ) ;
2005-01-22 00:16:07 +01:00
* msg = verified ? " Verified server updated " : " Unverified server updated. (Have you sent us your key fingerprint?) " ;
2005-02-25 21:46:13 +01:00
routerinfo_free ( ri_old ) ;
2004-05-18 19:41:40 +02:00
smartlist_del_keeporder ( descriptor_list , found ) ;
2003-09-27 23:30:10 +02:00
} else {
2004-05-18 19:41:40 +02:00
/* Add at the end. */
2004-11-25 05:20:10 +01:00
log_fn ( LOG_INFO , " Dirserv adding desc for nickname '%s' " , ri - > nickname ) ;
2005-01-22 00:16:07 +01:00
* msg = verified ? " Verified server added " : " Unverified server added. (Have you sent us your key fingerprint?) " ;
2003-09-27 23:30:10 +02:00
}
2003-12-14 06:25:23 +01:00
2005-04-03 21:01:47 +02:00
ri - > is_verified = verified | |
tor_version_as_new_as ( ri - > platform , " 0.1.0.2-rc " ) ;
2005-02-25 21:46:13 +01:00
smartlist_add ( descriptor_list , ri ) ;
2004-05-18 19:41:40 +02:00
2003-09-27 23:30:10 +02:00
* desc = end ;
2003-12-14 06:25:23 +01:00
directory_set_dirty ( ) ;
2005-01-03 18:47:32 +01:00
return verified ;
2003-09-27 23:30:10 +02:00
}
2004-05-09 18:47:25 +02:00
/** Remove all descriptors whose nicknames or fingerprints we don't
2004-05-05 02:30:43 +02:00
* recognize . ( Descriptors that used to be good can become
* unrecognized when we reload the fingerprint list . )
*/
2004-04-13 22:06:08 +02:00
static void
directory_remove_unrecognized ( void )
{
int i ;
2005-04-06 03:09:26 +02:00
int r ;
2005-02-25 21:46:13 +01:00
routerinfo_t * ent ;
2004-05-18 19:41:40 +02:00
if ( ! descriptor_list )
descriptor_list = smartlist_create ( ) ;
for ( i = 0 ; i < smartlist_len ( descriptor_list ) ; + + i ) {
ent = smartlist_get ( descriptor_list , i ) ;
2005-04-06 03:09:26 +02:00
r = dirserv_router_fingerprint_is_known ( ent ) ;
if ( r < 0 ) {
log ( LOG_INFO , " Router '%s' is now verified with a key; removing old router with same name and different key. " ,
2004-05-18 19:41:40 +02:00
ent - > nickname ) ;
2005-02-25 21:46:13 +01:00
routerinfo_free ( ent ) ;
2004-05-18 19:41:40 +02:00
smartlist_del ( descriptor_list , i - - ) ;
2005-04-06 03:09:26 +02:00
} else if ( r > 0 & & ! ent - > is_verified ) {
log ( LOG_INFO , " Router '%s' is now approved. " , ent - > nickname ) ;
ent - > is_verified = 1 ;
} else if ( r = = 0 & & ent - > is_verified ) {
2005-04-06 05:20:06 +02:00
log ( LOG_INFO , " Router '%s' is no longer approved. " , ent - > nickname ) ;
2005-04-06 03:09:26 +02:00
ent - > is_verified = 0 ;
2004-04-13 22:06:08 +02:00
}
}
}
2004-05-10 06:34:48 +02:00
/** Mark the directory as <b>dirty</b> -- when we're next asked for a
2004-05-05 02:30:43 +02:00
* directory , we will rebuild it instead of reusing the most recently
* generated one .
*/
2003-12-17 22:09:31 +01:00
void
2003-09-27 23:30:10 +02:00
directory_set_dirty ( )
{
2004-09-23 21:58:44 +02:00
time_t now = time ( NULL ) ;
2004-11-28 10:05:49 +01:00
if ( ! the_directory_is_dirty )
2004-09-23 21:58:44 +02:00
the_directory_is_dirty = now ;
2004-11-28 10:05:49 +01:00
if ( ! runningrouters_is_dirty )
2004-09-23 21:58:44 +02:00
runningrouters_is_dirty = now ;
2003-09-27 23:30:10 +02:00
}
2004-06-25 02:29:31 +02:00
/** Load all descriptors from a directory stored in the string
2004-05-10 06:34:48 +02:00
* < b > dir < / b > .
2004-05-05 02:30:43 +02:00
*/
2003-12-17 22:09:31 +01:00
int
2004-06-25 02:29:31 +02:00
dirserv_load_from_directory_string ( const char * dir )
2003-09-27 23:30:10 +02:00
{
2005-01-20 21:18:32 +01:00
const char * cp = dir , * m ;
2004-11-28 10:05:49 +01:00
while ( 1 ) {
2003-09-27 23:30:10 +02:00
cp = strstr ( cp , " \n router " ) ;
if ( ! cp ) break ;
+ + cp ;
2005-01-29 12:23:34 +01:00
if ( dirserv_add_descriptor ( & cp , & m ) < - 1 ) {
/* only fail if parsing failed; keep going if simply rejected */
2003-09-27 23:30:10 +02:00
return - 1 ;
}
- - cp ; /*Back up to newline.*/
}
return 0 ;
}
2004-10-27 02:48:51 +02:00
/**
* Allocate and return a description of the status of the server < b > desc < / b > ,
2005-05-02 23:22:31 +02:00
* for use in a router - status line . The server is listed
2004-10-27 02:48:51 +02:00
* as running iff < b > is_live < / b > is true .
2004-05-05 02:30:43 +02:00
*/
2004-10-27 02:48:51 +02:00
static char *
2005-05-02 23:22:31 +02:00
list_single_server_status ( routerinfo_t * desc , int is_live )
2003-10-01 02:43:34 +02:00
{
2004-10-27 02:48:51 +02:00
char buf [ MAX_NICKNAME_LEN + HEX_DIGEST_LEN + 4 ] ; /* !nickname=$hexdigest\0 */
2003-10-01 02:43:34 +02:00
char * cp ;
2004-07-13 20:23:40 +02:00
2004-10-27 02:48:51 +02:00
tor_assert ( desc ) ;
cp = buf ;
if ( ! is_live ) {
* cp + + = ' ! ' ;
}
2005-02-25 21:46:13 +01:00
if ( desc - > is_verified ) {
2004-10-27 08:48:16 +02:00
strlcpy ( cp , desc - > nickname , sizeof ( buf ) - ( cp - buf ) ) ;
2004-10-27 02:48:51 +02:00
cp + = strlen ( cp ) ;
2005-05-02 23:22:31 +02:00
* cp + + = ' = ' ;
2004-10-27 02:48:51 +02:00
}
2005-05-02 23:22:31 +02:00
* cp + + = ' $ ' ;
base16_encode ( cp , HEX_DIGEST_LEN + 1 , desc - > identity_digest ,
DIGEST_LEN ) ;
2004-10-27 02:48:51 +02:00
return tor_strdup ( buf ) ;
}
2005-03-23 20:15:10 +01:00
/** Based on the routerinfo_ts in <b>routers</b>, allocate the
2005-05-02 23:22:31 +02:00
* contents of a router - status line , and store it in
* * < b > router_status_out < / b > . Return 0 on success , - 1 on failure .
2004-10-27 02:48:51 +02:00
*/
2005-03-22 04:27:51 +01:00
int
2005-05-02 23:22:31 +02:00
list_server_status ( smartlist_t * routers , char * * router_status_out )
2004-10-27 02:48:51 +02:00
{
/* List of entries in a router-status style: An optional !, then an optional
* equals - suffixed nickname , then a dollar - prefixed hexdigest . */
smartlist_t * rs_entries ;
2005-03-23 20:15:10 +01:00
/* XXXX Really, we should merge descriptor_list into routerlist. But
* this is potentially tricky , since the semantics of the two lists
* are not quite the same . In any case , it ' s not for the 0.1 .0 . x
* series .
*/
int authdir_mode = get_options ( ) - > AuthoritativeDir ;
2005-05-02 23:22:31 +02:00
tor_assert ( router_status_out ) ;
2004-10-27 02:48:51 +02:00
rs_entries = smartlist_create ( ) ;
2005-03-23 20:15:10 +01:00
SMARTLIST_FOREACH ( routers , routerinfo_t * , ri ,
2004-10-27 02:48:51 +02:00
{
int is_live ;
2004-11-09 18:12:56 +01:00
connection_t * conn ;
2004-10-27 20:14:38 +02:00
conn = connection_get_by_identity_digest (
2005-02-25 21:46:13 +01:00
ri - > identity_digest , CONN_TYPE_OR ) ;
2005-03-23 20:15:10 +01:00
if ( authdir_mode ) {
/* Treat a router as alive if
* - It ' s me , and I ' m not hibernating .
* or - we ' re connected to it . */
is_live = ( router_is_me ( ri ) & & ! we_are_hibernating ( ) ) | |
( conn & & conn - > state = = OR_CONN_STATE_OPEN ) ;
} else {
is_live = ri - > is_running ;
}
2005-05-02 23:22:31 +02:00
smartlist_add ( rs_entries , list_single_server_status ( ri , is_live ) ) ;
2004-10-27 02:48:51 +02:00
} ) ;
2005-05-02 23:22:31 +02:00
* router_status_out = smartlist_join_strings ( rs_entries , " " , 0 , NULL ) ;
2004-10-27 02:48:51 +02:00
SMARTLIST_FOREACH ( rs_entries , char * , cp , tor_free ( cp ) ) ;
smartlist_free ( rs_entries ) ;
2003-10-01 02:43:34 +02:00
return 0 ;
}
2004-08-07 00:15:25 +02:00
/** Remove any descriptors from the directory that are more than <b>age</b>
2004-03-29 21:28:16 +02:00
* seconds old .
*/
void
2004-08-07 00:15:25 +02:00
dirserv_remove_old_servers ( int age )
2004-03-29 21:28:16 +02:00
{
int i ;
time_t cutoff ;
2005-02-25 21:46:13 +01:00
routerinfo_t * ent ;
2004-05-18 19:41:40 +02:00
if ( ! descriptor_list )
descriptor_list = smartlist_create ( ) ;
2004-08-07 00:15:25 +02:00
cutoff = time ( NULL ) - age ;
2004-05-18 19:41:40 +02:00
for ( i = 0 ; i < smartlist_len ( descriptor_list ) ; + + i ) {
ent = smartlist_get ( descriptor_list , i ) ;
2005-02-25 21:46:13 +01:00
if ( ent - > published_on < = cutoff ) {
2004-03-29 21:28:16 +02:00
/* descriptor_list[i] is too old. Remove it. */
2005-02-25 21:46:13 +01:00
routerinfo_free ( ent ) ;
2004-05-18 19:41:40 +02:00
smartlist_del ( descriptor_list , i - - ) ;
2004-03-29 21:28:16 +02:00
directory_set_dirty ( ) ;
}
}
}
2004-12-24 03:17:32 +01:00
/** Generate a new directory and write it into a newly allocated string.
* Point * < b > dir_out < / b > to the allocated string . Sign the
2004-05-10 06:34:48 +02:00
* directory with < b > private_key < / b > . Return 0 on success , - 1 on
* failure .
2004-03-29 21:28:16 +02:00
*/
2003-09-27 23:30:10 +02:00
int
2004-12-24 03:17:32 +01:00
dirserv_dump_directory_to_string ( char * * dir_out ,
2003-09-27 23:30:10 +02:00
crypto_pk_env_t * private_key )
{
2004-12-24 03:17:32 +01:00
char * cp ;
2005-05-02 23:22:31 +02:00
char * router_status ;
2004-10-07 23:10:40 +02:00
char * identity_pkey ; /* Identity key, DER64-encoded. */
2004-10-15 07:09:48 +02:00
char * recommended_versions ;
2003-09-27 23:30:10 +02:00
char digest [ 20 ] ;
char signature [ 128 ] ;
char published [ 33 ] ;
time_t published_on ;
2004-12-24 03:17:32 +01:00
char * buf = NULL ;
size_t buf_len ;
2004-10-07 05:11:42 +02:00
int i ;
2005-05-02 23:22:31 +02:00
size_t identity_pkey_len ;
2004-12-24 03:17:32 +01:00
tor_assert ( dir_out ) ;
* dir_out = NULL ;
2003-09-27 23:30:10 +02:00
2004-05-18 19:41:40 +02:00
if ( ! descriptor_list )
descriptor_list = smartlist_create ( ) ;
2005-05-02 23:22:31 +02:00
if ( list_server_status ( descriptor_list , & router_status ) )
2003-09-27 23:30:10 +02:00
return - 1 ;
2004-10-07 05:11:42 +02:00
2005-05-02 23:22:31 +02:00
if ( crypto_pk_write_public_key_to_string ( private_key , & identity_pkey ,
& identity_pkey_len ) < 0 ) {
2004-10-06 15:31:48 +02:00
log_fn ( LOG_WARN , " write identity_pkey to string failed! " ) ;
return - 1 ;
}
2004-10-15 07:09:48 +02:00
{
smartlist_t * versions ;
struct config_line_t * ln ;
versions = smartlist_create ( ) ;
2004-11-06 06:18:11 +01:00
for ( ln = get_options ( ) - > RecommendedVersions ; ln ; ln = ln - > next ) {
2004-11-09 21:04:00 +01:00
smartlist_split_string ( versions , ln - > value , " , " ,
2004-10-15 07:09:48 +02:00
SPLIT_SKIP_SPACE | SPLIT_IGNORE_BLANK , 0 ) ;
}
2004-11-03 19:33:07 +01:00
recommended_versions = smartlist_join_strings ( versions , " , " , 0 , NULL ) ;
2004-10-15 07:09:48 +02:00
SMARTLIST_FOREACH ( versions , char * , s , tor_free ( s ) ) ;
smartlist_free ( versions ) ;
}
2004-11-09 21:04:00 +01:00
2004-08-07 00:15:25 +02:00
dirserv_remove_old_servers ( ROUTER_MAX_AGE ) ;
2003-09-27 23:30:10 +02:00
published_on = time ( NULL ) ;
2004-08-07 04:46:16 +02:00
format_iso_time ( published , published_on ) ;
2004-12-24 03:17:32 +01:00
2005-05-02 23:22:31 +02:00
buf_len = 2048 + strlen ( recommended_versions ) +
2004-12-24 03:17:32 +01:00
strlen ( router_status ) ;
2005-02-25 21:46:13 +01:00
SMARTLIST_FOREACH ( descriptor_list , routerinfo_t * , ri ,
buf_len + = strlen ( ri - > signed_descriptor ) ) ;
2004-12-24 03:17:32 +01:00
buf = tor_malloc ( buf_len ) ;
/* We'll be comparing against buf_len throughout the rest of the
function , though strictly speaking we shouldn ' t be able to exceed
it . This is C , after all , so we may as well check for buffer
overruns . */
tor_snprintf ( buf , buf_len ,
2003-09-27 23:30:10 +02:00
" signed-directory \n "
" published %s \n "
2003-11-13 07:49:25 +01:00
" recommended-software %s \n "
2005-05-02 23:22:31 +02:00
" router-status %s \n "
" dir-signing-key \n %s \n " ,
published , recommended_versions , router_status ,
2004-10-27 02:48:51 +02:00
identity_pkey ) ;
2004-06-25 02:29:31 +02:00
2005-02-01 00:47:25 +01:00
tor_free ( recommended_versions ) ;
2004-10-27 02:48:51 +02:00
tor_free ( router_status ) ;
2004-10-06 15:31:48 +02:00
tor_free ( identity_pkey ) ;
2004-12-24 03:17:32 +01:00
i = strlen ( buf ) ;
cp = buf + i ;
2003-12-14 06:25:23 +01:00
2005-02-25 21:46:13 +01:00
SMARTLIST_FOREACH ( descriptor_list , routerinfo_t * , ri ,
if ( strlcat ( buf , ri - > signed_descriptor , buf_len ) > = buf_len )
2004-05-18 19:41:40 +02:00
goto truncated ) ;
2004-03-29 21:28:16 +02:00
/* These multiple strlcat calls are inefficient, but dwarfed by the RSA
2003-09-27 23:30:10 +02:00
signature .
*/
2004-12-24 03:17:32 +01:00
if ( strlcat ( buf , " directory-signature " , buf_len ) > = buf_len )
2004-03-29 21:28:16 +02:00
goto truncated ;
2004-12-24 03:17:32 +01:00
if ( strlcat ( buf , get_options ( ) - > Nickname , buf_len ) > = buf_len )
2004-04-25 00:17:50 +02:00
goto truncated ;
2004-12-24 03:17:32 +01:00
if ( strlcat ( buf , " \n " , buf_len ) > = buf_len )
2004-04-25 00:17:50 +02:00
goto truncated ;
2004-12-24 03:17:32 +01:00
if ( router_get_dir_hash ( buf , digest ) ) {
2003-10-10 03:48:32 +02:00
log_fn ( LOG_WARN , " couldn't compute digest " ) ;
2004-12-24 03:17:32 +01:00
tor_free ( buf ) ;
2003-09-27 23:30:10 +02:00
return - 1 ;
}
2004-11-02 03:28:51 +01:00
if ( crypto_pk_private_sign ( private_key , signature , digest , 20 ) < 0 ) {
2003-10-10 03:48:32 +02:00
log_fn ( LOG_WARN , " couldn't sign digest " ) ;
2004-12-24 03:17:32 +01:00
tor_free ( buf ) ;
2003-09-27 23:30:10 +02:00
return - 1 ;
}
2004-04-06 22:16:12 +02:00
log ( LOG_DEBUG , " generated directory digest begins with %s " , hex_str ( digest , 4 ) ) ;
2003-12-14 06:25:23 +01:00
2004-12-24 03:17:32 +01:00
if ( strlcat ( cp , " -----BEGIN SIGNATURE----- \n " , buf_len ) > = buf_len )
2004-03-29 21:28:16 +02:00
goto truncated ;
2003-12-14 06:25:23 +01:00
2004-12-24 03:17:32 +01:00
i = strlen ( buf ) ;
cp = buf + i ;
if ( base64_encode ( cp , buf_len - i , signature , 128 ) < 0 ) {
2003-10-10 03:48:32 +02:00
log_fn ( LOG_WARN , " couldn't base64-encode signature " ) ;
2004-12-24 03:17:32 +01:00
tor_free ( buf ) ;
2003-09-27 23:30:10 +02:00
return - 1 ;
}
2004-07-23 01:21:12 +02:00
2004-12-24 03:17:32 +01:00
if ( strlcat ( buf , " -----END SIGNATURE----- \n " , buf_len ) > = buf_len )
2004-03-29 21:28:16 +02:00
goto truncated ;
2003-09-27 23:30:10 +02:00
2004-12-24 03:17:32 +01:00
* dir_out = buf ;
2003-09-27 23:30:10 +02:00
return 0 ;
2004-03-29 21:28:16 +02:00
truncated :
log_fn ( LOG_WARN , " tried to exceed string length. " ) ;
2004-12-24 03:17:32 +01:00
tor_free ( buf ) ;
2004-03-29 21:28:16 +02:00
return - 1 ;
2003-09-27 23:30:10 +02:00
}
2004-05-10 06:34:48 +02:00
/** Most recently generated encoded signed directory. */
2003-12-14 06:25:23 +01:00
static char * the_directory = NULL ;
2004-10-01 23:02:12 +02:00
static size_t the_directory_len = 0 ;
2004-09-02 20:57:09 +02:00
static char * the_directory_z = NULL ;
2004-10-01 23:02:12 +02:00
static size_t the_directory_z_len = 0 ;
2004-09-02 20:57:09 +02:00
2004-11-15 05:04:20 +01:00
typedef struct cached_dir_t {
char * dir ;
char * dir_z ;
size_t dir_len ;
size_t dir_z_len ;
time_t published ;
} cached_dir_t ;
/* used only by non-auth dirservers */
static cached_dir_t cached_directory = { NULL , NULL , 0 , 0 , 0 } ;
static cached_dir_t cached_runningrouters = { NULL , NULL , 0 , 0 , 0 } ;
2004-06-21 06:37:27 +02:00
2004-11-09 19:22:17 +01:00
/** If we have no cached directory, or it is older than <b>when</b>, then
* replace it with < b > directory < / b > , published at < b > when < / b > .
*/
2004-11-15 05:04:20 +01:00
void dirserv_set_cached_directory ( const char * directory , time_t when ,
int is_running_routers )
2004-06-21 06:37:27 +02:00
{
time_t now ;
2004-11-15 05:04:20 +01:00
cached_dir_t * d ;
2004-06-21 06:37:27 +02:00
now = time ( NULL ) ;
2004-11-15 05:04:20 +01:00
d = is_running_routers ? & cached_runningrouters : & cached_directory ;
if ( when < = d - > published ) {
2004-09-08 08:52:33 +02:00
log_fn ( LOG_INFO , " Ignoring old directory; not caching. " ) ;
2005-03-23 07:39:53 +01:00
} else if ( when > = now + ROUTER_MAX_AGE ) {
2004-09-08 08:52:33 +02:00
log_fn ( LOG_INFO , " Ignoring future directory; not caching. " ) ;
2005-03-23 07:39:53 +01:00
} else {
/* if (when>d->published && when<now+ROUTER_MAX_AGE) */
2004-09-08 08:52:33 +02:00
log_fn ( LOG_DEBUG , " Caching directory. " ) ;
2004-11-15 05:04:20 +01:00
tor_free ( d - > dir ) ;
d - > dir = tor_strdup ( directory ) ;
d - > dir_len = strlen ( directory ) ;
tor_free ( d - > dir_z ) ;
if ( tor_gzip_compress ( & ( d - > dir_z ) , & ( d - > dir_z_len ) , d - > dir , d - > dir_len ,
2004-09-02 20:57:09 +02:00
ZLIB_METHOD ) ) {
log_fn ( LOG_WARN , " Error compressing cached directory " ) ;
}
2004-11-15 05:04:20 +01:00
d - > published = when ;
if ( ! is_running_routers ) {
char filename [ 512 ] ;
tor_snprintf ( filename , sizeof ( filename ) , " %s/cached-directory " , get_options ( ) - > DataDirectory ) ;
2004-11-28 10:05:49 +01:00
if ( write_str_to_file ( filename , cached_directory . dir , 0 ) < 0 ) {
2004-12-13 01:44:39 +01:00
log_fn ( LOG_NOTICE , " Couldn't write cached directory to disk. Ignoring. " ) ;
2004-11-15 05:04:20 +01:00
}
2004-09-08 08:52:33 +02:00
}
2004-06-21 06:37:27 +02:00
}
}
2003-12-14 06:25:23 +01:00
2004-05-10 06:34:48 +02:00
/** Set *<b>directory</b> to the most recently generated encoded signed
2004-11-15 05:04:20 +01:00
* directory , generating a new one as necessary . If not an authoritative
* directory may return 0 if no directory is yet cached . */
2004-09-27 08:57:16 +02:00
size_t dirserv_get_directory ( const char * * directory , int compress )
2003-09-27 23:30:10 +02:00
{
2004-11-06 06:18:11 +01:00
if ( ! get_options ( ) - > AuthoritativeDir ) {
2004-11-15 05:04:20 +01:00
cached_dir_t * d = & cached_directory ;
* directory = compress ? d - > dir_z : d - > dir ;
if ( * directory ) {
return compress ? d - > dir_z_len : d - > dir_len ;
2004-06-21 06:37:27 +02:00
} else {
/* no directory yet retrieved */
return 0 ;
}
}
2004-09-23 21:58:44 +02:00
if ( the_directory_is_dirty & &
the_directory_is_dirty + DIR_REGEN_SLACK_TIME < time ( NULL ) ) {
2004-09-02 20:57:09 +02:00
if ( dirserv_regenerate_directory ( ) )
2003-09-27 23:30:10 +02:00
return 0 ;
} else {
log ( LOG_INFO , " Directory still clean, reusing. " ) ;
}
2004-09-27 08:57:16 +02:00
* directory = compress ? the_directory_z : the_directory ;
return compress ? the_directory_z_len : the_directory_len ;
2004-09-02 20:57:09 +02:00
}
/**
* Generate a fresh directory ( authdirservers only . )
*/
static int dirserv_regenerate_directory ( void )
{
2004-12-24 03:17:32 +01:00
char * new_directory = NULL ;
2004-09-02 20:57:09 +02:00
2004-12-24 03:17:32 +01:00
if ( dirserv_dump_directory_to_string ( & new_directory ,
2004-09-02 20:57:09 +02:00
get_identity_key ( ) ) ) {
log ( LOG_WARN , " Error creating directory. " ) ;
tor_free ( new_directory ) ;
return - 1 ;
}
tor_free ( the_directory ) ;
the_directory = new_directory ;
the_directory_len = strlen ( the_directory ) ;
2004-10-01 23:02:12 +02:00
log_fn ( LOG_INFO , " New directory (size %d): \n %s " , ( int ) the_directory_len ,
2004-09-02 20:57:09 +02:00
the_directory ) ;
tor_free ( the_directory_z ) ;
2004-10-01 23:02:12 +02:00
if ( tor_gzip_compress ( & the_directory_z , & the_directory_z_len ,
2004-09-02 20:57:09 +02:00
the_directory , the_directory_len ,
ZLIB_METHOD ) ) {
log_fn ( LOG_WARN , " Error gzipping directory. " ) ;
return - 1 ;
}
2005-04-27 02:48:05 +02:00
#if 0
2004-09-02 20:57:09 +02:00
/* Now read the directory we just made in order to update our own
* router lists . This does more signature checking than is strictly
* necessary , but safe is better than sorry . */
new_directory = tor_strdup ( the_directory ) ;
/* use a new copy of the dir, since get_dir_from_string scribbles on it */
2005-01-06 21:11:52 +01:00
if ( router_load_routerlist_from_directory ( new_directory ,
get_identity_key ( ) , 1 , 0 ) ) {
2004-09-02 20:57:09 +02:00
log_fn ( LOG_ERR , " We just generated a directory we can't parse. Dying. " ) ;
tor_cleanup ( ) ;
exit ( 0 ) ;
}
2004-09-29 08:52:36 +02:00
tor_free ( new_directory ) ;
2005-04-27 02:48:05 +02:00
# endif
2004-09-02 20:57:09 +02:00
the_directory_is_dirty = 0 ;
2004-11-15 17:17:59 +01:00
/* Save the directory to disk so we re-load it quickly on startup.
*/
dirserv_set_cached_directory ( the_directory , time ( NULL ) , 0 ) ;
2004-09-02 20:57:09 +02:00
return 0 ;
2003-09-27 23:30:10 +02:00
}
2003-10-18 05:23:26 +02:00
2004-11-15 05:04:20 +01:00
static char * the_runningrouters = NULL ;
static size_t the_runningrouters_len = 0 ;
static char * the_runningrouters_z = NULL ;
static size_t the_runningrouters_z_len = 0 ;
2004-06-25 02:29:31 +02:00
/** Replace the current running-routers list with a newly generated one. */
static int generate_runningrouters ( crypto_pk_env_t * private_key )
{
2004-10-27 14:34:02 +02:00
char * s = NULL , * cp ;
char * router_status = NULL ;
2004-06-25 02:29:31 +02:00
char digest [ DIGEST_LEN ] ;
char signature [ PK_BYTES ] ;
2004-08-04 01:57:05 +02:00
int i ;
2004-06-25 02:29:31 +02:00
char published [ 33 ] ;
2004-08-04 01:57:05 +02:00
size_t len ;
2004-06-25 02:29:31 +02:00
time_t published_on ;
2004-10-07 23:10:40 +02:00
char * identity_pkey ; /* Identity key, DER64-encoded. */
2005-05-02 23:22:31 +02:00
size_t identity_pkey_len ;
2004-06-25 02:29:31 +02:00
2005-03-23 20:15:10 +01:00
if ( ! descriptor_list )
descriptor_list = smartlist_create ( ) ;
2005-05-02 23:22:31 +02:00
if ( list_server_status ( descriptor_list , & router_status ) ) {
2004-10-27 14:34:02 +02:00
goto err ;
}
2005-05-02 23:22:31 +02:00
if ( crypto_pk_write_public_key_to_string ( private_key , & identity_pkey ,
& identity_pkey_len ) < 0 ) {
2004-10-07 23:10:40 +02:00
log_fn ( LOG_WARN , " write identity_pkey to string failed! " ) ;
2004-10-27 14:34:02 +02:00
goto err ;
2004-10-07 23:10:40 +02:00
}
2004-06-25 02:29:31 +02:00
published_on = time ( NULL ) ;
2004-08-07 04:46:16 +02:00
format_iso_time ( published , published_on ) ;
2004-12-24 02:41:52 +01:00
len = 2048 + strlen ( router_status ) ;
s = tor_malloc_zero ( len ) ;
2004-10-27 08:37:34 +02:00
tor_snprintf ( s , len , " network-status \n "
2004-06-25 02:29:31 +02:00
" published %s \n "
2004-10-27 02:48:51 +02:00
" router-status %s \n "
2005-05-02 23:22:31 +02:00
" dir-signing-key \n %s "
2004-06-25 02:29:31 +02:00
" directory-signature %s \n "
" -----BEGIN SIGNATURE----- \n " ,
2004-11-06 06:18:11 +01:00
published , router_status , identity_pkey , get_options ( ) - > Nickname ) ;
2004-10-27 02:48:51 +02:00
tor_free ( router_status ) ;
2004-10-07 23:10:40 +02:00
tor_free ( identity_pkey ) ;
2004-06-25 02:29:31 +02:00
if ( router_get_runningrouters_hash ( s , digest ) ) {
log_fn ( LOG_WARN , " couldn't compute digest " ) ;
2004-10-27 14:34:02 +02:00
goto err ;
2004-06-25 02:29:31 +02:00
}
2004-11-02 03:28:51 +01:00
if ( crypto_pk_private_sign ( private_key , signature , digest , 20 ) < 0 ) {
2004-06-25 02:29:31 +02:00
log_fn ( LOG_WARN , " couldn't sign digest " ) ;
2004-10-27 14:34:02 +02:00
goto err ;
2004-06-25 02:29:31 +02:00
}
i = strlen ( s ) ;
cp = s + i ;
if ( base64_encode ( cp , len - i , signature , 128 ) < 0 ) {
log_fn ( LOG_WARN , " couldn't base64-encode signature " ) ;
2004-10-27 14:34:02 +02:00
goto err ;
2004-06-25 02:29:31 +02:00
}
if ( strlcat ( s , " -----END SIGNATURE----- \n " , len ) > = len ) {
2004-10-27 14:34:02 +02:00
goto err ;
2004-06-25 02:29:31 +02:00
}
2004-11-15 05:04:20 +01:00
tor_free ( the_runningrouters ) ;
the_runningrouters = s ;
the_runningrouters_len = strlen ( s ) ;
tor_free ( the_runningrouters_z ) ;
if ( tor_gzip_compress ( & the_runningrouters_z , & the_runningrouters_z_len ,
the_runningrouters , the_runningrouters_len ,
ZLIB_METHOD ) ) {
log_fn ( LOG_WARN , " Error gzipping runningrouters " ) ;
return - 1 ;
}
2004-06-25 02:29:31 +02:00
runningrouters_is_dirty = 0 ;
2004-11-15 17:17:59 +01:00
2004-12-01 04:48:14 +01:00
/* We don't cache running-routers to disk, so there's no point in
2004-11-15 17:17:59 +01:00
* authdirservers caching it . */
/* dirserv_set_cached_directory(the_runningrouters, time(NULL), 1); */
2004-06-25 02:29:31 +02:00
return 0 ;
2004-10-27 14:34:02 +02:00
err :
tor_free ( s ) ;
tor_free ( router_status ) ;
return - 1 ;
2004-06-25 02:29:31 +02:00
}
2004-06-16 23:08:29 +02:00
/** Set *<b>rr</b> to the most recently generated encoded signed
2004-08-06 22:00:16 +02:00
* running - routers list , generating a new one as necessary . Return the
* size of the directory on success , and 0 on failure . */
2004-11-15 05:04:20 +01:00
size_t dirserv_get_runningrouters ( const char * * rr , int compress )
2004-06-16 23:08:29 +02:00
{
2004-11-15 05:04:20 +01:00
if ( ! get_options ( ) - > AuthoritativeDir ) {
cached_dir_t * d = & cached_runningrouters ;
* rr = compress ? d - > dir_z : d - > dir ;
if ( * rr ) {
return compress ? d - > dir_z_len : d - > dir_len ;
} else {
/* no directory yet retrieved */
return 0 ;
}
}
2004-09-23 21:58:44 +02:00
if ( runningrouters_is_dirty & &
runningrouters_is_dirty + DIR_REGEN_SLACK_TIME < time ( NULL ) ) {
2004-11-28 10:05:49 +01:00
if ( generate_runningrouters ( get_identity_key ( ) ) ) {
2004-06-25 02:29:31 +02:00
log_fn ( LOG_ERR , " Couldn't generate running-routers list? " ) ;
2004-08-06 22:00:16 +02:00
return 0 ;
2004-06-25 02:29:31 +02:00
}
}
2004-11-15 05:04:20 +01:00
* rr = compress ? the_runningrouters_z : the_runningrouters ;
return compress ? the_runningrouters_z_len : the_runningrouters_len ;
2004-06-16 23:08:29 +02:00
}
2005-04-06 23:09:47 +02:00
/** Called when a TLS handshake has completed successfully with a
* router listening at < b > address < / b > : < b > or_port < / b > , and has yielded
* a certificate with digest < b > digest_rcvd < / b > and nickname
* < b > nickname_rcvd < / b > . When this happens , it ' s clear that any other
* descriptors for that address / port combination must be unusable :
* delete them if they are not verified .
*/
void
dirserv_orconn_tls_done ( const char * address ,
uint16_t or_port ,
const char * digest_rcvd ,
const char * nickname_rcvd )
{
int i ;
tor_assert ( address ) ;
tor_assert ( digest_rcvd ) ;
tor_assert ( nickname_rcvd ) ;
if ( ! descriptor_list )
return ;
for ( i = 0 ; i < smartlist_len ( descriptor_list ) ; + + i ) {
routerinfo_t * ri = smartlist_get ( descriptor_list , i ) ;
int drop = 0 ;
if ( ri - > is_verified )
continue ;
if ( ! strcasecmp ( address , ri - > address ) & &
or_port = = ri - > or_port ) {
/* We have a router at the same address! */
if ( strcasecmp ( ri - > nickname , nickname_rcvd ) ) {
2005-04-13 00:09:04 +02:00
log_fn ( LOG_NOTICE , " Dropping descriptor: nickname '%s' does not match nickname '%s' in cert from %s:%d " ,
2005-04-06 23:09:47 +02:00
ri - > nickname , nickname_rcvd , address , or_port ) ;
drop = 1 ;
} else if ( memcmp ( ri - > identity_digest , digest_rcvd , DIGEST_LEN ) ) {
2005-04-13 00:09:04 +02:00
log_fn ( LOG_NOTICE , " Dropping descriptor: identity key does not match key in cert from %s:%d " ,
2005-04-06 23:09:47 +02:00
address , or_port ) ;
drop = 1 ;
}
if ( drop ) {
routerinfo_free ( ri ) ;
smartlist_del ( descriptor_list , i - - ) ;
directory_set_dirty ( ) ;
}
}
}
}
2005-02-11 00:18:39 +01:00
void
dirserv_free_all ( void )
{
if ( fingerprint_list ) {
SMARTLIST_FOREACH ( fingerprint_list , fingerprint_entry_t * , fp ,
{ tor_free ( fp - > nickname ) ;
tor_free ( fp - > fingerprint ) ;
tor_free ( fp ) ; } ) ;
smartlist_free ( fingerprint_list ) ;
fingerprint_list = NULL ;
}
if ( descriptor_list ) {
2005-02-25 21:46:13 +01:00
SMARTLIST_FOREACH ( descriptor_list , routerinfo_t * , ri ,
routerinfo_free ( ri ) ) ;
2005-02-11 00:18:39 +01:00
smartlist_free ( descriptor_list ) ;
descriptor_list = NULL ;
}
tor_free ( the_directory ) ;
tor_free ( the_directory_z ) ;
the_directory_len = 0 ;
the_directory_z_len = 0 ;
2005-03-23 07:20:50 +01:00
tor_free ( the_runningrouters ) ;
tor_free ( the_runningrouters_z ) ;
the_runningrouters_len = 0 ;
the_runningrouters_z_len = 0 ;
2005-02-11 00:18:39 +01:00
tor_free ( cached_directory . dir ) ;
tor_free ( cached_directory . dir_z ) ;
tor_free ( cached_runningrouters . dir ) ;
tor_free ( cached_runningrouters . dir_z ) ;
memset ( & cached_directory , 0 , sizeof ( cached_directory ) ) ;
memset ( & cached_runningrouters , 0 , sizeof ( cached_runningrouters ) ) ;
}