Fall back to direct descriptor request to bridges when

requests to authorities fail due to a network error.

Bug#1138
"When a Tor client starts up using a bridge, and UpdateBridgesFromAuthority
is set, Tor will go to the authority first and look up the bridge by
fingerprint. If the bridge authority is filtered, Tor will never notice that
the bridge authority lookup failed. So it will never fall back."

Add connection_dir_bridge_routerdesc_failed(), a function for unpacking
the bridge information from a failed request, and ensure
connection_dir_request_failed() calls it if the failed request
was for a bridge descriptor.

Test:

1. for ip in `grep -iR 'router ' cached-descriptors|cut -d ' ' -f 3`;
do sudo iptables -A OUTPUT -p tcp -d $ip -j DROP; done
2. remove all files from user tor directory
3. Put the following in torrc:

UseBridges 1
UpdateBridgesFromAuthority 1
Bridge 85.108.88.19:443 7E1B28DB47C175392A0E8E4A287C7CB8686575B7

4. Launch tor - it should fall back to downloading descriptors
   directly from the bridge.

Initial patch reviewed and corrected by mingw-san.
This commit is contained in:
Robert Hogan 2010-08-10 22:07:50 +01:00
parent a207d9db4c
commit d6744d611f
2 changed files with 57 additions and 12 deletions

5
changes/bug1138 Normal file
View File

@ -0,0 +1,5 @@
o Major bugfixes:
- Fall back to direct descriptor request to bridges when
requests to authorities fail due to a network error.
Bugfix in 0.2.1.19, closes bug 1138.

View File

@ -67,8 +67,10 @@ static void http_set_address_origin(const char *headers, connection_t *conn);
static void connection_dir_download_networkstatus_failed( static void connection_dir_download_networkstatus_failed(
dir_connection_t *conn, int status_code); dir_connection_t *conn, int status_code);
static void connection_dir_download_routerdesc_failed(dir_connection_t *conn); static void connection_dir_download_routerdesc_failed(dir_connection_t *conn);
static void connection_dir_bridge_routerdesc_failed(dir_connection_t *conn);
static void connection_dir_download_cert_failed( static void connection_dir_download_cert_failed(
dir_connection_t *conn, int status_code); dir_connection_t *conn, int status_code);
static void connection_dir_retry_bridges(smartlist_t* failed, int was_ei);
static void dir_networkstatus_download_failed(smartlist_t *failed, static void dir_networkstatus_download_failed(smartlist_t *failed,
int status_code); int status_code);
static void dir_routerdesc_download_failed(smartlist_t *failed, static void dir_routerdesc_download_failed(smartlist_t *failed,
@ -592,6 +594,8 @@ connection_dir_request_failed(dir_connection_t *conn)
conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) { conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) {
log_info(LD_DIR, "Giving up on directory server at '%s'; retrying", log_info(LD_DIR, "Giving up on directory server at '%s'; retrying",
conn->_base.address); conn->_base.address);
if (conn->router_purpose == ROUTER_PURPOSE_BRIDGE)
connection_dir_bridge_routerdesc_failed(conn);
connection_dir_download_routerdesc_failed(conn); connection_dir_download_routerdesc_failed(conn);
} else if (conn->_base.purpose == DIR_PURPOSE_FETCH_CONSENSUS) { } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_CONSENSUS) {
networkstatus_consensus_download_failed(0); networkstatus_consensus_download_failed(0);
@ -645,6 +649,25 @@ connection_dir_download_networkstatus_failed(dir_connection_t *conn,
} }
} }
/** Helper: Attempt to fetch directly the descriptors of each bridge
* listed in <b>failed</b>.
*/
static void
connection_dir_retry_bridges(smartlist_t* failed, int was_ei)
{
char digest[DIGEST_LEN];
tor_assert(!was_ei); /* not supported yet */
SMARTLIST_FOREACH(failed, const char *, cp,
{
if (base16_decode(digest, DIGEST_LEN, cp, strlen(cp))<0) {
log_warn(LD_BUG, "Malformed fingerprint in list: %s",
escaped(cp));
continue;
}
retry_bridge_descriptor_fetch_directly(digest);
});
}
/** Called when an attempt to download one or more router descriptors /** Called when an attempt to download one or more router descriptors
* or extra-info documents on connection <b>conn</b> failed. * or extra-info documents on connection <b>conn</b> failed.
*/ */
@ -662,6 +685,33 @@ connection_dir_download_routerdesc_failed(dir_connection_t *conn)
(void) conn; (void) conn;
} }
/** Called when an attempt to download a bridge's routerdesc from
* one of the authorities failed due to a network error. If
* possible attempt to download descriptors from the bridge directly.
*/
static void
connection_dir_bridge_routerdesc_failed(dir_connection_t *conn)
{
int was_ei;
smartlist_t *which = NULL;
/* Requests for bridge descriptors are in the form 'fp/', so ignore
anything else. */
if (conn->requested_resource && strcmpstart(conn->requested_resource,"fp/"))
return;
which = smartlist_create();
dir_split_resource_into_fingerprints(conn->requested_resource + 3,
which, NULL, 0);
was_ei = conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO;
if (smartlist_len(which)) {
connection_dir_retry_bridges(which, was_ei);
SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
}
smartlist_free(which);
}
/** Called when an attempt to fetch a certificate fails. */ /** Called when an attempt to fetch a certificate fails. */
static void static void
connection_dir_download_cert_failed(dir_connection_t *conn, int status) connection_dir_download_cert_failed(dir_connection_t *conn, int status)
@ -3498,18 +3548,8 @@ dir_routerdesc_download_failed(smartlist_t *failed, int status_code,
time_t now = time(NULL); time_t now = time(NULL);
int server = directory_fetches_from_authorities(get_options()); int server = directory_fetches_from_authorities(get_options());
if (!was_descriptor_digests) { if (!was_descriptor_digests) {
if (router_purpose == ROUTER_PURPOSE_BRIDGE) { if (router_purpose == ROUTER_PURPOSE_BRIDGE)
tor_assert(!was_extrainfo); /* not supported yet */ connection_dir_retry_bridges(failed, was_extrainfo);
SMARTLIST_FOREACH(failed, const char *, cp,
{
if (base16_decode(digest, DIGEST_LEN, cp, strlen(cp))<0) {
log_warn(LD_BUG, "Malformed fingerprint in list: %s",
escaped(cp));
continue;
}
retry_bridge_descriptor_fetch_directly(digest);
});
}
return; /* FFFF should implement for other-than-router-purpose someday */ return; /* FFFF should implement for other-than-router-purpose someday */
} }
SMARTLIST_FOREACH(failed, const char *, cp, SMARTLIST_FOREACH(failed, const char *, cp,