use microdescriptors if *any* of our bridges can handle them

Now as we move into a future where most bridges can handle microdescs
we will generally find ourselves using them, rather than holding back
just because one of our bridges doesn't use them.
This commit is contained in:
Roger Dingledine 2012-01-25 20:18:51 -05:00 committed by Andrea Shepard
parent acb43c0735
commit a8297cdbd3
6 changed files with 60 additions and 30 deletions

7
changes/feature4994 Normal file
View File

@ -0,0 +1,7 @@
o Minor features:
- Teach bridge-using clients to avoid 0.2.2 bridges when making
microdescriptor-related dir requests, and only fall back to normal
descriptors if none of their bridges can handle microdescriptors
(as opposed to the fix in ticket 4013, which caused them to fall
back to normal descriptors if *any* of their bridges preferred
them). Resolves ticket 4994.

View File

@ -25,6 +25,7 @@
#include "directory.h"
#include "entrynodes.h"
#include "main.h"
#include "microdesc.h"
#include "networkstatus.h"
#include "nodelist.h"
#include "onion.h"
@ -3372,7 +3373,7 @@ choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state)
(purpose != CIRCUIT_PURPOSE_TESTING || options->BridgeRelay)) {
/* This request is for an entry server to use for a regular circuit,
* and we use entry guard nodes. Just return one of the guard nodes. */
return choose_random_entry(state);
return choose_random_entry(state, 0);
}
excluded = smartlist_new();

View File

