Add a MinTimeToReportBandwidth option; make it 0 for testing networks.

This option changes the time for which a bandwidth measurement period
must have been in progress before we include it when reporting our
observed bandwidth in our descriptors.  Without this option, we only
consider a time period towards our maximum if it has been running
for a full day.  Obviously, that's unacceptable for testing
networks, where we'd like to get results as soon as possible.

For non-testing networks, I've put a (somewhat arbitrary) 2-hour
minimum on the option, since there are traffic analysis concerns
with immediate reporting here.

Closes #40337.
This commit is contained in:
Nick Mathewson 2021-03-17 08:45:37 -04:00
parent 59bbf8cde9
commit 2ae24d003d
9 changed files with 56 additions and 8 deletions

12
changes/ticket40337 Normal file
View File

@ -0,0 +1,12 @@
o Minor features (bandwidth reporting):
- Relays can now use the MinTimeToReportBandwidth option to change
the smallest amount of time over which they're willing to report
their observed maximum bandwidth. Previously, this was fixed
at 1 day. For safety, values under 2 hours are only supported on
testing networks. Part of a fix for ticket 40337.
o Minor features (testing):
- Relays on testing networks now report their observed bandwidths
immediately from startup. Previously, they waited
until they had been running for a full day. Closes ticket
40337.

View File

@ -2448,6 +2448,13 @@ is non-zero):
If we have more onionskins queued for processing than we can process in
this amount of time, reject new ones. (Default: 1750 msec)
[[MinTimeToReportBandwidth]] **MinTimeToReportBandwidth** __N__ **seconds**|**minutes**|**hours**::
Do not report our measurements for our maximum observed bandwidth for any
time period that has lasted for less than this amount of time.
Setting this option too low can enable traffic analysis, and is
not permitted except on testing networks. Values over 1 day have
no effect. (Default: 1 day)
[[MyFamily]] **MyFamily** __fingerprint__,__fingerprint__,...::
Declare that this Tor relay is controlled or administered by a group or
organization identical or similar to that of the other relays, defined by

View File

@ -563,6 +563,7 @@ static const config_var_t option_vars_[] = {
V(MaxUnparseableDescSizeToLog, MEMUNIT, "10 MB"),
VPORT(MetricsPort),
V(MetricsPortPolicy, LINELIST, NULL),
V(MinTimeToReportBandwidth, INTERVAL, "1 day"),
VAR("MyFamily", LINELIST, MyFamily_lines, NULL),
V(NewCircuitPeriod, INTERVAL, "30 seconds"),
OBSOLETE("NamingAuthoritativeDirectory"),
@ -3711,6 +3712,13 @@ options_validate_cb(const void *old_options_, void *options_, char **msg)
options->HeartbeatPeriod = MIN_HEARTBEAT_PERIOD;
}
if (options->MinTimeToReportBandwidth < MIN_MIN_TIME_TO_REPORT_BW &&
!options->TestingTorNetwork) {
log_warn(LD_CONFIG, "MinTimeToReportBandwidth is too short; "
"raising to %d seconds.", MIN_MIN_TIME_TO_REPORT_BW);
options->MinTimeToReportBandwidth = MIN_MIN_TIME_TO_REPORT_BW;
}
if (options->KeepalivePeriod < 1)
REJECT("KeepalivePeriod option must be positive.");

View File

@ -24,6 +24,13 @@
* expose more information than we're comfortable with. */
#define MIN_HEARTBEAT_PERIOD (30*60)
/**
* Lowest allowable value for MinTimeToReportBandwidth on a non-testing
* network; if this is too low we might report detail that is too
* fine-grained.
**/
#define MIN_MIN_TIME_TO_REPORT_BW (2*60*60)
/** Maximum default value for MaxMemInQueues, in bytes. */
#if SIZEOF_VOID_P >= 8
#define MAX_DEFAULT_MEMORY_QUEUE_SIZE (UINT64_C(8) << 30)

