From 9482b1b9d5aa892aad997799be7dadbc94856371 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 14 Dec 2005 22:00:58 +0000 Subject: [PATCH] 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 --- doc/TODO | 4 +- src/common/ht.h | 2 +- src/or/directory.c | 109 +++++++++++++++++++++++++++----------------- src/or/or.h | 30 +++++++----- src/or/relay.c | 3 +- src/or/routerlist.c | 103 +++++++++++++++++++++++++---------------- 6 files changed, 154 insertions(+), 97 deletions(-) diff --git a/doc/TODO b/doc/TODO index 99c70b372f..083e9f090b 100644 --- a/doc/TODO +++ b/doc/TODO @@ -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? diff --git a/src/common/ht.h b/src/common/ht.h index e50ada29c5..d2be68322c 100644 --- a/src/common/ht.h +++ b/src/common/ht.h @@ -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; \ diff --git a/src/or/directory.c b/src/or/directory.c index 4fbad1583e..b2244e53f7 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -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,10 +138,11 @@ 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, - NULL, payload, payload_len); + 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, - retry_if_no_servers); - if (!r) { + rs = router_pick_directory_server(1, 1, need_v2_support, + retry_if_no_servers); + 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,20 +207,18 @@ 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, - retry_if_no_servers); + 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, - resource, NULL, 0); + if (rs) + directory_initiate_command_routerstatus(rs, purpose, !directconn, + resource, NULL, 0); else { notice(LD_DIR, "No running dirservers known. Will try again later. (purpose %d)", @@ -247,28 +242,56 @@ 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, - purpose, private_connection, resource, - payload, payload_len); + 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 dirserv. **/ -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) +/** Launch a new connection to the directory server status to upload or + * download a service or rendezvous descriptor. purpose determines what + * kind of directory connection we're launching, and must be one of + * DIR_PURPOSE_{FETCH|UPLOAD}_{DIR|RENDDESC}. + * + * When uploading, payload and payload_len determine the content + * of the HTTP post. Otherwise, payload should be NULL. + * + * When fetching a rendezvous descriptor, resource 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) { - directory_initiate_command(dirserv->address, dirserv->addr, - dirserv->dir_port, NULL, dirserv->digest, purpose, - private_connection, resource, - payload, payload_len); + 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); } /** Called when we are unable to complete the client's request to a diff --git a/src/or/or.h b/src/or/or.h index 128abf5e0a..e716c209b0 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -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,24 +2189,26 @@ 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 - * authority for the older ("v1") - * directory protocol.*/ + 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, - int fascistfirewall, - int for_v2_directory, - int retry_if_no_servers); -trusted_dir_server_t *router_pick_trusteddirserver(int need_v1_support, - int requireother, - int fascistfirewall, - int retry_if_no_servers); +routerstatus_t *router_pick_directory_server(int requireother, + int fascistfirewall, + int for_v2_directory, + int retry_if_no_servers); +routerstatus_t *router_pick_trusteddirserver(int need_v1_authority, + int requireother, + int fascistfirewall, + int retry_if_no_servers); trusted_dir_server_t *router_get_trusteddirserver_by_digest( const char *digest); int all_trusted_directory_servers_down(void); diff --git a/src/or/relay.c b/src/or/relay.c index 529c149715..028261078f 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -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 diff --git a/src/or/routerlist.c b/src/or/routerlist.c index b90e790cb3..c2c835c76a 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -18,11 +18,11 @@ const char routerlist_c_id[] = /****************************************************************************/ /* static function prototypes */ -static routerinfo_t *router_pick_directory_server_impl(int requireother, - int fascistfirewall, - int for_v2_directory); -static trusted_dir_server_t *router_pick_trusteddirserver_impl( - int need_v1_support, int requireother, int fascistfirewall); +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); 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 digest, 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 retry_if_no_servers is non-zero, * set them all as running again, and try again. + * If need_v1_authority 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 fascistfirewall, - * make sure the port we pick is allowed by our firewall options. - * If requireother, it cannot be us. If need_v1_support, choose - * a trusted authority for the v1 directory system. +/** Choose randomly from among the trusted dirservers that are up. If + * fascistfirewall, make sure the port we pick is allowed by our + * firewall options. If requireother, it cannot be us. If + * need_v1_authority, 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));