@ -472,12 +472,14 @@ directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
if (options->UseBridges && type != BRIDGE_DIRINFO) {
/* We want to ask a running bridge for which we have a descriptor.
*
* Be careful here: we should only ask questions that we know our
* bridges can answer. So far we're solving that by backing off to
* the behavior supported by our oldest bridge; see for example
* any_bridges_dont_support_microdescriptors().
* When we ask choose_random_entry() for a bridge, we specify that
* we're going to be using it for a dir fetch: if any of our bridges
* can handle microdescriptor questions, we'll get one of the ones
* that can.
*/
const node_t *node = choose_random_entry(NULL);
/* XXX024 Not all bridges handle conditional consensus downloading,
* so, for now, never assume the server supports that. -PP */
const node_t *node = choose_random_entry(NULL, 1);
if (node && node->ri) {
/* every bridge has a routerinfo. */
tor_addr_t addr;

View File

@ -23,6 +23,7 @@
#include "directory.h"
#include "entrynodes.h"
#include "main.h"
#include "microdesc.h"
#include "nodelist.h"
#include "policies.h"
#include "router.h"
@ -63,7 +64,8 @@ static int entry_guards_dirty = 0;
static void bridge_free(bridge_info_t *bridge);
static const node_t *choose_random_entry_impl(cpath_build_state_t *state,
int for_directory,
dirinfo_type_t dirtype);
dirinfo_type_t dirtype,
int prefer_microdescs);
/** Return the list of entry guards, creating it if necessary. */
const smartlist_t *
@ -829,15 +831,33 @@ entry_list_is_constrained(const or_options_t *options)
return 0;
}
/** Return true iff this node can answer directory questions about
* microdescriptors. */
static int
node_understands_microdescriptors(const node_t *node)
{
tor_assert(node);
if (node->rs && node->rs->version_supports_microdesc_cache)
return 1;
if (node->ri && tor_version_supports_microdescriptors(node->ri->platform))
return 1;
return 0;
}
/** Pick a live (up and listed) entry guard from entry_guards. If
* <b>state</b> is non-NULL, this is for a specific circuit --
* make sure not to pick this circuit's exit or any node in the
* exit's family. If <b>state</b> is NULL, we're looking for a random
* guard (likely a bridge). */
* guard (likely a bridge).
*
* If the prefer_microdescs flag is set, we are looking for a bridge to
* use for directory fetching and pick a bridge that supports microdescriptors
* if we know any that do so.
*/
const node_t *
choose_random_entry(cpath_build_state_t *state)
choose_random_entry(cpath_build_state_t *state, int prefer_microdescs)
{
return choose_random_entry_impl(state, 0, 0);
return choose_random_entry_impl(state, 0, 0, prefer_microdescs);
}
/** Pick a live (up and listed) directory guard from entry_guards for
@ -845,13 +865,13 @@ choose_random_entry(cpath_build_state_t *state)
const node_t *
choose_random_dirguard(dirinfo_type_t type)
{
return choose_random_entry_impl(NULL, 1, type);
return choose_random_entry_impl(NULL, 1, type, 0);
}
/** Helper for choose_random{entry,dirguard}. */
static const node_t *
choose_random_entry_impl(cpath_build_state_t *state, int for_directory,
dirinfo_type_t dirinfo_type)
dirinfo_type_t dirinfo_type, int prefer_microdescs)
{
const or_options_t *options = get_options();
smartlist_t *live_entry_guards = smartlist_new();
@ -903,6 +923,10 @@ choose_random_entry_impl(cpath_build_state_t *state, int for_directory,
continue; /* don't pick the same node for entry and exit */
if (consider_exit_family && smartlist_contains(exit_family, node))
continue; /* avoid relays that are family members of our exit */
if (prefer_microdescs &&
we_use_microdescriptors_for_circuits(options) &&
!node_understands_microdescriptors(node))
continue; /* this node won't be able to answer our dir questions */
#if 0 /* since EntryNodes is always strict now, this clause is moot */
if (options->EntryNodes &&
!routerset_contains_node(options->EntryNodes, node)) {
@ -1982,7 +2006,7 @@ int
any_bridge_descriptors_known(void)
{
tor_assert(get_options()->UseBridges);
return choose_random_entry(NULL)!=NULL ? 1 : 0;
return choose_random_entry(NULL, 0)!=NULL ? 1 : 0;
}
/** Return 1 if there are any directory conns fetching bridge descriptors
@ -2064,29 +2088,24 @@ entries_retry_all(const or_options_t *options)
entries_retry_helper(options, 1);
}
/** Return true if we've ever had a bridge running a Tor version that can't
* provide microdescriptors to us. In that case fall back to asking for
* full descriptors. Eventually all bridges will support microdescriptors
* and we can take this check out; see bug 4013. */
/** Return true if at least one of our bridges runs a Tor version that can
* provide microdescriptors to us. If not, we'll fall back to asking for
* full descriptors. */
int
any_bridges_dont_support_microdescriptors(void)
any_bridge_supports_microdescriptors(void)
{
const node_t *node;
static int ever_answered_yes = 0;
if (!get_options()->UseBridges || !entry_guards)
return 0;
if (ever_answered_yes)
return 1; /* if we ever answer 'yes', always answer 'yes' */
SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
node = node_get_by_id(e->identity);
if (node && node->ri &&
if (node && node->is_running &&
node_is_bridge(node) && node_is_a_configured_bridge(node) &&
!tor_version_supports_microdescriptors(node->ri->platform)) {
node_understands_microdescriptors(node)) {
/* This is one of our current bridges, and we know enough about
* it to know that it won't be able to answer our microdescriptor
* it to know that it will be able to answer our microdescriptor
* questions. */
ever_answered_yes = 1;
return 1;
return 1;
}
} SMARTLIST_FOREACH_END(e);
return 0;

View File

@ -78,7 +78,8 @@ int entry_guard_register_connect_status(const char *digest, int succeeded,
int mark_relay_status, time_t now);
void entry_nodes_should_be_added(void);
int entry_list_is_constrained(const or_options_t *options);
const node_t *choose_random_entry(cpath_build_state_t *state);
const node_t *choose_random_entry(cpath_build_state_t *state,
int prefer_microdescs);
const node_t *choose_random_dirguard(dirinfo_type_t t);
int entry_guards_parse_state(or_state_t *state, int set, char **msg);
void entry_guards_update_state(or_state_t *state);
@ -104,7 +105,7 @@ int any_pending_bridge_descriptor_fetches(void);
int entries_known_but_down(const or_options_t *options);
void entries_retry_all(const or_options_t *options);
int any_bridges_dont_support_microdescriptors(void);
int any_bridge_supports_microdescriptors(void);
void entry_guards_free_all(void);

View File

@ -730,9 +730,9 @@ we_use_microdescriptors_for_circuits(const or_options_t *options)
int ret = options->UseMicrodescriptors;
if (ret == -1) {
/* UseMicrodescriptors is "auto"; we need to decide: */
/* If we are configured to use bridges and one of our bridges doesn't
/* If we are configured to use bridges and none of our bridges
* know what a microdescriptor is, the answer is no. */
if (options->UseBridges && any_bridges_dont_support_microdescriptors())
if (options->UseBridges && !any_bridge_supports_microdescriptors())
return 0;
/* Otherwise, we decide that we'll use microdescriptors iff we are
* not a server, and we're not autofetching everything. */