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
2005-06-11 07:31:17 +02:00
* \ brief Directory server core implementation . Manages directory
* contents and generates directories .
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-09-08 22:47:11 +02:00
# define DIR_REGEN_SLACK_TIME 30
2003-10-22 18:41:35 +02:00
2005-08-24 04:31:02 +02:00
extern long stats_n_seconds_working ;
2005-09-15 02:51:42 +02:00
typedef enum {
FP_NAMED , /**< Listed in fingerprint file. */
FP_VALID , /**< Unlisted but believed valid. */
FP_INVALID , /**< Believed invalid. */
FP_REJECT , /**< We will not publish this router. */
} router_status_t ;
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 ;
2005-08-27 00:16:09 +02:00
static int the_v2_networkstatus_is_dirty = 1 ;
2003-09-27 23:30:10 +02:00
2005-06-21 03:00:42 +02:00
static void directory_remove_invalid ( void ) ;
2004-09-02 20:57:09 +02:00
static int dirserv_regenerate_directory ( void ) ;
2005-08-25 22:33:17 +02:00
static char * format_versions_list ( config_line_t * ln ) ;
2004-11-02 04:02:17 +01:00
/* Should be static; exposed for testing */
2005-06-21 03:00:42 +02:00
int add_fingerprint_to_dir ( const char * nickname , const char * fp , smartlist_t * list ) ;
2005-08-25 22:33:17 +02:00
static int router_is_general_exit ( routerinfo_t * ri ) ;
2005-09-15 02:51:42 +02:00
static router_status_t dirserv_router_get_status ( const routerinfo_t * router ,
const char * * msg ) ;
2005-09-15 07:19:38 +02:00
static int dirserv_thinks_router_is_reachable ( routerinfo_t * router ,
time_t now ) ;
2003-10-01 02:43:34 +02:00
2003-09-29 09:50:08 +02:00
/************** Fingerprint handling code ************/
2005-09-15 16:39:05 +02:00
static addr_policy_t * authdir_reject_policy = NULL ;
static addr_policy_t * authdir_invalid_policy = NULL ;
/** Parse authdir policy strings from the configuration.
*/
void
parse_authdir_policy ( void ) {
addr_policy_t * n ;
if ( authdir_reject_policy ) {
addr_policy_free ( authdir_reject_policy ) ;
authdir_reject_policy = NULL ;
}
config_parse_addr_policy ( get_options ( ) - > AuthDirReject ,
& authdir_reject_policy , ADDR_POLICY_ACCEPT ) ;
/* ports aren't used. */
for ( n = authdir_reject_policy ; n ; n = n - > next ) {
n - > prt_min = 1 ;
n - > prt_max = 65535 ;
}
if ( authdir_invalid_policy ) {
addr_policy_free ( authdir_invalid_policy ) ;
authdir_invalid_policy = NULL ;
}
config_parse_addr_policy ( get_options ( ) - > AuthDirInvalid ,
& authdir_invalid_policy , ADDR_POLICY_ACCEPT ) ;
/* ports aren't used. */
for ( n = authdir_invalid_policy ; n ; n = n - > next ) {
n - > prt_min = 1 ;
n - > prt_max = 65535 ;
}
}
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 . */
2005-06-28 00:25:09 +02:00
/* Should be static; exposed for testing */
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
2005-06-21 03:00:42 +02:00
* the smartlist of fingerprint_entry_t ' s < b > list < / b > . Return 0 if it ' s
* new , or 1 if we replaced the old value .
2004-05-05 02:30:43 +02:00
*/
2005-06-21 03:00:42 +02:00
int /* Should be static; exposed for testing */
add_fingerprint_to_dir ( const char * nickname , const char * fp , smartlist_t * list )
2003-09-30 21:27:54 +02:00
{
int i ;
2004-05-18 19:41:40 +02:00
fingerprint_entry_t * ent ;
2005-08-24 00:00:35 +02:00
char * fingerprint ;
2005-06-21 03:00:42 +02:00
tor_assert ( nickname ) ;
tor_assert ( fp ) ;
tor_assert ( list ) ;
2004-05-18 19:41:40 +02:00
2005-08-24 00:00:35 +02:00
fingerprint = tor_strdup ( fp ) ;
tor_strstrip ( fingerprint , " " ) ;
2005-06-21 03:00:42 +02:00
for ( i = 0 ; i < smartlist_len ( list ) ; + + i ) {
ent = smartlist_get ( list , i ) ;
2004-05-18 19:41:40 +02:00
if ( ! strcasecmp ( ent - > nickname , nickname ) ) {
tor_free ( ent - > fingerprint ) ;
2005-08-24 00:00:35 +02:00
ent - > fingerprint = fingerprint ;
2005-06-21 03:00:42 +02:00
return 1 ;
2003-09-30 21:27:54 +02:00
}
}
2004-05-18 19:41:40 +02:00
ent = tor_malloc ( sizeof ( fingerprint_entry_t ) ) ;
ent - > nickname = tor_strdup ( nickname ) ;
2005-08-24 00:00:35 +02:00
ent - > fingerprint = fingerprint ;
2005-06-21 03:00:42 +02:00
smartlist_add ( list , ent ) ;
return 0 ;
2003-09-30 21:27:54 +02:00
}
2005-06-21 03:00:42 +02:00
/** Add the nickname and fingerprint for this OR to the
* global list of recognized identity key fingerprints . */
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 ;
}
2005-06-21 03:00:42 +02:00
if ( ! fingerprint_list )
fingerprint_list = smartlist_create ( ) ;
add_fingerprint_to_dir ( nickname , fp , fingerprint_list ) ;
2003-09-30 21:27:54 +02:00
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 ;
2005-06-21 03:00:42 +02:00
int result ;
2005-07-22 23:12:10 +02:00
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
}
2005-09-15 16:39:05 +02:00
if ( ! is_legal_nickname ( nickname ) & &
2005-09-15 23:10:58 +02:00
strcasecmp ( nickname , " !reject " ) & &
strcasecmp ( nickname , " !invalid " ) ) {
log ( LOG_NOTICE , " Invalid nickname '%s' in fingerprint file. Skipping. " , nickname ) ;
2005-09-15 16:39:05 +02:00
continue ;
}
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 ;
}
2005-06-21 03:00:42 +02:00
if ( add_fingerprint_to_dir ( nickname , fingerprint , fingerprint_list_new ) ! = 0 )
log ( LOG_NOTICE , " Duplicate nickname '%s'. " , nickname ) ;
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 */
2005-06-21 03:00:42 +02:00
directory_remove_invalid ( ) ;
2004-11-06 06:18:11 +01:00
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
2005-09-15 02:51:42 +02:00
* we recognize from the fingerprint list , or an IP we automatically act on
2005-09-15 08:15:31 +02:00
* according to our configuration . Return the appropriate router status .
*
* If the status is ' FP_REJECT ' and < b > msg < / b > is provided , set
* * < b > msg < / b > to an explanation of why .
2005-09-15 02:51:42 +02:00
*/
static router_status_t
dirserv_router_get_status ( const routerinfo_t * router , const char * * msg )
2003-09-27 23:30:10 +02:00
{
2005-09-15 16:39:05 +02:00
fingerprint_entry_t * nn_ent = NULL , * fp_ent = NULL ;
2003-09-27 23:30:10 +02:00
char fp [ FINGERPRINT_LEN + 1 ] ;
2004-05-18 19:41:40 +02:00
if ( ! fingerprint_list )
fingerprint_list = smartlist_create ( ) ;
2005-09-15 16:39:05 +02:00
if ( crypto_pk_get_fingerprint ( router - > identity_pkey , fp , 0 ) ) {
log_fn ( LOG_WARN , " Error computing fingerprint " ) ;
return - 1 ;
}
2004-05-18 19:41:40 +02:00
log_fn ( LOG_DEBUG , " %d fingerprints known. " , smartlist_len ( fingerprint_list ) ) ;
2005-09-15 02:51:42 +02:00
SMARTLIST_FOREACH ( fingerprint_list , fingerprint_entry_t * , ent ,
{
2005-09-15 16:39:05 +02:00
if ( ! strcasecmp ( fp , ent - > fingerprint ) )
fp_ent = ent ;
if ( ! strcasecmp ( router - > nickname , ent - > nickname ) )
2005-09-15 02:51:42 +02:00
nn_ent = ent ;
} ) ;
2005-09-15 16:39:05 +02:00
if ( fp_ent ) {
if ( ! strcasecmp ( fp_ent - > nickname , " !reject " ) ) {
if ( msg )
* msg = " Fingerprint is marked rejected " ;
return FP_REJECT ;
} else if ( ! strcasecmp ( fp_ent - > nickname , " !invalid " ) ) {
if ( msg )
* msg = " Fingerprint is marged invalid " ;
return FP_INVALID ;
}
}
2005-09-15 02:51:42 +02:00
if ( ! nn_ent ) { /* No such server known with that nickname */
2005-09-15 16:39:05 +02:00
addr_policy_result_t rej = router_compare_addr_to_addr_policy (
router - > addr , router - > or_port , authdir_reject_policy ) ;
addr_policy_result_t inv = router_compare_addr_to_addr_policy (
router - > addr , router - > or_port , authdir_invalid_policy ) ;
if ( rej = = ADDR_POLICY_PROBABLY_ACCEPTED | | rej = = ADDR_POLICY_ACCEPTED ) {
log_fn ( LOG_INFO , " Rejecting '%s' because of address %s " ,
router - > nickname , router - > address ) ;
if ( msg )
* msg = " Authdir is rejecting routers in this range. " ;
return FP_REJECT ;
}
if ( inv = = ADDR_POLICY_PROBABLY_ACCEPTED | | inv = = ADDR_POLICY_ACCEPTED ) {
log_fn ( LOG_INFO , " Not marking '%s' valid because of address %s " ,
router - > nickname , router - > address ) ;
return FP_INVALID ;
}
2005-09-15 02:51:42 +02:00
if ( tor_version_as_new_as ( router - > platform , " 0.1.0.2-rc " ) )
return FP_VALID ;
else
return FP_INVALID ;
log_fn ( LOG_INFO , " No fingerprint found for '%s' " , router - > nickname ) ;
2003-09-27 23:30:10 +02:00
return 0 ;
}
2005-09-15 02:51:42 +02:00
if ( 0 = = strcasecmp ( nn_ent - > fingerprint , fp ) ) {
log_fn ( LOG_DEBUG , " Good fingerprint for '%s' " , router - > nickname ) ;
return FP_NAMED ; /* Right fingerprint. */
2003-09-27 23:30:10 +02:00
} else {
2005-09-15 02:51:42 +02:00
log_fn ( LOG_WARN , " Mismatched fingerprint for '%s': expected '%s' got '%s'. ContactInfo '%s', platform '%s'.) " ,
router - > nickname , nn_ent - > fingerprint , fp ,
router - > contact_info ? router - > contact_info : " " ,
router - > platform ? router - > platform : " " ) ;
if ( msg )
* msg = " Rejected: There is already a verified server with this nickname and a different fingerprint. " ;
return FP_REJECT ; /* 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 . */
2005-06-11 20:52:12 +02:00
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-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-08-26 22:59:04 +02:00
static smartlist_t *
get_descriptor_list ( void )
2003-09-27 23:30:10 +02:00
{
2005-08-26 22:59:04 +02:00
routerlist_t * routerlist ;
router_get_routerlist ( & routerlist ) ;
if ( ! routerlist )
return NULL ;
return routerlist - > routers ;
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 ;
}
2005-09-15 02:51:42 +02:00
/** Check whether we, as a directory server, want to accept <b>ri</b>. If so,
2005-09-15 07:19:38 +02:00
* return 0 , and set its is_valid , named , running fields . Otherwise , return - 1.
*
2005-09-15 08:15:31 +02:00
* If the router is rejected and < b > msg < / b > is provided , set
* * < b > msg < / b > to an explanation of why .
2005-09-15 02:51:42 +02:00
*/
2003-09-27 23:30:10 +02:00
int
2005-09-15 02:51:42 +02:00
authdir_wants_to_reject_router ( routerinfo_t * ri ,
2005-08-26 22:59:04 +02:00
const char * * msg )
2003-09-27 23:30:10 +02:00
{
/* Okay. Now check whether the fingerprint is recognized. */
2005-09-15 02:51:42 +02:00
router_status_t status = dirserv_router_get_status ( ri , msg ) ;
2005-08-26 22:59:04 +02:00
time_t now ;
2005-09-15 02:51:42 +02:00
if ( status = = FP_REJECT )
return - 1 ; /* msg is already set. */
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. " ;
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. " ;
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. " ;
return - 1 ;
2005-01-06 22:03:27 +01:00
}
2005-09-15 02:51:42 +02:00
/* Okay, looks like we're willing to accept this one. */
switch ( status ) {
case FP_NAMED :
ri - > is_named = ri - > is_verified = 1 ;
break ;
case FP_VALID :
ri - > is_named = 0 ;
ri - > is_verified = 1 ;
break ;
case FP_INVALID :
ri - > is_named = ri - > is_verified = 0 ;
break ;
default :
tor_assert ( 0 ) ;
}
2005-08-26 22:59:04 +02:00
return 0 ;
}
2005-08-31 08:14:37 +02:00
/** Parse the server descriptor at <b>desc</b> and maybe insert it into
* the list of server descriptors . Set * < b > msg < / b > to a message that
* should be passed back to the origin of this descriptor .
2005-08-26 22:59:04 +02:00
*
2005-08-31 08:14:37 +02:00
* Return 2 if descriptor is well - formed and accepted ;
* 1 if well - formed and accepted but origin should hear * msg ;
2005-08-26 23:55:38 +02:00
* 0 if well - formed but redundant with one we already have ;
2005-08-26 22:59:04 +02:00
* - 1 if it looks vaguely like a router descriptor but rejected ;
2005-08-31 08:14:37 +02:00
* - 2 if we can ' t find a router descriptor in < b > desc < / b > .
2005-08-26 22:59:04 +02:00
*/
int
2005-08-26 23:28:16 +02:00
dirserv_add_descriptor ( const char * desc , const char * * msg )
2005-08-26 22:59:04 +02:00
{
2005-08-26 23:46:24 +02:00
int r ;
2005-08-26 22:59:04 +02:00
routerinfo_t * ri = NULL ;
tor_assert ( msg ) ;
* msg = NULL ;
/* Check: is the descriptor syntactically valid? */
2005-08-26 23:28:16 +02:00
ri = router_parse_entry_from_string ( desc , NULL ) ;
2005-08-26 22:59:04 +02:00
if ( ! ri ) {
log ( LOG_WARN , " Couldn't parse descriptor " ) ;
* msg = " Rejected: Couldn't parse server descriptor. " ;
2005-08-31 08:14:37 +02:00
return - 2 ;
2005-08-26 22:59:04 +02:00
}
2005-09-15 07:19:38 +02:00
if ( ( r = router_add_to_routerlist ( ri , msg , 0 ) ) < 0 ) {
2005-08-26 23:46:24 +02:00
return r = = - 1 ? 0 : - 1 ;
2005-08-26 22:59:04 +02:00
} else {
2005-08-26 23:02:18 +02:00
smartlist_t * changed = smartlist_create ( ) ;
smartlist_add ( changed , ri ) ;
control_event_descriptors_changed ( changed ) ;
smartlist_free ( changed ) ;
2005-08-26 23:46:24 +02:00
if ( ! * msg ) {
* msg = ri - > is_verified ? " Verified server descriptor accepted " :
" Unverified server descriptor accepted " ;
}
2005-08-31 08:14:37 +02:00
return r = = 0 ? 2 : 1 ;
2005-08-26 22:59:04 +02:00
}
2003-09-27 23:30:10 +02:00
}
2005-06-21 03:00:42 +02:00
/** Remove all descriptors whose nicknames or fingerprints no longer
* are allowed by our fingerprint list . ( Descriptors that used to be
* good can become bad when we reload the fingerprint list . )
2004-05-05 02:30:43 +02:00
*/
2004-04-13 22:06:08 +02:00
static void
2005-06-21 03:00:42 +02:00
directory_remove_invalid ( void )
2004-04-13 22:06:08 +02:00
{
int i ;
2005-08-26 22:59:04 +02:00
int changed = 0 ;
smartlist_t * descriptor_list = get_descriptor_list ( ) ;
2004-05-18 19:41:40 +02:00
if ( ! descriptor_list )
2005-08-26 22:59:04 +02:00
return ;
2004-05-18 19:41:40 +02:00
for ( i = 0 ; i < smartlist_len ( descriptor_list ) ; + + i ) {
2005-09-15 02:51:42 +02:00
const char * msg ;
2005-08-26 22:59:04 +02:00
routerinfo_t * ent = smartlist_get ( descriptor_list , i ) ;
2005-09-15 02:51:42 +02:00
router_status_t r = dirserv_router_get_status ( ent , & msg ) ;
switch ( r ) {
case FP_REJECT :
log ( LOG_INFO , " Router '%s' is now rejected: %s " ,
ent - > nickname , msg ? msg : " " ) ;
routerinfo_free ( ent ) ;
smartlist_del ( descriptor_list , i - - ) ;
changed = 1 ;
break ;
case FP_NAMED :
if ( ! ent - > is_verified | | ! ent - > is_named ) {
log ( LOG_INFO , " Router '%s' is now verified and named. " , ent - > nickname ) ;
ent - > is_verified = ent - > is_named = 1 ;
changed = 1 ;
}
break ;
case FP_VALID :
if ( ! ent - > is_verified | | ent - > is_named ) {
log ( LOG_INFO , " Router '%s' is now verified. " , ent - > nickname ) ;
ent - > is_verified = 1 ;
ent - > is_named = 0 ;
changed = 1 ;
}
break ;
case FP_INVALID :
if ( ent - > is_verified | | ent - > is_named ) {
log ( LOG_INFO , " Router '%s' is no longer verified. " , ent - > nickname ) ;
ent - > is_verified = ent - > is_named = 0 ;
changed = 1 ;
}
break ;
2004-04-13 22:06:08 +02:00
}
}
2005-08-26 22:59:04 +02:00
if ( changed )
directory_set_dirty ( ) ;
2004-04-13 22:06:08 +02:00
}
2005-08-13 03:55:23 +02:00
/** Write a list of unregistered descriptors into a newly allocated
* string and return it . Used by dirserv operators to keep track of
* fast nodes that haven ' t registered .
*/
char *
2005-08-13 04:20:00 +02:00
dirserver_getinfo_unregistered ( const char * question )
2005-08-13 03:55:23 +02:00
{
2005-09-15 02:51:42 +02:00
int i ;
router_status_t r ;
2005-08-13 03:55:23 +02:00
smartlist_t * answerlist ;
char buf [ 1024 ] ;
char * answer ;
routerinfo_t * ent ;
2005-08-13 04:20:00 +02:00
int min_bw = atoi ( question ) ;
2005-08-26 22:59:04 +02:00
smartlist_t * descriptor_list = get_descriptor_list ( ) ;
2005-08-13 03:55:23 +02:00
if ( ! descriptor_list )
return tor_strdup ( " " ) ;
answerlist = smartlist_create ( ) ;
for ( i = 0 ; i < smartlist_len ( descriptor_list ) ; + + i ) {
ent = smartlist_get ( descriptor_list , i ) ;
2005-09-15 02:51:42 +02:00
r = dirserv_router_get_status ( ent , NULL ) ;
2005-09-08 08:37:50 +02:00
if ( ent - > bandwidthcapacity > = ( size_t ) min_bw & &
ent - > bandwidthrate > = ( size_t ) min_bw & &
2005-09-15 02:51:42 +02:00
r ! = FP_NAMED ) {
2005-08-13 03:55:23 +02:00
/* then log this one */
tor_snprintf ( buf , sizeof ( buf ) ,
" %s: BW %d on '%s'. " ,
ent - > nickname , ent - > bandwidthcapacity ,
ent - > platform ? ent - > platform : " " ) ;
smartlist_add ( answerlist , tor_strdup ( buf ) ) ;
}
}
answer = smartlist_join_strings ( answerlist , " \r \n " , 0 , NULL ) ;
SMARTLIST_FOREACH ( answerlist , char * , cp , tor_free ( cp ) ) ;
smartlist_free ( answerlist ) ;
return answer ;
}
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 ;
2005-09-15 01:14:37 +02:00
if ( ! the_v2_networkstatus_is_dirty )
the_v2_networkstatus_is_dirty = now ;
2003-09-27 23:30:10 +02:00
}
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-08-24 04:31:02 +02:00
# define REACHABLE_TIMEOUT (60*60) /* an hour */
/* Make sure this is 3 times the value of get_dir_fetch_period() */
2005-08-30 08:43:07 +02:00
/** Treat a router as alive if
* - It ' s me , and I ' m not hibernating .
* or - we ' re connected to it and we ' ve found it reachable recently . */
static int
dirserv_thinks_router_is_reachable ( routerinfo_t * router , time_t now )
{
connection_t * conn ;
if ( router_is_me ( router ) & & ! we_are_hibernating ( ) )
return 1 ;
conn = connection_get_by_identity_digest ( router - > identity_digest ,
CONN_TYPE_OR ) ;
if ( conn & & conn - > state = = OR_CONN_STATE_OPEN )
return get_options ( ) - > AssumeReachable | |
now < router - > last_reachable + REACHABLE_TIMEOUT ;
return 0 ;
}
/** Return 1 if we're confident that there's a problem with
* < b > router < / b > ' s reachability and its operator should be notified .
*/
2005-08-31 08:14:37 +02:00
int
2005-08-30 08:43:07 +02:00
dirserv_thinks_router_is_blatantly_unreachable ( routerinfo_t * router , time_t now )
{
connection_t * conn ;
2005-08-30 08:48:24 +02:00
if ( router - > is_hibernating )
return 0 ;
2005-08-30 08:43:07 +02:00
conn = connection_get_by_identity_digest ( router - > identity_digest ,
CONN_TYPE_OR ) ;
if ( conn & & conn - > state = = OR_CONN_STATE_OPEN & &
now > = router - > last_reachable + 2 * REACHABLE_TIMEOUT & &
router - > testing_since & &
now > = router - > testing_since + 2 * REACHABLE_TIMEOUT )
return 1 ;
return 0 ;
}
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-08-24 04:31:02 +02:00
time_t now = time ( NULL ) ;
2005-03-23 20:15:10 +01:00
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
{
2005-03-23 20:15:10 +01:00
if ( authdir_mode ) {
2005-08-29 20:42:36 +02:00
/* Update router status in routerinfo_t. */
2005-08-30 08:43:07 +02:00
ri - > is_running = dirserv_thinks_router_is_reachable ( ri , now ) ;
2005-03-23 20:15:10 +01:00
}
2005-08-30 08:43:07 +02:00
smartlist_add ( rs_entries , list_single_server_status ( ri , ri - > is_running ) ) ;
2004-10-27 02:48:51 +02:00
} ) ;
2005-08-30 08:43:07 +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 ;
}
2005-09-15 08:15:31 +02:00
/** Helper: Given pointers to two strings describing tor versions, return -1
* if _a precedes _b , 1 if _b preceeds _a , and 0 if they are equivalent .
* Used to sort a list of versions . */
2005-09-14 22:59:25 +02:00
static int
2005-09-12 10:46:37 +02:00
_compare_tor_version_str_ptr ( const void * * _a , const void * * _b )
{
const char * a = * _a , * b = * _b ;
int ca , cb ;
tor_version_t va , vb ;
ca = tor_version_parse ( a , & va ) ;
cb = tor_version_parse ( b , & vb ) ;
/* If they both parse, compare them. */
2005-09-12 10:49:21 +02:00
if ( ! ca & & ! cb )
2005-09-12 10:46:37 +02:00
return tor_version_compare ( & va , & vb ) ;
/* If one parses, it comes first. */
if ( ! ca & & cb )
2005-09-12 10:49:21 +02:00
return - 1 ;
if ( ca & & ! cb )
2005-09-12 10:46:37 +02:00
return 1 ;
2005-09-12 23:42:59 +02:00
/* If neither parses, compare strings. Also, the directory server admin needs
2005-09-12 10:46:37 +02:00
* * to be smacked upside the head . But Tor is tolerant and gentle . */
return strcmp ( a , b ) ;
}
2005-08-26 17:34:53 +02:00
/* Given a (possibly empty) list of config_line_t, each line of which contains
* a list of comma - separated version numbers surrounded by optional space ,
* allocate and return a new string containing the version numbers , in order ,
2005-09-15 08:15:31 +02:00
* separated by commas . Used to generate Recommended ( Client | Server ) ? Versions
*/
2005-08-25 22:33:17 +02:00
static char *
format_versions_list ( config_line_t * ln )
{
smartlist_t * versions ;
char * result ;
versions = smartlist_create ( ) ;
for ( ; ln ; ln = ln - > next ) {
smartlist_split_string ( versions , ln - > value , " , " ,
SPLIT_SKIP_SPACE | SPLIT_IGNORE_BLANK , 0 ) ;
}
2005-09-12 10:46:37 +02:00
smartlist_sort ( versions , _compare_tor_version_str_ptr ) ;
2005-08-25 22:33:17 +02:00
result = smartlist_join_strings ( versions , " , " , 0 , NULL ) ;
SMARTLIST_FOREACH ( versions , char * , s , tor_free ( s ) ) ;
smartlist_free ( versions ) ;
return result ;
}
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 )
{
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 ;
2005-08-25 22:33:17 +02:00
char digest [ DIGEST_LEN ] ;
char published [ ISO_TIME_LEN + 1 ] ;
2003-09-27 23:30:10 +02:00
time_t published_on ;
2004-12-24 03:17:32 +01:00
char * buf = NULL ;
size_t buf_len ;
2005-05-02 23:22:31 +02:00
size_t identity_pkey_len ;
2005-08-26 22:59:04 +02:00
smartlist_t * descriptor_list = get_descriptor_list ( ) ;
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 )
2005-08-26 22:59:04 +02:00
return - 1 ;
2004-05-18 19:41:40 +02:00
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
2005-08-25 22:33:17 +02:00
recommended_versions = format_versions_list ( get_options ( ) - > RecommendedVersions ) ;
2004-11-09 21:04:00 +01:00
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 ,
2005-08-26 22:59:04 +02:00
buf_len + = ri - > signed_descriptor_len ) ;
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 ) ;
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 ;
}
2005-08-26 17:34:53 +02:00
if ( router_append_dirobj_signature ( buf , buf_len , digest , private_key ) < 0 ) {
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
* 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
}
2005-08-25 22:33:17 +02:00
/** Most recently generated encoded signed directory. (auth dirservers only.)*/
static cached_dir_t the_directory = { NULL , NULL , 0 , 0 , 0 } ;
2005-08-26 17:34:53 +02:00
/* Used only by non-auth dirservers: The directory and runningrouters we'll
2005-09-14 22:59:25 +02:00
* serve when requested . */
2004-11-15 05:04:20 +01:00
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
2005-08-26 17:34:53 +02:00
/* Used for other dirservers' v2 network statuses. Map from hexdigest to
2005-08-25 22:33:17 +02:00
* cached_dir_t . */
static strmap_t * cached_v2_networkstatus = NULL ;
2005-08-26 17:34:53 +02:00
/** Possibly replace the contents of <b>d</b> with the value of
2005-08-28 06:20:37 +02:00
* < b > directory < / b > published on < b > when < / b > , unless < b > when < / b > is older than
* the last value , or too far in the future .
*
* Does not copy < b > directory < / b > ; free it if it isn ' t used .
*/
2005-08-25 22:33:17 +02:00
static void
2005-08-28 06:20:37 +02:00
set_cached_dir ( cached_dir_t * d , char * directory , time_t when )
2004-06-21 06:37:27 +02:00
{
2005-08-25 22:33:17 +02:00
time_t now = time ( NULL ) ;
2004-11-15 05:04:20 +01:00
if ( when < = d - > published ) {
2004-09-08 08:52:33 +02:00
log_fn ( LOG_INFO , " Ignoring old directory; not caching. " ) ;
2005-08-28 06:20:37 +02:00
tor_free ( directory ) ;
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-08-28 06:20:37 +02:00
tor_free ( directory ) ;
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 ) ;
2005-08-28 06:20:37 +02:00
d - > dir = directory ;
2004-11-15 05:04:20 +01:00
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 ;
2005-08-25 22:33:17 +02:00
}
}
2005-08-26 17:34:53 +02:00
/** Remove all storage held in <b>d</b>, but do not free <b>d</b> itself. */
2005-08-25 22:33:17 +02:00
static void
clear_cached_dir ( cached_dir_t * d )
{
tor_free ( d - > dir ) ;
tor_free ( d - > dir_z ) ;
memset ( d , 0 , sizeof ( cached_dir_t ) ) ;
}
2005-08-26 17:34:53 +02:00
/** Free all storage held by the cached_dir_t in <b>d</b>. */
2005-08-25 22:33:17 +02:00
static void
free_cached_dir ( void * _d )
{
cached_dir_t * d = ( cached_dir_t * ) _d ;
clear_cached_dir ( d ) ;
tor_free ( d ) ;
}
/** 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 > .
*/
void
dirserv_set_cached_directory ( const char * directory , time_t published ,
int is_running_routers )
{
cached_dir_t * d ;
d = is_running_routers ? & cached_runningrouters : & cached_directory ;
2005-08-28 06:20:37 +02:00
set_cached_dir ( d , tor_strdup ( directory ) , published ) ;
2005-08-25 22:33:17 +02:00
}
2005-08-26 20:02:49 +02:00
/** We've just received a v2 network-status for an authoritative directory
* with fingerprint < b > fp < / b > ( hex digest , no spaces ) , published at
2005-09-13 23:14:55 +02:00
* < b > published < / b > . Store it so we can serve it to others . If
* < b > directory < / b > is NULL , remove the entry with the given fingerprint from
* the cache .
2005-08-26 20:02:49 +02:00
*/
2005-08-25 22:33:17 +02:00
void
dirserv_set_cached_networkstatus_v2 ( const char * directory , const char * fp ,
time_t published )
{
cached_dir_t * d ;
if ( ! cached_v2_networkstatus )
cached_v2_networkstatus = strmap_new ( ) ;
tor_assert ( strlen ( fp ) = = HEX_DIGEST_LEN ) ;
if ( ! ( d = strmap_get ( cached_v2_networkstatus , fp ) ) ) {
2005-09-12 08:56:42 +02:00
if ( ! directory )
return ;
2005-08-25 22:33:17 +02:00
d = tor_malloc_zero ( sizeof ( cached_dir_t ) ) ;
strmap_set ( cached_v2_networkstatus , fp , d ) ;
}
tor_assert ( d ) ;
2005-09-12 08:56:42 +02:00
if ( directory ) {
set_cached_dir ( d , tor_strdup ( directory ) , published ) ;
} else {
free_cached_dir ( d ) ;
strmap_remove ( cached_v2_networkstatus , fp ) ;
}
2005-09-07 18:42:53 +02:00
}
2005-08-25 22:33:17 +02:00
2005-09-13 23:14:55 +02:00
/** Helper: If we're an authority for the right directory version (the
* directory version is determined by < b > is_v1_object < / b > ) , try to regenerate
* auth_src as appropriate and return it , falling back to cache_src on
* failure . If we ' re a cache , return cach_src .
*/
2005-09-07 18:42:53 +02:00
static cached_dir_t *
dirserv_pick_cached_dir_obj ( cached_dir_t * cache_src ,
cached_dir_t * auth_src ,
time_t dirty , int ( * regenerate ) ( void ) ,
const char * name ,
int is_v1_object )
{
int authority = get_options ( ) - > AuthoritativeDir & &
( ! is_v1_object | | get_options ( ) - > V1AuthoritativeDir ) ;
2005-08-25 22:33:17 +02:00
2005-09-07 18:42:53 +02:00
if ( ! authority ) {
return cache_src ;
} else {
/* We're authoritative. */
if ( regenerate ! = NULL ) {
if ( dirty & & dirty + DIR_REGEN_SLACK_TIME < time ( NULL ) ) {
if ( regenerate ( ) ) {
log_fn ( LOG_ERR , " Couldn't generate %s? " , name ) ;
exit ( 1 ) ;
}
} else {
log_fn ( LOG_INFO , " The %s is still clean; reusing. " , name ) ;
}
}
return auth_src ? auth_src : cache_src ;
2005-08-25 22:33:17 +02:00
}
}
2005-08-26 20:02:49 +02:00
/** Helper: If we're authoritative and <b>auth_src</b> is set, use
* < b > auth_src < / b > , otherwise use < b > cache_src < / b > . If we ' re using
* < b > auth_src < / b > and it ' s been < b > dirty < / b > for at least
* DIR_REGEN_SLACK_TIME seconds , call < b > regenerate < / b > ( ) to make a fresh one .
* Yields the compressed version of the directory object if < b > compress < / b > is
* set ; otherwise return the uncompressed version . ( In either case , sets
2005-09-13 23:14:55 +02:00
* * < b > out < / b > and returns the size of the buffer in * < b > out < / b > . )
2005-09-07 18:42:53 +02:00
*
2005-09-13 23:14:55 +02:00
* Use < b > is_v1_object < / b > to help determine whether we ' re authoritative for
* this kind of object .
2005-09-07 18:42:53 +02:00
* */
2005-08-25 22:33:17 +02:00
static size_t
dirserv_get_obj ( const char * * out , int compress ,
cached_dir_t * cache_src ,
cached_dir_t * auth_src ,
time_t dirty , int ( * regenerate ) ( void ) ,
2005-09-07 18:42:53 +02:00
const char * name ,
int is_v1_object )
2005-08-25 22:33:17 +02:00
{
2005-09-07 18:42:53 +02:00
cached_dir_t * d = dirserv_pick_cached_dir_obj (
cache_src , auth_src ,
dirty , regenerate , name , is_v1_object ) ;
2005-08-25 22:33:17 +02:00
if ( ! d )
return 0 ;
* out = compress ? d - > dir_z : d - > dir ;
if ( * out ) {
return compress ? d - > dir_z_len : d - > dir_len ;
} else {
/* not yet available. */
return 0 ;
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 . */
2005-06-11 20:52:12 +02:00
size_t
dirserv_get_directory ( const char * * directory , int compress )
2003-09-27 23:30:10 +02:00
{
2005-08-25 22:33:17 +02:00
return dirserv_get_obj ( directory , compress ,
& cached_directory , & the_directory ,
the_directory_is_dirty ,
dirserv_regenerate_directory ,
2005-09-07 18:42:53 +02:00
" server directory " , 1 ) ;
2004-09-02 20:57:09 +02:00
}
/**
* Generate a fresh directory ( authdirservers only . )
*/
2005-06-11 20:52:12 +02:00
static int
dirserv_regenerate_directory ( void )
2004-09-02 20:57:09 +02:00
{
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 ;
}
2005-08-25 22:33:17 +02:00
set_cached_dir ( & the_directory , new_directory , time ( NULL ) ) ;
log_fn ( LOG_INFO , " New directory (size %d): \n %s " , ( int ) the_directory . dir_len ,
the_directory . dir ) ;
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.
*/
2005-08-25 22:33:17 +02:00
dirserv_set_cached_directory ( the_directory . dir , time ( NULL ) , 0 ) ;
2004-11-15 17:17:59 +01:00
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
2005-08-26 20:02:49 +02:00
/** For authoritative directories: the current (v1) network status */
2005-08-25 22:33:17 +02:00
static cached_dir_t the_runningrouters = { NULL , NULL , 0 , 0 , 0 } ;
2004-06-25 02:29:31 +02:00
/** Replace the current running-routers list with a newly generated one. */
2005-06-11 20:52:12 +02:00
static int
2005-08-25 22:33:17 +02:00
generate_runningrouters ( void )
2004-06-25 02:29:31 +02:00
{
2005-08-25 22:33:17 +02:00
char * s = NULL ;
2004-10-27 14:34:02 +02:00
char * router_status = NULL ;
2004-06-25 02:29:31 +02:00
char digest [ DIGEST_LEN ] ;
2005-08-25 22:33:17 +02:00
char published [ ISO_TIME_LEN + 1 ] ;
2004-08-04 01:57:05 +02:00
size_t len ;
2005-08-25 22:33:17 +02:00
crypto_pk_env_t * private_key = get_identity_key ( ) ;
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 ;
2005-08-26 22:59:04 +02:00
smartlist_t * descriptor_list = get_descriptor_list ( ) ;
2005-03-23 20:15:10 +01:00
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
}
2005-08-25 22:33:17 +02:00
format_iso_time ( published , time ( NULL ) ) ;
2004-12-24 02:41:52 +01:00
len = 2048 + strlen ( router_status ) ;
s = tor_malloc_zero ( len ) ;
2005-08-25 22:33:17 +02:00
tor_snprintf ( s , len ,
" network-status \n "
" published %s \n "
" router-status %s \n "
" dir-signing-key \n %s "
" directory-signature %s \n " ,
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
}
2005-08-26 17:34:53 +02:00
if ( router_append_dirobj_signature ( s , len , digest , private_key ) < 0 )
2004-10-27 14:34:02 +02:00
goto err ;
2004-06-25 02:29:31 +02:00
2005-08-25 22:33:17 +02:00
set_cached_dir ( & the_runningrouters , s , time ( NULL ) ) ;
2004-06-25 02:29:31 +02:00
runningrouters_is_dirty = 0 ;
2004-11-15 17:17:59 +01:00
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 . */
2005-06-11 20:52:12 +02:00
size_t
dirserv_get_runningrouters ( const char * * rr , int compress )
2004-06-16 23:08:29 +02:00
{
2005-08-25 22:33:17 +02:00
return dirserv_get_obj ( rr , compress ,
& cached_runningrouters , & the_runningrouters ,
runningrouters_is_dirty ,
generate_runningrouters ,
2005-09-07 18:42:53 +02:00
" v1 network status list " , 1 ) ;
2005-08-25 22:33:17 +02:00
}
2005-09-08 07:23:55 +02:00
/** Return true iff <b>ri</b> is "useful as an exit node", meaning
* it allows exit to at least one / 8 address space for at least
* one of ports 80 , 443 , and 6667. */
2005-08-25 22:33:17 +02:00
static int
router_is_general_exit ( routerinfo_t * ri )
{
2005-09-08 07:23:55 +02:00
static const int ports [ ] = { 80 , 443 , 6667 } ;
2005-08-25 22:33:17 +02:00
int n_allowed = 3 ;
int i ;
for ( i = 0 ; i < 3 ; + + i ) {
struct addr_policy_t * policy = ri - > exit_policy ;
for ( ; policy ; policy = policy - > next ) {
if ( policy - > prt_min > ports [ i ] | | policy - > prt_max < ports [ i ] )
continue ; /* Doesn't cover our port. */
if ( ( policy - > msk & 0x00fffffful ) ! = 0 )
2005-09-08 07:23:55 +02:00
continue ; /* Narrower than a /8. */
2005-08-25 22:33:17 +02:00
if ( ( policy - > addr & 0xff000000ul ) = = 0x7f000000ul )
continue ; /* 127.x */
2005-09-08 07:23:55 +02:00
/* We have a match that is at least a /8. */
2005-08-25 22:33:17 +02:00
if ( policy - > policy_type ! = ADDR_POLICY_ACCEPT )
- - n_allowed ;
break ;
2004-11-15 05:04:20 +01:00
}
}
2005-08-25 22:33:17 +02:00
return n_allowed > 0 ;
}
2005-08-26 20:02:49 +02:00
/** For authoritative directories: the current (v2) network status */
2005-08-25 22:33:17 +02:00
static cached_dir_t the_v2_networkstatus = { NULL , NULL , 0 , 0 , 0 } ;
2005-08-26 20:02:49 +02:00
/** For authoritative directories only: replace the contents of
* < b > the_v2_networkstatus < / b > with a newly generated network status
* object . */
2005-08-25 22:33:17 +02:00
static int
generate_v2_networkstatus ( void )
{
2005-08-26 23:11:53 +02:00
# define BASE64_DIGEST_LEN 27
2005-08-25 22:33:17 +02:00
# define LONGEST_STATUS_FLAG_NAME_LEN 7
# define N_STATUS_FLAGS 6
# define RS_ENTRY_LEN \
( /* first line */ \
MAX_NICKNAME_LEN + BASE64_DIGEST_LEN * 2 + ISO_TIME_LEN + INET_NTOA_BUF_LEN + \
5 * 2 /* ports */ + 10 /* punctuation */ + \
/* second line */ \
( LONGEST_STATUS_FLAG_NAME_LEN + 1 ) * N_STATUS_FLAGS + 2 )
int r = - 1 ;
size_t len , identity_pkey_len ;
char * status = NULL , * client_versions = NULL , * server_versions = NULL ,
* identity_pkey = NULL , * hostname = NULL ;
char * outp , * endp ;
or_options_t * options = get_options ( ) ;
char fingerprint [ FINGERPRINT_LEN + 1 ] ;
char ipaddr [ INET_NTOA_BUF_LEN + 1 ] ;
char published [ ISO_TIME_LEN ] ;
char digest [ DIGEST_LEN ] ;
struct in_addr in ;
uint32_t addr ;
crypto_pk_env_t * private_key = get_identity_key ( ) ;
2005-08-26 22:59:04 +02:00
smartlist_t * descriptor_list = get_descriptor_list ( ) ;
2005-09-15 07:19:38 +02:00
time_t now = time ( NULL ) ;
2005-09-15 16:39:05 +02:00
int naming = options - > NamingAuthoritativeDir ;
2005-09-02 22:30:03 +02:00
const char * contact ;
2005-08-26 22:59:04 +02:00
if ( ! descriptor_list ) {
log_fn ( LOG_WARN , " Couldn't get router list. " ) ;
goto done ;
}
2005-08-25 22:33:17 +02:00
if ( resolve_my_address ( options , & addr , & hostname ) < 0 ) {
log_fn ( LOG_WARN , " Couldn't resolve my hostname " ) ;
goto done ;
}
in . s_addr = htonl ( addr ) ;
tor_inet_ntoa ( & in , ipaddr , sizeof ( ipaddr ) ) ;
format_iso_time ( published , time ( NULL ) ) ;
client_versions = format_versions_list ( options - > RecommendedClientVersions ) ;
server_versions = format_versions_list ( options - > RecommendedServerVersions ) ;
if ( crypto_pk_write_public_key_to_string ( private_key , & identity_pkey ,
& identity_pkey_len ) < 0 ) {
log_fn ( LOG_WARN , " Writing public key to string failed. " ) ;
goto done ;
}
if ( crypto_pk_get_fingerprint ( private_key , fingerprint , 0 ) < 0 ) {
log_fn ( LOG_ERR , " Error computing fingerprint " ) ;
2005-09-09 21:37:12 +02:00
goto done ;
2005-08-25 22:33:17 +02:00
}
2005-09-02 22:30:03 +02:00
contact = get_options ( ) - > ContactInfo ;
if ( ! contact )
contact = " (none) " ;
2005-08-25 22:33:17 +02:00
len = 2048 + strlen ( client_versions ) + strlen ( server_versions ) + identity_pkey_len * 2 ;
len + = ( RS_ENTRY_LEN ) * smartlist_len ( descriptor_list ) ;
status = tor_malloc ( len ) ;
tor_snprintf ( status , len ,
" network-status-version 2 \n "
" dir-source %s %s %d \n "
2005-09-02 22:30:03 +02:00
" fingerprint %s \n "
" contact %s \n "
2005-08-25 22:33:17 +02:00
" published %s \n "
2005-09-15 16:39:05 +02:00
" dir-options%s \n "
2005-08-25 22:33:17 +02:00
" client-versions %s \n "
" server-versions %s \n "
" dir-signing-key \n %s \n " ,
hostname , ipaddr , ( int ) options - > DirPort ,
fingerprint ,
2005-09-02 22:30:03 +02:00
contact ,
2005-09-03 04:38:39 +02:00
published ,
2005-09-15 16:39:05 +02:00
naming ? " Names " : " " ,
2005-08-25 22:33:17 +02:00
client_versions ,
server_versions ,
identity_pkey ) ;
outp = status + strlen ( status ) ;
endp = status + len ;
SMARTLIST_FOREACH ( descriptor_list , routerinfo_t * , ri , {
int f_exit = router_is_general_exit ( ri ) ;
int f_stable = ! router_is_unreliable ( ri , 1 , 0 ) ;
int f_fast = ! router_is_unreliable ( ri , 0 , 1 ) ;
int f_running ;
2005-09-15 16:39:05 +02:00
int f_named = naming & & ri - > is_named ;
int f_valid = ri - > is_verified ;
2005-08-25 22:33:17 +02:00
char identity64 [ 128 ] ;
char digest64 [ 128 ] ;
if ( options - > AuthoritativeDir ) {
2005-09-15 07:19:38 +02:00
ri - > is_running = dirserv_thinks_router_is_reachable ( ri , now ) ;
2005-08-25 22:33:17 +02:00
}
2005-09-15 07:19:38 +02:00
f_running = ri - > is_running ;
2005-08-25 22:33:17 +02:00
format_iso_time ( published , ri - > published_on ) ;
if ( base64_encode ( identity64 , sizeof ( identity64 ) ,
2005-09-09 21:37:12 +02:00
ri - > identity_digest , DIGEST_LEN ) < 0 ) {
log_fn ( LOG_WARN , " Unable to encode router identity digest. " ) ;
2005-08-25 22:33:17 +02:00
goto done ;
2005-09-09 21:37:12 +02:00
}
2005-08-25 22:33:17 +02:00
if ( base64_encode ( digest64 , sizeof ( digest64 ) ,
2005-09-09 21:37:12 +02:00
ri - > signed_descriptor_digest , DIGEST_LEN ) < 0 ) {
log_fn ( LOG_WARN , " Unable to encode router descriptor digest. " ) ;
2005-08-25 22:33:17 +02:00
goto done ;
2005-09-09 21:37:12 +02:00
}
2005-08-25 22:33:17 +02:00
identity64 [ BASE64_DIGEST_LEN ] = ' \0 ' ;
digest64 [ BASE64_DIGEST_LEN ] = ' \0 ' ;
in . s_addr = htonl ( ri - > addr ) ;
tor_inet_ntoa ( & in , ipaddr , sizeof ( ipaddr ) ) ;
if ( tor_snprintf ( outp , endp - outp ,
" r %s %s %s %s %s %d %d \n "
" s%s%s%s%s%s%s \n " ,
ri - > nickname ,
identity64 ,
digest64 ,
published ,
ipaddr ,
ri - > or_port ,
ri - > dir_port ,
f_exit ? " Exit " : " " ,
f_stable ? " Stable " : " " ,
f_fast ? " Fast " : " " ,
f_running ? " Running " : " " ,
f_named ? " Named " : " " ,
f_valid ? " Valid " : " " ) < 0 ) {
log_fn ( LOG_WARN , " Unable to print router status. " ) ;
goto done ;
}
outp + = strlen ( outp ) ;
} ) ;
if ( tor_snprintf ( outp , endp - outp , " directory-signature %s \n " ,
get_options ( ) - > Nickname ) < 0 ) {
log_fn ( LOG_WARN , " Unable to write signature line. " ) ;
goto done ;
}
if ( router_get_networkstatus_v2_hash ( status , digest ) < 0 ) {
log_fn ( LOG_WARN , " Unable to hash network status " ) ;
goto done ;
}
2005-09-09 21:37:12 +02:00
if ( router_append_dirobj_signature ( outp , endp - outp , digest , private_key ) < 0 ) {
log_fn ( LOG_WARN , " Unable to sign router status. " ) ;
2005-08-25 22:33:17 +02:00
goto done ;
2005-09-09 21:37:12 +02:00
}
2005-08-25 22:33:17 +02:00
set_cached_dir ( & the_v2_networkstatus , status , time ( NULL ) ) ;
2005-08-28 06:20:37 +02:00
status = NULL ; /* So it doesn't get double-freed. */
2005-08-27 00:08:24 +02:00
the_v2_networkstatus_is_dirty = 0 ;
2005-09-08 22:36:40 +02:00
router_set_networkstatus ( the_v2_networkstatus . dir , time ( NULL ) , NS_GENERATED ,
NULL ) ;
2005-08-25 22:33:17 +02:00
r = 0 ;
done :
tor_free ( client_versions ) ;
tor_free ( server_versions ) ;
tor_free ( status ) ;
tor_free ( hostname ) ;
tor_free ( identity_pkey ) ;
return r ;
}
2005-08-26 20:02:49 +02:00
/** Look for a network status object as specified by <b>key</b>, which should
2005-08-30 08:01:13 +02:00
* be either " authority " ( to find a network status generated by us ) , a hex
2005-08-26 20:02:49 +02:00
* identity digest ( to find a network status generated by given directory ) , or
2005-08-30 08:01:13 +02:00
* " all " ( to return all the v2 network status objects we have , concatenated ) .
2005-08-26 20:02:49 +02:00
* If < b > compress < / b > , find the version compressed with zlib . Return 0 if
* nothing was found ; otherwise set * < b > directory < / b > to the matching network
* status and return its length .
*/
2005-09-07 18:42:53 +02:00
int
dirserv_get_networkstatus_v2 ( smartlist_t * result ,
const char * key )
2005-08-25 22:33:17 +02:00
{
2005-09-07 18:42:53 +02:00
tor_assert ( result ) ;
2005-09-08 20:14:23 +02:00
if ( ! cached_v2_networkstatus )
cached_v2_networkstatus = strmap_new ( ) ;
2005-08-25 22:33:17 +02:00
if ( ! ( strcmp ( key , " authority " ) ) ) {
if ( get_options ( ) - > AuthoritativeDir ) {
2005-09-07 18:42:53 +02:00
cached_dir_t * d =
dirserv_pick_cached_dir_obj ( NULL ,
& the_v2_networkstatus ,
the_v2_networkstatus_is_dirty ,
generate_v2_networkstatus ,
" network status list " , 0 ) ;
2005-09-09 21:37:12 +02:00
log_fn ( LOG_WARN , " Unable to generate an authoritative network stautus. " ) ;
2005-09-07 18:42:53 +02:00
if ( d )
smartlist_add ( result , d ) ;
2004-06-25 02:29:31 +02:00
}
2005-08-25 22:33:17 +02:00
} else if ( ! strcmp ( key , " all " ) ) {
2005-09-07 18:42:53 +02:00
strmap_iter_t * iter = strmap_iter_init ( cached_v2_networkstatus ) ;
while ( ! strmap_iter_done ( iter ) ) {
const char * fp ;
void * val ;
strmap_iter_get ( iter , & fp , & val ) ;
smartlist_add ( result , val ) ;
2005-09-08 23:20:20 +02:00
iter = strmap_iter_next ( cached_v2_networkstatus , iter ) ;
2005-09-07 18:42:53 +02:00
}
2005-09-09 21:37:12 +02:00
if ( smartlist_len ( result ) = = 0 )
log_fn ( LOG_WARN , " Client requested 'all' network status objects; we have none. " ) ;
2005-09-07 18:42:53 +02:00
} else if ( ! strcmpstart ( key , " fp/ " ) ) {
smartlist_t * hexdigests = smartlist_create ( ) ;
smartlist_split_string ( hexdigests , key + 3 , " + " , 0 , 0 ) ;
SMARTLIST_FOREACH ( hexdigests , char * , cp ,
{
cached_dir_t * cached ;
2005-09-08 20:34:41 +02:00
tor_strupper ( cp ) ;
2005-09-08 22:18:15 +02:00
if ( router_fingerprint_is_me ( cp ) & &
2005-09-08 21:29:21 +02:00
get_options ( ) - > AuthoritativeDir & &
the_v2_networkstatus_is_dirty & &
the_v2_networkstatus_is_dirty + DIR_REGEN_SLACK_TIME < time ( NULL ) )
generate_v2_networkstatus ( ) ;
2005-09-07 18:42:53 +02:00
cached = strmap_get ( cached_v2_networkstatus , cp ) ;
2005-09-09 21:37:12 +02:00
if ( cached ) {
2005-09-07 18:42:53 +02:00
smartlist_add ( result , cached ) ;
2005-09-09 21:37:12 +02:00
} else {
2005-09-09 23:03:57 +02:00
log_fn ( LOG_INFO , " Don't know about any network status with fingerprint '%s' " , cp ) ;
2005-09-09 21:37:12 +02:00
}
tor_free ( cp ) ;
2005-09-07 18:42:53 +02:00
} ) ;
2005-09-09 21:37:12 +02:00
smartlist_free ( hexdigests ) ;
2005-08-25 22:33:17 +02:00
}
return 0 ;
}
2005-09-08 08:49:23 +02:00
/** Add a routerinfo_t to <b>descs_out</b> for each router matching
2005-08-26 20:02:49 +02:00
* < b > key < / b > . The key should be either " /tor/server/authority " for our own
* routerinfo ; " /tor/server/all " for all the routerinfos we have ,
* concatenated ; or " /tor/server/FP " where FP is a plus - separated sequence of
* hex identity digests .
*/
2005-08-25 22:33:17 +02:00
void
dirserv_get_routerdescs ( smartlist_t * descs_out , const char * key )
{
2005-08-26 22:59:04 +02:00
smartlist_t * complete_list = get_descriptor_list ( ) ;
2005-08-25 22:54:12 +02:00
if ( ! complete_list )
return ;
2005-08-25 22:33:17 +02:00
if ( ! strcmp ( key , " /tor/server/all " ) ) {
2005-08-26 22:59:04 +02:00
smartlist_add_all ( descs_out , complete_list ) ;
2005-08-25 22:33:17 +02:00
} else if ( ! strcmp ( key , " /tor/server/authority " ) ) {
routerinfo_t * ri = router_get_my_routerinfo ( ) ;
if ( ri )
smartlist_add ( descs_out , ri ) ;
} else if ( ! strcmpstart ( key , " /tor/server/fp/ " ) ) {
smartlist_t * hexdigests = smartlist_create ( ) ;
smartlist_t * digests = smartlist_create ( ) ;
key + = strlen ( " /tor/server/fp/ " ) ;
smartlist_split_string ( hexdigests , key , " + " , 0 , 0 ) ;
SMARTLIST_FOREACH ( hexdigests , char * , cp ,
{
char * d ;
if ( strlen ( cp ) ! = HEX_DIGEST_LEN )
continue ;
d = tor_malloc_zero ( DIGEST_LEN ) ;
base16_decode ( d , DIGEST_LEN , cp , HEX_DIGEST_LEN ) ;
tor_free ( cp ) ;
smartlist_add ( digests , d ) ;
} ) ;
smartlist_free ( hexdigests ) ;
2005-09-08 23:01:24 +02:00
SMARTLIST_FOREACH ( digests , const char * , d ,
{
if ( router_digest_is_me ( d ) ) {
smartlist_add ( descs_out , router_get_my_routerinfo ( ) ) ;
} else {
routerinfo_t * ri = router_get_by_digest ( d ) ;
2005-09-13 03:20:26 +02:00
if ( ri )
2005-09-08 23:01:24 +02:00
smartlist_add ( descs_out , ri ) ;
}
} ) ;
2005-08-25 22:33:17 +02:00
SMARTLIST_FOREACH ( digests , char * , d , tor_free ( d ) ) ;
smartlist_free ( digests ) ;
2004-06-25 02:29:31 +02:00
}
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 .
2005-06-21 01:04:13 +02:00
*
* Also , if as_advertised is 1 , then inform the reachability checker
* that we could get to this guy .
2005-04-06 23:09:47 +02:00
*/
void
dirserv_orconn_tls_done ( const char * address ,
uint16_t or_port ,
const char * digest_rcvd ,
2005-06-21 01:04:13 +02:00
const char * nickname_rcvd ,
2005-08-24 04:31:02 +02:00
int as_advertised )
2005-04-06 23:09:47 +02:00
{
int i ;
2005-08-26 22:59:04 +02:00
smartlist_t * descriptor_list = get_descriptor_list ( ) ;
2005-04-06 23:09:47 +02:00
tor_assert ( address ) ;
tor_assert ( digest_rcvd ) ;
tor_assert ( nickname_rcvd ) ;
if ( ! descriptor_list )
return ;
2005-08-26 22:59:04 +02:00
// XXXXNM We should really have a better solution here than dropping
// XXXXNM whole routers; otherwise, they come back way too easily.
2005-04-06 23:09:47 +02:00
for ( i = 0 ; i < smartlist_len ( descriptor_list ) ; + + i ) {
routerinfo_t * ri = smartlist_get ( descriptor_list , i ) ;
int drop = 0 ;
2005-08-24 04:31:02 +02:00
if ( strcasecmp ( address , ri - > address ) | | or_port ! = ri - > or_port )
2005-04-06 23:09:47 +02:00
continue ;
2005-08-24 04:31:02 +02:00
if ( ! ri - > is_verified ) {
2005-04-06 23:09:47 +02:00
/* 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 ;
}
2005-08-24 04:31:02 +02:00
}
if ( drop ) {
routerinfo_free ( ri ) ;
smartlist_del ( descriptor_list , i - - ) ;
directory_set_dirty ( ) ;
} else { /* correct nickname and digest. mark this router reachable! */
log_fn ( LOG_INFO , " Found router %s to be reachable. Yay. " , ri - > nickname ) ;
ri - > last_reachable = time ( NULL ) ;
2005-09-01 10:13:40 +02:00
ri - > num_unreachable_notifications = 0 ;
2005-04-06 23:09:47 +02:00
}
}
}
2005-06-11 20:52:12 +02:00
/** Release all storage used by the directory server. */
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 ;
}
2005-09-15 16:39:05 +02:00
if ( authdir_reject_policy )
addr_policy_free ( authdir_reject_policy ) ;
if ( authdir_invalid_policy )
addr_policy_free ( authdir_invalid_policy ) ;
2005-08-25 22:33:17 +02:00
clear_cached_dir ( & the_directory ) ;
clear_cached_dir ( & the_runningrouters ) ;
clear_cached_dir ( & cached_directory ) ;
clear_cached_dir ( & cached_runningrouters ) ;
2005-08-26 20:48:13 +02:00
if ( cached_v2_networkstatus ) {
strmap_free ( cached_v2_networkstatus , free_cached_dir ) ;
cached_v2_networkstatus = NULL ;
}
2005-02-11 00:18:39 +01:00
}
2005-06-09 21:03:31 +02:00