2004-11-07 02:33:06 +01:00
|
|
|
/* Copyright 2001 Matej Pfajfar.
|
|
|
|
* Copyright 2001-2004 Roger Dingledine.
|
2005-04-01 22:15:56 +02:00
|
|
|
* Copyright 2004-2005 Roger Dingledine, Nick Mathewson. */
|
Implemented link padding and receiver token buckets
Each socket reads at most 'bandwidth' bytes per second sustained, but
can handle bursts of up to 10*bandwidth bytes.
Cells are now sent out at evenly-spaced intervals, with padding sent
out otherwise. Set Linkpadding=0 in the rc file to send cells as soon
as they're available (and to never send padding cells).
Added license/copyrights statements at the top of most files.
router->min and router->max have been merged into a single 'bandwidth'
value. We should make the routerinfo_t reflect this (want to do that,
Mat?)
As the bandwidth increases, and we want to stop sleeping more and more
frequently to send a single cell, cpu usage goes up. At 128kB/s we're
pretty much calling poll with a timeout of 1ms or even 0ms. The current
code takes a timeout of 0-9ms and makes it 10ms. prepare_for_poll()
handles everything that should have happened in the past, so as long as
our buffers don't get too full in that 10ms, we're ok.
Speaking of too full, if you run three servers at 100kB/s with -l debug,
it spends too much time printing debugging messages to be able to keep
up with the cells. The outbuf ultimately fills up and it kills that
connection. If you run with -l err, it works fine up through 500kB/s and
probably beyond. Down the road we'll want to teach it to recognize when
an outbuf is getting full, and back off.
svn:r50
2002-07-16 03:12:15 +02:00
|
|
|
/* See LICENSE for licensing information */
|
|
|
|
/* $Id$ */
|
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,
|
|
|
|
int for_v2_directory);
|
|
|
|
static routerstatus_t *router_pick_trusteddirserver_impl(
|
|
|
|
int need_v1_authority, int requireother, int fascistfirewall);
|
2004-10-12 17:55:20 +02:00
|
|
|
static void mark_all_trusteddirservers_up(void);
|
2005-06-21 01:04:13 +02:00
|
|
|
static int router_nickname_is_in_list(routerinfo_t *router, const char *list);
|
|
|
|
static int router_nickname_matches(routerinfo_t *router, const char *nickname);
|
2005-09-18 04:24:42 +02:00
|
|
|
static void routerstatus_list_update_from_networkstatus(time_t now);
|
2005-09-30 23:04:52 +02:00
|
|
|
static void local_routerstatus_free(local_routerstatus_t *rs);
|
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);
|
2003-12-09 05:29:52 +01:00
|
|
|
|
2005-11-23 08:06:36 +01:00
|
|
|
#define MAX_DESCRIPTORS_PER_ROUTER 5
|
|
|
|
|
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
|
|
|
|
2005-10-05 04:20:46 +02:00
|
|
|
/** Global list of local_routerstatus_t for each router, known or unknown. */
|
2005-09-18 04:24:42 +02:00
|
|
|
static smartlist_t *routerstatus_list = NULL;
|
2005-11-01 04:48:51 +01:00
|
|
|
|
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;
|
|
|
|
|
2005-10-11 03:57:28 +02:00
|
|
|
/* DOCDOC */
|
2005-10-05 04:20:46 +02:00
|
|
|
static int have_warned_about_unverified_status = 0;
|
|
|
|
static int have_warned_about_old_version = 0;
|
|
|
|
static int have_warned_about_new_version = 0;
|
|
|
|
|
2005-09-13 17:32:03 +02:00
|
|
|
/** Repopulate our list of network_status_t objects from the list cached on
|
|
|
|
* disk. Return 0 on success, -1 on failure. */
|
2005-09-05 01:12:27 +02:00
|
|
|
int
|
|
|
|
router_reload_networkstatus(void)
|
|
|
|
{
|
|
|
|
char filename[512];
|
|
|
|
struct stat st;
|
2005-09-30 23:38:45 +02:00
|
|
|
smartlist_t *entries;
|
2005-09-05 01:12:27 +02:00
|
|
|
char *s;
|
|
|
|
tor_assert(get_options()->DataDirectory);
|
|
|
|
if (!networkstatus_list)
|
|
|
|
networkstatus_list = smartlist_create();
|
|
|
|
|
|
|
|
tor_snprintf(filename,sizeof(filename),"%s/cached-status",
|
|
|
|
get_options()->DataDirectory);
|
|
|
|
entries = tor_listdir(filename);
|
|
|
|
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))) {
|
2005-10-24 21:39:45 +02:00
|
|
|
info(LD_DIR,
|
2005-12-10 10:36:26 +01:00
|
|
|
"Skipping cached-status file with unexpected name \"%s\"",fn);
|
2005-09-07 18:42:53 +02:00
|
|
|
continue;
|
|
|
|
}
|
2005-09-05 01:12:27 +02:00
|
|
|
tor_snprintf(filename,sizeof(filename),"%s/cached-status/%s",
|
|
|
|
get_options()->DataDirectory, fn);
|
|
|
|
s = read_file_to_str(filename, 0);
|
|
|
|
if (s) {
|
|
|
|
stat(filename, &st);
|
2005-09-08 22:36:40 +02:00
|
|
|
if (router_set_networkstatus(s, st.st_mtime, NS_FROM_CACHE, NULL)<0) {
|
2005-10-24 21:39:45 +02:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2005-09-13 23:14:55 +02:00
|
|
|
/** Add the <b>len</b>-type router descriptor in <b>s</b> to the router
|
|
|
|
* journal. */
|
2005-09-15 07:41:30 +02:00
|
|
|
static int
|
2005-09-13 23:14:55 +02:00
|
|
|
router_append_to_journal(const char *s, size_t len)
|
2005-09-13 08:21:10 +02:00
|
|
|
{
|
|
|
|
or_options_t *options = get_options();
|
|
|
|
size_t fname_len = strlen(options->DataDirectory)+32;
|
|
|
|
char *fname = tor_malloc(len);
|
|
|
|
|
2005-09-13 23:14:55 +02:00
|
|
|
tor_snprintf(fname, fname_len, "%s/cached-routers.new",
|
2005-09-13 08:21:10 +02:00
|
|
|
options->DataDirectory);
|
|
|
|
|
|
|
|
if (!len)
|
|
|
|
len = strlen(s);
|
|
|
|
|
|
|
|
if (append_bytes_to_file(fname, s, len, 0)) {
|
2005-10-24 21:39:45 +02:00
|
|
|
warn(LD_FS, "Unable to store router descriptor");
|
2005-09-13 08:21:10 +02:00
|
|
|
tor_free(fname);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
tor_free(fname);
|
2005-09-13 23:18:00 +02:00
|
|
|
router_journal_len += len;
|
2005-09-13 08:21:10 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-09-13 23:14:55 +02:00
|
|
|
/** If the journal is too long, or if <b>force</b> is true, then atomically
|
|
|
|
* replace the router store with the routers currently in our routerlist, and
|
|
|
|
* clear the journal. Return 0 on success, -1 on failure.
|
|
|
|
*/
|
2005-09-15 07:41:30 +02:00
|
|
|
static int
|
2005-09-13 08:21:10 +02:00
|
|
|
router_rebuild_store(int force)
|
|
|
|
{
|
|
|
|
size_t len = 0;
|
|
|
|
or_options_t *options;
|
|
|
|
size_t fname_len;
|
|
|
|
smartlist_t *chunk_list = NULL;
|
|
|
|
char *fname = NULL;
|
2005-10-27 02:34:39 +02:00
|
|
|
int r = -1, i;
|
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
|
|
|
|
2005-09-13 08:21:10 +02:00
|
|
|
options = get_options();
|
|
|
|
fname_len = strlen(options->DataDirectory)+32;
|
|
|
|
fname = tor_malloc(fname_len);
|
|
|
|
tor_snprintf(fname, fname_len, "%s/cached-routers", options->DataDirectory);
|
|
|
|
chunk_list = smartlist_create();
|
|
|
|
|
2005-10-27 02:34:39 +02:00
|
|
|
for (i = 0; i < 2; ++i) {
|
2005-12-14 21:40:40 +01:00
|
|
|
smartlist_t *lst = (i == 0) ? routerlist->old_routers :
|
|
|
|
routerlist->routers;
|
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;
|
2005-11-05 21:15:27 +01:00
|
|
|
if (!sd->signed_descriptor) {
|
|
|
|
warn(LD_BUG, "Bug! No descriptor stored for router.");
|
2005-10-27 02:34:39 +02:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
c = tor_malloc(sizeof(sized_chunk_t));
|
2005-11-05 21:15:27 +01:00
|
|
|
c->bytes = sd->signed_descriptor;
|
|
|
|
c->len = sd->signed_descriptor_len;
|
2005-10-27 02:34:39 +02:00
|
|
|
smartlist_add(chunk_list, c);
|
|
|
|
});
|
|
|
|
}
|
2005-09-13 08:21:10 +02:00
|
|
|
if (write_chunks_to_file(fname, chunk_list, 0)<0) {
|
2005-10-24 21:39:45 +02:00
|
|
|
warn(LD_FS, "Error writing router store to disk.");
|
2005-09-13 08:21:10 +02:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2005-09-13 23:14:55 +02:00
|
|
|
tor_snprintf(fname, fname_len, "%s/cached-routers.new",
|
2005-09-13 08:21:10 +02:00
|
|
|
options->DataDirectory);
|
|
|
|
|
|
|
|
write_str_to_file(fname, "", 0);
|
|
|
|
|
|
|
|
r = 0;
|
|
|
|
router_store_len = len;
|
2005-09-13 23:18:00 +02:00
|
|
|
router_journal_len = 0;
|
2005-11-23 08:24:59 +01:00
|
|
|
router_bytes_dropped = 0;
|
2005-09-13 08:21:10 +02:00
|
|
|
done:
|
|
|
|
tor_free(fname);
|
|
|
|
if (chunk_list) {
|
|
|
|
SMARTLIST_FOREACH(chunk_list, sized_chunk_t *, c, tor_free(c));
|
|
|
|
smartlist_free(chunk_list);
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2005-09-15 08:15:31 +02:00
|
|
|
/* Load all cached router descriptors from the store. Return 0 on success and
|
|
|
|
* -1 on failure.
|
|
|
|
*/
|
2005-09-15 07:19:38 +02:00
|
|
|
int
|
|
|
|
router_reload_router_list(void)
|
|
|
|
{
|
|
|
|
or_options_t *options = get_options();
|
|
|
|
size_t fname_len = strlen(options->DataDirectory)+32;
|
|
|
|
char *fname = tor_malloc(fname_len);
|
|
|
|
struct stat st;
|
|
|
|
int j;
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
for (j = 0; j < 2; ++j) {
|
|
|
|
char *contents;
|
|
|
|
tor_snprintf(fname, fname_len,
|
|
|
|
(j==0)?"%s/cached-routers":"%s/cached-routers.new",
|
|
|
|
options->DataDirectory);
|
|
|
|
contents = read_file_to_str(fname, 0);
|
|
|
|
if (contents) {
|
|
|
|
stat(fname, &st);
|
|
|
|
if (j==0)
|
|
|
|
router_store_len = st.st_size;
|
|
|
|
else
|
|
|
|
router_journal_len = st.st_size;
|
|
|
|
router_load_routers_from_string(contents, 1, NULL);
|
|
|
|
tor_free(contents);
|
|
|
|
}
|
|
|
|
}
|
2005-09-30 23:11:22 +02:00
|
|
|
tor_free(fname);
|
2005-09-15 07:19:38 +02:00
|
|
|
|
|
|
|
/* Don't cache expired routers. */
|
2005-11-01 18:34:17 +01:00
|
|
|
routerlist_remove_old_routers();
|
2005-09-15 07:19:38 +02:00
|
|
|
|
|
|
|
if (router_journal_len) {
|
|
|
|
/* Always clear the journal on startup.*/
|
|
|
|
router_rebuild_store(1);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-09-13 23:14:55 +02:00
|
|
|
/** Set *<b>outp</b> to a smartlist containing a list of
|
2004-10-15 21:04:38 +02:00
|
|
|
* trusted_dir_server_t * for all known trusted dirservers. Callers
|
|
|
|
* must not modify the list or its contents.
|
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
router_get_trusted_dir_servers(smartlist_t **outp)
|
2004-10-15 21:04:38 +02:00
|
|
|
{
|
|
|
|
if (!trusted_dir_servers)
|
|
|
|
trusted_dir_servers = smartlist_create();
|
|
|
|
|
|
|
|
*outp = trusted_dir_servers;
|
|
|
|
}
|
|
|
|
|
2004-07-20 08:44:16 +02:00
|
|
|
/** Try to find a running dirserver. If there are no running dirservers
|
2005-06-21 01:04:13 +02:00
|
|
|
* in our routerlist and <b>retry_if_no_servers</b> is non-zero,
|
|
|
|
* set all the authoritative ones as running again, and pick one;
|
|
|
|
* if there are then no dirservers at all in our routerlist,
|
|
|
|
* reload the routerlist and try one last time. If for_runningrouters is
|
2004-11-29 22:01:34 +01:00
|
|
|
* true, then only pick a dirserver that can answer runningrouters queries
|
|
|
|
* (that is, a trusted dirserver, or one running 0.0.9rc5-cvs or later).
|
2005-06-21 01:04:13 +02:00
|
|
|
* Other args are as in router_pick_directory_server_impl().
|
2004-11-29 22:01:34 +01:00
|
|
|
*/
|
2005-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;
|
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,
|
2005-09-07 18:42:53 +02:00
|
|
|
for_v2_directory);
|
2005-01-03 21:51:24 +01:00
|
|
|
if (choice || !retry_if_no_servers)
|
2004-07-20 08:44:16 +02:00
|
|
|
return choice;
|
|
|
|
|
2005-12-14 21:40:40 +01:00
|
|
|
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,
|
2005-09-07 18:42:53 +02:00
|
|
|
for_v2_directory);
|
2004-11-28 10:05:49 +01:00
|
|
|
if (choice)
|
2004-07-20 08:44:16 +02:00
|
|
|
return choice;
|
|
|
|
|
2005-10-24 21:39:45 +02:00
|
|
|
info(LD_DIR,"Still no %s router entries. Reloading and trying again.",
|
2005-12-10 10:36:26 +01:00
|
|
|
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,
|
2005-09-07 18:42:53 +02:00
|
|
|
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 *
|
|
|
|
router_pick_trusteddirserver(int need_v1_authority,
|
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;
|
2004-10-12 17:55:20 +02:00
|
|
|
|
2005-12-14 23:00:58 +01:00
|
|
|
choice = router_pick_trusteddirserver_impl(need_v1_authority,
|
2005-09-07 18:42:53 +02:00
|
|
|
requireother, fascistfirewall);
|
2005-01-03 21:51:24 +01:00
|
|
|
if (choice || !retry_if_no_servers)
|
2004-10-12 17:55:20 +02:00
|
|
|
return choice;
|
|
|
|
|
2005-10-24 21:39:45 +02:00
|
|
|
info(LD_DIR,"No trusted dirservers are reachable. Trying them all again.");
|
2004-10-12 17:55:20 +02:00
|
|
|
mark_all_trusteddirservers_up();
|
2005-12-14 23:00:58 +01:00
|
|
|
return router_pick_trusteddirserver_impl(need_v1_authority,
|
2005-09-07 18:42:53 +02:00
|
|
|
requireother, fascistfirewall);
|
2004-10-12 17:55:20 +02:00
|
|
|
}
|
|
|
|
|
2005-06-21 01:04:13 +02:00
|
|
|
/** Pick a random running verified directory server/mirror from our
|
|
|
|
* routerlist.
|
2005-11-19 11:12:10 +01:00
|
|
|
* If <b>fascistfirewall</b>,
|
|
|
|
* make sure the router we pick is allowed by our firewall options.
|
2005-09-13 17:32:03 +02:00
|
|
|
* If <b>requireother</b>, it cannot be us. If <b>for_v2_directory</b>,
|
|
|
|
* choose a directory server new enough to support the v2 directory
|
|
|
|
* functionality.
|
2004-07-20 08:44:16 +02:00
|
|
|
*/
|
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,
|
2005-09-07 18:42:53 +02:00
|
|
|
int for_v2_directory)
|
2004-07-20 08:44:16 +02:00
|
|
|
{
|
2005-12-14 23:00:58 +01:00
|
|
|
routerstatus_t *result;
|
2003-12-13 02:43:21 +01:00
|
|
|
smartlist_t *sl;
|
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;
|
|
|
|
|
2004-05-04 20:17:45 +02:00
|
|
|
/* Find all the running dirservers we know about. */
|
2004-03-31 00:59:00 +02:00
|
|
|
sl = smartlist_create();
|
2005-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);
|
|
|
|
if (!status->is_running || !status->dir_port || !status->is_valid)
|
2004-07-20 08:44:16 +02:00
|
|
|
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;
|
2004-11-28 10:05:49 +01:00
|
|
|
if (fascistfirewall) {
|
2005-12-14 23:00:58 +01:00
|
|
|
if (!fascist_firewall_allows_address(status->addr, status->dir_port))
|
2004-08-16 22:47:00 +02:00
|
|
|
continue;
|
|
|
|
}
|
2005-09-07 18:42:53 +02:00
|
|
|
if (for_v2_directory &&
|
2005-12-14 23:00:58 +01:00
|
|
|
!(status->is_v2_dir ||
|
|
|
|
router_digest_is_trusted_dir(status->identity_digest)))
|
2004-11-29 22:01:34 +01:00
|
|
|
continue;
|
2005-12-14 23:00:58 +01:00
|
|
|
smartlist_add(sl, status);
|
2005-09-13 17:32:03 +02:00
|
|
|
});
|
2002-09-26 14:09:10 +02:00
|
|
|
|
2005-09-13 17:32:03 +02:00
|
|
|
result = smartlist_choose(sl);
|
2003-12-13 02:43:21 +01:00
|
|
|
smartlist_free(sl);
|
2005-09-13 17:32:03 +02:00
|
|
|
return result;
|
2004-07-20 08:44:16 +02:00
|
|
|
}
|
2003-11-10 09:06:55 +01:00
|
|
|
|
2005-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 *
|
|
|
|
router_pick_trusteddirserver_impl(int need_v1_authority,
|
2005-09-07 18:42:53 +02:00
|
|
|
int requireother, int fascistfirewall)
|
2004-10-12 17:55:20 +02:00
|
|
|
{
|
|
|
|
smartlist_t *sl;
|
|
|
|
routerinfo_t *me;
|
2005-12-14 23:00:58 +01:00
|
|
|
routerstatus_t *rs;
|
2004-10-12 17:55:20 +02:00
|
|
|
sl = smartlist_create();
|
|
|
|
me = router_get_my_routerinfo();
|
2004-07-20 08:44:16 +02:00
|
|
|
|
2004-10-14 04:29:03 +02:00
|
|
|
if (!trusted_dir_servers)
|
|
|
|
return NULL;
|
|
|
|
|
2004-10-12 17:55:20 +02:00
|
|
|
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, d,
|
|
|
|
{
|
|
|
|
if (!d->is_running) continue;
|
2005-12-14 23:00:58 +01:00
|
|
|
if (need_v1_authority && !d->is_v1_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;
|
2004-10-12 17:55:20 +02:00
|
|
|
if (fascistfirewall) {
|
2005-08-08 23:58:48 +02:00
|
|
|
if (!fascist_firewall_allows_address(d->addr, d->dir_port))
|
2004-10-12 17:55:20 +02:00
|
|
|
continue;
|
|
|
|
}
|
2005-12-14 23:00:58 +01:00
|
|
|
smartlist_add(sl, &d->fake_status);
|
2004-10-12 17:55:20 +02:00
|
|
|
});
|
2004-05-04 20:17:45 +02:00
|
|
|
|
2005-12-14 23:00:58 +01:00
|
|
|
rs = smartlist_choose(sl);
|
2004-10-12 17:55:20 +02:00
|
|
|
smartlist_free(sl);
|
2005-12-14 23:00:58 +01:00
|
|
|
return rs;
|
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;
|
2005-12-15 21:44:15 +01:00
|
|
|
rs = router_get_combined_status_by_digest(dir->digest);
|
|
|
|
if (rs)
|
|
|
|
rs->status.is_running = 1;
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** 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
|
|
|
}
|
|
|
|
|
2005-11-30 07:27:59 +01:00
|
|
|
#if 0
|
2005-05-17 19:01:36 +02:00
|
|
|
/** Return 0 if \\exists an authoritative dirserver that's currently
|
2004-07-12 22:39:40 +02:00
|
|
|
* thought to be running, else return 1.
|
|
|
|
*/
|
2005-11-30 07:27:59 +01:00
|
|
|
/* XXXX Nobody calls this function. Should it go away? */
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
|
|
|
all_trusted_directory_servers_down(void)
|
|
|
|
{
|
2004-10-12 17:55:20 +02:00
|
|
|
if (!trusted_dir_servers)
|
|
|
|
return 1;
|
|
|
|
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, dir,
|
|
|
|
if (dir->is_running) return 0);
|
2004-07-12 22:39:40 +02:00
|
|
|
return 1;
|
2002-09-26 14:09:10 +02:00
|
|
|
}
|
2005-11-30 07:27:59 +01:00
|
|
|
#endif
|
2002-09-26 14:09:10 +02:00
|
|
|
|
2004-10-15 03:58:11 +02:00
|
|
|
/** Add all the family of <b>router</b> to the smartlist <b>sl</b>.
|
2005-06-21 01:04:13 +02:00
|
|
|
* This is used to make sure we don't pick siblings in a single path.
|
2004-09-10 23:40:29 +02:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
routerlist_add_family(smartlist_t *sl, routerinfo_t *router)
|
|
|
|
{
|
2004-10-15 03:58:11 +02:00
|
|
|
routerinfo_t *r;
|
2005-07-22 23:12:10 +02:00
|
|
|
config_line_t *cl;
|
2004-09-10 23:40:29 +02:00
|
|
|
|
2004-10-15 03:58:11 +02:00
|
|
|
if (!router->declared_family)
|
|
|
|
return;
|
2004-10-15 22:52:09 +02:00
|
|
|
|
2004-10-15 05:55:53 +02:00
|
|
|
/* Add every r such that router declares familyness with r, and r
|
|
|
|
* declares familyhood with router. */
|
2004-10-15 03:58:11 +02:00
|
|
|
SMARTLIST_FOREACH(router->declared_family, const char *, n,
|
|
|
|
{
|
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)) {
|
2005-10-05 00:23:31 +02:00
|
|
|
add_nickname_list_to_smartlist(sl, cl->value, 1, 1);
|
2004-10-15 22:52:09 +02:00
|
|
|
}
|
|
|
|
}
|
2004-09-10 23:40:29 +02:00
|
|
|
}
|
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** Given a comma-and-whitespace separated list of nicknames, see which
|
2004-05-10 06:34:48 +02:00
|
|
|
* nicknames in <b>list</b> name routers in our routerlist that are
|
|
|
|
* currently running. Add the routerinfos for those routers to <b>sl</b>.
|
2004-05-04 20:17:45 +02:00
|
|
|
*/
|
2004-08-18 13:20:15 +02:00
|
|
|
void
|
2005-12-14 21:40:40 +01:00
|
|
|
add_nickname_list_to_smartlist(smartlist_t *sl, const char *list,
|
|
|
|
int warn_if_down, int warn_if_unnamed)
|
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)) {
|
2005-10-24 21:39:45 +02:00
|
|
|
warn(LD_CONFIG, "Nickname %s is misformed; skipping", nick);
|
2004-07-22 23:36:03 +02:00
|
|
|
continue;
|
|
|
|
}
|
2005-10-05 00:23:31 +02:00
|
|
|
router = router_get_by_nickname(nick, warn_if_unnamed);
|
2005-04-03 07:53:34 +02:00
|
|
|
warned = smartlist_string_isin(warned_nicknames, nick);
|
2004-04-03 00:23:15 +02:00
|
|
|
if (router) {
|
2005-04-03 07:53:34 +02:00
|
|
|
if (router->is_running) {
|
2004-04-03 00:23:15 +02:00
|
|
|
smartlist_add(sl,router);
|
2005-04-03 07:53:34 +02:00
|
|
|
if (warned)
|
|
|
|
smartlist_string_remove(warned_nicknames, nick);
|
|
|
|
} else {
|
|
|
|
if (!warned) {
|
2005-10-24 21:39:45 +02:00
|
|
|
log_fn(warn_if_down ? LOG_WARN : LOG_DEBUG, LD_CONFIG,
|
2005-04-03 07:53:34 +02:00
|
|
|
"Nickname list includes '%s' which is known but down.",nick);
|
|
|
|
smartlist_add(warned_nicknames, tor_strdup(nick));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2004-10-15 22:52:09 +02:00
|
|
|
/** Return 1 iff any member of the comma-separated list <b>list</b> is an
|
|
|
|
* acceptable nickname or hexdigest for <b>router</b>. Else return 0.
|
|
|
|
*/
|
2005-06-21 01:04:13 +02:00
|
|
|
static int
|
2004-10-15 22:52:09 +02:00
|
|
|
router_nickname_is_in_list(routerinfo_t *router, const char *list)
|
|
|
|
{
|
|
|
|
smartlist_t *nickname_list;
|
|
|
|
int v = 0;
|
|
|
|
|
2004-11-28 10:05:49 +01:00
|
|
|
if (!list)
|
2004-11-03 11:08:44 +01:00
|
|
|
return 0; /* definitely not */
|
2004-10-15 22:52:09 +02:00
|
|
|
tor_assert(router);
|
|
|
|
|
|
|
|
nickname_list = smartlist_create();
|
|
|
|
smartlist_split_string(nickname_list, list, ",",
|
|
|
|
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
|
2004-10-16 10:39:56 +02:00
|
|
|
SMARTLIST_FOREACH(nickname_list, const char *, cp,
|
2004-10-15 22:52:09 +02:00
|
|
|
if (router_nickname_matches(router, cp)) {v=1;break;});
|
2004-10-16 10:39:56 +02:00
|
|
|
SMARTLIST_FOREACH(nickname_list, char *, cp, tor_free(cp));
|
|
|
|
smartlist_free(nickname_list);
|
2004-10-15 22:52:09 +02:00
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Add every router from our routerlist that is currently running to
|
|
|
|
* <b>sl</b>.
|
2004-05-04 20:17:45 +02:00
|
|
|
*/
|
2004-08-17 08:27:32 +02:00
|
|
|
static void
|
2004-08-20 23:34:36 +02:00
|
|
|
router_add_running_routers_to_smartlist(smartlist_t *sl, int allow_unverified,
|
2005-01-12 05:58:23 +01:00
|
|
|
int need_uptime, int need_capacity)
|
2004-08-17 08:27:32 +02:00
|
|
|
{
|
2004-11-28 10:05:49 +01:00
|
|
|
if (!routerlist)
|
2003-12-13 08:01:46 +01:00
|
|
|
return;
|
2003-12-03 11:28:51 +01:00
|
|
|
|
2005-09-13 17:32:03 +02:00
|
|
|
SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router,
|
|
|
|
{
|
2004-11-28 10:05:49 +01:00
|
|
|
if (router->is_running &&
|
2004-11-28 12:39:53 +01:00
|
|
|
(router->is_verified ||
|
|
|
|
(allow_unverified &&
|
2005-01-12 05:58:23 +01:00
|
|
|
!router_is_unreliable(router, need_uptime, need_capacity)))) {
|
2004-08-20 23:34:36 +02:00
|
|
|
/* If it's running, and either it's verified or we're ok picking
|
|
|
|
* unverified routers and this one is suitable.
|
|
|
|
*/
|
2004-08-18 11:07:11 +02:00
|
|
|
smartlist_add(sl, router);
|
2004-08-08 12:32:36 +02:00
|
|
|
}
|
2005-09-13 17:32:03 +02:00
|
|
|
});
|
2003-12-03 11:28:51 +01:00
|
|
|
}
|
|
|
|
|
2005-06-21 01:04:13 +02:00
|
|
|
/** Look through the routerlist until we find a router that has my key.
|
|
|
|
Return it. */
|
2004-08-18 12:32:50 +02:00
|
|
|
routerinfo_t *
|
2005-06-11 20:52:12 +02:00
|
|
|
routerlist_find_my_routerinfo(void)
|
|
|
|
{
|
2004-11-28 10:05:49 +01:00
|
|
|
if (!routerlist)
|
2004-08-18 12:32:50 +02:00
|
|
|
return NULL;
|
|
|
|
|
2005-09-13 17:32:03 +02:00
|
|
|
SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router,
|
|
|
|
{
|
2004-11-28 10:05:49 +01:00
|
|
|
if (router_is_me(router))
|
2004-08-18 12:32:50 +02:00
|
|
|
return router;
|
2005-09-13 17:32:03 +02:00
|
|
|
});
|
2004-08-18 12:32:50 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2005-08-15 05:25:40 +02:00
|
|
|
/** Find a router that's up, that has this IP address, and
|
|
|
|
* that allows exit to this address:port, or return NULL if there
|
|
|
|
* isn't a good one.
|
|
|
|
*/
|
|
|
|
routerinfo_t *
|
2005-09-13 17:32:03 +02:00
|
|
|
router_find_exact_exit_enclave(const char *address, uint16_t port)
|
|
|
|
{
|
2005-08-15 05:25:40 +02:00
|
|
|
uint32_t addr;
|
|
|
|
struct in_addr in;
|
|
|
|
|
|
|
|
if (!tor_inet_aton(address, &in))
|
|
|
|
return NULL; /* it's not an IP already */
|
|
|
|
addr = ntohl(in.s_addr);
|
|
|
|
|
2005-09-13 17:32:03 +02:00
|
|
|
SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router,
|
|
|
|
{
|
2005-08-15 05:25:40 +02:00
|
|
|
if (router->is_running &&
|
|
|
|
router->addr == addr &&
|
|
|
|
router_compare_addr_to_addr_policy(addr, port, router->exit_policy) ==
|
|
|
|
ADDR_POLICY_ACCEPTED)
|
|
|
|
return router;
|
2005-09-13 17:32:03 +02:00
|
|
|
});
|
2005-08-15 05:25:40 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2005-06-21 01:04:13 +02:00
|
|
|
/** Return 1 if <b>router</b> is not suitable for these parameters, else 0.
|
|
|
|
* If <b>need_uptime</b> is non-zero, we require a minimum uptime.
|
|
|
|
* If <b>need_capacity</b> is non-zero, we require a minimum advertised
|
|
|
|
* bandwidth.
|
|
|
|
*/
|
2004-08-20 23:34:36 +02:00
|
|
|
int
|
2005-01-12 05:58:23 +01:00
|
|
|
router_is_unreliable(routerinfo_t *router, int need_uptime, int need_capacity)
|
2004-08-20 23:34:36 +02:00
|
|
|
{
|
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;
|
|
|
|
return 0;
|
|
|
|
}
|
2004-08-15 10:15:12 +02:00
|
|
|
|
2005-06-21 01:04:13 +02:00
|
|
|
/** Remove from routerlist <b>sl</b> all routers who have a low uptime. */
|
2004-08-15 10:15:12 +02:00
|
|
|
static void
|
|
|
|
routerlist_sl_remove_unreliable_routers(smartlist_t *sl)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
routerinfo_t *router;
|
|
|
|
|
|
|
|
for (i = 0; i < smartlist_len(sl); ++i) {
|
|
|
|
router = smartlist_get(sl, i);
|
2005-01-12 05:58:23 +01:00
|
|
|
if (router_is_unreliable(router, 1, 0)) {
|
2005-08-12 02:34:50 +02:00
|
|
|
// log(LOG_DEBUG, "Router '%s' has insufficient uptime; deleting.",
|
|
|
|
// router->nickname);
|
2004-08-15 10:15:12 +02:00
|
|
|
smartlist_del(sl, i--);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-06-21 01:04:13 +02:00
|
|
|
#define MAX_BELIEVABLE_BANDWIDTH 2000000 /* 2 MB/sec */
|
|
|
|
|
|
|
|
/** Choose a random element of router list <b>sl</b>, weighted by
|
|
|
|
* the advertised bandwidth of each router.
|
|
|
|
*/
|
2004-08-18 08:10:12 +02:00
|
|
|
routerinfo_t *
|
2004-08-15 10:15:12 +02:00
|
|
|
routerlist_sl_choose_by_bandwidth(smartlist_t *sl)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
routerinfo_t *router;
|
|
|
|
smartlist_t *bandwidths;
|
|
|
|
uint32_t this_bw, tmp, total_bw=0, rand_bw;
|
|
|
|
uint32_t *p;
|
|
|
|
|
2005-06-21 01:04:13 +02:00
|
|
|
/* First count the total bandwidth weight, and make a smartlist
|
|
|
|
* of each value. */
|
2004-08-15 10:15:12 +02:00
|
|
|
bandwidths = smartlist_create();
|
|
|
|
for (i = 0; i < smartlist_len(sl); ++i) {
|
|
|
|
router = smartlist_get(sl, i);
|
2004-10-17 23:51:20 +02:00
|
|
|
this_bw = (router->bandwidthcapacity < router->bandwidthrate) ?
|
|
|
|
router->bandwidthcapacity : router->bandwidthrate;
|
2005-06-21 01:04:13 +02:00
|
|
|
/* if they claim something huge, don't believe it */
|
|
|
|
if (this_bw > MAX_BELIEVABLE_BANDWIDTH)
|
|
|
|
this_bw = MAX_BELIEVABLE_BANDWIDTH;
|
2004-08-15 10:15:12 +02:00
|
|
|
p = tor_malloc(sizeof(uint32_t));
|
|
|
|
*p = this_bw;
|
|
|
|
smartlist_add(bandwidths, p);
|
|
|
|
total_bw += this_bw;
|
|
|
|
}
|
2004-12-07 09:51:10 +01:00
|
|
|
if (!total_bw) {
|
|
|
|
SMARTLIST_FOREACH(bandwidths, uint32_t*, p, tor_free(p));
|
|
|
|
smartlist_free(bandwidths);
|
2004-11-20 13:41:05 +01:00
|
|
|
return smartlist_choose(sl);
|
2004-12-07 09:51:10 +01:00
|
|
|
}
|
2005-06-21 01:04:13 +02:00
|
|
|
/* Second, choose a random value from the bandwidth weights. */
|
2005-10-07 00:18:01 +02:00
|
|
|
rand_bw = crypto_rand_int(total_bw);
|
2005-06-21 01:04:13 +02:00
|
|
|
/* Last, count through sl until we get to the element we picked */
|
2004-08-15 10:15:12 +02:00
|
|
|
tmp = 0;
|
2004-11-28 10:05:49 +01:00
|
|
|
for (i=0; ; i++) {
|
2004-08-15 10:15:12 +02:00
|
|
|
tor_assert(i < smartlist_len(sl));
|
|
|
|
p = smartlist_get(bandwidths, i);
|
|
|
|
tmp += *p;
|
2004-11-28 10:05:49 +01:00
|
|
|
if (tmp >= rand_bw)
|
2004-08-15 10:15:12 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
SMARTLIST_FOREACH(bandwidths, uint32_t*, p, tor_free(p));
|
|
|
|
smartlist_free(bandwidths);
|
2005-06-21 01:04:13 +02:00
|
|
|
return (routerinfo_t *)smartlist_get(sl, i);
|
2004-08-15 10:15:12 +02:00
|
|
|
}
|
|
|
|
|
2004-05-20 21:12:28 +02:00
|
|
|
/** Return a random running router from the routerlist. If any node
|
2004-08-15 22:14:44 +02:00
|
|
|
* named in <b>preferred</b> is available, pick one of those. Never
|
|
|
|
* pick a node named in <b>excluded</b>, or whose routerinfo is in
|
|
|
|
* <b>excludedsmartlist</b>, even if they are the only nodes
|
|
|
|
* available. If <b>strict</b> is true, never pick any node besides
|
|
|
|
* those in <b>preferred</b>.
|
2005-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.
|
2004-04-03 00:30:39 +02:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
routerinfo_t *
|
|
|
|
router_choose_random_node(const char *preferred,
|
|
|
|
const char *excluded,
|
|
|
|
smartlist_t *excludedsmartlist,
|
|
|
|
int need_uptime, int need_capacity,
|
|
|
|
int allow_unverified, int strict)
|
2004-04-03 00:23:15 +02:00
|
|
|
{
|
|
|
|
smartlist_t *sl, *excludednodes;
|
|
|
|
routerinfo_t *choice;
|
|
|
|
|
|
|
|
excludednodes = smartlist_create();
|
2005-10-05 00:23:31 +02:00
|
|
|
add_nickname_list_to_smartlist(excludednodes,excluded,0,1);
|
2004-04-03 00:23:15 +02:00
|
|
|
|
2005-04-06 08:17:35 +02:00
|
|
|
/* Try the preferred nodes first. Ignore need_uptime and need_capacity,
|
|
|
|
* since the user explicitly asked for these nodes. */
|
2004-04-03 00:23:15 +02:00
|
|
|
sl = smartlist_create();
|
2005-10-05 00:23:31 +02:00
|
|
|
add_nickname_list_to_smartlist(sl,preferred,1,1);
|
2004-04-03 00:23:15 +02:00
|
|
|
smartlist_subtract(sl,excludednodes);
|
2004-11-28 10:05:49 +01:00
|
|
|
if (excludedsmartlist)
|
2004-04-03 00:30:39 +02:00
|
|
|
smartlist_subtract(sl,excludedsmartlist);
|
2005-04-06 08:17:35 +02:00
|
|
|
choice = smartlist_choose(sl);
|
2004-04-03 00:23:15 +02:00
|
|
|
smartlist_free(sl);
|
2004-11-28 10:05:49 +01:00
|
|
|
if (!choice && !strict) {
|
2005-04-06 08:17:35 +02:00
|
|
|
/* Then give up on our preferred choices: any node
|
|
|
|
* will do that has the required attributes. */
|
2004-04-03 00:23:15 +02:00
|
|
|
sl = smartlist_create();
|
2004-08-20 23:34:36 +02:00
|
|
|
router_add_running_routers_to_smartlist(sl, allow_unverified,
|
2005-01-12 05:58:23 +01:00
|
|
|
need_uptime, need_capacity);
|
2004-04-03 00:23:15 +02:00
|
|
|
smartlist_subtract(sl,excludednodes);
|
2004-11-28 10:05:49 +01:00
|
|
|
if (excludedsmartlist)
|
2004-04-03 00:30:39 +02:00
|
|
|
smartlist_subtract(sl,excludedsmartlist);
|
2005-01-12 05:58:23 +01:00
|
|
|
if (need_uptime)
|
2004-08-15 10:15:12 +02:00
|
|
|
routerlist_sl_remove_unreliable_routers(sl);
|
2005-01-12 05:58:23 +01:00
|
|
|
if (need_capacity)
|
2004-08-15 10:15:12 +02:00
|
|
|
choice = routerlist_sl_choose_by_bandwidth(sl);
|
2004-08-18 09:53:43 +02:00
|
|
|
else
|
|
|
|
choice = smartlist_choose(sl);
|
2004-04-03 00:23:15 +02:00
|
|
|
smartlist_free(sl);
|
2005-12-15 10:53:00 +01:00
|
|
|
if (!choice && (need_uptime || need_capacity)) {
|
|
|
|
/* try once more -- recurse but with fewer restrictions. */
|
|
|
|
info(LD_CIRC, "We couldn't find any live%s%s routers; falling back "
|
|
|
|
"to list of all routers.",
|
|
|
|
need_capacity?", fast":"",
|
|
|
|
need_uptime?", stable":"");
|
|
|
|
choice = router_choose_random_node(
|
|
|
|
NULL, excluded, excludedsmartlist, 0, 0, allow_unverified, 0);
|
|
|
|
}
|
2004-04-03 00:23:15 +02:00
|
|
|
}
|
|
|
|
smartlist_free(excludednodes);
|
2004-11-28 10:05:49 +01:00
|
|
|
if (!choice)
|
2005-10-24 21:39:45 +02:00
|
|
|
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];
|
|
|
|
tor_assert(hexdigest);
|
|
|
|
if (hexdigest[0] == '$')
|
|
|
|
++hexdigest;
|
|
|
|
|
2005-11-05 21:15:27 +01:00
|
|
|
/* XXXXNM Any place that uses this inside a loop could probably do better. */
|
2004-07-17 00:23:18 +02:00
|
|
|
if (strlen(hexdigest) != HEX_DIGEST_LEN ||
|
|
|
|
base16_decode(digest, DIGEST_LEN, hexdigest, HEX_DIGEST_LEN)<0)
|
2004-07-03 01:40:03 +02:00
|
|
|
return 0;
|
2005-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;
|
2003-09-25 07:17:11 +02:00
|
|
|
|
2004-05-12 21:49:48 +02:00
|
|
|
tor_assert(nickname);
|
2004-06-02 22:00:57 +02:00
|
|
|
if (!routerlist)
|
|
|
|
return NULL;
|
2004-07-03 01:40:03 +02:00
|
|
|
if (nickname[0] == '$')
|
|
|
|
return router_get_by_hexdigest(nickname);
|
2005-02-27 08:23:42 +01:00
|
|
|
if (server_mode(get_options()) &&
|
|
|
|
!strcasecmp(nickname, get_options()->Nickname))
|
|
|
|
return router_get_my_routerinfo();
|
2004-07-03 01:40:03 +02:00
|
|
|
|
2004-07-01 03:16:59 +02:00
|
|
|
maybedigest = (strlen(nickname) == HEX_DIGEST_LEN) &&
|
|
|
|
(base16_decode(digest,DIGEST_LEN,nickname,HEX_DIGEST_LEN) == 0);
|
|
|
|
|
2005-09-13 17:32:03 +02:00
|
|
|
SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router,
|
|
|
|
{
|
2005-10-05 00:23:31 +02:00
|
|
|
if (!strcasecmp(router->nickname, nickname)) {
|
|
|
|
if (router->is_named)
|
|
|
|
return router;
|
|
|
|
else {
|
|
|
|
++n_matches;
|
|
|
|
best_match = router;
|
|
|
|
}
|
|
|
|
} else if (maybedigest &&
|
2005-12-14 21:40:40 +01:00
|
|
|
!memcmp(digest, router->cache_info.identity_digest, DIGEST_LEN)
|
|
|
|
) {
|
2004-07-01 03:16:59 +02:00
|
|
|
return router;
|
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);
|
2005-10-05 00:23:31 +02:00
|
|
|
if (!rs->name_lookup_warned) {
|
|
|
|
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);
|
2005-10-24 21:39:45 +02:00
|
|
|
warn(LD_CONFIG, "There are multiple matches for the nickname \"%s\","
|
2005-12-10 10:36:26 +01:00
|
|
|
" but none is listed as named by the directory authories. "
|
|
|
|
"Choosing one arbitrarily. If you meant one in particular, "
|
|
|
|
"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);
|
2005-10-24 21:39:45 +02:00
|
|
|
warn(LD_CONFIG, "You specified a server \"%s\" by name, but the "
|
2005-12-10 10:36:26 +01:00
|
|
|
"directory authorities do not have a listing for this name. "
|
|
|
|
"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;
|
2004-10-12 17:55:20 +02:00
|
|
|
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ent,
|
|
|
|
if (!memcmp(digest, ent->digest, DIGEST_LEN)) return 1);
|
2004-07-20 22:09:59 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-07-01 03:16:59 +02:00
|
|
|
/** Return the router in our routerlist whose hexadecimal key digest
|
|
|
|
* is <b>hexdigest</b>. Return NULL if no such router is known. */
|
2005-06-11 20:52:12 +02:00
|
|
|
routerinfo_t *
|
|
|
|
router_get_by_hexdigest(const char *hexdigest)
|
|
|
|
{
|
2004-07-01 03:16:59 +02:00
|
|
|
char digest[DIGEST_LEN];
|
|
|
|
|
|
|
|
tor_assert(hexdigest);
|
|
|
|
if (!routerlist)
|
|
|
|
return NULL;
|
2004-07-03 01:40:03 +02:00
|
|
|
if (hexdigest[0]=='$')
|
|
|
|
++hexdigest;
|
2004-07-01 03:16:59 +02:00
|
|
|
if (strlen(hexdigest) != HEX_DIGEST_LEN ||
|
|
|
|
base16_decode(digest,DIGEST_LEN,hexdigest,HEX_DIGEST_LEN) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return router_get_by_digest(digest);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Return the router in our routerlist whose 20-byte key digest
|
2005-03-22 01:42:38 +01:00
|
|
|
* is <b>digest</b>. Return NULL if no such router is known. */
|
2005-06-11 20:52:12 +02:00
|
|
|
routerinfo_t *
|
|
|
|
router_get_by_digest(const char *digest)
|
|
|
|
{
|
2004-07-01 03:16:59 +02:00
|
|
|
tor_assert(digest);
|
2005-06-21 01:04:13 +02:00
|
|
|
|
2005-02-27 10:47:01 +01:00
|
|
|
if (!routerlist) return NULL;
|
2003-09-25 07:17:11 +02:00
|
|
|
|
2005-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
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
2005-11-05 21:15:27 +01:00
|
|
|
tor_free(router->cache_info.signed_descriptor);
|
2003-10-21 11:48:17 +02:00
|
|
|
tor_free(router->address);
|
|
|
|
tor_free(router->nickname);
|
2004-04-07 23:36:03 +02:00
|
|
|
tor_free(router->platform);
|
2005-05-06 10:53:23 +02:00
|
|
|
tor_free(router->contact_info);
|
2003-09-25 07:17:11 +02:00
|
|
|
if (router->onion_pkey)
|
|
|
|
crypto_free_pk_env(router->onion_pkey);
|
|
|
|
if (router->identity_pkey)
|
|
|
|
crypto_free_pk_env(router->identity_pkey);
|
2004-10-15 03:58:11 +02:00
|
|
|
if (router->declared_family) {
|
|
|
|
SMARTLIST_FOREACH(router->declared_family, char *, s, tor_free(s));
|
|
|
|
smartlist_free(router->declared_family);
|
|
|
|
}
|
2004-11-12 20:39:13 +01:00
|
|
|
addr_policy_free(router->exit_policy);
|
2004-09-29 08:52:36 +02:00
|
|
|
tor_free(router);
|
2002-09-24 12:43:57 +02:00
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
tor_free(sd->signed_descriptor);
|
|
|
|
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));
|
|
|
|
ri->cache_info.signed_descriptor = NULL;
|
|
|
|
routerinfo_free(ri);
|
|
|
|
return sd;
|
|
|
|
}
|
|
|
|
|
2005-11-30 07:27:59 +01:00
|
|
|
#if 0
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Allocate a fresh copy of <b>router</b> */
|
2005-11-30 07:27:59 +01:00
|
|
|
/* XXX Nobody uses this. Remove it? */
|
2005-06-11 20:52:12 +02:00
|
|
|
routerinfo_t *
|
|
|
|
routerinfo_copy(const routerinfo_t *router)
|
2004-04-08 00:18:57 +02:00
|
|
|
{
|
|
|
|
routerinfo_t *r;
|
2004-12-04 02:14:36 +01:00
|
|
|
addr_policy_t **e, *tmp;
|
2004-04-08 00:18:57 +02:00
|
|
|
|
|
|
|
r = tor_malloc(sizeof(routerinfo_t));
|
|
|
|
memcpy(r, router, sizeof(routerinfo_t));
|
|
|
|
|
|
|
|
r->address = tor_strdup(r->address);
|
|
|
|
r->nickname = tor_strdup(r->nickname);
|
|
|
|
r->platform = tor_strdup(r->platform);
|
2005-11-05 21:15:27 +01:00
|
|
|
if (r->cache_info.signed_descriptor)
|
2005-12-14 21:40:40 +01:00
|
|
|
r->cache_info.signed_descriptor =
|
|
|
|
tor_strdup(r->cache_info.signed_descriptor);
|
2004-04-08 00:18:57 +02:00
|
|
|
if (r->onion_pkey)
|
|
|
|
r->onion_pkey = crypto_pk_dup_key(r->onion_pkey);
|
|
|
|
if (r->identity_pkey)
|
|
|
|
r->identity_pkey = crypto_pk_dup_key(r->identity_pkey);
|
|
|
|
e = &r->exit_policy;
|
|
|
|
while (*e) {
|
2004-12-04 02:14:36 +01:00
|
|
|
tmp = tor_malloc(sizeof(addr_policy_t));
|
|
|
|
memcpy(tmp,*e,sizeof(addr_policy_t));
|
2004-04-08 00:18:57 +02:00
|
|
|
*e = tmp;
|
|
|
|
(*e)->string = tor_strdup((*e)->string);
|
|
|
|
e = & ((*e)->next);
|
|
|
|
}
|
2004-10-15 03:58:11 +02:00
|
|
|
if (r->declared_family) {
|
|
|
|
r->declared_family = smartlist_create();
|
|
|
|
SMARTLIST_FOREACH(router->declared_family, const char *, s,
|
|
|
|
smartlist_add(r->declared_family, tor_strdup(s)));
|
|
|
|
}
|
2004-04-08 00:18:57 +02:00
|
|
|
return r;
|
|
|
|
}
|
2005-11-30 07:27:59 +01:00
|
|
|
#endif
|
2004-04-08 00:18:57 +02:00
|
|
|
|
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);
|
2004-04-07 21:46:27 +02:00
|
|
|
tor_free(rl);
|
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));
|
|
|
|
}
|
|
|
|
|
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) >
|
|
|
|
smartlist_len(rl->routers)*(MAX_DESCRIPTORS_PER_ROUTER+1);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
* as needed. */
|
|
|
|
static void
|
|
|
|
routerlist_insert(routerlist_t *rl, routerinfo_t *ri)
|
|
|
|
{
|
2005-11-05 21:15:27 +01:00
|
|
|
digestmap_set(rl->identity_map, ri->cache_info.identity_digest, ri);
|
|
|
|
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);
|
2005-10-18 22:13:09 +02:00
|
|
|
// routerlist_assert_ok(rl);
|
2005-10-18 19:43:54 +02:00
|
|
|
}
|
|
|
|
|
2005-10-27 02:34:39 +02:00
|
|
|
static void
|
|
|
|
routerlist_insert_old(routerlist_t *rl, routerinfo_t *ri)
|
|
|
|
{
|
|
|
|
if (get_options()->DirPort) {
|
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
|
|
|
}
|
|
|
|
|
2005-10-18 19:43:54 +02:00
|
|
|
/** Remove an item <b>ri</b> into the routerlist <b>rl</b>, updating indices
|
|
|
|
* 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
|
|
|
|
* the list, if any exists. <b>ri</b> is freed. */
|
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;
|
2005-10-18 19:43:54 +02:00
|
|
|
smartlist_del(rl->routers, idx);
|
2005-11-05 21:15:27 +01:00
|
|
|
ri_tmp = digestmap_remove(rl->identity_map, ri->cache_info.identity_digest);
|
2005-10-18 22:13:09 +02:00
|
|
|
tor_assert(ri_tmp == ri);
|
2005-10-27 02:34:39 +02:00
|
|
|
if (make_old && get_options()->DirPort) {
|
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
|
2005-11-01 04:48:51 +01:00
|
|
|
* index as ri_old, if possible. ri is freed as appropriate. */
|
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
|
|
|
{
|
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);
|
2005-10-19 05:02:28 +02:00
|
|
|
if (idx >= 0) {
|
|
|
|
smartlist_set(rl->routers, idx, ri_new);
|
|
|
|
} else {
|
2005-10-28 01:06:09 +02:00
|
|
|
warn(LD_BUG, "Appending entry from routerlist_replace.");
|
|
|
|
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
|
|
|
}
|
2005-11-05 21:15:27 +01:00
|
|
|
digestmap_set(rl->identity_map, ri_new->cache_info.identity_digest, ri_new);
|
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
|
|
|
|
|
|
|
if (make_old && get_options()->DirPort) {
|
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;
|
|
|
|
}
|
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);
|
|
|
|
|
|
|
|
have_warned_about_unverified_status = 0;
|
|
|
|
have_warned_about_old_version = 0;
|
|
|
|
have_warned_about_new_version = 0;
|
|
|
|
}
|
|
|
|
|
2004-07-12 20:19:55 +02:00
|
|
|
/** Mark the router with ID <b>digest</b> as non-running in our routerlist. */
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
router_mark_as_down(const char *digest)
|
|
|
|
{
|
2004-05-12 21:49:48 +02:00
|
|
|
routerinfo_t *router;
|
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))
|
|
|
|
d->is_running = 0);
|
|
|
|
|
2004-07-03 01:40:03 +02:00
|
|
|
router = router_get_by_digest(digest);
|
2005-12-14 23:05:10 +01:00
|
|
|
if (router) {
|
|
|
|
debug(LD_DIR,"Marking router '%s' as down.",router->nickname);
|
|
|
|
if (router_is_me(router) && !we_are_hibernating())
|
|
|
|
warn(LD_NET, "We just marked ourself as down. Are your external "
|
|
|
|
"addresses reachable?");
|
|
|
|
router->is_running = 0;
|
|
|
|
}
|
|
|
|
status = router_get_combined_status_by_digest(digest);
|
|
|
|
if (status) {
|
|
|
|
status->status.is_running = 0;
|
|
|
|
}
|
2002-09-26 15:17:14 +02:00
|
|
|
}
|
|
|
|
|
2004-05-17 22:31:01 +02:00
|
|
|
/** Add <b>router</b> to the routerlist, if we don't already have it. Replace
|
2005-09-15 08:15:31 +02:00
|
|
|
* older entries (if any) with the same key. Note: Callers should not hold
|
2005-05-14 07:01:41 +02:00
|
|
|
* their pointers to <b>router</b> if this function fails; <b>router</b>
|
2005-08-31 08:14:37 +02:00
|
|
|
* will either be inserted into the routerlist or freed.
|
2005-04-03 00:02:13 +02:00
|
|
|
*
|
2005-08-31 08:14:37 +02:00
|
|
|
* Returns >= 0 if the router was added; less than 0 if it was not.
|
|
|
|
*
|
|
|
|
* If we're returning non-zero, then assign to *<b>msg</b> a static string
|
|
|
|
* describing the reason for not liking the routerinfo.
|
2005-08-26 23:46:24 +02:00
|
|
|
*
|
|
|
|
* If the return value is less than -1, there was a problem with the
|
2005-08-31 08:14:37 +02:00
|
|
|
* routerinfo. If the return value is equal to -1, then the routerinfo was
|
|
|
|
* fine, but out-of-date. If the return value is equal to 1, the
|
|
|
|
* routerinfo was accepted, but we should notify the generator of the
|
|
|
|
* descriptor using the message *<b>msg</b>.
|
2005-09-15 02:51:42 +02:00
|
|
|
*
|
2005-09-15 08:15:31 +02:00
|
|
|
* This function should be called *after*
|
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.
|
2005-09-15 07:19:38 +02:00
|
|
|
*
|
|
|
|
* XXXX never replace your own descriptor.
|
2004-05-17 22:31:01 +02:00
|
|
|
*/
|
2005-08-26 22:59:04 +02:00
|
|
|
int
|
2005-09-15 07:19:38 +02:00
|
|
|
router_add_to_routerlist(routerinfo_t *router, const char **msg,
|
|
|
|
int from_cache)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2004-05-17 22:31:01 +02:00
|
|
|
int i;
|
2004-08-07 05:38:07 +02:00
|
|
|
char id_digest[DIGEST_LEN];
|
2005-08-26 22:59:04 +02:00
|
|
|
int authdir = get_options()->AuthoritativeDir;
|
|
|
|
int authdir_verified = 0;
|
2004-08-07 05:38:07 +02:00
|
|
|
|
2005-08-27 01:12:13 +02:00
|
|
|
tor_assert(msg);
|
|
|
|
|
2005-10-18 22:13:09 +02:00
|
|
|
if (!routerlist)
|
|
|
|
router_get_routerlist();
|
2005-08-26 23:12:34 +02:00
|
|
|
|
2005-10-27 02:34:39 +02:00
|
|
|
/* XXXX NM If this assert doesn't trigger, we should remove the id_digest
|
|
|
|
* local. */
|
2004-08-07 05:38:07 +02:00
|
|
|
crypto_pk_get_digest(router->identity_pkey, id_digest);
|
2005-12-14 21:40:40 +01:00
|
|
|
tor_assert(!memcmp(id_digest, router->cache_info.identity_digest,
|
|
|
|
DIGEST_LEN));
|
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)) {
|
2005-10-27 02:34:39 +02:00
|
|
|
info(LD_DIR, "Dropping descriptor that we already have for router '%s'",
|
|
|
|
router->nickname);
|
|
|
|
*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) {
|
2005-10-28 20:44:51 +02:00
|
|
|
if (authdir_wants_to_reject_router(router, msg)) {
|
|
|
|
routerinfo_free(router);
|
2005-08-26 23:46:24 +02:00
|
|
|
return -2;
|
2005-10-28 20:44:51 +02:00
|
|
|
}
|
2005-09-15 02:51:42 +02:00
|
|
|
authdir_verified = router->is_verified;
|
2005-12-27 06:26:03 +01:00
|
|
|
} else if (!from_cache) {
|
|
|
|
/* Only check the descriptor digest against the network statuses when
|
|
|
|
* we are recieving from somewhere other than the cache.*/
|
|
|
|
if (!signed_desc_digest_is_recognized(&router->cache_info)) {
|
|
|
|
warn(LD_DIR, "Dropping unrecognized descriptor for router '%s'",
|
2005-10-12 15:49:13 +02:00
|
|
|
router->nickname);
|
2005-11-01 04:48:51 +01:00
|
|
|
routerinfo_free(router);
|
2005-10-12 15:49:13 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2005-08-26 22:59:04 +02:00
|
|
|
}
|
|
|
|
|
2004-05-17 22:31:01 +02:00
|
|
|
/* If we have a router with this name, and the identity key is the same,
|
|
|
|
* choose the newer one. If the identity key has changed, drop the router.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < smartlist_len(routerlist->routers); ++i) {
|
2005-08-26 22:59:04 +02:00
|
|
|
routerinfo_t *old_router = smartlist_get(routerlist->routers, i);
|
|
|
|
if (!crypto_pk_cmp_keys(router->identity_pkey,old_router->identity_pkey)) {
|
2005-11-05 21:15:27 +01:00
|
|
|
if (router->cache_info.published_on <=
|
|
|
|
old_router->cache_info.published_on) {
|
2005-09-15 02:51:42 +02:00
|
|
|
/* Same key, but old */
|
2005-10-24 21:39:45 +02:00
|
|
|
debug(LD_DIR, "Skipping not-new descriptor for router '%s'",
|
2005-12-10 10:36:26 +01:00
|
|
|
router->nickname);
|
2005-10-27 02:34:39 +02:00
|
|
|
routerlist_insert_old(routerlist, router);
|
2005-08-31 08:14:37 +02:00
|
|
|
*msg = "Router descriptor was not new.";
|
2004-05-17 22:31:01 +02:00
|
|
|
return -1;
|
2005-08-26 22:59:04 +02:00
|
|
|
} else {
|
2005-09-15 02:51:42 +02:00
|
|
|
/* Same key, new. */
|
2005-09-01 10:13:40 +02:00
|
|
|
int unreachable = 0;
|
2005-10-24 21:39:45 +02:00
|
|
|
debug(LD_DIR, "Replacing entry for router '%s/%s' [%s]",
|
2005-12-10 10:36:26 +01:00
|
|
|
router->nickname, old_router->nickname,
|
|
|
|
hex_str(id_digest,DIGEST_LEN));
|
2005-08-26 22:59:04 +02:00
|
|
|
if (router->addr == old_router->addr &&
|
|
|
|
router->or_port == old_router->or_port) {
|
|
|
|
/* these carry over when the address and orport are unchanged.*/
|
|
|
|
router->last_reachable = old_router->last_reachable;
|
|
|
|
router->testing_since = old_router->testing_since;
|
2005-09-01 10:13:40 +02:00
|
|
|
router->num_unreachable_notifications =
|
|
|
|
old_router->num_unreachable_notifications;
|
2005-08-26 22:59:04 +02:00
|
|
|
}
|
2005-09-01 10:13:40 +02:00
|
|
|
if (authdir &&
|
2005-12-14 21:40:40 +01:00
|
|
|
dirserv_thinks_router_is_blatantly_unreachable(router,
|
|
|
|
time(NULL))) {
|
2005-09-01 10:13:40 +02:00
|
|
|
if (router->num_unreachable_notifications >= 3) {
|
|
|
|
unreachable = 1;
|
2005-12-14 21:40:40 +01:00
|
|
|
notice(LD_DIR, "Notifying server '%s' that it's unreachable. "
|
|
|
|
"(ContactInfo '%s', platform '%s').",
|
|
|
|
router->nickname,
|
|
|
|
router->contact_info ? router->contact_info : "",
|
2005-12-10 10:36:26 +01:00
|
|
|
router->platform ? router->platform : "");
|
2005-09-01 10:13:40 +02:00
|
|
|
} else {
|
2005-12-09 06:37:26 +01:00
|
|
|
info(LD_DIR,"'%s' may be unreachable -- the %d previous "
|
|
|
|
"descriptors were thought to be unreachable.",
|
|
|
|
router->nickname, router->num_unreachable_notifications);
|
2005-09-01 10:13:40 +02:00
|
|
|
router->num_unreachable_notifications++;
|
|
|
|
}
|
2005-08-31 08:18:19 +02:00
|
|
|
}
|
2005-10-27 02:34:39 +02:00
|
|
|
routerlist_replace(routerlist, old_router, router, i, 1);
|
2005-09-15 07:19:38 +02:00
|
|
|
if (!from_cache)
|
2005-11-05 21:15:27 +01:00
|
|
|
router_append_to_journal(router->cache_info.signed_descriptor,
|
|
|
|
router->cache_info.signed_descriptor_len);
|
2005-08-26 22:59:04 +02:00
|
|
|
directory_set_dirty();
|
2005-08-31 08:14:37 +02:00
|
|
|
*msg = unreachable ? "Dirserver believes your ORPort is unreachable" :
|
|
|
|
authdir_verified ? "Verified server updated" :
|
2005-12-14 21:40:40 +01:00
|
|
|
("Unverified server updated. (Have you sent us your key "
|
|
|
|
"fingerprint?)");
|
2005-08-31 08:14:37 +02:00
|
|
|
return unreachable ? 1 : 0;
|
2004-05-17 22:31:01 +02:00
|
|
|
}
|
2005-08-26 22:59:04 +02:00
|
|
|
} else if (!strcasecmp(router->nickname, old_router->nickname)) {
|
2004-08-17 08:06:05 +02:00
|
|
|
/* nicknames match, keys don't. */
|
2005-09-15 02:51:42 +02:00
|
|
|
if (router->is_named) {
|
2004-08-17 08:06:05 +02:00
|
|
|
/* The new verified router replaces the old one; remove the
|
2004-08-17 10:00:23 +02:00
|
|
|
* old one. And carry on to the end of the list, in case
|
2004-12-01 04:48:14 +01:00
|
|
|
* there are more old unverified routers with this nickname
|
2004-08-17 08:06:05 +02:00
|
|
|
*/
|
2004-08-17 10:00:23 +02:00
|
|
|
/* mark-for-close connections using the old key, so we can
|
|
|
|
* make new ones with the new key.
|
|
|
|
*/
|
|
|
|
connection_t *conn;
|
2005-11-30 04:01:16 +01:00
|
|
|
while ((conn = connection_or_get_by_identity_digest(
|
2005-11-19 07:57:44 +01:00
|
|
|
old_router->cache_info.identity_digest))) {
|
2005-10-24 21:39:45 +02:00
|
|
|
// And LD_OR? XXXXNM
|
2005-12-14 21:40:40 +01:00
|
|
|
info(LD_DIR,"Closing conn to router '%s'; there is now a named "
|
|
|
|
"router with that name.",
|
2005-12-10 10:36:26 +01:00
|
|
|
old_router->nickname);
|
2004-08-17 10:00:23 +02:00
|
|
|
connection_mark_for_close(conn);
|
|
|
|
}
|
2005-10-27 02:34:39 +02:00
|
|
|
routerlist_remove(routerlist, old_router, i--, 0);
|
2005-09-15 02:51:42 +02:00
|
|
|
} else if (old_router->is_named) {
|
2004-08-17 08:06:05 +02:00
|
|
|
/* Can't replace a verified router with an unverified one. */
|
2005-10-24 21:39:45 +02:00
|
|
|
debug(LD_DIR, "Skipping unverified entry for verified router '%s'",
|
2005-12-10 10:36:26 +01:00
|
|
|
router->nickname);
|
2004-08-17 08:06:05 +02:00
|
|
|
routerinfo_free(router);
|
2005-12-14 21:40:40 +01:00
|
|
|
*msg =
|
|
|
|
"Already have named router with same nickname and different key.";
|
2005-08-26 23:46:24 +02:00
|
|
|
return -2;
|
2004-08-17 08:06:05 +02:00
|
|
|
}
|
2004-05-17 22:31:01 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* We haven't seen a router with this name before. Add it to the end of
|
|
|
|
* the list. */
|
2005-10-18 19:43:54 +02:00
|
|
|
routerlist_insert(routerlist, router);
|
2005-09-15 07:19:38 +02:00
|
|
|
if (!from_cache)
|
2005-11-05 21:15:27 +01:00
|
|
|
router_append_to_journal(router->cache_info.signed_descriptor,
|
|
|
|
router->cache_info.signed_descriptor_len);
|
2005-08-26 22:59:04 +02:00
|
|
|
directory_set_dirty();
|
2004-05-17 22:31:01 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct duration_idx_t {
|
|
|
|
int duration;
|
|
|
|
int idx;
|
|
|
|
int old;
|
|
|
|
};
|
|
|
|
|
|
|
|
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
|
|
|
|
* than MAX_DESCRIPTORS_PER_ROUTER remaining. Start by removing the oldest
|
|
|
|
* 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. */
|
|
|
|
n_extra = n - MAX_DESCRIPTORS_PER_ROUTER;
|
|
|
|
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
|
|
|
|
* ROUTER_MAX_AGE seconds old; 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;
|
|
|
|
time_t cutoff;
|
2005-11-01 18:34:17 +01:00
|
|
|
routerinfo_t *router;
|
2005-12-27 06:26:03 +01:00
|
|
|
digestmap_t *retain;
|
|
|
|
or_options_t *options = get_options();
|
|
|
|
if (!routerlist || !networkstatus_list)
|
2005-10-27 02:34:39 +02:00
|
|
|
return;
|
|
|
|
|
2005-12-27 06:26:03 +01:00
|
|
|
retain = digestmap_new();
|
|
|
|
if (server_mode(options) && options->DirPort) {
|
|
|
|
SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
|
|
|
|
{
|
|
|
|
SMARTLIST_FOREACH(ns->entries, routerstatus_t *, rs,
|
|
|
|
digestmap_set(retain, rs->descriptor_digest, (void*)1));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2005-11-01 18:34:17 +01:00
|
|
|
cutoff = time(NULL) - ROUTER_MAX_AGE;
|
|
|
|
/* Remove old members of routerlist->routers. */
|
|
|
|
for (i = 0; i < smartlist_len(routerlist->routers); ++i) {
|
|
|
|
router = smartlist_get(routerlist->routers, i);
|
2005-12-27 06:26:03 +01:00
|
|
|
if (router->cache_info.published_on <= cutoff &&
|
|
|
|
!digestmap_get(retain, router->cache_info.signed_descriptor_digest)) {
|
2005-11-01 18:34:17 +01:00
|
|
|
/* Too old. Remove it. */
|
|
|
|
info(LD_DIR, "Forgetting obsolete (too old) routerinfo for router '%s'",
|
|
|
|
router->nickname);
|
|
|
|
routerlist_remove(routerlist, router, i--, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now we're looking at routerlist->old_routers. 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 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) <
|
|
|
|
smartlist_len(routerlist->routers) * (MAX_DESCRIPTORS_PER_ROUTER - 1))
|
|
|
|
return;
|
|
|
|
|
|
|
|
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);
|
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
|
2005-04-03 00:02:13 +02:00
|
|
|
router_load_single_router(const char *s, const char **msg)
|
2005-02-25 21:46:13 +01:00
|
|
|
{
|
|
|
|
routerinfo_t *ri;
|
2005-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
|
|
|
|
|
|
|
if (!(ri = router_parse_entry_from_string(s, NULL))) {
|
2005-10-24 21:39:45 +02:00
|
|
|
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;
|
|
|
|
}
|
2005-05-14 07:01:41 +02:00
|
|
|
if (router_is_me(ri)) {
|
2005-10-24 21:39:45 +02:00
|
|
|
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
|
|
|
|
2005-09-15 07:19:38 +02:00
|
|
|
if (router_add_to_routerlist(ri, msg, 0)<0) {
|
2005-10-24 21:39:45 +02:00
|
|
|
warn(LD_DIR, "Couldn't add router to list: %s Dropping.",
|
2005-12-10 10:36:26 +01:00
|
|
|
*msg?*msg:"(No message).");
|
2005-06-21 01:04:13 +02:00
|
|
|
/* we've already assigned to *msg now, and ri is already freed */
|
2005-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);
|
2005-10-24 21:39:45 +02:00
|
|
|
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
|
|
|
|
* routers into our directory. If <b>from_cache</b> is false, the routers
|
|
|
|
* have come from the network: cache them.
|
|
|
|
*
|
|
|
|
* If <b>requested_fingerprints</b> is provided, it must contain a list of
|
|
|
|
* uppercased identity fingerprints. Do not update any router whose
|
|
|
|
* fingerprint is not on the list; after updating a router, remove its
|
|
|
|
* fingerprint from the list.
|
|
|
|
*/
|
2005-09-15 07:19:38 +02:00
|
|
|
void
|
|
|
|
router_load_routers_from_string(const char *s, int from_cache,
|
|
|
|
smartlist_t *requested_fingerprints)
|
|
|
|
{
|
|
|
|
smartlist_t *routers = smartlist_create(), *changed = smartlist_create();
|
|
|
|
char fp[HEX_DIGEST_LEN+1];
|
|
|
|
const char *msg;
|
|
|
|
|
|
|
|
router_parse_list_from_string(&s, routers);
|
|
|
|
|
2005-12-27 06:26:03 +01:00
|
|
|
routers_update_status_from_networkstatus(routers, !from_cache);
|
|
|
|
|
|
|
|
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);
|
2005-12-10 09:27:01 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (router_add_to_routerlist(ri, &msg, from_cache) >= 0)
|
|
|
|
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
|
|
|
|
* where we plan to cache <b>ns</b>. */
|
2005-09-12 08:56:42 +02:00
|
|
|
static char *
|
|
|
|
networkstatus_get_cache_filename(const networkstatus_t *ns)
|
|
|
|
{
|
|
|
|
const char *datadir = get_options()->DataDirectory;
|
|
|
|
size_t len = strlen(datadir)+64;
|
|
|
|
char fp[HEX_DIGEST_LEN+1];
|
|
|
|
char *fn = tor_malloc(len+1);
|
|
|
|
base16_encode(fp, HEX_DIGEST_LEN+1, ns->identity_digest, DIGEST_LEN);
|
|
|
|
tor_snprintf(fn, len, "%s/cached-status/%s",datadir,fp);
|
|
|
|
return fn;
|
|
|
|
}
|
2005-09-13 17:32:03 +02:00
|
|
|
|
|
|
|
/** Helper for smartlist_sort: Compare two networkstatus objects by
|
|
|
|
* publication date. */
|
2005-09-12 08:56:42 +02:00
|
|
|
static int
|
|
|
|
_compare_networkstatus_published_on(const void **_a, const void **_b)
|
|
|
|
{
|
|
|
|
const networkstatus_t *a = *_a, *b = *_b;
|
|
|
|
if (a->published_on < b->published_on)
|
|
|
|
return -1;
|
|
|
|
else if (a->published_on > b->published_on)
|
|
|
|
return 1;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-09-13 17:32:03 +02:00
|
|
|
/** How far in the future do we allow a network-status to get before removing
|
|
|
|
* it? (seconds) */
|
2005-09-08 23:01:24 +02:00
|
|
|
#define NETWORKSTATUS_ALLOW_SKEW (48*60*60)
|
2005-09-13 17:32:03 +02:00
|
|
|
/** Given a string <b>s</b> containing a network status that we received at
|
|
|
|
* <b>arrived_at</b> from <b>source</b>, try to parse it, see if we want to
|
|
|
|
* store it, and put it into our cache is necessary.
|
|
|
|
*
|
|
|
|
* If <b>source</b> is NS_FROM_DIR or NS_FROM_CACHE, do not replace our
|
|
|
|
* own networkstatus_t (if we're a directory server).
|
|
|
|
*
|
|
|
|
* If <b>source</b> is NS_FROM_CACHE, do not write our networkstatus_t to the
|
|
|
|
* cache.
|
|
|
|
*
|
|
|
|
* If <b>requested_fingerprints</b> is provided, it must contain a list of
|
|
|
|
* uppercased identity fingerprints. Do not update any networkstatus whose
|
|
|
|
* fingerprint is not on the list; after updating a networkstatus, remove its
|
|
|
|
* fingerprint from the list.
|
|
|
|
*
|
2005-09-18 04:24:42 +02:00
|
|
|
* Return 0 on success, -1 on failure.
|
|
|
|
*
|
|
|
|
* Callers should make sure that routers_update_all_from_networkstatus() is
|
|
|
|
* invoked after this function succeeds.
|
2005-09-07 18:42:53 +02:00
|
|
|
*/
|
|
|
|
int
|
2005-09-08 22:36:40 +02:00
|
|
|
router_set_networkstatus(const char *s, time_t arrived_at,
|
|
|
|
networkstatus_source_t source, smartlist_t *requested_fingerprints)
|
2005-09-07 18:42:53 +02:00
|
|
|
{
|
|
|
|
networkstatus_t *ns;
|
|
|
|
int i, found;
|
|
|
|
time_t now;
|
2005-09-08 23:01:24 +02:00
|
|
|
int skewed = 0;
|
2005-09-12 08:56:42 +02:00
|
|
|
trusted_dir_server_t *trusted_dir;
|
|
|
|
char fp[HEX_DIGEST_LEN+1];
|
2005-09-15 01:42:06 +02:00
|
|
|
char published[ISO_TIME_LEN+1];
|
2005-09-07 18:42:53 +02:00
|
|
|
|
|
|
|
ns = networkstatus_parse_from_string(s);
|
|
|
|
if (!ns) {
|
2005-10-24 21:39:45 +02:00
|
|
|
warn(LD_DIR, "Couldn't parse network status.");
|
2005-09-07 18:42:53 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2005-12-14 21:40:40 +01:00
|
|
|
if (!(trusted_dir =
|
|
|
|
router_get_trusteddirserver_by_digest(ns->identity_digest))) {
|
|
|
|
info(LD_DIR, "Network status was signed, but not by an authoritative "
|
|
|
|
"directory we recognize.");
|
2005-09-08 22:36:40 +02:00
|
|
|
networkstatus_free(ns);
|
2005-09-07 18:42:53 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
now = time(NULL);
|
|
|
|
if (arrived_at > now)
|
|
|
|
arrived_at = now;
|
|
|
|
|
|
|
|
ns->received_on = arrived_at;
|
|
|
|
|
2005-09-15 01:42:06 +02:00
|
|
|
format_iso_time(published, ns->published_on);
|
|
|
|
|
2005-09-08 23:01:24 +02:00
|
|
|
if (ns->published_on > now + NETWORKSTATUS_ALLOW_SKEW) {
|
2005-12-09 06:37:26 +01:00
|
|
|
warn(LD_GENERAL, "Network status from %s was published in the future "
|
|
|
|
"(%s GMT). Somebody is skewed here: check your clock. Not caching.",
|
|
|
|
trusted_dir->description, published);
|
2005-09-08 23:01:24 +02:00
|
|
|
skewed = 1;
|
|
|
|
}
|
2005-09-07 18:42:53 +02:00
|
|
|
|
|
|
|
if (!networkstatus_list)
|
|
|
|
networkstatus_list = smartlist_create();
|
|
|
|
|
2005-09-08 22:36:40 +02:00
|
|
|
if (source == NS_FROM_DIR && router_digest_is_me(ns->identity_digest)) {
|
2005-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;
|
|
|
|
}
|
|
|
|
|
|
|
|
base16_encode(fp, HEX_DIGEST_LEN+1, ns->identity_digest, DIGEST_LEN);
|
|
|
|
|
2005-09-12 08:56:42 +02:00
|
|
|
if (requested_fingerprints) {
|
|
|
|
if (smartlist_string_isin(requested_fingerprints, fp)) {
|
|
|
|
smartlist_string_remove(requested_fingerprints, fp);
|
|
|
|
} else {
|
2005-12-14 21:40:40 +01:00
|
|
|
char *requested =
|
|
|
|
smartlist_join_strings(requested_fingerprints," ",0,NULL);
|
2005-12-10 10:36:26 +01:00
|
|
|
warn(LD_DIR,
|
|
|
|
"We received a network status with a fingerprint (%s) that we "
|
|
|
|
"never requested. (We asked for: %s.) Dropping.", fp, requested);
|
2005-09-12 08:56:42 +02:00
|
|
|
tor_free(requested);
|
|
|
|
return 0;
|
|
|
|
}
|
2005-09-08 22:36:40 +02:00
|
|
|
}
|
|
|
|
|
2005-09-12 08:56:42 +02:00
|
|
|
if (source != NS_FROM_CACHE)
|
|
|
|
trusted_dir->n_networkstatus_failures = 0;
|
|
|
|
|
2005-09-07 18:42:53 +02:00
|
|
|
found = 0;
|
|
|
|
for (i=0; i < smartlist_len(networkstatus_list); ++i) {
|
|
|
|
networkstatus_t *old_ns = smartlist_get(networkstatus_list, i);
|
|
|
|
|
|
|
|
if (!memcmp(old_ns->identity_digest, ns->identity_digest, DIGEST_LEN)) {
|
|
|
|
if (!memcmp(old_ns->networkstatus_digest,
|
|
|
|
ns->networkstatus_digest, DIGEST_LEN)) {
|
2005-09-08 08:22:44 +02:00
|
|
|
/* Same one we had before. */
|
2005-09-07 18:42:53 +02:00
|
|
|
networkstatus_free(ns);
|
2005-10-24 21:39:45 +02:00
|
|
|
info(LD_DIR,
|
2005-12-10 10:36:26 +01:00
|
|
|
"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) {
|
|
|
|
char *fn = networkstatus_get_cache_filename(old_ns);
|
|
|
|
/* We use mtime to tell when it arrived, so update that. */
|
|
|
|
touch_file(fn);
|
|
|
|
tor_free(fn);
|
|
|
|
}
|
2005-09-08 08:22:44 +02:00
|
|
|
old_ns->received_on = arrived_at;
|
2005-09-15 01:42:06 +02:00
|
|
|
}
|
2005-09-07 18:42:53 +02:00
|
|
|
return 0;
|
|
|
|
} else if (old_ns->published_on >= ns->published_on) {
|
2005-09-15 01:42:06 +02:00
|
|
|
char old_published[ISO_TIME_LEN+1];
|
|
|
|
format_iso_time(old_published, old_ns->published_on);
|
2005-10-24 21:39:45 +02:00
|
|
|
info(LD_DIR,
|
2005-12-10 10:36:26 +01:00
|
|
|
"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,
|
|
|
|
{
|
|
|
|
if (!router_get_by_descriptor_digest(rs->descriptor_digest))
|
|
|
|
rs->need_to_mirror = 1;
|
|
|
|
});
|
|
|
|
|
2005-10-24 21:39:45 +02:00
|
|
|
info(LD_DIR, "Setting networkstatus %s %s (published %s)",
|
2005-12-10 10:36:26 +01:00
|
|
|
source == NS_FROM_CACHE?"cached from":
|
|
|
|
(source==NS_FROM_DIR?"downloaded from":"generated for"),
|
|
|
|
trusted_dir->description, published);
|
2005-09-14 23:09:25 +02:00
|
|
|
networkstatus_list_has_changed = 1;
|
|
|
|
|
2005-09-12 08:56:42 +02:00
|
|
|
smartlist_sort(networkstatus_list, _compare_networkstatus_published_on);
|
|
|
|
|
2005-09-08 23:01:24 +02:00
|
|
|
if (source != NS_FROM_CACHE && !skewed) {
|
2005-09-12 08:56:42 +02:00
|
|
|
char *fn = networkstatus_get_cache_filename(ns);
|
2005-09-07 18:42:53 +02:00
|
|
|
if (write_str_to_file(fn, s, 0)<0) {
|
2005-10-24 21:39:45 +02:00
|
|
|
notice(LD_FS, "Couldn't write cached network status to \"%s\"", fn);
|
2005-09-07 18:42:53 +02:00
|
|
|
}
|
|
|
|
tor_free(fn);
|
|
|
|
}
|
|
|
|
|
2005-09-18 04:24:42 +02:00
|
|
|
networkstatus_list_update_recent(now);
|
|
|
|
|
2005-09-08 23:01:24 +02:00
|
|
|
if (get_options()->DirPort && !skewed)
|
2005-10-18 22:13:09 +02:00
|
|
|
dirserv_set_cached_networkstatus_v2(s,
|
|
|
|
ns->identity_digest,
|
|
|
|
ns->published_on);
|
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);
|
|
|
|
char *fname = NULL;;
|
|
|
|
if (ns->published_on + MAX_NETWORKSTATUS_AGE > now)
|
|
|
|
continue;
|
|
|
|
/* Okay, this one is too old. Remove it from the list, and delete it
|
|
|
|
* from the cache. */
|
|
|
|
smartlist_del(networkstatus_list, i--);
|
|
|
|
fname = networkstatus_get_cache_filename(ns);
|
|
|
|
if (file_status(fname) == FN_FILE) {
|
2005-10-24 21:39:45 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Helper for bsearching a list of routerstatus_t pointers.*/
|
|
|
|
static int
|
|
|
|
_compare_digest_to_routerstatus_entry(const void *_key, const void **_member)
|
|
|
|
{
|
|
|
|
const char *key = _key;
|
|
|
|
const routerstatus_t *rs = *_member;
|
|
|
|
return memcmp(key, rs->identity_digest, DIGEST_LEN);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Return the entry in <b>ns</b> for the identity digest <b>digest</b>, or
|
|
|
|
* NULL if none was found. */
|
2005-09-15 07:41:30 +02:00
|
|
|
static routerstatus_t *
|
2005-09-12 08:56:42 +02:00
|
|
|
networkstatus_find_entry(networkstatus_t *ns, const char *digest)
|
|
|
|
{
|
|
|
|
return smartlist_bsearch(ns->entries, digest,
|
|
|
|
_compare_digest_to_routerstatus_entry);
|
|
|
|
}
|
|
|
|
|
2005-09-30 22:04:55 +02:00
|
|
|
/** Return the consensus view of the status of the router whose digest is
|
|
|
|
* <b>digest</b>, or NULL if we don't know about any such router. */
|
2005-09-22 03:51:14 +02:00
|
|
|
local_routerstatus_t *
|
2005-09-18 04:24:42 +02:00
|
|
|
router_get_combined_status_by_digest(const char *digest)
|
|
|
|
{
|
|
|
|
if (!routerstatus_list)
|
|
|
|
return NULL;
|
|
|
|
return smartlist_bsearch(routerstatus_list, digest,
|
|
|
|
_compare_digest_to_routerstatus_entry);
|
|
|
|
}
|
|
|
|
|
2005-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;
|
|
|
|
}
|
|
|
|
|
2005-09-08 23:01:24 +02:00
|
|
|
/* XXXX These should be configurable, perhaps? NM */
|
2005-12-27 06:26:03 +01:00
|
|
|
#define AUTHORITY_NS_CACHE_INTERVAL 5*60
|
2005-09-08 22:18:15 +02:00
|
|
|
#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,
|
|
|
|
{
|
|
|
|
char resource[HEX_DIGEST_LEN+6];
|
|
|
|
if (router_digest_is_me(ds->digest))
|
|
|
|
continue;
|
2005-09-12 08:56:42 +02:00
|
|
|
if (connection_get_by_type_addr_port_purpose(
|
|
|
|
CONN_TYPE_DIR, ds->addr, ds->dir_port,
|
2005-09-13 17:32:03 +02:00
|
|
|
DIR_PURPOSE_FETCH_NETWORKSTATUS)) {
|
|
|
|
/* We are already fetching this one. */
|
2005-09-12 08:56:42 +02:00
|
|
|
continue;
|
2005-09-13 17:32:03 +02:00
|
|
|
}
|
2005-09-08 22:18:15 +02:00
|
|
|
strlcpy(resource, "fp/", sizeof(resource));
|
|
|
|
base16_encode(resource+3, sizeof(resource)-3, ds->digest, DIGEST_LEN);
|
|
|
|
strlcat(resource, ".z", sizeof(resource));
|
2005-12-14 21:40:40 +01:00
|
|
|
directory_get_from_dirserver(DIR_PURPOSE_FETCH_NETWORKSTATUS,
|
|
|
|
resource,1);
|
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
|
|
|
/*XXXX Should these be configurable? NM*/
|
2005-09-14 23:09:25 +02:00
|
|
|
/** How old (in seconds) can a network-status be before we try replacing it? */
|
2005-09-08 23:01:24 +02:00
|
|
|
#define NETWORKSTATUS_MAX_VALIDITY (48*60*60)
|
|
|
|
/** How long (in seconds) does a client wait after getting a network status
|
|
|
|
* before downloading the next in sequence? */
|
|
|
|
#define NETWORKSTATUS_CLIENT_DL_INTERVAL (30*60)
|
2005-09-14 23:09:25 +02:00
|
|
|
/* How many times do we allow a networkstatus download to fail before we
|
|
|
|
* assume that the authority isn't publishing? */
|
|
|
|
#define NETWORKSTATUS_N_ALLOWABLE_FAILURES 3
|
2005-09-13 17:32:03 +02:00
|
|
|
/** We are not a directory cache or authority. Update our network-status list
|
|
|
|
* by launching a new directory fetch for enough network-status documents "as
|
|
|
|
* necessary". See function comments for implementation details.
|
|
|
|
*/
|
2005-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
|
|
|
{
|
2005-09-14 23:09:25 +02:00
|
|
|
int n_live = 0, needed = 0, n_running_dirservers, n_dirservers, i;
|
2005-09-08 08:22:44 +02:00
|
|
|
int most_recent_idx = -1;
|
|
|
|
trusted_dir_server_t *most_recent = NULL;
|
|
|
|
time_t most_recent_received = 0;
|
2005-09-08 23:01:24 +02:00
|
|
|
char *resource, *cp;
|
|
|
|
size_t resource_len;
|
2005-09-08 08:22:44 +02:00
|
|
|
|
2005-09-12 08:56:42 +02:00
|
|
|
if (connection_get_by_type_purpose(CONN_TYPE_DIR,
|
|
|
|
DIR_PURPOSE_FETCH_NETWORKSTATUS))
|
|
|
|
return;
|
|
|
|
|
2005-09-08 08:22:44 +02:00
|
|
|
/* This is a little tricky. We want to download enough network-status
|
2005-09-12 08:56:42 +02:00
|
|
|
* objects so that we have at least half of them under
|
|
|
|
* NETWORKSTATUS_MAX_VALIDITY publication time. We want to download a new
|
|
|
|
* *one* if the most recent one's publication time is under
|
|
|
|
* NETWORKSTATUS_CLIENT_DL_INTERVAL.
|
2005-09-08 08:22:44 +02:00
|
|
|
*/
|
2005-09-08 18:18:28 +02:00
|
|
|
if (!trusted_dir_servers || !smartlist_len(trusted_dir_servers))
|
|
|
|
return;
|
2005-09-14 23:09:25 +02:00
|
|
|
n_dirservers = n_running_dirservers = smartlist_len(trusted_dir_servers);
|
2005-09-08 08:22:44 +02:00
|
|
|
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
|
|
|
|
{
|
|
|
|
networkstatus_t *ns = networkstatus_get_by_digest(ds->digest);
|
2005-09-08 18:18:28 +02:00
|
|
|
if (!ns)
|
|
|
|
continue;
|
2005-09-14 23:09:25 +02:00
|
|
|
if (ds->n_networkstatus_failures > NETWORKSTATUS_N_ALLOWABLE_FAILURES) {
|
|
|
|
--n_running_dirservers;
|
|
|
|
continue;
|
|
|
|
}
|
2005-09-08 23:01:24 +02:00
|
|
|
if (ns->published_on > now-NETWORKSTATUS_MAX_VALIDITY)
|
2005-09-08 08:22:44 +02:00
|
|
|
++n_live;
|
|
|
|
if (!most_recent || ns->received_on > most_recent_received) {
|
2005-09-13 17:32:03 +02:00
|
|
|
most_recent_idx = ds_sl_idx; /* magic variable from FOREACH */
|
2005-09-08 08:22:44 +02:00
|
|
|
most_recent = ds;
|
|
|
|
most_recent_received = ns->received_on;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
/* Download enough so we have at least half live, but no more than all the
|
|
|
|
* trusted dirservers we know.
|
|
|
|
*/
|
|
|
|
if (n_live < (n_dirservers/2)+1)
|
|
|
|
needed = (n_dirservers/2)+1-n_live;
|
2005-09-14 23:09:25 +02:00
|
|
|
if (needed > n_running_dirservers)
|
|
|
|
needed = n_running_dirservers;
|
|
|
|
|
|
|
|
if (needed)
|
2005-10-24 21:39:45 +02:00
|
|
|
info(LD_DIR, "For %d/%d running directory servers, we have %d live"
|
2005-12-10 10:36:26 +01:00
|
|
|
" network-status documents. Downloading %d.",
|
|
|
|
n_running_dirservers, n_dirservers, n_live, needed);
|
2005-09-14 23:09:25 +02:00
|
|
|
|
2005-09-08 23:01:24 +02:00
|
|
|
/* Also, download at least 1 every NETWORKSTATUS_CLIENT_DL_INTERVAL. */
|
2005-09-14 23:09:25 +02:00
|
|
|
if (n_running_dirservers &&
|
2005-12-14 21:40:40 +01:00
|
|
|
most_recent_received < now-NETWORKSTATUS_CLIENT_DL_INTERVAL &&
|
|
|
|
needed < 1) {
|
2005-10-24 21:39:45 +02:00
|
|
|
info(LD_DIR, "Our most recent network-status document (from %s) "
|
2005-12-10 10:36:26 +01:00
|
|
|
"is %d seconds old; downloading another.",
|
|
|
|
most_recent?most_recent->description:"nobody",
|
|
|
|
(int)(now-most_recent_received));
|
2005-09-08 08:22:44 +02:00
|
|
|
needed = 1;
|
2005-09-14 23:09:25 +02:00
|
|
|
}
|
2005-09-08 08:22:44 +02:00
|
|
|
|
2005-09-08 23:01:24 +02:00
|
|
|
if (!needed)
|
|
|
|
return;
|
|
|
|
|
2005-09-08 08:22:44 +02:00
|
|
|
/* If no networkstatus was found, choose a dirserver at random as "most
|
|
|
|
* recent". */
|
|
|
|
if (most_recent_idx<0)
|
2005-10-07 00:18:01 +02:00
|
|
|
most_recent_idx = crypto_rand_int(n_dirservers);
|
2005-09-08 08:22:44 +02:00
|
|
|
|
2005-09-08 23:01:24 +02:00
|
|
|
/* Build a request string for all the resources we want. */
|
|
|
|
resource_len = needed * (HEX_DIGEST_LEN+1) + 6;
|
|
|
|
resource = tor_malloc(resource_len);
|
|
|
|
memcpy(resource, "fp/", 3);
|
|
|
|
cp = resource+3;
|
2005-09-08 08:22:44 +02:00
|
|
|
for (i = most_recent_idx+1; needed; ++i) {
|
|
|
|
trusted_dir_server_t *ds;
|
2005-09-08 18:18:28 +02:00
|
|
|
if (i >= n_dirservers)
|
2005-09-08 08:22:44 +02:00
|
|
|
i = 0;
|
|
|
|
ds = smartlist_get(trusted_dir_servers, i);
|
2005-09-14 23:09:25 +02:00
|
|
|
if (ds->n_networkstatus_failures > NETWORKSTATUS_N_ALLOWABLE_FAILURES)
|
|
|
|
continue;
|
2005-09-08 23:01:24 +02:00
|
|
|
base16_encode(cp, HEX_DIGEST_LEN+1, ds->digest, DIGEST_LEN);
|
|
|
|
cp += HEX_DIGEST_LEN;
|
2005-09-08 08:22:44 +02:00
|
|
|
--needed;
|
2005-09-08 23:39:39 +02:00
|
|
|
if (needed)
|
|
|
|
*cp++ = '+';
|
2005-09-08 08:22:44 +02:00
|
|
|
}
|
2005-09-08 23:01:24 +02:00
|
|
|
memcpy(cp, ".z", 3);
|
|
|
|
directory_get_from_dirserver(DIR_PURPOSE_FETCH_NETWORKSTATUS, resource, 1);
|
|
|
|
tor_free(resource);
|
2005-09-08 08:22:44 +02:00
|
|
|
}
|
|
|
|
|
2005-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();
|
|
|
|
if (server_mode(options) && options->DirPort)
|
|
|
|
update_networkstatus_cache_downloads(time(NULL));
|
|
|
|
else
|
|
|
|
update_networkstatus_client_downloads(time(NULL));
|
|
|
|
}
|
|
|
|
|
2005-03-19 07:57:16 +01:00
|
|
|
/** Decide whether a given addr:port is definitely accepted,
|
|
|
|
* definitely rejected, probably accepted, or probably rejected by a
|
|
|
|
* given policy. If <b>addr</b> is 0, we don't know the IP of the
|
|
|
|
* target address. If <b>port</b> is 0, we don't know the port of the
|
|
|
|
* target address.
|
2003-12-09 05:29:52 +01:00
|
|
|
*
|
2005-03-19 07:57:16 +01:00
|
|
|
* For now, the algorithm is pretty simple: we look for definite and
|
|
|
|
* uncertain matches. The first definite match is what we guess; if
|
2005-07-01 03:59:37 +02:00
|
|
|
* it was preceded by no uncertain matches of the opposite policy,
|
2005-03-19 07:57:16 +01:00
|
|
|
* then the guess is definite; otherwise it is probable. (If we
|
|
|
|
* have a known addr and port, all matches are definite; if we have an
|
|
|
|
* unknown addr/port, any address/port ranges other than "all" are
|
|
|
|
* uncertain.)
|
|
|
|
*
|
|
|
|
* We could do better by assuming that some ranges never match typical
|
|
|
|
* addresses (127.0.0.1, and so on). But we'll try this for now.
|
2003-12-09 05:29:52 +01:00
|
|
|
*/
|
2005-03-19 07:57:16 +01:00
|
|
|
addr_policy_result_t
|
|
|
|
router_compare_addr_to_addr_policy(uint32_t addr, uint16_t port,
|
|
|
|
addr_policy_t *policy)
|
2003-05-07 20:30:46 +02:00
|
|
|
{
|
2003-12-09 05:29:52 +01:00
|
|
|
int maybe_reject = 0;
|
2004-02-17 08:56:33 +01:00
|
|
|
int maybe_accept = 0;
|
2003-12-09 05:29:52 +01:00
|
|
|
int match = 0;
|
2004-02-17 09:52:03 +01:00
|
|
|
int maybe = 0;
|
2004-12-04 02:14:36 +01:00
|
|
|
addr_policy_t *tmpe;
|
2003-12-05 10:51:49 +01:00
|
|
|
|
2004-11-28 10:05:49 +01:00
|
|
|
for (tmpe=policy; tmpe; tmpe=tmpe->next) {
|
2004-02-17 09:52:03 +01:00
|
|
|
maybe = 0;
|
2003-12-09 05:29:52 +01:00
|
|
|
if (!addr) {
|
|
|
|
/* Address is unknown. */
|
2004-12-05 08:10:08 +01:00
|
|
|
if ((port >= tmpe->prt_min && port <= tmpe->prt_max) ||
|
|
|
|
(!port && tmpe->prt_min<=1 && tmpe->prt_max>=65535)) {
|
2004-02-17 09:52:03 +01:00
|
|
|
/* The port definitely matches. */
|
|
|
|
if (tmpe->msk == 0) {
|
|
|
|
match = 1;
|
2004-02-17 08:56:33 +01:00
|
|
|
} else {
|
2004-02-17 09:52:03 +01:00
|
|
|
maybe = 1;
|
2004-02-17 09:10:07 +01:00
|
|
|
}
|
2004-02-17 09:52:03 +01:00
|
|
|
} else if (!port) {
|
|
|
|
/* The port maybe matches. */
|
|
|
|
maybe = 1;
|
2003-12-09 05:29:52 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Address is known */
|
2004-02-17 09:52:57 +01:00
|
|
|
if ((addr & tmpe->msk) == (tmpe->addr & tmpe->msk)) {
|
|
|
|
if (port >= tmpe->prt_min && port <= tmpe->prt_max) {
|
|
|
|
/* Exact match for the policy */
|
|
|
|
match = 1;
|
|
|
|
} else if (!port) {
|
|
|
|
maybe = 1;
|
|
|
|
}
|
2003-12-09 05:29:52 +01:00
|
|
|
}
|
|
|
|
}
|
2004-02-17 09:52:03 +01:00
|
|
|
if (maybe) {
|
2004-11-12 20:39:13 +01:00
|
|
|
if (tmpe->policy_type == ADDR_POLICY_REJECT)
|
2004-02-17 09:52:03 +01:00
|
|
|
maybe_reject = 1;
|
|
|
|
else
|
|
|
|
maybe_accept = 1;
|
|
|
|
}
|
2003-12-09 05:29:52 +01:00
|
|
|
if (match) {
|
2004-11-28 10:05:49 +01:00
|
|
|
if (tmpe->policy_type == ADDR_POLICY_ACCEPT) {
|
2004-02-17 08:56:33 +01:00
|
|
|
/* If we already hit a clause that might trigger a 'reject', than we
|
|
|
|
* can't be sure of this certain 'accept'.*/
|
2005-12-14 21:40:40 +01:00
|
|
|
return maybe_reject ? ADDR_POLICY_PROBABLY_ACCEPTED :
|
|
|
|
ADDR_POLICY_ACCEPTED;
|
2004-02-17 08:56:33 +01:00
|
|
|
} else {
|
2005-12-14 21:40:40 +01:00
|
|
|
return maybe_accept ? ADDR_POLICY_PROBABLY_REJECTED :
|
|
|
|
ADDR_POLICY_REJECTED;
|
2004-02-17 08:56:33 +01:00
|
|
|
}
|
2003-12-09 05:29:52 +01:00
|
|
|
}
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
}
|
2004-02-17 08:56:33 +01:00
|
|
|
/* accept all by default. */
|
2005-03-19 07:57:16 +01:00
|
|
|
return maybe_reject ? ADDR_POLICY_PROBABLY_ACCEPTED : ADDR_POLICY_ACCEPTED;
|
2003-09-25 07:17:11 +02:00
|
|
|
}
|
|
|
|
|
2005-01-12 05:58:23 +01:00
|
|
|
/** Return 1 if all running sufficiently-stable routers will reject
|
|
|
|
* addr:port, return 0 if any might accept it. */
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
|
|
|
router_exit_policy_all_routers_reject(uint32_t addr, uint16_t port,
|
|
|
|
int need_uptime)
|
|
|
|
{
|
2005-03-19 07:57:16 +01:00
|
|
|
addr_policy_result_t r;
|
2004-10-14 05:44:45 +02:00
|
|
|
if (!routerlist) return 1;
|
2003-08-23 12:09:25 +02:00
|
|
|
|
2005-09-13 17:32:03 +02:00
|
|
|
SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router,
|
|
|
|
{
|
2005-01-12 05:58:23 +01:00
|
|
|
if (router->is_running &&
|
2005-03-19 07:57:16 +01:00
|
|
|
!router_is_unreliable(router, need_uptime, 0)) {
|
|
|
|
r = router_compare_addr_to_addr_policy(addr, port, router->exit_policy);
|
|
|
|
if (r != ADDR_POLICY_REJECTED && r != ADDR_POLICY_PROBABLY_REJECTED)
|
|
|
|
return 0; /* this one could be ok. good enough. */
|
|
|
|
}
|
2005-09-13 17:32:03 +02:00
|
|
|
});
|
2003-12-09 05:29:52 +01:00
|
|
|
return 1; /* all will reject. */
|
2003-08-23 12:09:25 +02:00
|
|
|
}
|
|
|
|
|
2005-01-20 19:39:48 +01:00
|
|
|
/**
|
|
|
|
* If <b>policy</b> implicitly allows connections to any port in the
|
|
|
|
* IP set <b>addr</b>/<b>mask</b>, then set *<b>policy_out</b> to the
|
|
|
|
* part of the policy that allows it, and return 1. Else return 0.
|
|
|
|
*
|
|
|
|
* A policy allows an IP:Port combination <em>implicitly</em> if
|
|
|
|
* it is included in a *: pattern, or in a fallback pattern.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
policy_includes_addr_mask_implicitly(addr_policy_t *policy,
|
|
|
|
uint32_t addr, uint32_t mask,
|
|
|
|
addr_policy_t **policy_out)
|
|
|
|
{
|
|
|
|
uint32_t addr2;
|
|
|
|
tor_assert(policy_out);
|
|
|
|
addr &= mask;
|
|
|
|
addr2 = addr | ~mask;
|
|
|
|
for (; policy; policy=policy->next) {
|
|
|
|
/* Does this policy cover all of the address range we're looking at? */
|
|
|
|
/* Boolean logic time: range X is contained in range Y if, for
|
|
|
|
* each bit B, all possible values of B in X are values of B in Y.
|
|
|
|
* In "addr", we have every fixed bit set to its value, and every
|
|
|
|
* free bit set to 0. In "addr2", we have every fixed bit set to
|
|
|
|
* its value, and every free bit set to 1. So if addr and addr2 are
|
|
|
|
* both in the policy, the range is covered by the policy.
|
|
|
|
*/
|
2005-05-14 02:13:17 +02:00
|
|
|
uint32_t p_addr = policy->addr & policy->msk;
|
|
|
|
if (p_addr == (addr & policy->msk) &&
|
|
|
|
p_addr == (addr2 & policy->msk) &&
|
2005-01-20 19:39:48 +01:00
|
|
|
(policy->prt_min <= 1 && policy->prt_max == 65535)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/* Does this policy cover some of the address range we're looking at? */
|
|
|
|
/* Boolean logic time: range X and range Y intersect if there is
|
|
|
|
* some z such that z & Xmask == Xaddr and z & Ymask == Yaddr.
|
|
|
|
* This is FALSE iff there is some bit b where Xmask == yMask == 1
|
|
|
|
* and Xaddr != Yaddr. So if X intersects with Y iff at every
|
|
|
|
* place where Xmask&Ymask==1, Xaddr == Yaddr, or equivalently,
|
|
|
|
* Xaddr&Xmask&Ymask == Yaddr&Xmask&Ymask.
|
|
|
|
*/
|
|
|
|
if ((policy->addr & policy->msk & mask) == (addr & policy->msk) &&
|
|
|
|
policy->policy_type == ADDR_POLICY_ACCEPT) {
|
|
|
|
*policy_out = policy;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*policy_out = NULL;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** If <b>policy</b> implicitly allows connections to any port on
|
2005-11-15 04:05:23 +01:00
|
|
|
* 127.*, 192.168.*, etc, then warn (if <b>should_warn</b> is set) and return
|
2005-01-20 19:39:48 +01:00
|
|
|
* true. Else return false.
|
|
|
|
**/
|
|
|
|
int
|
|
|
|
exit_policy_implicitly_allows_local_networks(addr_policy_t *policy,
|
2005-11-15 04:05:23 +01:00
|
|
|
int should_warn)
|
2005-01-20 19:39:48 +01:00
|
|
|
{
|
|
|
|
addr_policy_t *p;
|
|
|
|
int r=0,i;
|
|
|
|
static struct {
|
|
|
|
uint32_t addr; uint32_t mask; const char *network;
|
|
|
|
} private_networks[] = {
|
2005-06-29 21:15:23 +02:00
|
|
|
{ 0x7f000000, 0xff000000, "localhost (127.0.0.0/8)" },
|
|
|
|
{ 0x0a000000, 0xff000000, "addresses in private network 10.0.0.0/8" },
|
|
|
|
{ 0xa9fe0000, 0xffff0000, "addresses in private network 169.254.0.0/16" },
|
|
|
|
{ 0xac100000, 0xfff00000, "addresses in private network 172.16.0.0/12" },
|
|
|
|
{ 0xc0a80000, 0xffff0000, "addresses in private network 192.168.0.0/16" },
|
2005-01-20 19:39:48 +01:00
|
|
|
{ 0,0,NULL},
|
|
|
|
};
|
|
|
|
for (i=0; private_networks[i].addr; ++i) {
|
|
|
|
p = NULL;
|
2005-05-14 02:13:17 +02:00
|
|
|
/* log_fn(LOG_INFO,"Checking network %s", private_networks[i].network); */
|
|
|
|
if (policy_includes_addr_mask_implicitly(
|
2005-12-14 21:40:40 +01:00
|
|
|
policy, private_networks[i].addr, private_networks[i].mask, &p)) {
|
2005-11-15 04:05:23 +01:00
|
|
|
if (should_warn)
|
2005-10-24 21:39:45 +02:00
|
|
|
warn(LD_CONFIG, "Exit policy %s implicitly accepts %s",
|
2005-12-10 10:36:26 +01:00
|
|
|
p?p->string:"(default)",
|
|
|
|
private_networks[i].network);
|
2005-05-14 02:13:17 +02:00
|
|
|
r = 1;
|
|
|
|
}
|
2005-01-20 19:39:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Return true iff <b>router</b> does not permit exit streams.
|
2004-05-04 20:17:45 +02:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
|
|
|
router_exit_policy_rejects_all(routerinfo_t *router)
|
|
|
|
{
|
2004-12-05 08:10:08 +01:00
|
|
|
return router_compare_addr_to_addr_policy(0, 0, router->exit_policy)
|
2004-02-17 08:56:33 +01:00
|
|
|
== ADDR_POLICY_REJECTED;
|
2003-05-07 20:30:46 +02:00
|
|
|
}
|
|
|
|
|
2004-11-09 18:14:15 +01:00
|
|
|
/** Add to the list of authorized directory servers one at
|
2005-08-26 21:31:51 +02:00
|
|
|
* <b>address</b>:<b>port</b>, with identity key <b>digest</b>. If
|
|
|
|
* <b>address</b> is NULL, add ourself. */
|
2004-11-09 18:14:15 +01:00
|
|
|
void
|
2005-10-04 23:21:09 +02:00
|
|
|
add_trusted_dir_server(const char *nickname, const char *address,
|
|
|
|
uint16_t port, const char *digest, int supports_v1)
|
2004-10-12 17:55:20 +02:00
|
|
|
{
|
|
|
|
trusted_dir_server_t *ent;
|
|
|
|
uint32_t a;
|
2005-08-26 21:31:51 +02:00
|
|
|
char *hostname = NULL;
|
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. */
|
|
|
|
if (resolve_my_address(get_options(), &a, &hostname) < 0) {
|
2005-12-14 21:40:40 +01:00
|
|
|
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)) {
|
2005-11-18 03:47:09 +01:00
|
|
|
warn(LD_CONFIG, "Unable to lookup address for directory server at '%s'",
|
2005-10-24 21:39:45 +02:00
|
|
|
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;
|
2004-10-12 17:55:20 +02:00
|
|
|
ent->dir_port = port;
|
|
|
|
ent->is_running = 1;
|
2005-12-14 23:00:58 +01:00
|
|
|
ent->is_v1_authority = supports_v1;
|
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",
|
|
|
|
nickname, hostname, (int)port);
|
|
|
|
else
|
|
|
|
tor_snprintf(ent->description, dlen, "directory server at %s:%d",
|
|
|
|
hostname, (int)port);
|
|
|
|
|
2005-12-14 23:00:58 +01:00
|
|
|
ent->fake_status.addr = ent->addr;
|
|
|
|
memcpy(ent->fake_status.identity_digest, digest, DIGEST_LEN);
|
2005-12-18 23:45:27 +01:00
|
|
|
if (nickname)
|
|
|
|
strlcpy(ent->fake_status.nickname, nickname,
|
|
|
|
sizeof(ent->fake_status.nickname));
|
|
|
|
else
|
|
|
|
ent->fake_status.nickname[0] = '\0';
|
2005-12-14 23:00:58 +01:00
|
|
|
ent->fake_status.dir_port = ent->dir_port;
|
|
|
|
|
2004-10-13 20:28:39 +02:00
|
|
|
smartlist_add(trusted_dir_servers, ent);
|
2004-10-12 17:55:20 +02:00
|
|
|
}
|
|
|
|
|
2005-10-05 07:03:52 +02:00
|
|
|
/** Free storage held in <b>ds</b> */
|
|
|
|
void
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
2005-06-09 21:03:31 +02:00
|
|
|
|
2005-09-13 17:32:03 +02:00
|
|
|
/** Return the network status with a given identity digest. */
|
2005-09-08 08:22:44 +02:00
|
|
|
networkstatus_t *
|
|
|
|
networkstatus_get_by_digest(const char *digest)
|
|
|
|
{
|
|
|
|
SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
|
|
|
|
{
|
|
|
|
if (!memcmp(ns->identity_digest, digest, DIGEST_LEN))
|
|
|
|
return ns;
|
|
|
|
});
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2005-09-14 23:09:25 +02:00
|
|
|
/** If the network-status list has changed since the last time we called this
|
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)
|
|
|
|
{
|
2005-09-21 02:41:06 +02:00
|
|
|
#define SELF_OPINION_INTERVAL 90*60
|
2005-09-14 23:09:25 +02:00
|
|
|
routerinfo_t *me;
|
2005-09-18 04:24:42 +02:00
|
|
|
time_t now;
|
|
|
|
if (!routerlist || !networkstatus_list ||
|
|
|
|
(!networkstatus_list_has_changed && !routerstatus_list_has_changed))
|
2005-09-14 23:09:25 +02:00
|
|
|
return;
|
|
|
|
|
2005-09-18 04:24:42 +02:00
|
|
|
now = time(NULL);
|
|
|
|
if (networkstatus_list_has_changed)
|
|
|
|
routerstatus_list_update_from_networkstatus(now);
|
|
|
|
|
2005-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();
|
2005-09-21 02:41:06 +02:00
|
|
|
if (me && !have_warned_about_unverified_status) {
|
|
|
|
int n_recent = 0, n_listing = 0, n_valid = 0, n_named = 0;
|
|
|
|
routerstatus_t *rs;
|
|
|
|
SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
|
|
|
|
{
|
|
|
|
if (ns->received_on + SELF_OPINION_INTERVAL < now)
|
|
|
|
continue;
|
|
|
|
++n_recent;
|
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;
|
|
|
|
});
|
|
|
|
|
|
|
|
if (n_recent >= 2 && n_listing >= 2) {
|
2005-11-11 18:01:20 +01:00
|
|
|
/* XXX When we have more than 3 dirservers, these warnings
|
|
|
|
* might become spurious depending on which combination of
|
|
|
|
* network-statuses we have. Perhaps we should wait until we
|
|
|
|
* have tried all of them? -RD */
|
2005-09-21 02:41:06 +02:00
|
|
|
if (n_valid <= n_recent/2) {
|
2005-12-14 21:40:40 +01:00
|
|
|
warn(LD_GENERAL,
|
|
|
|
"%d/%d recent directory servers list us as invalid. Please "
|
|
|
|
"consider sending your identity fingerprint to the tor-ops.",
|
2005-12-10 10:36:26 +01:00
|
|
|
n_recent-n_valid, n_recent);
|
2005-09-21 02:41:06 +02:00
|
|
|
have_warned_about_unverified_status = 1;
|
2005-11-11 18:01:20 +01:00
|
|
|
} else if (!n_named) { // (n_named <= n_recent/2) {
|
2005-12-14 21:40:40 +01:00
|
|
|
warn(LD_GENERAL, "0/%d recent directory servers recognize this "
|
|
|
|
"server. Please consider sending your identity fingerprint to "
|
|
|
|
"the tor-ops.",
|
2005-12-10 10:36:26 +01:00
|
|
|
n_recent);
|
2005-09-21 02:41:06 +02:00
|
|
|
have_warned_about_unverified_status = 1;
|
|
|
|
}
|
2005-09-14 23:09:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
helper_nodes_set_status_from_directory();
|
|
|
|
|
2005-09-21 02:41:06 +02:00
|
|
|
if (!have_warned_about_old_version) {
|
|
|
|
int n_recent = 0;
|
|
|
|
int n_recommended = 0;
|
|
|
|
int is_server = server_mode(get_options());
|
|
|
|
version_status_t consensus = VS_RECOMMENDED;
|
|
|
|
SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
|
|
|
|
{
|
|
|
|
version_status_t vs;
|
2005-09-21 04:38:51 +02:00
|
|
|
if (!ns->recommends_versions ||
|
|
|
|
ns->received_on + SELF_OPINION_INTERVAL < now )
|
2005-09-21 02:41:06 +02:00
|
|
|
continue;
|
|
|
|
vs = tor_version_is_obsolete(
|
|
|
|
VERSION, is_server ? ns->server_versions : ns->client_versions);
|
|
|
|
if (vs == VS_RECOMMENDED)
|
|
|
|
++n_recommended;
|
|
|
|
if (n_recent++ == 0) {
|
|
|
|
consensus = vs;
|
|
|
|
} else if (consensus != vs) {
|
|
|
|
consensus = version_status_join(consensus, vs);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
if (n_recent > 2 && n_recommended < n_recent/2) {
|
|
|
|
if (consensus == VS_NEW || consensus == VS_NEW_IN_SERIES) {
|
|
|
|
if (!have_warned_about_new_version) {
|
2005-12-14 21:40:40 +01:00
|
|
|
notice(LD_GENERAL, "This version of Tor (%s) is newer than any "
|
|
|
|
"recommended version%s, according to %d/%d recent network "
|
|
|
|
"statuses.",
|
|
|
|
VERSION,
|
|
|
|
consensus == VS_NEW_IN_SERIES ? " in its series" : "",
|
2005-09-21 02:41:06 +02:00
|
|
|
n_recent-n_recommended, n_recent);
|
|
|
|
have_warned_about_new_version = 1;
|
|
|
|
}
|
|
|
|
} else {
|
2005-12-14 21:40:40 +01:00
|
|
|
notice(LD_GENERAL, "This version of Tor (%s) is %s, according to "
|
|
|
|
"%d/%d recent network statuses.",
|
2005-09-21 02:41:06 +02:00
|
|
|
VERSION, consensus == VS_OLD ? "obsolete" : "not recommended",
|
|
|
|
n_recent-n_recommended, n_recent);
|
|
|
|
have_warned_about_old_version = 1;
|
|
|
|
}
|
|
|
|
} else {
|
2005-10-24 21:39:45 +02:00
|
|
|
info(LD_GENERAL, "%d/%d recent directories think my version is ok.",
|
2005-12-10 10:36:26 +01:00
|
|
|
n_recommended, n_recent);
|
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. */
|
2005-09-12 08:56:42 +02:00
|
|
|
#define DEFAULT_RUNNING_INTERVAL 60*60
|
2005-09-13 17:32:03 +02:00
|
|
|
/** If possible, always allow at least this many network-statuses to influence
|
|
|
|
* our view of who's running. */
|
2005-09-12 08:56:42 +02:00
|
|
|
#define MIN_TO_INFLUENCE_RUNNING 3
|
2005-09-18 04:24:42 +02:00
|
|
|
|
2005-09-30 22:04:55 +02:00
|
|
|
/** Change the is_recent field of each member of networkstatus_list so that
|
|
|
|
* all members more recent than DEFAULT_RUNNING_INTERVAL are recent, and
|
|
|
|
* at least the MIN_TO_INFLUENCE_RUNNING most recent members are resent, and no
|
|
|
|
* others are recent. Set networkstatus_list_has_changed if anything happeed.
|
|
|
|
*/
|
2005-09-12 08:56:42 +02:00
|
|
|
void
|
2005-09-18 04:24:42 +02:00
|
|
|
networkstatus_list_update_recent(time_t now)
|
2005-09-12 08:56:42 +02:00
|
|
|
{
|
2005-09-18 04:24:42 +02:00
|
|
|
int n_statuses, n_recent, changed, i;
|
|
|
|
char published[ISO_TIME_LEN+1];
|
2005-09-12 08:56:42 +02:00
|
|
|
|
2005-09-18 04:24:42 +02:00
|
|
|
if (!networkstatus_list)
|
2005-09-12 08:56:42 +02:00
|
|
|
return;
|
2005-09-18 04:24:42 +02:00
|
|
|
|
|
|
|
n_statuses = smartlist_len(networkstatus_list);
|
|
|
|
n_recent = 0;
|
|
|
|
changed = 0;
|
|
|
|
for (i=n_statuses-1; i >= 0; --i) {
|
|
|
|
networkstatus_t *ns = smartlist_get(networkstatus_list, i);
|
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);
|
2005-10-24 21:39:45 +02:00
|
|
|
info(LD_DIR,
|
2005-12-10 10:36:26 +01:00
|
|
|
"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);
|
2005-10-24 21:39:45 +02:00
|
|
|
info(LD_DIR,
|
2005-12-10 10:36:26 +01:00
|
|
|
"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
|
|
|
}
|
2005-09-18 04:24:42 +02:00
|
|
|
if (changed)
|
|
|
|
networkstatus_list_has_changed = 1;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
int i, j, warned;
|
2005-09-22 03:51:14 +02:00
|
|
|
int *index, *size;
|
|
|
|
networkstatus_t **networkstatus;
|
|
|
|
smartlist_t *result;
|
2005-09-22 08:34:29 +02:00
|
|
|
strmap_t *name_map;
|
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
|
|
|
|
|
|
|
networkstatus_list_update_recent(now);
|
2005-09-12 08:56:42 +02:00
|
|
|
|
2005-09-18 04:24:42 +02:00
|
|
|
if (!networkstatus_list_has_changed)
|
|
|
|
return;
|
2005-09-12 08:56:42 +02:00
|
|
|
if (!networkstatus_list)
|
|
|
|
networkstatus_list = smartlist_create();
|
2005-09-18 04:24:42 +02:00
|
|
|
if (!routerstatus_list)
|
|
|
|
routerstatus_list = smartlist_create();
|
2005-09-12 08:56:42 +02:00
|
|
|
if (!trusted_dir_servers)
|
|
|
|
trusted_dir_servers = smartlist_create();
|
2005-10-05 03:53:44 +02:00
|
|
|
if (!warned_conflicts)
|
|
|
|
warned_conflicts = smartlist_create();
|
2005-09-12 08:56:42 +02:00
|
|
|
|
|
|
|
n_trusted = smartlist_len(trusted_dir_servers);
|
|
|
|
n_statuses = smartlist_len(networkstatus_list);
|
|
|
|
|
|
|
|
if (n_statuses < (n_trusted/2)+1) {
|
|
|
|
/* Not enough statuses to adjust status. */
|
2005-10-24 21:39:45 +02:00
|
|
|
notice(LD_DIR,"Not enough statuses to update router status list. (%d/%d)",
|
2005-09-18 04:24:42 +02:00
|
|
|
n_statuses, n_trusted);
|
2005-09-12 08:56:42 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-10-24 21:39:45 +02:00
|
|
|
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;
|
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();
|
|
|
|
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);
|
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) {
|
|
|
|
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);
|
|
|
|
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();
|
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 <=
|
|
|
|
* j < index[i1], networkstatus[i1]->entries[j]->identity_digest <
|
|
|
|
* networkstatus[i2]->entries[index[i2]]->identity_digest.
|
|
|
|
*
|
|
|
|
* (That is, the indices are always advanced past lower digest before
|
|
|
|
* higher.)
|
|
|
|
*/
|
|
|
|
while (1) {
|
2005-09-18 04:24:42 +02:00
|
|
|
int n_running=0, n_named=0, n_valid=0, n_listing=0;
|
2005-12-14 23:00:58 +01:00
|
|
|
int n_v2_dir=0, n_fast=0, n_stable=0, n_exit=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)) {
|
2005-12-14 21:40:40 +01:00
|
|
|
warn(LD_DIR, "Naming authorities disagree about nicknames for $%s "
|
|
|
|
"(\"%s\" vs \"%s\")",
|
2005-12-10 10:36:26 +01:00
|
|
|
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;
|
|
|
|
if (rs->is_stable)
|
|
|
|
++n_stable;
|
|
|
|
if (rs->is_v2_dir)
|
|
|
|
++n_v2_dir;
|
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;
|
2005-09-18 04:24:42 +02:00
|
|
|
}
|
|
|
|
smartlist_add(result, rs_out);
|
2005-10-24 21:39:45 +02:00
|
|
|
debug(LD_DIR, "Router '%s' is listed by %d/%d directories, "
|
2005-12-10 10:36:26 +01:00
|
|
|
"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;
|
|
|
|
rs_out->status.is_stable = n_stable > n_statuses/2;
|
|
|
|
rs_out->status.is_v2_dir = n_v2_dir > n_statuses/2;
|
2005-09-18 04:24:42 +02:00
|
|
|
}
|
2005-09-30 23:04:52 +02:00
|
|
|
SMARTLIST_FOREACH(routerstatus_list, local_routerstatus_t *, rs,
|
|
|
|
local_routerstatus_free(rs));
|
2005-09-18 04:24:42 +02:00
|
|
|
smartlist_free(routerstatus_list);
|
|
|
|
routerstatus_list = result;
|
|
|
|
|
2005-09-22 03:51:14 +02:00
|
|
|
tor_free(networkstatus);
|
|
|
|
tor_free(index);
|
|
|
|
tor_free(size);
|
2005-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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Given a list <b>routers</b> of routerinfo_t *, update each routers's
|
|
|
|
* is_named, is_verified, and is_running fields according to our current
|
|
|
|
* networkstatus_t documents. */
|
|
|
|
void
|
2005-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-12-27 06:26:03 +01:00
|
|
|
routerstatus_t *rs2;
|
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) {
|
|
|
|
/* If we're an authdir, don't believe others. */
|
2005-09-22 03:51:14 +02:00
|
|
|
router->is_verified = rs->status.is_valid;
|
|
|
|
router->is_running = rs->status.is_running;
|
2005-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;
|
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-12-27 06:26:03 +01:00
|
|
|
|
|
|
|
/* Note that we have this descriptor. This may be redundant? */
|
|
|
|
SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
|
|
|
|
{
|
|
|
|
rs2 = networkstatus_find_entry(ns, router->cache_info.identity_digest);
|
|
|
|
if (rs2 && !memcmp(rs2->descriptor_digest,
|
|
|
|
router->cache_info.signed_descriptor_digest,
|
|
|
|
DIGEST_LEN))
|
|
|
|
rs2->need_to_mirror = 0;
|
|
|
|
});
|
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) {
|
2005-12-27 06:26:03 +01:00
|
|
|
if (!strcmpstart(conn->requested_resource, prefix))
|
|
|
|
dir_split_resource_into_fingerprints(conn->requested_resource+p_len,
|
|
|
|
tmp, NULL, 1);
|
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
|
|
|
|
2005-12-27 06:26:03 +01:00
|
|
|
/** Launch downloads for the all the descriptors whose digests are listed
|
|
|
|
* 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
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
#define MAX_OLD_SERVER_DOWNLOAD_RATE 2*60*60
|
|
|
|
#define ESTIMATED_PROPAGATION_TIME 10*60
|
|
|
|
int n_downloadable = 0;
|
|
|
|
smartlist_t *downloadable = smartlist_create();
|
|
|
|
digestmap_t *downloading;
|
|
|
|
time_t now = time(NULL);
|
|
|
|
/* these are just used for logging */
|
|
|
|
int n_not_ready = 0, n_in_progress = 0, n_uptodate = 0,
|
|
|
|
n_obsolete = 0, n_too_young = 0;
|
|
|
|
|
|
|
|
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;
|
|
|
|
if (rs->status.published_on + ROUTER_MAX_AGE < now) {
|
|
|
|
/* This one is too old to consider. */
|
|
|
|
++n_obsolete;
|
|
|
|
} else if (digestmap_get(downloading, rs->status.descriptor_digest)) {
|
|
|
|
/* We're downloading this one now. */
|
|
|
|
++n_in_progress;
|
|
|
|
#if 0
|
|
|
|
/* Authorities don't call this path any longer. */
|
|
|
|
} else if (options->AuthoritativeDir &&
|
|
|
|
dirserv_would_reject_router(&rs->status)) {
|
|
|
|
++n_would_reject;
|
|
|
|
#endif
|
|
|
|
} else if (router_get_by_descriptor_digest(rs->status.descriptor_digest)) {
|
|
|
|
/* We have the 'best' descriptor for this router. */
|
|
|
|
++n_uptodate;
|
|
|
|
} else if ((ri = router_get_by_digest(rs->status.identity_digest)) &&
|
|
|
|
ri->cache_info.published_on > rs->status.published_on) {
|
|
|
|
/* Oddly, we have a descriptor more resent than the 'best' one, but it
|
|
|
|
was once best. So that's okay. */
|
|
|
|
++n_uptodate;
|
|
|
|
} else if (rs->status.published_on + ESTIMATED_PROPAGATION_TIME > now) {
|
|
|
|
/* Most caches probably don't have this descriptor yet. */
|
|
|
|
++n_too_young;
|
|
|
|
} 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
|
|
|
|
info(LD_DIR,
|
|
|
|
"%d routers are downloadable. %d are too old to consider. "
|
|
|
|
"%d are in progress. %d are up-to-date. %d are too young to consider. "
|
|
|
|
"%d failed too recently to retry.",
|
|
|
|
n_downloadable, n_obsolete, n_in_progress, n_uptodate, n_too_young,
|
|
|
|
n_not_ready);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
digestmap_free(downloading, NULL);
|
|
|
|
return downloadable;
|
2005-09-12 08:56:42 +02:00
|
|
|
}
|
|
|
|
|
2005-09-15 08:15:31 +02:00
|
|
|
/** Initiate new router downloads as needed.
|
|
|
|
*
|
|
|
|
* We only allow one router descriptor download at a time.
|
|
|
|
* If we have less than two network-status documents, we ask
|
|
|
|
* a directory for "all descriptors."
|
|
|
|
* Otherwise, we ask for all descriptors that we think are different
|
|
|
|
* from what we have.
|
|
|
|
*/
|
2005-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
|
|
|
{
|
2005-09-22 08:34:29 +02:00
|
|
|
#define MAX_DL_PER_REQUEST 128
|
2005-09-23 20:05:14 +02:00
|
|
|
#define MIN_DL_PER_REQUEST 4
|
2005-09-22 08:34:29 +02:00
|
|
|
#define MIN_REQUESTS 3
|
2005-09-30 22:04:55 +02:00
|
|
|
#define MAX_DL_TO_DELAY 16
|
2005-10-04 22:18:26 +02:00
|
|
|
#define MAX_CLIENT_INTERVAL_WITHOUT_REQUEST 10*60
|
|
|
|
#define MAX_SERVER_INTERVAL_WITHOUT_REQUEST 1*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
|
|
|
|
2005-12-27 06:26:03 +01:00
|
|
|
if (server_mode(options) && options->DirPort) {
|
|
|
|
warn(LD_BUG, "Called router_descriptor_client_downloads() on a mirror?");
|
2005-09-23 20:05:14 +02:00
|
|
|
}
|
|
|
|
|
2005-12-27 06:26:03 +01:00
|
|
|
if (networkstatus_list && smartlist_len(networkstatus_list) < 2) {
|
|
|
|
/* XXXX Is this redundant? -NM */
|
|
|
|
info(LD_DIR, "Not enough networkstatus documents to launch requests.");
|
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2005-10-24 21:39:45 +02:00
|
|
|
debug(LD_DIR,
|
2005-12-10 10:36:26 +01:00
|
|
|
"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) {
|
2005-11-17 23:23:18 +01:00
|
|
|
// 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 +
|
2005-10-06 00:36:18 +02:00
|
|
|
MAX_CLIENT_INTERVAL_WITHOUT_REQUEST) > now;
|
2005-12-27 06:26:03 +01:00
|
|
|
}
|
|
|
|
if (should_delay) {
|
2005-12-14 21:40:40 +01:00
|
|
|
// debug(LD_DIR, "There are not many downloadable routerdescs; "
|
|
|
|
// "waiting till we have some more.");
|
2005-12-27 06:26:03 +01:00
|
|
|
} else {
|
|
|
|
info(LD_DIR, "There are not many downloadable routerdescs, but we've "
|
|
|
|
"been waiting long enough (%d seconds). Downloading.",
|
|
|
|
(int)(now-last_routerdesc_download_attempted));
|
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;
|
|
|
|
|
2005-10-24 21:39:45 +02:00
|
|
|
info(LD_DIR, "Launching %d request%s for %d router%s, %d at a time",
|
2005-12-10 10:36:26 +01:00
|
|
|
(n_downloadable+n_per_request-1)/n_per_request,
|
|
|
|
n_downloadable>n_per_request?"s":"",
|
|
|
|
n_downloadable, n_downloadable>1?"s":"", n_per_request);
|
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
|
|
|
}
|
|
|
|
|
2005-12-27 06:26:03 +01:00
|
|
|
/* DOCDOC */
|
|
|
|
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();
|
|
|
|
|
|
|
|
if (!(server_mode(options) && options->DirPort)) {
|
|
|
|
warn(LD_BUG, "Called update_router_descriptor_cache_downloads() "
|
|
|
|
"on a non-mirror?");
|
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
|
|
|
{
|
|
|
|
smartlist_t *dl = smartlist_create();
|
|
|
|
downloadable[ns_sl_idx] = dl;
|
|
|
|
download_from[ns_sl_idx] = smartlist_create();
|
|
|
|
SMARTLIST_FOREACH(ns->entries, routerstatus_t * , rs,
|
|
|
|
{
|
|
|
|
if (!rs->need_to_mirror)
|
|
|
|
continue;
|
|
|
|
if (router_get_by_descriptor_digest(rs->descriptor_digest)) {
|
|
|
|
warn(LD_BUG, "We have a router descriptor, but need_to_mirror=1.");
|
|
|
|
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.)
|
|
|
|
* - If d is a mamber of download_from[y], d is a member of downloadable[y].
|
|
|
|
* (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;
|
|
|
|
tor_assert(dl);
|
|
|
|
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);
|
|
|
|
if (!ds) {
|
|
|
|
warn(LD_BUG, "Networkstatus with no corresponding authority!");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
smartlist_t *dl = download_from[i];
|
|
|
|
info(LD_DIR, "Requesting %d descriptors from authority \"%s\"",
|
|
|
|
smartlist_len(dl), ds->nickname);
|
|
|
|
for (j=0; j < smartlist_len(dl); j += MAX_DL_PER_REQUEST) {
|
|
|
|
initiate_descriptor_downloads(&(ds->fake_status), dl, j,
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* DOCDOC */
|
|
|
|
void
|
|
|
|
update_router_descriptor_downloads(time_t now)
|
|
|
|
{
|
|
|
|
or_options_t *options = get_options();
|
|
|
|
if (server_mode(options) && options->DirPort) {
|
|
|
|
update_router_descriptor_cache_downloads(now);
|
|
|
|
} else {
|
|
|
|
update_router_descriptor_client_downloads(now);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-09-15 08:15:31 +02:00
|
|
|
/** Return true iff we have enough networkstatus and router information to
|
|
|
|
* start building circuits. Right now, this means "at least 2 networkstatus
|
|
|
|
* documents, and at least 1/4 of expected routers." */
|
2005-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)
|
|
|
|
{
|
2005-12-15 21:44:15 +01:00
|
|
|
int tot = 0, any_running = 0;
|
|
|
|
int n_ns, res, avg;
|
|
|
|
static int have_enough = 0;
|
|
|
|
if (!networkstatus_list || !routerlist) {
|
|
|
|
res = 0;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
n_ns = smartlist_len(networkstatus_list);
|
|
|
|
if (n_ns<2) {
|
|
|
|
res = 0;
|
|
|
|
goto done;
|
|
|
|
}
|
2005-09-15 07:19:38 +02:00
|
|
|
SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
|
|
|
|
tot += smartlist_len(ns->entries));
|
2005-12-15 21:44:15 +01:00
|
|
|
avg = tot / n_ns;
|
|
|
|
SMARTLIST_FOREACH(routerstatus_list, local_routerstatus_t *, rs,
|
|
|
|
{
|
|
|
|
if (rs->status.is_running) {
|
|
|
|
any_running = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
res = smartlist_len(routerlist->routers) > (avg/4) && any_running;
|
|
|
|
done:
|
|
|
|
if (res && !have_enough) {
|
|
|
|
log(LOG_NOTICE, LD_DIR,
|
|
|
|
"We now have enough directory information to build circuits.");
|
|
|
|
}
|
2005-12-15 21:56:46 +01:00
|
|
|
if (!res && have_enough) {
|
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",
|
2005-12-15 23:10:03 +01:00
|
|
|
any_running ? "" :
|
|
|
|
" (No servers seem reachable -- is your network connection down?)");
|
2005-12-15 21:44:15 +01:00
|
|
|
}
|
2005-12-15 22:44:23 +01:00
|
|
|
have_enough = res;
|
2005-12-15 21:44:15 +01:00
|
|
|
return res;
|
2005-09-15 07:19:38 +02:00
|
|
|
}
|
|
|
|
|
2005-09-30 22:04:55 +02:00
|
|
|
/** Reset the descriptor download failure count on all routers, so that we
|
|
|
|
* can retry any long-failed routers immediately.
|
|
|
|
*/
|
2005-09-22 08:34:29 +02:00
|
|
|
void
|
|
|
|
router_reset_descriptor_download_failures(void)
|
|
|
|
{
|
|
|
|
if (!routerstatus_list)
|
|
|
|
return;
|
|
|
|
SMARTLIST_FOREACH(routerstatus_list, local_routerstatus_t *, rs,
|
|
|
|
{
|
|
|
|
rs->n_download_failures = 0;
|
|
|
|
rs->next_attempt_at = 0;
|
|
|
|
});
|
2005-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
|
|
|
|
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;
|
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 ||
|
|
|
|
config_cmp_addr_policies(r1->exit_policy, r2->exit_policy))
|
|
|
|
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? */
|
2005-11-05 21:15:27 +01:00
|
|
|
if (r1->cache_info.published_on + 12*60*60 < 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,
|
|
|
|
* give or take 30 minutes? */
|
2005-12-14 21:40:40 +01:00
|
|
|
r1pub = r1->cache_info.published_on;
|
|
|
|
r2pub = r2->cache_info.published_on;
|
|
|
|
if (abs(r2->uptime - (r1->uptime + (r2pub - r1pub))))
|
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
|
|
|
|
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);
|
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
|
|
|
}
|
|
|
|
|