diff --git a/doc/spec/path-spec.txt b/doc/spec/path-spec.txt index ae5ab3e3dd..2beeedeace 100644 --- a/doc/spec/path-spec.txt +++ b/doc/spec/path-spec.txt @@ -382,6 +382,12 @@ of their choices. construction. If these parameters are not present in the consensus, the listed default values should be used instead. + cbtdisabled + Default: 0 + Effect: If non-zero, all CircuitBuildTime learning code should be + disabled and history should be discarded. For use in + emergency situations only. + cbtrecentcount Default: 20 Effect: This is the number of circuit build times to keep track of diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 2ae5005d8c..e6bce02e3b 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -419,9 +419,16 @@ The following options are useful only for clients (that is, if fingerprint to look up the bridge descriptor at the bridge authority, if it's provided and if UpdateBridgesFromAuthority is set too. +**LearnCircuitBuildTimeout** **0**|**1**:: + If 0, CircuitBuildTimeout adaptive learning is disabled. (Default: 1) + **CircuitBuildTimeout** __NUM__:: + Try for at most NUM seconds when building circuits. If the circuit isn't - open in that time, give up on it. (Default: 1 minute.) + open in that time, give up on it. If LearnCircuitBuildTimeout is 1, this + value serves as the initial value to use before a timeout is learned. If + LearnCircuitBuildTimeout is 0, this value is the only value used. + (Default: 60 seconds.) **CircuitIdleTimeout** __NUM__:: If we have kept a clean (never used) circuit around for NUM seconds, then diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 3600ce7c4d..4f79d32444 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -81,6 +81,28 @@ static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice); static void entry_guards_changed(void); +static int +circuit_build_times_disabled(void) +{ + int consensus_disabled = networkstatus_get_param(NULL, "cbtdisabled", + 0); + int config_disabled = !get_options()->LearnCircuitBuildTimeout; + int dirauth_disabled = get_options()->AuthoritativeDir; + int state_disabled = (get_or_state()->LastWritten == -1); + + if (consensus_disabled || config_disabled || dirauth_disabled || + state_disabled) { + log_info(LD_CIRC, + "CircuitBuildTime learning is disabled. " + "Consensus=%d, Config=%d, AuthDir=%d, StateFile=%d", + consensus_disabled, config_disabled, dirauth_disabled, + state_disabled); + return 1; + } else { + return 0; + } +} + static int32_t circuit_build_times_max_timeouts(void) { @@ -531,11 +553,16 @@ circuit_build_times_parse_state(circuit_build_times_t *cbt, uint32_t loaded_cnt = 0, N = 0; config_line_t *line; int i; - build_time_t *loaded_times = tor_malloc(sizeof(build_time_t) - * state->TotalBuildTimes); + build_time_t *loaded_times; circuit_build_times_init(cbt); *msg = NULL; + if (circuit_build_times_disabled()) { + return 0; + } + + loaded_times = tor_malloc(sizeof(build_time_t)*state->TotalBuildTimes); + for (line = state->BuildtimeHistogram; line; line = line->next) { smartlist_t *args = smartlist_create(); smartlist_split_string(args, line->value, " ", @@ -1020,6 +1047,11 @@ circuit_build_times_add_timeout(circuit_build_times_t *cbt, int did_onehop, time_t start_time) { + if (circuit_build_times_disabled()) { + cbt->timeout_ms = circuit_build_times_get_initial_timeout(); + return 0; + } + circuit_build_times_network_timeout(cbt, did_onehop, start_time); /* Only count timeouts if network is live.. */ @@ -1769,7 +1801,7 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) if (timediff < 0 || timediff > 2*circ_times.timeout_ms+1000) { log_notice(LD_CIRC, "Strange value for circuit build time: %ld. " "Assuming clock jump.", timediff); - } else { + } else if (!circuit_build_times_disabled()) { circuit_build_times_add_time(&circ_times, (build_time_t)timediff); circuit_build_times_network_circ_success(&circ_times); circuit_build_times_set_timeout(&circ_times); diff --git a/src/or/config.c b/src/or/config.c index 5d07cd7343..77ef45ec42 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -167,6 +167,7 @@ static config_var_t _option_vars[] = { V(BridgeRecordUsageByCountry, BOOL, "1"), V(BridgeRelay, BOOL, "0"), V(CellStatistics, BOOL, "0"), + V(LearnCircuitBuildTimeout, BOOL, "1"), V(CircuitBuildTimeout, INTERVAL, "0"), V(CircuitIdleTimeout, INTERVAL, "1 hour"), V(CircuitStreamTimeout, INTERVAL, "0"), @@ -4982,7 +4983,6 @@ or_state_save(time_t now) if (accounting_is_enabled(get_options())) accounting_run_housekeeping(now); - global_state->LastWritten = time(NULL); tor_free(global_state->TorVersion); tor_asprintf(&global_state->TorVersion, "Tor %s", get_version()); @@ -4997,10 +4997,13 @@ or_state_save(time_t now) fname = get_datadir_fname("state"); if (write_str_to_file(fname, contents, 0)<0) { log_warn(LD_FS, "Unable to write state to file \"%s\"", fname); + global_state->LastWritten = -1; tor_free(fname); tor_free(contents); return -1; } + + global_state->LastWritten = time(NULL); log_info(LD_GENERAL, "Saved state to \"%s\"", fname); tor_free(fname); tor_free(contents); diff --git a/src/or/or.h b/src/or/or.h index f31847408e..36c45e2db0 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -2496,9 +2496,12 @@ typedef struct { * connections alive? */ int SocksTimeout; /**< How long do we let a socks connection wait * unattached before we fail it? */ - int CircuitBuildTimeout; /**< If non-zero, cull non-open circuits that - * were born at least this many seconds ago. If - * zero, use the internal adaptive algorithm. */ + int LearnCircuitBuildTimeout; /**< If non-zero, we attempt to learn a value + * for CircuitBuildTimeout based on timeout + * history */ + int CircuitBuildTimeout; /**< Cull non-open circuits that were born at + * least this many seconds ago. Used until + * adaptive algorithm learns a new value. */ int CircuitIdleTimeout; /**< Cull open clean circuits that were born * at least this many seconds ago. */ int CircuitStreamTimeout; /**< If non-zero, detach streams from circuits