Choose directory servers from routerstatus list, not from routerinfo list. This way, as soon was we have a networkstatus, we can ask a cache to give us routers, rather than needing to ask the directories.

svn:r5586
This commit is contained in:
Nick Mathewson 2005-12-14 22:00:58 +00:00
parent 7e6a41af93
commit 9482b1b9d5
6 changed files with 154 additions and 97 deletions

View File

@ -194,8 +194,8 @@ N - Clients use Stable and Fast instead of uptime and bandwidth to
servers?
- Is this still necessary?
o All versions of Tor should get cosmetic changes rate-limited.
- Pick directories from networkstatus objects, not from routerlist.
- But! We can't do this easily, since we want to know about platform,
o Pick directories from networkstatus objects, not from routerlist.
o But! We can't do this easily, since we want to know about platform,
and networkstatus doesn't tell us Tor version. Can we solve this?
Should we do it by adding flags to networkstatus or what?

View File

@ -24,7 +24,7 @@
}
#define HT_INITIALIZER() \
{ 0, NULL, 0, 0, -1 }
{ NULL, 0, 0, 0, -1 }
#define HT_INIT(root) do { \
(root)->hth_table_length = 0; \

View File

@ -31,11 +31,6 @@ const char directory_c_id[] =
* connection_finished_connecting() in connection.c
*/
static void
directory_initiate_command_trusted_dir(trusted_dir_server_t *dirserv,
uint8_t purpose, int private_connection,
const char *resource,
const char *payload, size_t payload_len);
static void
directory_initiate_command(const char *address, uint32_t addr, uint16_t port,
const char *platform,
const char *digest, uint8_t purpose,
@ -143,9 +138,10 @@ directory_post_to_dirservers(uint8_t purpose, const char *payload,
*/
SMARTLIST_FOREACH(dirservers, trusted_dir_server_t *, ds,
{
routerstatus_t *rs = &(ds->fake_status);
post_via_tor = purpose_is_private(purpose) ||
!fascist_firewall_allows_address(ds->addr,ds->dir_port);
directory_initiate_command_trusted_dir(ds, purpose, post_via_tor,
directory_initiate_command_routerstatus(rs, purpose, post_via_tor,
NULL, payload, payload_len);
});
}
@ -159,8 +155,7 @@ void
directory_get_from_dirserver(uint8_t purpose, const char *resource,
int retry_if_no_servers)
{
routerinfo_t *r = NULL;
trusted_dir_server_t *ds = NULL;
routerstatus_t *rs = NULL;
or_options_t *options = get_options();
int fetch_fresh_first = server_mode(options) && options->DirPort != 0;
int directconn = !purpose_is_private(purpose);
@ -175,19 +170,21 @@ directory_get_from_dirserver(uint8_t purpose, const char *resource,
!strcmpstart(resource,"fp/") && strlen(resource) == HEX_DIGEST_LEN+3) {
/* Try to ask the actual dirserver its opinion. */
char digest[DIGEST_LEN];
trusted_dir_server_t *ds;
base16_decode(digest, DIGEST_LEN, resource+3, HEX_DIGEST_LEN);
ds = router_get_trusteddirserver_by_digest(digest);
rs = &(ds->fake_status);
}
if (!ds && fetch_fresh_first) {
if (!rs && fetch_fresh_first) {
/* only ask authdirservers, and don't ask myself */
ds = router_pick_trusteddirserver(need_v1_support, 1, 1,
rs = router_pick_trusteddirserver(need_v1_support, 1, 1,
retry_if_no_servers);
}
if (!ds) {
if (!rs) {
/* anybody with a non-zero dirport will do */
r = router_pick_directory_server(1, 1, need_v2_support,
rs = router_pick_directory_server(1, 1, need_v2_support,
retry_if_no_servers);
if (!r) {
if (!rs) {
const char *which;
if (purpose == DIR_PURPOSE_FETCH_DIR)
which = "directory";
@ -199,9 +196,9 @@ directory_get_from_dirserver(uint8_t purpose, const char *resource,
which = "server descriptors";
info(LD_DIR,
"No router found for %s; falling back to dirserver list", which);
ds = router_pick_trusteddirserver(1, 1, 1,
rs = router_pick_trusteddirserver(1, 1, 1,
retry_if_no_servers);
if (!ds)
if (!rs)
directconn = 0; /* last resort: try routing it via Tor */
}
}
@ -210,19 +207,17 @@ directory_get_from_dirserver(uint8_t purpose, const char *resource,
/* Never use fascistfirewall; we're going via Tor. */
if (purpose == DIR_PURPOSE_FETCH_RENDDESC) {
/* only ask authdirservers, any of them will do */
ds = router_pick_trusteddirserver(0, 0, 0, retry_if_no_servers);
rs = router_pick_trusteddirserver(0, 0, 0, retry_if_no_servers);
} else {
/* anybody with a non-zero dirport will do. Disregard firewalls. */
r = router_pick_directory_server(1, 0, need_v2_support,
rs = router_pick_directory_server(1, 0, need_v2_support,
retry_if_no_servers);
/* XXXX If no rs, fall back to trusted dir servers? -NM */
}
}
if (r)
directory_initiate_command_router(r, purpose, !directconn,
resource, NULL, 0);
else if (ds)
directory_initiate_command_trusted_dir(ds, purpose, !directconn,
if (rs)
directory_initiate_command_routerstatus(rs, purpose, !directconn,
resource, NULL, 0);
else {
notice(LD_DIR,
@ -247,27 +242,55 @@ directory_get_from_dirserver(uint8_t purpose, const char *resource,
* want to fetch.
*/
void
directory_initiate_command_router(routerinfo_t *router, uint8_t purpose,
int private_connection, const char *resource,
const char *payload, size_t payload_len)
directory_initiate_command_router(routerinfo_t *router,
uint8_t purpose,
int private_connection,
const char *resource,
const char *payload,
size_t payload_len)
{
directory_initiate_command(router->address, router->addr, router->dir_port,
router->platform, router->cache_info.identity_digest,
router->platform,
router->cache_info.identity_digest,
purpose, private_connection, resource,
payload, payload_len);
}
/** As directory_initiate_command_router, but send the command to a trusted
* directory server <b>dirserv</b>. **/
static void
directory_initiate_command_trusted_dir(trusted_dir_server_t *dirserv,
uint8_t purpose, int private_connection,
/** Launch a new connection to the directory server <b>status</b> to upload or
* download a service or rendezvous descriptor. <b>purpose</b> determines what
* kind of directory connection we're launching, and must be one of
* DIR_PURPOSE_{FETCH|UPLOAD}_{DIR|RENDDESC}.
*
* When uploading, <b>payload</b> and <b>payload_len</b> determine the content
* of the HTTP post. Otherwise, <b>payload</b> should be NULL.
*
* When fetching a rendezvous descriptor, <b>resource</b> is the service ID we
* want to fetch.
*/
void
directory_initiate_command_routerstatus(routerstatus_t *status,
uint8_t purpose,
int private_connection,
const char *resource,
const char *payload, size_t payload_len)
const char *payload,
size_t payload_len)
{
directory_initiate_command(dirserv->address, dirserv->addr,
dirserv->dir_port, NULL, dirserv->digest, purpose,
private_connection, resource,
const char *platform = NULL;
routerinfo_t *router;
char address_buf[INET_NTOA_BUF_LEN];
struct in_addr in;
const char *address;
if ((router = router_get_by_digest(status->identity_digest))) {
platform = router->platform;
address = router->address;
} else {
in.s_addr = htonl(status->addr);
tor_inet_ntoa(&in, address_buf, sizeof(address_buf));
address = address_buf;
}
directory_initiate_command(address, status->addr, status->dir_port,
platform, status->identity_digest,
purpose, private_connection, resource,
payload, payload_len);
}

View File

@ -1822,6 +1822,12 @@ void directory_initiate_command_router(routerinfo_t *router, uint8_t purpose,
const char *resource,
const char *payload,
size_t payload_len);
void directory_initiate_command_routerstatus(routerstatus_t *status,
uint8_t purpose,
int private_connection,
const char *resource,
const char *payload,
size_t payload_len);
int parse_http_response(const char *headers, int *code, time_t *date,
int *compression, char **response);
@ -2183,21 +2189,23 @@ typedef struct trusted_dir_server_t {
uint16_t dir_port; /**< Directory port */
char digest[DIGEST_LEN]; /**< Digest of identity key */
unsigned int is_running:1; /**< True iff we think this server is running. */
unsigned int supports_v1_protocol:1; /**< True iff this server is an
unsigned int is_v1_authority:1; /**< True iff this server is an
* authority for the older ("v1")
* directory protocol.*/
int n_networkstatus_failures; /**< How many times have we asked for this
* server's network-status unsuccessfully? */
routerstatus_t fake_status; /**< Used when we need to pass this trusted
* dir_server_t as a routerstatus_t. */
} trusted_dir_server_t;
int router_reload_router_list(void);
int router_reload_networkstatus(void);
void router_get_trusted_dir_servers(smartlist_t **outp);
routerinfo_t *router_pick_directory_server(int requireother,
routerstatus_t *router_pick_directory_server(int requireother,
int fascistfirewall,
int for_v2_directory,
int retry_if_no_servers);
trusted_dir_server_t *router_pick_trusteddirserver(int need_v1_support,
routerstatus_t *router_pick_trusteddirserver(int need_v1_authority,
int requireother,
int fascistfirewall,
int retry_if_no_servers);

View File

@ -3,7 +3,8 @@
* Copyright 2004-2005 Roger Dingledine, Nick Mathewson. */
/* See LICENSE for licensing information */
/* $Id$ */
const char relay_c_id[] = "$Id$";
const char relay_c_id[] =
"$Id$";
/**
* \file relay.c

View File

@ -18,11 +18,11 @@ const char routerlist_c_id[] =
/****************************************************************************/
/* static function prototypes */
static routerinfo_t *router_pick_directory_server_impl(int requireother,
static routerstatus_t *router_pick_directory_server_impl(int requireother,
int fascistfirewall,
int for_v2_directory);
static trusted_dir_server_t *router_pick_trusteddirserver_impl(
int need_v1_support, int requireother, int fascistfirewall);
static routerstatus_t *router_pick_trusteddirserver_impl(
int need_v1_authority, int requireother, int fascistfirewall);
static void mark_all_trusteddirservers_up(void);
static int router_nickname_is_in_list(routerinfo_t *router, const char *list);
static int router_nickname_matches(routerinfo_t *router, const char *nickname);
@ -321,13 +321,13 @@ router_get_trusted_dir_servers(smartlist_t **outp)
* (that is, a trusted dirserver, or one running 0.0.9rc5-cvs or later).
* Other args are as in router_pick_directory_server_impl().
*/
routerinfo_t *
routerstatus_t *
router_pick_directory_server(int requireother,
int fascistfirewall,
int for_v2_directory,
int retry_if_no_servers)
{
routerinfo_t *choice;
routerstatus_t *choice;
if (!routerlist)
return NULL;
@ -358,6 +358,9 @@ router_pick_directory_server(int requireother,
return choice;
}
/** 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.
*/
trusted_dir_server_t *
router_get_trusteddirserver_by_digest(const char *digest)
{
@ -376,24 +379,26 @@ router_get_trusteddirserver_by_digest(const char *digest)
/** 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.
* If <b>need_v1_authority</b> is set, return only trusted servers
* that are authorities for the V1 directory protocol.
* Other args are as in router_pick_trusteddirserver_impl().
*/
trusted_dir_server_t *
router_pick_trusteddirserver(int need_v1_support,
routerstatus_t *
router_pick_trusteddirserver(int need_v1_authority,
int requireother,
int fascistfirewall,
int retry_if_no_servers)
{
trusted_dir_server_t *choice;
routerstatus_t *choice;
choice = router_pick_trusteddirserver_impl(need_v1_support,
choice = router_pick_trusteddirserver_impl(need_v1_authority,
requireother, fascistfirewall);
if (choice || !retry_if_no_servers)
return choice;
info(LD_DIR,"No trusted dirservers are reachable. Trying them all again.");
mark_all_trusteddirservers_up();
return router_pick_trusteddirserver_impl(need_v1_support,
return router_pick_trusteddirserver_impl(need_v1_authority,
requireother, fascistfirewall);
}
@ -405,37 +410,34 @@ router_pick_trusteddirserver(int need_v1_support,
* choose a directory server new enough to support the v2 directory
* functionality.
*/
static routerinfo_t *
static routerstatus_t *
router_pick_directory_server_impl(int requireother, int fascistfirewall,
int for_v2_directory)
{
routerinfo_t *result;
routerstatus_t *result;
smartlist_t *sl;
if (!routerlist)
if (!routerstatus_list)
return NULL;
/* Find all the running dirservers we know about. */
sl = smartlist_create();
SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router,
SMARTLIST_FOREACH(routerstatus_list, local_routerstatus_t *, _local_status,
{
if (!router->is_running || !router->dir_port || !router->is_verified)
routerstatus_t *status = &(_local_status->status);
if (!status->is_running || !status->dir_port || !status->is_valid)
continue;
if (requireother && router_is_me(router))
if (requireother && router_digest_is_me(status->identity_digest))
continue;
if (fascistfirewall) {
if (!fascist_firewall_allows_address(router->addr, router->dir_port))
if (!fascist_firewall_allows_address(status->addr, status->dir_port))
continue;
}
/* Before 0.1.1.6-alpha, only trusted dirservers served status info.
* Before 0.1.1.7-alpha, retrieving nonexistent server IDs could bork
* the directory server.
*/
if (for_v2_directory &&
!(tor_version_as_new_as(router->platform,"0.1.1.7-alpha") ||
router_digest_is_trusted_dir(router->cache_info.identity_digest)))
!(status->is_v2_dir ||
router_digest_is_trusted_dir(status->identity_digest)))
continue;
smartlist_add(sl, router);
smartlist_add(sl, status);
});
result = smartlist_choose(sl);
@ -443,19 +445,19 @@ router_pick_directory_server_impl(int requireother, int fascistfirewall,
return result;
}
/** 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_support</b>, choose
* a trusted authority for the v1 directory system.
/** 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.
*/
static trusted_dir_server_t *
router_pick_trusteddirserver_impl(int need_v1_support,
static routerstatus_t *
router_pick_trusteddirserver_impl(int need_v1_authority,
int requireother, int fascistfirewall)
{
smartlist_t *sl;
routerinfo_t *me;
trusted_dir_server_t *ds;
routerstatus_t *rs;
sl = smartlist_create();
me = router_get_my_routerinfo();
@ -465,7 +467,7 @@ router_pick_trusteddirserver_impl(int need_v1_support,
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, d,
{
if (!d->is_running) continue;
if (need_v1_support && !d->supports_v1_protocol)
if (need_v1_authority && !d->is_v1_authority)
continue;
if (requireother && me && router_digest_is_me(d->digest))
continue;
@ -473,12 +475,12 @@ router_pick_trusteddirserver_impl(int need_v1_support,
if (!fascist_firewall_allows_address(d->addr, d->dir_port))
continue;
}
smartlist_add(sl, d);
smartlist_add(sl, &d->fake_status);
});
ds = smartlist_choose(sl);
rs = smartlist_choose(sl);
smartlist_free(sl);
return ds;
return rs;
}
/** Go through and mark the authoritative dirservers as up. */
@ -2526,7 +2528,7 @@ add_trusted_dir_server(const char *nickname, const char *address,
ent->addr = a;
ent->dir_port = port;
ent->is_running = 1;
ent->supports_v1_protocol = supports_v1;
ent->is_v1_authority = supports_v1;
memcpy(ent->digest, digest, DIGEST_LEN);
dlen = 64 + strlen(hostname) + (nickname?strlen(nickname):0);
@ -2538,6 +2540,16 @@ add_trusted_dir_server(const char *nickname, const char *address,
tor_snprintf(ent->description, dlen, "directory server at %s:%d",
hostname, (int)port);
ent->fake_status.addr = ent->addr;
memcpy(ent->fake_status.identity_digest, digest, DIGEST_LEN);
strlcpy(ent->fake_status.nickname, nickname,
sizeof(ent->fake_status.nickname));
ent->fake_status.dir_port = ent->dir_port;
ent->fake_status.is_running = 1;
ent->fake_status.is_named = 1;
ent->fake_status.is_valid = 1;
ent->fake_status.is_v2_dir = 1;
smartlist_add(trusted_dir_servers, ent);
}
@ -2848,6 +2860,7 @@ routerstatus_list_update_from_networkstatus(time_t now)
*/
while (1) {
int n_running=0, n_named=0, n_valid=0, n_listing=0;
int n_v2_dir=0, n_fast=0, n_stable=0, n_exit=0;
const char *the_name = NULL;
local_routerstatus_t *rs_out, *rs_old;
routerstatus_t *rs, *most_recent;
@ -2902,6 +2915,14 @@ routerstatus_list_update_from_networkstatus(time_t now)
++n_valid;
if (rs->is_running && ns->is_recent)
++n_running;
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;
}
rs_out = tor_malloc_zero(sizeof(local_routerstatus_t));
memcpy(&rs_out->status, most_recent, sizeof(routerstatus_t));
@ -2930,6 +2951,10 @@ routerstatus_list_update_from_networkstatus(time_t now)
sizeof(rs_out->status.nickname));
rs_out->status.is_valid = n_valid > n_statuses/2;
rs_out->status.is_running = n_running > n_recent/2;
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;
}
SMARTLIST_FOREACH(routerstatus_list, local_routerstatus_t *, rs,
local_routerstatus_free(rs));