mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-10 21:23:58 +01:00
Implement Path use bias accounting.
Path use bias measures how often we can actually succeed using the circuits we actually try to use. It is a subset of path bias accounting, but it is computed as a separate statistic because the rate of client circuit use may vary depending on use case.
This commit is contained in:
parent
ee421e68d5
commit
e13e30221e
@ -67,7 +67,9 @@ static int entry_guard_inc_circ_attempt_count(entry_guard_t *guard);
|
|||||||
static void pathbias_count_build_success(origin_circuit_t *circ);
|
static void pathbias_count_build_success(origin_circuit_t *circ);
|
||||||
static void pathbias_count_successful_close(origin_circuit_t *circ);
|
static void pathbias_count_successful_close(origin_circuit_t *circ);
|
||||||
static void pathbias_count_collapse(origin_circuit_t *circ);
|
static void pathbias_count_collapse(origin_circuit_t *circ);
|
||||||
static void pathbias_count_unusable(origin_circuit_t *circ);
|
static void pathbias_count_use_failed(origin_circuit_t *circ);
|
||||||
|
static int pathbias_check_use_rate(entry_guard_t *guard);
|
||||||
|
static int pathbias_check_close_rate(entry_guard_t *guard);
|
||||||
|
|
||||||
/** This function tries to get a channel to the specified endpoint,
|
/** This function tries to get a channel to the specified endpoint,
|
||||||
* and then calls command_setup_channel() to give it the right
|
* and then calls command_setup_channel() to give it the right
|
||||||
@ -1210,19 +1212,65 @@ pathbias_get_mult_factor(const or_options_t *options)
|
|||||||
pathbias_get_scale_factor(options));
|
pathbias_get_scale_factor(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** The minimum number of circuit usage attempts before we start
|
||||||
|
* thinking about warning about path use bias and dropping guards */
|
||||||
|
static int
|
||||||
|
pathbias_get_min_use(const or_options_t *options)
|
||||||
|
{
|
||||||
|
#define DFLT_PATH_BIAS_MIN_USE 20
|
||||||
|
if (options->PathBiasUseThreshold >= 3)
|
||||||
|
return options->PathBiasUseThreshold;
|
||||||
|
else
|
||||||
|
return networkstatus_get_param(NULL, "pb_minuse",
|
||||||
|
DFLT_PATH_BIAS_MIN_USE,
|
||||||
|
3, INT32_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The circuit use success rate below which we issue a notice */
|
||||||
|
static double
|
||||||
|
pathbias_get_notice_use_rate(const or_options_t *options)
|
||||||
|
{
|
||||||
|
#define DFLT_PATH_BIAS_NOTICE_USE_PCT 90
|
||||||
|
if (options->PathBiasNoticeUseRate >= 0.0)
|
||||||
|
return options->PathBiasNoticeUseRate;
|
||||||
|
else
|
||||||
|
return networkstatus_get_param(NULL, "pb_noticeusepct",
|
||||||
|
DFLT_PATH_BIAS_NOTICE_USE_PCT,
|
||||||
|
0, 100)/100.0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If this parameter is set to a true value (default), we use the
|
* The extreme use rate is the rate at which we would drop the guard,
|
||||||
* successful_circuits_closed. Otherwise, we use the success_count.
|
* if pb_dropguard is also set. Otherwise we just warn.
|
||||||
|
*/
|
||||||
|
double
|
||||||
|
pathbias_get_extreme_use_rate(const or_options_t *options)
|
||||||
|
{
|
||||||
|
#define DFLT_PATH_BIAS_EXTREME_USE_PCT 70
|
||||||
|
if (options->PathBiasExtremeUseRate >= 0.0)
|
||||||
|
return options->PathBiasExtremeUseRate;
|
||||||
|
else
|
||||||
|
return networkstatus_get_param(NULL, "pb_extremeusepct",
|
||||||
|
DFLT_PATH_BIAS_EXTREME_USE_PCT,
|
||||||
|
0, 100)/100.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the number of circuits at which we scale our
|
||||||
|
* use counts by mult_factor/scale_factor. Note, this count is
|
||||||
|
* not exact, as we only perform the scaling in the event
|
||||||
|
* of no integer truncation.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
pathbias_use_close_counts(const or_options_t *options)
|
pathbias_get_scale_use_threshold(const or_options_t *options)
|
||||||
{
|
{
|
||||||
#define DFLT_PATH_BIAS_USE_CLOSE_COUNTS 1
|
#define DFLT_PATH_BIAS_SCALE_USE_THRESHOLD 100
|
||||||
if (options->PathBiasUseCloseCounts >= 0)
|
if (options->PathBiasScaleUseThreshold >= 10)
|
||||||
return options->PathBiasUseCloseCounts;
|
return options->PathBiasScaleUseThreshold;
|
||||||
else
|
else
|
||||||
return networkstatus_get_param(NULL, "pb_useclosecounts",
|
return networkstatus_get_param(NULL, "pb_scaleuse",
|
||||||
DFLT_PATH_BIAS_USE_CLOSE_COUNTS, 0, 1);
|
DFLT_PATH_BIAS_SCALE_USE_THRESHOLD,
|
||||||
|
10, INT32_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1238,10 +1286,14 @@ pathbias_state_to_string(path_state_t state)
|
|||||||
return "build attempted";
|
return "build attempted";
|
||||||
case PATH_STATE_BUILD_SUCCEEDED:
|
case PATH_STATE_BUILD_SUCCEEDED:
|
||||||
return "build succeeded";
|
return "build succeeded";
|
||||||
|
case PATH_STATE_USE_ATTEMPTED:
|
||||||
|
return "use attempted";
|
||||||
case PATH_STATE_USE_SUCCEEDED:
|
case PATH_STATE_USE_SUCCEEDED:
|
||||||
return "use succeeded";
|
return "use succeeded";
|
||||||
case PATH_STATE_USE_FAILED:
|
case PATH_STATE_USE_FAILED:
|
||||||
return "use failed";
|
return "use failed";
|
||||||
|
case PATH_STATE_ALREADY_COUNTED:
|
||||||
|
return "already counted";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "unknown";
|
return "unknown";
|
||||||
@ -1338,7 +1390,7 @@ pathbias_should_count(origin_circuit_t *circ)
|
|||||||
* Also check for several potential error cases for bug #6475.
|
* Also check for several potential error cases for bug #6475.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
pathbias_count_circ_attempt(origin_circuit_t *circ)
|
pathbias_count_build_attempt(origin_circuit_t *circ)
|
||||||
{
|
{
|
||||||
#define CIRC_ATTEMPT_NOTICE_INTERVAL (600)
|
#define CIRC_ATTEMPT_NOTICE_INTERVAL (600)
|
||||||
static ratelim_t circ_attempt_notice_limit =
|
static ratelim_t circ_attempt_notice_limit =
|
||||||
@ -1504,6 +1556,126 @@ pathbias_count_build_success(origin_circuit_t *circ)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Record an attempt to use a circuit. Changes the circuit's
|
||||||
|
* path state and update its guard's usage counter.
|
||||||
|
*
|
||||||
|
* Used for path bias usage accounting.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
pathbias_count_use_attempt(origin_circuit_t *circ)
|
||||||
|
{
|
||||||
|
entry_guard_t *guard;
|
||||||
|
|
||||||
|
if (!pathbias_should_count(circ)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (circ->path_state < PATH_STATE_BUILD_SUCCEEDED) {
|
||||||
|
log_notice(LD_BUG,
|
||||||
|
"Used circuit is in strange path state %s. "
|
||||||
|
"Circuit is a %s currently %s.",
|
||||||
|
pathbias_state_to_string(circ->path_state),
|
||||||
|
circuit_purpose_to_string(circ->base_.purpose),
|
||||||
|
circuit_state_to_string(circ->base_.state));
|
||||||
|
} else if (circ->path_state < PATH_STATE_USE_ATTEMPTED) {
|
||||||
|
guard = entry_guard_get_by_id_digest(
|
||||||
|
circ->cpath->extend_info->identity_digest);
|
||||||
|
if (guard) {
|
||||||
|
pathbias_check_use_rate(guard);
|
||||||
|
guard->use_attempts++;
|
||||||
|
|
||||||
|
log_debug(LD_CIRC, "Marked circuit %d as used for guard %s=%s.",
|
||||||
|
circ->global_identifier, guard->nickname,
|
||||||
|
hex_str(guard->identity, DIGEST_LEN));
|
||||||
|
}
|
||||||
|
|
||||||
|
circ->path_state = PATH_STATE_USE_ATTEMPTED;
|
||||||
|
} else {
|
||||||
|
/* Harmless but educational log message */
|
||||||
|
log_info(LD_CIRC,
|
||||||
|
"Used circuit %d is already in path state %s. "
|
||||||
|
"Circuit is a %s currently %s.",
|
||||||
|
circ->global_identifier,
|
||||||
|
pathbias_state_to_string(circ->path_state),
|
||||||
|
circuit_purpose_to_string(circ->base_.purpose),
|
||||||
|
circuit_state_to_string(circ->base_.state));
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the circuit's path stat is appropriate and it as successfully
|
||||||
|
* used.
|
||||||
|
*
|
||||||
|
* We don't actually increment the guard's counters until
|
||||||
|
* pathbias_check_close().
|
||||||
|
*
|
||||||
|
* Used for path bias usage accounting.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
pathbias_mark_use_success(origin_circuit_t *circ)
|
||||||
|
{
|
||||||
|
if (!pathbias_should_count(circ)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (circ->path_state < PATH_STATE_USE_ATTEMPTED) {
|
||||||
|
log_notice(LD_BUG,
|
||||||
|
"Used circuit %d is in strange path state %s. "
|
||||||
|
"Circuit is a %s currently %s.",
|
||||||
|
circ->global_identifier,
|
||||||
|
pathbias_state_to_string(circ->path_state),
|
||||||
|
circuit_purpose_to_string(circ->base_.purpose),
|
||||||
|
circuit_state_to_string(circ->base_.state));
|
||||||
|
|
||||||
|
pathbias_count_use_attempt(circ);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We don't do any accounting at the guard until actual circuit close */
|
||||||
|
circ->path_state = PATH_STATE_USE_SUCCEEDED;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actually count a circuit success towards a guard's usage counters
|
||||||
|
* if the path state is appropriate.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
pathbias_count_use_success(origin_circuit_t *circ)
|
||||||
|
{
|
||||||
|
entry_guard_t *guard;
|
||||||
|
|
||||||
|
if (!pathbias_should_count(circ)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (circ->path_state != PATH_STATE_USE_SUCCEEDED) {
|
||||||
|
log_notice(LD_BUG,
|
||||||
|
"Successfully used circuit %d is in strange path state %s. "
|
||||||
|
"Circuit is a %s currently %s.",
|
||||||
|
circ->global_identifier,
|
||||||
|
pathbias_state_to_string(circ->path_state),
|
||||||
|
circuit_purpose_to_string(circ->base_.purpose),
|
||||||
|
circuit_state_to_string(circ->base_.state));
|
||||||
|
} else {
|
||||||
|
guard = entry_guard_get_by_id_digest(
|
||||||
|
circ->cpath->extend_info->identity_digest);
|
||||||
|
if (guard) {
|
||||||
|
guard->use_successes++;
|
||||||
|
|
||||||
|
log_debug(LD_CIRC,
|
||||||
|
"Marked circuit %d as used successfully for guard %s=%s.",
|
||||||
|
circ->global_identifier, guard->nickname,
|
||||||
|
hex_str(guard->identity, DIGEST_LEN));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a probe down a circuit that the client attempted to use,
|
* Send a probe down a circuit that the client attempted to use,
|
||||||
* but for which the stream timed out/failed. The probe is a
|
* but for which the stream timed out/failed. The probe is a
|
||||||
@ -1648,7 +1820,7 @@ pathbias_check_probe_response(circuit_t *circ, const cell_t *cell)
|
|||||||
|
|
||||||
/* Check nonce */
|
/* Check nonce */
|
||||||
if (ipv4_host == ocirc->pathbias_probe_nonce) {
|
if (ipv4_host == ocirc->pathbias_probe_nonce) {
|
||||||
ocirc->path_state = PATH_STATE_USE_SUCCEEDED;
|
pathbias_mark_use_success(ocirc);
|
||||||
circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
|
circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
|
||||||
log_info(LD_CIRC,
|
log_info(LD_CIRC,
|
||||||
"Got valid path bias probe back for circ %d, stream %d.",
|
"Got valid path bias probe back for circ %d, stream %d.",
|
||||||
@ -1691,24 +1863,11 @@ pathbias_check_close(origin_circuit_t *ocirc, int reason)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ocirc->path_state == PATH_STATE_BUILD_SUCCEEDED) {
|
switch (ocirc->path_state) {
|
||||||
if (circ->timestamp_dirty) {
|
/* If the circuit was closed after building, but before use, we need
|
||||||
if (pathbias_send_usable_probe(circ) == 0)
|
* to ensure we were the ones who tried to close it (and not a remote
|
||||||
return -1;
|
* actor). */
|
||||||
else
|
case PATH_STATE_BUILD_SUCCEEDED:
|
||||||
pathbias_count_unusable(ocirc);
|
|
||||||
|
|
||||||
/* Any circuit where there were attempted streams but no successful
|
|
||||||
* streams could be bias */
|
|
||||||
log_info(LD_CIRC,
|
|
||||||
"Circuit %d closed without successful use for reason %d. "
|
|
||||||
"Circuit purpose %d currently %d,%s. Len %d.",
|
|
||||||
ocirc->global_identifier,
|
|
||||||
reason, circ->purpose, ocirc->has_opened,
|
|
||||||
circuit_state_to_string(circ->state),
|
|
||||||
ocirc->build_state->desired_path_len);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (reason & END_CIRC_REASON_FLAG_REMOTE) {
|
if (reason & END_CIRC_REASON_FLAG_REMOTE) {
|
||||||
/* Remote circ close reasons on an unused circuit all could be bias */
|
/* Remote circ close reasons on an unused circuit all could be bias */
|
||||||
log_info(LD_CIRC,
|
log_info(LD_CIRC,
|
||||||
@ -1739,11 +1898,41 @@ pathbias_check_close(origin_circuit_t *ocirc, int reason)
|
|||||||
} else {
|
} else {
|
||||||
pathbias_count_successful_close(ocirc);
|
pathbias_count_successful_close(ocirc);
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
} else if (ocirc->path_state == PATH_STATE_USE_SUCCEEDED) {
|
|
||||||
pathbias_count_successful_close(ocirc);
|
/* If we tried to use a circuit but failed, we should probe it to ensure
|
||||||
|
* it has not been tampered with. */
|
||||||
|
case PATH_STATE_USE_ATTEMPTED:
|
||||||
|
/* XXX: Only probe and/or count failure if the network is live?
|
||||||
|
* What about clock jumps/suspends? */
|
||||||
|
if (pathbias_send_usable_probe(circ) == 0)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
pathbias_count_use_failed(ocirc);
|
||||||
|
|
||||||
|
/* Any circuit where there were attempted streams but no successful
|
||||||
|
* streams could be bias */
|
||||||
|
log_info(LD_CIRC,
|
||||||
|
"Circuit %d closed without successful use for reason %d. "
|
||||||
|
"Circuit purpose %d currently %d,%s. Len %d.",
|
||||||
|
ocirc->global_identifier,
|
||||||
|
reason, circ->purpose, ocirc->has_opened,
|
||||||
|
circuit_state_to_string(circ->state),
|
||||||
|
ocirc->build_state->desired_path_len);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PATH_STATE_USE_SUCCEEDED:
|
||||||
|
pathbias_count_successful_close(ocirc);
|
||||||
|
pathbias_count_use_success(ocirc);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Other states are uninteresting. No stats to count.
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ocirc->path_state = PATH_STATE_ALREADY_COUNTED;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1792,6 +1981,7 @@ static void
|
|||||||
pathbias_count_collapse(origin_circuit_t *circ)
|
pathbias_count_collapse(origin_circuit_t *circ)
|
||||||
{
|
{
|
||||||
entry_guard_t *guard = NULL;
|
entry_guard_t *guard = NULL;
|
||||||
|
|
||||||
if (!pathbias_should_count(circ)) {
|
if (!pathbias_should_count(circ)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1816,8 +2006,13 @@ pathbias_count_collapse(origin_circuit_t *circ)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count a known failed circuit (because we could not probe it).
|
||||||
|
*
|
||||||
|
* This counter is informational.
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
pathbias_count_unusable(origin_circuit_t *circ)
|
pathbias_count_use_failed(origin_circuit_t *circ)
|
||||||
{
|
{
|
||||||
entry_guard_t *guard = NULL;
|
entry_guard_t *guard = NULL;
|
||||||
if (!pathbias_should_count(circ)) {
|
if (!pathbias_should_count(circ)) {
|
||||||
@ -1886,7 +2081,7 @@ pathbias_count_timeout(origin_circuit_t *circ)
|
|||||||
* of the doubt.
|
* of the doubt.
|
||||||
*/
|
*/
|
||||||
double
|
double
|
||||||
pathbias_get_closed_count(entry_guard_t *guard)
|
pathbias_get_close_success_count(entry_guard_t *guard)
|
||||||
{
|
{
|
||||||
circuit_t *circ;
|
circuit_t *circ;
|
||||||
int open_circuits = 0;
|
int open_circuits = 0;
|
||||||
@ -1903,7 +2098,12 @@ pathbias_get_closed_count(entry_guard_t *guard)
|
|||||||
if (!ocirc->cpath || !ocirc->cpath->extend_info)
|
if (!ocirc->cpath || !ocirc->cpath->extend_info)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* Don't count known failed or already counted circuits */
|
||||||
|
if (ocirc->path_state >= PATH_STATE_USE_FAILED)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (ocirc->path_state >= PATH_STATE_BUILD_SUCCEEDED &&
|
if (ocirc->path_state >= PATH_STATE_BUILD_SUCCEEDED &&
|
||||||
|
pathbias_should_count(ocirc) &&
|
||||||
fast_memeq(guard->identity,
|
fast_memeq(guard->identity,
|
||||||
ocirc->cpath->extend_info->identity_digest,
|
ocirc->cpath->extend_info->identity_digest,
|
||||||
DIGEST_LEN)) {
|
DIGEST_LEN)) {
|
||||||
@ -1915,50 +2115,83 @@ pathbias_get_closed_count(entry_guard_t *guard)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function checks the consensus parameters to decide
|
* Return the number of circuits counted as successfully used
|
||||||
* if it should return guard->circ_successes or
|
* this guard.
|
||||||
* guard->successful_circuits_closed.
|
*
|
||||||
|
* Also add in the currently open circuits that we are attempting
|
||||||
|
* to use to give them the benefit of the doubt.
|
||||||
*/
|
*/
|
||||||
double
|
double
|
||||||
pathbias_get_success_count(entry_guard_t *guard)
|
pathbias_get_use_success_count(entry_guard_t *guard)
|
||||||
{
|
{
|
||||||
if (pathbias_use_close_counts(get_options())) {
|
circuit_t *circ = global_circuitlist;
|
||||||
return pathbias_get_closed_count(guard);
|
int open_circuits = 0;
|
||||||
} else {
|
|
||||||
return guard->circ_successes;
|
/* Count currently open circuits. Give them the benefit of the doubt */
|
||||||
|
for ( ; circ; circ = circ->next) {
|
||||||
|
origin_circuit_t *ocirc = NULL;
|
||||||
|
if (!CIRCUIT_IS_ORIGIN(circ) || /* didn't originate here */
|
||||||
|
circ->marked_for_close) /* already counted */
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ocirc = TO_ORIGIN_CIRCUIT(circ);
|
||||||
|
|
||||||
|
if (!ocirc->cpath || !ocirc->cpath->extend_info)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Don't count known failed or already counted circuits */
|
||||||
|
if (ocirc->path_state >= PATH_STATE_USE_FAILED)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ocirc->path_state >= PATH_STATE_USE_ATTEMPTED &&
|
||||||
|
pathbias_should_count(ocirc) &&
|
||||||
|
fast_memeq(guard->identity,
|
||||||
|
ocirc->cpath->extend_info->identity_digest,
|
||||||
|
DIGEST_LEN)) {
|
||||||
|
open_circuits++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return guard->use_successes + open_circuits;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Increment the number of times we successfully extended a circuit to
|
/**
|
||||||
* <b>guard</b>, first checking if the failure rate is high enough that
|
* Check the path bias use rate against our consensus parameter limits.
|
||||||
* we should eliminate the guard. Return -1 if the guard looks no good;
|
*
|
||||||
* return 0 if the guard looks fine.
|
* Emits a log message if the use success rates are too low.
|
||||||
|
*
|
||||||
|
* If pathbias_get_dropguards() is set, we also disable the use of
|
||||||
|
* very failure prone guards.
|
||||||
|
*
|
||||||
|
* Returns -1 if we decided to disable the guard, 0 otherwise.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
entry_guard_inc_circ_attempt_count(entry_guard_t *guard)
|
pathbias_check_use_rate(entry_guard_t *guard)
|
||||||
{
|
{
|
||||||
const or_options_t *options = get_options();
|
const or_options_t *options = get_options();
|
||||||
|
|
||||||
entry_guards_changed();
|
if (guard->use_attempts > pathbias_get_min_use(options)) {
|
||||||
|
|
||||||
if (guard->circ_attempts > pathbias_get_min_circs(options)) {
|
|
||||||
/* Note: We rely on the < comparison here to allow us to set a 0
|
/* Note: We rely on the < comparison here to allow us to set a 0
|
||||||
* rate and disable the feature entirely. If refactoring, don't
|
* rate and disable the feature entirely. If refactoring, don't
|
||||||
* change to <= */
|
* change to <= */
|
||||||
if (pathbias_get_success_count(guard)/guard->circ_attempts
|
if (pathbias_get_use_success_count(guard)/guard->use_attempts
|
||||||
< pathbias_get_extreme_rate(options)) {
|
< pathbias_get_extreme_use_rate(options)) {
|
||||||
/* Dropping is currently disabled by default. */
|
/* Dropping is currently disabled by default. */
|
||||||
if (pathbias_get_dropguards(options)) {
|
if (pathbias_get_dropguards(options)) {
|
||||||
if (!guard->path_bias_disabled) {
|
if (!guard->path_bias_disabled) {
|
||||||
log_warn(LD_CIRC,
|
log_warn(LD_CIRC,
|
||||||
"Your Guard %s=%s is failing an extremely large amount of "
|
"Your Guard %s=%s is failing to carry an extremely large "
|
||||||
"circuits. To avoid potential route manipulation attacks, "
|
"amount of stream on its circuits. "
|
||||||
"Tor has disabled use of this guard. "
|
"To avoid potential route manipluation attacks, Tor has "
|
||||||
"Success counts are %ld/%ld. %ld circuits completed, %ld "
|
"disabled use of this guard. "
|
||||||
"were unusable, %ld collapsed, and %ld timed out. For "
|
"Use counts are %ld/%ld. Success counts are %ld/%ld. "
|
||||||
"reference, your timeout cutoff is %ld seconds.",
|
"%ld circuits completed, %ld were unusable, %ld collapsed, "
|
||||||
|
"and %ld timed out. "
|
||||||
|
"For reference, your timeout cutoff is %ld seconds.",
|
||||||
guard->nickname, hex_str(guard->identity, DIGEST_LEN),
|
guard->nickname, hex_str(guard->identity, DIGEST_LEN),
|
||||||
tor_lround(pathbias_get_closed_count(guard)),
|
tor_lround(pathbias_get_use_success_count(guard)),
|
||||||
|
tor_lround(guard->use_attempts),
|
||||||
|
tor_lround(pathbias_get_close_success_count(guard)),
|
||||||
tor_lround(guard->circ_attempts),
|
tor_lround(guard->circ_attempts),
|
||||||
tor_lround(guard->circ_successes),
|
tor_lround(guard->circ_successes),
|
||||||
tor_lround(guard->unusable_circuits),
|
tor_lround(guard->unusable_circuits),
|
||||||
@ -1972,14 +2205,18 @@ entry_guard_inc_circ_attempt_count(entry_guard_t *guard)
|
|||||||
} else if (!guard->path_bias_extreme) {
|
} else if (!guard->path_bias_extreme) {
|
||||||
guard->path_bias_extreme = 1;
|
guard->path_bias_extreme = 1;
|
||||||
log_warn(LD_CIRC,
|
log_warn(LD_CIRC,
|
||||||
"Your Guard %s=%s is failing an extremely large amount of "
|
"Your Guard %s=%s is failing to carry an extremely large "
|
||||||
"circuits. This could indicate a route manipulation attack, "
|
"amount of streams on its circuits. "
|
||||||
"extreme network overload, or a bug. "
|
"This could indicate a route manipulation attack, network "
|
||||||
"Success counts are %ld/%ld. %ld circuits completed, %ld "
|
"overload, bad local network connectivity, or a bug. "
|
||||||
"were unusable, %ld collapsed, and %ld timed out. For "
|
"Use counts are %ld/%ld. Success counts are %ld/%ld. "
|
||||||
"reference, your timeout cutoff is %ld seconds.",
|
"%ld circuits completed, %ld were unusable, %ld collapsed, "
|
||||||
|
"and %ld timed out. "
|
||||||
|
"For reference, your timeout cutoff is %ld seconds.",
|
||||||
guard->nickname, hex_str(guard->identity, DIGEST_LEN),
|
guard->nickname, hex_str(guard->identity, DIGEST_LEN),
|
||||||
tor_lround(pathbias_get_closed_count(guard)),
|
tor_lround(pathbias_get_use_success_count(guard)),
|
||||||
|
tor_lround(guard->use_attempts),
|
||||||
|
tor_lround(pathbias_get_close_success_count(guard)),
|
||||||
tor_lround(guard->circ_attempts),
|
tor_lround(guard->circ_attempts),
|
||||||
tor_lround(guard->circ_successes),
|
tor_lround(guard->circ_successes),
|
||||||
tor_lround(guard->unusable_circuits),
|
tor_lround(guard->unusable_circuits),
|
||||||
@ -1987,45 +2224,170 @@ entry_guard_inc_circ_attempt_count(entry_guard_t *guard)
|
|||||||
tor_lround(guard->timeouts),
|
tor_lround(guard->timeouts),
|
||||||
tor_lround(circ_times.close_ms/1000));
|
tor_lround(circ_times.close_ms/1000));
|
||||||
}
|
}
|
||||||
} else if (pathbias_get_success_count(guard)/((double)guard->circ_attempts)
|
} else if (pathbias_get_use_success_count(guard)/guard->use_attempts
|
||||||
< pathbias_get_warn_rate(options)) {
|
< pathbias_get_notice_use_rate(options)) {
|
||||||
|
if (!guard->path_bias_noticed) {
|
||||||
|
guard->path_bias_noticed = 1;
|
||||||
|
log_notice(LD_CIRC,
|
||||||
|
"Your Guard %s=%s is failing to carry more streams on its "
|
||||||
|
"circuits than usual. "
|
||||||
|
"Most likely this means the Tor network is overloaded "
|
||||||
|
"or your network connection is poor. "
|
||||||
|
"Use counts are %ld/%ld. Success counts are %ld/%ld. "
|
||||||
|
"%ld circuits completed, %ld were unusable, %ld collapsed, "
|
||||||
|
"and %ld timed out. "
|
||||||
|
"For reference, your timeout cutoff is %ld seconds.",
|
||||||
|
guard->nickname, hex_str(guard->identity, DIGEST_LEN),
|
||||||
|
tor_lround(pathbias_get_use_success_count(guard)),
|
||||||
|
tor_lround(guard->use_attempts),
|
||||||
|
tor_lround(pathbias_get_close_success_count(guard)),
|
||||||
|
tor_lround(guard->circ_attempts),
|
||||||
|
tor_lround(guard->circ_successes),
|
||||||
|
tor_lround(guard->unusable_circuits),
|
||||||
|
tor_lround(guard->collapsed_circuits),
|
||||||
|
tor_lround(guard->timeouts),
|
||||||
|
tor_lround(circ_times.close_ms/1000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we get a ton of circuits, just scale everything down */
|
||||||
|
if (guard->use_attempts > pathbias_get_scale_use_threshold(options)) {
|
||||||
|
const int scale_factor = pathbias_get_scale_factor(options);
|
||||||
|
const int mult_factor = pathbias_get_mult_factor(options);
|
||||||
|
log_info(LD_CIRC,
|
||||||
|
"Scaling pathbias use counts to (%f/%f)*(%d/%d) for guard %s=%s",
|
||||||
|
guard->use_successes, guard->use_attempts,
|
||||||
|
mult_factor, scale_factor, guard->nickname,
|
||||||
|
hex_str(guard->identity, DIGEST_LEN));
|
||||||
|
|
||||||
|
guard->use_attempts *= mult_factor;
|
||||||
|
guard->use_successes *= mult_factor;
|
||||||
|
|
||||||
|
guard->use_attempts /= scale_factor;
|
||||||
|
guard->use_successes /= scale_factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the path bias circuit close status rates against our consensus
|
||||||
|
* parameter limits.
|
||||||
|
*
|
||||||
|
* Emits a log message if the use success rates are too low.
|
||||||
|
*
|
||||||
|
* If pathbias_get_dropguards() is set, we also disable the use of
|
||||||
|
* very failure prone guards.
|
||||||
|
*
|
||||||
|
* Returns -1 if we decided to disable the guard, 0 otherwise.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
pathbias_check_close_rate(entry_guard_t *guard)
|
||||||
|
{
|
||||||
|
const or_options_t *options = get_options();
|
||||||
|
|
||||||
|
if (guard->circ_attempts > pathbias_get_min_circs(options)) {
|
||||||
|
/* Note: We rely on the < comparison here to allow us to set a 0
|
||||||
|
* rate and disable the feature entirely. If refactoring, don't
|
||||||
|
* change to <= */
|
||||||
|
if (pathbias_get_close_success_count(guard)/guard->circ_attempts
|
||||||
|
< pathbias_get_extreme_rate(options)) {
|
||||||
|
/* Dropping is currently disabled by default. */
|
||||||
|
if (pathbias_get_dropguards(options)) {
|
||||||
|
if (!guard->path_bias_disabled) {
|
||||||
|
log_warn(LD_CIRC,
|
||||||
|
"Your Guard %s=%s is failing an extremely large "
|
||||||
|
"amount of circuits. "
|
||||||
|
"To avoid potential route manipluation attacks, Tor has "
|
||||||
|
"disabled use of this guard. "
|
||||||
|
"Success counts are %ld/%ld. Use counts are %ld/%ld. "
|
||||||
|
"%ld circuits completed, %ld were unusable, %ld collapsed, "
|
||||||
|
"and %ld timed out. "
|
||||||
|
"For reference, your timeout cutoff is %ld seconds.",
|
||||||
|
guard->nickname, hex_str(guard->identity, DIGEST_LEN),
|
||||||
|
tor_lround(pathbias_get_close_success_count(guard)),
|
||||||
|
tor_lround(guard->circ_attempts),
|
||||||
|
tor_lround(pathbias_get_use_success_count(guard)),
|
||||||
|
tor_lround(guard->use_attempts),
|
||||||
|
tor_lround(guard->circ_successes),
|
||||||
|
tor_lround(guard->unusable_circuits),
|
||||||
|
tor_lround(guard->collapsed_circuits),
|
||||||
|
tor_lround(guard->timeouts),
|
||||||
|
tor_lround(circ_times.close_ms/1000));
|
||||||
|
guard->path_bias_disabled = 1;
|
||||||
|
guard->bad_since = approx_time();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else if (!guard->path_bias_extreme) {
|
||||||
|
guard->path_bias_extreme = 1;
|
||||||
|
log_warn(LD_CIRC,
|
||||||
|
"Your Guard %s=%s is failing an extremely large "
|
||||||
|
"amount of circuits. "
|
||||||
|
"This could indicate a route manipulation attack, "
|
||||||
|
"extreme network overload, or a bug. "
|
||||||
|
"Success counts are %ld/%ld. Use counts are %ld/%ld. "
|
||||||
|
"%ld circuits completed, %ld were unusable, %ld collapsed, "
|
||||||
|
"and %ld timed out. "
|
||||||
|
"For reference, your timeout cutoff is %ld seconds.",
|
||||||
|
guard->nickname, hex_str(guard->identity, DIGEST_LEN),
|
||||||
|
tor_lround(pathbias_get_close_success_count(guard)),
|
||||||
|
tor_lround(guard->circ_attempts),
|
||||||
|
tor_lround(pathbias_get_use_success_count(guard)),
|
||||||
|
tor_lround(guard->use_attempts),
|
||||||
|
tor_lround(guard->circ_successes),
|
||||||
|
tor_lround(guard->unusable_circuits),
|
||||||
|
tor_lround(guard->collapsed_circuits),
|
||||||
|
tor_lround(guard->timeouts),
|
||||||
|
tor_lround(circ_times.close_ms/1000));
|
||||||
|
}
|
||||||
|
} else if (pathbias_get_close_success_count(guard)/guard->circ_attempts
|
||||||
|
< pathbias_get_warn_rate(options)) {
|
||||||
if (!guard->path_bias_warned) {
|
if (!guard->path_bias_warned) {
|
||||||
guard->path_bias_warned = 1;
|
guard->path_bias_warned = 1;
|
||||||
log_warn(LD_CIRC,
|
log_warn(LD_CIRC,
|
||||||
"Your Guard %s=%s is failing a very large amount of "
|
"Your Guard %s=%s is failing a very large "
|
||||||
"circuits. Most likely this means the Tor network is "
|
"amount of circuits. "
|
||||||
|
"Most likely this means the Tor network is "
|
||||||
"overloaded, but it could also mean an attack against "
|
"overloaded, but it could also mean an attack against "
|
||||||
"you or potentially the guard itself. "
|
"you or the potentially the guard itself. "
|
||||||
"Success counts are %ld/%ld. %ld circuits completed, %ld "
|
"Success counts are %ld/%ld. Use counts are %ld/%ld. "
|
||||||
"were unusable, %ld collapsed, and %ld timed out. For "
|
"%ld circuits completed, %ld were unusable, %ld collapsed, "
|
||||||
"reference, your timeout cutoff is %ld seconds.",
|
"and %ld timed out. "
|
||||||
|
"For reference, your timeout cutoff is %ld seconds.",
|
||||||
guard->nickname, hex_str(guard->identity, DIGEST_LEN),
|
guard->nickname, hex_str(guard->identity, DIGEST_LEN),
|
||||||
tor_lround(pathbias_get_closed_count(guard)),
|
tor_lround(pathbias_get_close_success_count(guard)),
|
||||||
tor_lround(guard->circ_attempts),
|
tor_lround(guard->circ_attempts),
|
||||||
|
tor_lround(pathbias_get_use_success_count(guard)),
|
||||||
|
tor_lround(guard->use_attempts),
|
||||||
tor_lround(guard->circ_successes),
|
tor_lround(guard->circ_successes),
|
||||||
tor_lround(guard->unusable_circuits),
|
tor_lround(guard->unusable_circuits),
|
||||||
tor_lround(guard->collapsed_circuits),
|
tor_lround(guard->collapsed_circuits),
|
||||||
tor_lround(guard->timeouts),
|
tor_lround(guard->timeouts),
|
||||||
tor_lround(circ_times.close_ms/1000));
|
tor_lround(circ_times.close_ms/1000));
|
||||||
}
|
}
|
||||||
} else if (pathbias_get_success_count(guard)/((double)guard->circ_attempts)
|
} else if (pathbias_get_close_success_count(guard)/guard->circ_attempts
|
||||||
< pathbias_get_notice_rate(options)) {
|
< pathbias_get_notice_rate(options)) {
|
||||||
if (!guard->path_bias_noticed) {
|
if (!guard->path_bias_noticed) {
|
||||||
guard->path_bias_noticed = 1;
|
guard->path_bias_noticed = 1;
|
||||||
log_notice(LD_CIRC,
|
log_notice(LD_CIRC,
|
||||||
"Your Guard %s=%s is failing more circuits than usual. "
|
"Your Guard %s=%s is failing more circuits than "
|
||||||
"Most likely this means the Tor network is overloaded. "
|
"usual. "
|
||||||
"Success counts are %ld/%ld. %ld circuits completed, %ld "
|
"Most likely this means the Tor network is overloaded. "
|
||||||
"were unusable, %ld collapsed, and %ld timed out. For "
|
"Success counts are %ld/%ld. Use counts are %ld/%ld. "
|
||||||
"reference, your timeout cutoff is %ld seconds.",
|
"%ld circuits completed, %ld were unusable, %ld collapsed, "
|
||||||
guard->nickname, hex_str(guard->identity, DIGEST_LEN),
|
"and %ld timed out. "
|
||||||
tor_lround(pathbias_get_closed_count(guard)),
|
"For reference, your timeout cutoff is %ld seconds.",
|
||||||
tor_lround(guard->circ_attempts),
|
guard->nickname, hex_str(guard->identity, DIGEST_LEN),
|
||||||
tor_lround(guard->circ_successes),
|
tor_lround(pathbias_get_close_success_count(guard)),
|
||||||
tor_lround(guard->unusable_circuits),
|
tor_lround(guard->circ_attempts),
|
||||||
tor_lround(guard->collapsed_circuits),
|
tor_lround(pathbias_get_use_success_count(guard)),
|
||||||
tor_lround(guard->timeouts),
|
tor_lround(guard->use_attempts),
|
||||||
tor_lround(circ_times.close_ms/1000));
|
tor_lround(guard->circ_successes),
|
||||||
|
tor_lround(guard->unusable_circuits),
|
||||||
|
tor_lround(guard->collapsed_circuits),
|
||||||
|
tor_lround(guard->timeouts),
|
||||||
|
tor_lround(circ_times.close_ms/1000));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2054,7 +2416,24 @@ entry_guard_inc_circ_attempt_count(entry_guard_t *guard)
|
|||||||
guard->collapsed_circuits /= scale_factor;
|
guard->collapsed_circuits /= scale_factor;
|
||||||
guard->unusable_circuits /= scale_factor;
|
guard->unusable_circuits /= scale_factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 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
|
||||||
|
* guard looks fine. */
|
||||||
|
static int
|
||||||
|
entry_guard_inc_circ_attempt_count(entry_guard_t *guard)
|
||||||
|
{
|
||||||
|
entry_guards_changed();
|
||||||
|
|
||||||
|
if (pathbias_check_close_rate(guard) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
guard->circ_attempts++;
|
guard->circ_attempts++;
|
||||||
|
|
||||||
log_info(LD_CIRC, "Got success count %f/%f for guard %s=%s",
|
log_info(LD_CIRC, "Got success count %f/%f for guard %s=%s",
|
||||||
guard->circ_successes, guard->circ_attempts, guard->nickname,
|
guard->circ_successes, guard->circ_attempts, guard->nickname,
|
||||||
hex_str(guard->identity, DIGEST_LEN));
|
hex_str(guard->identity, DIGEST_LEN));
|
||||||
@ -2078,7 +2457,7 @@ circuit_finish_handshake(origin_circuit_t *circ,
|
|||||||
crypt_path_t *hop;
|
crypt_path_t *hop;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
if ((rv = pathbias_count_circ_attempt(circ)) < 0)
|
if ((rv = pathbias_count_build_attempt(circ)) < 0)
|
||||||
return rv;
|
return rv;
|
||||||
|
|
||||||
if (circ->cpath->state == CPATH_STATE_AWAITING_KEYS) {
|
if (circ->cpath->state == CPATH_STATE_AWAITING_KEYS) {
|
||||||
|
@ -58,10 +58,13 @@ const char *build_state_get_exit_nickname(cpath_build_state_t *state);
|
|||||||
const node_t *choose_good_entry_server(uint8_t purpose,
|
const node_t *choose_good_entry_server(uint8_t purpose,
|
||||||
cpath_build_state_t *state);
|
cpath_build_state_t *state);
|
||||||
double pathbias_get_extreme_rate(const or_options_t *options);
|
double pathbias_get_extreme_rate(const or_options_t *options);
|
||||||
|
double pathbias_get_extreme_use_rate(const or_options_t *options);
|
||||||
int pathbias_get_dropguards(const or_options_t *options);
|
int pathbias_get_dropguards(const or_options_t *options);
|
||||||
void pathbias_count_timeout(origin_circuit_t *circ);
|
void pathbias_count_timeout(origin_circuit_t *circ);
|
||||||
int pathbias_check_close(origin_circuit_t *circ, int reason);
|
int pathbias_check_close(origin_circuit_t *circ, int reason);
|
||||||
int pathbias_check_probe_response(circuit_t *circ, const cell_t *cell);
|
int pathbias_check_probe_response(circuit_t *circ, const cell_t *cell);
|
||||||
|
void pathbias_count_use_attempt(origin_circuit_t *circ);
|
||||||
|
void pathbias_mark_use_success(origin_circuit_t *circ);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -2037,6 +2037,8 @@ connection_ap_handshake_attach_chosen_circuit(entry_connection_t *conn,
|
|||||||
if (!circ->base_.timestamp_dirty)
|
if (!circ->base_.timestamp_dirty)
|
||||||
circ->base_.timestamp_dirty = time(NULL);
|
circ->base_.timestamp_dirty = time(NULL);
|
||||||
|
|
||||||
|
pathbias_count_use_attempt(circ);
|
||||||
|
|
||||||
link_apconn_to_circ(conn, circ, cpath);
|
link_apconn_to_circ(conn, circ, cpath);
|
||||||
tor_assert(conn->socks_request);
|
tor_assert(conn->socks_request);
|
||||||
if (conn->socks_request->command == SOCKS_COMMAND_CONNECT) {
|
if (conn->socks_request->command == SOCKS_COMMAND_CONNECT) {
|
||||||
@ -2163,6 +2165,11 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn)
|
|||||||
* feasibility, at this point.
|
* feasibility, at this point.
|
||||||
*/
|
*/
|
||||||
rendcirc->base_.timestamp_dirty = time(NULL);
|
rendcirc->base_.timestamp_dirty = time(NULL);
|
||||||
|
|
||||||
|
/* We've also attempted to use them. If they fail, we need to
|
||||||
|
* probe them for path bias */
|
||||||
|
pathbias_count_use_attempt(rendcirc);
|
||||||
|
|
||||||
link_apconn_to_circ(conn, rendcirc, NULL);
|
link_apconn_to_circ(conn, rendcirc, NULL);
|
||||||
if (connection_ap_handshake_send_begin(conn) < 0)
|
if (connection_ap_handshake_send_begin(conn) < 0)
|
||||||
return 0; /* already marked, let them fade away */
|
return 0; /* already marked, let them fade away */
|
||||||
@ -2214,6 +2221,10 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn)
|
|||||||
case 0: /* success */
|
case 0: /* success */
|
||||||
rendcirc->base_.timestamp_dirty = time(NULL);
|
rendcirc->base_.timestamp_dirty = time(NULL);
|
||||||
introcirc->base_.timestamp_dirty = time(NULL);
|
introcirc->base_.timestamp_dirty = time(NULL);
|
||||||
|
|
||||||
|
pathbias_count_use_attempt(introcirc);
|
||||||
|
pathbias_count_use_attempt(rendcirc);
|
||||||
|
|
||||||
assert_circuit_ok(TO_CIRCUIT(rendcirc));
|
assert_circuit_ok(TO_CIRCUIT(rendcirc));
|
||||||
assert_circuit_ok(TO_CIRCUIT(introcirc));
|
assert_circuit_ok(TO_CIRCUIT(introcirc));
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -323,7 +323,12 @@ static config_var_t option_vars_[] = {
|
|||||||
V(PathBiasScaleFactor, INT, "-1"),
|
V(PathBiasScaleFactor, INT, "-1"),
|
||||||
V(PathBiasMultFactor, INT, "-1"),
|
V(PathBiasMultFactor, INT, "-1"),
|
||||||
V(PathBiasDropGuards, AUTOBOOL, "0"),
|
V(PathBiasDropGuards, AUTOBOOL, "0"),
|
||||||
V(PathBiasUseCloseCounts, AUTOBOOL, "1"),
|
OBSOLETE("PathBiasUseCloseCounts"),
|
||||||
|
|
||||||
|
V(PathBiasUseThreshold, INT, "-1"),
|
||||||
|
V(PathBiasNoticeUseRate, DOUBLE, "-1"),
|
||||||
|
V(PathBiasExtremeUseRate, DOUBLE, "-1"),
|
||||||
|
V(PathBiasScaleUseThreshold, INT, "-1"),
|
||||||
|
|
||||||
OBSOLETE("PathlenCoinWeight"),
|
OBSOLETE("PathlenCoinWeight"),
|
||||||
V(PerConnBWBurst, MEMUNIT, "0"),
|
V(PerConnBWBurst, MEMUNIT, "0"),
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include "router.h"
|
#include "router.h"
|
||||||
#include "routerlist.h"
|
#include "routerlist.h"
|
||||||
#include "routerset.h"
|
#include "routerset.h"
|
||||||
|
#include "circuitbuild.h"
|
||||||
|
|
||||||
#ifdef HAVE_LINUX_TYPES_H
|
#ifdef HAVE_LINUX_TYPES_H
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
@ -2205,8 +2206,10 @@ connection_ap_handshake_socks_reply(entry_connection_t *conn, char *reply,
|
|||||||
U64_PRINTF_ARG(ENTRY_TO_CONN(conn)->global_identifier),
|
U64_PRINTF_ARG(ENTRY_TO_CONN(conn)->global_identifier),
|
||||||
endreason);
|
endreason);
|
||||||
} else {
|
} else {
|
||||||
TO_ORIGIN_CIRCUIT(conn->edge_.on_circuit)->path_state
|
// XXX: Hrmm. It looks like optimistic data can't go through this
|
||||||
= PATH_STATE_USE_SUCCEEDED;
|
// codepath, but someone should probably test it and make sure.
|
||||||
|
// We don't want to mark optimistically opened streams as successful.
|
||||||
|
pathbias_mark_use_success(TO_ORIGIN_CIRCUIT(conn->edge_.on_circuit));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2480,7 +2483,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
|
|||||||
connection_exit_connect(n_stream);
|
connection_exit_connect(n_stream);
|
||||||
|
|
||||||
/* For path bias: This circuit was used successfully */
|
/* For path bias: This circuit was used successfully */
|
||||||
origin_circ->path_state = PATH_STATE_USE_SUCCEEDED;
|
pathbias_mark_use_success(origin_circ);
|
||||||
|
|
||||||
tor_free(address);
|
tor_free(address);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1098,6 +1098,40 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
digestmap_set(added_by, d, tor_strdup(line->value+HEX_DIGEST_LEN+1));
|
digestmap_set(added_by, d, tor_strdup(line->value+HEX_DIGEST_LEN+1));
|
||||||
|
} else if (!strcasecmp(line->key, "EntryGuardPathUseBias")) {
|
||||||
|
const or_options_t *options = get_options();
|
||||||
|
double use_cnt, success_cnt;
|
||||||
|
|
||||||
|
if (!node) {
|
||||||
|
*msg = tor_strdup("Unable to parse entry nodes: "
|
||||||
|
"EntryGuardPathUseBias without EntryGuard");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tor_sscanf(line->value, "%lf %lf",
|
||||||
|
&use_cnt, &success_cnt) != 2) {
|
||||||
|
log_info(LD_GENERAL, "Malformed path use bias line for node %s",
|
||||||
|
node->nickname);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->use_attempts = use_cnt;
|
||||||
|
node->use_successes = success_cnt;
|
||||||
|
|
||||||
|
log_info(LD_GENERAL, "Read %f/%f path use bias for node %s",
|
||||||
|
node->use_successes, node->use_attempts, node->nickname);
|
||||||
|
|
||||||
|
/* Note: We rely on the < comparison here to allow us to set a 0
|
||||||
|
* rate and disable the feature entirely. If refactoring, don't
|
||||||
|
* change to <= */
|
||||||
|
if (pathbias_get_use_success_count(node)/node->use_attempts
|
||||||
|
< pathbias_get_extreme_use_rate(options) &&
|
||||||
|
pathbias_get_dropguards(options)) {
|
||||||
|
node->path_bias_disabled = 1;
|
||||||
|
log_info(LD_GENERAL,
|
||||||
|
"Path use bias is too high (%f/%f); disabling node %s",
|
||||||
|
node->circ_successes, node->circ_attempts, node->nickname);
|
||||||
|
}
|
||||||
} else if (!strcasecmp(line->key, "EntryGuardPathBias")) {
|
} else if (!strcasecmp(line->key, "EntryGuardPathBias")) {
|
||||||
const or_options_t *options = get_options();
|
const or_options_t *options = get_options();
|
||||||
double hop_cnt, success_cnt, timeouts, collapsed, successful_closed,
|
double hop_cnt, success_cnt, timeouts, collapsed, successful_closed,
|
||||||
@ -1144,7 +1178,7 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg)
|
|||||||
/* Note: We rely on the < comparison here to allow us to set a 0
|
/* Note: We rely on the < comparison here to allow us to set a 0
|
||||||
* rate and disable the feature entirely. If refactoring, don't
|
* rate and disable the feature entirely. If refactoring, don't
|
||||||
* change to <= */
|
* change to <= */
|
||||||
if (pathbias_get_success_count(node)/node->circ_attempts
|
if (pathbias_get_close_success_count(node)/node->circ_attempts
|
||||||
< pathbias_get_extreme_rate(options) &&
|
< pathbias_get_extreme_rate(options) &&
|
||||||
pathbias_get_dropguards(options)) {
|
pathbias_get_dropguards(options)) {
|
||||||
node->path_bias_disabled = 1;
|
node->path_bias_disabled = 1;
|
||||||
@ -1282,10 +1316,20 @@ entry_guards_update_state(or_state_t *state)
|
|||||||
* unusable_circuits */
|
* unusable_circuits */
|
||||||
tor_asprintf(&line->value, "%f %f %f %f %f %f",
|
tor_asprintf(&line->value, "%f %f %f %f %f %f",
|
||||||
e->circ_attempts, e->circ_successes,
|
e->circ_attempts, e->circ_successes,
|
||||||
pathbias_get_closed_count(e), e->collapsed_circuits,
|
pathbias_get_close_success_count(e),
|
||||||
|
e->collapsed_circuits,
|
||||||
e->unusable_circuits, e->timeouts);
|
e->unusable_circuits, e->timeouts);
|
||||||
next = &(line->next);
|
next = &(line->next);
|
||||||
}
|
}
|
||||||
|
if (e->use_attempts > 0) {
|
||||||
|
*next = line = tor_malloc_zero(sizeof(config_line_t));
|
||||||
|
line->key = tor_strdup("EntryGuardPathUseBias");
|
||||||
|
|
||||||
|
tor_asprintf(&line->value, "%f %f",
|
||||||
|
e->use_attempts,
|
||||||
|
pathbias_get_use_success_count(e));
|
||||||
|
next = &(line->next);
|
||||||
|
}
|
||||||
|
|
||||||
} SMARTLIST_FOREACH_END(e);
|
} SMARTLIST_FOREACH_END(e);
|
||||||
if (!get_options()->AvoidDiskWrites)
|
if (!get_options()->AvoidDiskWrites)
|
||||||
|
@ -61,6 +61,9 @@ typedef struct entry_guard_t {
|
|||||||
* attempted, but none succeeded. */
|
* attempted, but none succeeded. */
|
||||||
double timeouts; /**< Number of 'right-censored' circuit timeouts for this
|
double timeouts; /**< Number of 'right-censored' circuit timeouts for this
|
||||||
* guard. */
|
* guard. */
|
||||||
|
double use_attempts; /**< Number of circuits we tried to use with streams */
|
||||||
|
double use_successes; /**< Number of successfully used circuits using
|
||||||
|
* this guard as first hop. */
|
||||||
} entry_guard_t;
|
} entry_guard_t;
|
||||||
|
|
||||||
entry_guard_t *entry_guard_get_by_id_digest(const char *digest);
|
entry_guard_t *entry_guard_get_by_id_digest(const char *digest);
|
||||||
@ -113,8 +116,8 @@ int find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port,
|
|||||||
|
|
||||||
int validate_pluggable_transports_config(void);
|
int validate_pluggable_transports_config(void);
|
||||||
|
|
||||||
double pathbias_get_closed_count(entry_guard_t *gaurd);
|
double pathbias_get_close_success_count(entry_guard_t *guard);
|
||||||
double pathbias_get_success_count(entry_guard_t *guard);
|
double pathbias_get_use_success_count(entry_guard_t *guard);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
32
src/or/or.h
32
src/or/or.h
@ -2838,6 +2838,15 @@ typedef enum {
|
|||||||
PATH_STATE_BUILD_ATTEMPTED = 1,
|
PATH_STATE_BUILD_ATTEMPTED = 1,
|
||||||
/** This circuit has been completely built */
|
/** This circuit has been completely built */
|
||||||
PATH_STATE_BUILD_SUCCEEDED = 2,
|
PATH_STATE_BUILD_SUCCEEDED = 2,
|
||||||
|
/** Did we try to attach any SOCKS streams or hidserv introductions to
|
||||||
|
* this circuit?
|
||||||
|
*
|
||||||
|
* Note: If we ever implement end-to-end stream timing through test
|
||||||
|
* stream probes (#5707), we must *not* set this for those probes
|
||||||
|
* (or any other automatic streams) because the adversary could
|
||||||
|
* just tag at a later point.
|
||||||
|
*/
|
||||||
|
PATH_STATE_USE_ATTEMPTED = 3,
|
||||||
/** Did any SOCKS streams or hidserv introductions actually succeed on
|
/** Did any SOCKS streams or hidserv introductions actually succeed on
|
||||||
* this circuit?
|
* this circuit?
|
||||||
*
|
*
|
||||||
@ -2846,13 +2855,20 @@ typedef enum {
|
|||||||
* (or any other automatic streams) because the adversary could
|
* (or any other automatic streams) because the adversary could
|
||||||
* just tag at a later point.
|
* just tag at a later point.
|
||||||
*/
|
*/
|
||||||
PATH_STATE_USE_SUCCEEDED = 3,
|
PATH_STATE_USE_SUCCEEDED = 4,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a special state to indicate that we got a corrupted
|
* This is a special state to indicate that we got a corrupted
|
||||||
* relay cell on a circuit and we don't intend to probe it.
|
* relay cell on a circuit and we don't intend to probe it.
|
||||||
*/
|
*/
|
||||||
PATH_STATE_USE_FAILED = 4,
|
PATH_STATE_USE_FAILED = 5,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a special state to indicate that we already counted
|
||||||
|
* the circuit. Used to guard against potential state machine
|
||||||
|
* violations.
|
||||||
|
*/
|
||||||
|
PATH_STATE_ALREADY_COUNTED = 6,
|
||||||
} path_state_t;
|
} path_state_t;
|
||||||
|
|
||||||
/** An origin_circuit_t holds data necessary to build and use a circuit.
|
/** An origin_circuit_t holds data necessary to build and use a circuit.
|
||||||
@ -2997,7 +3013,6 @@ typedef struct origin_circuit_t {
|
|||||||
* ISO_STREAM. */
|
* ISO_STREAM. */
|
||||||
uint64_t associated_isolated_stream_global_id;
|
uint64_t associated_isolated_stream_global_id;
|
||||||
/**@}*/
|
/**@}*/
|
||||||
|
|
||||||
} origin_circuit_t;
|
} origin_circuit_t;
|
||||||
|
|
||||||
/** An or_circuit_t holds information needed to implement a circuit at an
|
/** An or_circuit_t holds information needed to implement a circuit at an
|
||||||
@ -3909,7 +3924,16 @@ typedef struct {
|
|||||||
int PathBiasScaleThreshold;
|
int PathBiasScaleThreshold;
|
||||||
int PathBiasScaleFactor;
|
int PathBiasScaleFactor;
|
||||||
int PathBiasMultFactor;
|
int PathBiasMultFactor;
|
||||||
int PathBiasUseCloseCounts;
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters for path-bias use detection
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
int PathBiasUseThreshold;
|
||||||
|
double PathBiasNoticeUseRate;
|
||||||
|
double PathBiasExtremeUseRate;
|
||||||
|
int PathBiasScaleUseThreshold;
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
int IPv6Exit; /**< Do we support exiting to IPv6 addresses? */
|
int IPv6Exit; /**< Do we support exiting to IPv6 addresses? */
|
||||||
|
@ -730,7 +730,7 @@ connection_ap_process_end_not_open(
|
|||||||
* We rely on recognized+digest being strong enough to make
|
* We rely on recognized+digest being strong enough to make
|
||||||
* tags unlikely to allow us to get tagged, yet 'recognized'
|
* tags unlikely to allow us to get tagged, yet 'recognized'
|
||||||
* reason codes here. */
|
* reason codes here. */
|
||||||
circ->path_state = PATH_STATE_USE_SUCCEEDED;
|
pathbias_mark_use_success(circ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +71,9 @@ rend_client_send_establish_rendezvous(origin_circuit_t *circ)
|
|||||||
* and the rend cookie also means we've used the circ. */
|
* and the rend cookie also means we've used the circ. */
|
||||||
circ->base_.timestamp_dirty = time(NULL);
|
circ->base_.timestamp_dirty = time(NULL);
|
||||||
|
|
||||||
|
/* We've attempted to use this circuit. Probe it if we fail */
|
||||||
|
pathbias_count_use_attempt(circ);
|
||||||
|
|
||||||
if (relay_send_command_from_edge(0, TO_CIRCUIT(circ),
|
if (relay_send_command_from_edge(0, TO_CIRCUIT(circ),
|
||||||
RELAY_COMMAND_ESTABLISH_RENDEZVOUS,
|
RELAY_COMMAND_ESTABLISH_RENDEZVOUS,
|
||||||
circ->rend_data->rend_cookie,
|
circ->rend_data->rend_cookie,
|
||||||
@ -316,6 +319,8 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
|
|||||||
* state. */
|
* state. */
|
||||||
introcirc->base_.timestamp_dirty = time(NULL);
|
introcirc->base_.timestamp_dirty = time(NULL);
|
||||||
|
|
||||||
|
pathbias_count_use_attempt(introcirc);
|
||||||
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
perm_err:
|
perm_err:
|
||||||
@ -395,7 +400,7 @@ rend_client_introduction_acked(origin_circuit_t *circ,
|
|||||||
|
|
||||||
/* For path bias: This circuit was used successfully. Valid
|
/* For path bias: This circuit was used successfully. Valid
|
||||||
* nacks and acks count. */
|
* nacks and acks count. */
|
||||||
circ->path_state = PATH_STATE_USE_SUCCEEDED;
|
pathbias_mark_use_success(circ);
|
||||||
|
|
||||||
if (request_len == 0) {
|
if (request_len == 0) {
|
||||||
/* It's an ACK; the introduction point relayed our introduction request. */
|
/* It's an ACK; the introduction point relayed our introduction request. */
|
||||||
@ -902,7 +907,7 @@ rend_client_rendezvous_acked(origin_circuit_t *circ, const uint8_t *request,
|
|||||||
* Waiting any longer opens us up to attacks from Bob. He could induce
|
* Waiting any longer opens us up to attacks from Bob. He could induce
|
||||||
* Alice to attempt to connect to his hidden service and never reply
|
* Alice to attempt to connect to his hidden service and never reply
|
||||||
* to her rend requests */
|
* to her rend requests */
|
||||||
circ->path_state = PATH_STATE_USE_SUCCEEDED;
|
pathbias_mark_use_success(circ);
|
||||||
|
|
||||||
/* XXXX This is a pretty brute-force approach. It'd be better to
|
/* XXXX This is a pretty brute-force approach. It'd be better to
|
||||||
* attach only the connections that are waiting on this circuit, rather
|
* attach only the connections that are waiting on this circuit, rather
|
||||||
|
@ -1384,9 +1384,6 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
|
|||||||
goto err;
|
goto err;
|
||||||
memcpy(cpath->rend_circ_nonce, keys, DIGEST_LEN);
|
memcpy(cpath->rend_circ_nonce, keys, DIGEST_LEN);
|
||||||
|
|
||||||
/* For path bias: This intro circuit was used successfully */
|
|
||||||
circuit->path_state = PATH_STATE_USE_SUCCEEDED;
|
|
||||||
|
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
log_error:
|
log_error:
|
||||||
@ -2511,6 +2508,9 @@ rend_service_intro_has_opened(origin_circuit_t *circuit)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We've attempted to use this circuit */
|
||||||
|
pathbias_count_use_attempt(circuit);
|
||||||
|
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
@ -2558,6 +2558,10 @@ rend_service_intro_established(origin_circuit_t *circuit,
|
|||||||
"Received INTRO_ESTABLISHED cell on circuit %d for service %s",
|
"Received INTRO_ESTABLISHED cell on circuit %d for service %s",
|
||||||
circuit->base_.n_circ_id, serviceid);
|
circuit->base_.n_circ_id, serviceid);
|
||||||
|
|
||||||
|
/* Getting a valid INTRODUCE_ESTABLISHED means we've successfully
|
||||||
|
* used the circ */
|
||||||
|
pathbias_mark_use_success(circuit);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
err:
|
err:
|
||||||
circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_REASON_TORPROTOCOL);
|
circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_REASON_TORPROTOCOL);
|
||||||
@ -2589,6 +2593,9 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit)
|
|||||||
if (!circuit->base_.timestamp_dirty)
|
if (!circuit->base_.timestamp_dirty)
|
||||||
circuit->base_.timestamp_dirty = time(NULL);
|
circuit->base_.timestamp_dirty = time(NULL);
|
||||||
|
|
||||||
|
/* This may be redundant */
|
||||||
|
pathbias_count_use_attempt(circuit);
|
||||||
|
|
||||||
hop = circuit->build_state->service_pending_final_cpath_ref->cpath;
|
hop = circuit->build_state->service_pending_final_cpath_ref->cpath;
|
||||||
|
|
||||||
base16_encode(hexcookie,9,circuit->rend_data->rend_cookie,4);
|
base16_encode(hexcookie,9,circuit->rend_data->rend_cookie,4);
|
||||||
|
Loading…
Reference in New Issue
Block a user