Record intro point timeouts in rend_intro_point_t

This commit is contained in:
Robert Ransom 2011-09-17 03:19:29 -07:00
parent 6803c1c371
commit eaed37d14c
4 changed files with 66 additions and 20 deletions

View File

@ -1119,9 +1119,8 @@ circuit_expire_all_dirty_circs(void)
* - If circ isn't open yet: call circuit_build_failed() if we're
* the origin, and in either case call circuit_rep_hist_note_result()
* to note stats.
* - If purpose is C_INTRODUCE_ACK_WAIT, remove the intro point we
* just tried from our list of intro points for that service
* descriptor.
* - If purpose is C_INTRODUCE_ACK_WAIT, report the intro point
* failure we just had to the hidden service client module.
* - 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
@ -1190,16 +1189,20 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line,
}
if (circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
int timed_out = (reason == END_STREAM_REASON_TIMEOUT);
tor_assert(circ->state == CIRCUIT_STATE_OPEN);
tor_assert(ocirc->build_state->chosen_exit);
tor_assert(ocirc->rend_data);
/* treat this like getting a nack from it */
log_info(LD_REND, "Failed intro circ %s to %s (awaiting ack). "
"Removing from descriptor.",
log_info(LD_REND, "Failed intro circ %s to %s (awaiting ack). %s",
safe_str_client(ocirc->rend_data->onion_address),
safe_str_client(build_state_get_exit_nickname(ocirc->build_state)));
rend_client_remove_intro_point(ocirc->build_state->chosen_exit,
ocirc->rend_data);
safe_str_client(build_state_get_exit_nickname(ocirc->build_state)),
timed_out ? "Recording timeout." : "Removing from descriptor.");
rend_client_report_intro_point_failure(ocirc->build_state->chosen_exit,
ocirc->rend_data,
timed_out ?
INTRO_POINT_FAILURE_TIMEOUT :
INTRO_POINT_FAILURE_GENERIC);
}
if (circ->n_conn) {
circuit_clear_cell_queue(circ, circ->n_conn);

View File

@ -3463,6 +3463,13 @@ typedef struct rend_intro_point_t {
extend_info_t *extend_info; /**< Extend info of this introduction point. */
crypto_pk_env_t *intro_key; /**< Introduction key that replaces the service
* key, if this descriptor is V2. */
/** (Client side only) Flag indicating that a timeout has occurred
* after sending an INTRODUCE cell to this intro point. After a
* timeout, an intro point should not be tried again during the same
* hidden service connection attempt, but it may be tried again
* during a future connection attempt. */
unsigned int timed_out : 1;
} rend_intro_point_t;
/** Information used to connect to a hidden service. Used on both the

View File

@ -366,8 +366,9 @@ rend_client_introduction_acked(origin_circuit_t *circ,
log_info(LD_REND, "Got nack for %s from %s...",
safe_str_client(circ->rend_data->onion_address),
safe_str_client(extend_info_describe(circ->build_state->chosen_exit)));
if (rend_client_remove_intro_point(circ->build_state->chosen_exit,
circ->rend_data) > 0) {
if (rend_client_report_intro_point_failure(circ->build_state->chosen_exit,
circ->rend_data,
INTRO_POINT_FAILURE_GENERIC)>0){
/* There are introduction points left. Re-extend the circuit to
* another intro point and try again. */
int result = rend_client_reextend_intro_circuit(circ);
@ -648,16 +649,26 @@ rend_client_cancel_descriptor_fetches(void)
} SMARTLIST_FOREACH_END(conn);
}
/** Remove failed_intro from ent. If ent now has no intro points, or
* service is unrecognized, then launch a new renddesc fetch.
/** Mark <b>failed_intro</b> as a failed introduction point for the
* hidden service specified by <b>rend_query</b>. If the HS now has no
* usable intro points, or we do not have an HS descriptor for it,
* then launch a new renddesc fetch.
*
* Return -1 if error, 0 if no intro points remain or service
* If <b>failure_type</b> is INTRO_POINT_FAILURE_GENERIC, remove the
* intro point from (our parsed copy of) the HS descriptor.
*
* If <b>failure_type</b> is INTRO_POINT_FAILURE_TIMEOUT, mark the
* intro point as 'timed out'; it will not be retried until the
* current hidden service connection attempt has ended or it has
* appeared in a newly fetched rendezvous descriptor.
*
* Return -1 if error, 0 if no usable intro points remain or service
* unrecognized, 1 if recognized and some intro points remain.
*/
int
rend_client_remove_intro_point(extend_info_t *failed_intro,
const rend_data_t *rend_query)
rend_client_report_intro_point_failure(extend_info_t *failed_intro,
const rend_data_t *rend_query,
unsigned int failure_type)
{
int i, r;
rend_cache_entry_t *ent;
@ -680,9 +691,21 @@ rend_client_remove_intro_point(extend_info_t *failed_intro,
rend_intro_point_t *intro = smartlist_get(ent->parsed->intro_nodes, i);
if (tor_memeq(failed_intro->identity_digest,
intro->extend_info->identity_digest, DIGEST_LEN)) {
switch (failure_type) {
default:
log_warn(LD_BUG, "Unknown failure type %u. Removing intro point.",
failure_type);
tor_fragile_assert();
/* fall through */
case INTRO_POINT_FAILURE_GENERIC:
rend_intro_point_free(intro);
smartlist_del(ent->parsed->intro_nodes, i);
break;
case INTRO_POINT_FAILURE_TIMEOUT:
intro->timed_out = 1;
break;
}
break;
}
}
@ -911,6 +934,13 @@ rend_client_get_random_intro_impl(const rend_cache_entry_t *entry,
usable_nodes = smartlist_create();
smartlist_add_all(usable_nodes, entry->parsed->intro_nodes);
/* Remove the intro points that have timed out during this HS
* connection attempt from our list of usable nodes. */
SMARTLIST_FOREACH(usable_nodes, rend_intro_point_t *, ip,
if (ip->timed_out) {
SMARTLIST_DEL_CURRENT(usable_nodes, ip);
});
again:
if (smartlist_len(usable_nodes) == 0) {
if (n_excluded && get_options()->StrictNodes && warnings) {

View File

@ -22,8 +22,14 @@ int rend_client_introduction_acked(origin_circuit_t *circ,
void rend_client_refetch_v2_renddesc(const rend_data_t *rend_query);
void rend_client_cancel_descriptor_fetches(void);
void rend_client_purge_last_hid_serv_requests(void);
int rend_client_remove_intro_point(extend_info_t *failed_intro,
const rend_data_t *rend_query);
#define INTRO_POINT_FAILURE_GENERIC 0
#define INTRO_POINT_FAILURE_TIMEOUT 1
int rend_client_report_intro_point_failure(extend_info_t *failed_intro,
const rend_data_t *rend_query,
unsigned int failure_type);
int rend_client_rendezvous_acked(origin_circuit_t *circ,
const uint8_t *request,
size_t request_len);