2004-11-07 02:33:06 +01:00
/* Copyright 2001 Matej Pfajfar.
* Copyright 2001 - 2004 Roger Dingledine .
2005-04-01 22:15:56 +02:00
* Copyright 2004 - 2005 Roger Dingledine , Nick Mathewson . */
Implemented link padding and receiver token buckets
Each socket reads at most 'bandwidth' bytes per second sustained, but
can handle bursts of up to 10*bandwidth bytes.
Cells are now sent out at evenly-spaced intervals, with padding sent
out otherwise. Set Linkpadding=0 in the rc file to send cells as soon
as they're available (and to never send padding cells).
Added license/copyrights statements at the top of most files.
router->min and router->max have been merged into a single 'bandwidth'
value. We should make the routerinfo_t reflect this (want to do that,
Mat?)
As the bandwidth increases, and we want to stop sleeping more and more
frequently to send a single cell, cpu usage goes up. At 128kB/s we're
pretty much calling poll with a timeout of 1ms or even 0ms. The current
code takes a timeout of 0-9ms and makes it 10ms. prepare_for_poll()
handles everything that should have happened in the past, so as long as
our buffers don't get too full in that 10ms, we're ok.
Speaking of too full, if you run three servers at 100kB/s with -l debug,
it spends too much time printing debugging messages to be able to keep
up with the cells. The outbuf ultimately fills up and it kills that
connection. If you run with -l err, it works fine up through 500kB/s and
probably beyond. Down the road we'll want to teach it to recognize when
an outbuf is getting full, and back off.
svn:r50
2002-07-16 03:12:15 +02:00
/* See LICENSE for licensing information */
/* $Id$ */
2004-11-29 23:25:31 +01:00
const char routerlist_c_id [ ] = " $Id$ " ;
Implemented link padding and receiver token buckets
Each socket reads at most 'bandwidth' bytes per second sustained, but
can handle bursts of up to 10*bandwidth bytes.
Cells are now sent out at evenly-spaced intervals, with padding sent
out otherwise. Set Linkpadding=0 in the rc file to send cells as soon
as they're available (and to never send padding cells).
Added license/copyrights statements at the top of most files.
router->min and router->max have been merged into a single 'bandwidth'
value. We should make the routerinfo_t reflect this (want to do that,
Mat?)
As the bandwidth increases, and we want to stop sleeping more and more
frequently to send a single cell, cpu usage goes up. At 128kB/s we're
pretty much calling poll with a timeout of 1ms or even 0ms. The current
code takes a timeout of 0-9ms and makes it 10ms. prepare_for_poll()
handles everything that should have happened in the past, so as long as
our buffers don't get too full in that 10ms, we're ok.
Speaking of too full, if you run three servers at 100kB/s with -l debug,
it spends too much time printing debugging messages to be able to keep
up with the cells. The outbuf ultimately fills up and it kills that
connection. If you run with -l err, it works fine up through 500kB/s and
probably beyond. Down the road we'll want to teach it to recognize when
an outbuf is getting full, and back off.
svn:r50
2002-07-16 03:12:15 +02:00
2004-05-09 18:47:25 +02:00
/**
* \ file routerlist . c
2004-05-10 19:30:51 +02:00
* \ brief Code to
2004-05-05 02:30:43 +02:00
* maintain and access the global list of routerinfos for known
* servers .
2004-05-09 18:47:25 +02:00
* */
2004-05-05 02:30:43 +02:00
2005-06-11 07:31:17 +02:00
# include "or.h"
2002-09-26 14:09:10 +02:00
/****************************************************************************/
2005-09-13 17:32:03 +02:00
/** Global list of a trusted_dir_server_t object for each trusted directory
* server . */
2004-10-12 17:55:20 +02:00
static smartlist_t * trusted_dir_servers = NULL ;
2002-09-24 12:43:57 +02:00
/* static function prototypes */
2005-09-13 17:32:03 +02:00
static routerinfo_t * router_pick_directory_server_impl ( int requireother ,
int fascistfirewall ,
int for_v2_directory ) ;
static trusted_dir_server_t * router_pick_trusteddirserver_impl (
int need_v1_support , int requireother , int fascistfirewall ) ;
2004-10-12 17:55:20 +02:00
static void mark_all_trusteddirservers_up ( void ) ;
2005-06-21 01:04:13 +02:00
static int router_nickname_is_in_list ( routerinfo_t * router , const char * list ) ;
static int router_nickname_matches ( routerinfo_t * router , const char * nickname ) ;
2005-09-18 04:24:42 +02:00
static void routerstatus_list_update_from_networkstatus ( time_t now ) ;
2005-09-30 23:04:52 +02:00
static void local_routerstatus_free ( local_routerstatus_t * rs ) ;
2003-12-09 05:29:52 +01:00
/****************************************************************************/
2003-12-13 02:43:21 +01:00
2004-05-04 20:17:45 +02:00
/****
* Functions to manage and access our list of known routers . ( Note :
* dirservers maintain a separate , independent list of known router
* descriptors . )
2005-06-21 01:04:13 +02:00
* * * */
2004-05-04 20:17:45 +02:00
2005-09-05 01:12:27 +02:00
/** Global list of all of the routers that we know about. */
2004-05-04 20:17:45 +02:00
static routerlist_t * routerlist = NULL ;
2004-02-29 02:31:33 +01:00
2004-05-09 18:47:25 +02:00
extern int has_fetched_directory ; /**< from main.c */
2004-05-04 20:17:45 +02:00
2005-09-05 01:12:27 +02:00
/** Global list of all of the current network_status documents that we know
2005-09-13 17:32:03 +02:00
* about . This list is kept sorted by published_on . */
2005-09-05 01:12:27 +02:00
static smartlist_t * networkstatus_list = NULL ;
2005-09-18 04:24:42 +02:00
/** Global list of routerstatuses_t for each router, known or unknown. */
static smartlist_t * routerstatus_list = NULL ;
2005-09-30 22:04:55 +02:00
/** True iff any member of networkstatus_list has changed since the last time
* we called routerstatus_list_update_from_networkstatus ( ) . */
2005-09-14 23:09:25 +02:00
static int networkstatus_list_has_changed = 0 ;
2005-09-30 22:04:55 +02:00
/** True iff any element of routerstatus_list has changed since the last
* time we called routers_update_all_from_networkstatus ( ) . */
2005-09-18 04:24:42 +02:00
static int routerstatus_list_has_changed = 0 ;
2005-09-05 01:12:27 +02:00
2005-09-13 17:32:03 +02:00
/** Repopulate our list of network_status_t objects from the list cached on
* disk . Return 0 on success , - 1 on failure . */
2005-09-05 01:12:27 +02:00
int
router_reload_networkstatus ( void )
{
char filename [ 512 ] ;
struct stat st ;
2005-09-07 18:42:53 +02:00
smartlist_t * entries , * bad_names ;
2005-09-05 01:12:27 +02:00
char * s ;
tor_assert ( get_options ( ) - > DataDirectory ) ;
if ( ! networkstatus_list )
networkstatus_list = smartlist_create ( ) ;
tor_snprintf ( filename , sizeof ( filename ) , " %s/cached-status " ,
get_options ( ) - > DataDirectory ) ;
entries = tor_listdir ( filename ) ;
2005-09-07 18:42:53 +02:00
bad_names = smartlist_create ( ) ;
2005-09-05 01:12:27 +02:00
SMARTLIST_FOREACH ( entries , const char * , fn , {
2005-09-07 18:42:53 +02:00
char buf [ DIGEST_LEN ] ;
if ( strlen ( fn ) ! = HEX_DIGEST_LEN | |
base16_decode ( buf , sizeof ( buf ) , fn , strlen ( fn ) ) ) {
log_fn ( LOG_INFO ,
" Skipping cached-status file with unexpected name \" %s \" " , fn ) ;
continue ;
}
2005-09-05 01:12:27 +02:00
tor_snprintf ( filename , sizeof ( filename ) , " %s/cached-status/%s " ,
get_options ( ) - > DataDirectory , fn ) ;
s = read_file_to_str ( filename , 0 ) ;
if ( s ) {
stat ( filename , & st ) ;
2005-09-08 22:36:40 +02:00
if ( router_set_networkstatus ( s , st . st_mtime , NS_FROM_CACHE , NULL ) < 0 ) {
2005-09-07 18:42:53 +02:00
log_fn ( LOG_WARN , " Couldn't load networkstatus from \" %s \" " , filename ) ;
}
tor_free ( s ) ;
2005-09-05 01:12:27 +02:00
}
} ) ;
2005-09-15 07:41:30 +02:00
networkstatus_list_clean ( time ( NULL ) ) ;
2005-09-14 23:09:25 +02:00
routers_update_all_from_networkstatus ( ) ;
2005-09-05 01:12:27 +02:00
return 0 ;
}
2005-09-13 23:14:55 +02:00
/* Router descriptor storage.
*
* Routerdescs are stored in a big file , named " cached-routers " . As new
* routerdescs arrive , we append them to a journal file named
2005-09-15 07:19:38 +02:00
* " cached-routers.new " .
2005-09-13 23:14:55 +02:00
*
* From time to time , we replace " cached-routers " with a new file containing
2005-09-15 07:19:38 +02:00
* only the live , non - superseded descriptors , and clear cached - routers . new .
2005-09-13 23:14:55 +02:00
*
* On startup , we read both files .
*/
/** The size of the router log, in bytes. */
static size_t router_journal_len = 0 ;
/** The size of the router store, in bytes. */
2005-09-13 08:21:10 +02:00
static size_t router_store_len = 0 ;
2005-09-13 23:14:55 +02:00
/** Helper: return 1 iff the router log is so big we want to rebuild the
* store . */
2005-09-13 08:21:10 +02:00
static int
router_should_rebuild_store ( void )
{
if ( router_store_len > ( 1 < < 16 ) )
2005-09-13 23:14:55 +02:00
return router_journal_len > router_store_len / 2 ;
2005-09-13 08:21:10 +02:00
else
2005-09-13 23:14:55 +02:00
return router_journal_len > ( 1 < < 15 ) ;
2005-09-13 08:21:10 +02:00
}
2005-09-13 23:14:55 +02:00
/** Add the <b>len</b>-type router descriptor in <b>s</b> to the router
* journal . */
2005-09-15 07:41:30 +02:00
static int
2005-09-13 23:14:55 +02:00
router_append_to_journal ( const char * s , size_t len )
2005-09-13 08:21:10 +02:00
{
or_options_t * options = get_options ( ) ;
size_t fname_len = strlen ( options - > DataDirectory ) + 32 ;
char * fname = tor_malloc ( len ) ;
2005-09-13 23:14:55 +02:00
tor_snprintf ( fname , fname_len , " %s/cached-routers.new " ,
2005-09-13 08:21:10 +02:00
options - > DataDirectory ) ;
if ( ! len )
len = strlen ( s ) ;
if ( append_bytes_to_file ( fname , s , len , 0 ) ) {
log_fn ( LOG_WARN , " Unable to store router descriptor " ) ;
tor_free ( fname ) ;
return - 1 ;
}
tor_free ( fname ) ;
2005-09-13 23:18:00 +02:00
router_journal_len + = len ;
2005-09-13 08:21:10 +02:00
return 0 ;
}
2005-09-13 23:14:55 +02:00
/** If the journal is too long, or if <b>force</b> is true, then atomically
* replace the router store with the routers currently in our routerlist , and
* clear the journal . Return 0 on success , - 1 on failure .
*/
2005-09-15 07:41:30 +02:00
static int
2005-09-13 08:21:10 +02:00
router_rebuild_store ( int force )
{
size_t len = 0 ;
or_options_t * options ;
size_t fname_len ;
smartlist_t * chunk_list = NULL ;
char * fname = NULL ;
int r = - 1 ;
if ( ! force & & ! router_should_rebuild_store ( ) )
return 0 ;
if ( ! routerlist )
return 0 ;
2005-09-15 07:19:38 +02:00
/* Don't save deadweight. */
routerlist_remove_old_routers ( ROUTER_MAX_AGE ) ;
2005-09-13 08:21:10 +02:00
options = get_options ( ) ;
fname_len = strlen ( options - > DataDirectory ) + 32 ;
fname = tor_malloc ( fname_len ) ;
tor_snprintf ( fname , fname_len , " %s/cached-routers " , options - > DataDirectory ) ;
chunk_list = smartlist_create ( ) ;
SMARTLIST_FOREACH ( routerlist - > routers , routerinfo_t * , ri ,
{
sized_chunk_t * c ;
if ( ! ri - > signed_descriptor ) {
log_fn ( LOG_WARN , " Bug! No descriptor stored for router '%s'. " ,
ri - > nickname ) ;
goto done ;
}
c = tor_malloc ( sizeof ( sized_chunk_t ) ) ;
c - > bytes = ri - > signed_descriptor ;
c - > len = ri - > signed_descriptor_len ;
smartlist_add ( chunk_list , c ) ;
} ) ;
if ( write_chunks_to_file ( fname , chunk_list , 0 ) < 0 ) {
log_fn ( LOG_WARN , " Error writing router store to disk. " ) ;
goto done ;
}
2005-09-13 23:14:55 +02:00
tor_snprintf ( fname , fname_len , " %s/cached-routers.new " ,
2005-09-13 08:21:10 +02:00
options - > DataDirectory ) ;
write_str_to_file ( fname , " " , 0 ) ;
r = 0 ;
router_store_len = len ;
2005-09-13 23:18:00 +02:00
router_journal_len = 0 ;
2005-09-13 08:21:10 +02:00
done :
tor_free ( fname ) ;
if ( chunk_list ) {
SMARTLIST_FOREACH ( chunk_list , sized_chunk_t * , c , tor_free ( c ) ) ;
smartlist_free ( chunk_list ) ;
}
return r ;
}
2005-09-15 08:15:31 +02:00
/* Load all cached router descriptors from the store. Return 0 on success and
* - 1 on failure .
*/
2005-09-15 07:19:38 +02:00
int
router_reload_router_list ( void )
{
or_options_t * options = get_options ( ) ;
size_t fname_len = strlen ( options - > DataDirectory ) + 32 ;
char * fname = tor_malloc ( fname_len ) ;
struct stat st ;
int j ;
if ( ! routerlist ) {
routerlist = tor_malloc_zero ( sizeof ( routerlist_t ) ) ;
routerlist - > routers = smartlist_create ( ) ;
}
router_journal_len = router_store_len = 0 ;
for ( j = 0 ; j < 2 ; + + j ) {
char * contents ;
tor_snprintf ( fname , fname_len ,
( j = = 0 ) ? " %s/cached-routers " : " %s/cached-routers.new " ,
options - > DataDirectory ) ;
contents = read_file_to_str ( fname , 0 ) ;
if ( contents ) {
stat ( fname , & st ) ;
if ( j = = 0 )
router_store_len = st . st_size ;
else
router_journal_len = st . st_size ;
router_load_routers_from_string ( contents , 1 , NULL ) ;
tor_free ( contents ) ;
}
}
/* Don't cache expired routers. */
routerlist_remove_old_routers ( ROUTER_MAX_AGE ) ;
if ( router_journal_len ) {
/* Always clear the journal on startup.*/
router_rebuild_store ( 1 ) ;
}
return 0 ;
}
2005-09-13 23:14:55 +02:00
/** Set *<b>outp</b> to a smartlist containing a list of
2004-10-15 21:04:38 +02:00
* trusted_dir_server_t * for all known trusted dirservers . Callers
* must not modify the list or its contents .
*/
2005-06-11 20:52:12 +02:00
void
router_get_trusted_dir_servers ( smartlist_t * * outp )
2004-10-15 21:04:38 +02:00
{
if ( ! trusted_dir_servers )
trusted_dir_servers = smartlist_create ( ) ;
* outp = trusted_dir_servers ;
}
2004-07-20 08:44:16 +02:00
/** Try to find a running dirserver. If there are no running dirservers
2005-06-21 01:04:13 +02:00
* in our routerlist and < b > retry_if_no_servers < / b > is non - zero ,
* set all the authoritative ones as running again , and pick one ;
* if there are then no dirservers at all in our routerlist ,
* reload the routerlist and try one last time . If for_runningrouters is
2004-11-29 22:01:34 +01:00
* true , then only pick a dirserver that can answer runningrouters queries
* ( that is , a trusted dirserver , or one running 0.0 .9 rc5 - cvs or later ) .
2005-06-21 01:04:13 +02:00
* Other args are as in router_pick_directory_server_impl ( ) .
2004-11-29 22:01:34 +01:00
*/
2005-06-11 20:52:12 +02:00
routerinfo_t *
2005-06-21 01:04:13 +02:00
router_pick_directory_server ( int requireother ,
2005-06-11 20:52:12 +02:00
int fascistfirewall ,
2005-09-07 18:42:53 +02:00
int for_v2_directory ,
2005-06-11 20:52:12 +02:00
int retry_if_no_servers )
{
2004-02-26 23:56:36 +01:00
routerinfo_t * choice ;
2004-10-14 03:44:32 +02:00
if ( ! routerlist )
2004-10-14 04:29:03 +02:00
return NULL ;
2004-10-14 03:44:32 +02:00
2005-06-21 01:04:13 +02:00
choice = router_pick_directory_server_impl ( requireother , fascistfirewall ,
2005-09-07 18:42:53 +02:00
for_v2_directory ) ;
2005-01-03 21:51:24 +01:00
if ( choice | | ! retry_if_no_servers )
2004-07-20 08:44:16 +02:00
return choice ;
2004-10-14 03:44:32 +02:00
log_fn ( LOG_INFO , " No reachable router entries for dirservers. Trying them all again. " ) ;
2004-08-18 23:13:58 +02:00
/* mark all authdirservers as up again */
2004-10-12 17:55:20 +02:00
mark_all_trusteddirservers_up ( ) ;
2004-07-20 08:44:16 +02:00
/* try again */
2005-06-21 01:04:13 +02:00
choice = router_pick_directory_server_impl ( requireother , fascistfirewall ,
2005-09-07 18:42:53 +02:00
for_v2_directory ) ;
2004-11-28 10:05:49 +01:00
if ( choice )
2004-07-20 08:44:16 +02:00
return choice ;
2004-10-14 03:44:32 +02:00
log_fn ( LOG_INFO , " Still no %s router entries. Reloading and trying again. " ,
2005-08-08 23:58:48 +02:00
firewall_is_fascist ( ) ? " reachable " : " known " ) ;
2004-07-20 08:44:16 +02:00
has_fetched_directory = 0 ; /* reset it */
2004-11-28 10:05:49 +01:00
if ( router_reload_router_list ( ) ) {
2004-09-08 08:52:33 +02:00
return NULL ;
2004-02-26 23:56:36 +01:00
}
2004-07-20 08:44:16 +02:00
/* give it one last try */
2005-06-21 01:04:13 +02:00
choice = router_pick_directory_server_impl ( requireother , 0 ,
2005-09-07 18:42:53 +02:00
for_v2_directory ) ;
2004-02-26 23:56:36 +01:00
return choice ;
}
2005-09-08 08:22:44 +02:00
trusted_dir_server_t *
router_get_trusteddirserver_by_digest ( const char * digest )
{
if ( ! trusted_dir_servers )
return NULL ;
SMARTLIST_FOREACH ( trusted_dir_servers , trusted_dir_server_t * , ds ,
{
if ( ! memcmp ( ds - > digest , digest , DIGEST_LEN ) )
return ds ;
} ) ;
return NULL ;
}
2005-06-21 01:04:13 +02:00
/** Try to find a running trusted dirserver. If there are no running
* trusted dirservers and < b > retry_if_no_servers < / b > is non - zero ,
* set them all as running again , and try again .
* Other args are as in router_pick_trusteddirserver_impl ( ) .
*/
2005-06-11 20:52:12 +02:00
trusted_dir_server_t *
2005-09-07 18:42:53 +02:00
router_pick_trusteddirserver ( int need_v1_support ,
int requireother ,
2005-06-11 20:52:12 +02:00
int fascistfirewall ,
int retry_if_no_servers )
{
2004-10-12 17:55:20 +02:00
trusted_dir_server_t * choice ;
2005-09-07 18:42:53 +02:00
choice = router_pick_trusteddirserver_impl ( need_v1_support ,
requireother , fascistfirewall ) ;
2005-01-03 21:51:24 +01:00
if ( choice | | ! retry_if_no_servers )
2004-10-12 17:55:20 +02:00
return choice ;
log_fn ( LOG_INFO , " No trusted dirservers are reachable. Trying them all again. " ) ;
mark_all_trusteddirservers_up ( ) ;
2005-09-07 18:42:53 +02:00
return router_pick_trusteddirserver_impl ( need_v1_support ,
requireother , fascistfirewall ) ;
2004-10-12 17:55:20 +02:00
}
2005-06-21 01:04:13 +02:00
/** Pick a random running verified directory server/mirror from our
* routerlist .
* If < b > fascistfirewall < / b > and we ' re not using a proxy ,
* make sure the port we pick is allowed by options - \ > firewallports .
2005-09-13 17:32:03 +02:00
* If < b > requireother < / b > , it cannot be us . If < b > for_v2_directory < / b > ,
* choose a directory server new enough to support the v2 directory
* functionality .
2004-07-20 08:44:16 +02:00
*/
static routerinfo_t *
2005-06-21 01:04:13 +02:00
router_pick_directory_server_impl ( int requireother , int fascistfirewall ,
2005-09-07 18:42:53 +02:00
int for_v2_directory )
2004-07-20 08:44:16 +02:00
{
2005-09-13 17:32:03 +02:00
routerinfo_t * result ;
2003-12-13 02:43:21 +01:00
smartlist_t * sl ;
2003-12-03 11:39:27 +01:00
2004-11-28 10:05:49 +01:00
if ( ! routerlist )
2002-09-26 14:09:10 +02:00
return NULL ;
2004-11-28 10:05:49 +01:00
if ( get_options ( ) - > HttpProxy )
2004-10-15 06:57:36 +02:00
fascistfirewall = 0 ;
2004-05-04 20:17:45 +02:00
/* Find all the running dirservers we know about. */
2004-03-31 00:59:00 +02:00
sl = smartlist_create ( ) ;
2005-09-13 17:32:03 +02:00
SMARTLIST_FOREACH ( routerlist - > routers , routerinfo_t * , router ,
{
2005-02-10 08:00:23 +01:00
if ( ! router - > is_running | | ! router - > dir_port | | ! router - > is_verified )
2004-07-20 08:44:16 +02:00
continue ;
2005-06-21 01:04:13 +02:00
if ( requireother & & router_is_me ( router ) )
2004-07-20 08:44:16 +02:00
continue ;
2004-11-28 10:05:49 +01:00
if ( fascistfirewall ) {
2005-08-08 23:58:48 +02:00
if ( ! fascist_firewall_allows_address ( router - > addr , router - > dir_port ) )
2004-08-16 22:47:00 +02:00
continue ;
}
2005-09-14 21:12:35 +02:00
/* Before 0.1.1.6-alpha, only trusted dirservers served status info.
* Before 0.1 .1 .7 - alpha , retrieving nonexistent server IDs could bork
* the directory server .
*/
2005-09-07 18:42:53 +02:00
if ( for_v2_directory & &
2005-09-14 21:12:35 +02:00
! ( tor_version_as_new_as ( router - > platform , " 0.1.1.7-alpha " ) | |
2004-11-29 22:01:34 +01:00
router_digest_is_trusted_dir ( router - > identity_digest ) ) )
continue ;
2004-07-20 08:44:16 +02:00
smartlist_add ( sl , router ) ;
2005-09-13 17:32:03 +02:00
} ) ;
2002-09-26 14:09:10 +02:00
2005-09-13 17:32:03 +02:00
result = smartlist_choose ( sl ) ;
2003-12-13 02:43:21 +01:00
smartlist_free ( sl ) ;
2005-09-13 17:32:03 +02:00
return result ;
2004-07-20 08:44:16 +02:00
}
2003-11-10 09:06:55 +01:00
2005-06-21 01:04:13 +02:00
/** Choose randomly from among the trusted dirservers that are up.
* If < b > fascistfirewall < / b > and we ' re not using a proxy ,
* make sure the port we pick is allowed by options - \ > firewallports .
2005-09-13 17:32:03 +02:00
* If < b > requireother < / b > , it cannot be us . If < b > need_v1_support < / b > , choose
* a trusted authority for the v1 directory system .
2005-06-21 01:04:13 +02:00
*/
2004-10-12 17:55:20 +02:00
static trusted_dir_server_t *
2005-09-07 18:42:53 +02:00
router_pick_trusteddirserver_impl ( int need_v1_support ,
int requireother , int fascistfirewall )
2004-10-12 17:55:20 +02:00
{
smartlist_t * sl ;
routerinfo_t * me ;
trusted_dir_server_t * ds ;
sl = smartlist_create ( ) ;
me = router_get_my_routerinfo ( ) ;
2004-07-20 08:44:16 +02:00
2004-10-14 04:29:03 +02:00
if ( ! trusted_dir_servers )
return NULL ;
2004-11-28 10:05:49 +01:00
if ( get_options ( ) - > HttpProxy )
2004-10-15 06:57:36 +02:00
fascistfirewall = 0 ;
2004-10-12 17:55:20 +02:00
SMARTLIST_FOREACH ( trusted_dir_servers , trusted_dir_server_t * , d ,
{
if ( ! d - > is_running ) continue ;
2005-09-07 18:42:53 +02:00
if ( need_v1_support & & ! d - > supports_v1_protocol )
continue ;
2004-10-12 17:55:20 +02:00
if ( requireother & & me & &
! memcmp ( me - > identity_digest , d - > digest , DIGEST_LEN ) )
continue ;
if ( fascistfirewall ) {
2005-08-08 23:58:48 +02:00
if ( ! fascist_firewall_allows_address ( d - > addr , d - > dir_port ) )
2004-10-12 17:55:20 +02:00
continue ;
}
smartlist_add ( sl , d ) ;
} ) ;
2004-05-04 20:17:45 +02:00
2004-10-12 17:55:20 +02:00
ds = smartlist_choose ( sl ) ;
smartlist_free ( sl ) ;
return ds ;
}
2005-06-21 01:04:13 +02:00
/** Go through and mark the authoritative dirservers as up. */
2005-06-11 20:52:12 +02:00
static void
mark_all_trusteddirservers_up ( void )
{
2004-11-28 10:05:49 +01:00
if ( routerlist ) {
2004-10-12 17:55:20 +02:00
SMARTLIST_FOREACH ( routerlist - > routers , routerinfo_t * , router ,
2005-07-15 20:56:59 +02:00
if ( router_digest_is_trusted_dir ( router - > identity_digest ) & &
router - > dir_port > 0 ) {
2004-10-19 20:19:59 +02:00
router - > is_running = 1 ;
} ) ;
2004-10-12 17:55:20 +02:00
}
if ( trusted_dir_servers ) {
SMARTLIST_FOREACH ( trusted_dir_servers , trusted_dir_server_t * , dir ,
2005-09-14 23:09:25 +02:00
{
dir - > is_running = 1 ;
dir - > n_networkstatus_failures = 0 ;
} ) ;
2003-12-03 11:39:27 +01:00
}
2004-07-12 22:39:40 +02:00
}
2005-05-17 19:01:36 +02:00
/** Return 0 if \\exists an authoritative dirserver that's currently
2004-07-12 22:39:40 +02:00
* thought to be running , else return 1.
*/
2005-06-11 20:52:12 +02:00
int
all_trusted_directory_servers_down ( void )
{
2004-10-12 17:55:20 +02:00
if ( ! trusted_dir_servers )
return 1 ;
SMARTLIST_FOREACH ( trusted_dir_servers , trusted_dir_server_t * , dir ,
if ( dir - > is_running ) return 0 ) ;
2004-07-12 22:39:40 +02:00
return 1 ;
2002-09-26 14:09:10 +02:00
}
2004-10-15 03:58:11 +02:00
/** Add all the family of <b>router</b> to the smartlist <b>sl</b>.
2005-06-21 01:04:13 +02:00
* This is used to make sure we don ' t pick siblings in a single path .
2004-09-10 23:40:29 +02:00
*/
2005-06-11 20:52:12 +02:00
void
routerlist_add_family ( smartlist_t * sl , routerinfo_t * router )
{
2004-10-15 03:58:11 +02:00
routerinfo_t * r ;
2005-07-22 23:12:10 +02:00
config_line_t * cl ;
2004-09-10 23:40:29 +02:00
2004-10-15 03:58:11 +02:00
if ( ! router - > declared_family )
return ;
2004-10-15 22:52:09 +02:00
2004-10-15 05:55:53 +02:00
/* Add every r such that router declares familyness with r, and r
* declares familyhood with router . */
2004-10-15 03:58:11 +02:00
SMARTLIST_FOREACH ( router - > declared_family , const char * , n ,
{
if ( ! ( r = router_get_by_nickname ( n ) ) )
continue ;
if ( ! r - > declared_family )
continue ;
SMARTLIST_FOREACH ( r - > declared_family , const char * , n2 ,
{
if ( router_nickname_matches ( router , n2 ) )
smartlist_add ( sl , r ) ;
} ) ;
} ) ;
2004-10-15 22:52:09 +02:00
2005-06-21 01:04:13 +02:00
/* If the user declared any families locally, honor those too. */
2004-11-06 06:18:11 +01:00
for ( cl = get_options ( ) - > NodeFamilies ; cl ; cl = cl - > next ) {
2004-10-15 22:52:09 +02:00
if ( router_nickname_is_in_list ( router , cl - > value ) ) {
add_nickname_list_to_smartlist ( sl , cl - > value , 0 ) ;
}
}
2004-09-10 23:40:29 +02:00
}
2005-06-21 01:04:13 +02:00
/** List of strings for nicknames we've already warned about and that are
* still unknown / unavailable . */
2005-04-03 07:53:34 +02:00
static smartlist_t * warned_nicknames = NULL ;
2004-05-09 18:47:25 +02:00
/** Given a comma-and-whitespace separated list of nicknames, see which
2004-05-10 06:34:48 +02:00
* nicknames in < b > list < / b > name routers in our routerlist that are
* currently running . Add the routerinfos for those routers to < b > sl < / b > .
2004-05-04 20:17:45 +02:00
*/
2004-08-18 13:20:15 +02:00
void
add_nickname_list_to_smartlist ( smartlist_t * sl , const char * list , int warn_if_down )
{
2004-04-03 00:23:15 +02:00
routerinfo_t * router ;
2004-09-02 20:39:59 +02:00
smartlist_t * nickname_list ;
2004-04-03 00:23:15 +02:00
2004-11-28 10:05:49 +01:00
if ( ! list )
2004-11-03 11:08:44 +01:00
return ; /* nothing to do */
2004-04-25 22:37:37 +02:00
tor_assert ( sl ) ;
2004-04-03 01:38:26 +02:00
2004-09-02 20:39:59 +02:00
nickname_list = smartlist_create ( ) ;
2005-04-03 07:53:34 +02:00
if ( ! warned_nicknames )
warned_nicknames = smartlist_create ( ) ;
2004-04-03 00:23:15 +02:00
2004-09-02 20:39:59 +02:00
smartlist_split_string ( nickname_list , list , " , " ,
SPLIT_SKIP_SPACE | SPLIT_IGNORE_BLANK , 0 ) ;
SMARTLIST_FOREACH ( nickname_list , const char * , nick , {
2005-04-03 07:53:34 +02:00
int warned ;
2005-01-03 18:53:20 +01:00
if ( ! is_legal_nickname_or_hexdigest ( nick ) ) {
log_fn ( LOG_WARN , " Nickname %s is misformed; skipping " , nick ) ;
2004-07-22 23:36:03 +02:00
continue ;
}
2004-04-03 00:23:15 +02:00
router = router_get_by_nickname ( nick ) ;
2005-04-03 07:53:34 +02:00
warned = smartlist_string_isin ( warned_nicknames , nick ) ;
2004-04-03 00:23:15 +02:00
if ( router ) {
2005-04-03 07:53:34 +02:00
if ( router - > is_running ) {
2004-04-03 00:23:15 +02:00
smartlist_add ( sl , router ) ;
2005-04-03 07:53:34 +02:00
if ( warned )
smartlist_string_remove ( warned_nicknames , nick ) ;
} else {
if ( ! warned ) {
log_fn ( warn_if_down ? LOG_WARN : LOG_DEBUG ,
" Nickname list includes '%s' which is known but down. " , nick ) ;
smartlist_add ( warned_nicknames , tor_strdup ( nick ) ) ;
}
}
} else {
if ( ! warned ) {
log_fn ( has_fetched_directory ? LOG_WARN : LOG_INFO ,
" Nickname list includes '%s' which isn't a known router. " , nick ) ;
smartlist_add ( warned_nicknames , tor_strdup ( nick ) ) ;
}
}
2004-09-02 20:39:59 +02:00
} ) ;
SMARTLIST_FOREACH ( nickname_list , char * , nick , tor_free ( nick ) ) ;
smartlist_free ( nickname_list ) ;
2004-04-03 00:23:15 +02:00
}
2004-10-15 22:52:09 +02:00
/** Return 1 iff any member of the comma-separated list <b>list</b> is an
* acceptable nickname or hexdigest for < b > router < / b > . Else return 0.
*/
2005-06-21 01:04:13 +02:00
static int
2004-10-15 22:52:09 +02:00
router_nickname_is_in_list ( routerinfo_t * router , const char * list )
{
smartlist_t * nickname_list ;
int v = 0 ;
2004-11-28 10:05:49 +01:00
if ( ! list )
2004-11-03 11:08:44 +01:00
return 0 ; /* definitely not */
2004-10-15 22:52:09 +02:00
tor_assert ( router ) ;
nickname_list = smartlist_create ( ) ;
smartlist_split_string ( nickname_list , list , " , " ,
SPLIT_SKIP_SPACE | SPLIT_IGNORE_BLANK , 0 ) ;
2004-10-16 10:39:56 +02:00
SMARTLIST_FOREACH ( nickname_list , const char * , cp ,
2004-10-15 22:52:09 +02:00
if ( router_nickname_matches ( router , cp ) ) { v = 1 ; break ; } ) ;
2004-10-16 10:39:56 +02:00
SMARTLIST_FOREACH ( nickname_list , char * , cp , tor_free ( cp ) ) ;
smartlist_free ( nickname_list ) ;
2004-10-15 22:52:09 +02:00
return v ;
}
2004-05-10 06:34:48 +02:00
/** Add every router from our routerlist that is currently running to
* < b > sl < / b > .
2004-05-04 20:17:45 +02:00
*/
2004-08-17 08:27:32 +02:00
static void
2004-08-20 23:34:36 +02:00
router_add_running_routers_to_smartlist ( smartlist_t * sl , int allow_unverified ,
2005-01-12 05:58:23 +01:00
int need_uptime , int need_capacity )
2004-08-17 08:27:32 +02:00
{
2004-11-28 10:05:49 +01:00
if ( ! routerlist )
2003-12-13 08:01:46 +01:00
return ;
2003-12-03 11:28:51 +01:00
2005-09-13 17:32:03 +02:00
SMARTLIST_FOREACH ( routerlist - > routers , routerinfo_t * , router ,
{
2004-11-28 10:05:49 +01:00
if ( router - > is_running & &
2004-11-28 12:39:53 +01:00
( router - > is_verified | |
( allow_unverified & &
2005-01-12 05:58:23 +01:00
! router_is_unreliable ( router , need_uptime , need_capacity ) ) ) ) {
2004-08-20 23:34:36 +02:00
/* If it's running, and either it's verified or we're ok picking
* unverified routers and this one is suitable .
*/
2004-08-18 11:07:11 +02:00
smartlist_add ( sl , router ) ;
2004-08-08 12:32:36 +02:00
}
2005-09-13 17:32:03 +02:00
} ) ;
2003-12-03 11:28:51 +01:00
}
2005-06-21 01:04:13 +02:00
/** Look through the routerlist until we find a router that has my key.
Return it . */
2004-08-18 12:32:50 +02:00
routerinfo_t *
2005-06-11 20:52:12 +02:00
routerlist_find_my_routerinfo ( void )
{
2004-11-28 10:05:49 +01:00
if ( ! routerlist )
2004-08-18 12:32:50 +02:00
return NULL ;
2005-09-13 17:32:03 +02:00
SMARTLIST_FOREACH ( routerlist - > routers , routerinfo_t * , router ,
{
2004-11-28 10:05:49 +01:00
if ( router_is_me ( router ) )
2004-08-18 12:32:50 +02:00
return router ;
2005-09-13 17:32:03 +02:00
} ) ;
2004-08-18 12:32:50 +02:00
return NULL ;
}
2005-08-15 05:25:40 +02:00
/** Find a router that's up, that has this IP address, and
* that allows exit to this address : port , or return NULL if there
* isn ' t a good one .
*/
routerinfo_t *
2005-09-13 17:32:03 +02:00
router_find_exact_exit_enclave ( const char * address , uint16_t port )
{
2005-08-15 05:25:40 +02:00
uint32_t addr ;
struct in_addr in ;
if ( ! tor_inet_aton ( address , & in ) )
return NULL ; /* it's not an IP already */
addr = ntohl ( in . s_addr ) ;
2005-09-13 17:32:03 +02:00
SMARTLIST_FOREACH ( routerlist - > routers , routerinfo_t * , router ,
{
2005-08-15 05:25:40 +02:00
if ( router - > is_running & &
router - > addr = = addr & &
router_compare_addr_to_addr_policy ( addr , port , router - > exit_policy ) = =
ADDR_POLICY_ACCEPTED )
return router ;
2005-09-13 17:32:03 +02:00
} ) ;
2005-08-15 05:25:40 +02:00
return NULL ;
}
2005-06-21 01:04:13 +02:00
/** Return 1 if <b>router</b> is not suitable for these parameters, else 0.
* If < b > need_uptime < / b > is non - zero , we require a minimum uptime .
* If < b > need_capacity < / b > is non - zero , we require a minimum advertised
* bandwidth .
*/
2004-08-20 23:34:36 +02:00
int
2005-01-12 05:58:23 +01:00
router_is_unreliable ( routerinfo_t * router , int need_uptime , int need_capacity )
2004-08-20 23:34:36 +02:00
{
2004-11-28 10:05:49 +01:00
if ( need_uptime & & router - > uptime < ROUTER_REQUIRED_MIN_UPTIME )
2004-08-20 23:34:36 +02:00
return 1 ;
2005-01-12 05:58:23 +01:00
if ( need_capacity & & router - > bandwidthcapacity < ROUTER_REQUIRED_MIN_BANDWIDTH )
2004-08-20 23:34:36 +02:00
return 1 ;
return 0 ;
}
2004-08-15 10:15:12 +02:00
2005-06-21 01:04:13 +02:00
/** Remove from routerlist <b>sl</b> all routers who have a low uptime. */
2004-08-15 10:15:12 +02:00
static void
routerlist_sl_remove_unreliable_routers ( smartlist_t * sl )
{
int i ;
routerinfo_t * router ;
for ( i = 0 ; i < smartlist_len ( sl ) ; + + i ) {
router = smartlist_get ( sl , i ) ;
2005-01-12 05:58:23 +01:00
if ( router_is_unreliable ( router , 1 , 0 ) ) {
2005-08-12 02:34:50 +02:00
// log(LOG_DEBUG, "Router '%s' has insufficient uptime; deleting.",
// router->nickname);
2004-08-15 10:15:12 +02:00
smartlist_del ( sl , i - - ) ;
}
}
}
2005-06-21 01:04:13 +02:00
# define MAX_BELIEVABLE_BANDWIDTH 2000000 /* 2 MB/sec */
/** Choose a random element of router list <b>sl</b>, weighted by
* the advertised bandwidth of each router .
*/
2004-08-18 08:10:12 +02:00
routerinfo_t *
2004-08-15 10:15:12 +02:00
routerlist_sl_choose_by_bandwidth ( smartlist_t * sl )
{
int i ;
routerinfo_t * router ;
smartlist_t * bandwidths ;
uint32_t this_bw , tmp , total_bw = 0 , rand_bw ;
uint32_t * p ;
2005-06-21 01:04:13 +02:00
/* First count the total bandwidth weight, and make a smartlist
* of each value . */
2004-08-15 10:15:12 +02:00
bandwidths = smartlist_create ( ) ;
for ( i = 0 ; i < smartlist_len ( sl ) ; + + i ) {
router = smartlist_get ( sl , i ) ;
2004-10-17 23:51:20 +02:00
this_bw = ( router - > bandwidthcapacity < router - > bandwidthrate ) ?
router - > bandwidthcapacity : router - > bandwidthrate ;
2005-06-21 01:04:13 +02:00
/* if they claim something huge, don't believe it */
if ( this_bw > MAX_BELIEVABLE_BANDWIDTH )
this_bw = MAX_BELIEVABLE_BANDWIDTH ;
2004-08-15 10:15:12 +02:00
p = tor_malloc ( sizeof ( uint32_t ) ) ;
* p = this_bw ;
smartlist_add ( bandwidths , p ) ;
total_bw + = this_bw ;
}
2004-12-07 09:51:10 +01:00
if ( ! total_bw ) {
SMARTLIST_FOREACH ( bandwidths , uint32_t * , p , tor_free ( p ) ) ;
smartlist_free ( bandwidths ) ;
2004-11-20 13:41:05 +01:00
return smartlist_choose ( sl ) ;
2004-12-07 09:51:10 +01:00
}
2005-06-21 01:04:13 +02:00
/* Second, choose a random value from the bandwidth weights. */
2004-08-15 10:15:12 +02:00
rand_bw = crypto_pseudo_rand_int ( total_bw ) ;
2005-06-21 01:04:13 +02:00
/* Last, count through sl until we get to the element we picked */
2004-08-15 10:15:12 +02:00
tmp = 0 ;
2004-11-28 10:05:49 +01:00
for ( i = 0 ; ; i + + ) {
2004-08-15 10:15:12 +02:00
tor_assert ( i < smartlist_len ( sl ) ) ;
p = smartlist_get ( bandwidths , i ) ;
tmp + = * p ;
2004-11-28 10:05:49 +01:00
if ( tmp > = rand_bw )
2004-08-15 10:15:12 +02:00
break ;
}
SMARTLIST_FOREACH ( bandwidths , uint32_t * , p , tor_free ( p ) ) ;
smartlist_free ( bandwidths ) ;
2005-06-21 01:04:13 +02:00
return ( routerinfo_t * ) smartlist_get ( sl , i ) ;
2004-08-15 10:15:12 +02:00
}
2004-05-20 21:12:28 +02:00
/** Return a random running router from the routerlist. If any node
2004-08-15 22:14:44 +02:00
* named in < b > preferred < / b > is available , pick one of those . Never
* pick a node named in < b > excluded < / b > , or whose routerinfo is in
* < b > excludedsmartlist < / b > , even if they are the only nodes
* available . If < b > strict < / b > is true , never pick any node besides
* those in < b > preferred < / b > .
2005-06-21 01:04:13 +02:00
* If < b > need_uptime < / b > is non - zero , don ' t return a router with less
* than a minimum uptime .
* If < b > need_capacity < / b > is non - zero , weight your choice by the
* advertised capacity of each router .
2004-04-03 00:30:39 +02:00
*/
2005-06-11 20:52:12 +02:00
routerinfo_t *
router_choose_random_node ( const char * preferred ,
const char * excluded ,
smartlist_t * excludedsmartlist ,
int need_uptime , int need_capacity ,
int allow_unverified , int strict )
2004-04-03 00:23:15 +02:00
{
smartlist_t * sl , * excludednodes ;
routerinfo_t * choice ;
excludednodes = smartlist_create ( ) ;
2004-08-18 13:20:15 +02:00
add_nickname_list_to_smartlist ( excludednodes , excluded , 0 ) ;
2004-04-03 00:23:15 +02:00
2005-04-06 08:17:35 +02:00
/* Try the preferred nodes first. Ignore need_uptime and need_capacity,
* since the user explicitly asked for these nodes . */
2004-04-03 00:23:15 +02:00
sl = smartlist_create ( ) ;
2004-08-18 13:20:15 +02:00
add_nickname_list_to_smartlist ( sl , preferred , 1 ) ;
2004-04-03 00:23:15 +02:00
smartlist_subtract ( sl , excludednodes ) ;
2004-11-28 10:05:49 +01:00
if ( excludedsmartlist )
2004-04-03 00:30:39 +02:00
smartlist_subtract ( sl , excludedsmartlist ) ;
2005-04-06 08:17:35 +02:00
choice = smartlist_choose ( sl ) ;
2004-04-03 00:23:15 +02:00
smartlist_free ( sl ) ;
2004-11-28 10:05:49 +01:00
if ( ! choice & & ! strict ) {
2005-04-06 08:17:35 +02:00
/* Then give up on our preferred choices: any node
* will do that has the required attributes . */
2004-04-03 00:23:15 +02:00
sl = smartlist_create ( ) ;
2004-08-20 23:34:36 +02:00
router_add_running_routers_to_smartlist ( sl , allow_unverified ,
2005-01-12 05:58:23 +01:00
need_uptime , need_capacity ) ;
2004-04-03 00:23:15 +02:00
smartlist_subtract ( sl , excludednodes ) ;
2004-11-28 10:05:49 +01:00
if ( excludedsmartlist )
2004-04-03 00:30:39 +02:00
smartlist_subtract ( sl , excludedsmartlist ) ;
2005-01-12 05:58:23 +01:00
if ( need_uptime )
2004-08-15 10:15:12 +02:00
routerlist_sl_remove_unreliable_routers ( sl ) ;
2005-01-12 05:58:23 +01:00
if ( need_capacity )
2004-08-15 10:15:12 +02:00
choice = routerlist_sl_choose_by_bandwidth ( sl ) ;
2004-08-18 09:53:43 +02:00
else
choice = smartlist_choose ( sl ) ;
2004-04-03 00:23:15 +02:00
smartlist_free ( sl ) ;
}
smartlist_free ( excludednodes ) ;
2004-11-28 10:05:49 +01:00
if ( ! choice )
2004-04-03 00:23:15 +02:00
log_fn ( LOG_WARN , " No available nodes when trying to choose node. Failing. " ) ;
return choice ;
}
2004-07-17 00:23:18 +02:00
/** Return true iff the digest of <b>router</b>'s identity key,
* encoded in hexadecimal , matches < b > hexdigest < / b > ( which is
* optionally prefixed with a single dollar sign ) . Return false if
* < b > hexdigest < / b > is malformed , or it doesn ' t match . */
2005-06-11 20:52:12 +02:00
static INLINE int
router_hex_digest_matches ( routerinfo_t * router , const char * hexdigest )
2004-07-03 01:40:03 +02:00
{
char digest [ DIGEST_LEN ] ;
tor_assert ( hexdigest ) ;
if ( hexdigest [ 0 ] = = ' $ ' )
+ + hexdigest ;
2004-07-17 00:23:18 +02:00
if ( strlen ( hexdigest ) ! = HEX_DIGEST_LEN | |
base16_decode ( digest , DIGEST_LEN , hexdigest , HEX_DIGEST_LEN ) < 0 )
2004-07-03 01:40:03 +02:00
return 0 ;
2005-06-21 01:04:13 +02:00
return ( ! memcmp ( digest , router - > identity_digest , DIGEST_LEN ) ) ;
2004-07-03 01:40:03 +02:00
}
2005-06-21 01:04:13 +02:00
/** Return true if <b>router</b>'s nickname matches <b>nickname</b>
2004-07-17 00:23:18 +02:00
* ( case - insensitive ) , or if < b > router ' s < / b > identity key digest
* matches a hexadecimal value stored in < b > nickname < / b > . Return
2005-06-21 01:04:13 +02:00
* false otherwise . */
static int
2005-06-11 20:52:12 +02:00
router_nickname_matches ( routerinfo_t * router , const char * nickname )
2004-07-03 01:40:03 +02:00
{
if ( nickname [ 0 ] ! = ' $ ' & & ! strcasecmp ( router - > nickname , nickname ) )
return 1 ;
2005-06-21 01:04:13 +02:00
return router_hex_digest_matches ( router , nickname ) ;
2004-07-03 01:40:03 +02:00
}
2004-07-01 03:16:59 +02:00
/** Return the router in our routerlist whose (case-insensitive)
* nickname or ( case - sensitive ) hexadecimal key digest is
* < b > nickname < / b > . Return NULL if no such router is known .
2004-05-04 20:17:45 +02:00
*/
2005-06-11 20:52:12 +02:00
routerinfo_t *
router_get_by_nickname ( const char * nickname )
2003-09-25 07:17:11 +02:00
{
2005-09-13 17:32:03 +02:00
int maybedigest ;
2004-07-01 03:16:59 +02:00
char digest [ DIGEST_LEN ] ;
2003-09-25 07:17:11 +02:00
2004-05-12 21:49:48 +02:00
tor_assert ( nickname ) ;
2004-06-02 22:00:57 +02:00
if ( ! routerlist )
return NULL ;
2004-07-03 01:40:03 +02:00
if ( nickname [ 0 ] = = ' $ ' )
return router_get_by_hexdigest ( nickname ) ;
2005-02-27 08:23:42 +01:00
if ( server_mode ( get_options ( ) ) & &
! strcasecmp ( nickname , get_options ( ) - > Nickname ) )
return router_get_my_routerinfo ( ) ;
2004-07-03 01:40:03 +02:00
2004-07-01 03:16:59 +02:00
maybedigest = ( strlen ( nickname ) = = HEX_DIGEST_LEN ) & &
( base16_decode ( digest , DIGEST_LEN , nickname , HEX_DIGEST_LEN ) = = 0 ) ;
2005-09-13 17:32:03 +02:00
SMARTLIST_FOREACH ( routerlist - > routers , routerinfo_t * , router ,
{
2005-09-16 18:41:45 +02:00
/* XXXX011 NM Should this restrict by Named rouers, or warn on
2005-09-15 01:42:06 +02:00
* non - named routers , or something ? */
2004-07-01 03:16:59 +02:00
if ( 0 = = strcasecmp ( router - > nickname , nickname ) | |
( maybedigest & & 0 = = memcmp ( digest , router - > identity_digest ,
DIGEST_LEN ) ) )
return router ;
2005-09-13 17:32:03 +02:00
} ) ;
2004-07-01 03:16:59 +02:00
return NULL ;
}
2004-07-20 22:09:59 +02:00
/** Return true iff <b>digest</b> is the digest of the identity key of
* a trusted directory . */
2005-06-11 20:52:12 +02:00
int
router_digest_is_trusted_dir ( const char * digest )
{
2004-10-12 17:55:20 +02:00
if ( ! trusted_dir_servers )
2004-07-20 22:09:59 +02:00
return 0 ;
2004-10-12 17:55:20 +02:00
SMARTLIST_FOREACH ( trusted_dir_servers , trusted_dir_server_t * , ent ,
if ( ! memcmp ( digest , ent - > digest , DIGEST_LEN ) ) return 1 ) ;
2004-07-20 22:09:59 +02:00
return 0 ;
}
2004-07-01 03:16:59 +02:00
/** Return the router in our routerlist whose hexadecimal key digest
* is < b > hexdigest < / b > . Return NULL if no such router is known . */
2005-06-11 20:52:12 +02:00
routerinfo_t *
router_get_by_hexdigest ( const char * hexdigest )
{
2004-07-01 03:16:59 +02:00
char digest [ DIGEST_LEN ] ;
tor_assert ( hexdigest ) ;
if ( ! routerlist )
return NULL ;
2004-07-03 01:40:03 +02:00
if ( hexdigest [ 0 ] = = ' $ ' )
+ + hexdigest ;
2004-07-01 03:16:59 +02:00
if ( strlen ( hexdigest ) ! = HEX_DIGEST_LEN | |
base16_decode ( digest , DIGEST_LEN , hexdigest , HEX_DIGEST_LEN ) < 0 )
return NULL ;
return router_get_by_digest ( digest ) ;
}
/** Return the router in our routerlist whose 20-byte key digest
2005-03-22 01:42:38 +01:00
* is < b > digest < / b > . Return NULL if no such router is known . */
2005-06-11 20:52:12 +02:00
routerinfo_t *
router_get_by_digest ( const char * digest )
{
2004-07-01 03:16:59 +02:00
tor_assert ( digest ) ;
2005-06-21 01:04:13 +02:00
2005-02-27 10:47:01 +01:00
if ( ! routerlist ) return NULL ;
2003-09-25 07:17:11 +02:00
2005-09-13 17:32:03 +02:00
SMARTLIST_FOREACH ( routerlist - > routers , routerinfo_t * , router ,
{
2004-07-01 03:16:59 +02:00
if ( 0 = = memcmp ( router - > identity_digest , digest , DIGEST_LEN ) )
2003-09-25 07:17:11 +02:00
return router ;
2005-09-13 17:32:03 +02:00
} ) ;
2004-04-06 00:22:42 +02:00
2003-09-25 07:17:11 +02:00
return NULL ;
}
2003-09-11 22:32:15 +02:00
2004-05-10 06:34:48 +02:00
/** Set *<b>prouterlist</b> to the current list of all known routers. */
2005-06-11 20:52:12 +02:00
void
router_get_routerlist ( routerlist_t * * prouterlist )
{
2003-12-05 10:51:49 +01:00
* prouterlist = routerlist ;
2002-09-26 14:09:10 +02:00
}
2004-05-10 06:34:48 +02:00
/** Free all storage held by <b>router</b>. */
2005-06-11 20:52:12 +02:00
void
routerinfo_free ( routerinfo_t * router )
2002-06-27 00:45:49 +02:00
{
2003-05-09 04:00:33 +02:00
if ( ! router )
2002-06-27 00:45:49 +02:00
return ;
2005-02-25 21:46:13 +01:00
tor_free ( router - > signed_descriptor ) ;
2003-10-21 11:48:17 +02:00
tor_free ( router - > address ) ;
tor_free ( router - > nickname ) ;
2004-04-07 23:36:03 +02:00
tor_free ( router - > platform ) ;
2005-05-06 10:53:23 +02:00
tor_free ( router - > contact_info ) ;
2003-09-25 07:17:11 +02:00
if ( router - > onion_pkey )
crypto_free_pk_env ( router - > onion_pkey ) ;
if ( router - > identity_pkey )
crypto_free_pk_env ( router - > identity_pkey ) ;
2004-10-15 03:58:11 +02:00
if ( router - > declared_family ) {
SMARTLIST_FOREACH ( router - > declared_family , char * , s , tor_free ( s ) ) ;
smartlist_free ( router - > declared_family ) ;
}
2004-11-12 20:39:13 +01:00
addr_policy_free ( router - > exit_policy ) ;
2004-09-29 08:52:36 +02:00
tor_free ( router ) ;
2002-09-24 12:43:57 +02:00
}
2004-05-10 06:34:48 +02:00
/** Allocate a fresh copy of <b>router</b> */
2005-06-11 20:52:12 +02:00
routerinfo_t *
routerinfo_copy ( const routerinfo_t * router )
2004-04-08 00:18:57 +02:00
{
routerinfo_t * r ;
2004-12-04 02:14:36 +01:00
addr_policy_t * * e , * tmp ;
2004-04-08 00:18:57 +02:00
r = tor_malloc ( sizeof ( routerinfo_t ) ) ;
memcpy ( r , router , sizeof ( routerinfo_t ) ) ;
r - > address = tor_strdup ( r - > address ) ;
r - > nickname = tor_strdup ( r - > nickname ) ;
r - > platform = tor_strdup ( r - > platform ) ;
2005-02-28 04:37:27 +01:00
if ( r - > signed_descriptor )
r - > signed_descriptor = tor_strdup ( r - > signed_descriptor ) ;
2004-04-08 00:18:57 +02:00
if ( r - > onion_pkey )
r - > onion_pkey = crypto_pk_dup_key ( r - > onion_pkey ) ;
if ( r - > identity_pkey )
r - > identity_pkey = crypto_pk_dup_key ( r - > identity_pkey ) ;
e = & r - > exit_policy ;
while ( * e ) {
2004-12-04 02:14:36 +01:00
tmp = tor_malloc ( sizeof ( addr_policy_t ) ) ;
memcpy ( tmp , * e , sizeof ( addr_policy_t ) ) ;
2004-04-08 00:18:57 +02:00
* e = tmp ;
( * e ) - > string = tor_strdup ( ( * e ) - > string ) ;
e = & ( ( * e ) - > next ) ;
}
2004-10-15 03:58:11 +02:00
if ( r - > declared_family ) {
r - > declared_family = smartlist_create ( ) ;
SMARTLIST_FOREACH ( router - > declared_family , const char * , s ,
smartlist_add ( r - > declared_family , tor_strdup ( s ) ) ) ;
}
2004-04-08 00:18:57 +02:00
return r ;
}
2004-05-10 06:34:48 +02:00
/** Free all storage held by a routerlist <b>rl</b> */
2005-06-11 20:52:12 +02:00
void
routerlist_free ( routerlist_t * rl )
2003-05-06 19:38:16 +02:00
{
2005-02-25 00:01:26 +01:00
tor_assert ( rl ) ;
2004-04-07 21:46:27 +02:00
SMARTLIST_FOREACH ( rl - > routers , routerinfo_t * , r ,
routerinfo_free ( r ) ) ;
smartlist_free ( rl - > routers ) ;
tor_free ( rl ) ;
2003-05-06 19:38:16 +02:00
}
2005-09-15 01:42:06 +02:00
/** Free all memory held by the rouerlist module */
2005-06-11 20:52:12 +02:00
void
2005-09-15 01:42:06 +02:00
routerlist_free_all ( void )
2005-02-11 00:18:39 +01:00
{
2005-02-25 00:01:26 +01:00
if ( routerlist )
routerlist_free ( routerlist ) ;
2005-02-11 00:18:39 +01:00
routerlist = NULL ;
2005-04-03 07:53:34 +02:00
if ( warned_nicknames ) {
SMARTLIST_FOREACH ( warned_nicknames , char * , cp , tor_free ( cp ) ) ;
smartlist_free ( warned_nicknames ) ;
warned_nicknames = NULL ;
}
2005-09-15 01:42:06 +02:00
if ( trusted_dir_servers ) {
SMARTLIST_FOREACH ( trusted_dir_servers , trusted_dir_server_t * , ds ,
{ tor_free ( ds - > address ) ; tor_free ( ds ) ; } ) ;
smartlist_free ( trusted_dir_servers ) ;
trusted_dir_servers = NULL ;
}
if ( networkstatus_list ) {
SMARTLIST_FOREACH ( networkstatus_list , networkstatus_t * , ns ,
networkstatus_free ( ns ) ) ;
smartlist_free ( networkstatus_list ) ;
networkstatus_list = NULL ;
}
2005-09-30 23:04:52 +02:00
if ( routerstatus_list ) {
SMARTLIST_FOREACH ( routerstatus_list , local_routerstatus_t * , rs ,
local_routerstatus_free ( rs ) ) ;
smartlist_free ( routerstatus_list ) ;
routerstatus_list = NULL ;
}
2005-02-11 00:18:39 +01:00
}
2005-09-02 22:37:31 +02:00
/** Free all storage held by the routerstatus object <b>rs</b>. */
void
routerstatus_free ( routerstatus_t * rs )
{
tor_free ( rs ) ;
}
2005-09-30 23:04:52 +02:00
/** Free all storage held by the local_routerstatus object <b>rs</b>. */
static void
local_routerstatus_free ( local_routerstatus_t * rs )
{
tor_free ( rs ) ;
}
2005-09-02 22:37:31 +02:00
/** Free all storage held by the networkstatus object <b>ns</b>. */
void
networkstatus_free ( networkstatus_t * ns )
{
tor_free ( ns - > source_address ) ;
tor_free ( ns - > contact ) ;
2005-09-08 20:46:25 +02:00
if ( ns - > signing_key )
crypto_free_pk_env ( ns - > signing_key ) ;
2005-09-02 22:37:31 +02:00
tor_free ( ns - > client_versions ) ;
tor_free ( ns - > server_versions ) ;
if ( ns - > entries ) {
SMARTLIST_FOREACH ( ns - > entries , routerstatus_t * , rs , routerstatus_free ( rs ) ) ;
smartlist_free ( ns - > entries ) ;
}
tor_free ( ns ) ;
}
2004-07-12 20:19:55 +02:00
/** Mark the router with ID <b>digest</b> as non-running in our routerlist. */
2005-06-11 20:52:12 +02:00
void
router_mark_as_down ( const char * digest )
{
2004-05-12 21:49:48 +02:00
routerinfo_t * router ;
2004-07-03 01:40:03 +02:00
tor_assert ( digest ) ;
2004-10-12 17:55:20 +02:00
SMARTLIST_FOREACH ( trusted_dir_servers , trusted_dir_server_t * , d ,
if ( ! memcmp ( d - > digest , digest , DIGEST_LEN ) )
d - > is_running = 0 ) ;
2004-07-03 01:40:03 +02:00
router = router_get_by_digest ( digest ) ;
2004-11-28 10:05:49 +01:00
if ( ! router ) /* we don't seem to know about him in the first place */
2002-09-26 15:17:14 +02:00
return ;
2004-11-25 05:20:10 +01:00
log_fn ( LOG_DEBUG , " Marking router '%s' as down. " , router - > nickname ) ;
2005-09-01 10:19:49 +02:00
if ( router_is_me ( router ) & & ! we_are_hibernating ( ) )
2004-09-21 19:14:47 +02:00
log_fn ( LOG_WARN , " We just marked ourself as down. Are your external addresses reachable? " ) ;
2003-09-30 23:27:16 +02:00
router - > is_running = 0 ;
2002-09-26 15:17:14 +02:00
}
2004-05-17 22:31:01 +02:00
/** Add <b>router</b> to the routerlist, if we don't already have it. Replace
2005-09-15 08:15:31 +02:00
* older entries ( if any ) with the same key . Note : Callers should not hold
2005-05-14 07:01:41 +02:00
* their pointers to < b > router < / b > if this function fails ; < b > router < / b >
2005-08-31 08:14:37 +02:00
* will either be inserted into the routerlist or freed .
2005-04-03 00:02:13 +02:00
*
2005-08-31 08:14:37 +02:00
* Returns > = 0 if the router was added ; less than 0 if it was not .
*
* If we ' re returning non - zero , then assign to * < b > msg < / b > a static string
* describing the reason for not liking the routerinfo .
2005-08-26 23:46:24 +02:00
*
* If the return value is less than - 1 , there was a problem with the
2005-08-31 08:14:37 +02:00
* routerinfo . If the return value is equal to - 1 , then the routerinfo was
* fine , but out - of - date . If the return value is equal to 1 , the
* routerinfo was accepted , but we should notify the generator of the
* descriptor using the message * < b > msg < / b > .
2005-09-15 02:51:42 +02:00
*
2005-09-15 08:15:31 +02:00
* This function should be called * after *
* routers_update_status_from_networkstatus ; subsequenctly , you should call
* router_rebuild_store and control_event_descriptors_changed .
2005-09-15 07:19:38 +02:00
*
* XXXX never replace your own descriptor .
2004-05-17 22:31:01 +02:00
*/
2005-08-26 22:59:04 +02:00
int
2005-09-15 07:19:38 +02:00
router_add_to_routerlist ( routerinfo_t * router , const char * * msg ,
int from_cache )
2005-06-11 20:52:12 +02:00
{
2004-05-17 22:31:01 +02:00
int i ;
2004-08-07 05:38:07 +02:00
char id_digest [ DIGEST_LEN ] ;
2005-08-26 22:59:04 +02:00
int authdir = get_options ( ) - > AuthoritativeDir ;
int authdir_verified = 0 ;
2004-08-07 05:38:07 +02:00
2005-08-27 01:12:13 +02:00
tor_assert ( msg ) ;
2005-08-26 23:12:34 +02:00
if ( ! routerlist ) {
routerlist = tor_malloc_zero ( sizeof ( routerlist_t ) ) ;
routerlist - > routers = smartlist_create ( ) ;
}
2004-08-07 05:38:07 +02:00
crypto_pk_get_digest ( router - > identity_pkey , id_digest ) ;
2005-08-26 22:59:04 +02:00
if ( authdir ) {
2005-09-15 02:51:42 +02:00
if ( authdir_wants_to_reject_router ( router , msg ) )
2005-08-26 23:46:24 +02:00
return - 2 ;
2005-09-15 02:51:42 +02:00
authdir_verified = router - > is_verified ;
2005-08-26 22:59:04 +02:00
}
2004-05-17 22:31:01 +02:00
/* If we have a router with this name, and the identity key is the same,
* choose the newer one . If the identity key has changed , drop the router .
*/
for ( i = 0 ; i < smartlist_len ( routerlist - > routers ) ; + + i ) {
2005-08-26 22:59:04 +02:00
routerinfo_t * old_router = smartlist_get ( routerlist - > routers , i ) ;
if ( ! crypto_pk_cmp_keys ( router - > identity_pkey , old_router - > identity_pkey ) ) {
if ( router - > published_on < = old_router - > published_on ) {
2005-09-15 02:51:42 +02:00
/* Same key, but old */
2005-04-03 00:02:13 +02:00
log_fn ( LOG_DEBUG , " Skipping not-new descriptor for router '%s' " ,
2004-05-17 22:31:01 +02:00
router - > nickname ) ;
routerinfo_free ( router ) ;
2005-08-31 08:14:37 +02:00
* msg = " Router descriptor was not new. " ;
2004-05-17 22:31:01 +02:00
return - 1 ;
2005-08-26 22:59:04 +02:00
} else {
2005-09-15 02:51:42 +02:00
/* Same key, new. */
2005-09-01 10:13:40 +02:00
int unreachable = 0 ;
2005-08-26 22:59:04 +02:00
log_fn ( LOG_DEBUG , " Replacing entry for router '%s/%s' [%s] " ,
router - > nickname , old_router - > nickname ,
hex_str ( id_digest , DIGEST_LEN ) ) ;
if ( router - > addr = = old_router - > addr & &
router - > or_port = = old_router - > or_port ) {
/* these carry over when the address and orport are unchanged.*/
router - > last_reachable = old_router - > last_reachable ;
router - > testing_since = old_router - > testing_since ;
2005-09-01 10:13:40 +02:00
router - > num_unreachable_notifications =
old_router - > num_unreachable_notifications ;
2005-08-26 22:59:04 +02:00
}
2005-09-01 10:13:40 +02:00
if ( authdir & &
dirserv_thinks_router_is_blatantly_unreachable ( router , time ( NULL ) ) ) {
if ( router - > num_unreachable_notifications > = 3 ) {
unreachable = 1 ;
2005-09-10 22:40:16 +02:00
log_fn ( LOG_NOTICE , " Notifying server '%s' that it's unreachable. (ContactInfo '%s', platform '%s'). " ,
2005-09-01 10:13:40 +02:00
router - > nickname , router - > contact_info ? router - > contact_info : " " ,
router - > platform ? router - > platform : " " ) ;
} else {
2005-09-10 22:40:16 +02:00
log_fn ( LOG_INFO , " '%s' may be unreachable -- the %d previous descriptors were thought to be unreachable. " , router - > nickname , router - > num_unreachable_notifications ) ;
2005-09-01 10:13:40 +02:00
router - > num_unreachable_notifications + + ;
}
2005-08-31 08:18:19 +02:00
}
2005-08-26 22:59:04 +02:00
routerinfo_free ( old_router ) ;
smartlist_set ( routerlist - > routers , i , router ) ;
2005-09-15 07:19:38 +02:00
if ( ! from_cache )
router_append_to_journal ( router - > signed_descriptor ,
router - > signed_descriptor_len ) ;
2005-08-26 22:59:04 +02:00
directory_set_dirty ( ) ;
2005-08-31 08:14:37 +02:00
* msg = unreachable ? " Dirserver believes your ORPort is unreachable " :
authdir_verified ? " Verified server updated " :
" Unverified server updated. (Have you sent us your key fingerprint?) " ;
return unreachable ? 1 : 0 ;
2004-05-17 22:31:01 +02:00
}
2005-08-26 22:59:04 +02:00
} else if ( ! strcasecmp ( router - > nickname , old_router - > nickname ) ) {
2004-08-17 08:06:05 +02:00
/* nicknames match, keys don't. */
2005-09-15 02:51:42 +02:00
if ( router - > is_named ) {
2004-08-17 08:06:05 +02:00
/* The new verified router replaces the old one; remove the
2004-08-17 10:00:23 +02:00
* old one . And carry on to the end of the list , in case
2004-12-01 04:48:14 +01:00
* there are more old unverified routers with this nickname
2004-08-17 08:06:05 +02:00
*/
2004-08-17 10:00:23 +02:00
/* mark-for-close connections using the old key, so we can
* make new ones with the new key .
*/
connection_t * conn ;
2005-08-26 22:59:04 +02:00
while ( ( conn = connection_get_by_identity_digest (
old_router - > identity_digest , CONN_TYPE_OR ) ) ) {
log_fn ( LOG_INFO , " Closing conn to obsolete router '%s' " ,
old_router - > nickname ) ;
2004-08-17 10:00:23 +02:00
connection_mark_for_close ( conn ) ;
}
2005-08-26 22:59:04 +02:00
routerinfo_free ( old_router ) ;
2004-08-17 08:06:05 +02:00
smartlist_del_keeporder ( routerlist - > routers , i - - ) ;
2005-09-15 02:51:42 +02:00
} else if ( old_router - > is_named ) {
2004-08-17 08:06:05 +02:00
/* Can't replace a verified router with an unverified one. */
log_fn ( LOG_DEBUG , " Skipping unverified entry for verified router '%s' " ,
router - > nickname ) ;
routerinfo_free ( router ) ;
2005-08-31 08:14:37 +02:00
* msg = " Already have verified router with same nickname and different key. " ;
2005-08-26 23:46:24 +02:00
return - 2 ;
2004-08-17 08:06:05 +02:00
}
2004-05-17 22:31:01 +02:00
}
}
/* We haven't seen a router with this name before. Add it to the end of
* the list . */
smartlist_add ( routerlist - > routers , router ) ;
2005-09-15 07:19:38 +02:00
if ( ! from_cache )
router_append_to_journal ( router - > signed_descriptor ,
router - > signed_descriptor_len ) ;
2005-08-26 22:59:04 +02:00
directory_set_dirty ( ) ;
2004-05-17 22:31:01 +02:00
return 0 ;
}
2004-08-07 00:15:25 +02:00
/** Remove any routers from the routerlist that are more than <b>age</b>
2004-05-20 07:10:30 +02:00
* seconds old .
*/
void
2004-08-07 00:15:25 +02:00
routerlist_remove_old_routers ( int age )
2004-05-20 07:10:30 +02:00
{
int i ;
time_t cutoff ;
routerinfo_t * router ;
if ( ! routerlist )
return ;
2004-08-07 00:15:25 +02:00
cutoff = time ( NULL ) - age ;
2004-05-20 07:10:30 +02:00
for ( i = 0 ; i < smartlist_len ( routerlist - > routers ) ; + + i ) {
router = smartlist_get ( routerlist - > routers , i ) ;
2004-10-19 20:19:59 +02:00
if ( router - > published_on < = cutoff ) {
/* Too old. Remove it. */
2004-11-25 05:20:10 +01:00
log_fn ( LOG_INFO , " Forgetting obsolete routerinfo for router '%s' " , router - > nickname ) ;
2004-05-20 07:10:30 +02:00
routerinfo_free ( router ) ;
smartlist_del ( routerlist - > routers , i - - ) ;
}
}
}
2005-08-26 22:59:04 +02:00
/**
2005-06-21 01:04:13 +02:00
* Code to parse a single router descriptor and insert it into the
* routerlist . Return - 1 if the descriptor was ill - formed ; 0 if the
2005-04-03 00:02:13 +02:00
* descriptor was well - formed but could not be added ; and 1 if the
* descriptor was added .
2005-06-21 01:04:13 +02:00
*
* If we don ' t add it and < b > msg < / b > is not NULL , then assign to
* * < b > msg < / b > a static string describing the reason for refusing the
* descriptor .
2005-08-26 22:59:04 +02:00
*
* This is used only by the controller .
2004-05-10 06:34:48 +02:00
*/
2005-02-25 21:46:13 +01:00
int
2005-04-03 00:02:13 +02:00
router_load_single_router ( const char * s , const char * * msg )
2005-02-25 21:46:13 +01:00
{
routerinfo_t * ri ;
2005-05-18 05:52:07 +02:00
tor_assert ( msg ) ;
2005-07-15 21:40:38 +02:00
* msg = NULL ;
2005-02-25 21:46:13 +01:00
if ( ! ( ri = router_parse_entry_from_string ( s , NULL ) ) ) {
log_fn ( LOG_WARN , " Error parsing router descriptor; dropping. " ) ;
2005-07-15 21:40:38 +02:00
* msg = " Couldn't parse router descriptor. " ;
2005-02-25 21:46:13 +01:00
return - 1 ;
}
2005-05-14 07:01:41 +02:00
if ( router_is_me ( ri ) ) {
log_fn ( LOG_WARN , " Router's identity key matches mine; dropping. " ) ;
2005-05-18 05:52:07 +02:00
* msg = " Router's identity key matches mine. " ;
2005-05-14 07:01:41 +02:00
routerinfo_free ( ri ) ;
return 0 ;
}
2005-09-14 23:09:25 +02:00
/* XXXX011 update router status from networkstatus!! */
2005-09-15 07:19:38 +02:00
if ( router_add_to_routerlist ( ri , msg , 0 ) < 0 ) {
2005-07-15 21:40:38 +02:00
log_fn ( LOG_WARN , " Couldn't add router to list: %s Dropping. " ,
* msg ? * msg : " (No message). " ) ;
2005-06-21 01:04:13 +02:00
/* we've already assigned to *msg now, and ri is already freed */
2005-04-03 00:02:13 +02:00
return 0 ;
2005-03-02 23:29:58 +01:00
} else {
smartlist_t * changed = smartlist_create ( ) ;
smartlist_add ( changed , ri ) ;
control_event_descriptors_changed ( changed ) ;
smartlist_free ( changed ) ;
2005-02-25 21:46:13 +01:00
}
2005-05-11 00:33:45 +02:00
2005-02-25 21:46:13 +01:00
log_fn ( LOG_DEBUG , " Added router to list " ) ;
2005-04-03 00:02:13 +02:00
return 1 ;
2005-02-25 21:46:13 +01:00
}
2004-04-25 21:04:11 +02:00
2005-09-15 08:15:31 +02:00
/** Given a string <b>s</b> containing some routerdescs, parse it and put the
* routers into our directory . If < b > from_cache < / b > is false , the routers
* have come from the network : cache them .
*
* If < b > requested_fingerprints < / b > is provided , it must contain a list of
* uppercased identity fingerprints . Do not update any router whose
* fingerprint is not on the list ; after updating a router , remove its
* fingerprint from the list .
*/
2005-09-15 07:19:38 +02:00
void
router_load_routers_from_string ( const char * s , int from_cache ,
smartlist_t * requested_fingerprints )
{
smartlist_t * routers = smartlist_create ( ) , * changed = smartlist_create ( ) ;
char fp [ HEX_DIGEST_LEN + 1 ] ;
const char * msg ;
router_parse_list_from_string ( & s , routers ) ;
2005-09-18 04:51:12 +02:00
routers_update_status_from_networkstatus ( routers , ! from_cache ) ;
2005-09-15 07:19:38 +02:00
SMARTLIST_FOREACH ( routers , routerinfo_t * , ri ,
{
base16_encode ( fp , sizeof ( fp ) , ri - > identity_digest , DIGEST_LEN ) ;
if ( requested_fingerprints ) {
if ( smartlist_string_isin ( requested_fingerprints , fp ) ) {
smartlist_string_remove ( requested_fingerprints , fp ) ;
} else {
char * requested =
smartlist_join_strings ( requested_fingerprints , " " , 0 , NULL ) ;
log_fn ( LOG_WARN , " We received a router descriptor with a fingerprint (%s) that we never requested. (We asked for: %s.) Dropping. " , fp , requested ) ;
tor_free ( requested ) ;
routerinfo_free ( ri ) ;
continue ;
}
}
if ( router_add_to_routerlist ( ri , & msg , from_cache ) > = 0 )
smartlist_add ( changed , ri ) ;
} ) ;
control_event_descriptors_changed ( changed ) ;
router_rebuild_store ( 0 ) ;
smartlist_free ( routers ) ;
smartlist_free ( changed ) ;
}
2005-09-13 17:32:03 +02:00
/** Helper: return a newly allocated string containing the name of the filename
* where we plan to cache < b > ns < / b > . */
2005-09-12 08:56:42 +02:00
static char *
networkstatus_get_cache_filename ( const networkstatus_t * ns )
{
const char * datadir = get_options ( ) - > DataDirectory ;
size_t len = strlen ( datadir ) + 64 ;
char fp [ HEX_DIGEST_LEN + 1 ] ;
char * fn = tor_malloc ( len + 1 ) ;
base16_encode ( fp , HEX_DIGEST_LEN + 1 , ns - > identity_digest , DIGEST_LEN ) ;
tor_snprintf ( fn , len , " %s/cached-status/%s " , datadir , fp ) ;
return fn ;
}
2005-09-13 17:32:03 +02:00
/** Helper for smartlist_sort: Compare two networkstatus objects by
* publication date . */
2005-09-12 08:56:42 +02:00
static int
_compare_networkstatus_published_on ( const void * * _a , const void * * _b )
{
const networkstatus_t * a = * _a , * b = * _b ;
if ( a - > published_on < b - > published_on )
return - 1 ;
else if ( a - > published_on > b - > published_on )
return 1 ;
else
return 0 ;
}
2005-09-13 17:32:03 +02:00
/** How far in the future do we allow a network-status to get before removing
* it ? ( seconds ) */
2005-09-08 23:01:24 +02:00
# define NETWORKSTATUS_ALLOW_SKEW (48*60*60)
2005-09-13 17:32:03 +02:00
/** Given a string <b>s</b> containing a network status that we received at
* < b > arrived_at < / b > from < b > source < / b > , try to parse it , see if we want to
* store it , and put it into our cache is necessary .
*
* If < b > source < / b > is NS_FROM_DIR or NS_FROM_CACHE , do not replace our
* own networkstatus_t ( if we ' re a directory server ) .
*
* If < b > source < / b > is NS_FROM_CACHE , do not write our networkstatus_t to the
* cache .
*
* If < b > requested_fingerprints < / b > is provided , it must contain a list of
* uppercased identity fingerprints . Do not update any networkstatus whose
* fingerprint is not on the list ; after updating a networkstatus , remove its
* fingerprint from the list .
*
2005-09-18 04:24:42 +02:00
* Return 0 on success , - 1 on failure .
*
* Callers should make sure that routers_update_all_from_networkstatus ( ) is
* invoked after this function succeeds .
2005-09-07 18:42:53 +02:00
*/
int
2005-09-08 22:36:40 +02:00
router_set_networkstatus ( const char * s , time_t arrived_at ,
networkstatus_source_t source , smartlist_t * requested_fingerprints )
2005-09-07 18:42:53 +02:00
{
networkstatus_t * ns ;
int i , found ;
time_t now ;
2005-09-08 23:01:24 +02:00
int skewed = 0 ;
2005-09-12 08:56:42 +02:00
trusted_dir_server_t * trusted_dir ;
char fp [ HEX_DIGEST_LEN + 1 ] ;
2005-09-15 01:42:06 +02:00
char published [ ISO_TIME_LEN + 1 ] ;
2005-09-07 18:42:53 +02:00
ns = networkstatus_parse_from_string ( s ) ;
if ( ! ns ) {
log_fn ( LOG_WARN , " Couldn't parse network status. " ) ;
return - 1 ;
}
2005-09-12 08:56:42 +02:00
if ( ! ( trusted_dir = router_get_trusteddirserver_by_digest ( ns - > identity_digest ) ) ) {
2005-09-07 18:42:53 +02:00
log_fn ( LOG_INFO , " Network status was signed, but not by an authoritative directory we recognize. " ) ;
2005-09-08 22:36:40 +02:00
networkstatus_free ( ns ) ;
2005-09-07 18:42:53 +02:00
return - 1 ;
}
now = time ( NULL ) ;
if ( arrived_at > now )
arrived_at = now ;
ns - > received_on = arrived_at ;
2005-09-15 01:42:06 +02:00
format_iso_time ( published , ns - > published_on ) ;
2005-09-08 23:01:24 +02:00
if ( ns - > published_on > now + NETWORKSTATUS_ALLOW_SKEW ) {
2005-09-15 01:42:06 +02:00
log_fn ( LOG_WARN , " Network status was published in the future (%s GMT). Somebody is skewed here: check your clock. Not caching. " , published ) ;
2005-09-08 23:01:24 +02:00
skewed = 1 ;
}
2005-09-07 18:42:53 +02:00
if ( ! networkstatus_list )
networkstatus_list = smartlist_create ( ) ;
2005-09-08 22:36:40 +02:00
if ( source = = NS_FROM_DIR & & router_digest_is_me ( ns - > identity_digest ) ) {
2005-09-12 08:56:42 +02:00
/* Don't replace our own networkstatus when we get it from somebody else. */
2005-09-08 22:36:40 +02:00
networkstatus_free ( ns ) ;
return 0 ;
}
base16_encode ( fp , HEX_DIGEST_LEN + 1 , ns - > identity_digest , DIGEST_LEN ) ;
2005-09-12 08:56:42 +02:00
if ( requested_fingerprints ) {
if ( smartlist_string_isin ( requested_fingerprints , fp ) ) {
smartlist_string_remove ( requested_fingerprints , fp ) ;
} else {
char * requested = smartlist_join_strings ( requested_fingerprints , " " , 0 , NULL ) ;
2005-09-15 01:42:06 +02:00
log_fn ( LOG_WARN , " We received a network status with a fingerprint (%s) that we never requested. (We asked for: %s.) Dropping. " , fp , requested ) ;
2005-09-12 08:56:42 +02:00
tor_free ( requested ) ;
return 0 ;
}
2005-09-08 22:36:40 +02:00
}
2005-09-12 08:56:42 +02:00
if ( source ! = NS_FROM_CACHE )
trusted_dir - > n_networkstatus_failures = 0 ;
2005-09-07 18:42:53 +02:00
found = 0 ;
for ( i = 0 ; i < smartlist_len ( networkstatus_list ) ; + + i ) {
networkstatus_t * old_ns = smartlist_get ( networkstatus_list , i ) ;
if ( ! memcmp ( old_ns - > identity_digest , ns - > identity_digest , DIGEST_LEN ) ) {
if ( ! memcmp ( old_ns - > networkstatus_digest ,
ns - > networkstatus_digest , DIGEST_LEN ) ) {
2005-09-08 08:22:44 +02:00
/* Same one we had before. */
2005-09-07 18:42:53 +02:00
networkstatus_free ( ns ) ;
2005-09-15 01:42:06 +02:00
log_fn ( LOG_NOTICE ,
" Dropping network-status from %s:%d (published %s); already have it. " ,
trusted_dir - > address , trusted_dir - > dir_port , published ) ;
if ( old_ns - > received_on < arrived_at ) {
if ( source ! = NS_FROM_CACHE ) {
char * fn = networkstatus_get_cache_filename ( old_ns ) ;
/* We use mtime to tell when it arrived, so update that. */
touch_file ( fn ) ;
tor_free ( fn ) ;
}
2005-09-08 08:22:44 +02:00
old_ns - > received_on = arrived_at ;
2005-09-15 01:42:06 +02:00
}
2005-09-07 18:42:53 +02:00
return 0 ;
} else if ( old_ns - > published_on > = ns - > published_on ) {
2005-09-15 01:42:06 +02:00
char old_published [ ISO_TIME_LEN + 1 ] ;
format_iso_time ( old_published , old_ns - > published_on ) ;
log_fn ( LOG_NOTICE ,
" Dropping network-status from %s:%d (published %s); "
" we have a newer one (published %s) for this authority. " ,
trusted_dir - > address , trusted_dir - > dir_port , published ,
old_published ) ;
2005-09-07 18:42:53 +02:00
networkstatus_free ( ns ) ;
return 0 ;
} else {
networkstatus_free ( old_ns ) ;
smartlist_set ( networkstatus_list , i , ns ) ;
found = 1 ;
break ;
}
}
}
if ( ! found )
smartlist_add ( networkstatus_list , ns ) ;
2005-09-14 23:09:25 +02:00
/*XXXX011 downgrade to INFO NM */
2005-09-15 01:42:06 +02:00
log_fn ( LOG_NOTICE , " Setting networkstatus %s %s:%d (published %s) " ,
source = = NS_FROM_CACHE ? " cached from " :
( source = = NS_FROM_DIR ? " downloaded from " : " generated for " ) ,
trusted_dir - > address , trusted_dir - > dir_port , published ) ;
2005-09-14 23:09:25 +02:00
networkstatus_list_has_changed = 1 ;
2005-09-12 08:56:42 +02:00
smartlist_sort ( networkstatus_list , _compare_networkstatus_published_on ) ;
2005-09-08 23:01:24 +02:00
if ( source ! = NS_FROM_CACHE & & ! skewed ) {
2005-09-12 08:56:42 +02:00
char * fn = networkstatus_get_cache_filename ( ns ) ;
2005-09-07 18:42:53 +02:00
if ( write_str_to_file ( fn , s , 0 ) < 0 ) {
log_fn ( LOG_NOTICE , " Couldn't write cached network status to \" %s \" " , fn ) ;
}
tor_free ( fn ) ;
}
2005-09-18 04:24:42 +02:00
networkstatus_list_update_recent ( now ) ;
2005-09-08 23:01:24 +02:00
if ( get_options ( ) - > DirPort & & ! skewed )
2005-09-07 18:42:53 +02:00
dirserv_set_cached_networkstatus_v2 ( s , fp , ns - > published_on ) ;
2005-09-07 19:18:52 +02:00
return 0 ;
2005-09-07 18:42:53 +02:00
}
2005-09-13 17:32:03 +02:00
/** How old do we allow a network-status to get before removing it completely? */
2005-09-12 08:56:42 +02:00
# define MAX_NETWORKSTATUS_AGE (10*24*60*60)
2005-09-13 17:32:03 +02:00
/** Remove all very-old network_status_t objects from memory and from the
* disk cache . */
2005-09-12 08:56:42 +02:00
void
networkstatus_list_clean ( time_t now )
{
int i ;
if ( ! networkstatus_list )
return ;
for ( i = 0 ; i < smartlist_len ( networkstatus_list ) ; + + i ) {
networkstatus_t * ns = smartlist_get ( networkstatus_list , i ) ;
char * fname = NULL ; ;
if ( ns - > published_on + MAX_NETWORKSTATUS_AGE > now )
continue ;
/* Okay, this one is too old. Remove it from the list, and delete it
* from the cache . */
smartlist_del ( networkstatus_list , i - - ) ;
fname = networkstatus_get_cache_filename ( ns ) ;
if ( file_status ( fname ) = = FN_FILE ) {
log_fn ( LOG_INFO , " Removing too-old networkstatus in %s " , fname ) ;
unlink ( fname ) ;
}
tor_free ( fname ) ;
if ( get_options ( ) - > DirPort ) {
char fp [ HEX_DIGEST_LEN + 1 ] ;
base16_encode ( fp , sizeof ( fp ) , ns - > identity_digest , DIGEST_LEN ) ;
dirserv_set_cached_networkstatus_v2 ( NULL , fp , 0 ) ;
}
networkstatus_free ( ns ) ;
}
}
/** Helper for bsearching a list of routerstatus_t pointers.*/
static int
_compare_digest_to_routerstatus_entry ( const void * _key , const void * * _member )
{
const char * key = _key ;
const routerstatus_t * rs = * _member ;
return memcmp ( key , rs - > identity_digest , DIGEST_LEN ) ;
}
/** Return the entry in <b>ns</b> for the identity digest <b>digest</b>, or
* NULL if none was found . */
2005-09-15 07:41:30 +02:00
static routerstatus_t *
2005-09-12 08:56:42 +02:00
networkstatus_find_entry ( networkstatus_t * ns , const char * digest )
{
return smartlist_bsearch ( ns - > entries , digest ,
_compare_digest_to_routerstatus_entry ) ;
}
2005-09-30 22:04:55 +02:00
/** Return the consensus view of the status of the router whose digest is
* < b > digest < / b > , or NULL if we don ' t know about any such router . */
2005-09-22 03:51:14 +02:00
local_routerstatus_t *
2005-09-18 04:24:42 +02:00
router_get_combined_status_by_digest ( const char * digest )
{
if ( ! routerstatus_list )
return NULL ;
return smartlist_bsearch ( routerstatus_list , digest ,
_compare_digest_to_routerstatus_entry ) ;
}
2005-09-08 23:01:24 +02:00
/* XXXX These should be configurable, perhaps? NM */
2005-09-08 22:18:15 +02:00
# define AUTHORITY_NS_CACHE_INTERVAL 10*60
# define NONAUTHORITY_NS_CACHE_INTERVAL 15*60
2005-09-13 17:32:03 +02:00
/** We are a directory server, and so cache network_status documents.
* Initiate downloads as needed to update them . For authorities , this means
* asking each trusted directory for its network - status . For caches , this means
* asking a random authority for all network - statuses .
*/
2005-09-08 22:18:15 +02:00
void
update_networkstatus_cache_downloads ( time_t now )
{
static time_t last_downloaded = 0 ;
int authority = authdir_mode ( get_options ( ) ) ;
int interval =
authority ? AUTHORITY_NS_CACHE_INTERVAL : NONAUTHORITY_NS_CACHE_INTERVAL ;
2005-09-13 17:32:03 +02:00
/*XXXXX NM we should retry on failure. */
2005-09-08 22:18:15 +02:00
if ( last_downloaded + interval > = now )
return ;
if ( ! trusted_dir_servers )
return ;
last_downloaded = now ;
if ( authority ) {
/* An authority launches a separate connection for everybody. */
SMARTLIST_FOREACH ( trusted_dir_servers , trusted_dir_server_t * , ds ,
{
char resource [ HEX_DIGEST_LEN + 6 ] ;
if ( router_digest_is_me ( ds - > digest ) )
continue ;
2005-09-12 08:56:42 +02:00
if ( connection_get_by_type_addr_port_purpose (
CONN_TYPE_DIR , ds - > addr , ds - > dir_port ,
2005-09-13 17:32:03 +02:00
DIR_PURPOSE_FETCH_NETWORKSTATUS ) ) {
/* We are already fetching this one. */
2005-09-12 08:56:42 +02:00
continue ;
2005-09-13 17:32:03 +02:00
}
2005-09-08 22:18:15 +02:00
strlcpy ( resource , " fp/ " , sizeof ( resource ) ) ;
base16_encode ( resource + 3 , sizeof ( resource ) - 3 , ds - > digest , DIGEST_LEN ) ;
strlcat ( resource , " .z " , sizeof ( resource ) ) ;
directory_get_from_dirserver ( DIR_PURPOSE_FETCH_NETWORKSTATUS , resource , 1 ) ;
} ) ;
} else {
/* A non-authority cache launches one connection to a random authority. */
2005-09-13 17:32:03 +02:00
/* (Check whether we're currently fetching network-status objects.) */
2005-09-12 08:56:42 +02:00
if ( ! connection_get_by_type_purpose ( CONN_TYPE_DIR ,
DIR_PURPOSE_FETCH_NETWORKSTATUS ) )
directory_get_from_dirserver ( DIR_PURPOSE_FETCH_NETWORKSTATUS , " all.z " , 1 ) ;
2005-09-08 22:18:15 +02:00
}
}
2005-09-08 23:01:24 +02:00
/*XXXX Should these be configurable? NM*/
2005-09-14 23:09:25 +02:00
/** How old (in seconds) can a network-status be before we try replacing it? */
2005-09-08 23:01:24 +02:00
# define NETWORKSTATUS_MAX_VALIDITY (48*60*60)
/** How long (in seconds) does a client wait after getting a network status
* before downloading the next in sequence ? */
# define NETWORKSTATUS_CLIENT_DL_INTERVAL (30*60)
2005-09-14 23:09:25 +02:00
/* How many times do we allow a networkstatus download to fail before we
* assume that the authority isn ' t publishing ? */
# define NETWORKSTATUS_N_ALLOWABLE_FAILURES 3
2005-09-13 17:32:03 +02:00
/** We are not a directory cache or authority. Update our network-status list
* by launching a new directory fetch for enough network - status documents " as
* necessary " . See function comments for implementation details.
*/
2005-09-08 08:22:44 +02:00
void
2005-09-08 22:18:15 +02:00
update_networkstatus_client_downloads ( time_t now )
2005-09-08 08:22:44 +02:00
{
2005-09-14 23:09:25 +02:00
int n_live = 0 , needed = 0 , n_running_dirservers , n_dirservers , i ;
2005-09-08 08:22:44 +02:00
int most_recent_idx = - 1 ;
trusted_dir_server_t * most_recent = NULL ;
time_t most_recent_received = 0 ;
2005-09-08 23:01:24 +02:00
char * resource , * cp ;
size_t resource_len ;
2005-09-08 08:22:44 +02:00
2005-09-12 08:56:42 +02:00
if ( connection_get_by_type_purpose ( CONN_TYPE_DIR ,
DIR_PURPOSE_FETCH_NETWORKSTATUS ) )
return ;
2005-09-08 08:22:44 +02:00
/* This is a little tricky. We want to download enough network-status
2005-09-12 08:56:42 +02:00
* objects so that we have at least half of them under
* NETWORKSTATUS_MAX_VALIDITY publication time . We want to download a new
* * one * if the most recent one ' s publication time is under
* NETWORKSTATUS_CLIENT_DL_INTERVAL .
2005-09-08 08:22:44 +02:00
*/
2005-09-08 18:18:28 +02:00
if ( ! trusted_dir_servers | | ! smartlist_len ( trusted_dir_servers ) )
return ;
2005-09-14 23:09:25 +02:00
n_dirservers = n_running_dirservers = smartlist_len ( trusted_dir_servers ) ;
2005-09-08 08:22:44 +02:00
SMARTLIST_FOREACH ( trusted_dir_servers , trusted_dir_server_t * , ds ,
{
networkstatus_t * ns = networkstatus_get_by_digest ( ds - > digest ) ;
2005-09-08 18:18:28 +02:00
if ( ! ns )
continue ;
2005-09-14 23:09:25 +02:00
if ( ds - > n_networkstatus_failures > NETWORKSTATUS_N_ALLOWABLE_FAILURES ) {
- - n_running_dirservers ;
continue ;
}
2005-09-08 23:01:24 +02:00
if ( ns - > published_on > now - NETWORKSTATUS_MAX_VALIDITY )
2005-09-08 08:22:44 +02:00
+ + n_live ;
if ( ! most_recent | | ns - > received_on > most_recent_received ) {
2005-09-13 17:32:03 +02:00
most_recent_idx = ds_sl_idx ; /* magic variable from FOREACH */
2005-09-08 08:22:44 +02:00
most_recent = ds ;
most_recent_received = ns - > received_on ;
}
} ) ;
/* Download enough so we have at least half live, but no more than all the
* trusted dirservers we know .
*/
if ( n_live < ( n_dirservers / 2 ) + 1 )
needed = ( n_dirservers / 2 ) + 1 - n_live ;
2005-09-14 23:09:25 +02:00
if ( needed > n_running_dirservers )
needed = n_running_dirservers ;
if ( needed )
2005-09-16 18:41:45 +02:00
/* XXXX011 Downgrade to info NM */
2005-09-14 23:09:25 +02:00
log_fn ( LOG_NOTICE , " For %d/%d running directory servers, we have %d live "
" network-status documents. Downloading %d. " ,
n_running_dirservers , n_dirservers , n_live , needed ) ;
2005-09-08 23:01:24 +02:00
/* Also, download at least 1 every NETWORKSTATUS_CLIENT_DL_INTERVAL. */
2005-09-14 23:09:25 +02:00
if ( n_running_dirservers & &
most_recent_received < now - NETWORKSTATUS_CLIENT_DL_INTERVAL & & needed < 1 ) {
2005-09-15 02:51:42 +02:00
const char * addr = most_recent ? most_recent - > address : " nobody " ;
int port = most_recent ? most_recent - > dir_port : 0 ;
log_fn ( LOG_NOTICE , " Our most recent network-status document (from %s:%d) "
" is %d seconds old; downloading another. " ,
addr , port , ( int ) ( now - most_recent_received ) ) ;
2005-09-08 08:22:44 +02:00
needed = 1 ;
2005-09-14 23:09:25 +02:00
}
2005-09-08 08:22:44 +02:00
2005-09-08 23:01:24 +02:00
if ( ! needed )
return ;
2005-09-08 08:22:44 +02:00
/* If no networkstatus was found, choose a dirserver at random as "most
* recent " . */
if ( most_recent_idx < 0 )
most_recent_idx = crypto_pseudo_rand_int ( n_dirservers ) ;
2005-09-08 23:01:24 +02:00
/* Build a request string for all the resources we want. */
resource_len = needed * ( HEX_DIGEST_LEN + 1 ) + 6 ;
resource = tor_malloc ( resource_len ) ;
memcpy ( resource , " fp/ " , 3 ) ;
cp = resource + 3 ;
2005-09-08 08:22:44 +02:00
for ( i = most_recent_idx + 1 ; needed ; + + i ) {
trusted_dir_server_t * ds ;
2005-09-08 18:18:28 +02:00
if ( i > = n_dirservers )
2005-09-08 08:22:44 +02:00
i = 0 ;
ds = smartlist_get ( trusted_dir_servers , i ) ;
2005-09-14 23:09:25 +02:00
if ( ds - > n_networkstatus_failures > NETWORKSTATUS_N_ALLOWABLE_FAILURES )
continue ;
2005-09-08 23:01:24 +02:00
base16_encode ( cp , HEX_DIGEST_LEN + 1 , ds - > digest , DIGEST_LEN ) ;
cp + = HEX_DIGEST_LEN ;
2005-09-08 08:22:44 +02:00
- - needed ;
2005-09-08 23:39:39 +02:00
if ( needed )
* cp + + = ' + ' ;
2005-09-08 08:22:44 +02:00
}
2005-09-08 23:01:24 +02:00
memcpy ( cp , " .z " , 3 ) ;
directory_get_from_dirserver ( DIR_PURPOSE_FETCH_NETWORKSTATUS , resource , 1 ) ;
tor_free ( resource ) ;
2005-09-08 08:22:44 +02:00
}
2005-03-19 07:57:16 +01:00
/** Decide whether a given addr:port is definitely accepted,
* definitely rejected , probably accepted , or probably rejected by a
* given policy . If < b > addr < / b > is 0 , we don ' t know the IP of the
* target address . If < b > port < / b > is 0 , we don ' t know the port of the
* target address .
2003-12-09 05:29:52 +01:00
*
2005-03-19 07:57:16 +01:00
* For now , the algorithm is pretty simple : we look for definite and
* uncertain matches . The first definite match is what we guess ; if
2005-07-01 03:59:37 +02:00
* it was preceded by no uncertain matches of the opposite policy ,
2005-03-19 07:57:16 +01:00
* then the guess is definite ; otherwise it is probable . ( If we
* have a known addr and port , all matches are definite ; if we have an
* unknown addr / port , any address / port ranges other than " all " are
* uncertain . )
*
* We could do better by assuming that some ranges never match typical
* addresses ( 127.0 .0 .1 , and so on ) . But we ' ll try this for now .
2003-12-09 05:29:52 +01:00
*/
2005-03-19 07:57:16 +01:00
addr_policy_result_t
router_compare_addr_to_addr_policy ( uint32_t addr , uint16_t port ,
addr_policy_t * policy )
2003-05-07 20:30:46 +02:00
{
2003-12-09 05:29:52 +01:00
int maybe_reject = 0 ;
2004-02-17 08:56:33 +01:00
int maybe_accept = 0 ;
2003-12-09 05:29:52 +01:00
int match = 0 ;
2004-02-17 09:52:03 +01:00
int maybe = 0 ;
2004-12-04 02:14:36 +01:00
addr_policy_t * tmpe ;
2003-12-05 10:51:49 +01:00
2004-11-28 10:05:49 +01:00
for ( tmpe = policy ; tmpe ; tmpe = tmpe - > next ) {
2004-02-17 09:52:03 +01:00
maybe = 0 ;
2003-12-09 05:29:52 +01:00
if ( ! addr ) {
/* Address is unknown. */
2004-12-05 08:10:08 +01:00
if ( ( port > = tmpe - > prt_min & & port < = tmpe - > prt_max ) | |
( ! port & & tmpe - > prt_min < = 1 & & tmpe - > prt_max > = 65535 ) ) {
2004-02-17 09:52:03 +01:00
/* The port definitely matches. */
if ( tmpe - > msk = = 0 ) {
match = 1 ;
2004-02-17 08:56:33 +01:00
} else {
2004-02-17 09:52:03 +01:00
maybe = 1 ;
2004-02-17 09:10:07 +01:00
}
2004-02-17 09:52:03 +01:00
} else if ( ! port ) {
/* The port maybe matches. */
maybe = 1 ;
2003-12-09 05:29:52 +01:00
}
} else {
/* Address is known */
2004-02-17 09:52:57 +01:00
if ( ( addr & tmpe - > msk ) = = ( tmpe - > addr & tmpe - > msk ) ) {
if ( port > = tmpe - > prt_min & & port < = tmpe - > prt_max ) {
/* Exact match for the policy */
match = 1 ;
} else if ( ! port ) {
maybe = 1 ;
}
2003-12-09 05:29:52 +01:00
}
}
2004-02-17 09:52:03 +01:00
if ( maybe ) {
2004-11-12 20:39:13 +01:00
if ( tmpe - > policy_type = = ADDR_POLICY_REJECT )
2004-02-17 09:52:03 +01:00
maybe_reject = 1 ;
else
maybe_accept = 1 ;
}
2003-12-09 05:29:52 +01:00
if ( match ) {
2004-11-28 10:05:49 +01:00
if ( tmpe - > policy_type = = ADDR_POLICY_ACCEPT ) {
2004-02-17 08:56:33 +01:00
/* If we already hit a clause that might trigger a 'reject', than we
* can ' t be sure of this certain ' accept ' . */
2005-03-19 07:57:16 +01:00
return maybe_reject ? ADDR_POLICY_PROBABLY_ACCEPTED : ADDR_POLICY_ACCEPTED ;
2004-02-17 08:56:33 +01:00
} else {
2005-03-19 07:57:16 +01:00
return maybe_accept ? ADDR_POLICY_PROBABLY_REJECTED : ADDR_POLICY_REJECTED ;
2004-02-17 08:56:33 +01:00
}
2003-12-09 05:29:52 +01:00
}
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
}
2004-02-17 08:56:33 +01:00
/* accept all by default. */
2005-03-19 07:57:16 +01:00
return maybe_reject ? ADDR_POLICY_PROBABLY_ACCEPTED : ADDR_POLICY_ACCEPTED ;
2003-09-25 07:17:11 +02:00
}
2005-01-12 05:58:23 +01:00
/** Return 1 if all running sufficiently-stable routers will reject
* addr : port , return 0 if any might accept it . */
2005-06-11 20:52:12 +02:00
int
router_exit_policy_all_routers_reject ( uint32_t addr , uint16_t port ,
int need_uptime )
{
2005-03-19 07:57:16 +01:00
addr_policy_result_t r ;
2004-10-14 05:44:45 +02:00
if ( ! routerlist ) return 1 ;
2003-08-23 12:09:25 +02:00
2005-09-13 17:32:03 +02:00
SMARTLIST_FOREACH ( routerlist - > routers , routerinfo_t * , router ,
{
2005-01-12 05:58:23 +01:00
if ( router - > is_running & &
2005-03-19 07:57:16 +01:00
! router_is_unreliable ( router , need_uptime , 0 ) ) {
r = router_compare_addr_to_addr_policy ( addr , port , router - > exit_policy ) ;
if ( r ! = ADDR_POLICY_REJECTED & & r ! = ADDR_POLICY_PROBABLY_REJECTED )
return 0 ; /* this one could be ok. good enough. */
}
2005-09-13 17:32:03 +02:00
} ) ;
2003-12-09 05:29:52 +01:00
return 1 ; /* all will reject. */
2003-08-23 12:09:25 +02:00
}
2005-01-20 19:39:48 +01:00
/**
* If < b > policy < / b > implicitly allows connections to any port in the
* IP set < b > addr < / b > / < b > mask < / b > , then set * < b > policy_out < / b > to the
* part of the policy that allows it , and return 1. Else return 0.
*
* A policy allows an IP : Port combination < em > implicitly < / em > if
* it is included in a * : pattern , or in a fallback pattern .
*/
static int
policy_includes_addr_mask_implicitly ( addr_policy_t * policy ,
uint32_t addr , uint32_t mask ,
addr_policy_t * * policy_out )
{
uint32_t addr2 ;
tor_assert ( policy_out ) ;
addr & = mask ;
addr2 = addr | ~ mask ;
for ( ; policy ; policy = policy - > next ) {
/* Does this policy cover all of the address range we're looking at? */
/* Boolean logic time: range X is contained in range Y if, for
* each bit B , all possible values of B in X are values of B in Y .
* In " addr " , we have every fixed bit set to its value , and every
* free bit set to 0. In " addr2 " , we have every fixed bit set to
* its value , and every free bit set to 1. So if addr and addr2 are
* both in the policy , the range is covered by the policy .
*/
2005-05-14 02:13:17 +02:00
uint32_t p_addr = policy - > addr & policy - > msk ;
if ( p_addr = = ( addr & policy - > msk ) & &
p_addr = = ( addr2 & policy - > msk ) & &
2005-01-20 19:39:48 +01:00
( policy - > prt_min < = 1 & & policy - > prt_max = = 65535 ) ) {
return 0 ;
}
/* Does this policy cover some of the address range we're looking at? */
/* Boolean logic time: range X and range Y intersect if there is
* some z such that z & Xmask = = Xaddr and z & Ymask = = Yaddr .
* This is FALSE iff there is some bit b where Xmask = = yMask = = 1
* and Xaddr ! = Yaddr . So if X intersects with Y iff at every
* place where Xmask & Ymask = = 1 , Xaddr = = Yaddr , or equivalently ,
* Xaddr & Xmask & Ymask = = Yaddr & Xmask & Ymask .
*/
if ( ( policy - > addr & policy - > msk & mask ) = = ( addr & policy - > msk ) & &
policy - > policy_type = = ADDR_POLICY_ACCEPT ) {
* policy_out = policy ;
return 1 ;
}
}
* policy_out = NULL ;
return 1 ;
}
/** If <b>policy</b> implicitly allows connections to any port on
* 127. * , 192.168 . * , etc , then warn ( if < b > warn < / b > is set ) and return
* true . Else return false .
* */
int
exit_policy_implicitly_allows_local_networks ( addr_policy_t * policy ,
int warn )
{
addr_policy_t * p ;
int r = 0 , i ;
static struct {
uint32_t addr ; uint32_t mask ; const char * network ;
} private_networks [ ] = {
2005-06-29 21:15:23 +02:00
{ 0x7f000000 , 0xff000000 , " localhost (127.0.0.0/8) " } ,
{ 0x0a000000 , 0xff000000 , " addresses in private network 10.0.0.0/8 " } ,
{ 0xa9fe0000 , 0xffff0000 , " addresses in private network 169.254.0.0/16 " } ,
{ 0xac100000 , 0xfff00000 , " addresses in private network 172.16.0.0/12 " } ,
{ 0xc0a80000 , 0xffff0000 , " addresses in private network 192.168.0.0/16 " } ,
2005-01-20 19:39:48 +01:00
{ 0 , 0 , NULL } ,
} ;
for ( i = 0 ; private_networks [ i ] . addr ; + + i ) {
p = NULL ;
2005-05-14 02:13:17 +02:00
/* log_fn(LOG_INFO,"Checking network %s", private_networks[i].network); */
if ( policy_includes_addr_mask_implicitly (
2005-01-20 19:39:48 +01:00
policy , private_networks [ i ] . addr , private_networks [ i ] . mask , & p ) ) {
2005-05-14 02:13:17 +02:00
if ( warn )
log_fn ( LOG_WARN , " Exit policy %s implicitly accepts %s " ,
p ? p - > string : " (default) " ,
private_networks [ i ] . network ) ;
r = 1 ;
}
2005-01-20 19:39:48 +01:00
}
return r ;
}
2004-05-10 06:34:48 +02:00
/** Return true iff <b>router</b> does not permit exit streams.
2004-05-04 20:17:45 +02:00
*/
2005-06-11 20:52:12 +02:00
int
router_exit_policy_rejects_all ( routerinfo_t * router )
{
2004-12-05 08:10:08 +01:00
return router_compare_addr_to_addr_policy ( 0 , 0 , router - > exit_policy )
2004-02-17 08:56:33 +01:00
= = ADDR_POLICY_REJECTED ;
2003-05-07 20:30:46 +02:00
}
2004-11-09 18:14:15 +01:00
/** Add to the list of authorized directory servers one at
2005-08-26 21:31:51 +02:00
* < b > address < / b > : < b > port < / b > , with identity key < b > digest < / b > . If
* < b > address < / b > is NULL , add ourself . */
2004-11-09 18:14:15 +01:00
void
2005-09-07 18:42:53 +02:00
add_trusted_dir_server ( const char * address , uint16_t port , const char * digest ,
int supports_v1 )
2004-10-12 17:55:20 +02:00
{
trusted_dir_server_t * ent ;
uint32_t a ;
2005-08-26 21:31:51 +02:00
char * hostname = NULL ;
2004-10-12 17:55:20 +02:00
if ( ! trusted_dir_servers )
trusted_dir_servers = smartlist_create ( ) ;
2005-08-26 21:31:51 +02:00
if ( ! address ) { /* The address is us; we should guess. */
if ( resolve_my_address ( get_options ( ) , & a , & hostname ) < 0 ) {
2005-08-26 09:41:19 +02:00
log_fn ( LOG_WARN , " Couldn't find a suitable address. Returning. " ) ;
return ;
}
2005-08-26 21:25:36 +02:00
} else {
if ( tor_lookup_hostname ( address , & a ) ) {
log_fn ( LOG_WARN , " Unable to lookup address for directory server at %s " ,
address ) ;
return ;
}
2005-08-26 21:31:51 +02:00
hostname = tor_strdup ( address ) ;
2005-08-26 21:25:36 +02:00
a = ntohl ( a ) ;
2004-10-12 17:55:20 +02:00
}
2005-09-13 17:32:03 +02:00
ent = tor_malloc_zero ( sizeof ( trusted_dir_server_t ) ) ;
2005-08-26 21:31:51 +02:00
ent - > address = hostname ;
2005-08-26 09:41:19 +02:00
ent - > addr = a ;
2004-10-12 17:55:20 +02:00
ent - > dir_port = port ;
ent - > is_running = 1 ;
2005-09-07 18:42:53 +02:00
ent - > supports_v1_protocol = supports_v1 ;
2004-10-12 17:55:20 +02:00
memcpy ( ent - > digest , digest , DIGEST_LEN ) ;
2004-10-13 20:28:39 +02:00
smartlist_add ( trusted_dir_servers , ent ) ;
2004-10-12 17:55:20 +02:00
}
2005-03-17 13:38:37 +01:00
/** Remove all members from the list of trusted dir servers. */
2005-06-11 20:52:12 +02:00
void
clear_trusted_dir_servers ( void )
2004-10-12 17:55:20 +02:00
{
if ( trusted_dir_servers ) {
SMARTLIST_FOREACH ( trusted_dir_servers , trusted_dir_server_t * , ent ,
{ tor_free ( ent - > address ) ; tor_free ( ent ) ; } ) ;
smartlist_clear ( trusted_dir_servers ) ;
} else {
trusted_dir_servers = smartlist_create ( ) ;
}
}
2005-06-09 21:03:31 +02:00
2005-09-13 17:32:03 +02:00
/** Return the network status with a given identity digest. */
2005-09-08 08:22:44 +02:00
networkstatus_t *
networkstatus_get_by_digest ( const char * digest )
{
SMARTLIST_FOREACH ( networkstatus_list , networkstatus_t * , ns ,
{
if ( ! memcmp ( ns - > identity_digest , digest , DIGEST_LEN ) )
return ns ;
} ) ;
return NULL ;
}
2005-09-14 23:09:25 +02:00
/** If the network-status list has changed since the last time we called this
* function , update the status of every router from the network - status list .
*/
void
routers_update_all_from_networkstatus ( void )
{
2005-09-21 02:41:06 +02:00
# define SELF_OPINION_INTERVAL 90*60
2005-09-14 23:09:25 +02:00
static int have_warned_about_unverified_status = 0 ;
2005-09-21 02:41:06 +02:00
static int have_warned_about_old_version = 0 ;
static int have_warned_about_new_version = 0 ;
2005-09-14 23:09:25 +02:00
routerinfo_t * me ;
2005-09-18 04:24:42 +02:00
time_t now ;
if ( ! routerlist | | ! networkstatus_list | |
( ! networkstatus_list_has_changed & & ! routerstatus_list_has_changed ) )
2005-09-14 23:09:25 +02:00
return ;
2005-09-18 04:24:42 +02:00
now = time ( NULL ) ;
if ( networkstatus_list_has_changed )
routerstatus_list_update_from_networkstatus ( now ) ;
2005-09-18 04:51:12 +02:00
routers_update_status_from_networkstatus ( routerlist - > routers , 0 ) ;
2005-09-14 23:09:25 +02:00
me = router_get_my_routerinfo ( ) ;
2005-09-21 02:41:06 +02:00
if ( me & & ! have_warned_about_unverified_status ) {
int n_recent = 0 , n_listing = 0 , n_valid = 0 , n_named = 0 ;
routerstatus_t * rs ;
SMARTLIST_FOREACH ( networkstatus_list , networkstatus_t * , ns ,
{
if ( ns - > received_on + SELF_OPINION_INTERVAL < now )
continue ;
+ + n_recent ;
if ( ! ( rs = networkstatus_find_entry ( ns , me - > identity_digest ) ) )
continue ;
+ + n_listing ;
if ( rs - > is_valid )
+ + n_valid ;
if ( rs - > is_named )
+ + n_named ;
} ) ;
if ( n_recent > = 2 & & n_listing > = 2 ) {
if ( n_valid < = n_recent / 2 ) {
log_fn ( LOG_WARN , " %d/%d recent directory servers list us as invalid. Please consider sending your identity fingerprint to the tor-ops. " ,
n_recent - n_valid , n_recent ) ;
have_warned_about_unverified_status = 1 ;
} else if ( n_named < = n_recent / 2 ) {
log_fn ( LOG_WARN , " %d/%d recent directory servers list us as unnamed. Please consider sending your identity fingerprint to the tor-ops. " ,
n_recent - n_valid , n_recent ) ;
have_warned_about_unverified_status = 1 ;
}
2005-09-14 23:09:25 +02:00
}
}
helper_nodes_set_status_from_directory ( ) ;
2005-09-21 02:41:06 +02:00
if ( ! have_warned_about_old_version ) {
int n_recent = 0 ;
int n_recommended = 0 ;
int is_server = server_mode ( get_options ( ) ) ;
version_status_t consensus = VS_RECOMMENDED ;
SMARTLIST_FOREACH ( networkstatus_list , networkstatus_t * , ns ,
{
version_status_t vs ;
2005-09-21 04:38:51 +02:00
if ( ! ns - > recommends_versions | |
ns - > received_on + SELF_OPINION_INTERVAL < now )
2005-09-21 02:41:06 +02:00
continue ;
vs = tor_version_is_obsolete (
VERSION , is_server ? ns - > server_versions : ns - > client_versions ) ;
if ( vs = = VS_RECOMMENDED )
+ + n_recommended ;
if ( n_recent + + = = 0 ) {
consensus = vs ;
} else if ( consensus ! = vs ) {
consensus = version_status_join ( consensus , vs ) ;
}
} ) ;
if ( n_recent > 2 & & n_recommended < n_recent / 2 ) {
if ( consensus = = VS_NEW | | consensus = = VS_NEW_IN_SERIES ) {
if ( ! have_warned_about_new_version ) {
log_fn ( LOG_NOTICE , " This version of Tor (%s) is newer than any recommended version%s, according to %d/%d recent network statuses. " ,
VERSION , consensus = = VS_NEW_IN_SERIES ? " in its series " : " " ,
n_recent - n_recommended , n_recent ) ;
have_warned_about_new_version = 1 ;
}
} else {
log_fn ( LOG_NOTICE , " This version of Tor (%s) is %s, according to %d/%d recent network statuses. " ,
VERSION , consensus = = VS_OLD ? " obsolete " : " not recommended " ,
n_recent - n_recommended , n_recent ) ;
have_warned_about_old_version = 1 ;
}
} else {
2005-09-21 04:38:51 +02:00
log_fn ( LOG_INFO , " %d/%d recent directories think my version is ok. " ,
2005-09-21 02:41:06 +02:00
n_recommended , n_recent ) ;
}
}
2005-09-18 04:24:42 +02:00
routerstatus_list_has_changed = 0 ;
2005-09-14 23:09:25 +02:00
}
2005-09-13 17:32:03 +02:00
/** Allow any network-status newer than this to influence our view of who's
* running . */
2005-09-12 08:56:42 +02:00
# define DEFAULT_RUNNING_INTERVAL 60*60
2005-09-13 17:32:03 +02:00
/** If possible, always allow at least this many network-statuses to influence
* our view of who ' s running . */
2005-09-12 08:56:42 +02:00
# define MIN_TO_INFLUENCE_RUNNING 3
2005-09-18 04:24:42 +02:00
2005-09-30 22:04:55 +02:00
/** Change the is_recent field of each member of networkstatus_list so that
* all members more recent than DEFAULT_RUNNING_INTERVAL are recent , and
* at least the MIN_TO_INFLUENCE_RUNNING most recent members are resent , and no
* others are recent . Set networkstatus_list_has_changed if anything happeed .
*/
2005-09-12 08:56:42 +02:00
void
2005-09-18 04:24:42 +02:00
networkstatus_list_update_recent ( time_t now )
2005-09-12 08:56:42 +02:00
{
2005-09-18 04:24:42 +02:00
int n_statuses , n_recent , changed , i ;
char published [ ISO_TIME_LEN + 1 ] ;
2005-09-12 08:56:42 +02:00
2005-09-18 04:24:42 +02:00
if ( ! networkstatus_list )
2005-09-12 08:56:42 +02:00
return ;
2005-09-18 04:24:42 +02:00
n_statuses = smartlist_len ( networkstatus_list ) ;
n_recent = 0 ;
changed = 0 ;
for ( i = n_statuses - 1 ; i > = 0 ; - - i ) {
networkstatus_t * ns = smartlist_get ( networkstatus_list , i ) ;
if ( n_recent < MIN_TO_INFLUENCE_RUNNING | |
ns - > published_on + DEFAULT_RUNNING_INTERVAL > now ) {
if ( ! ns - > is_recent ) {
format_iso_time ( published , ns - > published_on ) ;
log_fn ( LOG_NOTICE ,
" Networkstatus from %s:%d (published %s) is now \" recent \" " ,
ns - > source_address , ns - > source_dirport , published ) ;
changed = 1 ;
}
ns - > is_recent = 1 ;
+ + n_recent ;
} else {
if ( ns - > is_recent ) {
format_iso_time ( published , ns - > published_on ) ;
log_fn ( LOG_NOTICE ,
" Networkstatus from %s:%d (published %s) is no longer \" recent \" " ,
ns - > source_address , ns - > source_dirport , published ) ;
changed = 1 ;
ns - > is_recent = 0 ;
}
}
2005-09-12 08:56:42 +02:00
}
2005-09-18 04:24:42 +02:00
if ( changed )
networkstatus_list_has_changed = 1 ;
}
2005-09-30 22:04:55 +02:00
/** Update our view of router status (as stored in routerstatus_list) from
* the current set of network status documents ( as stored in networkstatus_list ) .
* Do nothing unless the network status list has changed since the last time
* this function was called .
*/
2005-09-18 04:24:42 +02:00
static void
routerstatus_list_update_from_networkstatus ( time_t now )
{
int n_trusted , n_statuses , n_recent = 0 , n_naming = 0 ;
int n_distinct = 0 ;
int i ;
2005-09-22 03:51:14 +02:00
int * index , * size ;
networkstatus_t * * networkstatus ;
smartlist_t * result ;
2005-09-22 08:34:29 +02:00
strmap_t * name_map ;
char conflict [ DIGEST_LEN ] ;
2005-09-18 04:24:42 +02:00
networkstatus_list_update_recent ( now ) ;
2005-09-12 08:56:42 +02:00
2005-09-18 04:24:42 +02:00
if ( ! networkstatus_list_has_changed )
return ;
2005-09-12 08:56:42 +02:00
if ( ! networkstatus_list )
networkstatus_list = smartlist_create ( ) ;
2005-09-18 04:24:42 +02:00
if ( ! routerstatus_list )
routerstatus_list = smartlist_create ( ) ;
2005-09-12 08:56:42 +02:00
if ( ! trusted_dir_servers )
trusted_dir_servers = smartlist_create ( ) ;
n_trusted = smartlist_len ( trusted_dir_servers ) ;
n_statuses = smartlist_len ( networkstatus_list ) ;
if ( n_statuses < ( n_trusted / 2 ) + 1 ) {
/* Not enough statuses to adjust status. */
2005-09-18 04:24:42 +02:00
log_fn ( LOG_NOTICE , " Not enough statuses to update router status list. (%d/%d) " ,
n_statuses , n_trusted ) ;
2005-09-12 08:56:42 +02:00
return ;
}
2005-09-18 04:24:42 +02:00
log_fn ( LOG_NOTICE , " rebuilding router status list. " ) ;
2005-09-12 08:56:42 +02:00
2005-09-22 03:51:14 +02:00
index = tor_malloc ( sizeof ( int ) * n_statuses ) ;
size = tor_malloc ( sizeof ( int ) * n_statuses ) ;
networkstatus = tor_malloc ( sizeof ( networkstatus_t * ) * n_statuses ) ;
for ( i = 0 ; i < n_statuses ; + + i ) {
index [ i ] = 0 ;
networkstatus [ i ] = smartlist_get ( networkstatus_list , i ) ;
size [ i ] = smartlist_len ( networkstatus [ i ] - > entries ) ;
if ( networkstatus [ i ] - > binds_names )
2005-09-18 04:24:42 +02:00
+ + n_naming ;
2005-09-22 03:51:14 +02:00
if ( networkstatus [ i ] - > is_recent )
2005-09-18 04:24:42 +02:00
+ + n_recent ;
2005-09-22 03:51:14 +02:00
}
2005-09-12 08:56:42 +02:00
2005-09-22 08:34:29 +02:00
name_map = strmap_new ( ) ;
memset ( conflict , 0xff , sizeof ( conflict ) ) ;
for ( i = 0 ; i < n_statuses ; + + i ) {
if ( ! networkstatus [ i ] - > binds_names )
continue ;
SMARTLIST_FOREACH ( networkstatus [ i ] - > entries , routerstatus_t * , rs ,
{
const char * other_digest ;
if ( ! rs - > is_named )
continue ;
other_digest = strmap_get_lc ( name_map , rs - > nickname ) ;
if ( ! other_digest )
strmap_set_lc ( name_map , rs - > nickname , rs - > identity_digest ) ;
else if ( memcmp ( other_digest , rs - > identity_digest , DIGEST_LEN ) & &
other_digest ! = conflict ) {
/*XXXX011 rate-limit this?*/
log_fn ( LOG_WARN ,
" Naming authorities disagree about which key goes with %s. " ,
rs - > nickname ) ;
strmap_set_lc ( name_map , rs - > nickname , conflict ) ;
}
} ) ;
}
2005-09-22 03:51:14 +02:00
result = smartlist_create ( ) ;
/* Iterate through all of the sorted routerstatus lists in step.
* Invariants :
* - For 0 < = i < n_statuses : index [ i ] is an index into
* networkstatus [ i ] - > entries , which has size [ i ] elements .
* - For i1 , i2 , j such that 0 < = i1 < n_statuses , 0 < = i2 < n_statues , 0 < =
* j < index [ i1 ] , networkstatus [ i1 ] - > entries [ j ] - > identity_digest <
* networkstatus [ i2 ] - > entries [ index [ i2 ] ] - > identity_digest .
*
* ( That is , the indices are always advanced past lower digest before
* higher . )
*/
while ( 1 ) {
2005-09-18 04:24:42 +02:00
int n_running = 0 , n_named = 0 , n_valid = 0 , n_listing = 0 ;
const char * the_name = NULL ;
2005-09-22 03:51:14 +02:00
local_routerstatus_t * rs_out , * rs_old ;
routerstatus_t * rs , * most_recent ;
networkstatus_t * ns ;
const char * lowest = NULL ;
/* Find out which of the digests appears first. */
for ( i = 0 ; i < n_statuses ; + + i ) {
if ( index [ i ] < size [ i ] ) {
rs = smartlist_get ( networkstatus [ i ] - > entries , index [ i ] ) ;
if ( ! lowest | | memcmp ( rs - > identity_digest , lowest , DIGEST_LEN ) < 0 )
lowest = rs - > identity_digest ;
}
}
if ( ! lowest ) {
/* We're out of routers. Great! */
break ;
}
/* Okay. The routers at networkstatus[i]->entries[index[i]] whose digests
* match " lowest " are next in order . Iterate over them , incrementing those
* index [ i ] as we go . */
2005-09-18 04:24:42 +02:00
+ + n_distinct ;
2005-09-22 03:51:14 +02:00
most_recent = NULL ;
for ( i = 0 ; i < n_statuses ; + + i ) {
if ( index [ i ] > = size [ i ] )
2005-09-12 08:56:42 +02:00
continue ;
2005-09-22 03:51:14 +02:00
ns = networkstatus [ i ] ;
rs = smartlist_get ( ns - > entries , index [ i ] ) ;
if ( memcmp ( rs - > identity_digest , lowest , DIGEST_LEN ) )
continue ;
+ + index [ i ] ;
2005-09-12 08:56:42 +02:00
+ + n_listing ;
2005-09-22 03:51:14 +02:00
if ( ! most_recent | | rs - > published_on > most_recent - > published_on )
2005-09-18 04:24:42 +02:00
most_recent = rs ;
if ( rs - > is_named & & ns - > binds_names ) {
if ( ! the_name )
the_name = rs - > nickname ;
if ( ! strcasecmp ( rs - > nickname , the_name ) ) {
+ + n_named ;
2005-09-22 08:34:29 +02:00
} else if ( strcmp ( the_name , " **mismatch** " ) ) {
char hd [ HEX_DIGEST_LEN + 1 ] ;
base16_encode ( hd , HEX_DIGEST_LEN + 1 , rs - > identity_digest , DIGEST_LEN ) ;
log_fn ( LOG_WARN , " Naming authorities disagree about nicknames for $%s " ,
hd ) ;
2005-09-18 04:24:42 +02:00
the_name = " **mismatch** " ;
}
}
2005-09-12 08:56:42 +02:00
if ( rs - > is_valid )
+ + n_valid ;
2005-09-18 04:24:42 +02:00
if ( rs - > is_running & & ns - > is_recent )
+ + n_running ;
2005-09-22 03:51:14 +02:00
}
2005-09-23 20:05:14 +02:00
rs_out = tor_malloc_zero ( sizeof ( local_routerstatus_t ) ) ;
2005-09-22 03:51:14 +02:00
memcpy ( & rs_out - > status , most_recent , sizeof ( routerstatus_t ) ) ;
if ( ( rs_old = router_get_combined_status_by_digest ( lowest ) ) ) {
rs_out - > n_download_failures = rs_old - > n_download_failures ;
2005-09-22 08:34:29 +02:00
rs_out - > next_attempt_at = rs_old - > next_attempt_at ;
2005-09-18 04:24:42 +02:00
}
smartlist_add ( result , rs_out ) ;
log_fn ( LOG_DEBUG , " Router '%s' is listed by %d/%d directories, "
2005-09-12 08:56:42 +02:00
" named by %d/%d, validated by %d/%d, and %d/%d recent directories "
" think it's running. " ,
2005-09-22 03:51:14 +02:00
rs_out - > status . nickname ,
2005-09-12 08:56:42 +02:00
n_listing , n_statuses , n_named , n_naming , n_valid , n_statuses ,
n_running , n_recent ) ;
2005-09-22 08:34:29 +02:00
rs_out - > status . is_named = 0 ;
if ( the_name & & strcmp ( the_name , " **mismatch** " ) & & n_named > 0 ) {
const char * d = strmap_get_lc ( name_map , the_name ) ;
if ( d & & d ! = conflict )
rs_out - > status . is_named = 1 ;
}
2005-09-22 03:51:14 +02:00
if ( rs_out - > status . is_named )
strlcpy ( rs_out - > status . nickname , the_name , sizeof ( rs_out - > status . nickname ) ) ;
rs_out - > status . is_valid = n_valid > n_statuses / 2 ;
rs_out - > status . is_running = n_running > n_recent / 2 ;
2005-09-18 04:24:42 +02:00
}
2005-09-30 23:04:52 +02:00
SMARTLIST_FOREACH ( routerstatus_list , local_routerstatus_t * , rs ,
local_routerstatus_free ( rs ) ) ;
2005-09-18 04:24:42 +02:00
smartlist_free ( routerstatus_list ) ;
routerstatus_list = result ;
2005-09-22 03:51:14 +02:00
tor_free ( networkstatus ) ;
tor_free ( index ) ;
tor_free ( size ) ;
2005-09-22 08:34:29 +02:00
strmap_free ( name_map , NULL ) ;
2005-09-22 03:51:14 +02:00
2005-09-18 04:24:42 +02:00
networkstatus_list_has_changed = 0 ;
routerstatus_list_has_changed = 1 ;
}
/** Given a list <b>routers</b> of routerinfo_t *, update each routers's
* is_named , is_verified , and is_running fields according to our current
* networkstatus_t documents . */
void
2005-09-18 04:51:12 +02:00
routers_update_status_from_networkstatus ( smartlist_t * routers , int reset_failures )
2005-09-18 04:24:42 +02:00
{
trusted_dir_server_t * ds ;
2005-09-22 03:51:14 +02:00
local_routerstatus_t * rs ;
2005-09-18 04:24:42 +02:00
or_options_t * options = get_options ( ) ;
int authdir = options - > AuthoritativeDir ;
int namingdir = options - > NamingAuthoritativeDir ;
if ( ! routerstatus_list )
return ;
SMARTLIST_FOREACH ( routers , routerinfo_t * , router ,
{
rs = router_get_combined_status_by_digest ( router - > identity_digest ) ;
ds = router_get_trusteddirserver_by_digest ( router - > identity_digest ) ;
if ( ! rs )
continue ;
2005-09-22 08:34:29 +02:00
if ( reset_failures ) {
2005-09-18 04:51:12 +02:00
rs - > n_download_failures = 0 ;
2005-09-22 08:34:29 +02:00
rs - > next_attempt_at = 0 ;
}
2005-09-18 04:51:12 +02:00
2005-09-18 04:24:42 +02:00
if ( ! namingdir )
2005-09-22 03:51:14 +02:00
router - > is_named = rs - > status . is_named ;
2005-09-12 08:56:42 +02:00
2005-09-16 06:53:28 +02:00
if ( ! authdir ) {
/* If we're an authdir, don't believe others. */
2005-09-22 03:51:14 +02:00
router - > is_verified = rs - > status . is_valid ;
router - > is_running = rs - > status . is_running ;
2005-09-15 16:39:05 +02:00
if ( router - > is_running & & ds ) {
2005-09-16 18:41:45 +02:00
/* XXXX011 NM Hm. What about authorities? When do they reset
2005-09-15 16:39:05 +02:00
* n_networkstatus_failures ? */
ds - > n_networkstatus_failures = 0 ;
}
}
2005-09-12 08:56:42 +02:00
} ) ;
}
2005-09-15 07:19:38 +02:00
/** Return new list of ID fingerprints for superseded routers. A router is
2005-09-13 17:32:03 +02:00
* superseded if any network - status has a router with a different digest
2005-09-30 01:03:34 +02:00
* published more recently , or if it is listed in the network - status but not
2005-09-13 17:32:03 +02:00
* in the router list .
2005-09-12 08:56:42 +02:00
*/
2005-09-15 07:41:30 +02:00
static smartlist_t *
2005-09-15 07:19:38 +02:00
router_list_downloadable ( void )
2005-09-12 08:56:42 +02:00
{
2005-09-23 23:25:29 +02:00
# define MAX_OLD_SERVER_DOWNLOAD_RATE 2*60*60
2005-09-22 08:34:29 +02:00
int n_conns , i , n_downloadable = 0 ;
2005-09-23 23:25:29 +02:00
int n_uptodate = 0 , n_skip_old = 0 ;
2005-09-22 08:34:29 +02:00
connection_t * * carray ;
2005-09-12 08:56:42 +02:00
smartlist_t * superseded = smartlist_create ( ) ;
2005-09-22 08:34:29 +02:00
smartlist_t * downloading ;
2005-09-18 04:24:42 +02:00
time_t now = time ( NULL ) ;
2005-09-23 23:33:59 +02:00
int mirror = server_mode ( get_options ( ) ) & & get_options ( ) - > DirPort ;
2005-09-12 08:56:42 +02:00
2005-09-18 04:24:42 +02:00
if ( ! routerstatus_list )
2005-09-12 08:56:42 +02:00
return superseded ;
2005-09-22 08:34:29 +02:00
get_connection_array ( & carray , & n_conns ) ;
2005-09-18 04:24:42 +02:00
routerstatus_list_update_from_networkstatus ( now ) ;
2005-09-22 03:51:14 +02:00
SMARTLIST_FOREACH ( routerstatus_list , local_routerstatus_t * , rs ,
2005-09-12 08:56:42 +02:00
{
2005-09-22 08:34:29 +02:00
if ( rs - > next_attempt_at < now ) {
rs - > should_download = 1 ;
+ + n_downloadable ;
} else {
2005-09-23 20:17:37 +02:00
/*
2005-09-23 20:05:14 +02:00
char fp [ HEX_DIGEST_LEN + 1 ] ;
base16_encode ( fp , HEX_DIGEST_LEN + 1 , rs - > status . identity_digest , DIGEST_LEN ) ;
log_fn ( LOG_NOTICE , " Not yet ready to download %s (%d more seconds) " , fp ,
( int ) ( rs - > next_attempt_at - now ) ) ;
2005-09-23 20:17:37 +02:00
*/
2005-09-22 08:34:29 +02:00
rs - > should_download = 0 ;
}
2005-09-12 08:56:42 +02:00
} ) ;
2005-09-13 17:32:03 +02:00
2005-09-22 08:34:29 +02:00
downloading = smartlist_create ( ) ;
for ( i = 0 ; i < n_conns ; + + i ) {
connection_t * conn = carray [ i ] ;
if ( conn - > type = = CONN_TYPE_DIR & &
conn - > purpose = = DIR_PURPOSE_FETCH_SERVERDESC & &
! conn - > marked_for_close ) {
if ( ! strcmpstart ( conn - > requested_resource , " all " ) )
n_downloadable = 0 ;
dir_split_resource_into_fingerprints ( conn - > requested_resource ,
downloading , NULL ) ;
}
}
2005-09-23 20:05:14 +02:00
/*
log_fn ( LOG_NOTICE , " %d downloads already in progress " ,
smartlist_len ( downloading ) ) ;
smartlist_sort_strings ( downloading ) ;
*/
2005-09-22 08:34:29 +02:00
if ( n_downloadable ) {
SMARTLIST_FOREACH ( downloading , const char * , dl ,
{
char d [ DIGEST_LEN ] ;
local_routerstatus_t * rs ;
base16_decode ( d , DIGEST_LEN , dl , strlen ( dl ) ) ;
if ( ( rs = router_get_combined_status_by_digest ( d ) ) & & rs - > should_download ) {
rs - > should_download = 0 ;
- - n_downloadable ;
2005-09-23 20:05:14 +02:00
// log_fn(LOG_NOTICE, "%s is in-progress; not fetching", dl);
2005-09-22 08:34:29 +02:00
}
} ) ;
}
SMARTLIST_FOREACH ( downloading , char * , cp , tor_free ( cp ) ) ;
smartlist_free ( downloading ) ;
if ( ! n_downloadable )
return superseded ;
2005-09-15 07:19:38 +02:00
if ( routerlist ) {
SMARTLIST_FOREACH ( routerlist - > routers , routerinfo_t * , ri ,
{
2005-09-22 08:34:29 +02:00
local_routerstatus_t * rs ;
if ( ! ( rs = router_get_combined_status_by_digest ( ri - > identity_digest ) ) | |
! rs - > should_download ) {
2005-09-18 04:24:42 +02:00
// log_fn(LOG_NOTICE, "No status for %s", fp);
2005-09-15 07:19:38 +02:00
continue ;
}
2005-09-22 08:34:29 +02:00
/* Change this "or" to be an "and" once dirs generate hashes right.
2005-09-23 23:25:29 +02:00
* Remove the version check once older versions are uncommon .
2005-09-22 08:34:29 +02:00
* XXXXX . NM */
if ( ! memcmp ( ri - > signed_descriptor_digest , rs - > status . descriptor_digest ,
DIGEST_LEN ) | |
rs - > status . published_on < = ri - > published_on ) {
2005-09-23 23:25:29 +02:00
+ + n_uptodate ;
rs - > should_download = 0 ;
- - n_downloadable ;
2005-09-23 23:33:59 +02:00
} else if ( ! mirror & &
ri - > platform & &
2005-09-23 23:25:29 +02:00
! tor_version_as_new_as ( ri - > platform , " 0.1.1.6-alpha " ) & &
ri - > published_on + MAX_OLD_SERVER_DOWNLOAD_RATE > now ) {
/* Same digest, or date is up-to-date, or we have a comparatively recent
* server with an old version .
* No need to download it . */
2005-09-18 04:24:42 +02:00
// log_fn(LOG_NOTICE, "Up-to-date status for %s", fp);
2005-09-23 23:25:29 +02:00
+ + n_skip_old ;
2005-09-22 08:34:29 +02:00
rs - > should_download = 0 ;
- - n_downloadable ;
2005-09-23 22:31:07 +02:00
} /* else {
2005-09-18 04:24:42 +02:00
char t1 [ ISO_TIME_LEN + 1 ] ;
char t2 [ ISO_TIME_LEN + 1 ] ;
2005-09-23 22:31:07 +02:00
format_iso_time ( t1 , rs - > satus . published_on ) ;
2005-09-18 04:24:42 +02:00
format_iso_time ( t2 , ri - > published_on ) ;
log_fn ( LOG_NOTICE , " Out-of-date status for %s %s (%d %d) [%s %s] " , fp ,
ri - > nickname ,
2005-09-23 22:31:07 +02:00
! memcmp ( ri - > signed_descriptor_digest , rs - > status . descriptor_digest ,
DIGEST_LEN ) ,
2005-09-18 04:24:42 +02:00
rs - > published_on < ri - > published_on ,
t1 , t2 ) ;
2005-09-23 22:31:07 +02:00
} */
2005-09-15 07:19:38 +02:00
} ) ;
}
2005-09-23 23:25:29 +02:00
if ( n_skip_old )
log_fn ( LOG_INFO , " Skipped %d updatable pre-0.1.1.6 servers. " , n_skip_old ) ;
2005-09-22 08:34:29 +02:00
if ( ! n_downloadable )
return superseded ;
2005-09-13 17:32:03 +02:00
2005-09-22 08:34:29 +02:00
SMARTLIST_FOREACH ( routerstatus_list , local_routerstatus_t * , rs ,
{
if ( rs - > should_download ) {
char * fp = tor_malloc ( HEX_DIGEST_LEN + 1 ) ;
base16_encode ( fp , HEX_DIGEST_LEN + 1 , rs - > status . identity_digest , DIGEST_LEN ) ;
smartlist_add ( superseded , fp ) ;
}
} ) ;
2005-09-16 06:43:21 +02:00
2005-09-12 08:56:42 +02:00
return superseded ;
}
2005-09-15 08:15:31 +02:00
/** Initiate new router downloads as needed.
*
* We only allow one router descriptor download at a time .
* If we have less than two network - status documents , we ask
* a directory for " all descriptors. "
* Otherwise , we ask for all descriptors that we think are different
* from what we have .
*/
2005-09-15 07:19:38 +02:00
void
update_router_descriptor_downloads ( time_t now )
{
2005-09-22 08:34:29 +02:00
# define MAX_DL_PER_REQUEST 128
2005-09-23 20:05:14 +02:00
# define MIN_DL_PER_REQUEST 4
2005-09-22 08:34:29 +02:00
# define MIN_REQUESTS 3
2005-09-30 22:04:55 +02:00
# define MAX_DL_TO_DELAY 16
# define MAX_INTERVAL_WITHOUT_REQUEST 10*60
2005-09-18 04:24:42 +02:00
smartlist_t * downloadable = NULL ;
int get_all = 0 ;
2005-09-30 22:04:55 +02:00
int mirror = server_mode ( get_options ( ) ) & & get_options ( ) - > DirPort ;
static time_t last_download_attempted = 0 ;
2005-09-18 04:24:42 +02:00
if ( ! networkstatus_list | | smartlist_len ( networkstatus_list ) < 2 )
get_all = 1 ;
if ( get_all ) {
log_fn ( LOG_NOTICE , " Launching request for all routers " ) ;
2005-09-30 22:04:55 +02:00
last_download_attempted = now ;
2005-09-18 04:24:42 +02:00
directory_get_from_dirserver ( DIR_PURPOSE_FETCH_SERVERDESC , " all.z " , 1 ) ;
2005-09-23 20:05:14 +02:00
return ;
}
downloadable = router_list_downloadable ( ) ;
2005-09-30 22:04:55 +02:00
if ( smartlist_len ( downloadable ) > = MAX_DL_TO_DELAY | |
( smartlist_len ( downloadable ) & &
( mirror | |
last_download_attempted + MAX_INTERVAL_WITHOUT_REQUEST < now ) ) ) {
2005-09-23 20:08:31 +02:00
int i , j , n , n_per_request = MAX_DL_PER_REQUEST ;
2005-09-22 08:34:29 +02:00
size_t r_len = MAX_DL_PER_REQUEST * ( HEX_DIGEST_LEN + 1 ) + 16 ;
2005-09-18 04:24:42 +02:00
char * resource = tor_malloc ( r_len ) ;
2005-09-23 20:05:14 +02:00
2005-09-18 04:24:42 +02:00
n = smartlist_len ( downloadable ) ;
2005-09-30 22:04:55 +02:00
if ( ! mirror ) {
2005-09-23 20:08:31 +02:00
n_per_request = ( n + MIN_REQUESTS - 1 ) / MIN_REQUESTS ;
if ( n_per_request > MAX_DL_PER_REQUEST )
n_per_request = MAX_DL_PER_REQUEST ;
if ( n_per_request < MIN_DL_PER_REQUEST )
n_per_request = MIN_DL_PER_REQUEST ;
}
2005-09-23 20:05:14 +02:00
log_fn ( LOG_NOTICE , " Launching %d request%s for %d router%s, %d at a time " ,
( n + n_per_request - 1 ) / n_per_request , n > n_per_request ? " s " : " " ,
n , n > 1 ? " s " : " " , n_per_request ) ;
2005-09-22 08:34:29 +02:00
for ( i = 0 ; i < n ; i + = n_per_request ) {
2005-09-18 04:24:42 +02:00
char * cp = resource ;
memcpy ( resource , " fp/ " , 3 ) ;
cp = resource + 3 ;
2005-09-22 08:34:29 +02:00
for ( j = i ; j < i + n_per_request & & j < n ; + + j ) {
2005-09-18 04:24:42 +02:00
memcpy ( cp , smartlist_get ( downloadable , j ) , HEX_DIGEST_LEN ) ;
cp + = HEX_DIGEST_LEN ;
* cp + + = ' + ' ;
}
memcpy ( cp - 1 , " .z " , 3 ) ;
2005-09-30 22:04:55 +02:00
last_download_attempted = now ;
2005-09-18 04:24:42 +02:00
directory_get_from_dirserver ( DIR_PURPOSE_FETCH_SERVERDESC , resource , 1 ) ;
}
tor_free ( resource ) ;
}
2005-09-23 20:05:14 +02:00
SMARTLIST_FOREACH ( downloadable , char * , c , tor_free ( c ) ) ;
smartlist_free ( downloadable ) ;
2005-09-15 07:19:38 +02:00
}
2005-09-15 08:15:31 +02:00
/** Return true iff we have enough networkstatus and router information to
* start building circuits . Right now , this means " at least 2 networkstatus
* documents , and at least 1 / 4 of expected routers . " */
2005-09-15 07:19:38 +02:00
int
router_have_minimum_dir_info ( void )
{
int tot = 0 , avg ;
if ( ! networkstatus_list | | smartlist_len ( networkstatus_list ) < 2 | |
! routerlist )
return 0 ;
SMARTLIST_FOREACH ( networkstatus_list , networkstatus_t * , ns ,
tot + = smartlist_len ( ns - > entries ) ) ;
avg = tot / smartlist_len ( networkstatus_list ) ;
return smartlist_len ( routerlist - > routers ) > ( avg / 4 ) ;
}
2005-09-30 22:04:55 +02:00
/** Reset the descriptor download failure count on all routers, so that we
* can retry any long - failed routers immediately .
*/
2005-09-22 08:34:29 +02:00
void
router_reset_descriptor_download_failures ( void )
{
if ( ! routerstatus_list )
return ;
SMARTLIST_FOREACH ( routerstatus_list , local_routerstatus_t * , rs ,
{
rs - > n_download_failures = 0 ;
rs - > next_attempt_at = 0 ;
} ) ;
}
2005-09-23 19:11:20 +02:00