Allow 0.2.3.x clients to use 0.2.2.x bridges.

Previously the client would ask the bridge for microdescriptors, which are
only supported in 0.2.3.x and later, and then fail to bootstrap when it
didn't get the answers it wanted. Fixes bug 4013; bugfix on 0.2.3.2-alpha.

The fix here is to revert to using normal descriptors if any of our
bridges are known to not support microdescs. This is not ideal, a) because
we'll start downloading a microdesc consensus as soon as we get a bridge
descriptor, and that will waste time if we later get a bridge descriptor
that tells us we don't like microdescriptors; and b) by changing our mind
we're leaking to our other bridges that we have an old-version bridge.

The alternate fix would have been to change
we_use_microdescriptors_for_circuits() to ask if *any* of our bridges
can support microdescriptors, and then change the directory logic that
picks a bridge to only select from those that do. For people living in
the future, where 0.2.2.x is obsolete, there won't be a difference.

Note that in either of these potential fixes, we have risk of oscillation
if our one funny-looking bridges goes away / comes back.
This commit is contained in:
Roger Dingledine 2012-01-25 18:54:59 -05:00
parent 247a21379a
commit a0f0897795
7 changed files with 61 additions and 16 deletions

6
changes/bug4013 Normal file
View File

@ -0,0 +1,6 @@
o Major bugfixes:
- Allow 0.2.3.x clients to use 0.2.2.x bridges. Previously the client
would ask the bridge for microdescriptors, which are only supported
in 0.2.3.x and later, and then fail to bootstrap when it didn't
get the answers it wanted. Fixes bug 4013; bugfix on 0.2.3.2-alpha.

View File

@ -3339,7 +3339,7 @@ extend_info_from_router(const routerinfo_t *r, int for_direct_connect)
} }
/** Allocate and return a new extend_info that can be used to build a /** Allocate and return a new extend_info that can be used to build a
* ircuit to or through the node <b>node</b>. Use the primary address * circuit to or through the node <b>node</b>. Use the primary address
* of the node unless <b>for_direct_connect</b> is true, in which case * of the node unless <b>for_direct_connect</b> is true, in which case
* the preferred address is used instead. May return NULL if there is * the preferred address is used instead. May return NULL if there is
* not enough info about <b>node</b> to extend to it--for example, if * not enough info about <b>node</b> to extend to it--for example, if
@ -5328,6 +5328,30 @@ entries_retry_all(const or_options_t *options)
entries_retry_helper(options, 1); entries_retry_helper(options, 1);
} }
/** Return true if one of our bridges is 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. */
int
any_bridges_dont_support_microdescriptors(void)
{
const node_t *node;
if (!get_options()->UseBridges || !entry_guards)
return 0;
SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
node = node_get_by_id(e->identity);
if (node && node->ri &&
node_is_bridge(node) && node_is_a_configured_bridge(node) &&
!tor_version_supports_microdescriptors(node->ri->platform)) {
/* 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
* questions. */
return 1;
}
} SMARTLIST_FOREACH_END(e);
return 0;
}
/** Release all storage held by the list of entry guards and related /** Release all storage held by the list of entry guards and related
* memory structs. */ * memory structs. */
void void

View File

@ -100,6 +100,8 @@ int any_pending_bridge_descriptor_fetches(void);
int entries_known_but_down(const or_options_t *options); int entries_known_but_down(const or_options_t *options);
void entries_retry_all(const or_options_t *options); void entries_retry_all(const or_options_t *options);
int any_bridges_dont_support_microdescriptors(void);
void entry_guards_free_all(void); void entry_guards_free_all(void);
extern circuit_build_times_t circ_times; extern circuit_build_times_t circ_times;

View File

