From d6744d611f933e77398ed80ac45cabfec16430c1 Mon Sep 17 00:00:00 2001 From: Robert Hogan Date: Tue, 10 Aug 2010 22:07:50 +0100 Subject: [PATCH] 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. --- changes/bug1138 | 5 ++++ src/or/directory.c | 64 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 57 insertions(+), 12 deletions(-) create mode 100644 changes/bug1138 diff --git a/changes/bug1138 b/changes/bug1138 new file mode 100644 index 0000000000..ffb83bd4be --- /dev/null +++ b/changes/bug1138 @@ -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. + diff --git a/src/or/directory.c b/src/or/directory.c index a3e575ac97..11dce8ca71 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -67,8 +67,10 @@ static void http_set_address_origin(const char *headers, connection_t *conn); static void connection_dir_download_networkstatus_failed( dir_connection_t *conn, int status_code); 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( 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, int status_code); 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) { log_info(LD_DIR, "Giving up on directory server at '%s'; retrying", conn->_base.address); + if (conn->router_purpose == ROUTER_PURPOSE_BRIDGE) + connection_dir_bridge_routerdesc_failed(conn); connection_dir_download_routerdesc_failed(conn); } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_CONSENSUS) { 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 failed. + */ +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 * or extra-info documents on connection conn failed. */ @@ -662,6 +685,33 @@ connection_dir_download_routerdesc_failed(dir_connection_t *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. */ static void 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); int server = directory_fetches_from_authorities(get_options()); if (!was_descriptor_digests) { - if (router_purpose == ROUTER_PURPOSE_BRIDGE) { - tor_assert(!was_extrainfo); /* 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); - }); - } + if (router_purpose == ROUTER_PURPOSE_BRIDGE) + connection_dir_retry_bridges(failed, was_extrainfo); return; /* FFFF should implement for other-than-router-purpose someday */ } SMARTLIST_FOREACH(failed, const char *, cp,