diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 73018740c2..c8c8db3967 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -1056,6 +1056,53 @@ pathbias_state_to_string(path_state_t state) return "unknown"; } +/** + * Decide if the path bias code should count a circuit. + * + * @returns 1 if we should count it, 0 otherwise. + */ +static int +pathbias_should_count(origin_circuit_t *circ) +{ +#define PATHBIAS_COUNT_INTERVAL (600) + static ratelim_t count_limit = + RATELIM_INIT(PATHBIAS_COUNT_INTERVAL); + char *rate_msg = NULL; + + /* We can't do path bias accounting without entry guards. + * Testing and controller circuits also have no guards. */ + if (get_options()->UseEntryGuards == 0 || + circ->base_.purpose == CIRCUIT_PURPOSE_TESTING || + circ->base_.purpose == CIRCUIT_PURPOSE_CONTROLLER) { + return 0; + } + + /* Completely ignore one hop circuits */ + if (circ->build_state->onehop_tunnel || + circ->build_state->desired_path_len == 1) { + /* Check for inconsistency */ + if (circ->build_state->desired_path_len != 1 || + !circ->build_state->onehop_tunnel) { + if ((rate_msg = rate_limit_log(&count_limit, approx_time()))) { + log_notice(LD_BUG, + "One-hop circuit has length %d. Path state is %s. " + "Circuit is a %s currently %s.%s", + circ->build_state->desired_path_len, + pathbias_state_to_string(circ->path_state), + circuit_purpose_to_string(circ->base_.purpose), + circuit_state_to_string(circ->base_.state), + rate_msg); + tor_free(rate_msg); + } + tor_fragile_assert(); + } + return 0; + } + + return 1; +} + + /** * Check our circuit state to see if this is a successful first hop. * If so, record it in the current guard's path bias first_hop count. @@ -1290,6 +1337,26 @@ pathbias_count_success(origin_circuit_t *circ) } } +/** + * Count timeouts for path bias log messages. + * + * These counts are purely informational. + */ +void +pathbias_count_timeout(origin_circuit_t *circ) +{ + if(!pathbias_should_count(circ)) { + return; + } + entry_guard_t *guard = + entry_guard_get_by_id_digest(circ->base_.n_chan->identity_digest); + + if (guard) { + guard->timeouts++; + entry_guards_changed(); + } +} + /** Increment the number of times we successfully extended a circuit to * 'guard', first checking if the failure rate is high enough that we should * eliminate the guard. Return -1 if the guard looks no good; return 0 if the diff --git a/src/or/circuituse.c b/src/or/circuituse.c index e14f9d03ca..77822a36ad 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -663,6 +663,8 @@ circuit_expire_building(void) circuit_mark_for_close(victim, END_CIRC_REASON_MEASUREMENT_EXPIRED); else circuit_mark_for_close(victim, END_CIRC_REASON_TIMEOUT); + + pathbias_count_timeout(TO_ORIGIN_CIRCUIT(victim)); } } diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c index 8712241f62..d9a06a6573 100644 --- a/src/or/entrynodes.c +++ b/src/or/entrynodes.c @@ -1021,7 +1021,7 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg) digestmap_set(added_by, d, tor_strdup(line->value+HEX_DIGEST_LEN+1)); } else if (!strcasecmp(line->key, "EntryGuardPathBias")) { const or_options_t *options = get_options(); - unsigned hop_cnt, success_cnt; + unsigned hop_cnt, success_cnt, timeouts; if (!node) { *msg = tor_strdup("Unable to parse entry nodes: " @@ -1029,14 +1029,20 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg) break; } - if (tor_sscanf(line->value, "%u %u", &success_cnt, &hop_cnt) != 2) { - log_warn(LD_GENERAL, "Unable to parse guard path bias info: " + /* First try 3 params, then 2. */ + if (tor_sscanf(line->value, "%u %u %u", &success_cnt, &hop_cnt, + &timeouts) != 3) { + timeouts = 0; + if (tor_sscanf(line->value, "%u %u", &success_cnt, &hop_cnt) != 2) { + log_warn(LD_GENERAL, "Unable to parse guard path bias info: " "Misformated EntryGuardPathBias %s", escaped(line->value)); - continue; + continue; + } } node->first_hops = hop_cnt; node->circuit_successes = success_cnt; + node->timeouts = timeouts; log_info(LD_GENERAL, "Read %u/%u path bias for node %s", node->circuit_successes, node->first_hops, node->nickname); /* Note: We rely on the < comparison here to allow us to set a 0 @@ -1173,8 +1179,8 @@ entry_guards_update_state(or_state_t *state) if (e->first_hops) { *next = line = tor_malloc_zero(sizeof(config_line_t)); line->key = tor_strdup("EntryGuardPathBias"); - tor_asprintf(&line->value, "%u %u", - e->circuit_successes, e->first_hops); + tor_asprintf(&line->value, "%u %u %u", + e->circuit_successes, e->first_hops, e->timeouts); next = &(line->next); } diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h index 4d031c3593..b34744183c 100644 --- a/src/or/entrynodes.h +++ b/src/or/entrynodes.h @@ -47,6 +47,8 @@ typedef struct entry_guard_t { unsigned first_hops; /**< Number of first hops this guard has completed */ unsigned circuit_successes; /**< Number of successfully built circuits using * this guard as first hop. */ + unsigned timeouts; /**< Number of 'right-censored' timeouts + for this guard. */ } entry_guard_t; entry_guard_t *entry_guard_get_by_id_digest(const char *digest); diff --git a/src/or/or.h b/src/or/or.h index 195cb2b98f..59202104db 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -4067,6 +4067,8 @@ typedef struct { double close_ms; } circuit_build_times_t; +void pathbias_count_timeout(origin_circuit_t *circ); + /********************************* config.c ***************************/ /** An error from options_trial_assign() or options_init_from_string(). */