commit 8cc528c75067567ef32822e5bdb39535cea5d5e8 Author: Nick Mathewson nickm@torproject.org Date: Tue Oct 25 19:30:50 2016 -0400
Allow asking a bridge's own descriptor over one-hop connection
When we refactored purpose_needs_anonymity(), we made it so _all_ bridge requests required anonymity. But that missed the case that we are allowed to ask a bridge for its own descriptor.
With this patch, we consider the resource, and allow "authority.z" ("your own descriptor, compressed") for a bridge's server descriptor to be non-anonymous.
Fix for bug 20410; bug not in any released Tor. --- src/or/connection_edge.c | 4 +++- src/or/directory.c | 22 ++++++++++++++------ src/or/directory.h | 3 ++- src/or/routerlist.c | 3 ++- src/test/test_dir.c | 52 +++++++++++++++++++++++++++++++++--------------- 5 files changed, 59 insertions(+), 25 deletions(-)
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 44dfcef..1ee0c0f 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -2434,7 +2434,9 @@ connection_ap_handshake_send_begin(entry_connection_t *ap_conn) * Otherwise, directory connections are typically one-hop. * This matches the earlier check for directory connection path anonymity * in directory_initiate_command_rend(). */ - if (purpose_needs_anonymity(linked_dir_conn_base->purpose, 0)) { + if (purpose_needs_anonymity(linked_dir_conn_base->purpose, + TO_DIR_CONN(linked_dir_conn_base)->router_purpose, + TO_DIR_CONN(linked_dir_conn_base)->requested_resource)) { assert_circ_anonymity_ok(circ, options); } } else { diff --git a/src/or/directory.c b/src/or/directory.c index facd588..a73680a 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -127,14 +127,23 @@ static void connection_dir_close_consensus_fetches( * specifically been configured to be over an anonymous connection, * or 3) if the router is a bridge */ int -purpose_needs_anonymity(uint8_t dir_purpose, uint8_t router_purpose) +purpose_needs_anonymity(uint8_t dir_purpose, uint8_t router_purpose, + const char *resource) { if (get_options()->AllDirActionsPrivate) return 1;
- if (router_purpose == ROUTER_PURPOSE_BRIDGE) + if (router_purpose == ROUTER_PURPOSE_BRIDGE) { + if (dir_purpose == DIR_PURPOSE_FETCH_SERVERDESC + && resource && !strcmp(resource, "authority.z")) { + /* We are asking a bridge for its own descriptor. That doesn't need + anonymity. */ + return 0; + } + /* Assume all other bridge stuff needs anonymity. */ return 1; /* if no circuits yet, this might break bootstrapping, but it's * needed to be safe. */ + }
switch (dir_purpose) { @@ -364,7 +373,7 @@ directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose, log_info(LD_DIR, "Uploading an extrainfo too (length %d)", (int) extrainfo_len); } - if (purpose_needs_anonymity(dir_purpose, router_purpose)) { + if (purpose_needs_anonymity(dir_purpose, router_purpose, NULL)) { indirection = DIRIND_ANONYMOUS; } else if (!fascist_firewall_allows_dir_server(ds, FIREWALL_DIR_CONNECTION, @@ -458,7 +467,8 @@ MOCK_IMPL(void, directory_get_from_dirserver, ( int prefer_authority = (directory_fetches_from_authorities(options) || want_authority == DL_WANT_AUTHORITY); int require_authority = 0; - int get_via_tor = purpose_needs_anonymity(dir_purpose, router_purpose); + int get_via_tor = purpose_needs_anonymity(dir_purpose, router_purpose, + resource); dirinfo_type_t type = dir_fetch_type(dir_purpose, router_purpose, resource); time_t if_modified_since = 0;
@@ -592,7 +602,7 @@ MOCK_IMPL(void, directory_get_from_dirserver, ( "While fetching directory info, " "no running dirservers known. Will try again later. " "(purpose %d)", dir_purpose); - if (!purpose_needs_anonymity(dir_purpose, router_purpose)) { + if (!purpose_needs_anonymity(dir_purpose, router_purpose, resource)) { /* remember we tried them all and failed. */ directory_all_unreachable(time(NULL)); } @@ -1142,7 +1152,7 @@ directory_initiate_command_rend(const tor_addr_port_t *or_addr_port,
log_debug(LD_DIR, "Initiating %s", dir_conn_purpose_to_string(dir_purpose));
- if (purpose_needs_anonymity(dir_purpose, router_purpose)) { + if (purpose_needs_anonymity(dir_purpose, router_purpose, resource)) { tor_assert(anonymized_connection || rend_non_anonymous_mode_enabled(options)); } diff --git a/src/or/directory.h b/src/or/directory.h index f04e7ab..f1cdd9f 100644 --- a/src/or/directory.h +++ b/src/or/directory.h @@ -132,7 +132,8 @@ int download_status_get_n_failures(const download_status_t *dls); int download_status_get_n_attempts(const download_status_t *dls); time_t download_status_get_next_attempt_at(const download_status_t *dls);
-int purpose_needs_anonymity(uint8_t dir_purpose, uint8_t router_purpose); +int purpose_needs_anonymity(uint8_t dir_purpose, uint8_t router_purpose, + const char *resource);
#ifdef TOR_UNIT_TESTS /* Used only by directory.c and test_dir.c */ diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 83a2587..6f182d3 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -929,7 +929,8 @@ authority_certs_fetch_resource_impl(const char *resource, const routerstatus_t *rs) { const or_options_t *options = get_options(); - int get_via_tor = purpose_needs_anonymity(DIR_PURPOSE_FETCH_CERTIFICATE, 0); + int get_via_tor = purpose_needs_anonymity(DIR_PURPOSE_FETCH_CERTIFICATE, 0, + resource);
/* Make sure bridge clients never connect to anything but a bridge */ if (options->UseBridges) { diff --git a/src/test/test_dir.c b/src/test/test_dir.c index d9c565c..419aa24 100644 --- a/src/test/test_dir.c +++ b/src/test/test_dir.c @@ -3258,7 +3258,7 @@ test_dir_purpose_needs_anonymity_returns_true_by_default(void *arg) (void)arg;
tor_capture_bugs_(1); - tt_int_op(1, ==, purpose_needs_anonymity(0, 0)); + tt_int_op(1, ==, purpose_needs_anonymity(0, 0, NULL)); tt_int_op(1, ==, smartlist_len(tor_get_captured_bug_log_())); tor_end_capture_bugs_(); done: ; @@ -3269,9 +3269,21 @@ test_dir_purpose_needs_anonymity_returns_true_for_bridges(void *arg) { (void)arg;
- tt_int_op(1, ==, purpose_needs_anonymity(0, ROUTER_PURPOSE_BRIDGE)); + tt_int_op(1, ==, purpose_needs_anonymity(0, ROUTER_PURPOSE_BRIDGE, NULL)); + tt_int_op(1, ==, purpose_needs_anonymity(0, ROUTER_PURPOSE_BRIDGE, + "foobar")); tt_int_op(1, ==, purpose_needs_anonymity(DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2, - ROUTER_PURPOSE_BRIDGE)); + ROUTER_PURPOSE_BRIDGE, NULL)); + done: ; +} + +static void +test_dir_purpose_needs_anonymity_returns_false_for_own_bridge_desc(void *arg) +{ + (void)arg; + tt_int_op(0, ==, purpose_needs_anonymity(DIR_PURPOSE_FETCH_SERVERDESC, + ROUTER_PURPOSE_BRIDGE, + "authority.z")); done: ; }
@@ -3282,11 +3294,11 @@ test_dir_purpose_needs_anonymity_returns_true_for_sensitive_purpose(void *arg)
tt_int_op(1, ==, purpose_needs_anonymity( DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2, - ROUTER_PURPOSE_GENERAL)); + ROUTER_PURPOSE_GENERAL, NULL)); tt_int_op(1, ==, purpose_needs_anonymity( - DIR_PURPOSE_UPLOAD_RENDDESC_V2, 0)); + DIR_PURPOSE_UPLOAD_RENDDESC_V2, 0, NULL)); tt_int_op(1, ==, purpose_needs_anonymity( - DIR_PURPOSE_FETCH_RENDDESC_V2, 0)); + DIR_PURPOSE_FETCH_RENDDESC_V2, 0, NULL)); done: ; }
@@ -3296,17 +3308,24 @@ test_dir_purpose_needs_anonymity_ret_false_for_non_sensitive_conn(void *arg) (void)arg;
tt_int_op(0, ==, purpose_needs_anonymity(DIR_PURPOSE_UPLOAD_DIR, - ROUTER_PURPOSE_GENERAL)); - tt_int_op(0, ==, purpose_needs_anonymity(DIR_PURPOSE_UPLOAD_VOTE, 0)); - tt_int_op(0, ==, purpose_needs_anonymity(DIR_PURPOSE_UPLOAD_SIGNATURES, 0)); - tt_int_op(0, ==, purpose_needs_anonymity(DIR_PURPOSE_FETCH_STATUS_VOTE, 0)); + ROUTER_PURPOSE_GENERAL, NULL)); + tt_int_op(0, ==, purpose_needs_anonymity(DIR_PURPOSE_UPLOAD_VOTE, 0, NULL)); + tt_int_op(0, ==, + purpose_needs_anonymity(DIR_PURPOSE_UPLOAD_SIGNATURES, 0, NULL)); + tt_int_op(0, ==, + purpose_needs_anonymity(DIR_PURPOSE_FETCH_STATUS_VOTE, 0, NULL)); tt_int_op(0, ==, purpose_needs_anonymity( - DIR_PURPOSE_FETCH_DETACHED_SIGNATURES, 0)); - tt_int_op(0, ==, purpose_needs_anonymity(DIR_PURPOSE_FETCH_CONSENSUS, 0)); - tt_int_op(0, ==, purpose_needs_anonymity(DIR_PURPOSE_FETCH_CERTIFICATE, 0)); - tt_int_op(0, ==, purpose_needs_anonymity(DIR_PURPOSE_FETCH_SERVERDESC, 0)); - tt_int_op(0, ==, purpose_needs_anonymity(DIR_PURPOSE_FETCH_EXTRAINFO, 0)); - tt_int_op(0, ==, purpose_needs_anonymity(DIR_PURPOSE_FETCH_MICRODESC, 0)); + DIR_PURPOSE_FETCH_DETACHED_SIGNATURES, 0, NULL)); + tt_int_op(0, ==, + purpose_needs_anonymity(DIR_PURPOSE_FETCH_CONSENSUS, 0, NULL)); + tt_int_op(0, ==, + purpose_needs_anonymity(DIR_PURPOSE_FETCH_CERTIFICATE, 0, NULL)); + tt_int_op(0, ==, + purpose_needs_anonymity(DIR_PURPOSE_FETCH_SERVERDESC, 0, NULL)); + tt_int_op(0, ==, + purpose_needs_anonymity(DIR_PURPOSE_FETCH_EXTRAINFO, 0, NULL)); + tt_int_op(0, ==, + purpose_needs_anonymity(DIR_PURPOSE_FETCH_MICRODESC, 0, NULL)); done: ; }
@@ -5512,6 +5531,7 @@ struct testcase_t dir_tests[] = { DIR(dirserv_set_routerstatus_testing, 0), DIR(http_handling, 0), DIR(purpose_needs_anonymity_returns_true_for_bridges, 0), + DIR(purpose_needs_anonymity_returns_false_for_own_bridge_desc, 0), DIR(purpose_needs_anonymity_returns_true_by_default, 0), DIR(purpose_needs_anonymity_returns_true_for_sensitive_purpose, 0), DIR(purpose_needs_anonymity_ret_false_for_non_sensitive_conn, 0),