@ -421,11 +421,15 @@ directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
if (!get_via_tor) { if (!get_via_tor) {
if (options->UseBridges && type != BRIDGE_DIRINFO) { if (options->UseBridges && type != BRIDGE_DIRINFO) {
/* want to ask a running bridge for which we have a descriptor. */ /* We want to ask a running bridge for which we have a descriptor.
/* XXX023 we assume that all of our bridges can answer any *
* possible directory question. This won't be true forever. -RD */ * Be careful here: we should only ask questions that we know our
/* It certainly is not true with conditional consensus downloading, * bridges can answer. So far we're solving that by backing off to
* so, for now, never assume the server supports that. */ * the behavior supported by our oldest bridge; see for example
* any_bridges_dont_support_microdescriptors().
*/
/* 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); const node_t *node = choose_random_entry(NULL);
if (node && node->ri) { if (node && node->ri) {
/* every bridge has a routerinfo. */ /* every bridge has a routerinfo. */

View File

@ -2,6 +2,7 @@
/* See LICENSE for licensing information */ /* See LICENSE for licensing information */
#include "or.h" #include "or.h"
#include "circuitbuild.h"
#include "config.h" #include "config.h"
#include "directory.h" #include "directory.h"
#include "dirserv.h" #include "dirserv.h"
@ -720,8 +721,14 @@ we_use_microdescriptors_for_circuits(const or_options_t *options)
int ret = options->UseMicrodescriptors; int ret = options->UseMicrodescriptors;
if (ret == -1) { if (ret == -1) {
/* UseMicrodescriptors is "auto"; we need to decide: */ /* UseMicrodescriptors is "auto"; we need to decide: */
/* So we decide that we'll use microdescriptors iff we are not a server, /* If we are configured to use bridges and one of our bridges doesn't
* and we're not autofetching everything. */ * know what a microdescriptor is, the answer is no. */
if (options->UseBridges && any_bridges_dont_support_microdescriptors())
return 0;
/* Otherwise, we decide that we'll use microdescriptors iff we are
* not a server, and we're not autofetching everything. */
/* XXX023 what does not being a server have to do with it? also there's
* a partitioning issue here where bridges differ from clients. */
ret = !server_mode(options) && !options->FetchUselessDescriptors; ret = !server_mode(options) && !options->FetchUselessDescriptors;
} }
return ret; return ret;

View File

@ -2125,14 +2125,8 @@ routerstatus_parse_entry_from_string(memarea_t *area,
tor_version_as_new_as(tok->args[0], "0.2.0.8-alpha"); tor_version_as_new_as(tok->args[0], "0.2.0.8-alpha");
rs->version_supports_conditional_consensus = rs->version_supports_conditional_consensus =
tor_version_as_new_as(tok->args[0], "0.2.1.1-alpha"); tor_version_as_new_as(tok->args[0], "0.2.1.1-alpha");
/* XXXX023 NM microdescs: 0.2.3.1-alpha isn't widely used yet, but
* not all 0.2.3.0-alpha "versions" actually support microdesc cacheing
* right. There's a compromise here. Since this is 5 May, let's
* err on the side of having some possible caches to use. Once more
* caches are running 0.2.3.1-alpha, we can bump this version number.
*/
rs->version_supports_microdesc_cache = rs->version_supports_microdesc_cache =
tor_version_as_new_as(tok->args[0], "0.2.3.0-alpha"); tor_version_supports_microdescriptors(tok->args[0]);
rs->version_supports_optimistic_data = rs->version_supports_optimistic_data =
tor_version_as_new_as(tok->args[0], "0.2.3.1-alpha"); tor_version_as_new_as(tok->args[0], "0.2.3.1-alpha");
} }
@ -4431,6 +4425,13 @@ microdescs_parse_from_string(const char *s, const char *eos,
return result; return result;
} }
/** Return true iff this Tor version can answer directory questions
* about microdescriptors. */
int tor_version_supports_microdescriptors(const char *platform)
{
return tor_version_as_new_as(platform, "0.2.3.1-alpha");
}
/** Parse the Tor version of the platform string <b>platform</b>, /** Parse the Tor version of the platform string <b>platform</b>,
* and compare it to the version in <b>cutoff</b>. Return 1 if * and compare it to the version in <b>cutoff</b>. Return 1 if
* the router is at least as new as the cutoff, else return 0. * the router is at least as new as the cutoff, else return 0.

View File

@ -44,8 +44,9 @@ addr_policy_t *router_parse_addr_policy_item_from_string(const char *s,
int assume_action); int assume_action);
version_status_t tor_version_is_obsolete(const char *myversion, version_status_t tor_version_is_obsolete(const char *myversion,
const char *versionlist); const char *versionlist);
int tor_version_parse(const char *s, tor_version_t *out); int tor_version_supports_microdescriptors(const char *platform);
int tor_version_as_new_as(const char *platform, const char *cutoff); int tor_version_as_new_as(const char *platform, const char *cutoff);
int tor_version_parse(const char *s, tor_version_t *out);
int tor_version_compare(tor_version_t *a, tor_version_t *b); int tor_version_compare(tor_version_t *a, tor_version_t *b);
int tor_version_same_series(tor_version_t *a, tor_version_t *b); int tor_version_same_series(tor_version_t *a, tor_version_t *b);
void sort_version_list(smartlist_t *lst, int remove_duplicates); void sort_version_list(smartlist_t *lst, int remove_duplicates);