2006-02-09 06:46:49 +01:00
|
|
|
/* Copyright (c) 2001 Matej Pfajfar.
|
|
|
|
* Copyright (c) 2001-2004, Roger Dingledine.
|
2007-02-12 22:39:53 +01:00
|
|
|
* Copyright (c) 2004-2007, 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$ */
|
2005-12-14 21:40:40 +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
|
|
|
/****************************************************************************/
|
|
|
|
|
2002-09-24 12:43:57 +02:00
|
|
|
/* static function prototypes */
|
2005-12-14 23:00:58 +01:00
|
|
|
static routerstatus_t *router_pick_directory_server_impl(int requireother,
|
|
|
|
int fascistfirewall,
|
2007-01-03 07:33:03 +01:00
|
|
|
int prefer_tunnel,
|
2005-12-14 23:00:58 +01:00
|
|
|
int for_v2_directory);
|
|
|
|
static routerstatus_t *router_pick_trusteddirserver_impl(
|
2007-01-03 07:33:03 +01:00
|
|
|
authority_type_t type, int requireother,
|
|
|
|
int fascistfirewall, int prefer_tunnel);
|
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_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);
|
2005-10-05 07:03:52 +02:00
|
|
|
static void trusted_dir_server_free(trusted_dir_server_t *ds);
|
|
|
|
static void update_networkstatus_cache_downloads(time_t now);
|
|
|
|
static void update_networkstatus_client_downloads(time_t now);
|
2005-12-27 06:26:03 +01:00
|
|
|
static int signed_desc_digest_is_recognized(signed_descriptor_t *desc);
|
2005-10-18 22:13:09 +02:00
|
|
|
static void routerlist_assert_ok(routerlist_t *rl);
|
2006-04-07 06:52:32 +02:00
|
|
|
static int have_tried_downloading_all_statuses(int n_failures);
|
2006-03-27 07:07:57 +02:00
|
|
|
static routerstatus_t *networkstatus_find_entry(networkstatus_t *ns,
|
|
|
|
const char *digest);
|
2006-04-24 19:51:31 +02:00
|
|
|
static local_routerstatus_t *router_get_combined_status_by_nickname(
|
|
|
|
const char *nickname,
|
|
|
|
int warn_if_unnamed);
|
2006-08-15 05:54:09 +02:00
|
|
|
static void update_router_have_minimum_dir_info(void);
|
|
|
|
static void router_dir_info_changed(void);
|
2003-12-09 05:29:52 +01:00
|
|
|
|
|
|
|
/****************************************************************************/
|
2003-12-13 02:43:21 +01:00
|
|
|
|
2005-11-01 04:48:51 +01:00
|
|
|
/** Global list of a trusted_dir_server_t object for each trusted directory
|
|
|
|
* server. */
|
|
|
|
static smartlist_t *trusted_dir_servers = NULL;
|
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
|
|
|
|
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-11-01 04:48:51 +01:00
|
|
|
|
2006-09-20 01:48:14 +02:00
|
|
|
/** Global list of local_routerstatus_t for each router, known or unknown.
|
|
|
|
* Kept sorted by digest. */
|
2005-09-18 04:24:42 +02:00
|
|
|
static smartlist_t *routerstatus_list = NULL;
|
2005-11-01 04:48:51 +01:00
|
|
|
|
2006-09-20 01:48:14 +02:00
|
|
|
/** Map from lowercase nickname to digest of named server, if any. */
|
|
|
|
static strmap_t *named_server_map = 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-11-01 04:48:51 +01:00
|
|
|
|
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-11-01 04:48:51 +01:00
|
|
|
|
2005-10-05 03:53:44 +02:00
|
|
|
/** List of strings for nicknames we've already warned about and that are
|
|
|
|
* still unknown / unavailable. */
|
|
|
|
static smartlist_t *warned_nicknames = NULL;
|
2005-11-01 04:48:51 +01:00
|
|
|
|
2005-10-05 03:53:44 +02:00
|
|
|
/** List of strings for nicknames or fingerprints we've already warned about
|
|
|
|
* and that are still conflicted. */
|
|
|
|
static smartlist_t *warned_conflicts = NULL;
|
2005-09-05 01:12:27 +02:00
|
|
|
|
2005-10-11 03:57:28 +02:00
|
|
|
/** The last time we tried to download any routerdesc, or 0 for "never". We
|
|
|
|
* use this to rate-limit download attempts when the number of routerdescs to
|
|
|
|
* download is low. */
|
2005-10-05 07:03:52 +02:00
|
|
|
static time_t last_routerdesc_download_attempted = 0;
|
2005-11-01 04:48:51 +01:00
|
|
|
|
2005-10-11 03:57:28 +02:00
|
|
|
/** The last time we tried to download a networkstatus, or 0 for "never". We
|
|
|
|
* use this to rate-limit download attempts for directory caches (including
|
|
|
|
* mirrors). Clients don't use this now. */
|
2005-10-05 07:03:52 +02:00
|
|
|
static time_t last_networkstatus_download_attempted = 0;
|
|
|
|
|
2006-03-19 02:21:59 +01:00
|
|
|
/** True iff we have logged a warning about this OR not being valid or
|
2006-03-17 06:50:41 +01:00
|
|
|
* not being named. */
|
2006-03-19 02:21:59 +01:00
|
|
|
static int have_warned_about_invalid_status = 0;
|
2006-03-17 06:50:41 +01:00
|
|
|
/** True iff we have logged a warning about this OR's version being older than
|
|
|
|
* listed by the authorities */
|
2005-10-05 04:20:46 +02:00
|
|
|
static int have_warned_about_old_version = 0;
|
2006-03-17 06:50:41 +01:00
|
|
|
/** True iff we have logged a warning about this OR's version being newer than
|
|
|
|
* listed by the authorities */
|
2005-10-05 04:20:46 +02:00
|
|
|
static int have_warned_about_new_version = 0;
|
|
|
|
|
2006-09-29 01:57:59 +02:00
|
|
|
/** Return the number of v2 directory authorities */
|
|
|
|
static INLINE int
|
|
|
|
get_n_v2_authorities(void)
|
|
|
|
{
|
|
|
|
int n = 0;
|
|
|
|
if (!trusted_dir_servers)
|
|
|
|
return 0;
|
|
|
|
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
|
|
|
|
if (ds->is_v2_authority)
|
|
|
|
++n);
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
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];
|
2005-09-30 23:38:45 +02:00
|
|
|
smartlist_t *entries;
|
2007-02-01 19:09:27 +01:00
|
|
|
struct stat st;
|
2005-09-05 01:12:27 +02:00
|
|
|
char *s;
|
|
|
|
tor_assert(get_options()->DataDirectory);
|
|
|
|
if (!networkstatus_list)
|
|
|
|
networkstatus_list = smartlist_create();
|
|
|
|
|
2007-03-09 22:39:30 +01:00
|
|
|
tor_snprintf(filename,sizeof(filename),"%s"PATH_SEPARATOR"cached-status",
|
2005-09-05 01:12:27 +02:00
|
|
|
get_options()->DataDirectory);
|
|
|
|
entries = tor_listdir(filename);
|
|
|
|
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))) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_DIR,
|
|
|
|
"Skipping cached-status file with unexpected name \"%s\"",fn);
|
2005-09-07 18:42:53 +02:00
|
|
|
continue;
|
|
|
|
}
|
2007-03-09 22:39:30 +01:00
|
|
|
tor_snprintf(filename,sizeof(filename),
|
|
|
|
"%s"PATH_SEPARATOR"cached-status"PATH_SEPARATOR"%s",
|
2005-09-05 01:12:27 +02:00
|
|
|
get_options()->DataDirectory, fn);
|
2007-02-01 19:09:27 +01:00
|
|
|
s = read_file_to_str(filename, 0, &st);
|
2005-09-05 01:12:27 +02:00
|
|
|
if (s) {
|
2005-09-08 22:36:40 +02:00
|
|
|
if (router_set_networkstatus(s, st.st_mtime, NS_FROM_CACHE, NULL)<0) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_FS, "Couldn't load networkstatus from \"%s\"",filename);
|
2005-09-07 18:42:53 +02:00
|
|
|
}
|
|
|
|
tor_free(s);
|
2005-09-05 01:12:27 +02:00
|
|
|
}
|
|
|
|
});
|
2005-09-30 23:22:25 +02:00
|
|
|
SMARTLIST_FOREACH(entries, char *, fn, tor_free(fn));
|
|
|
|
smartlist_free(entries);
|
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-11-23 08:24:59 +01:00
|
|
|
/** Total bytes dropped since last rebuild. */
|
|
|
|
static size_t router_bytes_dropped = 0;
|
2005-09-13 08:21:10 +02:00
|
|
|
|
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-11-23 08:24:59 +01:00
|
|
|
return (router_journal_len > router_store_len / 2 ||
|
|
|
|
router_bytes_dropped > 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
|
|
|
}
|
|
|
|
|
2007-03-21 16:37:30 +01:00
|
|
|
/** Add the router descriptor in <b>desc</b> to the router
|
2007-01-22 20:20:33 +01:00
|
|
|
* journal; change its saved_location to SAVED_IN_JOURNAL and set its
|
2007-03-21 16:37:30 +01:00
|
|
|
* offset appropriately.
|
|
|
|
*
|
|
|
|
* If <b>purpose</b> isn't ROUTER_PURPOSE_GENERAL, just do nothing. */
|
2005-09-15 07:41:30 +02:00
|
|
|
static int
|
2007-03-21 16:37:30 +01:00
|
|
|
router_append_to_journal(signed_descriptor_t *desc, uint8_t purpose)
|
2005-09-13 08:21:10 +02:00
|
|
|
{
|
|
|
|
or_options_t *options = get_options();
|
|
|
|
size_t fname_len = strlen(options->DataDirectory)+32;
|
2007-03-21 16:37:30 +01:00
|
|
|
char *fname;
|
2006-01-12 19:04:17 +01:00
|
|
|
const char *body = signed_descriptor_get_body(desc);
|
|
|
|
size_t len = desc->signed_descriptor_len;
|
2005-09-13 08:21:10 +02:00
|
|
|
|
2007-03-21 16:37:30 +01:00
|
|
|
if (purpose != ROUTER_PURPOSE_GENERAL) {
|
|
|
|
/* we shouldn't cache it. be happy and return. */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
fname = tor_malloc(fname_len);
|
2007-03-09 22:39:30 +01:00
|
|
|
tor_snprintf(fname, fname_len, "%s"PATH_SEPARATOR"cached-routers.new",
|
2005-09-13 08:21:10 +02:00
|
|
|
options->DataDirectory);
|
|
|
|
|
2006-01-12 19:04:17 +01:00
|
|
|
tor_assert(len == strlen(body));
|
2005-09-13 08:21:10 +02:00
|
|
|
|
2006-07-10 00:28:12 +02:00
|
|
|
if (append_bytes_to_file(fname, body, len, 1)) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_FS, "Unable to store router descriptor");
|
2005-09-13 08:21:10 +02:00
|
|
|
tor_free(fname);
|
|
|
|
return -1;
|
|
|
|
}
|
2006-04-29 20:42:26 +02:00
|
|
|
desc->saved_location = SAVED_IN_JOURNAL;
|
|
|
|
desc->saved_offset = router_journal_len;
|
2005-09-13 08:21:10 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2007-02-16 21:01:02 +01:00
|
|
|
/** Sorting helper: return <0, 0, or >0 depending on whether the
|
|
|
|
* signed_descriptor_t* in *<b>a</b> is older, the same age as, or newer than
|
2007-02-24 08:50:38 +01:00
|
|
|
* the signed_descriptor_t* in *<b>b</b>. */
|
2006-06-22 09:01:54 +02:00
|
|
|
static int
|
|
|
|
_compare_old_routers_by_age(const void **_a, const void **_b)
|
|
|
|
{
|
|
|
|
const signed_descriptor_t *r1 = *_a, *r2 = *_b;
|
|
|
|
return r1->published_on - r2->published_on;
|
|
|
|
}
|
|
|
|
|
2007-02-16 21:01:02 +01:00
|
|
|
/** Sorting helper: return <0, 0, or >0 depending on whether the
|
|
|
|
* routerinfo_t* in *<b>a</b> is older, the same age as, or newer than
|
2007-02-24 08:50:38 +01:00
|
|
|
* the routerinfo_t* in *<b>b</b>. */
|
2006-06-22 09:01:54 +02:00
|
|
|
static int
|
|
|
|
_compare_routers_by_age(const void **_a, const void **_b)
|
|
|
|
{
|
|
|
|
const routerinfo_t *r1 = *_a, *r2 = *_b;
|
|
|
|
return r1->cache_info.published_on - r2->cache_info.published_on;
|
|
|
|
}
|
|
|
|
|
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;
|
2006-12-07 16:07:33 +01:00
|
|
|
char *fname = NULL, *fname_tmp = NULL;
|
2005-10-27 02:34:39 +02:00
|
|
|
int r = -1, i;
|
2006-06-27 17:52:51 +02:00
|
|
|
off_t offset = 0;
|
2006-06-28 10:55:53 +02:00
|
|
|
smartlist_t *old_routers, *routers;
|
2005-09-13 08:21:10 +02:00
|
|
|
|
|
|
|
if (!force && !router_should_rebuild_store())
|
|
|
|
return 0;
|
|
|
|
if (!routerlist)
|
|
|
|
return 0;
|
|
|
|
|
2005-09-15 07:19:38 +02:00
|
|
|
/* Don't save deadweight. */
|
2005-11-01 18:34:17 +01:00
|
|
|
routerlist_remove_old_routers();
|
2005-09-15 07:19:38 +02:00
|
|
|
|
2006-06-27 17:52:51 +02:00
|
|
|
log_info(LD_DIR, "Rebuilding router descriptor cache");
|
|
|
|
|
2005-09-13 08:21:10 +02:00
|
|
|
options = get_options();
|
|
|
|
fname_len = strlen(options->DataDirectory)+32;
|
|
|
|
fname = tor_malloc(fname_len);
|
2006-12-07 16:07:33 +01:00
|
|
|
fname_tmp = tor_malloc(fname_len);
|
2007-03-09 22:39:30 +01:00
|
|
|
tor_snprintf(fname, fname_len, "%s"PATH_SEPARATOR"cached-routers",
|
|
|
|
options->DataDirectory);
|
|
|
|
tor_snprintf(fname_tmp, fname_len, "%s"PATH_SEPARATOR"cached-routers.tmp",
|
2006-12-07 16:07:33 +01:00
|
|
|
options->DataDirectory);
|
|
|
|
|
2005-09-13 08:21:10 +02:00
|
|
|
chunk_list = smartlist_create();
|
|
|
|
|
2007-03-21 16:37:30 +01:00
|
|
|
/* We sort the routers by age to enhance locality on disk. */
|
2006-06-28 10:55:53 +02:00
|
|
|
old_routers = smartlist_create();
|
|
|
|
smartlist_add_all(old_routers, routerlist->old_routers);
|
|
|
|
smartlist_sort(old_routers, _compare_old_routers_by_age);
|
|
|
|
routers = smartlist_create();
|
|
|
|
smartlist_add_all(routers, routerlist->routers);
|
|
|
|
smartlist_sort(routers, _compare_routers_by_age);
|
2005-10-27 02:34:39 +02:00
|
|
|
for (i = 0; i < 2; ++i) {
|
2006-10-22 10:08:10 +02:00
|
|
|
smartlist_t *lst = (i == 0) ? old_routers : routers;
|
2006-06-22 09:01:54 +02:00
|
|
|
/* Now, add the appropriate members to chunk_list */
|
2005-11-05 21:15:27 +01:00
|
|
|
SMARTLIST_FOREACH(lst, void *, ptr,
|
2005-10-27 02:34:39 +02:00
|
|
|
{
|
2005-11-05 21:15:27 +01:00
|
|
|
signed_descriptor_t *sd = (i==0) ?
|
|
|
|
((signed_descriptor_t*)ptr): &((routerinfo_t*)ptr)->cache_info;
|
2005-10-27 02:34:39 +02:00
|
|
|
sized_chunk_t *c;
|
2006-01-12 19:04:17 +01:00
|
|
|
const char *body = signed_descriptor_get_body(sd);
|
|
|
|
if (!body) {
|
2007-03-04 21:11:46 +01:00
|
|
|
log_warn(LD_BUG, "No descriptor available for router.");
|
2005-10-27 02:34:39 +02:00
|
|
|
goto done;
|
|
|
|
}
|
2007-03-21 16:37:30 +01:00
|
|
|
if (i==1 && ((routerinfo_t*)ptr)->purpose != ROUTER_PURPOSE_GENERAL)
|
|
|
|
continue;
|
2005-10-27 02:34:39 +02:00
|
|
|
c = tor_malloc(sizeof(sized_chunk_t));
|
2006-01-12 19:04:17 +01:00
|
|
|
c->bytes = body;
|
2005-11-05 21:15:27 +01:00
|
|
|
c->len = sd->signed_descriptor_len;
|
2005-10-27 02:34:39 +02:00
|
|
|
smartlist_add(chunk_list, c);
|
|
|
|
});
|
|
|
|
}
|
2006-12-07 16:07:33 +01:00
|
|
|
if (write_chunks_to_file(fname_tmp, chunk_list, 1)<0) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_FS, "Error writing router store to disk.");
|
2005-09-13 08:21:10 +02:00
|
|
|
goto done;
|
|
|
|
}
|
2006-06-22 09:01:54 +02:00
|
|
|
/* Our mmap is now invalid. */
|
2006-08-05 19:53:21 +02:00
|
|
|
if (routerlist->mmap_descriptors) {
|
|
|
|
tor_munmap_file(routerlist->mmap_descriptors);
|
2006-06-22 09:01:54 +02:00
|
|
|
}
|
2006-12-07 16:07:33 +01:00
|
|
|
if (replace_file(fname_tmp, fname)<0) {
|
|
|
|
log_warn(LD_FS, "Error replacing old router store.");
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
routerlist->mmap_descriptors = tor_mmap_file(fname);
|
|
|
|
if (! routerlist->mmap_descriptors)
|
|
|
|
log_warn(LD_FS, "Unable to mmap new descriptor file at '%s'.",fname);
|
2006-06-22 09:01:54 +02:00
|
|
|
|
2006-06-27 17:52:51 +02:00
|
|
|
offset = 0;
|
2006-04-29 20:42:26 +02:00
|
|
|
for (i = 0; i < 2; ++i) {
|
2006-06-28 10:55:53 +02:00
|
|
|
smartlist_t *lst = (i == 0) ? old_routers : routers;
|
2006-04-29 20:42:26 +02:00
|
|
|
SMARTLIST_FOREACH(lst, void *, ptr,
|
|
|
|
{
|
|
|
|
signed_descriptor_t *sd = (i==0) ?
|
|
|
|
((signed_descriptor_t*)ptr): &((routerinfo_t*)ptr)->cache_info;
|
|
|
|
|
2007-03-21 16:37:30 +01:00
|
|
|
if (i==1 && ((routerinfo_t*)ptr)->purpose != ROUTER_PURPOSE_GENERAL)
|
|
|
|
continue;
|
|
|
|
|
2006-04-29 20:42:26 +02:00
|
|
|
sd->saved_location = SAVED_IN_CACHE;
|
2006-06-27 17:52:51 +02:00
|
|
|
if (routerlist->mmap_descriptors) {
|
|
|
|
tor_free(sd->signed_descriptor_body); // sets it to null
|
2006-06-28 17:39:02 +02:00
|
|
|
sd->saved_offset = offset;
|
2006-06-27 17:52:51 +02:00
|
|
|
}
|
2006-04-29 20:42:26 +02:00
|
|
|
offset += sd->signed_descriptor_len;
|
2006-06-28 13:03:34 +02:00
|
|
|
signed_descriptor_get_body(sd);
|
2006-04-29 20:42:26 +02:00
|
|
|
});
|
|
|
|
}
|
2005-09-13 08:21:10 +02:00
|
|
|
|
2007-03-09 22:39:30 +01:00
|
|
|
tor_snprintf(fname, fname_len, "%s"PATH_SEPARATOR"cached-routers.new",
|
2005-09-13 08:21:10 +02:00
|
|
|
options->DataDirectory);
|
|
|
|
|
2006-07-10 00:28:12 +02:00
|
|
|
write_str_to_file(fname, "", 1);
|
2005-09-13 08:21:10 +02:00
|
|
|
|
|
|
|
r = 0;
|
|
|
|
router_store_len = len;
|
2005-09-13 23:18:00 +02:00
|
|
|
router_journal_len = 0;
|
2005-11-23 08:24:59 +01:00
|
|
|
router_bytes_dropped = 0;
|
2005-09-13 08:21:10 +02:00
|
|
|
done:
|
2006-10-22 10:08:10 +02:00
|
|
|
smartlist_free(old_routers);
|
|
|
|
smartlist_free(routers);
|
2005-09-13 08:21:10 +02:00
|
|
|
tor_free(fname);
|
2006-10-22 10:08:10 +02:00
|
|
|
SMARTLIST_FOREACH(chunk_list, sized_chunk_t *, c, tor_free(c));
|
|
|
|
smartlist_free(chunk_list);
|
2005-09-13 08:21:10 +02:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2007-02-02 21:06:43 +01:00
|
|
|
/** Load all cached router descriptors from the store. Return 0 on success and
|
2005-09-15 08:15:31 +02:00
|
|
|
* -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;
|
2007-02-12 22:39:44 +01:00
|
|
|
char *fname = tor_malloc(fname_len), *contents = NULL;
|
2005-09-15 07:19:38 +02:00
|
|
|
|
2005-10-18 22:13:09 +02:00
|
|
|
if (!routerlist)
|
2005-11-01 04:48:51 +01:00
|
|
|
router_get_routerlist(); /* mallocs and inits it in place */
|
2005-09-15 07:19:38 +02:00
|
|
|
|
|
|
|
router_journal_len = router_store_len = 0;
|
|
|
|
|
2007-03-09 22:39:30 +01:00
|
|
|
tor_snprintf(fname, fname_len, "%s"PATH_SEPARATOR"cached-routers",
|
|
|
|
options->DataDirectory);
|
2006-08-27 04:07:54 +02:00
|
|
|
|
|
|
|
if (routerlist->mmap_descriptors) /* get rid of it first */
|
|
|
|
tor_munmap_file(routerlist->mmap_descriptors);
|
|
|
|
|
2006-08-05 19:53:21 +02:00
|
|
|
routerlist->mmap_descriptors = tor_mmap_file(fname);
|
2006-06-22 09:01:54 +02:00
|
|
|
if (routerlist->mmap_descriptors) {
|
2006-08-05 19:53:21 +02:00
|
|
|
router_store_len = routerlist->mmap_descriptors->size;
|
|
|
|
router_load_routers_from_string(routerlist->mmap_descriptors->data,
|
2006-06-22 09:01:54 +02:00
|
|
|
SAVED_IN_CACHE, NULL);
|
2005-09-15 07:19:38 +02:00
|
|
|
}
|
2006-06-22 09:01:54 +02:00
|
|
|
|
2007-03-09 22:39:30 +01:00
|
|
|
tor_snprintf(fname, fname_len, "%s"PATH_SEPARATOR"cached-routers.new",
|
2006-06-22 09:01:54 +02:00
|
|
|
options->DataDirectory);
|
2007-02-12 22:39:44 +01:00
|
|
|
if (file_status(fname) == FN_FILE)
|
|
|
|
contents = read_file_to_str(fname, RFTS_BIN|RFTS_IGNORE_MISSING, NULL);
|
2006-06-22 09:01:54 +02:00
|
|
|
if (contents) {
|
|
|
|
router_load_routers_from_string(contents,
|
|
|
|
SAVED_IN_JOURNAL, NULL);
|
2006-08-27 04:12:12 +02:00
|
|
|
tor_free(contents);
|
2006-06-22 09:01:54 +02:00
|
|
|
}
|
|
|
|
|
2005-09-30 23:11:22 +02:00
|
|
|
tor_free(fname);
|
2005-09-15 07:19:38 +02:00
|
|
|
|
|
|
|
if (router_journal_len) {
|
|
|
|
/* Always clear the journal on startup.*/
|
|
|
|
router_rebuild_store(1);
|
2006-01-10 05:57:12 +01:00
|
|
|
} else {
|
|
|
|
/* Don't cache expired routers. (This is in an else because
|
|
|
|
* router_rebuild_store() also calls remove_old_routers().) */
|
|
|
|
routerlist_remove_old_routers();
|
2005-09-15 07:19:38 +02:00
|
|
|
}
|
2006-01-10 05:57:12 +01:00
|
|
|
|
2005-09-15 07:19:38 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-04-10 03:35:56 +02:00
|
|
|
/** Return a smartlist containing a list of trusted_dir_server_t * for all
|
|
|
|
* known trusted dirservers. Callers must not modify the list or its
|
|
|
|
* contents.
|
2004-10-15 21:04:38 +02:00
|
|
|
*/
|
2006-04-10 03:35:56 +02:00
|
|
|
smartlist_t *
|
|
|
|
router_get_trusted_dir_servers(void)
|
2004-10-15 21:04:38 +02:00
|
|
|
{
|
|
|
|
if (!trusted_dir_servers)
|
|
|
|
trusted_dir_servers = smartlist_create();
|
|
|
|
|
2006-04-10 03:35:56 +02:00
|
|
|
return trusted_dir_servers;
|
2004-10-15 21:04:38 +02:00
|
|
|
}
|
|
|
|
|
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.9rc5-cvs or later).
|
2006-01-10 00:39:07 +01:00
|
|
|
* Don't pick an authority if any non-authority is viable.
|
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-12-14 23:00:58 +01:00
|
|
|
routerstatus_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)
|
|
|
|
{
|
2005-12-14 23:00:58 +01:00
|
|
|
routerstatus_t *choice;
|
2007-01-03 07:33:03 +01:00
|
|
|
int prefer_tunnel = get_options()->PreferTunneledDirConns;
|
2004-02-26 23:56:36 +01:00
|
|
|
|
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,
|
2007-01-03 07:33:03 +01:00
|
|
|
prefer_tunnel, 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;
|
|
|
|
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_DIR,
|
|
|
|
"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,
|
2007-01-03 07:33:03 +01:00
|
|
|
prefer_tunnel, for_v2_directory);
|
2004-11-28 10:05:49 +01:00
|
|
|
if (choice)
|
2004-07-20 08:44:16 +02:00
|
|
|
return choice;
|
|
|
|
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_DIR,"Still no %s router entries. Reloading and trying again.",
|
|
|
|
fascistfirewall ? "reachable" : "known");
|
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-11-19 11:38:23 +01:00
|
|
|
choice = router_pick_directory_server_impl(requireother, fascistfirewall,
|
2007-01-03 07:33:03 +01:00
|
|
|
prefer_tunnel, for_v2_directory);
|
2004-02-26 23:56:36 +01:00
|
|
|
return choice;
|
|
|
|
}
|
|
|
|
|
2005-12-14 23:00:58 +01:00
|
|
|
/** Return the trusted_dir_server_t for the directory authority whose identity
|
|
|
|
* key hashes to <b>digest</b>, or NULL if no such authority is known.
|
|
|
|
*/
|
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.
|
2005-12-14 23:00:58 +01:00
|
|
|
* If <b>need_v1_authority</b> is set, return only trusted servers
|
|
|
|
* that are authorities for the V1 directory protocol.
|
2005-06-21 01:04:13 +02:00
|
|
|
* Other args are as in router_pick_trusteddirserver_impl().
|
|
|
|
*/
|
2005-12-14 23:00:58 +01:00
|
|
|
routerstatus_t *
|
2006-09-29 01:57:59 +02:00
|
|
|
router_pick_trusteddirserver(authority_type_t type,
|
2005-09-07 18:42:53 +02:00
|
|
|
int requireother,
|
2005-06-11 20:52:12 +02:00
|
|
|
int fascistfirewall,
|
|
|
|
int retry_if_no_servers)
|
|
|
|
{
|
2005-12-14 23:00:58 +01:00
|
|
|
routerstatus_t *choice;
|
2007-01-03 07:33:03 +01:00
|
|
|
int prefer_tunnel = get_options()->PreferTunneledDirConns;
|
2004-10-12 17:55:20 +02:00
|
|
|
|
2007-01-03 07:33:03 +01:00
|
|
|
choice = router_pick_trusteddirserver_impl(type, requireother,
|
|
|
|
fascistfirewall, prefer_tunnel);
|
2005-01-03 21:51:24 +01:00
|
|
|
if (choice || !retry_if_no_servers)
|
2004-10-12 17:55:20 +02:00
|
|
|
return choice;
|
|
|
|
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_DIR,
|
|
|
|
"No trusted dirservers are reachable. Trying them all again.");
|
2004-10-12 17:55:20 +02:00
|
|
|
mark_all_trusteddirservers_up();
|
2007-01-03 07:33:03 +01:00
|
|
|
return router_pick_trusteddirserver_impl(type, requireother,
|
|
|
|
fascistfirewall, prefer_tunnel);
|
2004-10-12 17:55:20 +02:00
|
|
|
}
|
|
|
|
|
2006-12-24 03:45:35 +01:00
|
|
|
/** How long do we avoid using a directory server after it's given us a 503? */
|
|
|
|
#define DIR_503_TIMEOUT (60*60)
|
|
|
|
|
2006-03-19 02:21:59 +01:00
|
|
|
/** Pick a random running valid directory server/mirror from our
|
2006-01-10 00:39:07 +01:00
|
|
|
* routerlist. Don't pick an authority if any non-authorities are viable.
|
2007-01-22 06:59:59 +01:00
|
|
|
* If <b>fascistfirewall</b>, make sure the router we pick is allowed
|
|
|
|
* by our firewall options.
|
2007-01-03 07:33:03 +01:00
|
|
|
* If <b>requireother</b>, it cannot be us. If <b>for_v2_directory</b>,
|
2005-09-13 17:32:03 +02:00
|
|
|
* choose a directory server new enough to support the v2 directory
|
|
|
|
* functionality.
|
2007-01-03 07:33:03 +01:00
|
|
|
* If <b>prefer_tunnel</b>, choose a directory server that is reachable
|
|
|
|
* and supports BEGIN_DIR cells, if possible.
|
|
|
|
* Try to avoid using servers that are overloaded (have returned 503
|
|
|
|
* recently).
|
2004-07-20 08:44:16 +02:00
|
|
|
*/
|
2005-12-14 23:00:58 +01:00
|
|
|
static routerstatus_t *
|
2005-06-21 01:04:13 +02:00
|
|
|
router_pick_directory_server_impl(int requireother, int fascistfirewall,
|
2007-01-03 07:33:03 +01:00
|
|
|
int prefer_tunnel, int for_v2_directory)
|
2004-07-20 08:44:16 +02:00
|
|
|
{
|
2005-12-14 23:00:58 +01:00
|
|
|
routerstatus_t *result;
|
2007-01-03 07:33:03 +01:00
|
|
|
smartlist_t *direct, *tunnel;
|
|
|
|
smartlist_t *trusted_direct, *trusted_tunnel;
|
|
|
|
smartlist_t *overloaded_direct, *overloaded_tunnel;
|
2006-12-24 03:45:35 +01:00
|
|
|
time_t now = time(NULL);
|
2003-12-03 11:39:27 +01:00
|
|
|
|
2005-12-14 23:00:58 +01:00
|
|
|
if (!routerstatus_list)
|
2002-09-26 14:09:10 +02:00
|
|
|
return NULL;
|
|
|
|
|
2007-01-03 07:33:03 +01:00
|
|
|
direct = smartlist_create();
|
|
|
|
tunnel = smartlist_create();
|
|
|
|
trusted_direct = smartlist_create();
|
|
|
|
trusted_tunnel = smartlist_create();
|
|
|
|
overloaded_direct = smartlist_create();
|
|
|
|
overloaded_tunnel = smartlist_create();
|
|
|
|
|
2004-05-04 20:17:45 +02:00
|
|
|
/* Find all the running dirservers we know about. */
|
2005-12-14 23:00:58 +01:00
|
|
|
SMARTLIST_FOREACH(routerstatus_list, local_routerstatus_t *, _local_status,
|
2005-09-13 17:32:03 +02:00
|
|
|
{
|
2005-12-14 23:00:58 +01:00
|
|
|
routerstatus_t *status = &(_local_status->status);
|
2006-01-10 00:39:07 +01:00
|
|
|
int is_trusted;
|
2007-01-03 07:33:03 +01:00
|
|
|
int is_overloaded = _local_status->last_dir_503_at + DIR_503_TIMEOUT > now;
|
2005-12-14 23:00:58 +01:00
|
|
|
if (!status->is_running || !status->dir_port || !status->is_valid)
|
2004-07-20 08:44:16 +02:00
|
|
|
continue;
|
2007-01-03 20:58:00 +01:00
|
|
|
if (status->is_bad_directory)
|
|
|
|
continue;
|
2005-12-14 23:00:58 +01:00
|
|
|
if (requireother && router_digest_is_me(status->identity_digest))
|
2004-07-20 08:44:16 +02:00
|
|
|
continue;
|
2006-01-10 00:39:07 +01:00
|
|
|
is_trusted = router_digest_is_trusted_dir(status->identity_digest);
|
|
|
|
if (for_v2_directory && !(status->is_v2_dir || is_trusted))
|
2004-11-29 22:01:34 +01:00
|
|
|
continue;
|
2007-01-03 07:33:03 +01:00
|
|
|
if (fascistfirewall &&
|
|
|
|
prefer_tunnel &&
|
|
|
|
status->version_supports_begindir &&
|
2007-03-01 05:26:30 +01:00
|
|
|
router_get_by_digest(status->identity_digest) &&
|
2007-01-03 07:33:03 +01:00
|
|
|
fascist_firewall_allows_address_or(status->addr, status->or_port))
|
|
|
|
smartlist_add(is_trusted ? trusted_tunnel :
|
|
|
|
is_overloaded ? overloaded_tunnel : tunnel, status);
|
|
|
|
else if (!fascistfirewall || (fascistfirewall &&
|
|
|
|
fascist_firewall_allows_address_dir(status->addr,
|
|
|
|
status->dir_port)))
|
|
|
|
smartlist_add(is_trusted ? trusted_direct :
|
|
|
|
is_overloaded ? overloaded_direct : direct, status);
|
2005-09-13 17:32:03 +02:00
|
|
|
});
|
2002-09-26 14:09:10 +02:00
|
|
|
|
2007-01-03 07:33:03 +01:00
|
|
|
if (smartlist_len(tunnel)) {
|
2007-01-27 10:13:19 +01:00
|
|
|
result = routerstatus_sl_choose_by_bandwidth(tunnel);
|
2007-01-03 07:33:03 +01:00
|
|
|
} else if (smartlist_len(overloaded_tunnel)) {
|
2007-01-27 10:13:19 +01:00
|
|
|
result = routerstatus_sl_choose_by_bandwidth(overloaded_tunnel);
|
2007-01-04 10:12:23 +01:00
|
|
|
} else if (smartlist_len(trusted_tunnel)) {
|
2007-01-03 07:33:03 +01:00
|
|
|
/* FFFF We don't distinguish between trusteds and overloaded trusteds
|
|
|
|
* yet. Maybe one day we should. */
|
2007-01-27 10:13:19 +01:00
|
|
|
/* FFFF We also don't load balance over authorities yet. I think this
|
|
|
|
* is a feature, but it could easily be a bug. -RD */
|
2007-01-03 07:33:03 +01:00
|
|
|
result = smartlist_choose(trusted_tunnel);
|
|
|
|
} else if (smartlist_len(direct)) {
|
2007-01-27 10:13:19 +01:00
|
|
|
result = routerstatus_sl_choose_by_bandwidth(direct);
|
2007-01-03 07:33:03 +01:00
|
|
|
} else if (smartlist_len(overloaded_direct)) {
|
2007-01-27 10:13:19 +01:00
|
|
|
result = routerstatus_sl_choose_by_bandwidth(overloaded_direct);
|
2007-01-03 07:33:03 +01:00
|
|
|
} else {
|
|
|
|
result = smartlist_choose(trusted_direct);
|
|
|
|
}
|
|
|
|
smartlist_free(direct);
|
|
|
|
smartlist_free(tunnel);
|
|
|
|
smartlist_free(trusted_direct);
|
|
|
|
smartlist_free(trusted_tunnel);
|
|
|
|
smartlist_free(overloaded_direct);
|
|
|
|
smartlist_free(overloaded_tunnel);
|
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-12-14 23:00:58 +01:00
|
|
|
/** Choose randomly from among the trusted dirservers that are up. If
|
|
|
|
* <b>fascistfirewall</b>, make sure the port we pick is allowed by our
|
|
|
|
* firewall options. If <b>requireother</b>, it cannot be us. If
|
|
|
|
* <b>need_v1_authority</b>, choose a trusted authority for the v1 directory
|
|
|
|
* system.
|
2005-06-21 01:04:13 +02:00
|
|
|
*/
|
2005-12-14 23:00:58 +01:00
|
|
|
static routerstatus_t *
|
2006-09-29 01:57:59 +02:00
|
|
|
router_pick_trusteddirserver_impl(authority_type_t type,
|
2007-01-03 07:33:03 +01:00
|
|
|
int requireother, int fascistfirewall,
|
|
|
|
int prefer_tunnel)
|
2004-10-12 17:55:20 +02:00
|
|
|
{
|
2007-01-03 07:33:03 +01:00
|
|
|
smartlist_t *direct, *tunnel;
|
|
|
|
smartlist_t *overloaded_direct, *overloaded_tunnel;
|
|
|
|
routerinfo_t *me = router_get_my_routerinfo();
|
|
|
|
routerstatus_t *result;
|
2006-12-24 03:45:35 +01:00
|
|
|
time_t now = time(NULL);
|
2007-01-03 07:33:03 +01:00
|
|
|
|
|
|
|
direct = smartlist_create();
|
|
|
|
tunnel = smartlist_create();
|
|
|
|
overloaded_direct = smartlist_create();
|
|
|
|
overloaded_tunnel = smartlist_create();
|
2004-07-20 08:44:16 +02:00
|
|
|
|
2004-10-14 04:29:03 +02:00
|
|
|
if (!trusted_dir_servers)
|
|
|
|
return NULL;
|
|
|
|
|
2004-10-12 17:55:20 +02:00
|
|
|
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, d,
|
|
|
|
{
|
2007-01-03 07:33:03 +01:00
|
|
|
int is_overloaded =
|
|
|
|
d->fake_status.last_dir_503_at + DIR_503_TIMEOUT > now;
|
2004-10-12 17:55:20 +02:00
|
|
|
if (!d->is_running) continue;
|
2006-09-29 01:57:59 +02:00
|
|
|
if (type == V1_AUTHORITY && !d->is_v1_authority)
|
|
|
|
continue;
|
|
|
|
if (type == V2_AUTHORITY && !d->is_v2_authority)
|
|
|
|
continue;
|
|
|
|
if (type == HIDSERV_AUTHORITY && !d->is_hidserv_authority)
|
2005-09-07 18:42:53 +02:00
|
|
|
continue;
|
2005-11-05 21:15:27 +01:00
|
|
|
if (requireother && me && router_digest_is_me(d->digest))
|
|
|
|
continue;
|
2007-01-03 07:33:03 +01:00
|
|
|
|
|
|
|
if (fascistfirewall &&
|
|
|
|
prefer_tunnel &&
|
|
|
|
d->or_port &&
|
2007-03-01 05:26:30 +01:00
|
|
|
router_get_by_digest(d->digest) &&
|
2007-01-03 07:33:03 +01:00
|
|
|
fascist_firewall_allows_address_or(d->addr, d->or_port))
|
|
|
|
smartlist_add(is_overloaded ? overloaded_tunnel : tunnel,
|
|
|
|
&d->fake_status.status);
|
|
|
|
else if (!fascistfirewall || (fascistfirewall &&
|
|
|
|
fascist_firewall_allows_address_dir(d->addr,
|
|
|
|
d->dir_port)))
|
|
|
|
smartlist_add(is_overloaded ? overloaded_direct : direct,
|
|
|
|
&d->fake_status.status);
|
2004-10-12 17:55:20 +02:00
|
|
|
});
|
2004-05-04 20:17:45 +02:00
|
|
|
|
2007-01-03 07:33:03 +01:00
|
|
|
if (smartlist_len(tunnel)) {
|
|
|
|
result = smartlist_choose(tunnel);
|
|
|
|
} else if (smartlist_len(overloaded_tunnel)) {
|
|
|
|
result = smartlist_choose(overloaded_tunnel);
|
|
|
|
} else if (smartlist_len(direct)) {
|
|
|
|
result = smartlist_choose(direct);
|
|
|
|
} else {
|
|
|
|
result = smartlist_choose(overloaded_direct);
|
|
|
|
}
|
|
|
|
|
|
|
|
smartlist_free(direct);
|
|
|
|
smartlist_free(tunnel);
|
|
|
|
smartlist_free(overloaded_direct);
|
|
|
|
smartlist_free(overloaded_tunnel);
|
|
|
|
return result;
|
2004-10-12 17:55:20 +02:00
|
|
|
}
|
|
|
|
|
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-11-05 21:15:27 +01:00
|
|
|
if (router_digest_is_trusted_dir(router->cache_info.identity_digest) &&
|
|
|
|
router->dir_port > 0) {
|
|
|
|
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
|
|
|
{
|
2005-12-15 21:44:15 +01:00
|
|
|
local_routerstatus_t *rs;
|
2005-09-14 23:09:25 +02:00
|
|
|
dir->is_running = 1;
|
|
|
|
dir->n_networkstatus_failures = 0;
|
2006-12-24 03:45:35 +01:00
|
|
|
dir->fake_status.last_dir_503_at = 0;
|
2005-12-15 21:44:15 +01:00
|
|
|
rs = router_get_combined_status_by_digest(dir->digest);
|
2006-10-20 23:04:39 +02:00
|
|
|
if (rs && !rs->status.is_running) {
|
2005-12-15 21:44:15 +01:00
|
|
|
rs->status.is_running = 1;
|
2006-12-24 03:45:35 +01:00
|
|
|
rs->last_dir_503_at = 0;
|
2006-10-20 23:04:39 +02:00
|
|
|
control_event_networkstatus_changed_single(rs);
|
|
|
|
}
|
2005-09-14 23:09:25 +02:00
|
|
|
});
|
2003-12-03 11:39:27 +01:00
|
|
|
}
|
2005-10-05 07:03:52 +02:00
|
|
|
last_networkstatus_download_attempted = 0;
|
2006-08-31 20:46:46 +02:00
|
|
|
router_dir_info_changed();
|
2005-10-05 07:03:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Reset all internal variables used to count failed downloads of network
|
|
|
|
* status objects. */
|
|
|
|
void
|
|
|
|
router_reset_status_download_failures(void)
|
|
|
|
{
|
|
|
|
mark_all_trusteddirservers_up();
|
2004-07-12 22:39:40 +02:00
|
|
|
}
|
|
|
|
|
2006-08-16 05:44:13 +02:00
|
|
|
/** Look through the routerlist and identify routers that
|
|
|
|
* advertise the same /16 network address as <b>router</b>.
|
|
|
|
* Add each of them to <b>sl</b>.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
routerlist_add_network_family(smartlist_t *sl, routerinfo_t *router)
|
|
|
|
{
|
|
|
|
SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, r,
|
|
|
|
{
|
|
|
|
if (router != r &&
|
|
|
|
(router->addr & 0xffff0000) == (r->addr & 0xffff0000))
|
|
|
|
smartlist_add(sl, r);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
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;
|
2006-09-26 00:12:54 +02:00
|
|
|
or_options_t *options = get_options();
|
2004-09-10 23:40:29 +02:00
|
|
|
|
2007-02-22 08:41:10 +01:00
|
|
|
/* First, add any routers with similar network addresses. */
|
2006-09-26 00:12:54 +02:00
|
|
|
if (options->EnforceDistinctSubnets)
|
|
|
|
routerlist_add_network_family(sl, router);
|
2006-08-16 05:44:13 +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,
|
|
|
|
{
|
2005-10-05 00:23:31 +02:00
|
|
|
if (!(r = router_get_by_nickname(n, 0)))
|
2004-10-15 03:58:11 +02:00
|
|
|
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)) {
|
2007-02-13 02:27:55 +01:00
|
|
|
add_nickname_list_to_smartlist(sl, cl->value, 0);
|
2004-10-15 22:52:09 +02:00
|
|
|
}
|
|
|
|
}
|
2004-09-10 23:40:29 +02:00
|
|
|
}
|
|
|
|
|
2006-09-29 01:57:44 +02:00
|
|
|
/** Given a (possibly NULL) comma-and-whitespace separated list of nicknames,
|
|
|
|
* see which nicknames in <b>list</b> name routers in our routerlist, and add
|
|
|
|
* the routerinfos for those routers to <b>sl</b>. If <b>must_be_running</b>,
|
2007-02-13 02:27:55 +01:00
|
|
|
* only include routers that we think are running.
|
|
|
|
* Warn if any non-Named routers are specified by nickname.
|
2004-05-04 20:17:45 +02:00
|
|
|
*/
|
2004-08-18 13:20:15 +02:00
|
|
|
void
|
2005-12-14 21:40:40 +01:00
|
|
|
add_nickname_list_to_smartlist(smartlist_t *sl, const char *list,
|
2007-02-13 02:27:55 +01:00
|
|
|
int must_be_running)
|
2004-08-18 13:20:15 +02:00
|
|
|
{
|
2004-04-03 00:23:15 +02:00
|
|
|
routerinfo_t *router;
|
2004-09-02 20:39:59 +02:00
|
|
|
smartlist_t *nickname_list;
|
2005-12-15 21:44:15 +01:00
|
|
|
int have_dir_info = router_have_minimum_dir_info();
|
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)) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_CONFIG, "Nickname '%s' is misformed; skipping", nick);
|
2004-07-22 23:36:03 +02:00
|
|
|
continue;
|
|
|
|
}
|
2007-02-13 02:27:55 +01:00
|
|
|
router = router_get_by_nickname(nick, 1);
|
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-12-31 07:32:57 +01:00
|
|
|
if (!must_be_running || router->is_running) {
|
2004-04-03 00:23:15 +02:00
|
|
|
smartlist_add(sl,router);
|
2005-04-03 07:53:34 +02:00
|
|
|
}
|
2007-02-13 02:27:55 +01:00
|
|
|
} else if (!router_get_combined_status_by_nickname(nick,1)) {
|
2005-04-03 07:53:34 +02:00
|
|
|
if (!warned) {
|
2005-12-15 21:44:15 +01:00
|
|
|
log_fn(have_dir_info ? LOG_WARN : LOG_INFO, LD_CONFIG,
|
2005-04-03 07:53:34 +02:00
|
|
|
"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
|
|
|
}
|
|
|
|
|
2006-09-29 01:57:44 +02:00
|
|
|
/** Return 1 iff any member of the (possibly NULL) comma-separated list
|
|
|
|
* <b>list</b> is an acceptable nickname or hexdigest for <b>router</b>. Else
|
|
|
|
* return 0.
|
2004-10-15 22:52:09 +02:00
|
|
|
*/
|
2006-09-29 01:57:44 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2007-01-22 06:59:59 +01:00
|
|
|
/** Add every suitable router from our routerlist to <b>sl</b>, so that
|
|
|
|
* we can pick a node for a circuit.
|
2004-05-04 20:17:45 +02:00
|
|
|
*/
|
2004-08-17 08:27:32 +02:00
|
|
|
static void
|
2006-03-19 02:21:59 +01:00
|
|
|
router_add_running_routers_to_smartlist(smartlist_t *sl, int allow_invalid,
|
2006-02-12 04:43:39 +01:00
|
|
|
int need_uptime, int need_capacity,
|
|
|
|
int need_guard)
|
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 &&
|
2006-03-17 23:08:59 +01:00
|
|
|
router->purpose == ROUTER_PURPOSE_GENERAL &&
|
2007-01-22 06:59:59 +01:00
|
|
|
(router->is_valid || allow_invalid) &&
|
|
|
|
!router_is_unreliable(router, need_uptime,
|
|
|
|
need_capacity, need_guard)) {
|
|
|
|
/* If it's running, and it's suitable according to the
|
|
|
|
* other flags we had in mind */
|
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 &&
|
2006-03-27 04:25:34 +02:00
|
|
|
compare_addr_to_addr_policy(addr, port, router->exit_policy) ==
|
2005-08-15 05:25:40 +02:00
|
|
|
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.
|
2007-02-02 19:58:11 +01:00
|
|
|
* If <b>need_guard</b>, we require that the router is a possible entry guard.
|
2005-06-21 01:04:13 +02:00
|
|
|
*/
|
2004-08-20 23:34:36 +02:00
|
|
|
int
|
2006-02-12 04:43:39 +01:00
|
|
|
router_is_unreliable(routerinfo_t *router, int need_uptime,
|
|
|
|
int need_capacity, int need_guard)
|
2004-08-20 23:34:36 +02:00
|
|
|
{
|
2005-12-15 22:30:57 +01:00
|
|
|
if (need_uptime && !router->is_stable)
|
2004-08-20 23:34:36 +02:00
|
|
|
return 1;
|
2005-12-15 22:30:57 +01:00
|
|
|
if (need_capacity && !router->is_fast)
|
2004-08-20 23:34:36 +02:00
|
|
|
return 1;
|
2006-02-12 04:43:39 +01:00
|
|
|
if (need_guard && !router->is_possible_guard)
|
|
|
|
return 1;
|
2004-08-20 23:34:36 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2004-08-15 10:15:12 +02:00
|
|
|
|
2006-03-28 14:01:58 +02:00
|
|
|
/** Return the smaller of the router's configured BandwidthRate
|
|
|
|
* and its advertised capacity. */
|
|
|
|
uint32_t
|
|
|
|
router_get_advertised_bandwidth(routerinfo_t *router)
|
|
|
|
{
|
|
|
|
if (router->bandwidthcapacity < router->bandwidthrate)
|
|
|
|
return router->bandwidthcapacity;
|
|
|
|
return router->bandwidthrate;
|
|
|
|
}
|
|
|
|
|
2007-02-16 21:01:02 +01:00
|
|
|
/** Do not weight any declared bandwidth more than this much when picking
|
|
|
|
* routers by bandwidth. */
|
2005-12-30 05:46:43 +01:00
|
|
|
#define MAX_BELIEVABLE_BANDWIDTH 1500000 /* 1.5 MB/sec */
|
2005-06-21 01:04:13 +02:00
|
|
|
|
2007-01-27 10:13:19 +01:00
|
|
|
/** Helper function:
|
|
|
|
* choose a random element of smartlist <b>sl</b>, weighted by
|
|
|
|
* the advertised bandwidth of each element.
|
|
|
|
*
|
|
|
|
* If <b>statuses</b> is zero, then <b>sl</b> is a list of
|
|
|
|
* routerinfo_t's. Otherwise it's a list of routerstatus_t's.
|
|
|
|
*
|
2007-02-02 19:58:11 +01:00
|
|
|
* If <b>for_exit</b>, we're picking an exit node: consider all nodes'
|
|
|
|
* bandwidth equally regardless of their Exit status. If not <b>for_exit</b>,
|
|
|
|
* we're picking a non-exit node: weight exit-node's bandwidth downwards
|
|
|
|
* depending on the smallness of the fraction of Exit-to-total bandwidth.
|
2005-06-21 01:04:13 +02:00
|
|
|
*/
|
2007-01-27 10:13:19 +01:00
|
|
|
static void *
|
|
|
|
smartlist_choose_by_bandwidth(smartlist_t *sl, int for_exit, int statuses)
|
2004-08-15 10:15:12 +02:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
routerinfo_t *router;
|
2007-01-27 10:13:19 +01:00
|
|
|
routerstatus_t *status;
|
2007-02-08 20:44:55 +01:00
|
|
|
int32_t *bandwidths;
|
2007-02-09 00:24:03 +01:00
|
|
|
int is_exit;
|
2006-10-01 23:59:09 +02:00
|
|
|
uint64_t total_nonexit_bw = 0, total_exit_bw = 0, total_bw = 0;
|
|
|
|
uint64_t rand_bw, tmp;
|
|
|
|
double exit_weight;
|
2007-02-08 20:44:55 +01:00
|
|
|
int n_unknown = 0;
|
2004-08-15 10:15:12 +02:00
|
|
|
|
2007-01-22 06:59:59 +01:00
|
|
|
/* First count the total bandwidth weight, and make a list
|
2007-02-08 20:44:55 +01:00
|
|
|
* of each value. <0 means "unknown; no routerinfo." We use the
|
|
|
|
* bits of negative values to remember whether the router was fast (-x)&1
|
|
|
|
* and whether it was an exit (-x)&2. Yes, it's a hack. */
|
|
|
|
bandwidths = tor_malloc(sizeof(int32_t)*smartlist_len(sl));
|
|
|
|
|
|
|
|
/* Iterate over all the routerinfo_t or routerstatus_t, and */
|
2004-08-15 10:15:12 +02:00
|
|
|
for (i = 0; i < smartlist_len(sl); ++i) {
|
2007-01-27 10:13:19 +01:00
|
|
|
/* first, learn what bandwidth we think i has */
|
2007-02-08 20:44:55 +01:00
|
|
|
int is_known = 1;
|
|
|
|
int32_t flags = 0;
|
2007-02-09 00:24:03 +01:00
|
|
|
uint32_t this_bw = 0;
|
2007-01-27 10:13:19 +01:00
|
|
|
if (statuses) {
|
|
|
|
/* need to extract router info */
|
|
|
|
status = smartlist_get(sl, i);
|
|
|
|
router = router_get_by_digest(status->identity_digest);
|
|
|
|
is_exit = status->is_exit;
|
|
|
|
if (router) {
|
|
|
|
this_bw = router_get_advertised_bandwidth(router);
|
|
|
|
} else { /* guess */
|
2007-02-08 20:44:55 +01:00
|
|
|
is_known = 0;
|
|
|
|
flags = status->is_fast ? 1 : 0;
|
|
|
|
flags |= is_exit ? 2 : 0;
|
2007-01-27 10:13:19 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
router = smartlist_get(sl, i);
|
|
|
|
is_exit = router->is_exit;
|
|
|
|
this_bw = router_get_advertised_bandwidth(router);
|
|
|
|
}
|
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;
|
2007-02-08 20:44:55 +01:00
|
|
|
if (is_known) {
|
|
|
|
bandwidths[i] = (int32_t) this_bw; // safe since MAX_BELIEVABLE<INT32_MAX
|
|
|
|
if (is_exit)
|
|
|
|
total_exit_bw += this_bw;
|
|
|
|
else
|
|
|
|
total_nonexit_bw += this_bw;
|
|
|
|
} else {
|
|
|
|
++n_unknown;
|
|
|
|
bandwidths[i] = -flags;
|
|
|
|
}
|
2006-10-01 23:59:09 +02:00
|
|
|
}
|
2007-02-08 20:44:55 +01:00
|
|
|
|
|
|
|
/* Now, fill in the unknown values. */
|
|
|
|
if (n_unknown) {
|
|
|
|
int32_t avg_fast, avg_slow;
|
|
|
|
if (total_exit_bw+total_nonexit_bw) {
|
2007-02-08 21:27:58 +01:00
|
|
|
/* if there's some bandwidth, there's at least one known router,
|
|
|
|
* so no worries about div by 0 here */
|
2007-02-16 21:01:21 +01:00
|
|
|
int n_known = smartlist_len(sl)-n_unknown;
|
|
|
|
avg_fast = avg_slow = (int32_t)
|
|
|
|
((total_exit_bw+total_nonexit_bw)/((uint64_t) n_known));
|
2007-02-08 20:44:55 +01:00
|
|
|
} else {
|
|
|
|
avg_fast = 40000;
|
|
|
|
avg_slow = 20000;
|
|
|
|
}
|
|
|
|
for (i=0; i<smartlist_len(sl); ++i) {
|
|
|
|
int32_t bw = bandwidths[i];
|
|
|
|
if (bw>=0)
|
|
|
|
continue;
|
|
|
|
is_exit = ((-bw)&2);
|
|
|
|
bandwidths[i] = ((-bw)&1) ? avg_fast : avg_slow;
|
|
|
|
if (is_exit)
|
|
|
|
total_exit_bw += bandwidths[i];
|
|
|
|
else
|
|
|
|
total_nonexit_bw += bandwidths[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If there's no bandwidth at all, pick at random. */
|
2006-10-01 23:59:09 +02:00
|
|
|
if (!(total_exit_bw+total_nonexit_bw)) {
|
|
|
|
tor_free(bandwidths);
|
2004-11-20 13:41:05 +01:00
|
|
|
return smartlist_choose(sl);
|
2004-12-07 09:51:10 +01:00
|
|
|
}
|
2007-02-08 20:44:55 +01:00
|
|
|
|
|
|
|
/* Figure out how to weight exits. */
|
2006-10-01 23:59:09 +02:00
|
|
|
if (for_exit) {
|
2007-02-08 20:44:55 +01:00
|
|
|
/* If we're choosing an exit node, exit bandwidth counts fully. */
|
2006-10-01 23:59:09 +02:00
|
|
|
exit_weight = 1.0;
|
|
|
|
total_bw = total_exit_bw + total_nonexit_bw;
|
|
|
|
} else if (total_exit_bw < total_nonexit_bw / 2) {
|
2007-02-08 20:44:55 +01:00
|
|
|
/* If we're choosing a relay and exits are greatly outnumbered, ignore
|
|
|
|
* them. */
|
2006-10-01 23:59:09 +02:00
|
|
|
exit_weight = 0.0;
|
|
|
|
total_bw = total_nonexit_bw;
|
|
|
|
} else {
|
2007-02-08 20:44:55 +01:00
|
|
|
/* If we're choosing a relay and exits aren't outnumbered use the formula
|
|
|
|
* from path-spec. */
|
2006-10-01 23:59:09 +02:00
|
|
|
uint64_t leftover = (total_exit_bw - total_nonexit_bw / 2);
|
|
|
|
exit_weight = U64_TO_DBL(leftover) /
|
|
|
|
U64_TO_DBL(leftover + total_nonexit_bw);
|
|
|
|
total_bw = total_nonexit_bw +
|
|
|
|
DBL_TO_U64(exit_weight * U64_TO_DBL(total_exit_bw));
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
log_debug(LD_CIRC, "Total bw = "U64_FORMAT", total exit bw = "U64_FORMAT
|
|
|
|
", total nonexit bw = "U64_FORMAT", exit weight = %lf "
|
|
|
|
"(for exit == %d)",
|
|
|
|
U64_PRINTF_ARG(total_bw), U64_PRINTF_ARG(total_exit_bw),
|
|
|
|
U64_PRINTF_ARG(total_nonexit_bw), exit_weight, for_exit);
|
|
|
|
*/
|
|
|
|
|
2007-02-08 20:44:55 +01:00
|
|
|
/* Almost done: choose a random value from the bandwidth weights. */
|
2006-10-01 23:59:09 +02:00
|
|
|
rand_bw = crypto_rand_uint64(total_bw);
|
2007-02-08 20:44:55 +01:00
|
|
|
|
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;
|
2006-10-01 23:59:09 +02:00
|
|
|
for (i=0; i < smartlist_len(sl); i++) {
|
2007-01-27 10:13:19 +01:00
|
|
|
if (statuses) {
|
|
|
|
status = smartlist_get(sl, i);
|
|
|
|
is_exit = status->is_exit;
|
|
|
|
} else {
|
|
|
|
router = smartlist_get(sl, i);
|
|
|
|
is_exit = router->is_exit;
|
|
|
|
}
|
|
|
|
if (is_exit)
|
2006-10-01 23:59:09 +02:00
|
|
|
tmp += ((uint64_t)(bandwidths[i] * exit_weight));
|
|
|
|
else
|
|
|
|
tmp += bandwidths[i];
|
2004-11-28 10:05:49 +01:00
|
|
|
if (tmp >= rand_bw)
|
2004-08-15 10:15:12 +02:00
|
|
|
break;
|
|
|
|
}
|
2006-10-01 23:59:09 +02:00
|
|
|
tor_free(bandwidths);
|
2007-01-27 10:13:19 +01:00
|
|
|
return smartlist_get(sl, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Choose a random element of router list <b>sl</b>, weighted by
|
|
|
|
* the advertised bandwidth of each router.
|
|
|
|
*/
|
|
|
|
routerinfo_t *
|
|
|
|
routerlist_sl_choose_by_bandwidth(smartlist_t *sl, int for_exit)
|
|
|
|
{
|
|
|
|
return smartlist_choose_by_bandwidth(sl, for_exit, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Choose a random element of status list <b>sl</b>, weighted by
|
|
|
|
* the advertised bandwidth of each status.
|
|
|
|
*/
|
|
|
|
routerstatus_t *
|
|
|
|
routerstatus_sl_choose_by_bandwidth(smartlist_t *sl)
|
|
|
|
{
|
2007-01-27 19:33:33 +01:00
|
|
|
return smartlist_choose_by_bandwidth(sl, 1, 1);
|
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-12-15 10:53:00 +01:00
|
|
|
* If <b>need_uptime</b> is non-zero and any router has more than
|
|
|
|
* a minimum uptime, return one of those.
|
2005-06-21 01:04:13 +02:00
|
|
|
* If <b>need_capacity</b> is non-zero, weight your choice by the
|
|
|
|
* advertised capacity of each router.
|
2007-02-02 19:58:11 +01:00
|
|
|
* If ! <b>allow_invalid</b>, consider only Valid routers.
|
|
|
|
* If <b>need_guard</b>, consider only Guard routers.
|
|
|
|
* If <b>weight_for_exit</b>, we weight bandwidths as if picking an exit node,
|
|
|
|
* otherwise we weight bandwidths for picking a relay node (that is, possibly
|
|
|
|
* discounting exit nodes).
|
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,
|
2006-02-12 04:43:39 +01:00
|
|
|
int need_guard,
|
2006-10-01 23:59:09 +02:00
|
|
|
int allow_invalid, int strict,
|
|
|
|
int weight_for_exit)
|
2004-04-03 00:23:15 +02:00
|
|
|
{
|
|
|
|
smartlist_t *sl, *excludednodes;
|
2006-01-05 11:59:46 +01:00
|
|
|
routerinfo_t *choice = NULL;
|
2004-04-03 00:23:15 +02:00
|
|
|
|
|
|
|
excludednodes = smartlist_create();
|
2007-02-13 02:27:55 +01:00
|
|
|
add_nickname_list_to_smartlist(excludednodes,excluded,0);
|
2004-04-03 00:23:15 +02:00
|
|
|
|
2006-02-12 04:43:39 +01:00
|
|
|
/* Try the preferred nodes first. Ignore need_uptime and need_capacity
|
|
|
|
* and need_guard, since the user explicitly asked for these nodes. */
|
2006-01-05 11:59:46 +01:00
|
|
|
if (preferred) {
|
|
|
|
sl = smartlist_create();
|
2007-02-13 02:27:55 +01:00
|
|
|
add_nickname_list_to_smartlist(sl,preferred,1);
|
2006-01-05 11:59:46 +01:00
|
|
|
smartlist_subtract(sl,excludednodes);
|
|
|
|
if (excludedsmartlist)
|
|
|
|
smartlist_subtract(sl,excludedsmartlist);
|
|
|
|
choice = smartlist_choose(sl);
|
|
|
|
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();
|
2006-03-19 02:21:59 +01:00
|
|
|
router_add_running_routers_to_smartlist(sl, allow_invalid,
|
2006-02-12 04:43:39 +01:00
|
|
|
need_uptime, need_capacity,
|
|
|
|
need_guard);
|
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);
|
2007-01-22 06:59:59 +01:00
|
|
|
|
2006-12-29 21:49:47 +01:00
|
|
|
if (need_capacity)
|
2006-10-01 23:59:09 +02:00
|
|
|
choice = routerlist_sl_choose_by_bandwidth(sl, weight_for_exit);
|
2004-08-18 09:53:43 +02:00
|
|
|
else
|
|
|
|
choice = smartlist_choose(sl);
|
2007-01-22 06:59:59 +01:00
|
|
|
|
2004-04-03 00:23:15 +02:00
|
|
|
smartlist_free(sl);
|
2006-02-12 04:43:39 +01:00
|
|
|
if (!choice && (need_uptime || need_capacity || need_guard)) {
|
2005-12-15 10:53:00 +01:00
|
|
|
/* try once more -- recurse but with fewer restrictions. */
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_CIRC,
|
|
|
|
"We couldn't find any live%s%s%s routers; falling back "
|
|
|
|
"to list of all routers.",
|
|
|
|
need_capacity?", fast":"",
|
|
|
|
need_uptime?", stable":"",
|
|
|
|
need_guard?", guard":"");
|
2005-12-15 10:53:00 +01:00
|
|
|
choice = router_choose_random_node(
|
2006-10-01 23:59:09 +02:00
|
|
|
NULL, excluded, excludedsmartlist,
|
|
|
|
0, 0, 0, allow_invalid, 0, weight_for_exit);
|
2005-12-15 10:53:00 +01:00
|
|
|
}
|
2004-04-03 00:23:15 +02:00
|
|
|
}
|
|
|
|
smartlist_free(excludednodes);
|
2007-02-13 02:27:55 +01:00
|
|
|
if (!choice) {
|
|
|
|
if (strict) {
|
|
|
|
log_warn(LD_CIRC, "All preferred nodes were down when trying to choose "
|
2007-02-24 06:36:45 +01:00
|
|
|
"node, and the Strict[...]Nodes option is set. Failing.");
|
2007-02-13 02:27:55 +01:00
|
|
|
} else {
|
|
|
|
log_warn(LD_CIRC,
|
|
|
|
"No available nodes when trying to choose node. Failing.");
|
|
|
|
}
|
|
|
|
}
|
2004-04-03 00:23:15 +02:00
|
|
|
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];
|
2006-10-03 20:58:40 +02:00
|
|
|
size_t len;
|
2004-07-03 01:40:03 +02:00
|
|
|
tor_assert(hexdigest);
|
|
|
|
if (hexdigest[0] == '$')
|
|
|
|
++hexdigest;
|
|
|
|
|
2006-10-03 20:58:40 +02:00
|
|
|
len = strlen(hexdigest);
|
|
|
|
if (len < HEX_DIGEST_LEN)
|
|
|
|
return 0;
|
|
|
|
else if (len > HEX_DIGEST_LEN &&
|
|
|
|
(hexdigest[HEX_DIGEST_LEN] == '=' ||
|
|
|
|
hexdigest[HEX_DIGEST_LEN] == '~')) {
|
|
|
|
if (strcasecmp(hexdigest+HEX_DIGEST_LEN+1, router->nickname))
|
|
|
|
return 0;
|
|
|
|
if (hexdigest[HEX_DIGEST_LEN] == '=' && !router->is_named)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (base16_decode(digest, DIGEST_LEN, hexdigest, HEX_DIGEST_LEN)<0)
|
2004-07-03 01:40:03 +02:00
|
|
|
return 0;
|
2005-11-05 21:15:27 +01:00
|
|
|
return (!memcmp(digest, router->cache_info.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 *
|
2005-10-05 00:23:31 +02:00
|
|
|
router_get_by_nickname(const char *nickname, int warn_if_unnamed)
|
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];
|
2005-10-05 00:23:31 +02:00
|
|
|
routerinfo_t *best_match=NULL;
|
|
|
|
int n_matches = 0;
|
2006-09-20 01:48:14 +02:00
|
|
|
char *named_digest = NULL;
|
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);
|
2006-09-29 06:51:28 +02:00
|
|
|
if (!strcasecmp(nickname, UNNAMED_ROUTER_NICKNAME))
|
|
|
|
return NULL;
|
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
|
|
|
|
2006-10-03 20:58:40 +02:00
|
|
|
maybedigest = (strlen(nickname) >= HEX_DIGEST_LEN) &&
|
2004-07-01 03:16:59 +02:00
|
|
|
(base16_decode(digest,DIGEST_LEN,nickname,HEX_DIGEST_LEN) == 0);
|
|
|
|
|
2006-09-20 01:48:14 +02:00
|
|
|
if (named_server_map &&
|
|
|
|
(named_digest = strmap_get_lc(named_server_map, nickname))) {
|
|
|
|
return digestmap_get(routerlist->identity_map, named_digest);
|
|
|
|
}
|
|
|
|
|
2005-09-13 17:32:03 +02:00
|
|
|
SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router,
|
|
|
|
{
|
2005-10-05 00:23:31 +02:00
|
|
|
if (!strcasecmp(router->nickname, nickname)) {
|
2006-09-20 01:48:14 +02:00
|
|
|
++n_matches;
|
|
|
|
if (n_matches <= 1 || router->is_running)
|
|
|
|
best_match = router;
|
2005-10-05 00:23:31 +02:00
|
|
|
} else if (maybedigest &&
|
2005-12-14 21:40:40 +01:00
|
|
|
!memcmp(digest, router->cache_info.identity_digest, DIGEST_LEN)
|
|
|
|
) {
|
2006-10-03 20:58:40 +02:00
|
|
|
if (router_hex_digest_matches(router, nickname))
|
|
|
|
return router;
|
|
|
|
else
|
|
|
|
best_match = router; // XXXX NM not exactly right.
|
2005-10-05 00:23:31 +02:00
|
|
|
}
|
2005-09-13 17:32:03 +02:00
|
|
|
});
|
2004-07-01 03:16:59 +02:00
|
|
|
|
2005-10-05 00:23:31 +02:00
|
|
|
if (best_match) {
|
2005-10-11 03:57:28 +02:00
|
|
|
if (warn_if_unnamed && n_matches > 1) {
|
2005-10-05 00:23:31 +02:00
|
|
|
smartlist_t *fps = smartlist_create();
|
|
|
|
int any_unwarned = 0;
|
|
|
|
SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router,
|
|
|
|
{
|
|
|
|
local_routerstatus_t *rs;
|
|
|
|
char *desc;
|
|
|
|
size_t dlen;
|
|
|
|
char fp[HEX_DIGEST_LEN+1];
|
|
|
|
if (strcasecmp(router->nickname, nickname))
|
|
|
|
continue;
|
2005-12-14 21:40:40 +01:00
|
|
|
rs = router_get_combined_status_by_digest(
|
|
|
|
router->cache_info.identity_digest);
|
2006-04-04 05:25:36 +02:00
|
|
|
if (rs && !rs->name_lookup_warned) {
|
2005-10-05 00:23:31 +02:00
|
|
|
rs->name_lookup_warned = 1;
|
|
|
|
any_unwarned = 1;
|
|
|
|
}
|
2005-12-14 21:40:40 +01:00
|
|
|
base16_encode(fp, sizeof(fp),
|
|
|
|
router->cache_info.identity_digest, DIGEST_LEN);
|
2005-10-05 00:23:31 +02:00
|
|
|
dlen = 32 + HEX_DIGEST_LEN + strlen(router->address);
|
|
|
|
desc = tor_malloc(dlen);
|
|
|
|
tor_snprintf(desc, dlen, "\"$%s\" for the one at %s:%d",
|
|
|
|
fp, router->address, router->or_port);
|
|
|
|
smartlist_add(fps, desc);
|
|
|
|
});
|
|
|
|
if (any_unwarned) {
|
|
|
|
char *alternatives = smartlist_join_strings(fps, "; ",0,NULL);
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_CONFIG,
|
|
|
|
"There are multiple matches for the nickname \"%s\","
|
2006-04-25 08:02:46 +02:00
|
|
|
" but none is listed as named by the directory authorities. "
|
2006-04-04 05:25:36 +02:00
|
|
|
"Choosing one arbitrarily. If you meant one in particular, "
|
2006-02-13 11:33:00 +01:00
|
|
|
"you should say %s.", nickname, alternatives);
|
2005-10-05 00:23:31 +02:00
|
|
|
tor_free(alternatives);
|
|
|
|
}
|
|
|
|
SMARTLIST_FOREACH(fps, char *, cp, tor_free(cp));
|
|
|
|
smartlist_free(fps);
|
|
|
|
} else if (warn_if_unnamed) {
|
2005-12-14 21:40:40 +01:00
|
|
|
local_routerstatus_t *rs = router_get_combined_status_by_digest(
|
|
|
|
best_match->cache_info.identity_digest);
|
2005-10-05 00:23:31 +02:00
|
|
|
if (rs && !rs->name_lookup_warned) {
|
|
|
|
char fp[HEX_DIGEST_LEN+1];
|
2005-12-14 21:40:40 +01:00
|
|
|
base16_encode(fp, sizeof(fp),
|
|
|
|
best_match->cache_info.identity_digest, DIGEST_LEN);
|
2007-03-04 19:58:38 +01:00
|
|
|
log_warn(LD_CONFIG, "You specified a server \"%s\" by name, but this "
|
|
|
|
"name is not registered, so it could be used by any server, "
|
|
|
|
"not just the one you meant. "
|
2005-12-10 10:36:26 +01:00
|
|
|
"To make sure you get the same server in the future, refer to "
|
|
|
|
"it by key, as \"$%s\".", nickname, fp);
|
2005-10-05 00:23:31 +02:00
|
|
|
rs->name_lookup_warned = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return best_match;
|
|
|
|
}
|
|
|
|
|
2004-07-01 03:16:59 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2005-11-19 07:57:44 +01:00
|
|
|
/** Try to find a routerinfo for <b>digest</b>. If we don't have one,
|
|
|
|
* return 1. If we do, ask tor_version_as_new_as() for the answer.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
router_digest_version_as_new_as(const char *digest, const char *cutoff)
|
|
|
|
{
|
|
|
|
routerinfo_t *router = router_get_by_digest(digest);
|
|
|
|
if (!router)
|
|
|
|
return 1;
|
|
|
|
return tor_version_as_new_as(router->platform, cutoff);
|
|
|
|
}
|
|
|
|
|
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;
|
2006-04-08 23:19:40 +02:00
|
|
|
if (get_options()->AuthoritativeDir &&
|
|
|
|
router_digest_is_me(digest))
|
|
|
|
return 1;
|
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];
|
2006-10-03 20:58:40 +02:00
|
|
|
size_t len;
|
|
|
|
routerinfo_t *ri;
|
2004-07-01 03:16:59 +02:00
|
|
|
|
|
|
|
tor_assert(hexdigest);
|
|
|
|
if (!routerlist)
|
|
|
|
return NULL;
|
2004-07-03 01:40:03 +02:00
|
|
|
if (hexdigest[0]=='$')
|
|
|
|
++hexdigest;
|
2006-10-03 20:58:40 +02:00
|
|
|
len = strlen(hexdigest);
|
|
|
|
if (len < HEX_DIGEST_LEN ||
|
2004-07-01 03:16:59 +02:00
|
|
|
base16_decode(digest,DIGEST_LEN,hexdigest,HEX_DIGEST_LEN) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
2006-10-03 20:58:40 +02:00
|
|
|
ri = router_get_by_digest(digest);
|
|
|
|
|
|
|
|
if (len > HEX_DIGEST_LEN) {
|
|
|
|
if (hexdigest[HEX_DIGEST_LEN] == '=') {
|
|
|
|
if (strcasecmp(ri->nickname, hexdigest+HEX_DIGEST_LEN+1) ||
|
|
|
|
!ri->is_named)
|
|
|
|
return NULL;
|
|
|
|
} else if (hexdigest[HEX_DIGEST_LEN] == '~') {
|
|
|
|
if (strcasecmp(ri->nickname, hexdigest+HEX_DIGEST_LEN+1))
|
|
|
|
return NULL;
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ri;
|
2004-07-01 03:16:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** 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-10-18 22:13:09 +02:00
|
|
|
// routerlist_assert_ok(routerlist);
|
2004-04-06 00:22:42 +02:00
|
|
|
|
2005-10-18 22:13:09 +02:00
|
|
|
return digestmap_get(routerlist->identity_map, digest);
|
2003-09-25 07:17:11 +02:00
|
|
|
}
|
2003-09-11 22:32:15 +02:00
|
|
|
|
2005-10-14 06:56:20 +02:00
|
|
|
/** Return the router in our routerlist whose 20-byte descriptor
|
|
|
|
* is <b>digest</b>. Return NULL if no such router is known. */
|
2005-11-05 21:15:27 +01:00
|
|
|
signed_descriptor_t *
|
2005-10-14 06:56:20 +02:00
|
|
|
router_get_by_descriptor_digest(const char *digest)
|
|
|
|
{
|
|
|
|
tor_assert(digest);
|
|
|
|
|
|
|
|
if (!routerlist) return NULL;
|
|
|
|
|
2005-11-05 21:15:27 +01:00
|
|
|
return digestmap_get(routerlist->desc_digest_map, digest);
|
2005-10-14 06:56:20 +02:00
|
|
|
}
|
|
|
|
|
2007-01-22 08:51:06 +01:00
|
|
|
/** Return a pointer to the signed textual representation of a descriptor.
|
|
|
|
* The returned string is not guaranteed to be NUL-terminated: the string's
|
2007-01-22 20:20:33 +01:00
|
|
|
* length will be in desc-\>signed_descriptor_len. */
|
2006-01-12 19:04:17 +01:00
|
|
|
const char *
|
|
|
|
signed_descriptor_get_body(signed_descriptor_t *desc)
|
|
|
|
{
|
2006-06-22 09:01:54 +02:00
|
|
|
const char *r;
|
|
|
|
size_t len = desc->signed_descriptor_len;
|
|
|
|
tor_assert(len > 32);
|
|
|
|
if (desc->saved_location == SAVED_IN_CACHE && routerlist &&
|
|
|
|
routerlist->mmap_descriptors) {
|
2006-08-05 19:53:21 +02:00
|
|
|
tor_assert(desc->saved_offset + len <= routerlist->mmap_descriptors->size);
|
|
|
|
r = routerlist->mmap_descriptors->data + desc->saved_offset;
|
2006-06-22 09:01:54 +02:00
|
|
|
} else {
|
|
|
|
r = desc->signed_descriptor_body;
|
|
|
|
}
|
|
|
|
tor_assert(r);
|
|
|
|
tor_assert(!memcmp("router ", r, 7));
|
2006-06-28 10:57:41 +02:00
|
|
|
#if 0
|
2006-06-22 09:01:54 +02:00
|
|
|
tor_assert(!memcmp("\n-----END SIGNATURE-----\n",
|
|
|
|
r + len - 25, 25));
|
2006-06-28 10:57:41 +02:00
|
|
|
#endif
|
2006-06-22 09:01:54 +02:00
|
|
|
|
|
|
|
return r;
|
2006-01-12 19:04:17 +01:00
|
|
|
}
|
|
|
|
|
2005-10-18 19:43:54 +02:00
|
|
|
/** Return the current list of all known routers. */
|
|
|
|
routerlist_t *
|
|
|
|
router_get_routerlist(void)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2005-10-18 19:43:54 +02:00
|
|
|
if (!routerlist) {
|
|
|
|
routerlist = tor_malloc_zero(sizeof(routerlist_t));
|
|
|
|
routerlist->routers = smartlist_create();
|
2005-10-27 02:34:39 +02:00
|
|
|
routerlist->old_routers = smartlist_create();
|
2005-10-18 22:13:09 +02:00
|
|
|
routerlist->identity_map = digestmap_new();
|
2005-10-27 02:34:39 +02:00
|
|
|
routerlist->desc_digest_map = digestmap_new();
|
2005-10-18 19:43:54 +02:00
|
|
|
}
|
|
|
|
return 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;
|
|
|
|
|
2006-01-12 19:04:17 +01:00
|
|
|
tor_free(router->cache_info.signed_descriptor_body);
|
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
|
|
|
}
|
|
|
|
|
2005-12-27 06:26:03 +01:00
|
|
|
/** Release storage held by <b>sd</b>. */
|
2005-11-05 21:15:27 +01:00
|
|
|
static void
|
|
|
|
signed_descriptor_free(signed_descriptor_t *sd)
|
|
|
|
{
|
2006-01-12 19:04:17 +01:00
|
|
|
tor_free(sd->signed_descriptor_body);
|
2005-11-05 21:15:27 +01:00
|
|
|
tor_free(sd);
|
|
|
|
}
|
|
|
|
|
2005-12-27 06:26:03 +01:00
|
|
|
/** Extract a signed_descriptor_t from a routerinfo, and free the routerinfo.
|
|
|
|
*/
|
2005-11-05 21:15:27 +01:00
|
|
|
static signed_descriptor_t *
|
|
|
|
signed_descriptor_from_routerinfo(routerinfo_t *ri)
|
|
|
|
{
|
|
|
|
signed_descriptor_t *sd = tor_malloc_zero(sizeof(signed_descriptor_t));
|
|
|
|
memcpy(sd, &(ri->cache_info), sizeof(signed_descriptor_t));
|
2006-01-12 19:04:17 +01:00
|
|
|
ri->cache_info.signed_descriptor_body = NULL;
|
2005-11-05 21:15:27 +01:00
|
|
|
routerinfo_free(ri);
|
|
|
|
return sd;
|
|
|
|
}
|
|
|
|
|
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);
|
2005-10-18 22:13:09 +02:00
|
|
|
digestmap_free(rl->identity_map, NULL);
|
2005-10-27 02:34:39 +02:00
|
|
|
digestmap_free(rl->desc_digest_map, NULL);
|
2004-04-07 21:46:27 +02:00
|
|
|
SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r,
|
|
|
|
routerinfo_free(r));
|
2005-11-05 21:15:27 +01:00
|
|
|
SMARTLIST_FOREACH(rl->old_routers, signed_descriptor_t *, sd,
|
|
|
|
signed_descriptor_free(sd));
|
2004-04-07 21:46:27 +02:00
|
|
|
smartlist_free(rl->routers);
|
2005-10-27 02:34:39 +02:00
|
|
|
smartlist_free(rl->old_routers);
|
2006-08-27 04:07:54 +02:00
|
|
|
if (routerlist->mmap_descriptors)
|
|
|
|
tor_munmap_file(routerlist->mmap_descriptors);
|
2004-04-07 21:46:27 +02:00
|
|
|
tor_free(rl);
|
2006-08-31 20:46:46 +02:00
|
|
|
|
|
|
|
router_dir_info_changed();
|
2003-05-06 19:38:16 +02:00
|
|
|
}
|
|
|
|
|
2005-11-23 07:00:58 +01:00
|
|
|
void
|
|
|
|
dump_routerlist_mem_usage(int severity)
|
|
|
|
{
|
|
|
|
uint64_t livedescs = 0;
|
|
|
|
uint64_t olddescs = 0;
|
|
|
|
if (!routerlist)
|
|
|
|
return;
|
|
|
|
SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, r,
|
|
|
|
livedescs += r->cache_info.signed_descriptor_len);
|
|
|
|
SMARTLIST_FOREACH(routerlist->old_routers, signed_descriptor_t *, sd,
|
2005-11-23 08:06:36 +01:00
|
|
|
olddescs += sd->signed_descriptor_len);
|
2005-11-23 07:00:58 +01:00
|
|
|
|
|
|
|
log(severity, LD_GENERAL,
|
|
|
|
"In %d live descriptors: "U64_FORMAT" bytes. "
|
|
|
|
"In %d old descriptors: "U64_FORMAT" bytes.",
|
|
|
|
smartlist_len(routerlist->routers), U64_PRINTF_ARG(livedescs),
|
|
|
|
smartlist_len(routerlist->old_routers), U64_PRINTF_ARG(olddescs));
|
|
|
|
}
|
|
|
|
|
2006-03-27 19:29:53 +02:00
|
|
|
/** Return the greatest number of routerdescs we'll hold for any given router.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
max_descriptors_per_router(void)
|
|
|
|
{
|
2006-09-29 01:57:59 +02:00
|
|
|
int n_authorities = get_n_v2_authorities();
|
2006-03-27 19:29:53 +02:00
|
|
|
return (n_authorities < 5) ? 5 : n_authorities;
|
|
|
|
}
|
|
|
|
|
2005-11-23 08:30:44 +01:00
|
|
|
/** Return non-zero if we have a lot of extra descriptors in our
|
|
|
|
* routerlist, and should get rid of some of them. Else return 0.
|
|
|
|
*
|
|
|
|
* We should be careful to not return true too eagerly, since we
|
|
|
|
* could churn. By using "+1" below, we make sure this function
|
|
|
|
* only returns true at most every smartlist_len(rl-\>routers)
|
|
|
|
* new descriptors.
|
|
|
|
*/
|
2005-11-23 08:06:36 +01:00
|
|
|
static INLINE int
|
|
|
|
routerlist_is_overfull(routerlist_t *rl)
|
|
|
|
{
|
|
|
|
return smartlist_len(rl->old_routers) >
|
2006-03-27 19:29:53 +02:00
|
|
|
smartlist_len(rl->routers)*(max_descriptors_per_router()+1);
|
2005-11-23 08:06:36 +01:00
|
|
|
}
|
|
|
|
|
2005-10-27 02:34:39 +02:00
|
|
|
static INLINE int
|
2005-11-05 21:15:27 +01:00
|
|
|
_routerlist_find_elt(smartlist_t *sl, void *ri, int idx)
|
2005-10-27 02:34:39 +02:00
|
|
|
{
|
|
|
|
if (idx < 0 || smartlist_get(sl, idx) != ri) {
|
|
|
|
idx = -1;
|
|
|
|
SMARTLIST_FOREACH(sl, routerinfo_t *, r,
|
|
|
|
if (r == ri) {
|
|
|
|
idx = r_sl_idx;
|
|
|
|
break;
|
|
|
|
});
|
|
|
|
}
|
2005-10-28 01:06:09 +02:00
|
|
|
return idx;
|
2005-10-27 02:34:39 +02:00
|
|
|
}
|
|
|
|
|
2005-10-18 19:43:54 +02:00
|
|
|
/** Insert an item <b>ri</b> into the routerlist <b>rl</b>, updating indices
|
2007-03-11 21:34:44 +01:00
|
|
|
* as needed. There must be no previous member of <b>rl</b> with the same
|
2007-03-11 21:52:07 +01:00
|
|
|
* identity digest as <b>ri</b>: If there is, call routerlist_replace
|
2007-03-11 21:34:44 +01:00
|
|
|
* instead.
|
|
|
|
*/
|
2005-10-18 19:43:54 +02:00
|
|
|
static void
|
|
|
|
routerlist_insert(routerlist_t *rl, routerinfo_t *ri)
|
|
|
|
{
|
2007-03-11 21:34:44 +01:00
|
|
|
routerinfo_t *ri_old;
|
|
|
|
ri_old = digestmap_set(rl->identity_map, ri->cache_info.identity_digest, ri);
|
|
|
|
tor_assert(!ri_old);
|
2005-11-05 21:15:27 +01:00
|
|
|
digestmap_set(rl->desc_digest_map, ri->cache_info.signed_descriptor_digest,
|
|
|
|
&(ri->cache_info));
|
2005-10-18 19:43:54 +02:00
|
|
|
smartlist_add(rl->routers, ri);
|
2006-09-20 01:18:30 +02:00
|
|
|
ri->routerlist_index = smartlist_len(rl->routers) - 1;
|
2006-08-15 05:54:09 +02:00
|
|
|
router_dir_info_changed();
|
2005-10-18 22:13:09 +02:00
|
|
|
// routerlist_assert_ok(rl);
|
2005-10-18 19:43:54 +02:00
|
|
|
}
|
|
|
|
|
2007-02-26 06:33:17 +01:00
|
|
|
/** If we're a directory cache and routerlist <b>rl</b> doesn't have
|
|
|
|
* a copy of router <b>ri</b> yet, add it to the list of old (not
|
|
|
|
* recommended but still served) descriptors. Else free it. */
|
2005-10-27 02:34:39 +02:00
|
|
|
static void
|
|
|
|
routerlist_insert_old(routerlist_t *rl, routerinfo_t *ri)
|
|
|
|
{
|
2005-12-27 06:58:12 +01:00
|
|
|
if (get_options()->DirPort &&
|
2007-03-21 16:37:30 +01:00
|
|
|
ri->purpose == ROUTER_PURPOSE_GENERAL &&
|
2005-12-27 06:58:12 +01:00
|
|
|
!digestmap_get(rl->desc_digest_map,
|
|
|
|
ri->cache_info.signed_descriptor_digest)) {
|
2005-11-05 21:15:27 +01:00
|
|
|
signed_descriptor_t *sd = signed_descriptor_from_routerinfo(ri);
|
|
|
|
digestmap_set(rl->desc_digest_map, sd->signed_descriptor_digest, sd);
|
|
|
|
smartlist_add(rl->old_routers, sd);
|
2005-10-27 02:34:39 +02:00
|
|
|
} else {
|
|
|
|
routerinfo_free(ri);
|
|
|
|
}
|
2005-10-28 01:06:09 +02:00
|
|
|
// routerlist_assert_ok(rl);
|
2005-10-27 02:34:39 +02:00
|
|
|
}
|
|
|
|
|
2006-03-24 22:11:14 +01:00
|
|
|
/** Remove an item <b>ri</b> from the routerlist <b>rl</b>, updating indices
|
2005-10-18 19:43:54 +02:00
|
|
|
* as needed. If <b>idx</b> is nonnegative and smartlist_get(rl->routers,
|
|
|
|
* idx) == ri, we don't need to do a linear search over the list to decide
|
2005-11-01 04:48:51 +01:00
|
|
|
* which to remove. We fill the gap in rl->routers with a later element in
|
2007-03-21 16:37:30 +01:00
|
|
|
* the list, if any exists. <b>ri</b> is freed.
|
|
|
|
*
|
2007-03-26 16:08:29 +02:00
|
|
|
* If <b>make_old</b> is true, instead of deleting the router, we try adding
|
|
|
|
* it to rl->old_routers. */
|
2005-10-18 19:43:54 +02:00
|
|
|
void
|
2005-10-27 02:34:39 +02:00
|
|
|
routerlist_remove(routerlist_t *rl, routerinfo_t *ri, int idx, int make_old)
|
2005-10-18 19:43:54 +02:00
|
|
|
{
|
2005-10-18 22:13:09 +02:00
|
|
|
routerinfo_t *ri_tmp;
|
2005-10-27 02:34:39 +02:00
|
|
|
idx = _routerlist_find_elt(rl->routers, ri, idx);
|
|
|
|
if (idx < 0)
|
|
|
|
return;
|
2006-09-20 01:18:30 +02:00
|
|
|
ri->routerlist_index = -1;
|
2005-10-18 19:43:54 +02:00
|
|
|
smartlist_del(rl->routers, idx);
|
2006-09-20 01:18:30 +02:00
|
|
|
if (idx < smartlist_len(rl->routers)) {
|
|
|
|
routerinfo_t *r = smartlist_get(rl->routers, idx);
|
|
|
|
r->routerlist_index = idx;
|
|
|
|
}
|
|
|
|
|
2005-11-05 21:15:27 +01:00
|
|
|
ri_tmp = digestmap_remove(rl->identity_map, ri->cache_info.identity_digest);
|
2006-08-15 05:54:09 +02:00
|
|
|
router_dir_info_changed();
|
2005-10-18 22:13:09 +02:00
|
|
|
tor_assert(ri_tmp == ri);
|
2007-03-21 16:37:30 +01:00
|
|
|
if (make_old && get_options()->DirPort &&
|
|
|
|
ri->purpose == ROUTER_PURPOSE_GENERAL) {
|
2005-11-23 08:24:59 +01:00
|
|
|
signed_descriptor_t *sd;
|
|
|
|
sd = signed_descriptor_from_routerinfo(ri);
|
2005-11-05 21:15:27 +01:00
|
|
|
smartlist_add(rl->old_routers, sd);
|
|
|
|
digestmap_set(rl->desc_digest_map, sd->signed_descriptor_digest, sd);
|
2005-10-27 02:34:39 +02:00
|
|
|
} else {
|
|
|
|
ri_tmp = digestmap_remove(rl->desc_digest_map,
|
2005-11-05 21:15:27 +01:00
|
|
|
ri->cache_info.signed_descriptor_digest);
|
2005-10-27 02:34:39 +02:00
|
|
|
tor_assert(ri_tmp == ri);
|
2005-11-23 08:24:59 +01:00
|
|
|
router_bytes_dropped += ri->cache_info.signed_descriptor_len;
|
2005-10-27 02:34:39 +02:00
|
|
|
routerinfo_free(ri);
|
|
|
|
}
|
2005-10-28 01:06:09 +02:00
|
|
|
// routerlist_assert_ok(rl);
|
2005-10-27 02:34:39 +02:00
|
|
|
}
|
|
|
|
|
2005-11-01 18:34:17 +01:00
|
|
|
static void
|
2005-11-05 21:15:27 +01:00
|
|
|
routerlist_remove_old(routerlist_t *rl, signed_descriptor_t *sd, int idx)
|
2005-10-27 02:34:39 +02:00
|
|
|
{
|
2005-11-05 21:15:27 +01:00
|
|
|
signed_descriptor_t *sd_tmp;
|
|
|
|
idx = _routerlist_find_elt(rl->old_routers, sd, idx);
|
2005-10-27 02:34:39 +02:00
|
|
|
if (idx < 0)
|
|
|
|
return;
|
|
|
|
smartlist_del(rl->old_routers, idx);
|
2005-11-05 21:15:27 +01:00
|
|
|
sd_tmp = digestmap_remove(rl->desc_digest_map,
|
|
|
|
sd->signed_descriptor_digest);
|
|
|
|
tor_assert(sd_tmp == sd);
|
2005-11-23 08:24:59 +01:00
|
|
|
router_bytes_dropped += sd->signed_descriptor_len;
|
2005-11-05 21:15:27 +01:00
|
|
|
signed_descriptor_free(sd);
|
2005-11-23 08:24:59 +01:00
|
|
|
// routerlist_assert_ok(rl);
|
2005-10-18 19:43:54 +02:00
|
|
|
}
|
|
|
|
|
2005-10-19 05:08:50 +02:00
|
|
|
/** Remove <b>ri_old</b> from the routerlist <b>rl</b>, and replace it with
|
|
|
|
* <b>ri_new</b>, updating all index info. If <b>idx</b> is nonnegative and
|
|
|
|
* smartlist_get(rl->routers, idx) == ri, we don't need to do a linear
|
|
|
|
* search over the list to decide which to remove. We put ri_new in the same
|
2007-03-21 16:37:30 +01:00
|
|
|
* index as ri_old, if possible. ri is freed as appropriate.
|
|
|
|
*
|
2007-03-26 16:08:29 +02:00
|
|
|
* If <b>make_old</b> is true, instead of deleting the router, we try adding
|
|
|
|
* it to rl->old_routers. */
|
2005-10-19 05:02:28 +02:00
|
|
|
static void
|
|
|
|
routerlist_replace(routerlist_t *rl, routerinfo_t *ri_old,
|
2005-10-27 02:34:39 +02:00
|
|
|
routerinfo_t *ri_new, int idx, int make_old)
|
2005-10-19 05:02:28 +02:00
|
|
|
{
|
2007-03-11 21:34:44 +01:00
|
|
|
routerinfo_t *ri_tmp;
|
2005-10-28 01:06:09 +02:00
|
|
|
tor_assert(ri_old != ri_new);
|
2005-10-27 02:34:39 +02:00
|
|
|
idx = _routerlist_find_elt(rl->routers, ri_old, idx);
|
2006-08-15 05:54:09 +02:00
|
|
|
router_dir_info_changed();
|
2005-10-19 05:02:28 +02:00
|
|
|
if (idx >= 0) {
|
|
|
|
smartlist_set(rl->routers, idx, ri_new);
|
2006-09-20 01:18:30 +02:00
|
|
|
ri_old->routerlist_index = -1;
|
|
|
|
ri_new->routerlist_index = idx;
|
2005-10-19 05:02:28 +02:00
|
|
|
} else {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_BUG, "Appending entry from routerlist_replace.");
|
2005-10-28 01:06:09 +02:00
|
|
|
routerlist_insert(rl, ri_new);
|
|
|
|
return;
|
2005-10-19 05:02:28 +02:00
|
|
|
}
|
2005-12-14 21:40:40 +01:00
|
|
|
if (memcmp(ri_old->cache_info.identity_digest,
|
|
|
|
ri_new->cache_info.identity_digest, DIGEST_LEN)) {
|
2005-10-19 05:02:28 +02:00
|
|
|
/* digests don't match; digestmap_set won't replace */
|
2005-11-05 21:15:27 +01:00
|
|
|
digestmap_remove(rl->identity_map, ri_old->cache_info.identity_digest);
|
2005-10-19 05:02:28 +02:00
|
|
|
}
|
2007-03-11 21:34:44 +01:00
|
|
|
ri_tmp = digestmap_set(rl->identity_map,
|
|
|
|
ri_new->cache_info.identity_digest, ri_new);
|
2007-03-11 22:10:54 +01:00
|
|
|
tor_assert(!ri_tmp || ri_tmp == ri_old);
|
2005-12-14 21:40:40 +01:00
|
|
|
digestmap_set(rl->desc_digest_map,
|
|
|
|
ri_new->cache_info.signed_descriptor_digest, &(ri_new->cache_info));
|
2005-10-27 02:34:39 +02:00
|
|
|
|
2007-03-21 16:37:30 +01:00
|
|
|
if (make_old && get_options()->DirPort &&
|
|
|
|
ri_old->purpose == ROUTER_PURPOSE_GENERAL) {
|
2005-11-05 21:15:27 +01:00
|
|
|
signed_descriptor_t *sd = signed_descriptor_from_routerinfo(ri_old);
|
|
|
|
smartlist_add(rl->old_routers, sd);
|
|
|
|
digestmap_set(rl->desc_digest_map, sd->signed_descriptor_digest, sd);
|
2005-10-27 02:34:39 +02:00
|
|
|
} else {
|
2005-11-05 21:15:27 +01:00
|
|
|
if (memcmp(ri_old->cache_info.signed_descriptor_digest,
|
|
|
|
ri_new->cache_info.signed_descriptor_digest,
|
2005-10-27 02:34:39 +02:00
|
|
|
DIGEST_LEN)) {
|
|
|
|
/* digests don't match; digestmap_set didn't replace */
|
2005-12-14 21:40:40 +01:00
|
|
|
digestmap_remove(rl->desc_digest_map,
|
|
|
|
ri_old->cache_info.signed_descriptor_digest);
|
2005-10-27 02:34:39 +02:00
|
|
|
}
|
|
|
|
routerinfo_free(ri_old);
|
|
|
|
}
|
2005-10-28 01:06:09 +02:00
|
|
|
// routerlist_assert_ok(rl);
|
2005-10-19 05:02:28 +02:00
|
|
|
}
|
|
|
|
|
2005-11-01 04:48:51 +01:00
|
|
|
/** Free all memory held by the routerlist 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-10-05 03:53:44 +02:00
|
|
|
if (warned_conflicts) {
|
|
|
|
SMARTLIST_FOREACH(warned_conflicts, char *, cp, tor_free(cp));
|
|
|
|
smartlist_free(warned_conflicts);
|
2005-10-05 04:20:46 +02:00
|
|
|
warned_conflicts = NULL;
|
2005-10-05 03:53:44 +02:00
|
|
|
}
|
2005-09-15 01:42:06 +02:00
|
|
|
if (trusted_dir_servers) {
|
|
|
|
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
|
2005-10-05 07:03:52 +02:00
|
|
|
trusted_dir_server_free(ds));
|
2005-09-15 01:42:06 +02:00
|
|
|
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;
|
|
|
|
}
|
2006-09-25 18:06:39 +02:00
|
|
|
if (named_server_map) {
|
|
|
|
strmap_free(named_server_map, _tor_free);
|
|
|
|
}
|
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) {
|
2005-12-14 21:40:40 +01:00
|
|
|
SMARTLIST_FOREACH(ns->entries, routerstatus_t *, rs,
|
|
|
|
routerstatus_free(rs));
|
2005-09-02 22:37:31 +02:00
|
|
|
smartlist_free(ns->entries);
|
|
|
|
}
|
|
|
|
tor_free(ns);
|
|
|
|
}
|
|
|
|
|
2005-10-05 04:20:46 +02:00
|
|
|
/** Forget that we have issued any router-related warnings, so that we'll
|
|
|
|
* warn again if we see the same errors. */
|
|
|
|
void
|
|
|
|
routerlist_reset_warnings(void)
|
|
|
|
{
|
|
|
|
if (!warned_nicknames)
|
|
|
|
warned_nicknames = smartlist_create();
|
|
|
|
SMARTLIST_FOREACH(warned_nicknames, char *, cp, tor_free(cp));
|
|
|
|
smartlist_clear(warned_nicknames); /* now the list is empty. */
|
|
|
|
|
|
|
|
if (!warned_conflicts)
|
|
|
|
warned_conflicts = smartlist_create();
|
|
|
|
SMARTLIST_FOREACH(warned_conflicts, char *, cp, tor_free(cp));
|
|
|
|
smartlist_clear(warned_conflicts); /* now the list is empty. */
|
|
|
|
|
2005-11-28 17:29:27 +01:00
|
|
|
if (!routerstatus_list)
|
|
|
|
routerstatus_list = smartlist_create();
|
2005-10-05 04:20:46 +02:00
|
|
|
SMARTLIST_FOREACH(routerstatus_list, local_routerstatus_t *, rs,
|
|
|
|
rs->name_lookup_warned = 0);
|
|
|
|
|
2006-03-19 02:21:59 +01:00
|
|
|
have_warned_about_invalid_status = 0;
|
2005-10-05 04:20:46 +02:00
|
|
|
have_warned_about_old_version = 0;
|
|
|
|
have_warned_about_new_version = 0;
|
|
|
|
}
|
|
|
|
|
2006-03-18 02:24:04 +01:00
|
|
|
/** Mark the router with ID <b>digest</b> as running or non-running
|
|
|
|
* in our routerlist. */
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
2006-03-18 02:24:04 +01:00
|
|
|
router_set_status(const char *digest, int up)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2004-05-12 21:49:48 +02:00
|
|
|
routerinfo_t *router;
|
2005-12-14 23:05:10 +01:00
|
|
|
local_routerstatus_t *status;
|
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))
|
2006-03-18 02:24:04 +01:00
|
|
|
d->is_running = up);
|
2004-10-12 17:55:20 +02:00
|
|
|
|
2004-07-03 01:40:03 +02:00
|
|
|
router = router_get_by_digest(digest);
|
2005-12-14 23:05:10 +01:00
|
|
|
if (router) {
|
2006-03-18 02:24:04 +01:00
|
|
|
log_debug(LD_DIR,"Marking router '%s' as %s.",
|
|
|
|
router->nickname, up ? "up" : "down");
|
|
|
|
if (!up && router_is_me(router) && !we_are_hibernating())
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_NET, "We just marked ourself as down. Are your external "
|
|
|
|
"addresses reachable?");
|
2006-03-18 02:24:04 +01:00
|
|
|
router->is_running = up;
|
2005-12-14 23:05:10 +01:00
|
|
|
}
|
|
|
|
status = router_get_combined_status_by_digest(digest);
|
2006-10-20 23:04:39 +02:00
|
|
|
if (status && status->status.is_running != up) {
|
2006-03-18 02:24:04 +01:00
|
|
|
status->status.is_running = up;
|
2006-10-20 23:04:39 +02:00
|
|
|
control_event_networkstatus_changed_single(status);
|
2005-12-14 23:05:10 +01:00
|
|
|
}
|
2006-08-15 05:54:09 +02:00
|
|
|
router_dir_info_changed();
|
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
|
|
|
*
|
2006-01-04 05:42:10 +01:00
|
|
|
* If <b>from_cache</b>, this descriptor came from our disk cache. If
|
|
|
|
* <b>from_fetch</b>, we received it in response to a request we made.
|
|
|
|
* (If both are false, that means it was uploaded to us as an auth dir
|
|
|
|
* server or via the controller.)
|
|
|
|
*
|
2005-09-15 08:15:31 +02:00
|
|
|
* This function should be called *after*
|
2005-10-29 20:00:25 +02:00
|
|
|
* routers_update_status_from_networkstatus; subsequently, you should call
|
2005-09-15 08:15:31 +02:00
|
|
|
* router_rebuild_store and control_event_descriptors_changed.
|
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,
|
2006-01-04 05:42:10 +01:00
|
|
|
int from_cache, int from_fetch)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2006-03-17 06:50:41 +01:00
|
|
|
const char *id_digest;
|
2005-08-26 22:59:04 +02:00
|
|
|
int authdir = get_options()->AuthoritativeDir;
|
2006-03-19 02:21:59 +01:00
|
|
|
int authdir_believes_valid = 0;
|
2006-09-20 01:18:30 +02:00
|
|
|
routerinfo_t *old_router;
|
2004-08-07 05:38:07 +02:00
|
|
|
|
2005-08-27 01:12:13 +02:00
|
|
|
tor_assert(msg);
|
|
|
|
|
2005-10-18 22:13:09 +02:00
|
|
|
if (!routerlist)
|
|
|
|
router_get_routerlist();
|
2006-03-27 07:12:07 +02:00
|
|
|
if (!networkstatus_list)
|
|
|
|
networkstatus_list = smartlist_create();
|
2005-08-26 23:12:34 +02:00
|
|
|
|
2006-03-17 06:50:41 +01:00
|
|
|
id_digest = router->cache_info.identity_digest;
|
2005-10-27 02:34:39 +02:00
|
|
|
|
|
|
|
/* Make sure that we haven't already got this exact descriptor. */
|
|
|
|
if (digestmap_get(routerlist->desc_digest_map,
|
2005-11-05 21:15:27 +01:00
|
|
|
router->cache_info.signed_descriptor_digest)) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_DIR,
|
|
|
|
"Dropping descriptor that we already have for router '%s'",
|
|
|
|
router->nickname);
|
2005-10-27 02:34:39 +02:00
|
|
|
*msg = "Router descriptor was not new.";
|
2005-10-28 20:44:51 +02:00
|
|
|
routerinfo_free(router);
|
2005-10-27 02:34:39 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2004-08-07 05:38:07 +02:00
|
|
|
|
2005-11-23 08:06:36 +01:00
|
|
|
if (routerlist_is_overfull(routerlist))
|
|
|
|
routerlist_remove_old_routers();
|
|
|
|
|
2005-08-26 22:59:04 +02:00
|
|
|
if (authdir) {
|
2006-01-04 05:42:10 +01:00
|
|
|
if (authdir_wants_to_reject_router(router, msg,
|
|
|
|
!from_cache && !from_fetch)) {
|
2006-01-12 04:43:39 +01:00
|
|
|
tor_assert(*msg);
|
2005-10-28 20:44:51 +02:00
|
|
|
routerinfo_free(router);
|
2005-08-26 23:46:24 +02:00
|
|
|
return -2;
|
2005-10-28 20:44:51 +02:00
|
|
|
}
|
2006-03-19 02:21:59 +01:00
|
|
|
authdir_believes_valid = router->is_valid;
|
2006-01-12 04:43:39 +01:00
|
|
|
} else if (from_fetch) {
|
2005-12-27 06:26:03 +01:00
|
|
|
/* Only check the descriptor digest against the network statuses when
|
2006-01-12 04:43:39 +01:00
|
|
|
* we are receiving in response to a fetch. */
|
2007-02-22 08:41:10 +01:00
|
|
|
|
2005-12-27 06:26:03 +01:00
|
|
|
if (!signed_desc_digest_is_recognized(&router->cache_info)) {
|
2007-02-22 08:41:10 +01:00
|
|
|
/* We asked for it, so some networkstatus must have listed it when we
|
2007-02-24 22:21:38 +01:00
|
|
|
* did. Save it if we're a cache in case somebody else asks for it. */
|
2007-02-22 08:41:10 +01:00
|
|
|
log_info(LD_DIR,
|
|
|
|
"Received a no-longer-recognized descriptor for router '%s'",
|
2006-02-13 11:33:00 +01:00
|
|
|
router->nickname);
|
2006-01-12 04:43:39 +01:00
|
|
|
*msg = "Router descriptor is not referenced by any network-status.";
|
2007-02-22 08:41:10 +01:00
|
|
|
|
|
|
|
/* Only journal this desc if we'll be serving it. */
|
|
|
|
if (!from_cache && get_options()->DirPort)
|
2007-03-21 16:37:30 +01:00
|
|
|
router_append_to_journal(&router->cache_info, router->purpose);
|
2007-02-22 08:41:10 +01:00
|
|
|
routerlist_insert_old(routerlist, router);
|
2005-10-12 15:49:13 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2005-08-26 22:59:04 +02:00
|
|
|
}
|
|
|
|
|
2006-03-27 07:07:57 +02:00
|
|
|
/* We no longer need a router with this descriptor digest. */
|
|
|
|
SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
|
|
|
|
{
|
|
|
|
routerstatus_t *rs =
|
|
|
|
networkstatus_find_entry(ns, router->cache_info.identity_digest);
|
|
|
|
if (rs && !memcmp(rs->descriptor_digest,
|
|
|
|
router->cache_info.signed_descriptor_digest,
|
|
|
|
DIGEST_LEN))
|
|
|
|
rs->need_to_mirror = 0;
|
|
|
|
});
|
|
|
|
|
2006-09-20 01:18:30 +02:00
|
|
|
/* If we have a router with the same identity key, choose the newer one. */
|
|
|
|
old_router = digestmap_get(routerlist->identity_map,
|
|
|
|
router->cache_info.identity_digest);
|
|
|
|
if (old_router) {
|
|
|
|
int pos = old_router->routerlist_index;
|
|
|
|
tor_assert(smartlist_get(routerlist->routers, pos) == old_router);
|
|
|
|
|
|
|
|
if (router->cache_info.published_on <=
|
|
|
|
old_router->cache_info.published_on) {
|
|
|
|
/* Same key, but old */
|
|
|
|
log_debug(LD_DIR, "Skipping not-new descriptor for router '%s'",
|
|
|
|
router->nickname);
|
|
|
|
/* Only journal this desc if we'll be serving it. */
|
|
|
|
if (!from_cache && get_options()->DirPort)
|
2007-03-21 16:37:30 +01:00
|
|
|
router_append_to_journal(&router->cache_info, router->purpose);
|
2006-09-20 01:18:30 +02:00
|
|
|
routerlist_insert_old(routerlist, router);
|
|
|
|
*msg = "Router descriptor was not new.";
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
/* Same key, new. */
|
|
|
|
int unreachable = 0;
|
|
|
|
log_debug(LD_DIR, "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;
|
|
|
|
router->num_unreachable_notifications =
|
|
|
|
old_router->num_unreachable_notifications;
|
|
|
|
}
|
|
|
|
if (authdir && !from_cache && !from_fetch &&
|
|
|
|
router_have_minimum_dir_info() &&
|
|
|
|
dirserv_thinks_router_is_blatantly_unreachable(router,
|
|
|
|
time(NULL))) {
|
|
|
|
if (router->num_unreachable_notifications >= 3) {
|
|
|
|
unreachable = 1;
|
|
|
|
log_notice(LD_DIR, "Notifying server '%s' that it's unreachable. "
|
|
|
|
"(ContactInfo '%s', platform '%s').",
|
|
|
|
router->nickname,
|
|
|
|
router->contact_info ? router->contact_info : "",
|
|
|
|
router->platform ? router->platform : "");
|
|
|
|
} else {
|
|
|
|
log_info(LD_DIR,"'%s' may be unreachable -- the %d previous "
|
|
|
|
"descriptors were thought to be unreachable.",
|
|
|
|
router->nickname, router->num_unreachable_notifications);
|
|
|
|
router->num_unreachable_notifications++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
routerlist_replace(routerlist, old_router, router, pos, 1);
|
|
|
|
if (!from_cache) {
|
2007-03-21 16:37:30 +01:00
|
|
|
router_append_to_journal(&router->cache_info, router->purpose);
|
2006-09-20 01:18:30 +02:00
|
|
|
}
|
|
|
|
directory_set_dirty();
|
|
|
|
*msg = unreachable ? "Dirserver believes your ORPort is unreachable" :
|
|
|
|
authdir_believes_valid ? "Valid server updated" :
|
|
|
|
("Invalid server updated. (This dirserver is marking your "
|
|
|
|
"server as unapproved.)");
|
|
|
|
return unreachable ? 1 : 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-24 08:50:38 +01:00
|
|
|
/* We haven't seen a router with this identity before. Add it to the end of
|
2004-05-17 22:31:01 +02:00
|
|
|
* the list. */
|
2005-10-18 19:43:54 +02:00
|
|
|
routerlist_insert(routerlist, router);
|
2005-09-15 07:19:38 +02:00
|
|
|
if (!from_cache)
|
2007-03-21 16:37:30 +01:00
|
|
|
router_append_to_journal(&router->cache_info, router->purpose);
|
2005-08-26 22:59:04 +02:00
|
|
|
directory_set_dirty();
|
2004-05-17 22:31:01 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-02-16 21:01:02 +01:00
|
|
|
/** Sorting helper: return <0, 0, or >0 depending on whether the
|
2007-02-24 08:50:38 +01:00
|
|
|
* signed_descriptor_t* in *<b>a</b> has an identity digest preceding, equal
|
|
|
|
* to, or later than that of *<b>b</b>. */
|
2005-10-27 02:34:39 +02:00
|
|
|
static int
|
|
|
|
_compare_old_routers_by_identity(const void **_a, const void **_b)
|
|
|
|
{
|
|
|
|
int i;
|
2005-11-05 21:15:27 +01:00
|
|
|
const signed_descriptor_t *r1 = *_a, *r2 = *_b;
|
2005-10-27 02:34:39 +02:00
|
|
|
if ((i = memcmp(r1->identity_digest, r2->identity_digest, DIGEST_LEN)))
|
|
|
|
return i;
|
|
|
|
return r1->published_on - r2->published_on;
|
|
|
|
}
|
|
|
|
|
2007-02-16 21:01:02 +01:00
|
|
|
/** Internal type used to represent how long an old descriptor was valid,
|
|
|
|
* where it appeared in the list of old descriptors, and whether it's extra
|
|
|
|
* old. Used only by routerlist_remove_old_cached_routers_with_id(). */
|
2005-10-27 02:34:39 +02:00
|
|
|
struct duration_idx_t {
|
|
|
|
int duration;
|
|
|
|
int idx;
|
|
|
|
int old;
|
|
|
|
};
|
|
|
|
|
2007-02-16 21:01:02 +01:00
|
|
|
/** Sorting helper: compare two duration_idx_t by their duration. */
|
2005-10-27 02:34:39 +02:00
|
|
|
static int
|
|
|
|
_compare_duration_idx(const void *_d1, const void *_d2)
|
|
|
|
{
|
|
|
|
const struct duration_idx_t *d1 = _d1;
|
|
|
|
const struct duration_idx_t *d2 = _d2;
|
|
|
|
return d1->duration - d2->duration;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** The range <b>lo</b> through <b>hi</b> inclusive of routerlist->old_routers
|
|
|
|
* must contain routerinfo_t with the same identity and with publication time
|
|
|
|
* in ascending order. Remove members from this range until there are no more
|
2006-03-27 19:29:53 +02:00
|
|
|
* than max_descriptors_per_router() remaining. Start by removing the oldest
|
2005-10-27 02:34:39 +02:00
|
|
|
* members from before <b>cutoff</b>, then remove members which were current
|
|
|
|
* for the lowest amount of time. The order of members of old_routers at
|
|
|
|
* indices <b>lo</b> or higher may be changed.
|
|
|
|
*/
|
|
|
|
static void
|
2005-12-27 06:26:03 +01:00
|
|
|
routerlist_remove_old_cached_routers_with_id(time_t cutoff, int lo, int hi,
|
|
|
|
digestmap_t *retain)
|
2005-10-27 02:34:39 +02:00
|
|
|
{
|
|
|
|
int i, n = hi-lo+1, n_extra;
|
|
|
|
int n_rmv = 0;
|
|
|
|
struct duration_idx_t *lifespans;
|
2005-12-27 06:26:03 +01:00
|
|
|
uint8_t *rmv, *must_keep;
|
2005-10-27 02:34:39 +02:00
|
|
|
smartlist_t *lst = routerlist->old_routers;
|
|
|
|
#if 1
|
|
|
|
const char *ident;
|
|
|
|
tor_assert(hi < smartlist_len(lst));
|
|
|
|
tor_assert(lo <= hi);
|
2005-11-05 21:15:27 +01:00
|
|
|
ident = ((signed_descriptor_t*)smartlist_get(lst, lo))->identity_digest;
|
2005-10-27 02:34:39 +02:00
|
|
|
for (i = lo+1; i <= hi; ++i) {
|
2005-11-05 21:15:27 +01:00
|
|
|
signed_descriptor_t *r = smartlist_get(lst, i);
|
2005-10-27 02:34:39 +02:00
|
|
|
tor_assert(!memcmp(ident, r->identity_digest, DIGEST_LEN));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Check whether we need to do anything at all. */
|
2006-03-27 19:29:53 +02:00
|
|
|
n_extra = n - max_descriptors_per_router();
|
2005-10-27 02:34:39 +02:00
|
|
|
if (n_extra <= 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
lifespans = tor_malloc_zero(sizeof(struct duration_idx_t)*n);
|
|
|
|
rmv = tor_malloc_zero(sizeof(uint8_t)*n);
|
2005-12-27 06:26:03 +01:00
|
|
|
must_keep = tor_malloc_zero(sizeof(uint8_t)*n);
|
2005-10-27 02:34:39 +02:00
|
|
|
/* Set lifespans to contain the lifespan and index of each server. */
|
|
|
|
/* Set rmv[i-lo]=1 if we're going to remove a server for being too old. */
|
|
|
|
for (i = lo; i <= hi; ++i) {
|
2005-11-05 21:15:27 +01:00
|
|
|
signed_descriptor_t *r = smartlist_get(lst, i);
|
|
|
|
signed_descriptor_t *r_next;
|
2005-11-04 17:47:26 +01:00
|
|
|
lifespans[i-lo].idx = i;
|
2005-12-27 06:26:03 +01:00
|
|
|
if (retain && digestmap_get(retain, r->signed_descriptor_digest)) {
|
|
|
|
must_keep[i-lo] = 1;
|
|
|
|
}
|
2005-10-27 02:34:39 +02:00
|
|
|
if (i < hi) {
|
|
|
|
r_next = smartlist_get(lst, i+1);
|
|
|
|
tor_assert(r->published_on <= r_next->published_on);
|
2005-11-05 21:15:27 +01:00
|
|
|
lifespans[i-lo].duration = (r_next->published_on - r->published_on);
|
2005-10-27 02:34:39 +02:00
|
|
|
} else {
|
|
|
|
r_next = NULL;
|
2005-11-04 17:47:26 +01:00
|
|
|
lifespans[i-lo].duration = INT_MAX;
|
2005-10-27 02:34:39 +02:00
|
|
|
}
|
2005-12-27 06:26:03 +01:00
|
|
|
if (!must_keep[i-lo] && r->published_on < cutoff && n_rmv < n_extra) {
|
2005-10-27 02:34:39 +02:00
|
|
|
++n_rmv;
|
2005-11-04 17:47:26 +01:00
|
|
|
lifespans[i-lo].old = 1;
|
2005-10-27 02:34:39 +02:00
|
|
|
rmv[i-lo] = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (n_rmv < n_extra) {
|
|
|
|
/**
|
|
|
|
* We aren't removing enough servers for being old. Sort lifespans by
|
|
|
|
* the duration of liveness, and remove the ones we're not already going to
|
|
|
|
* remove based on how long they were alive.
|
|
|
|
**/
|
|
|
|
qsort(lifespans, n, sizeof(struct duration_idx_t), _compare_duration_idx);
|
|
|
|
for (i = 0; i < n && n_rmv < n_extra; ++i) {
|
2005-12-27 06:26:03 +01:00
|
|
|
if (!must_keep[lifespans[i].idx-lo] && !lifespans[i].old) {
|
2005-10-27 02:34:39 +02:00
|
|
|
rmv[lifespans[i].idx-lo] = 1;
|
|
|
|
++n_rmv;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-11-04 17:47:26 +01:00
|
|
|
for (i = hi; i >= lo; --i) {
|
2005-10-27 02:34:39 +02:00
|
|
|
if (rmv[i-lo])
|
|
|
|
routerlist_remove_old(routerlist, smartlist_get(lst, i), i);
|
|
|
|
}
|
2005-12-27 06:26:03 +01:00
|
|
|
tor_free(must_keep);
|
2005-10-27 02:34:39 +02:00
|
|
|
tor_free(rmv);
|
|
|
|
tor_free(lifespans);
|
|
|
|
}
|
|
|
|
|
2005-11-11 18:16:24 +01:00
|
|
|
/** Deactivate any routers from the routerlist that are more than
|
2006-10-20 01:04:56 +02:00
|
|
|
* ROUTER_MAX_AGE seconds old and not recommended by any networkstatuses;
|
|
|
|
* remove old routers from the list of cached routers if we have too many.
|
2005-11-01 18:34:17 +01:00
|
|
|
*/
|
2005-10-27 02:34:39 +02:00
|
|
|
void
|
2005-11-01 18:34:17 +01:00
|
|
|
routerlist_remove_old_routers(void)
|
2005-10-27 02:34:39 +02:00
|
|
|
{
|
|
|
|
int i, hi=-1;
|
|
|
|
const char *cur_id = NULL;
|
2006-02-05 03:07:28 +01:00
|
|
|
time_t now = time(NULL);
|
|
|
|
time_t cutoff;
|
2005-11-01 18:34:17 +01:00
|
|
|
routerinfo_t *router;
|
2006-01-10 05:57:12 +01:00
|
|
|
signed_descriptor_t *sd;
|
2005-12-27 06:26:03 +01:00
|
|
|
digestmap_t *retain;
|
|
|
|
if (!routerlist || !networkstatus_list)
|
2005-10-27 02:34:39 +02:00
|
|
|
return;
|
|
|
|
|
2005-12-27 06:26:03 +01:00
|
|
|
retain = digestmap_new();
|
2006-02-05 03:07:28 +01:00
|
|
|
cutoff = now - OLD_ROUTER_DESC_MAX_AGE;
|
2006-10-20 01:04:56 +02:00
|
|
|
/* Build a list of all the descriptors that _anybody_ recommends. */
|
|
|
|
SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
|
|
|
|
{
|
2007-02-26 19:01:23 +01:00
|
|
|
/* XXXX The inner loop here gets pretty expensive, and actually shows up
|
|
|
|
* on some profiles. It may be the reason digestmap_set shows up in
|
|
|
|
* profiles too. If instead we kept a per-descriptor digest count of
|
|
|
|
* how many networkstatuses recommended each descriptor, and changed
|
|
|
|
* that only when the networkstatuses changed, that would be a speed
|
|
|
|
* improvement, possibly 1-4% if it also removes digestmap_set from the
|
|
|
|
* profile. Not worth it for 0.1.2.x, though. The new directory
|
|
|
|
* system will obsolete this whole thing in 0.2.0.x. */
|
2006-10-20 01:04:56 +02:00
|
|
|
SMARTLIST_FOREACH(ns->entries, routerstatus_t *, rs,
|
|
|
|
if (rs->published_on >= cutoff)
|
|
|
|
digestmap_set(retain, rs->descriptor_digest, (void*)1));
|
|
|
|
});
|
2005-12-27 06:26:03 +01:00
|
|
|
|
2006-10-20 01:04:56 +02:00
|
|
|
/* If we have a bunch of networkstatuses, we should consider pruning current
|
|
|
|
* routers that are too old and that nobody recommends. (If we don't have
|
|
|
|
* enough networkstatuses, then we should get more before we decide to kill
|
|
|
|
* routers.) */
|
|
|
|
if (smartlist_len(networkstatus_list) > get_n_v2_authorities() / 2) {
|
|
|
|
cutoff = now - ROUTER_MAX_AGE;
|
|
|
|
/* Remove too-old unrecommended members of routerlist->routers. */
|
|
|
|
for (i = 0; i < smartlist_len(routerlist->routers); ++i) {
|
|
|
|
router = smartlist_get(routerlist->routers, i);
|
|
|
|
if (router->cache_info.published_on <= cutoff &&
|
|
|
|
!digestmap_get(retain,router->cache_info.signed_descriptor_digest)) {
|
|
|
|
/* Too old: remove it. (If we're a cache, just move it into
|
|
|
|
* old_routers.) */
|
|
|
|
log_info(LD_DIR,
|
|
|
|
"Forgetting obsolete (too old) routerinfo for router '%s'",
|
|
|
|
router->nickname);
|
|
|
|
routerlist_remove(routerlist, router, i--, 1);
|
|
|
|
}
|
2005-11-01 18:34:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-10 05:57:12 +01:00
|
|
|
/* Remove far-too-old members of routerlist->old_routers. */
|
|
|
|
cutoff = now - OLD_ROUTER_DESC_MAX_AGE;
|
|
|
|
for (i = 0; i < smartlist_len(routerlist->old_routers); ++i) {
|
|
|
|
sd = smartlist_get(routerlist->old_routers, i);
|
|
|
|
if (sd->published_on <= cutoff &&
|
|
|
|
!digestmap_get(retain, sd->signed_descriptor_digest)) {
|
|
|
|
/* Too old. Remove it. */
|
|
|
|
routerlist_remove_old(routerlist, sd, i--);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-10-20 01:04:56 +02:00
|
|
|
/* Now we might have to look at routerlist->old_routers for extraneous
|
|
|
|
* members. (We'd keep all the members if we could, but we need to save
|
2006-01-10 05:57:12 +01:00
|
|
|
* space.) First, check whether we have too many router descriptors, total.
|
|
|
|
* We're okay with having too many for some given router, so long as the
|
2006-03-27 19:29:53 +02:00
|
|
|
* total number doesn't approach max_descriptors_per_router()*len(router).
|
2005-10-27 02:34:39 +02:00
|
|
|
*/
|
|
|
|
if (smartlist_len(routerlist->old_routers) <
|
2006-03-27 19:29:53 +02:00
|
|
|
smartlist_len(routerlist->routers) * (max_descriptors_per_router() - 1))
|
2006-01-11 04:58:07 +01:00
|
|
|
goto done;
|
2005-10-27 02:34:39 +02:00
|
|
|
|
|
|
|
smartlist_sort(routerlist->old_routers, _compare_old_routers_by_identity);
|
|
|
|
|
|
|
|
/* Iterate through the list from back to front, so when we remove descriptors
|
|
|
|
* we don't mess up groups we haven't gotten to. */
|
|
|
|
for (i = smartlist_len(routerlist->old_routers)-1; i >= 0; --i) {
|
2005-11-05 21:15:27 +01:00
|
|
|
signed_descriptor_t *r = smartlist_get(routerlist->old_routers, i);
|
2005-10-27 02:34:39 +02:00
|
|
|
if (!cur_id) {
|
|
|
|
cur_id = r->identity_digest;
|
|
|
|
hi = i;
|
|
|
|
}
|
|
|
|
if (memcmp(cur_id, r->identity_digest, DIGEST_LEN)) {
|
2005-12-27 06:26:03 +01:00
|
|
|
routerlist_remove_old_cached_routers_with_id(cutoff, i+1, hi, retain);
|
2005-11-23 08:28:54 +01:00
|
|
|
cur_id = r->identity_digest;
|
2005-10-27 02:34:39 +02:00
|
|
|
hi = i;
|
2004-05-20 07:10:30 +02:00
|
|
|
}
|
|
|
|
}
|
2005-11-01 18:34:17 +01:00
|
|
|
if (hi>=0)
|
2005-12-27 06:26:03 +01:00
|
|
|
routerlist_remove_old_cached_routers_with_id(cutoff, 0, hi, retain);
|
2005-11-01 18:34:17 +01:00
|
|
|
routerlist_assert_ok(routerlist);
|
2006-01-11 04:58:07 +01:00
|
|
|
|
|
|
|
done:
|
2005-12-27 06:26:03 +01:00
|
|
|
digestmap_free(retain, NULL);
|
2004-05-20 07:10:30 +02:00
|
|
|
}
|
|
|
|
|
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
|
2006-03-17 23:08:59 +01:00
|
|
|
router_load_single_router(const char *s, uint8_t purpose, const char **msg)
|
2005-02-25 21:46:13 +01:00
|
|
|
{
|
|
|
|
routerinfo_t *ri;
|
2006-02-15 04:01:53 +01:00
|
|
|
int r;
|
2005-10-05 03:27:08 +02:00
|
|
|
smartlist_t *lst;
|
2005-10-05 04:06:36 +02:00
|
|
|
tor_assert(msg);
|
2005-07-15 21:40:38 +02:00
|
|
|
*msg = NULL;
|
2005-02-25 21:46:13 +01:00
|
|
|
|
2006-06-22 09:01:54 +02:00
|
|
|
if (!(ri = router_parse_entry_from_string(s, NULL, 1))) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_DIR, "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;
|
|
|
|
}
|
2006-03-17 23:08:59 +01:00
|
|
|
ri->purpose = purpose;
|
2005-05-14 07:01:41 +02:00
|
|
|
if (router_is_me(ri)) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_DIR, "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-10-05 03:27:08 +02:00
|
|
|
|
|
|
|
lst = smartlist_create();
|
|
|
|
smartlist_add(lst, ri);
|
2005-12-27 06:26:03 +01:00
|
|
|
routers_update_status_from_networkstatus(lst, 0);
|
2005-09-14 23:09:25 +02:00
|
|
|
|
2006-02-15 04:01:53 +01:00
|
|
|
if ((r=router_add_to_routerlist(ri, msg, 0, 0))<0) {
|
2005-06-21 01:04:13 +02:00
|
|
|
/* we've already assigned to *msg now, and ri is already freed */
|
2006-02-15 04:01:53 +01:00
|
|
|
tor_assert(*msg);
|
|
|
|
if (r < -1)
|
|
|
|
log_warn(LD_DIR, "Couldn't add router to list: %s Dropping.", *msg);
|
2005-10-05 03:27:08 +02:00
|
|
|
smartlist_free(lst);
|
2005-04-03 00:02:13 +02:00
|
|
|
return 0;
|
2005-03-02 23:29:58 +01:00
|
|
|
} else {
|
2005-10-05 03:27:08 +02:00
|
|
|
control_event_descriptors_changed(lst);
|
|
|
|
smartlist_free(lst);
|
2006-02-13 11:33:00 +01:00
|
|
|
log_debug(LD_DIR, "Added router to list");
|
2005-10-05 03:27:08 +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
|
2007-01-22 08:51:06 +01:00
|
|
|
* routers into our directory. If saved_location is SAVED_NOWHERE, the routers
|
|
|
|
* are in response to a query to the network: cache them by adding them to
|
|
|
|
* the journal.
|
2005-09-15 08:15:31 +02:00
|
|
|
*
|
|
|
|
* 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
|
2006-06-22 09:01:54 +02:00
|
|
|
router_load_routers_from_string(const char *s, saved_location_t saved_location,
|
2005-09-15 07:19:38 +02:00
|
|
|
smartlist_t *requested_fingerprints)
|
|
|
|
{
|
|
|
|
smartlist_t *routers = smartlist_create(), *changed = smartlist_create();
|
|
|
|
char fp[HEX_DIGEST_LEN+1];
|
|
|
|
const char *msg;
|
2006-06-22 09:01:54 +02:00
|
|
|
int from_cache = (saved_location != SAVED_NOWHERE);
|
2005-09-15 07:19:38 +02:00
|
|
|
|
2006-06-22 09:01:54 +02:00
|
|
|
router_parse_list_from_string(&s, routers, saved_location);
|
2005-09-15 07:19:38 +02:00
|
|
|
|
2005-12-27 06:26:03 +01:00
|
|
|
routers_update_status_from_networkstatus(routers, !from_cache);
|
|
|
|
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_DIR, "%d elements to add", smartlist_len(routers));
|
2005-09-15 07:19:38 +02:00
|
|
|
|
|
|
|
SMARTLIST_FOREACH(routers, routerinfo_t *, ri,
|
|
|
|
{
|
2005-12-27 06:26:03 +01:00
|
|
|
base16_encode(fp, sizeof(fp), ri->cache_info.signed_descriptor_digest,
|
|
|
|
DIGEST_LEN);
|
2005-09-15 07:19:38 +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);
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_DIR,
|
|
|
|
"We received a router descriptor with a fingerprint (%s) "
|
|
|
|
"that we never requested. (We asked for: %s.) Dropping.",
|
|
|
|
fp, requested);
|
2005-09-15 07:19:38 +02:00
|
|
|
tor_free(requested);
|
|
|
|
routerinfo_free(ri);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-04 05:42:10 +01:00
|
|
|
if (router_add_to_routerlist(ri, &msg, from_cache, !from_cache) >= 0)
|
2005-09-15 07:19:38 +02:00
|
|
|
smartlist_add(changed, ri);
|
|
|
|
});
|
|
|
|
|
2005-10-12 21:41:16 +02:00
|
|
|
if (smartlist_len(changed))
|
|
|
|
control_event_descriptors_changed(changed);
|
2005-09-15 07:19:38 +02:00
|
|
|
|
2005-10-18 23:58:19 +02:00
|
|
|
routerlist_assert_ok(routerlist);
|
2005-09-15 07:19:38 +02:00
|
|
|
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
|
2007-01-10 21:43:40 +01:00
|
|
|
* where we plan to cache the network status with the given identity digest. */
|
|
|
|
char *
|
|
|
|
networkstatus_get_cache_filename(const char *identity_digest)
|
2005-09-12 08:56:42 +02:00
|
|
|
{
|
|
|
|
const char *datadir = get_options()->DataDirectory;
|
|
|
|
size_t len = strlen(datadir)+64;
|
|
|
|
char fp[HEX_DIGEST_LEN+1];
|
|
|
|
char *fn = tor_malloc(len+1);
|
2007-01-10 21:43:40 +01:00
|
|
|
base16_encode(fp, HEX_DIGEST_LEN+1, identity_digest, DIGEST_LEN);
|
2007-03-09 22:39:30 +01:00
|
|
|
tor_snprintf(fn, len, "%s"PATH_SEPARATOR"cached-status"PATH_SEPARATOR"%s",
|
|
|
|
datadir,fp);
|
2005-09-12 08:56:42 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2006-01-08 22:26:33 +01:00
|
|
|
/** Add the parsed neworkstatus in <b>ns</b> (with original document in
|
|
|
|
* <b>s</b> to the disk cache (and the in-memory directory server cache) as
|
|
|
|
* appropriate. */
|
|
|
|
static int
|
|
|
|
add_networkstatus_to_cache(const char *s,
|
|
|
|
networkstatus_source_t source,
|
|
|
|
networkstatus_t *ns)
|
|
|
|
{
|
|
|
|
if (source != NS_FROM_CACHE) {
|
2007-01-10 21:43:40 +01:00
|
|
|
char *fn = networkstatus_get_cache_filename(ns->identity_digest);
|
2006-01-08 22:26:33 +01:00
|
|
|
if (write_str_to_file(fn, s, 0)<0) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_notice(LD_FS, "Couldn't write cached network status to \"%s\"", fn);
|
2006-01-08 22:26:33 +01:00
|
|
|
}
|
|
|
|
tor_free(fn);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (get_options()->DirPort)
|
|
|
|
dirserv_set_cached_networkstatus_v2(s,
|
|
|
|
ns->identity_digest,
|
|
|
|
ns->published_on);
|
|
|
|
|
|
|
|
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) */
|
2006-03-08 07:29:52 +01:00
|
|
|
#define NETWORKSTATUS_ALLOW_SKEW (24*60*60)
|
2006-09-15 07:30:25 +02:00
|
|
|
|
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
|
2006-03-21 06:27:35 +01:00
|
|
|
* store it, and put it into our cache as necessary.
|
2005-09-13 17:32:03 +02:00
|
|
|
*
|
|
|
|
* If <b>source</b> is NS_FROM_DIR or NS_FROM_CACHE, do not replace our
|
2006-09-15 06:29:36 +02:00
|
|
|
* own networkstatus_t (if we're an authoritative directory server).
|
2005-09-13 17:32:03 +02:00
|
|
|
*
|
|
|
|
* 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;
|
2006-01-08 22:26:33 +01:00
|
|
|
trusted_dir_server_t *trusted_dir = NULL;
|
|
|
|
const char *source_desc = NULL;
|
2005-09-12 08:56:42 +02:00
|
|
|
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) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_DIR, "Couldn't parse network status.");
|
2005-09-07 18:42:53 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2006-01-08 22:26:33 +01:00
|
|
|
base16_encode(fp, HEX_DIGEST_LEN+1, ns->identity_digest, DIGEST_LEN);
|
2005-12-14 21:40:40 +01:00
|
|
|
if (!(trusted_dir =
|
2006-10-07 02:50:39 +02:00
|
|
|
router_get_trusteddirserver_by_digest(ns->identity_digest)) ||
|
|
|
|
!trusted_dir->is_v2_authority) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_DIR, "Network status was signed, but not by an authoritative "
|
|
|
|
"directory we recognize.");
|
2006-01-08 22:26:33 +01:00
|
|
|
if (!get_options()->DirPort) {
|
|
|
|
networkstatus_free(ns);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
source_desc = fp;
|
|
|
|
} else {
|
|
|
|
source_desc = trusted_dir->description;
|
2005-09-07 18:42:53 +02:00
|
|
|
}
|
|
|
|
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) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_GENERAL, "Network status from %s was published in the future "
|
|
|
|
"(%s GMT). Somebody is skewed here: check your clock. "
|
|
|
|
"Not caching.",
|
|
|
|
source_desc, published);
|
2007-01-06 06:42:31 +01:00
|
|
|
control_event_general_status(LOG_WARN,
|
|
|
|
"CLOCK_SKEW SOURCE=NETWORKSTATUS:%s:%d",
|
|
|
|
ns->source_address, ns->source_dirport);
|
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();
|
|
|
|
|
2006-09-15 07:20:16 +02:00
|
|
|
if ( (source == NS_FROM_DIR_BY_FP || source == NS_FROM_DIR_ALL) &&
|
|
|
|
router_digest_is_me(ns->identity_digest)) {
|
2005-12-14 21:40:40 +01: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;
|
|
|
|
}
|
|
|
|
|
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 {
|
2006-09-15 07:20:16 +02:00
|
|
|
if (source != NS_FROM_DIR_ALL) {
|
2007-03-29 09:02:12 +02:00
|
|
|
char *requested =
|
|
|
|
smartlist_join_strings(requested_fingerprints," ",0,NULL);
|
2006-09-15 07:20:16 +02:00
|
|
|
log_warn(LD_DIR,
|
2006-02-13 11:33:00 +01:00
|
|
|
"We received a network status with a fingerprint (%s) that we "
|
|
|
|
"never requested. (We asked for: %s.) Dropping.",
|
|
|
|
fp, requested);
|
2006-09-15 07:20:16 +02:00
|
|
|
tor_free(requested);
|
|
|
|
return 0;
|
|
|
|
}
|
2005-09-12 08:56:42 +02:00
|
|
|
}
|
2005-09-08 22:36:40 +02:00
|
|
|
}
|
|
|
|
|
2006-01-08 22:26:33 +01:00
|
|
|
if (!trusted_dir) {
|
|
|
|
if (!skewed && get_options()->DirPort) {
|
2006-04-03 01:02:52 +02:00
|
|
|
/* We got a non-trusted networkstatus, and we're a directory cache.
|
|
|
|
* This means that we asked an authority, and it told us about another
|
|
|
|
* authority we didn't recognize. */
|
2006-09-15 07:20:16 +02:00
|
|
|
log_info(LD_DIR,
|
|
|
|
"We do not recognize authority (%s) but we are willing "
|
|
|
|
"to cache it", fp);
|
2006-01-08 22:26:33 +01:00
|
|
|
add_networkstatus_to_cache(s, source, ns);
|
|
|
|
networkstatus_free(ns);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (source != NS_FROM_CACHE && trusted_dir)
|
2005-09-12 08:56:42 +02:00
|
|
|
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);
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_DIR,
|
|
|
|
"Not replacing network-status from %s (published %s); "
|
|
|
|
"we already have it.",
|
|
|
|
trusted_dir->description, published);
|
2005-09-15 01:42:06 +02:00
|
|
|
if (old_ns->received_on < arrived_at) {
|
|
|
|
if (source != NS_FROM_CACHE) {
|
2007-01-10 21:43:40 +01:00
|
|
|
char *fn;
|
|
|
|
fn = networkstatus_get_cache_filename(old_ns->identity_digest);
|
2005-09-15 01:42:06 +02:00
|
|
|
/* 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);
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_DIR,
|
|
|
|
"Not replacing network-status from %s (published %s);"
|
|
|
|
" we have a newer one (published %s) for this authority.",
|
|
|
|
trusted_dir->description, 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-12-27 06:26:03 +01:00
|
|
|
SMARTLIST_FOREACH(ns->entries, routerstatus_t *, rs,
|
|
|
|
{
|
2006-01-08 22:26:33 +01:00
|
|
|
if (!router_get_by_descriptor_digest(rs->descriptor_digest))
|
|
|
|
rs->need_to_mirror = 1;
|
2005-12-27 06:26:03 +01:00
|
|
|
});
|
|
|
|
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_DIR, "Setting networkstatus %s %s (published %s)",
|
|
|
|
source == NS_FROM_CACHE?"cached from":
|
2006-09-15 07:20:16 +02:00
|
|
|
((source == NS_FROM_DIR_BY_FP || source == NS_FROM_DIR_ALL) ?
|
|
|
|
"downloaded from":"generated for"),
|
2006-02-13 11:33:00 +01:00
|
|
|
trusted_dir->description, published);
|
2005-09-14 23:09:25 +02:00
|
|
|
networkstatus_list_has_changed = 1;
|
2006-08-15 05:54:09 +02:00
|
|
|
router_dir_info_changed();
|
2005-09-14 23:09:25 +02:00
|
|
|
|
2005-09-12 08:56:42 +02:00
|
|
|
smartlist_sort(networkstatus_list, _compare_networkstatus_published_on);
|
|
|
|
|
2006-01-08 22:26:33 +01:00
|
|
|
if (!skewed)
|
|
|
|
add_networkstatus_to_cache(s, source, ns);
|
2005-09-07 18:42:53 +02:00
|
|
|
|
2005-09-18 04:24:42 +02:00
|
|
|
networkstatus_list_update_recent(now);
|
|
|
|
|
2005-09-07 19:18:52 +02:00
|
|
|
return 0;
|
2005-09-07 18:42:53 +02:00
|
|
|
}
|
|
|
|
|
2005-12-14 21:40:40 +01: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);
|
2007-01-10 21:43:40 +01:00
|
|
|
char *fname = NULL;
|
2005-09-12 08:56:42 +02:00
|
|
|
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--);
|
2007-01-10 21:43:40 +01:00
|
|
|
fname = networkstatus_get_cache_filename(ns->identity_digest);
|
2005-09-12 08:56:42 +02:00
|
|
|
if (file_status(fname) == FN_FILE) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_DIR, "Removing too-old networkstatus in %s", fname);
|
2005-09-12 08:56:42 +02:00
|
|
|
unlink(fname);
|
|
|
|
}
|
|
|
|
tor_free(fname);
|
|
|
|
if (get_options()->DirPort) {
|
2005-10-18 22:13:09 +02:00
|
|
|
dirserv_set_cached_networkstatus_v2(NULL, ns->identity_digest, 0);
|
2005-09-12 08:56:42 +02:00
|
|
|
}
|
|
|
|
networkstatus_free(ns);
|
2006-08-15 05:54:09 +02:00
|
|
|
router_dir_info_changed();
|
2005-09-12 08:56:42 +02:00
|
|
|
}
|
2007-01-10 21:43:40 +01:00
|
|
|
|
|
|
|
/* And now go through the directory cache for any cached untrusted
|
2007-02-13 00:39:24 +01:00
|
|
|
* networkstatuses and other network info. */
|
2007-01-10 21:43:40 +01:00
|
|
|
dirserv_clear_old_networkstatuses(now - MAX_NETWORKSTATUS_AGE);
|
2007-02-13 00:39:24 +01:00
|
|
|
dirserv_clear_old_v1_info(now);
|
2005-09-12 08:56:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** 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);
|
|
|
|
}
|
|
|
|
|
2007-02-16 21:01:02 +01:00
|
|
|
/** Given a nickname (possibly verbose, possibly a hexadecimal digest), return
|
|
|
|
* the corresponding local_routerstatus_t, or NULL if none exists. Warn the
|
|
|
|
* user if <b>warn_if_unnamed</b> is set, and they have specified a router by
|
|
|
|
* nickname, but the Named flag isn't set for that router. */
|
2006-04-24 19:51:31 +02:00
|
|
|
static local_routerstatus_t *
|
|
|
|
router_get_combined_status_by_nickname(const char *nickname,
|
|
|
|
int warn_if_unnamed)
|
|
|
|
{
|
|
|
|
char digest[DIGEST_LEN];
|
|
|
|
local_routerstatus_t *best=NULL;
|
|
|
|
smartlist_t *matches=NULL;
|
|
|
|
|
|
|
|
if (!routerstatus_list || !nickname)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (nickname[0] == '$') {
|
|
|
|
if (base16_decode(digest, DIGEST_LEN, nickname+1, strlen(nickname))<0)
|
|
|
|
return NULL;
|
|
|
|
return router_get_combined_status_by_digest(digest);
|
|
|
|
} else if (strlen(nickname) == HEX_DIGEST_LEN &&
|
|
|
|
(base16_decode(digest, DIGEST_LEN, nickname+1, strlen(nickname))==0)) {
|
|
|
|
return router_get_combined_status_by_digest(digest);
|
|
|
|
}
|
|
|
|
|
|
|
|
matches = smartlist_create();
|
|
|
|
SMARTLIST_FOREACH(routerstatus_list, local_routerstatus_t *, lrs,
|
|
|
|
{
|
|
|
|
if (!strcasecmp(lrs->status.nickname, nickname)) {
|
|
|
|
if (lrs->status.is_named) {
|
|
|
|
smartlist_free(matches);
|
|
|
|
return lrs;
|
|
|
|
} else {
|
|
|
|
smartlist_add(matches, lrs);
|
|
|
|
best = lrs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
if (smartlist_len(matches)>1 && warn_if_unnamed) {
|
|
|
|
int any_unwarned=0;
|
|
|
|
SMARTLIST_FOREACH(matches, local_routerstatus_t *, lrs,
|
|
|
|
{
|
|
|
|
if (! lrs->name_lookup_warned) {
|
|
|
|
lrs->name_lookup_warned=1;
|
|
|
|
any_unwarned=1;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
if (any_unwarned) {
|
2007-02-24 06:36:45 +01:00
|
|
|
log_warn(LD_CONFIG,"There are multiple matches for the nickname \"%s\","
|
2006-04-25 08:02:46 +02:00
|
|
|
" but none is listed as named by the directory authorites. "
|
2007-02-24 06:36:45 +01:00
|
|
|
"Choosing one arbitrarily.", nickname);
|
2006-04-24 19:51:31 +02:00
|
|
|
}
|
2006-04-25 08:20:47 +02:00
|
|
|
} else if (warn_if_unnamed && best && !best->name_lookup_warned) {
|
2006-04-24 19:51:31 +02:00
|
|
|
char fp[HEX_DIGEST_LEN+1];
|
|
|
|
base16_encode(fp, sizeof(fp),
|
|
|
|
best->status.identity_digest, DIGEST_LEN);
|
2006-09-30 00:33:34 +02:00
|
|
|
log_warn(LD_CONFIG,
|
2007-03-06 20:33:43 +01:00
|
|
|
"When looking up a status, you specified a server \"%s\" by name, "
|
|
|
|
"but the directory authorities do not have any key registered for "
|
|
|
|
"this nickname -- so it could be used by any server, "
|
|
|
|
"not just the one you meant. "
|
2006-09-30 00:33:34 +02:00
|
|
|
"To make sure you get the same server in the future, refer to "
|
|
|
|
"it by key, as \"$%s\".", nickname, fp);
|
2006-04-24 19:51:31 +02:00
|
|
|
best->name_lookup_warned = 1;
|
|
|
|
}
|
|
|
|
smartlist_free(matches);
|
|
|
|
return best;
|
|
|
|
}
|
|
|
|
|
2007-01-27 19:33:33 +01:00
|
|
|
/** Find a routerstatus_t that corresponds to <b>hexdigest</b>, if
|
|
|
|
* any. Prefer ones that belong to authorities. */
|
|
|
|
routerstatus_t *
|
|
|
|
routerstatus_get_by_hexdigest(const char *hexdigest)
|
|
|
|
{
|
|
|
|
char digest[DIGEST_LEN];
|
|
|
|
local_routerstatus_t *rs;
|
|
|
|
trusted_dir_server_t *ds;
|
|
|
|
|
|
|
|
if (strlen(hexdigest) < HEX_DIGEST_LEN ||
|
|
|
|
base16_decode(digest,DIGEST_LEN,hexdigest,HEX_DIGEST_LEN) < 0)
|
|
|
|
return NULL;
|
|
|
|
if ((ds = router_get_trusteddirserver_by_digest(digest)))
|
|
|
|
return &(ds->fake_status.status);
|
|
|
|
if ((rs = router_get_combined_status_by_digest(digest)))
|
|
|
|
return &(rs->status);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2005-12-27 06:26:03 +01:00
|
|
|
/** Return true iff any networkstatus includes a descriptor whose digest
|
|
|
|
* is that of <b>desc</b>. */
|
2005-10-12 06:31:44 +02:00
|
|
|
static int
|
2005-12-27 06:26:03 +01:00
|
|
|
signed_desc_digest_is_recognized(signed_descriptor_t *desc)
|
2005-10-12 06:31:44 +02:00
|
|
|
{
|
|
|
|
routerstatus_t *rs;
|
|
|
|
if (!networkstatus_list)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
|
|
|
|
{
|
2005-12-27 06:26:03 +01:00
|
|
|
if (!(rs = networkstatus_find_entry(ns, desc->identity_digest)))
|
2005-10-12 06:31:44 +02:00
|
|
|
continue;
|
2005-12-27 06:26:03 +01:00
|
|
|
if (!memcmp(rs->descriptor_digest,
|
|
|
|
desc->signed_descriptor_digest, DIGEST_LEN))
|
2005-10-12 06:31:44 +02:00
|
|
|
return 1;
|
|
|
|
});
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-03-12 23:48:18 +01:00
|
|
|
/** How frequently do directory authorities re-download fresh networkstatus
|
|
|
|
* documents? */
|
|
|
|
#define AUTHORITY_NS_CACHE_INTERVAL (5*60)
|
|
|
|
|
|
|
|
/** How frequently do non-authority directory caches re-download fresh
|
|
|
|
* networkstatus documents? */
|
|
|
|
#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
|
2005-10-11 03:57:28 +02:00
|
|
|
* asking each trusted directory for its network-status. For caches, this
|
|
|
|
* means asking a random authority for all network-statuses.
|
2005-09-13 17:32:03 +02:00
|
|
|
*/
|
2005-10-05 07:03:52 +02:00
|
|
|
static void
|
2005-09-08 22:18:15 +02:00
|
|
|
update_networkstatus_cache_downloads(time_t now)
|
|
|
|
{
|
|
|
|
int authority = authdir_mode(get_options());
|
|
|
|
int interval =
|
|
|
|
authority ? AUTHORITY_NS_CACHE_INTERVAL : NONAUTHORITY_NS_CACHE_INTERVAL;
|
|
|
|
|
2005-10-05 07:03:52 +02:00
|
|
|
if (last_networkstatus_download_attempted + interval >= now)
|
2005-09-08 22:18:15 +02:00
|
|
|
return;
|
|
|
|
if (!trusted_dir_servers)
|
|
|
|
return;
|
|
|
|
|
2005-10-05 07:03:52 +02:00
|
|
|
last_networkstatus_download_attempted = now;
|
2005-09-08 22:18:15 +02:00
|
|
|
|
|
|
|
if (authority) {
|
|
|
|
/* An authority launches a separate connection for everybody. */
|
|
|
|
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
|
|
|
|
{
|
2006-03-15 00:40:37 +01:00
|
|
|
char resource[HEX_DIGEST_LEN+6]; /* fp/hexdigit.z\0 */
|
2006-09-29 01:57:59 +02:00
|
|
|
if (!ds->is_v2_authority)
|
|
|
|
continue;
|
2005-09-08 22:18:15 +02:00
|
|
|
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));
|
2006-01-06 19:19:17 +01:00
|
|
|
directory_initiate_command_routerstatus(
|
2006-12-24 03:45:35 +01:00
|
|
|
&ds->fake_status.status, DIR_PURPOSE_FETCH_NETWORKSTATUS,
|
2006-01-06 19:19:17 +01:00
|
|
|
0, /* Not private */
|
|
|
|
resource,
|
|
|
|
NULL, 0 /* No payload. */);
|
2005-09-08 22:18:15 +02:00
|
|
|
});
|
|
|
|
} 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
|
|
|
/** 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)
|
2007-02-02 21:06:43 +01:00
|
|
|
/** How many times do we allow a networkstatus download to fail before we
|
2005-09-14 23:09:25 +02:00
|
|
|
* 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-10-05 07:03:52 +02:00
|
|
|
static void
|
2005-09-08 22:18:15 +02:00
|
|
|
update_networkstatus_client_downloads(time_t now)
|
2005-09-08 08:22:44 +02:00
|
|
|
{
|
2006-04-03 01:02:52 +02:00
|
|
|
int n_live = 0, n_dirservers, n_running_dirservers, needed = 0;
|
|
|
|
int fetch_latest = 0;
|
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;
|
2006-04-03 01:02:52 +02:00
|
|
|
smartlist_t *missing;
|
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
|
2006-04-03 01:02:52 +02:00
|
|
|
* objects so that we have all of them under
|
2006-03-08 07:29:52 +01:00
|
|
|
* NETWORKSTATUS_MAX_AGE publication time. We want to download a new
|
2005-09-12 08:56:42 +02:00
|
|
|
* *one* if the most recent one's publication time is under
|
|
|
|
* NETWORKSTATUS_CLIENT_DL_INTERVAL.
|
2005-09-08 08:22:44 +02:00
|
|
|
*/
|
2006-09-29 01:57:59 +02:00
|
|
|
if (!get_n_v2_authorities())
|
2005-09-08 18:18:28 +02:00
|
|
|
return;
|
2006-09-29 01:57:59 +02:00
|
|
|
n_dirservers = n_running_dirservers = 0;
|
2006-04-03 01:02:52 +02:00
|
|
|
missing = smartlist_create();
|
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);
|
2006-09-29 01:57:59 +02:00
|
|
|
if (!ds->is_v2_authority)
|
2005-09-14 23:09:25 +02:00
|
|
|
continue;
|
2006-09-29 01:57:59 +02:00
|
|
|
++n_dirservers;
|
|
|
|
if (ds->n_networkstatus_failures > NETWORKSTATUS_N_ALLOWABLE_FAILURES)
|
|
|
|
continue;
|
|
|
|
++n_running_dirservers;
|
2006-04-03 01:02:52 +02:00
|
|
|
if (ns && ns->published_on > now-NETWORKSTATUS_MAX_AGE)
|
2005-09-08 08:22:44 +02:00
|
|
|
++n_live;
|
2006-04-03 01:02:52 +02:00
|
|
|
else
|
|
|
|
smartlist_add(missing, ds->digest);
|
|
|
|
if (ns && (!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;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2005-09-08 23:01:24 +02:00
|
|
|
/* Also, download at least 1 every NETWORKSTATUS_CLIENT_DL_INTERVAL. */
|
2006-04-03 01:02:52 +02:00
|
|
|
if (!smartlist_len(missing) &&
|
|
|
|
most_recent_received < now-NETWORKSTATUS_CLIENT_DL_INTERVAL) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_DIR, "Our most recent network-status document (from %s) "
|
|
|
|
"is %d seconds old; downloading another.",
|
|
|
|
most_recent?most_recent->description:"nobody",
|
|
|
|
(int)(now-most_recent_received));
|
2006-04-03 01:02:52 +02:00
|
|
|
fetch_latest = 1;
|
2005-09-08 08:22:44 +02:00
|
|
|
needed = 1;
|
2006-04-03 01:02:52 +02:00
|
|
|
} else if (smartlist_len(missing)) {
|
|
|
|
log_info(LD_DIR, "For %d/%d running directory servers, we have %d live"
|
|
|
|
" network-status documents. Downloading %d.",
|
|
|
|
n_running_dirservers, n_dirservers, n_live,
|
|
|
|
smartlist_len(missing));
|
|
|
|
needed = smartlist_len(missing);
|
|
|
|
} else {
|
|
|
|
smartlist_free(missing);
|
2005-09-08 23:01:24 +02:00
|
|
|
return;
|
2006-04-03 01:02:52 +02:00
|
|
|
}
|
2005-09-08 23:01:24 +02:00
|
|
|
|
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)
|
2005-10-07 00:18:01 +02:00
|
|
|
most_recent_idx = crypto_rand_int(n_dirservers);
|
2005-09-08 08:22:44 +02:00
|
|
|
|
2006-04-03 01:02:52 +02:00
|
|
|
if (fetch_latest) {
|
|
|
|
int i;
|
2006-04-08 00:55:46 +02:00
|
|
|
int n_failed = 0;
|
|
|
|
for (i = most_recent_idx + 1; 1; ++i) {
|
2006-04-03 01:02:52 +02:00
|
|
|
trusted_dir_server_t *ds;
|
|
|
|
if (i >= n_dirservers)
|
|
|
|
i = 0;
|
|
|
|
ds = smartlist_get(trusted_dir_servers, i);
|
2006-09-29 01:57:59 +02:00
|
|
|
if (! ds->is_v2_authority)
|
|
|
|
continue;
|
2006-04-08 00:55:46 +02:00
|
|
|
if (n_failed < n_dirservers &&
|
|
|
|
ds->n_networkstatus_failures > NETWORKSTATUS_N_ALLOWABLE_FAILURES) {
|
|
|
|
++n_failed;
|
2006-04-03 01:02:52 +02:00
|
|
|
continue;
|
2006-04-08 00:55:46 +02:00
|
|
|
}
|
2006-04-03 01:02:52 +02:00
|
|
|
smartlist_add(missing, ds->digest);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-09-08 23:01:24 +02:00
|
|
|
/* Build a request string for all the resources we want. */
|
2006-04-03 01:02:52 +02:00
|
|
|
resource_len = smartlist_len(missing) * (HEX_DIGEST_LEN+1) + 6;
|
2005-09-08 23:01:24 +02:00
|
|
|
resource = tor_malloc(resource_len);
|
|
|
|
memcpy(resource, "fp/", 3);
|
|
|
|
cp = resource+3;
|
2006-06-21 06:57:12 +02:00
|
|
|
smartlist_sort_digests(missing);
|
2006-04-03 01:02:52 +02:00
|
|
|
needed = smartlist_len(missing);
|
|
|
|
SMARTLIST_FOREACH(missing, const char *, d,
|
|
|
|
{
|
|
|
|
base16_encode(cp, HEX_DIGEST_LEN+1, d, DIGEST_LEN);
|
|
|
|
cp += HEX_DIGEST_LEN;
|
|
|
|
--needed;
|
|
|
|
if (needed)
|
|
|
|
*cp++ = '+';
|
|
|
|
});
|
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);
|
2006-04-03 01:02:52 +02:00
|
|
|
smartlist_free(missing);
|
2005-09-08 08:22:44 +02:00
|
|
|
}
|
|
|
|
|
2005-12-27 06:26:03 +01:00
|
|
|
/** Launch requests for networkstatus documents as appropriate. */
|
2005-10-05 07:03:52 +02:00
|
|
|
void
|
|
|
|
update_networkstatus_downloads(time_t now)
|
|
|
|
{
|
|
|
|
or_options_t *options = get_options();
|
2006-05-30 08:11:36 +02:00
|
|
|
if (options->DirPort)
|
2006-06-05 00:42:13 +02:00
|
|
|
update_networkstatus_cache_downloads(now);
|
2006-05-30 08:11:36 +02:00
|
|
|
else
|
2006-06-05 00:42:13 +02:00
|
|
|
update_networkstatus_client_downloads(now);
|
2005-10-05 07:03:52 +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 &&
|
2006-02-12 04:43:39 +01:00
|
|
|
!router_is_unreliable(router, need_uptime, 0, 0)) {
|
2006-03-27 04:25:34 +02:00
|
|
|
r = compare_addr_to_addr_policy(addr, port, router->exit_policy);
|
2005-03-19 07:57:16 +01:00
|
|
|
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
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
{
|
2006-03-27 04:25:34 +02:00
|
|
|
return 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-10-04 23:21:09 +02:00
|
|
|
add_trusted_dir_server(const char *nickname, const char *address,
|
2006-12-24 03:45:27 +01:00
|
|
|
uint16_t dir_port, uint16_t or_port,
|
|
|
|
const char *digest, int is_v1_authority,
|
2006-09-29 01:57:59 +02:00
|
|
|
int is_v2_authority, int is_hidserv_authority)
|
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;
|
2005-10-04 23:21:09 +02:00
|
|
|
size_t dlen;
|
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. */
|
2006-07-15 22:26:05 +02:00
|
|
|
if (resolve_my_address(LOG_WARN, get_options(), &a, &hostname) < 0) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_CONFIG,
|
|
|
|
"Couldn't find a suitable address when adding ourself as a "
|
|
|
|
"trusted directory server.");
|
2005-08-26 09:41:19 +02:00
|
|
|
return;
|
|
|
|
}
|
2005-08-26 21:25:36 +02:00
|
|
|
} else {
|
|
|
|
if (tor_lookup_hostname(address, &a)) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_CONFIG,
|
|
|
|
"Unable to lookup address for directory server at '%s'",
|
|
|
|
address);
|
2005-08-26 21:25:36 +02:00
|
|
|
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-10-04 23:21:09 +02:00
|
|
|
ent->nickname = nickname ? tor_strdup(nickname) : NULL;
|
2005-08-26 21:31:51 +02:00
|
|
|
ent->address = hostname;
|
2005-08-26 09:41:19 +02:00
|
|
|
ent->addr = a;
|
2006-12-24 03:45:27 +01:00
|
|
|
ent->dir_port = dir_port;
|
|
|
|
ent->or_port = or_port;
|
2004-10-12 17:55:20 +02:00
|
|
|
ent->is_running = 1;
|
2006-04-10 23:29:29 +02:00
|
|
|
ent->is_v1_authority = is_v1_authority;
|
2006-09-29 01:57:59 +02:00
|
|
|
ent->is_v2_authority = is_v2_authority;
|
|
|
|
ent->is_hidserv_authority = is_hidserv_authority;
|
2004-10-12 17:55:20 +02:00
|
|
|
memcpy(ent->digest, digest, DIGEST_LEN);
|
2005-10-04 23:21:09 +02:00
|
|
|
|
|
|
|
dlen = 64 + strlen(hostname) + (nickname?strlen(nickname):0);
|
|
|
|
ent->description = tor_malloc(dlen);
|
|
|
|
if (nickname)
|
|
|
|
tor_snprintf(ent->description, dlen, "directory server \"%s\" at %s:%d",
|
2006-12-24 03:45:27 +01:00
|
|
|
nickname, hostname, (int)dir_port);
|
2005-10-04 23:21:09 +02:00
|
|
|
else
|
|
|
|
tor_snprintf(ent->description, dlen, "directory server at %s:%d",
|
2006-12-24 03:45:27 +01:00
|
|
|
hostname, (int)dir_port);
|
2005-10-04 23:21:09 +02:00
|
|
|
|
2006-12-24 03:45:35 +01:00
|
|
|
ent->fake_status.status.addr = ent->addr;
|
|
|
|
memcpy(ent->fake_status.status.identity_digest, digest, DIGEST_LEN);
|
2005-12-18 23:45:27 +01:00
|
|
|
if (nickname)
|
2006-12-24 03:45:35 +01:00
|
|
|
strlcpy(ent->fake_status.status.nickname, nickname,
|
|
|
|
sizeof(ent->fake_status.status.nickname));
|
2005-12-18 23:45:27 +01:00
|
|
|
else
|
2006-12-24 03:45:35 +01:00
|
|
|
ent->fake_status.status.nickname[0] = '\0';
|
|
|
|
ent->fake_status.status.dir_port = ent->dir_port;
|
|
|
|
ent->fake_status.status.or_port = ent->or_port;
|
2005-12-14 23:00:58 +01:00
|
|
|
|
2004-10-13 20:28:39 +02:00
|
|
|
smartlist_add(trusted_dir_servers, ent);
|
2006-08-15 05:54:09 +02:00
|
|
|
router_dir_info_changed();
|
2004-10-12 17:55:20 +02:00
|
|
|
}
|
|
|
|
|
2005-10-05 07:03:52 +02:00
|
|
|
/** Free storage held in <b>ds</b> */
|
2007-02-28 01:36:03 +01:00
|
|
|
static void
|
2005-10-05 07:03:52 +02:00
|
|
|
trusted_dir_server_free(trusted_dir_server_t *ds)
|
|
|
|
{
|
|
|
|
tor_free(ds->nickname);
|
|
|
|
tor_free(ds->description);
|
|
|
|
tor_free(ds->address);
|
|
|
|
tor_free(ds);
|
|
|
|
}
|
|
|
|
|
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,
|
2005-10-05 07:03:52 +02:00
|
|
|
trusted_dir_server_free(ent));
|
2004-10-12 17:55:20 +02:00
|
|
|
smartlist_clear(trusted_dir_servers);
|
|
|
|
} else {
|
|
|
|
trusted_dir_servers = smartlist_create();
|
|
|
|
}
|
2006-08-15 05:54:09 +02:00
|
|
|
router_dir_info_changed();
|
2004-10-12 17:55:20 +02:00
|
|
|
}
|
2005-06-09 21:03:31 +02:00
|
|
|
|
2006-03-15 01:10:13 +01:00
|
|
|
/** Return 1 if any trusted dir server supports v1 directories,
|
|
|
|
* else return 0. */
|
|
|
|
int
|
2006-04-10 23:29:29 +02:00
|
|
|
any_trusted_dir_is_v1_authority(void)
|
2006-03-15 01:10:13 +01:00
|
|
|
{
|
|
|
|
if (trusted_dir_servers)
|
|
|
|
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ent,
|
|
|
|
if (ent->is_v1_authority) return 1);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2006-02-06 06:04:27 +01:00
|
|
|
/** We believe networkstatuses more recent than this when they tell us that
|
|
|
|
* our server is broken, invalid, obsolete, etc. */
|
2006-03-12 23:48:18 +01:00
|
|
|
#define SELF_OPINION_INTERVAL (90*60)
|
2006-02-06 06:04:27 +01:00
|
|
|
|
2007-02-08 08:24:06 +01:00
|
|
|
/** Result of checking whether a version is recommended. */
|
|
|
|
typedef struct combined_version_status_t {
|
|
|
|
/** How many networkstatuses claim to know about versions? */
|
|
|
|
int n_versioning;
|
|
|
|
/** What do the majority of networkstatuses believe about this version? */
|
|
|
|
version_status_t consensus;
|
|
|
|
/** How many networkstatuses constitute the majority? */
|
|
|
|
int n_concurring;
|
|
|
|
} combined_version_status_t;
|
|
|
|
|
2006-02-06 06:04:27 +01:00
|
|
|
/** Return a string naming the versions of Tor recommended by
|
2006-04-10 10:37:16 +02:00
|
|
|
* more than half the versioning networkstatuses. */
|
2006-02-06 06:04:27 +01:00
|
|
|
static char *
|
2007-02-08 08:24:06 +01:00
|
|
|
compute_recommended_versions(time_t now, int client,
|
|
|
|
const char *my_version,
|
|
|
|
combined_version_status_t *status_out)
|
2006-02-06 06:04:27 +01:00
|
|
|
{
|
|
|
|
int n_seen;
|
|
|
|
char *current;
|
|
|
|
smartlist_t *combined, *recommended;
|
2007-02-08 08:24:06 +01:00
|
|
|
int n_versioning, n_recommending;
|
2006-02-06 06:04:27 +01:00
|
|
|
char *result;
|
2007-02-08 08:24:06 +01:00
|
|
|
/** holds the compromise status taken among all non-recommending
|
|
|
|
* authorities */
|
|
|
|
version_status_t consensus = VS_RECOMMENDED;
|
|
|
|
(void) now; /* right now, we consider *all* statuses, regardless of age. */
|
|
|
|
|
|
|
|
tor_assert(my_version);
|
|
|
|
tor_assert(status_out);
|
|
|
|
|
|
|
|
memset(status_out, 0, sizeof(combined_version_status_t));
|
2006-02-06 06:04:27 +01:00
|
|
|
|
|
|
|
if (!networkstatus_list)
|
|
|
|
return tor_strdup("<none>");
|
|
|
|
|
|
|
|
combined = smartlist_create();
|
2007-02-08 08:24:06 +01:00
|
|
|
n_versioning = n_recommending = 0;
|
2006-02-06 06:04:27 +01:00
|
|
|
SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
|
|
|
|
{
|
|
|
|
const char *vers;
|
2006-04-03 08:23:24 +02:00
|
|
|
smartlist_t *versions;
|
2007-02-08 08:24:06 +01:00
|
|
|
version_status_t status;
|
2006-02-06 06:04:27 +01:00
|
|
|
if (! ns->recommends_versions)
|
|
|
|
continue;
|
2006-04-10 10:37:16 +02:00
|
|
|
n_versioning++;
|
2006-02-06 06:04:27 +01:00
|
|
|
vers = client ? ns->client_versions : ns->server_versions;
|
|
|
|
if (!vers)
|
|
|
|
continue;
|
2006-04-03 08:23:24 +02:00
|
|
|
versions = smartlist_create();
|
|
|
|
smartlist_split_string(versions, vers, ",",
|
2006-02-06 06:04:27 +01:00
|
|
|
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
|
2006-04-03 08:23:24 +02:00
|
|
|
sort_version_list(versions, 1);
|
2006-04-10 10:02:56 +02:00
|
|
|
smartlist_add_all(combined, versions);
|
|
|
|
smartlist_free(versions);
|
2007-02-08 08:24:06 +01:00
|
|
|
|
|
|
|
/* now, check _our_ version */
|
|
|
|
status = tor_version_is_obsolete(my_version, vers);
|
|
|
|
if (status == VS_RECOMMENDED)
|
|
|
|
n_recommending++;
|
|
|
|
consensus = version_status_join(status, consensus);
|
2006-02-06 06:04:27 +01:00
|
|
|
});
|
|
|
|
|
2006-04-03 08:23:24 +02:00
|
|
|
sort_version_list(combined, 0);
|
2006-02-06 06:04:27 +01:00
|
|
|
|
|
|
|
current = NULL;
|
|
|
|
n_seen = 0;
|
|
|
|
recommended = smartlist_create();
|
|
|
|
SMARTLIST_FOREACH(combined, char *, cp,
|
|
|
|
{
|
|
|
|
if (current && !strcmp(cp, current)) {
|
|
|
|
++n_seen;
|
|
|
|
} else {
|
2007-02-08 08:24:06 +01:00
|
|
|
if (n_seen > n_versioning/2 && current)
|
2006-02-06 06:04:27 +01:00
|
|
|
smartlist_add(recommended, current);
|
|
|
|
n_seen = 0;
|
|
|
|
current = cp;
|
|
|
|
}
|
|
|
|
});
|
2007-02-08 08:24:06 +01:00
|
|
|
if (n_seen > n_versioning/2 && current)
|
2006-02-06 06:04:27 +01:00
|
|
|
smartlist_add(recommended, current);
|
|
|
|
|
|
|
|
result = smartlist_join_strings(recommended, ", ", 0, NULL);
|
|
|
|
|
|
|
|
SMARTLIST_FOREACH(combined, char *, cp, tor_free(cp));
|
|
|
|
smartlist_free(combined);
|
|
|
|
smartlist_free(recommended);
|
|
|
|
|
2007-02-08 08:24:06 +01:00
|
|
|
status_out->n_versioning = n_versioning;
|
|
|
|
if (n_recommending > n_versioning/2) {
|
|
|
|
status_out->consensus = VS_RECOMMENDED;
|
|
|
|
status_out->n_concurring = n_recommending;
|
|
|
|
} else {
|
|
|
|
status_out->consensus = consensus;
|
|
|
|
status_out->n_concurring = n_versioning - n_recommending;
|
|
|
|
}
|
|
|
|
|
2006-02-06 06:04:27 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2007-02-08 20:44:55 +01:00
|
|
|
/** How many times do we have to fail at getting a networkstatus we can't find
|
|
|
|
* before we're willing to believe it's okay to set up router statuses? */
|
|
|
|
#define N_NS_ATTEMPTS_TO_SET_ROUTERS 4
|
|
|
|
/** How many times do we have to fail at getting a networkstatus we can't find
|
|
|
|
* before we're willing to believe it's okay to check our version? */
|
|
|
|
#define N_NS_ATTEMPTS_TO_CHECK_VERSION 4
|
|
|
|
|
2005-09-14 23:09:25 +02:00
|
|
|
/** If the network-status list has changed since the last time we called this
|
2005-12-27 06:26:03 +01:00
|
|
|
* function, update the status of every routerinfo from the network-status
|
|
|
|
* list.
|
2005-09-14 23:09:25 +02:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
routers_update_all_from_networkstatus(void)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
2006-08-15 05:54:09 +02:00
|
|
|
router_dir_info_changed();
|
|
|
|
|
2005-09-18 04:24:42 +02:00
|
|
|
now = time(NULL);
|
|
|
|
if (networkstatus_list_has_changed)
|
|
|
|
routerstatus_list_update_from_networkstatus(now);
|
|
|
|
|
2005-12-27 06:26:03 +01:00
|
|
|
routers_update_status_from_networkstatus(routerlist->routers, 0);
|
2005-09-14 23:09:25 +02:00
|
|
|
|
|
|
|
me = router_get_my_routerinfo();
|
2006-04-07 06:52:32 +02:00
|
|
|
if (me && !have_warned_about_invalid_status &&
|
2007-02-08 20:44:55 +01:00
|
|
|
have_tried_downloading_all_statuses(N_NS_ATTEMPTS_TO_SET_ROUTERS)) {
|
2006-03-15 06:37:27 +01:00
|
|
|
int n_recent = 0, n_listing = 0, n_valid = 0, n_named = 0, n_naming = 0;
|
2005-09-21 02:41:06 +02:00
|
|
|
routerstatus_t *rs;
|
|
|
|
SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
|
|
|
|
{
|
|
|
|
if (ns->received_on + SELF_OPINION_INTERVAL < now)
|
|
|
|
continue;
|
|
|
|
++n_recent;
|
2006-03-15 06:37:27 +01:00
|
|
|
if (ns->binds_names)
|
|
|
|
++n_naming;
|
2005-11-05 21:15:27 +01:00
|
|
|
if (!(rs = networkstatus_find_entry(ns, me->cache_info.identity_digest)))
|
2005-09-21 02:41:06 +02:00
|
|
|
continue;
|
|
|
|
++n_listing;
|
|
|
|
if (rs->is_valid)
|
|
|
|
++n_valid;
|
|
|
|
if (rs->is_named)
|
|
|
|
++n_named;
|
|
|
|
});
|
|
|
|
|
2006-05-09 11:47:47 +02:00
|
|
|
if (n_listing) {
|
|
|
|
if (n_valid <= n_listing/2) {
|
|
|
|
log_info(LD_GENERAL,
|
2006-03-15 06:37:27 +01:00
|
|
|
"%d/%d recent statements from directory authorities list us "
|
2006-03-22 07:22:12 +01:00
|
|
|
"as unapproved. Are you misconfigured?",
|
2006-05-09 11:47:47 +02:00
|
|
|
n_listing-n_valid, n_listing);
|
2006-03-19 02:21:59 +01:00
|
|
|
have_warned_about_invalid_status = 1;
|
2006-03-22 07:22:12 +01:00
|
|
|
} else if (n_naming && !n_named) {
|
2006-04-14 22:19:33 +02:00
|
|
|
log_info(LD_GENERAL, "0/%d name-binding directory authorities "
|
2006-03-22 07:22:12 +01:00
|
|
|
"recognize your nickname. Please consider sending your "
|
|
|
|
"nickname and identity fingerprint to the tor-ops.",
|
2006-03-15 06:37:27 +01:00
|
|
|
n_naming);
|
2006-03-19 02:21:59 +01:00
|
|
|
have_warned_about_invalid_status = 1;
|
2005-09-21 02:41:06 +02:00
|
|
|
}
|
2005-09-14 23:09:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-09-29 01:57:44 +02:00
|
|
|
entry_guards_compute_status();
|
2005-09-14 23:09:25 +02:00
|
|
|
|
2006-04-07 06:52:32 +02:00
|
|
|
if (!have_warned_about_old_version &&
|
2007-02-08 20:44:55 +01:00
|
|
|
have_tried_downloading_all_statuses(N_NS_ATTEMPTS_TO_CHECK_VERSION)) {
|
2007-02-08 08:24:06 +01:00
|
|
|
combined_version_status_t st;
|
2005-09-21 02:41:06 +02:00
|
|
|
int is_server = server_mode(get_options());
|
2007-02-08 08:24:06 +01:00
|
|
|
char *recommended;
|
|
|
|
|
|
|
|
recommended = compute_recommended_versions(now, !is_server, VERSION, &st);
|
|
|
|
|
|
|
|
if (st.n_versioning) {
|
|
|
|
if (st.consensus == VS_RECOMMENDED) {
|
|
|
|
log_info(LD_GENERAL, "%d/%d statements from version-listing "
|
|
|
|
"directory authorities say my version is ok.",
|
|
|
|
st.n_concurring, st.n_versioning);
|
|
|
|
} else if (st.consensus == VS_NEW || st.consensus == VS_NEW_IN_SERIES) {
|
2005-09-21 02:41:06 +02:00
|
|
|
if (!have_warned_about_new_version) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_notice(LD_GENERAL, "This version of Tor (%s) is newer than any "
|
2007-02-08 08:24:06 +01:00
|
|
|
"recommended version%s, according to %d/%d version-listing "
|
|
|
|
"network statuses. Versions recommended by more than %d "
|
2006-02-21 04:55:47 +01:00
|
|
|
"authorit%s are: %s",
|
2005-12-14 21:40:40 +01:00
|
|
|
VERSION,
|
2007-02-08 08:24:06 +01:00
|
|
|
st.consensus == VS_NEW_IN_SERIES ? " in its series" : "",
|
|
|
|
st.n_concurring, st.n_versioning, st.n_versioning/2,
|
|
|
|
st.n_versioning/2 > 1 ? "ies" : "y", recommended);
|
2005-09-21 02:41:06 +02:00
|
|
|
have_warned_about_new_version = 1;
|
2006-10-23 12:16:43 +02:00
|
|
|
control_event_general_status(LOG_WARN, "DANGEROUS_VERSION "
|
|
|
|
"CURRENT=%s REASON=%s RECOMMENDED=\"%s\"",
|
2007-02-08 08:24:06 +01:00
|
|
|
VERSION, "NEW", recommended);
|
2005-09-21 02:41:06 +02:00
|
|
|
}
|
|
|
|
} else {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_GENERAL, "Please upgrade! "
|
2007-02-08 08:24:06 +01:00
|
|
|
"This version of Tor (%s) is %s, according to %d/%d version-"
|
|
|
|
"listing network statuses. Versions recommended by "
|
2006-04-10 10:37:16 +02:00
|
|
|
"at least %d authorit%s are: %s",
|
2007-02-08 08:24:06 +01:00
|
|
|
VERSION,
|
|
|
|
st.consensus == VS_OLD ? "obsolete" : "not recommended",
|
|
|
|
st.n_concurring, st.n_versioning, st.n_versioning/2,
|
|
|
|
st.n_versioning/2 > 1 ? "ies" : "y", recommended);
|
2005-09-21 02:41:06 +02:00
|
|
|
have_warned_about_old_version = 1;
|
2006-10-23 12:16:43 +02:00
|
|
|
control_event_general_status(LOG_WARN, "DANGEROUS_VERSION "
|
|
|
|
"CURRENT=%s REASON=%s RECOMMENDED=\"%s\"",
|
2007-02-08 08:24:06 +01:00
|
|
|
VERSION, st.consensus == VS_OLD ? "OLD" : "UNRECOMMENDED",
|
|
|
|
recommended);
|
2005-09-21 02:41:06 +02:00
|
|
|
}
|
|
|
|
}
|
2007-02-08 08:24:06 +01:00
|
|
|
tor_free(recommended);
|
2005-09-21 02:41:06 +02:00
|
|
|
}
|
|
|
|
|
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. */
|
2006-03-12 23:48:18 +01: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
|
2006-02-05 06:28:52 +01:00
|
|
|
* at least the MIN_TO_INFLUENCE_RUNNING most recent members are recent, and no
|
|
|
|
* others are recent. Set networkstatus_list_has_changed if anything happened.
|
2005-09-30 22:04:55 +02:00
|
|
|
*/
|
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);
|
2005-10-04 23:21:09 +02:00
|
|
|
trusted_dir_server_t *ds =
|
|
|
|
router_get_trusteddirserver_by_digest(ns->identity_digest);
|
|
|
|
const char *src = ds?ds->description:ns->source_address;
|
2005-09-18 04:24:42 +02:00
|
|
|
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);
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_DIR,
|
|
|
|
"Networkstatus from %s (published %s) is now \"recent\"",
|
|
|
|
src, published);
|
2005-09-18 04:24:42 +02:00
|
|
|
changed = 1;
|
|
|
|
}
|
|
|
|
ns->is_recent = 1;
|
|
|
|
++n_recent;
|
|
|
|
} else {
|
|
|
|
if (ns->is_recent) {
|
|
|
|
format_iso_time(published, ns->published_on);
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_DIR,
|
|
|
|
"Networkstatus from %s (published %s) is "
|
|
|
|
"no longer \"recent\"",
|
|
|
|
src, published);
|
2005-09-18 04:24:42 +02:00
|
|
|
changed = 1;
|
|
|
|
ns->is_recent = 0;
|
|
|
|
}
|
|
|
|
}
|
2005-09-12 08:56:42 +02:00
|
|
|
}
|
2006-08-15 05:54:09 +02:00
|
|
|
if (changed) {
|
2005-09-18 04:24:42 +02:00
|
|
|
networkstatus_list_has_changed = 1;
|
2006-08-15 05:54:09 +02:00
|
|
|
router_dir_info_changed();
|
|
|
|
}
|
2005-09-18 04:24:42 +02:00
|
|
|
}
|
|
|
|
|
2005-12-27 06:26:03 +01:00
|
|
|
/** Helper for routerstatus_list_update_from_networkstatus: remember how many
|
|
|
|
* authorities recommend a given descriptor digest. */
|
|
|
|
typedef struct {
|
|
|
|
routerstatus_t *rs;
|
|
|
|
int count;
|
|
|
|
} desc_digest_count_t;
|
|
|
|
|
2005-12-14 21:40:40 +01: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).
|
2005-09-30 22:04:55 +02:00
|
|
|
* 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)
|
|
|
|
{
|
2005-10-05 03:53:44 +02:00
|
|
|
or_options_t *options = get_options();
|
2005-12-27 06:26:03 +01:00
|
|
|
int n_trusted, n_statuses, n_recent = 0, n_naming = 0;
|
2007-01-03 20:58:00 +01:00
|
|
|
int n_listing_bad_exits = 0, n_listing_bad_directories = 0;
|
2005-12-27 06:26:03 +01:00
|
|
|
int i, j, warned;
|
2005-09-22 03:51:14 +02:00
|
|
|
int *index, *size;
|
|
|
|
networkstatus_t **networkstatus;
|
2006-10-20 23:04:39 +02:00
|
|
|
smartlist_t *result, *changed_list;
|
2005-09-22 08:34:29 +02:00
|
|
|
strmap_t *name_map;
|
2005-12-27 06:26:03 +01:00
|
|
|
char conflict[DIGEST_LEN]; /* Sentinel value */
|
|
|
|
desc_digest_count_t *digest_counts = NULL;
|
2005-09-18 04:24:42 +02:00
|
|
|
|
2006-02-05 06:28:52 +01:00
|
|
|
/* compute which network statuses will have a vote now */
|
2005-09-18 04:24:42 +02:00
|
|
|
networkstatus_list_update_recent(now);
|
2006-08-15 05:54:09 +02:00
|
|
|
router_dir_info_changed();
|
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();
|
2005-10-05 03:53:44 +02:00
|
|
|
if (!warned_conflicts)
|
|
|
|
warned_conflicts = smartlist_create();
|
2005-09-12 08:56:42 +02:00
|
|
|
|
|
|
|
n_statuses = smartlist_len(networkstatus_list);
|
2006-09-29 01:57:59 +02:00
|
|
|
n_trusted = get_n_v2_authorities();
|
2005-09-12 08:56:42 +02:00
|
|
|
|
2006-04-03 08:37:35 +02:00
|
|
|
if (n_statuses <= n_trusted/2) {
|
2005-09-12 08:56:42 +02:00
|
|
|
/* Not enough statuses to adjust status. */
|
2006-04-09 22:19:56 +02:00
|
|
|
log_info(LD_DIR,
|
|
|
|
"Not enough statuses to update router status list. (%d/%d)",
|
|
|
|
n_statuses, n_trusted);
|
2005-09-12 08:56:42 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_DIR, "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;
|
2006-10-19 17:45:48 +02:00
|
|
|
if (networkstatus[i]->lists_bad_exits)
|
|
|
|
++n_listing_bad_exits;
|
2007-01-03 20:58:00 +01:00
|
|
|
if (networkstatus[i]->lists_bad_directories)
|
|
|
|
++n_listing_bad_directories;
|
2005-09-22 03:51:14 +02:00
|
|
|
}
|
2005-09-12 08:56:42 +02:00
|
|
|
|
2005-12-27 06:26:03 +01:00
|
|
|
/** Iterate over all entries in all networkstatuses, and build
|
|
|
|
* name_map as a map from lc nickname to identity digest. If there
|
|
|
|
* is a conflict on that nickname, map the lc nickname to conflict.
|
|
|
|
*/
|
2005-09-22 08:34:29 +02:00
|
|
|
name_map = strmap_new();
|
2006-09-20 01:48:14 +02:00
|
|
|
/* Clear the global map... */
|
|
|
|
if (named_server_map)
|
|
|
|
strmap_free(named_server_map, _tor_free);
|
|
|
|
named_server_map = strmap_new();
|
2005-09-22 08:34:29 +02:00
|
|
|
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);
|
2005-10-05 03:53:44 +02:00
|
|
|
warned = smartlist_string_isin(warned_conflicts, rs->nickname);
|
|
|
|
if (!other_digest) {
|
2005-09-22 08:34:29 +02:00
|
|
|
strmap_set_lc(name_map, rs->nickname, rs->identity_digest);
|
2006-09-20 01:48:14 +02:00
|
|
|
strmap_set_lc(named_server_map, rs->nickname,
|
|
|
|
tor_memdup(rs->identity_digest, DIGEST_LEN));
|
2005-10-05 03:53:44 +02:00
|
|
|
if (warned)
|
|
|
|
smartlist_string_remove(warned_conflicts, rs->nickname);
|
|
|
|
} else if (memcmp(other_digest, rs->identity_digest, DIGEST_LEN) &&
|
|
|
|
other_digest != conflict) {
|
|
|
|
if (!warned) {
|
2006-09-20 01:48:14 +02:00
|
|
|
char *d;
|
2005-10-05 03:53:44 +02:00
|
|
|
int should_warn = options->DirPort && options->AuthoritativeDir;
|
|
|
|
char fp1[HEX_DIGEST_LEN+1];
|
|
|
|
char fp2[HEX_DIGEST_LEN+1];
|
|
|
|
base16_encode(fp1, sizeof(fp1), other_digest, DIGEST_LEN);
|
|
|
|
base16_encode(fp2, sizeof(fp2), rs->identity_digest, DIGEST_LEN);
|
2005-10-24 21:39:45 +02:00
|
|
|
log_fn(should_warn ? LOG_WARN : LOG_INFO, LD_DIR,
|
2005-12-14 21:40:40 +01:00
|
|
|
"Naming authorities disagree about which key goes with %s. "
|
|
|
|
"($%s vs $%s)",
|
2005-10-05 03:53:44 +02:00
|
|
|
rs->nickname, fp1, fp2);
|
|
|
|
strmap_set_lc(name_map, rs->nickname, conflict);
|
2006-09-20 01:48:14 +02:00
|
|
|
d = strmap_remove_lc(named_server_map, rs->nickname);
|
|
|
|
tor_free(d);
|
2005-10-05 03:53:44 +02:00
|
|
|
smartlist_add(warned_conflicts, tor_strdup(rs->nickname));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (warned)
|
|
|
|
smartlist_string_remove(warned_conflicts, rs->nickname);
|
2005-09-22 08:34:29 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2005-09-22 03:51:14 +02:00
|
|
|
result = smartlist_create();
|
2006-10-20 23:04:39 +02:00
|
|
|
changed_list = smartlist_create();
|
2005-12-27 06:26:03 +01:00
|
|
|
digest_counts = tor_malloc_zero(sizeof(desc_digest_count_t)*n_statuses);
|
2005-09-22 03:51:14 +02:00
|
|
|
|
2005-12-27 06:26:03 +01:00
|
|
|
/* Iterate through all of the sorted routerstatus lists in lockstep.
|
2005-09-22 03:51:14 +02:00
|
|
|
* 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 <=
|
2007-01-27 10:13:19 +01:00
|
|
|
* j < index[i1]: networkstatus[i1]->entries[j]->identity_digest <
|
2005-09-22 03:51:14 +02:00
|
|
|
* 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;
|
2006-10-12 00:06:01 +02:00
|
|
|
int n_v2_dir=0, n_fast=0, n_stable=0, n_exit=0, n_guard=0, n_bad_exit=0;
|
2007-01-03 20:58:00 +01:00
|
|
|
int n_bad_directory=0;
|
2006-12-24 05:09:48 +01:00
|
|
|
int n_version_known=0, n_supports_begindir=0;
|
2005-12-27 06:26:03 +01:00
|
|
|
int n_desc_digests=0, highest_count=0;
|
2005-09-18 04:24:42 +02:00
|
|
|
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;
|
2005-12-27 06:26:03 +01:00
|
|
|
|
2005-09-22 03:51:14 +02:00
|
|
|
/* 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. */
|
|
|
|
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;
|
2005-12-27 06:26:03 +01:00
|
|
|
/* At this point, we know that we're looking at a routersatus with
|
|
|
|
* identity "lowest".
|
|
|
|
*/
|
2005-09-22 03:51:14 +02:00
|
|
|
++index[i];
|
2005-09-12 08:56:42 +02:00
|
|
|
++n_listing;
|
2005-12-27 06:26:03 +01:00
|
|
|
/* Should we name this router? Only if all the names from naming
|
|
|
|
* authorities match. */
|
2005-09-18 04:24:42 +02:00
|
|
|
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);
|
2005-10-05 03:53:44 +02:00
|
|
|
if (! smartlist_string_isin(warned_conflicts, hd)) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_DIR,
|
|
|
|
"Naming authorities disagree about nicknames for $%s "
|
|
|
|
"(\"%s\" vs \"%s\")",
|
|
|
|
hd, the_name, rs->nickname);
|
2005-10-05 03:53:44 +02:00
|
|
|
smartlist_add(warned_conflicts, tor_strdup(hd));
|
|
|
|
}
|
2005-09-18 04:24:42 +02:00
|
|
|
the_name = "**mismatch**";
|
|
|
|
}
|
|
|
|
}
|
2005-12-27 06:26:03 +01:00
|
|
|
/* Keep a running count of how often which descriptor digests
|
|
|
|
* appear. */
|
|
|
|
for (j = 0; j < n_desc_digests; ++j) {
|
|
|
|
if (!memcmp(rs->descriptor_digest,
|
|
|
|
digest_counts[j].rs->descriptor_digest, DIGEST_LEN)) {
|
|
|
|
if (++digest_counts[j].count > highest_count)
|
|
|
|
highest_count = digest_counts[j].count;
|
|
|
|
goto found;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
digest_counts[n_desc_digests].rs = rs;
|
|
|
|
digest_counts[n_desc_digests].count = 1;
|
|
|
|
if (!highest_count)
|
|
|
|
highest_count = 1;
|
|
|
|
++n_desc_digests;
|
|
|
|
found:
|
|
|
|
/* Now tally up the easily-tallied flags. */
|
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-12-14 23:00:58 +01:00
|
|
|
if (rs->is_exit)
|
|
|
|
++n_exit;
|
|
|
|
if (rs->is_fast)
|
|
|
|
++n_fast;
|
2006-01-24 01:31:16 +01:00
|
|
|
if (rs->is_possible_guard)
|
|
|
|
++n_guard;
|
2005-12-14 23:00:58 +01:00
|
|
|
if (rs->is_stable)
|
|
|
|
++n_stable;
|
|
|
|
if (rs->is_v2_dir)
|
|
|
|
++n_v2_dir;
|
2006-10-12 00:06:01 +02:00
|
|
|
if (rs->is_bad_exit)
|
|
|
|
++n_bad_exit;
|
2007-01-03 20:58:00 +01:00
|
|
|
if (rs->is_bad_directory)
|
|
|
|
++n_bad_directory;
|
2006-12-24 05:09:48 +01:00
|
|
|
if (rs->version_known)
|
|
|
|
++n_version_known;
|
|
|
|
if (rs->version_supports_begindir)
|
|
|
|
++n_supports_begindir;
|
2005-09-22 03:51:14 +02:00
|
|
|
}
|
2005-12-27 06:26:03 +01:00
|
|
|
/* Go over the descriptor digests and figure out which descriptor we
|
|
|
|
* want. */
|
|
|
|
most_recent = NULL;
|
|
|
|
for (i = 0; i < n_desc_digests; ++i) {
|
|
|
|
/* If any digest appears twice or more, ignore those that don't.*/
|
|
|
|
if (highest_count >= 2 && digest_counts[i].count < 2)
|
|
|
|
continue;
|
|
|
|
if (!most_recent ||
|
|
|
|
digest_counts[i].rs->published_on > most_recent->published_on)
|
|
|
|
most_recent = digest_counts[i].rs;
|
|
|
|
}
|
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));
|
2005-12-27 06:26:03 +01:00
|
|
|
/* Copy status info about this router, if we had any before. */
|
2005-09-22 03:51:14 +02:00
|
|
|
if ((rs_old = router_get_combined_status_by_digest(lowest))) {
|
2005-12-27 06:26:03 +01:00
|
|
|
if (!memcmp(rs_out->status.descriptor_digest,
|
|
|
|
most_recent->descriptor_digest, DIGEST_LEN)) {
|
|
|
|
rs_out->n_download_failures = rs_old->n_download_failures;
|
|
|
|
rs_out->next_attempt_at = rs_old->next_attempt_at;
|
|
|
|
}
|
2005-10-05 00:23:31 +02:00
|
|
|
rs_out->name_lookup_warned = rs_old->name_lookup_warned;
|
2006-12-24 03:45:35 +01:00
|
|
|
rs_out->last_dir_503_at = rs_old->last_dir_503_at;
|
2005-09-18 04:24:42 +02:00
|
|
|
}
|
|
|
|
smartlist_add(result, rs_out);
|
2006-02-13 11:33:00 +01:00
|
|
|
log_debug(LD_DIR, "Router '%s' is listed by %d/%d directories, "
|
|
|
|
"named by %d/%d, validated by %d/%d, and %d/%d recent "
|
|
|
|
"directories think it's running.",
|
|
|
|
rs_out->status.nickname,
|
|
|
|
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-10-05 04:06:36 +02:00
|
|
|
if (smartlist_string_isin(warned_conflicts, rs_out->status.nickname))
|
|
|
|
smartlist_string_remove(warned_conflicts, rs_out->status.nickname);
|
2005-09-22 08:34:29 +02:00
|
|
|
}
|
2005-09-22 03:51:14 +02:00
|
|
|
if (rs_out->status.is_named)
|
2005-12-14 21:40:40 +01:00
|
|
|
strlcpy(rs_out->status.nickname, the_name,
|
|
|
|
sizeof(rs_out->status.nickname));
|
2005-09-22 03:51:14 +02:00
|
|
|
rs_out->status.is_valid = n_valid > n_statuses/2;
|
|
|
|
rs_out->status.is_running = n_running > n_recent/2;
|
2005-12-14 23:00:58 +01:00
|
|
|
rs_out->status.is_exit = n_exit > n_statuses/2;
|
|
|
|
rs_out->status.is_fast = n_fast > n_statuses/2;
|
2006-02-05 06:11:24 +01:00
|
|
|
rs_out->status.is_possible_guard = n_guard > n_statuses/2;
|
2005-12-14 23:00:58 +01:00
|
|
|
rs_out->status.is_stable = n_stable > n_statuses/2;
|
|
|
|
rs_out->status.is_v2_dir = n_v2_dir > n_statuses/2;
|
2006-10-19 17:45:48 +02:00
|
|
|
rs_out->status.is_bad_exit = n_bad_exit > n_listing_bad_exits/2;
|
2007-01-03 20:58:00 +01:00
|
|
|
rs_out->status.is_bad_directory =
|
|
|
|
n_bad_directory > n_listing_bad_directories/2;
|
2006-12-24 05:09:48 +01:00
|
|
|
rs_out->status.version_known = n_version_known > 0;
|
|
|
|
rs_out->status.version_supports_begindir =
|
|
|
|
n_supports_begindir > n_version_known/2;
|
2006-10-20 23:04:39 +02:00
|
|
|
if (!rs_old || memcmp(rs_old, rs_out, sizeof(local_routerstatus_t)))
|
|
|
|
smartlist_add(changed_list, rs_out);
|
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));
|
2006-09-20 01:48:14 +02:00
|
|
|
|
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-12-27 06:26:03 +01:00
|
|
|
tor_free(digest_counts);
|
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;
|
2006-10-20 23:04:39 +02:00
|
|
|
|
|
|
|
control_event_networkstatus_changed(changed_list);
|
|
|
|
smartlist_free(changed_list);
|
2005-09-18 04:24:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Given a list <b>routers</b> of routerinfo_t *, update each routers's
|
2006-03-19 02:21:59 +01:00
|
|
|
* is_named, is_valid, and is_running fields according to our current
|
2005-09-18 04:24:42 +02:00
|
|
|
* networkstatus_t documents. */
|
|
|
|
void
|
2005-12-14 21:40:40 +01:00
|
|
|
routers_update_status_from_networkstatus(smartlist_t *routers,
|
2005-12-27 06:26:03 +01:00
|
|
|
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;
|
2005-10-05 00:23:31 +02:00
|
|
|
int namingdir = options->AuthoritativeDir &&
|
|
|
|
options->NamingAuthoritativeDir;
|
2005-09-18 04:24:42 +02:00
|
|
|
|
|
|
|
if (!routerstatus_list)
|
|
|
|
return;
|
|
|
|
|
|
|
|
SMARTLIST_FOREACH(routers, routerinfo_t *, router,
|
|
|
|
{
|
2005-12-14 21:40:40 +01:00
|
|
|
const char *digest = router->cache_info.identity_digest;
|
|
|
|
rs = router_get_combined_status_by_digest(digest);
|
|
|
|
ds = router_get_trusteddirserver_by_digest(digest);
|
2005-09-18 04:24:42 +02:00
|
|
|
|
|
|
|
if (!rs)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
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) {
|
2006-03-18 01:22:23 +01:00
|
|
|
/* If we're not an authdir, believe others. */
|
2006-03-19 02:21:59 +01:00
|
|
|
router->is_valid = rs->status.is_valid;
|
2005-09-22 03:51:14 +02:00
|
|
|
router->is_running = rs->status.is_running;
|
2005-12-15 22:30:57 +01:00
|
|
|
router->is_fast = rs->status.is_fast;
|
2005-12-15 22:38:59 +01:00
|
|
|
router->is_stable = rs->status.is_stable;
|
2006-02-12 04:43:39 +01:00
|
|
|
router->is_possible_guard = rs->status.is_possible_guard;
|
2006-10-07 08:28:50 +02:00
|
|
|
router->is_exit = rs->status.is_exit;
|
2006-10-12 00:06:01 +02:00
|
|
|
router->is_bad_exit = rs->status.is_bad_exit;
|
2005-10-05 03:53:44 +02:00
|
|
|
}
|
|
|
|
if (router->is_running && ds) {
|
|
|
|
ds->n_networkstatus_failures = 0;
|
2005-09-15 16:39:05 +02:00
|
|
|
}
|
2005-12-27 06:26:03 +01:00
|
|
|
if (reset_failures) {
|
2005-10-12 15:49:13 +02:00
|
|
|
rs->n_download_failures = 0;
|
|
|
|
rs->next_attempt_at = 0;
|
2005-10-12 06:31:44 +02:00
|
|
|
}
|
2005-09-12 08:56:42 +02:00
|
|
|
});
|
2006-08-15 05:54:09 +02:00
|
|
|
router_dir_info_changed();
|
2005-09-12 08:56:42 +02:00
|
|
|
}
|
|
|
|
|
2005-12-27 06:26:03 +01:00
|
|
|
/** For every router descriptor we are currently downloading by descriptor
|
|
|
|
* digest, set result[d] to 1. */
|
|
|
|
static void
|
|
|
|
list_pending_descriptor_downloads(digestmap_t *result)
|
2005-09-12 08:56:42 +02:00
|
|
|
{
|
2005-12-27 06:26:03 +01:00
|
|
|
const char *prefix = "d/";
|
|
|
|
size_t p_len = strlen(prefix);
|
|
|
|
int i, n_conns;
|
2005-09-22 08:34:29 +02:00
|
|
|
connection_t **carray;
|
2005-12-27 06:26:03 +01:00
|
|
|
smartlist_t *tmp = smartlist_create();
|
2005-09-12 08:56:42 +02:00
|
|
|
|
2005-12-27 06:26:03 +01:00
|
|
|
tor_assert(result);
|
2005-09-22 08:34:29 +02:00
|
|
|
get_connection_array(&carray, &n_conns);
|
|
|
|
|
|
|
|
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) {
|
2006-07-26 21:07:37 +02:00
|
|
|
const char *resource = TO_DIR_CONN(conn)->requested_resource;
|
|
|
|
if (!strcmpstart(resource, prefix))
|
|
|
|
dir_split_resource_into_fingerprints(resource + p_len,
|
2006-06-21 06:57:12 +02:00
|
|
|
tmp, NULL, 1, 0);
|
2005-09-22 08:34:29 +02:00
|
|
|
}
|
|
|
|
}
|
2005-12-27 06:26:03 +01:00
|
|
|
SMARTLIST_FOREACH(tmp, char *, d,
|
|
|
|
{
|
|
|
|
digestmap_set(result, d, (void*)1);
|
|
|
|
tor_free(d);
|
|
|
|
});
|
|
|
|
smartlist_free(tmp);
|
|
|
|
}
|
2005-09-23 20:05:14 +02:00
|
|
|
|
2006-02-05 04:42:04 +01:00
|
|
|
/** Launch downloads for all the descriptors whose digests are listed
|
2005-12-27 06:26:03 +01:00
|
|
|
* as digests[i] for lo <= i < hi. (Lo and hi may be out of range.)
|
|
|
|
* If <b>source</b> is given, download from <b>source</b>; otherwise,
|
|
|
|
* download from an appropriate random directory server.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
initiate_descriptor_downloads(routerstatus_t *source,
|
|
|
|
smartlist_t *digests,
|
|
|
|
int lo, int hi)
|
|
|
|
{
|
|
|
|
int i, n = hi-lo;
|
|
|
|
char *resource, *cp;
|
|
|
|
size_t r_len;
|
|
|
|
if (n <= 0)
|
|
|
|
return;
|
|
|
|
if (lo < 0)
|
|
|
|
lo = 0;
|
|
|
|
if (hi > smartlist_len(digests))
|
|
|
|
hi = smartlist_len(digests);
|
|
|
|
|
|
|
|
r_len = 8 + (HEX_DIGEST_LEN+1)*n;
|
|
|
|
cp = resource = tor_malloc(r_len);
|
|
|
|
memcpy(cp, "d/", 2);
|
|
|
|
cp += 2;
|
|
|
|
for (i = lo; i < hi; ++i) {
|
|
|
|
base16_encode(cp, r_len-(cp-resource),
|
|
|
|
smartlist_get(digests,i), DIGEST_LEN);
|
|
|
|
cp += HEX_DIGEST_LEN;
|
|
|
|
*cp++ = '+';
|
2005-09-22 08:34:29 +02:00
|
|
|
}
|
2005-12-27 06:26:03 +01:00
|
|
|
memcpy(cp-1, ".z", 3);
|
2005-09-22 08:34:29 +02:00
|
|
|
|
2005-12-27 06:26:03 +01:00
|
|
|
if (source) {
|
|
|
|
/* We know which authority we want. */
|
|
|
|
directory_initiate_command_routerstatus(source,
|
|
|
|
DIR_PURPOSE_FETCH_SERVERDESC,
|
|
|
|
0, /* not private */
|
|
|
|
resource, NULL, 0);
|
|
|
|
} else {
|
|
|
|
directory_get_from_dirserver(DIR_PURPOSE_FETCH_SERVERDESC,
|
|
|
|
resource,
|
|
|
|
1);
|
2005-09-15 07:19:38 +02:00
|
|
|
}
|
2005-12-27 06:26:03 +01:00
|
|
|
tor_free(resource);
|
|
|
|
}
|
2005-09-15 07:19:38 +02:00
|
|
|
|
2006-03-12 23:48:18 +01:00
|
|
|
/** Clients don't download any descriptor this recent, since it will probably
|
|
|
|
* not have propageted to enough caches. */
|
|
|
|
#define ESTIMATED_PROPAGATION_TIME (10*60)
|
|
|
|
|
2006-04-08 08:56:38 +02:00
|
|
|
/** Return 0 if this routerstatus is obsolete, too new, isn't
|
|
|
|
* running, or otherwise not a descriptor that we would make any
|
|
|
|
* use of even if we had it. Else return 1. */
|
2006-09-17 22:12:10 +02:00
|
|
|
static INLINE int
|
2006-08-15 05:54:09 +02:00
|
|
|
client_would_use_router(routerstatus_t *rs, time_t now, or_options_t *options)
|
2006-04-08 08:56:38 +02:00
|
|
|
{
|
2006-08-15 05:54:09 +02:00
|
|
|
if (!rs->is_running && !options->FetchUselessDescriptors) {
|
2006-04-08 23:35:17 +02:00
|
|
|
/* If we had this router descriptor, we wouldn't even bother using it.
|
|
|
|
* But, if we want to have a complete list, fetch it anyway. */
|
2006-04-08 08:56:38 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (rs->published_on + ESTIMATED_PROPAGATION_TIME > now) {
|
|
|
|
/* Most caches probably don't have this descriptor yet. */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2005-12-27 06:26:03 +01:00
|
|
|
/** Return new list of ID fingerprints for routers that we (as a client) would
|
|
|
|
* like to download.
|
|
|
|
*/
|
|
|
|
static smartlist_t *
|
|
|
|
router_list_client_downloadable(void)
|
|
|
|
{
|
|
|
|
int n_downloadable = 0;
|
|
|
|
smartlist_t *downloadable = smartlist_create();
|
|
|
|
digestmap_t *downloading;
|
|
|
|
time_t now = time(NULL);
|
|
|
|
/* these are just used for logging */
|
2006-04-08 08:56:38 +02:00
|
|
|
int n_not_ready = 0, n_in_progress = 0, n_uptodate = 0, n_wouldnt_use = 0;
|
2006-08-15 05:54:09 +02:00
|
|
|
or_options_t *options = get_options();
|
2005-12-27 06:26:03 +01:00
|
|
|
|
|
|
|
if (!routerstatus_list)
|
|
|
|
return downloadable;
|
2005-09-23 23:25:29 +02:00
|
|
|
|
2005-12-27 06:26:03 +01:00
|
|
|
downloading = digestmap_new();
|
|
|
|
list_pending_descriptor_downloads(downloading);
|
2005-09-13 17:32:03 +02:00
|
|
|
|
2005-12-27 06:26:03 +01:00
|
|
|
routerstatus_list_update_from_networkstatus(now);
|
2005-09-22 08:34:29 +02:00
|
|
|
SMARTLIST_FOREACH(routerstatus_list, local_routerstatus_t *, rs,
|
|
|
|
{
|
2005-12-27 06:26:03 +01:00
|
|
|
routerinfo_t *ri;
|
2006-09-17 22:12:10 +02:00
|
|
|
if (router_get_by_descriptor_digest(rs->status.descriptor_digest)) {
|
|
|
|
/* We have the 'best' descriptor for this router. */
|
|
|
|
++n_uptodate;
|
|
|
|
} else if (!client_would_use_router(&rs->status, now, options)) {
|
2006-04-08 08:56:38 +02:00
|
|
|
/* We wouldn't want this descriptor even if we got it. */
|
|
|
|
++n_wouldnt_use;
|
2005-12-27 06:26:03 +01:00
|
|
|
} else if (digestmap_get(downloading, rs->status.descriptor_digest)) {
|
|
|
|
/* We're downloading this one now. */
|
|
|
|
++n_in_progress;
|
|
|
|
} else if ((ri = router_get_by_digest(rs->status.identity_digest)) &&
|
|
|
|
ri->cache_info.published_on > rs->status.published_on) {
|
2006-01-04 07:43:03 +01:00
|
|
|
/* Oddly, we have a descriptor more recent than the 'best' one, but it
|
2005-12-27 06:26:03 +01:00
|
|
|
was once best. So that's okay. */
|
|
|
|
++n_uptodate;
|
|
|
|
} else if (rs->next_attempt_at > now) {
|
|
|
|
/* We failed too recently to try again. */
|
|
|
|
++n_not_ready;
|
|
|
|
} else {
|
|
|
|
/* Okay, time to try it. */
|
|
|
|
smartlist_add(downloadable, rs->status.descriptor_digest);
|
|
|
|
++n_downloadable;
|
2005-09-22 08:34:29 +02:00
|
|
|
}
|
|
|
|
});
|
2005-09-16 06:43:21 +02:00
|
|
|
|
2005-12-27 06:26:03 +01:00
|
|
|
#if 0
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_DIR,
|
2006-04-08 08:56:38 +02:00
|
|
|
"%d router descriptors are downloadable. "
|
|
|
|
"%d are in progress. %d are up-to-date. "
|
2006-01-16 21:52:30 +01:00
|
|
|
"%d are non-useful. %d failed too recently to retry.",
|
2006-04-08 08:56:38 +02:00
|
|
|
n_downloadable, n_in_progress, n_uptodate,
|
2006-01-16 21:52:30 +01:00
|
|
|
n_wouldnt_use, n_not_ready);
|
2005-12-27 06:26:03 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
digestmap_free(downloading, NULL);
|
|
|
|
return downloadable;
|
2005-09-12 08:56:42 +02:00
|
|
|
}
|
|
|
|
|
2006-03-17 06:50:41 +01:00
|
|
|
/** Initiate new router downloads as needed, using the strategy for
|
|
|
|
* non-directory-servers.
|
2005-09-15 08:15:31 +02:00
|
|
|
*
|
2007-02-02 19:58:11 +01:00
|
|
|
* We don't launch any downloads if there are fewer than MAX_DL_TO_DELAY
|
|
|
|
* descriptors to get and less than MAX_CLIENT_INTERVAL_WITHOUT_REQUEST
|
|
|
|
* seconds have passed.
|
2007-01-22 20:20:33 +01:00
|
|
|
*
|
2007-02-02 19:58:11 +01:00
|
|
|
* Otherwise, we ask for all descriptors that we think are different from what
|
|
|
|
* we have, and that we don't currently have an in-progress download attempt
|
|
|
|
* for. */
|
2005-12-27 06:26:03 +01:00
|
|
|
static void
|
|
|
|
update_router_descriptor_client_downloads(time_t now)
|
2005-09-15 07:19:38 +02:00
|
|
|
{
|
2007-02-02 21:06:43 +01:00
|
|
|
/** Max amount of hashes to download per request.
|
2006-02-05 04:23:16 +01:00
|
|
|
* Since squid does not like URLs >= 4096 bytes we limit it to 96.
|
|
|
|
* 4096 - strlen(http://255.255.255.255/tor/server/d/.z) == 4058
|
|
|
|
* 4058/41 (40 for the hash and 1 for the + that separates them) => 98
|
|
|
|
* So use 96 because it's a nice number.
|
|
|
|
*/
|
2006-02-03 16:17:48 +01:00
|
|
|
#define MAX_DL_PER_REQUEST 96
|
2006-03-12 23:48:18 +01:00
|
|
|
/** Don't split our requests so finely that we are requesting fewer than
|
|
|
|
* this number per server. */
|
2005-09-23 20:05:14 +02:00
|
|
|
#define MIN_DL_PER_REQUEST 4
|
2006-03-12 23:48:18 +01:00
|
|
|
/** To prevent a single screwy cache from confusing us by selective reply,
|
|
|
|
* try to split our requests into at least this this many requests. */
|
2005-09-22 08:34:29 +02:00
|
|
|
#define MIN_REQUESTS 3
|
2006-03-12 23:48:18 +01:00
|
|
|
/** If we want fewer than this many descriptors, wait until we
|
2006-04-03 04:20:32 +02:00
|
|
|
* want more, or until MAX_CLIENT_INTERVAL_WITHOUT_REQUEST has
|
2006-03-12 23:48:18 +01:00
|
|
|
* passed. */
|
2005-09-30 22:04:55 +02:00
|
|
|
#define MAX_DL_TO_DELAY 16
|
2006-03-12 23:48:18 +01:00
|
|
|
/** When directory clients have only a few servers to request, they batch
|
|
|
|
* them until they have more, or until this amount of time has passed. */
|
|
|
|
#define MAX_CLIENT_INTERVAL_WITHOUT_REQUEST (10*60)
|
2005-09-18 04:24:42 +02:00
|
|
|
smartlist_t *downloadable = NULL;
|
2005-10-04 22:18:26 +02:00
|
|
|
int should_delay, n_downloadable;
|
2005-12-27 06:26:03 +01:00
|
|
|
or_options_t *options = get_options();
|
2005-09-18 04:24:42 +02:00
|
|
|
|
2006-05-30 08:11:36 +02:00
|
|
|
if (options->DirPort) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_BUG,
|
2006-05-30 08:11:36 +02:00
|
|
|
"Called router_descriptor_client_downloads() on a dir mirror?");
|
2005-09-23 20:05:14 +02:00
|
|
|
}
|
|
|
|
|
2006-06-09 00:36:13 +02:00
|
|
|
if (rep_hist_circbuilding_dormant(now)) {
|
2007-03-09 09:48:21 +01:00
|
|
|
// log_info(LD_CIRC, "Skipping descriptor downloads: we haven't needed "
|
|
|
|
// "any circuits lately.");
|
2006-05-30 08:19:06 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-09-29 01:57:59 +02:00
|
|
|
if (networkstatus_list &&
|
|
|
|
smartlist_len(networkstatus_list) <= get_n_v2_authorities()/2) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_DIR,
|
|
|
|
"Not enough networkstatus documents to launch requests.");
|
2007-01-22 21:57:26 +01:00
|
|
|
return;
|
2005-12-27 06:26:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
downloadable = router_list_client_downloadable();
|
2005-10-04 22:18:26 +02:00
|
|
|
n_downloadable = smartlist_len(downloadable);
|
2005-10-05 22:45:18 +02:00
|
|
|
if (n_downloadable >= MAX_DL_TO_DELAY) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_debug(LD_DIR,
|
|
|
|
"There are enough downloadable routerdescs to launch requests.");
|
2005-10-04 22:18:26 +02:00
|
|
|
should_delay = 0;
|
2005-10-05 22:45:18 +02:00
|
|
|
} else if (n_downloadable == 0) {
|
2006-02-13 11:33:00 +01:00
|
|
|
// log_debug(LD_DIR, "No routerdescs need to be downloaded.");
|
2005-10-04 22:18:26 +02:00
|
|
|
should_delay = 1;
|
2005-10-05 22:45:18 +02:00
|
|
|
} else {
|
2005-12-27 06:26:03 +01:00
|
|
|
should_delay = (last_routerdesc_download_attempted +
|
2006-02-05 04:42:04 +01:00
|
|
|
MAX_CLIENT_INTERVAL_WITHOUT_REQUEST) > now;
|
2006-02-19 20:44:09 +01:00
|
|
|
if (!should_delay) {
|
|
|
|
if (last_routerdesc_download_attempted) {
|
|
|
|
log_info(LD_DIR,
|
2006-02-13 11:33:00 +01:00
|
|
|
"There are not many downloadable routerdescs, but we've "
|
2006-02-05 04:42:04 +01:00
|
|
|
"been waiting long enough (%d seconds). Downloading.",
|
|
|
|
(int)(now-last_routerdesc_download_attempted));
|
2006-02-19 20:44:09 +01:00
|
|
|
} else {
|
|
|
|
log_info(LD_DIR,
|
2006-05-26 18:29:20 +02:00
|
|
|
"There are not many downloadable routerdescs, but we haven't "
|
|
|
|
"tried downloading descriptors recently. Downloading.");
|
2006-02-19 20:44:09 +01:00
|
|
|
}
|
|
|
|
}
|
2005-10-05 22:45:18 +02:00
|
|
|
}
|
2005-10-04 22:18:26 +02:00
|
|
|
|
|
|
|
if (! should_delay) {
|
2005-12-27 06:26:03 +01:00
|
|
|
int i, n_per_request;
|
|
|
|
n_per_request = (n_downloadable+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;
|
|
|
|
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_DIR,
|
|
|
|
"Launching %d request%s for %d router%s, %d at a time",
|
|
|
|
(n_downloadable+n_per_request-1)/n_per_request,
|
|
|
|
n_downloadable>n_per_request?"s":"",
|
|
|
|
n_downloadable, n_downloadable>1?"s":"", n_per_request);
|
2006-06-21 06:57:12 +02:00
|
|
|
smartlist_sort_digests(downloadable);
|
2005-10-04 22:18:26 +02:00
|
|
|
for (i=0; i < n_downloadable; i += n_per_request) {
|
2005-12-27 06:26:03 +01:00
|
|
|
initiate_descriptor_downloads(NULL, downloadable, i, i+n_per_request);
|
2005-09-18 04:24:42 +02:00
|
|
|
}
|
2005-10-05 07:03:52 +02:00
|
|
|
last_routerdesc_download_attempted = now;
|
2005-09-18 04:24:42 +02:00
|
|
|
}
|
2005-09-23 20:05:14 +02:00
|
|
|
smartlist_free(downloadable);
|
2005-09-15 07:19:38 +02:00
|
|
|
}
|
|
|
|
|
2006-03-17 06:50:41 +01:00
|
|
|
/** Launch downloads for router status as needed, using the strategy used by
|
|
|
|
* authorities and caches: download every descriptor we don't have but would
|
2007-01-22 06:59:59 +01:00
|
|
|
* serve, from a random authority that lists it. */
|
2005-12-27 06:26:03 +01:00
|
|
|
static void
|
|
|
|
update_router_descriptor_cache_downloads(time_t now)
|
|
|
|
{
|
|
|
|
smartlist_t **downloadable; /* For each authority, what can we dl from it? */
|
|
|
|
smartlist_t **download_from; /* ... and, what will we dl from it? */
|
|
|
|
digestmap_t *map; /* Which descs are in progress, or assigned? */
|
|
|
|
int i, j, n;
|
|
|
|
int n_download;
|
|
|
|
or_options_t *options = get_options();
|
2006-06-05 00:42:13 +02:00
|
|
|
(void) now;
|
2005-12-27 06:26:03 +01:00
|
|
|
|
2006-05-30 08:11:36 +02:00
|
|
|
if (!options->DirPort) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_BUG, "Called update_router_descriptor_cache_downloads() "
|
2006-05-30 08:11:36 +02:00
|
|
|
"on a non-dir-mirror?");
|
2005-12-27 06:26:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!networkstatus_list || !smartlist_len(networkstatus_list))
|
|
|
|
return;
|
|
|
|
|
|
|
|
map = digestmap_new();
|
|
|
|
n = smartlist_len(networkstatus_list);
|
|
|
|
|
|
|
|
downloadable = tor_malloc_zero(sizeof(smartlist_t*) * n);
|
|
|
|
download_from = tor_malloc_zero(sizeof(smartlist_t*) * n);
|
|
|
|
|
|
|
|
/* Set map[d]=1 for the digest of every descriptor that we are currently
|
|
|
|
* downloading. */
|
|
|
|
list_pending_descriptor_downloads(map);
|
|
|
|
|
|
|
|
/* For the digest of every descriptor that we don't have, and that we aren't
|
|
|
|
* downloading, add d to downloadable[i] if the i'th networkstatus knows
|
|
|
|
* about that descriptor, and we haven't already failed to get that
|
|
|
|
* descriptor from the corresponding authority.
|
|
|
|
*/
|
|
|
|
n_download = 0;
|
|
|
|
SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
|
|
|
|
{
|
2007-02-22 08:41:10 +01:00
|
|
|
smartlist_t *dl;
|
2007-02-24 00:11:08 +01:00
|
|
|
dl = downloadable[ns_sl_idx] = smartlist_create();
|
|
|
|
download_from[ns_sl_idx] = smartlist_create();
|
2007-02-26 06:33:17 +01:00
|
|
|
if (ns->published_on + MAX_NETWORKSTATUS_AGE+10*60 < now) {
|
2007-02-22 08:41:10 +01:00
|
|
|
/* Don't download if the networkstatus is almost ancient. */
|
2007-02-26 06:33:17 +01:00
|
|
|
/* Actually, I suspect what's happening here is that we ask
|
|
|
|
* for the descriptor when we have a given networkstatus,
|
|
|
|
* and then we get a newer networkstatus, and then we receive
|
|
|
|
* the descriptor. Having a networkstatus actually expire is
|
|
|
|
* probably a rare event, and we'll probably be happiest if
|
|
|
|
* we take this clause out. -RD */
|
2007-02-22 08:41:10 +01:00
|
|
|
continue;
|
|
|
|
}
|
2007-03-20 03:10:18 +01:00
|
|
|
{ /* XXX temporary hack so I can debug other stuff without bug 384
|
|
|
|
* filling up my logs. */
|
|
|
|
trusted_dir_server_t *ds;
|
|
|
|
ds = router_get_trusteddirserver_by_digest(ns->identity_digest);
|
|
|
|
if (ds && !ds->is_running)
|
|
|
|
continue;
|
|
|
|
}
|
2005-12-27 06:26:03 +01:00
|
|
|
SMARTLIST_FOREACH(ns->entries, routerstatus_t * , rs,
|
|
|
|
{
|
|
|
|
if (!rs->need_to_mirror)
|
|
|
|
continue;
|
|
|
|
if (router_get_by_descriptor_digest(rs->descriptor_digest)) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_BUG,
|
2007-03-04 21:11:46 +01:00
|
|
|
"We have a router descriptor, but need_to_mirror=1.");
|
2005-12-27 06:26:03 +01:00
|
|
|
rs->need_to_mirror = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (options->AuthoritativeDir && dirserv_would_reject_router(rs)) {
|
|
|
|
rs->need_to_mirror = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (digestmap_get(map, rs->descriptor_digest)) {
|
|
|
|
/* We're downloading it already. */
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
/* We could download it from this guy. */
|
|
|
|
smartlist_add(dl, rs->descriptor_digest);
|
|
|
|
++n_download;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
/* At random, assign descriptors to authorities such that:
|
|
|
|
* - if d is a member of some downloadable[x], d is a member of some
|
|
|
|
* download_from[y]. (Everything we want to download, we try to download
|
|
|
|
* from somebody.)
|
2006-03-22 07:22:12 +01:00
|
|
|
* - If d is a member of download_from[y], d is a member of downloadable[y].
|
2005-12-27 06:26:03 +01:00
|
|
|
* (We only try to download descriptors from authorities who claim to have
|
|
|
|
* them.)
|
|
|
|
* - No d is a member of download_from[x] and download_from[y] s.t. x != y.
|
|
|
|
* (We don't try to download anything from two authorities concurrently.)
|
|
|
|
*/
|
|
|
|
while (n_download) {
|
|
|
|
int which_ns = crypto_rand_int(n);
|
|
|
|
smartlist_t *dl = downloadable[which_ns];
|
|
|
|
int idx;
|
|
|
|
char *d;
|
|
|
|
if (!smartlist_len(dl))
|
|
|
|
continue;
|
|
|
|
idx = crypto_rand_int(smartlist_len(dl));
|
|
|
|
d = smartlist_get(dl, idx);
|
|
|
|
if (! digestmap_get(map, d)) {
|
|
|
|
smartlist_add(download_from[which_ns], d);
|
|
|
|
digestmap_set(map, d, (void*) 1);
|
|
|
|
}
|
|
|
|
smartlist_del(dl, idx);
|
|
|
|
--n_download;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now, we can actually launch our requests. */
|
|
|
|
for (i=0; i<n; ++i) {
|
|
|
|
networkstatus_t *ns = smartlist_get(networkstatus_list, i);
|
|
|
|
trusted_dir_server_t *ds =
|
|
|
|
router_get_trusteddirserver_by_digest(ns->identity_digest);
|
2005-12-29 21:25:53 +01:00
|
|
|
smartlist_t *dl = download_from[i];
|
2005-12-27 06:26:03 +01:00
|
|
|
if (!ds) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_BUG, "Networkstatus with no corresponding authority!");
|
2005-12-27 06:26:03 +01:00
|
|
|
continue;
|
|
|
|
}
|
2005-12-27 07:05:54 +01:00
|
|
|
if (! smartlist_len(dl))
|
|
|
|
continue;
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_DIR, "Requesting %d descriptors from authority \"%s\"",
|
|
|
|
smartlist_len(dl), ds->nickname);
|
2005-12-27 06:26:03 +01:00
|
|
|
for (j=0; j < smartlist_len(dl); j += MAX_DL_PER_REQUEST) {
|
2006-12-24 03:45:35 +01:00
|
|
|
initiate_descriptor_downloads(&(ds->fake_status.status), dl, j,
|
2005-12-27 06:26:03 +01:00
|
|
|
j+MAX_DL_PER_REQUEST);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<n; ++i) {
|
|
|
|
smartlist_free(download_from[i]);
|
|
|
|
smartlist_free(downloadable[i]);
|
|
|
|
}
|
|
|
|
tor_free(download_from);
|
|
|
|
tor_free(downloadable);
|
|
|
|
digestmap_free(map,NULL);
|
|
|
|
}
|
|
|
|
|
2006-03-17 06:50:41 +01:00
|
|
|
/** Launch downloads for router status as needed. */
|
2005-12-27 06:26:03 +01:00
|
|
|
void
|
|
|
|
update_router_descriptor_downloads(time_t now)
|
|
|
|
{
|
|
|
|
or_options_t *options = get_options();
|
2006-05-30 08:11:36 +02:00
|
|
|
if (options->DirPort) {
|
2005-12-27 06:26:03 +01:00
|
|
|
update_router_descriptor_cache_downloads(now);
|
|
|
|
} else {
|
|
|
|
update_router_descriptor_client_downloads(now);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-16 21:01:02 +01:00
|
|
|
/** Return the number of routerstatus_t in <b>entries</b> that we'd actually
|
|
|
|
* use. */
|
2006-04-08 08:56:38 +02:00
|
|
|
static int
|
|
|
|
routerstatus_count_usable_entries(smartlist_t *entries)
|
|
|
|
{
|
|
|
|
int count = 0;
|
|
|
|
time_t now = time(NULL);
|
2006-08-15 05:54:09 +02:00
|
|
|
or_options_t *options = get_options();
|
2006-04-08 08:56:38 +02:00
|
|
|
SMARTLIST_FOREACH(entries, routerstatus_t *, rs,
|
2006-08-15 05:54:09 +02:00
|
|
|
if (client_would_use_router(rs, now, options)) count++);
|
2006-04-08 08:56:38 +02:00
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2007-02-16 21:01:02 +01:00
|
|
|
/** True iff, the last time we checked whether we had enough directory info
|
|
|
|
* to build circuits, the answer was "yes". */
|
2006-08-15 05:54:09 +02:00
|
|
|
static int have_min_dir_info = 0;
|
2007-02-24 08:50:38 +01:00
|
|
|
/** True iff enough has changed since the last time we checked whether we had
|
2007-02-16 21:01:02 +01:00
|
|
|
* enough directory info to build circuits that our old answer can no longer
|
2007-02-24 08:50:38 +01:00
|
|
|
* be trusted. */
|
2006-08-15 05:54:09 +02:00
|
|
|
static int need_to_update_have_min_dir_info = 1;
|
|
|
|
|
2005-09-15 08:15:31 +02:00
|
|
|
/** Return true iff we have enough networkstatus and router information to
|
2006-03-22 07:22:12 +01:00
|
|
|
* start building circuits. Right now, this means "more than half the
|
|
|
|
* networkstatus documents, and at least 1/4 of expected routers." */
|
2005-12-15 22:26:52 +01:00
|
|
|
//XXX should consider whether we have enough exiting nodes here.
|
2005-09-15 07:19:38 +02:00
|
|
|
int
|
|
|
|
router_have_minimum_dir_info(void)
|
2006-08-15 05:54:09 +02:00
|
|
|
{
|
2007-03-06 21:25:44 +01:00
|
|
|
if (PREDICT_UNLIKELY(need_to_update_have_min_dir_info)) {
|
2006-08-15 05:54:09 +02:00
|
|
|
update_router_have_minimum_dir_info();
|
|
|
|
need_to_update_have_min_dir_info = 0;
|
|
|
|
}
|
|
|
|
return have_min_dir_info;
|
|
|
|
}
|
|
|
|
|
2007-01-22 08:51:06 +01:00
|
|
|
/** Called when our internal view of the directory has changed. This can be
|
|
|
|
* when the authorities change, networkstatuses change, the list of routerdescs
|
|
|
|
* changes, or number of running routers changes.
|
2006-08-15 05:54:09 +02:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
router_dir_info_changed(void)
|
|
|
|
{
|
|
|
|
need_to_update_have_min_dir_info = 1;
|
|
|
|
}
|
|
|
|
|
2007-01-22 08:51:06 +01:00
|
|
|
/** Change the value of have_min_dir_info, setting it true iff we have enough
|
|
|
|
* network and router information to build circuits. Clear the value of
|
|
|
|
* need_to_update_have_min_dir_info. */
|
2006-08-15 05:54:09 +02:00
|
|
|
static void
|
|
|
|
update_router_have_minimum_dir_info(void)
|
2005-09-15 07:19:38 +02:00
|
|
|
{
|
2006-01-03 14:09:49 +01:00
|
|
|
int tot = 0, num_running = 0;
|
2006-04-10 07:48:04 +02:00
|
|
|
int n_ns, n_authorities, res, avg;
|
2007-02-13 03:01:38 +01:00
|
|
|
time_t now = time(NULL);
|
2005-12-15 21:44:15 +01:00
|
|
|
if (!networkstatus_list || !routerlist) {
|
|
|
|
res = 0;
|
|
|
|
goto done;
|
|
|
|
}
|
2007-02-13 03:01:38 +01:00
|
|
|
routerlist_remove_old_routers();
|
|
|
|
networkstatus_list_clean(now);
|
|
|
|
|
2006-09-29 01:57:59 +02:00
|
|
|
n_authorities = get_n_v2_authorities();
|
2005-12-15 21:44:15 +01:00
|
|
|
n_ns = smartlist_len(networkstatus_list);
|
2006-03-22 07:22:12 +01:00
|
|
|
if (n_ns<=n_authorities/2) {
|
|
|
|
log_info(LD_DIR,
|
|
|
|
"We have %d of %d network statuses, and we want "
|
|
|
|
"more than %d.", n_ns, n_authorities, n_authorities/2);
|
2005-12-15 21:44:15 +01:00
|
|
|
res = 0;
|
|
|
|
goto done;
|
|
|
|
}
|
2005-09-15 07:19:38 +02:00
|
|
|
SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
|
2006-04-08 08:56:38 +02:00
|
|
|
tot += routerstatus_count_usable_entries(ns->entries));
|
2005-12-15 21:44:15 +01:00
|
|
|
avg = tot / n_ns;
|
2006-06-09 08:52:49 +02:00
|
|
|
if (!routerstatus_list)
|
|
|
|
routerstatus_list = smartlist_create();
|
2005-12-15 21:44:15 +01:00
|
|
|
SMARTLIST_FOREACH(routerstatus_list, local_routerstatus_t *, rs,
|
|
|
|
{
|
2006-01-03 14:09:49 +01:00
|
|
|
if (rs->status.is_running)
|
|
|
|
num_running++;
|
2005-12-15 21:44:15 +01:00
|
|
|
});
|
2006-01-03 14:09:49 +01:00
|
|
|
res = smartlist_len(routerlist->routers) >= (avg/4) && num_running > 2;
|
2005-12-15 21:44:15 +01:00
|
|
|
done:
|
2006-08-15 05:54:09 +02:00
|
|
|
if (res && !have_min_dir_info) {
|
2005-12-15 21:44:15 +01:00
|
|
|
log(LOG_NOTICE, LD_DIR,
|
|
|
|
"We now have enough directory information to build circuits.");
|
2006-10-23 12:16:43 +02:00
|
|
|
control_event_client_status(LOG_NOTICE, "ENOUGH_DIR_INFO");
|
2005-12-15 21:44:15 +01:00
|
|
|
}
|
2006-08-15 05:54:09 +02:00
|
|
|
if (!res && have_min_dir_info) {
|
2005-12-15 22:17:40 +01:00
|
|
|
log(LOG_NOTICE, LD_DIR,"Our directory information is no longer up-to-date "
|
2005-12-15 22:41:27 +01:00
|
|
|
"enough to build circuits.%s",
|
2006-01-03 14:12:17 +01:00
|
|
|
num_running > 2 ? "" : " (Not enough servers seem reachable -- "
|
|
|
|
"is your network connection down?)");
|
2006-10-23 12:16:43 +02:00
|
|
|
control_event_client_status(LOG_NOTICE, "NOT_ENOUGH_DIR_INFO");
|
2005-12-15 21:44:15 +01:00
|
|
|
}
|
2006-08-15 05:54:09 +02:00
|
|
|
have_min_dir_info = res;
|
2005-09-15 07:19:38 +02:00
|
|
|
}
|
|
|
|
|
2006-04-07 06:52:32 +02:00
|
|
|
/** Return true iff we have downloaded, or attempted to download at least
|
|
|
|
* n_failures times, a network status for each authority. */
|
2006-03-17 05:41:57 +01:00
|
|
|
static int
|
2006-04-07 06:52:32 +02:00
|
|
|
have_tried_downloading_all_statuses(int n_failures)
|
2006-03-17 05:41:57 +01:00
|
|
|
{
|
|
|
|
if (!trusted_dir_servers)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
|
|
|
|
{
|
2006-09-29 01:57:59 +02:00
|
|
|
if (!ds->is_v2_authority)
|
|
|
|
continue;
|
2006-03-17 05:41:57 +01:00
|
|
|
/* If we don't have the status, and we haven't failed to get the status,
|
|
|
|
* we haven't tried to get the status. */
|
|
|
|
if (!networkstatus_get_by_digest(ds->digest) &&
|
2006-04-07 06:52:32 +02:00
|
|
|
ds->n_networkstatus_failures <= n_failures)
|
2006-03-17 05:41:57 +01:00
|
|
|
return 0;
|
|
|
|
});
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
});
|
2006-01-17 05:14:04 +01:00
|
|
|
tor_assert(networkstatus_list);
|
2005-12-27 06:26:03 +01:00
|
|
|
SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
|
|
|
|
SMARTLIST_FOREACH(ns->entries, routerstatus_t *, rs,
|
|
|
|
{
|
|
|
|
if (!router_get_by_descriptor_digest(rs->descriptor_digest))
|
|
|
|
rs->need_to_mirror = 1;
|
|
|
|
}));
|
2005-10-05 07:03:52 +02:00
|
|
|
last_routerdesc_download_attempted = 0;
|
2005-09-22 08:34:29 +02:00
|
|
|
}
|
2005-09-23 19:11:20 +02:00
|
|
|
|
2006-03-12 23:48:18 +01:00
|
|
|
/** Any changes in a router descriptor's publication time larger than this are
|
|
|
|
* automatically non-cosmetic. */
|
|
|
|
#define ROUTER_MAX_COSMETIC_TIME_DIFFERENCE (12*60*60)
|
|
|
|
|
2006-06-18 18:05:54 +02:00
|
|
|
/** We allow uptime to vary from how much it ought to be by this much. */
|
2006-11-02 00:53:15 +01:00
|
|
|
#define ROUTER_ALLOW_UPTIME_DRIFT (6*60*60)
|
2006-06-18 18:05:54 +02:00
|
|
|
|
2005-10-12 15:49:13 +02:00
|
|
|
/** Return true iff the only differences between r1 and r2 are such that
|
2005-11-01 04:48:51 +01:00
|
|
|
* would not cause a recent (post 0.1.1.6) dirserver to republish.
|
2005-10-12 15:49:13 +02:00
|
|
|
*/
|
|
|
|
int
|
|
|
|
router_differences_are_cosmetic(routerinfo_t *r1, routerinfo_t *r2)
|
|
|
|
{
|
2005-12-14 21:40:40 +01:00
|
|
|
time_t r1pub, r2pub;
|
2006-11-02 00:53:15 +01:00
|
|
|
int time_difference;
|
2005-10-12 20:25:25 +02:00
|
|
|
tor_assert(r1 && r2);
|
|
|
|
|
2005-10-19 18:21:19 +02:00
|
|
|
/* r1 should be the one that was published first. */
|
2005-11-05 21:15:27 +01:00
|
|
|
if (r1->cache_info.published_on > r2->cache_info.published_on) {
|
2005-10-12 20:25:25 +02:00
|
|
|
routerinfo_t *ri_tmp = r2;
|
|
|
|
r2 = r1;
|
|
|
|
r1 = ri_tmp;
|
|
|
|
}
|
|
|
|
|
2005-10-12 15:49:13 +02:00
|
|
|
/* If any key fields differ, they're different. */
|
|
|
|
if (strcasecmp(r1->address, r2->address) ||
|
|
|
|
strcasecmp(r1->nickname, r2->nickname) ||
|
|
|
|
r1->or_port != r2->or_port ||
|
|
|
|
r1->dir_port != r2->dir_port ||
|
2005-10-12 19:16:25 +02:00
|
|
|
crypto_pk_cmp_keys(r1->onion_pkey, r2->onion_pkey) ||
|
|
|
|
crypto_pk_cmp_keys(r1->identity_pkey, r2->identity_pkey) ||
|
2005-10-12 15:49:13 +02:00
|
|
|
strcasecmp(r1->platform, r2->platform) ||
|
2005-10-18 23:19:02 +02:00
|
|
|
(r1->contact_info && !r2->contact_info) || /* contact_info is optional */
|
|
|
|
(!r1->contact_info && r2->contact_info) ||
|
2005-12-14 21:40:40 +01:00
|
|
|
(r1->contact_info && r2->contact_info &&
|
|
|
|
strcasecmp(r1->contact_info, r2->contact_info)) ||
|
2005-10-12 15:49:13 +02:00
|
|
|
r1->is_hibernating != r2->is_hibernating ||
|
2006-09-22 22:20:21 +02:00
|
|
|
r1->has_old_dnsworkers != r2->has_old_dnsworkers ||
|
2006-03-27 04:25:34 +02:00
|
|
|
cmp_addr_policies(r1->exit_policy, r2->exit_policy))
|
2005-10-12 15:49:13 +02:00
|
|
|
return 0;
|
|
|
|
if ((r1->declared_family == NULL) != (r2->declared_family == NULL))
|
|
|
|
return 0;
|
|
|
|
if (r1->declared_family && r2->declared_family) {
|
|
|
|
int i, n;
|
|
|
|
if (smartlist_len(r1->declared_family)!=smartlist_len(r2->declared_family))
|
|
|
|
return 0;
|
|
|
|
n = smartlist_len(r1->declared_family);
|
|
|
|
for (i=0; i < n; ++i) {
|
|
|
|
if (strcasecmp(smartlist_get(r1->declared_family, i),
|
|
|
|
smartlist_get(r2->declared_family, i)))
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Did bandwidth change a lot? */
|
|
|
|
if ((r1->bandwidthcapacity < r2->bandwidthcapacity/2) ||
|
|
|
|
(r2->bandwidthcapacity < r1->bandwidthcapacity/2))
|
|
|
|
return 0;
|
|
|
|
|
2005-10-19 18:21:19 +02:00
|
|
|
/* Did more than 12 hours pass? */
|
2006-03-12 23:48:18 +01:00
|
|
|
if (r1->cache_info.published_on + ROUTER_MAX_COSMETIC_TIME_DIFFERENCE
|
|
|
|
< r2->cache_info.published_on)
|
2005-10-12 20:25:25 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Did uptime fail to increase by approximately the amount we would think,
|
2006-12-02 23:47:46 +01:00
|
|
|
* give or take some slop? */
|
2005-12-14 21:40:40 +01:00
|
|
|
r1pub = r1->cache_info.published_on;
|
|
|
|
r2pub = r2->cache_info.published_on;
|
2006-11-02 00:53:15 +01:00
|
|
|
time_difference = abs(r2->uptime - (r1->uptime + (r2pub - r1pub)));
|
|
|
|
if (time_difference > ROUTER_ALLOW_UPTIME_DRIFT &&
|
|
|
|
time_difference > r1->uptime * .05 &&
|
|
|
|
time_difference > r2->uptime * .05)
|
2005-10-12 15:49:13 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Otherwise, the difference is cosmetic. */
|
|
|
|
return 1;
|
|
|
|
}
|
2005-10-14 06:56:20 +02:00
|
|
|
|
2006-10-20 16:58:29 +02:00
|
|
|
/** Generate networkstatus lines for a single routerstatus_t object, and
|
|
|
|
* return the result in a newly allocated string. Used only by controller
|
|
|
|
* interface (for now.) */
|
|
|
|
/* XXXX This should eventually merge into generate_v2_networkstatus() */
|
2006-10-20 23:04:39 +02:00
|
|
|
char *
|
2006-10-20 16:58:29 +02:00
|
|
|
networkstatus_getinfo_helper_single(routerstatus_t *rs)
|
|
|
|
{
|
|
|
|
char buf[192];
|
|
|
|
int r;
|
|
|
|
struct in_addr in;
|
|
|
|
|
|
|
|
int f_authority;
|
|
|
|
char published[ISO_TIME_LEN+1];
|
|
|
|
char ipaddr[INET_NTOA_BUF_LEN];
|
|
|
|
char identity64[BASE64_DIGEST_LEN+1];
|
|
|
|
char digest64[BASE64_DIGEST_LEN+1];
|
|
|
|
|
|
|
|
format_iso_time(published, rs->published_on);
|
|
|
|
digest_to_base64(identity64, rs->identity_digest);
|
|
|
|
digest_to_base64(digest64, rs->descriptor_digest);
|
|
|
|
in.s_addr = htonl(rs->addr);
|
|
|
|
tor_inet_ntoa(&in, ipaddr, sizeof(ipaddr));
|
|
|
|
|
|
|
|
f_authority = router_digest_is_trusted_dir(rs->identity_digest);
|
|
|
|
|
|
|
|
r = tor_snprintf(buf, sizeof(buf),
|
|
|
|
"r %s %s %s %s %s %d %d\n"
|
|
|
|
"s%s%s%s%s%s%s%s%s%s%s\n",
|
|
|
|
rs->nickname,
|
|
|
|
identity64,
|
|
|
|
digest64,
|
|
|
|
published,
|
|
|
|
ipaddr,
|
|
|
|
(int)rs->or_port,
|
|
|
|
(int)rs->dir_port,
|
|
|
|
|
|
|
|
f_authority?" Authority":"",
|
|
|
|
rs->is_bad_exit?" BadExit":"",
|
|
|
|
rs->is_exit?" Exit":"",
|
|
|
|
rs->is_fast?" Fast":"",
|
|
|
|
rs->is_possible_guard?" Guard":"",
|
|
|
|
rs->is_named?" Named":"",
|
|
|
|
rs->is_stable?" Stable":"",
|
|
|
|
rs->is_running?" Running":"",
|
|
|
|
rs->is_valid?" Valid":"",
|
|
|
|
rs->is_v2_dir?" V2Dir":"");
|
|
|
|
if (r<0)
|
|
|
|
log_warn(LD_BUG, "Not enough space in buffer.");
|
|
|
|
|
|
|
|
return tor_strdup(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** If <b>question</b> is a string beginning with "ns/" in a format the
|
|
|
|
* control interface expects for a GETINFO question, set *<b>answer</b> to a
|
|
|
|
* newly-allocated string containing networkstatus lines for the appropriate
|
2006-10-20 21:11:12 +02:00
|
|
|
* ORs. Return 0 on success, -1 on unrecognized question format. */
|
2006-10-20 16:58:29 +02:00
|
|
|
int
|
2006-12-08 05:39:13 +01:00
|
|
|
getinfo_helper_networkstatus(control_connection_t *conn,
|
|
|
|
const char *question, char **answer)
|
2006-10-20 16:58:29 +02:00
|
|
|
{
|
|
|
|
local_routerstatus_t *status;
|
2006-12-08 05:39:13 +01:00
|
|
|
(void) conn;
|
2006-10-20 16:58:29 +02:00
|
|
|
|
|
|
|
if (!routerstatus_list) {
|
|
|
|
*answer = tor_strdup("");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-10-20 21:11:12 +02:00
|
|
|
if (!strcmp(question, "ns/all")) {
|
2006-10-20 16:58:29 +02:00
|
|
|
smartlist_t *statuses = smartlist_create();
|
|
|
|
SMARTLIST_FOREACH(routerstatus_list, local_routerstatus_t *, lrs,
|
|
|
|
{
|
|
|
|
routerstatus_t *rs = &(lrs->status);
|
|
|
|
smartlist_add(statuses, networkstatus_getinfo_helper_single(rs));
|
|
|
|
});
|
|
|
|
*answer = smartlist_join_strings(statuses, "", 0, NULL);
|
|
|
|
SMARTLIST_FOREACH(statuses, char *, cp, tor_free(cp));
|
|
|
|
smartlist_free(statuses);
|
|
|
|
return 0;
|
|
|
|
} else if (!strcmpstart(question, "ns/id/")) {
|
|
|
|
char d[DIGEST_LEN];
|
|
|
|
|
|
|
|
if (base16_decode(d, DIGEST_LEN, question+6, strlen(question+6)))
|
|
|
|
return -1;
|
|
|
|
status = router_get_combined_status_by_digest(d);
|
|
|
|
} else if (!strcmpstart(question, "ns/name/")) {
|
|
|
|
status = router_get_combined_status_by_nickname(question+8, 0);
|
|
|
|
} else {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (status) {
|
|
|
|
*answer = networkstatus_getinfo_helper_single(&status->status);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-01-22 08:51:06 +01:00
|
|
|
/** Assert that the internal representation of <b>rl</b> is
|
|
|
|
* self-consistent. */
|
2005-10-18 22:13:09 +02:00
|
|
|
static void
|
|
|
|
routerlist_assert_ok(routerlist_t *rl)
|
|
|
|
{
|
|
|
|
digestmap_iter_t *iter;
|
2005-10-27 02:34:39 +02:00
|
|
|
routerinfo_t *r2;
|
2005-11-05 21:15:27 +01:00
|
|
|
signed_descriptor_t *sd2;
|
2005-10-18 22:13:09 +02:00
|
|
|
if (!routerlist)
|
|
|
|
return;
|
|
|
|
SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r,
|
|
|
|
{
|
2005-11-05 21:15:27 +01:00
|
|
|
r2 = digestmap_get(rl->identity_map, r->cache_info.identity_digest);
|
2005-10-27 02:34:39 +02:00
|
|
|
tor_assert(r == r2);
|
2005-12-14 21:40:40 +01:00
|
|
|
sd2 = digestmap_get(rl->desc_digest_map,
|
|
|
|
r->cache_info.signed_descriptor_digest);
|
2005-11-05 21:15:27 +01:00
|
|
|
tor_assert(&(r->cache_info) == sd2);
|
2006-09-20 01:18:30 +02:00
|
|
|
tor_assert(r->routerlist_index == r_sl_idx);
|
2005-10-27 02:34:39 +02:00
|
|
|
});
|
2005-11-05 21:15:27 +01:00
|
|
|
SMARTLIST_FOREACH(rl->old_routers, signed_descriptor_t *, sd,
|
2005-10-27 02:34:39 +02:00
|
|
|
{
|
2005-11-05 21:15:27 +01:00
|
|
|
r2 = digestmap_get(rl->identity_map, sd->identity_digest);
|
|
|
|
tor_assert(sd != &(r2->cache_info));
|
|
|
|
sd2 = digestmap_get(rl->desc_digest_map, sd->signed_descriptor_digest);
|
|
|
|
tor_assert(sd == sd2);
|
2005-10-18 22:13:09 +02:00
|
|
|
});
|
|
|
|
iter = digestmap_iter_init(rl->identity_map);
|
|
|
|
while (!digestmap_iter_done(iter)) {
|
|
|
|
const char *d;
|
|
|
|
void *_r;
|
|
|
|
routerinfo_t *r;
|
|
|
|
digestmap_iter_get(iter, &d, &_r);
|
|
|
|
r = _r;
|
2005-11-05 21:15:27 +01:00
|
|
|
tor_assert(!memcmp(r->cache_info.identity_digest, d, DIGEST_LEN));
|
2005-10-18 22:13:09 +02:00
|
|
|
iter = digestmap_iter_next(rl->identity_map, iter);
|
|
|
|
}
|
2005-10-27 02:34:39 +02:00
|
|
|
iter = digestmap_iter_init(rl->desc_digest_map);
|
|
|
|
while (!digestmap_iter_done(iter)) {
|
|
|
|
const char *d;
|
2005-11-05 21:15:27 +01:00
|
|
|
void *_sd;
|
|
|
|
signed_descriptor_t *sd;
|
|
|
|
digestmap_iter_get(iter, &d, &_sd);
|
|
|
|
sd = _sd;
|
|
|
|
tor_assert(!memcmp(sd->signed_descriptor_digest, d, DIGEST_LEN));
|
2005-10-27 02:34:39 +02:00
|
|
|
iter = digestmap_iter_next(rl->desc_digest_map, iter);
|
|
|
|
}
|
2005-10-18 22:13:09 +02:00
|
|
|
}
|
|
|
|
|
2006-03-11 18:52:55 +01:00
|
|
|
/** Allocate and return a new string representing the contact info
|
|
|
|
* and platform string for <b>router</b>,
|
|
|
|
* surrounded by quotes and using standard C escapes.
|
|
|
|
*
|
|
|
|
* THIS FUNCTION IS NOT REENTRANT. Don't call it from outside the main
|
|
|
|
* thread. Also, each call invalidates the last-returned value, so don't
|
|
|
|
* try log_warn(LD_GENERAL, "%s %s", esc_router_info(a), esc_router_info(b));
|
|
|
|
*/
|
2006-03-11 03:21:30 +01:00
|
|
|
const char *
|
|
|
|
esc_router_info(routerinfo_t *router)
|
|
|
|
{
|
|
|
|
static char *info;
|
|
|
|
char *esc_contact, *esc_platform;
|
|
|
|
size_t len;
|
|
|
|
if (info)
|
|
|
|
tor_free(info);
|
|
|
|
|
|
|
|
esc_contact = esc_for_log(router->contact_info);
|
|
|
|
esc_platform = esc_for_log(router->platform);
|
|
|
|
|
|
|
|
len = strlen(esc_contact)+strlen(esc_platform)+32;
|
|
|
|
info = tor_malloc(len);
|
|
|
|
tor_snprintf(info, len, "Contact %s, Platform %s", esc_contact,
|
|
|
|
esc_platform);
|
|
|
|
tor_free(esc_contact);
|
|
|
|
tor_free(esc_platform);
|
|
|
|
|
|
|
|
return info;
|
|
|
|
}
|
|
|
|
|