View File

@ -1082,6 +1082,10 @@ struct or_options_t {
/** List of policy allowed to query the Metrics port. */
struct config_line_t *MetricsPortPolicy;
/** How far must we be into the current bandwidth-measurement period to
* report bandwidth observations from this period? */
int MinTimeToReportBandwidth;
/**
* Configuration objects for individual modules.
*

View File

@ -19,6 +19,7 @@
{ "TestingV3AuthInitialDistDelay", "20 seconds" },
{ "TestingAuthDirTimeToLearnReachability", "0 minutes" },
{ "MinUptimeHidServDirectoryV2", "0 minutes" },
{ "MinTimeToReportBandwidth", "0 seconds" },
{ "TestingServerDownloadInitialDelay", "0" },
{ "TestingClientDownloadInitialDelay", "0" },
{ "TestingServerConsensusDownloadInitialDelay", "0" },

View File

@ -206,16 +206,24 @@ bwhist_note_dir_bytes_read(uint64_t num_bytes, time_t when)
add_obs(dir_read_array, when, num_bytes);
}
/** Helper: Return the largest value in b->maxima. (This is equal to the
/**
* Helper: Return the largest value in b->maxima. (This is equal to the
* most bandwidth used in any NUM_SECS_ROLLING_MEASURE period for the last
* NUM_SECS_BW_SUM_IS_VALID seconds.)
*
* Also include the current period if we have been observing it for
* at least min_observation_time seconds.
*/
STATIC uint64_t
find_largest_max(bw_array_t *b)
find_largest_max(bw_array_t *b, int min_observation_time)
{
int i;
uint64_t max;
max=0;
time_t period_start = b->next_period - NUM_SECS_BW_SUM_INTERVAL;
if (b->cur_obs_time > period_start + min_observation_time)
max = b->max_total;
else
max = 0;
for (i=0; i<NUM_TOTALS; ++i) {
if (b->maxima[i]>max)
max = b->maxima[i];
@ -233,8 +241,9 @@ MOCK_IMPL(int,
bwhist_bandwidth_assess,(void))
{
uint64_t w,r;
r = find_largest_max(read_array);
w = find_largest_max(write_array);
int min_obs_time = get_options()->MinTimeToReportBandwidth;
r = find_largest_max(read_array, min_obs_time);
w = find_largest_max(write_array, min_obs_time);
if (r>w)
return (int)(((double)w)/NUM_SECS_ROLLING_MEASURE);
else

View File

@ -28,7 +28,7 @@ int bwhist_load_state(struct or_state_t *state, char **err);
#ifdef BWHIST_PRIVATE
typedef struct bw_array_t bw_array_t;
STATIC uint64_t find_largest_max(bw_array_t *b);
STATIC uint64_t find_largest_max(bw_array_t *b, int min_observation_time);
STATIC void commit_max(bw_array_t *b);
STATIC void advance_obs(bw_array_t *b);
STATIC bw_array_t *bw_array_new(void);

View File

@ -98,7 +98,7 @@ test_relay_close_circuit(void *arg)
tt_int_op(new_count, OP_EQ, old_count + 1);
/* Ensure our write totals are 0 */
tt_u64_op(find_largest_max(write_array), OP_EQ, 0);
tt_u64_op(find_largest_max(write_array, 86400), OP_EQ, 0);
/* Mark the circuit for close */
circuit_mark_for_close(TO_CIRCUIT(orcirc), 0);
@ -107,7 +107,7 @@ test_relay_close_circuit(void *arg)
advance_obs(write_array);
commit_max(write_array);
/* Check for two cells plus overhead */
tt_u64_op(find_largest_max(write_array), OP_EQ,
tt_u64_op(find_largest_max(write_array, 86400), OP_EQ,
2*(get_cell_network_size(nchan->wide_circ_ids)
+TLS_PER_CELL_OVERHEAD));