commit fbea8c8ef1e2f549e84ee681a9640c3006f7ad64 Author: Robert Ransom rransom.8774@gmail.com Date: Sat Sep 17 03:53:07 2011 -0700
Detect and remove unreachable intro points --- changes/bug3825a | 8 ++++++++ src/or/circuitlist.c | 16 ++++++++++++++++ src/or/or.h | 10 ++++++++++ src/or/rendclient.c | 19 +++++++++++++++++++ src/or/rendclient.h | 1 + 5 files changed, 54 insertions(+), 0 deletions(-)
diff --git a/changes/bug3825a b/changes/bug3825a new file mode 100644 index 0000000..6606e36 --- /dev/null +++ b/changes/bug3825a @@ -0,0 +1,8 @@ + o Major bugfixes: + + - When one of a hidden service's introduction points appears to be + unreachable, stop trying it. Previously, we would keep trying + to build circuits to the introduction point until we lost the + descriptor, usually because the user gave up and restarted Tor. + Partly fixes bug 3825. + diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index 2fc645a..b25a71e 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -1121,6 +1121,9 @@ circuit_expire_all_dirty_circs(void) * to note stats. * - If purpose is C_INTRODUCE_ACK_WAIT, report the intro point * failure we just had to the hidden service client module. + * - If purpose is C_INTRODUCING and <b>reason</b> isn't TIMEOUT, + * report to the hidden service client module that the intro point + * we just tried may be unreachable. * - Send appropriate destroys and edge_destroys for conns and * streams attached to circ. * - If circ->rend_splice is set (we are the midpoint of a joined @@ -1203,6 +1206,19 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line, timed_out ? INTRO_POINT_FAILURE_TIMEOUT : INTRO_POINT_FAILURE_GENERIC); + } else if (circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCING && + reason != END_STREAM_REASON_TIMEOUT) { + origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); + tor_assert(ocirc->build_state->chosen_exit); + tor_assert(ocirc->rend_data); + log_info(LD_REND, "Failed intro circ %s to %s " + "(building circuit to intro point). " + "Marking intro point as possibly unreachable.", + safe_str_client(ocirc->rend_data->onion_address), + safe_str_client(build_state_get_exit_nickname(ocirc->build_state))); + rend_client_report_intro_point_failure(ocirc->build_state->chosen_exit, + ocirc->rend_data, + INTRO_POINT_FAILURE_UNREACHABLE); } if (circ->n_conn) { circuit_clear_cell_queue(circ, circ->n_conn); diff --git a/src/or/or.h b/src/or/or.h index 32d4b11..f884c12 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -3456,6 +3456,11 @@ typedef struct rend_encoded_v2_service_descriptor_t { char *desc_str; /**< Descriptor string. */ } rend_encoded_v2_service_descriptor_t;
+/** The maximum number of non-circuit-build-timeout failures a hidden + * service client will tolerate while trying to build a circuit to an + * introduction point. See also rend_intro_point_t.unreachable_count. */ +#define MAX_INTRO_POINT_REACHABILITY_FAILURES 5 + /** Introduction point information. Used both in rend_service_t (on * the service side) and in rend_service_descriptor_t (on both the * client and service side). */ @@ -3470,6 +3475,11 @@ typedef struct rend_intro_point_t { * hidden service connection attempt, but it may be tried again * during a future connection attempt. */ unsigned int timed_out : 1; + + /** (Client side only) The number of times we have failed to build a + * circuit to this intro point for some reason other than our + * circuit-build timeout. See also MAX_INTRO_POINT_REACHABILITY_FAILURES. */ + unsigned int unreachable_count : 3; } rend_intro_point_t;
/** Information used to connect to a hidden service. Used on both the diff --git a/src/or/rendclient.c b/src/or/rendclient.c index 3c1c116..0a9e2a6 100644 --- a/src/or/rendclient.c +++ b/src/or/rendclient.c @@ -662,6 +662,11 @@ rend_client_cancel_descriptor_fetches(void) * current hidden service connection attempt has ended or it has * appeared in a newly fetched rendezvous descriptor. * + * If <b>failure_type</b> is INTRO_POINT_FAILURE_UNREACHABLE, + * increment the intro point's reachability-failure count; if it has + * now failed MAX_INTRO_POINT_REACHABILITY_FAILURES or more times, + * remove the intro point from (our parsed copy of) the HS descriptor. + * * Return -1 if error, 0 if no usable intro points remain or service * unrecognized, 1 if recognized and some intro points remain. */ @@ -704,6 +709,20 @@ rend_client_report_intro_point_failure(extend_info_t *failed_intro, case INTRO_POINT_FAILURE_TIMEOUT: intro->timed_out = 1; break; + case INTRO_POINT_FAILURE_UNREACHABLE: + ++(intro->unreachable_count); + { + int zap_intro_point = + intro->unreachable_count >= MAX_INTRO_POINT_REACHABILITY_FAILURES; + log_info(LD_REND, "Failed to reach this intro point %u times.%s", + intro->unreachable_count, + zap_intro_point ? " Removing from descriptor.": ""); + if (zap_intro_point) { + rend_intro_point_free(intro); + smartlist_del(ent->parsed->intro_nodes, i); + } + } + break; } break; } diff --git a/src/or/rendclient.h b/src/or/rendclient.h index 46779b7..d87cb1f 100644 --- a/src/or/rendclient.h +++ b/src/or/rendclient.h @@ -25,6 +25,7 @@ void rend_client_purge_last_hid_serv_requests(void);
#define INTRO_POINT_FAILURE_GENERIC 0 #define INTRO_POINT_FAILURE_TIMEOUT 1 +#define INTRO_POINT_FAILURE_UNREACHABLE 2
int rend_client_report_intro_point_failure(extend_info_t *failed_intro, const rend_data_t *rend_query,