/** * This function decides if CBT learning should be disabled. It returns * true if one or more of the following four conditions are met: * * 1. If the cbtdisabled consensus parameter is set. * 2. If the torrc option LearnCircuitBuildTimeout is false. * 3. If we are a directory authority * 4. If we fail to write circuit build time history to our state file. */ int circuit_build_times_disabled(void) { if (unit_tests) { return 0; } else { int consensus_disabled = networkstatus_get_param(NULL, "cbtdisabled", 0, 0, 1); int config_disabled = !get_options()->LearnCircuitBuildTimeout; int dirauth_disabled = get_options()->AuthoritativeDir; int state_disabled = did_last_state_file_write_fail() ? 1 : 0; if (consensus_disabled || config_disabled || dirauth_disabled || state_disabled) { log_debug(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 { log_debug(LD_CIRC, "CircuitBuildTime learning is not disabled. " "Consensus=%d, Config=%d, AuthDir=%d, StateFile=%d", consensus_disabled, config_disabled, dirauth_disabled, state_disabled); return 0; } } }
/* Return the minimum version given by the consensus (if any) that should be * accepted when receiving a SENDME cell. */ STATIC int get_accept_min_version(void) { return networkstatus_get_param(NULL, "sendme_accept_min_version", SENDME_ACCEPT_MIN_VERSION_DEFAULT, SENDME_ACCEPT_MIN_VERSION_MIN, SENDME_ACCEPT_MIN_VERSION_MAX); }
/* DOCDOC circuit_build_times_get_bw_scale */ int circuit_build_times_get_bw_scale(networkstatus_t *ns) { return networkstatus_get_param(ns, "bwweightscale", BW_WEIGHT_SCALE, BW_MIN_WEIGHT_SCALE, BW_MAX_WEIGHT_SCALE); }
/** Pick a reasonable package_window to start out for our circuits. * Originally this was hard-coded at 1000, but now the consensus votes * on the answer. See proposal 168. */ int32_t circuit_initial_package_window(void) { int32_t num = networkstatus_get_param(NULL, "circwindow", CIRCWINDOW_START); /* If the consensus tells us a negative number, we'd assert. */ if (num < 0) num = CIRCWINDOW_START; return num; }
/** Return a fairness parameter, to prefer processing NTOR style * handshakes but still slowly drain the TAP queue so we don't starve * it entirely. */ static int num_ntors_per_tap(void) { #define DEFAULT_NUM_NTORS_PER_TAP 10 #define MIN_NUM_NTORS_PER_TAP 1 #define MAX_NUM_NTORS_PER_TAP 100000 return networkstatus_get_param(NULL, "NumNTorsPerTAP", DEFAULT_NUM_NTORS_PER_TAP, MIN_NUM_NTORS_PER_TAP, MAX_NUM_NTORS_PER_TAP); }
/** Return true iff we are configured (by torrc or by the networkstatus * parameters) to use Ed25519 identities in our Extend2 cells. */ static int should_include_ed25519_id_extend_cells(const networkstatus_t *ns, const or_options_t *options) { if (options->ExtendByEd25519ID != -1) return options->ExtendByEd25519ID; /* The user has an opinion. */ return (int) networkstatus_get_param(ns, "ExtendByEd25519ID", 0 /* default */, 0 /* min */, 1 /*max*/); }
/** * Retrieve and bounds-check the cbtmintimeout consensus parameter. * * Effect: This is the minimum allowed timeout value in milliseconds. * The minimum is to prevent rounding to 0 (we only check once * per second). */ static int32_t circuit_build_times_min_timeout(void) { int32_t num = networkstatus_get_param(NULL, "cbtmintimeout", CBT_DEFAULT_TIMEOUT_MIN_VALUE, CBT_MIN_TIMEOUT_MIN_VALUE, CBT_MAX_TIMEOUT_MIN_VALUE); if (!(get_options()->LearnCircuitBuildTimeout)) { log_debug(LD_BUG, "circuit_build_times_min_timeout() called, cbtmintimeout is %d", num); } return num; }
/** * Retrieve and bounds-check the cbttestfreq consensus paramter. * * Effect: Describes how often in seconds to build a test circuit to * gather timeout values. Only applies if less than 'cbtmincircs' * have been recorded. */ static int32_t circuit_build_times_test_frequency(void) { int32_t num = networkstatus_get_param(NULL, "cbttestfreq", CBT_DEFAULT_TEST_FREQUENCY, CBT_MIN_TEST_FREQUENCY, CBT_MAX_TEST_FREQUENCY); if (!(get_options()->LearnCircuitBuildTimeout)) { log_debug(LD_BUG, "circuit_build_times_test_frequency() called, cbttestfreq is %d", num); } return num; }
/** * Retrieve and bounds-check the cbtmincircs consensus paramter. * * Effect: This is the minimum number of circuits to build before * computing a timeout. */ static int32_t circuit_build_times_min_circs_to_observe(void) { int32_t num = networkstatus_get_param(NULL, "cbtmincircs", CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE, CBT_MIN_MIN_CIRCUITS_TO_OBSERVE, CBT_MAX_MIN_CIRCUITS_TO_OBSERVE); if (!(get_options()->LearnCircuitBuildTimeout)) { log_debug(LD_BUG, "circuit_build_times_min_circs_to_observe() called, cbtmincircs" " is %d", num); } return num; }
/** * Retrieve and bounds-check the cbtquantile consensus paramter. * * Effect: This is the position on the quantile curve to use to set the * timeout value. It is a percent (10-99). */ double circuit_build_times_quantile_cutoff(void) { int32_t num = networkstatus_get_param(NULL, "cbtquantile", CBT_DEFAULT_QUANTILE_CUTOFF, CBT_MIN_QUANTILE_CUTOFF, CBT_MAX_QUANTILE_CUTOFF); if (!(get_options()->LearnCircuitBuildTimeout)) { log_debug(LD_BUG, "circuit_build_times_quantile_cutoff() called, cbtquantile" " is %d", num); } return num/100.0; }
/** * Retrieve and bounds-check the cbtnummodes consensus paramter. * * Effect: This value governs how many modes to use in the weighted * average calculation of Pareto parameter Xm. A value of 3 introduces * some bias (2-5% of CDF) under ideal conditions, but allows for better * performance in the event that a client chooses guard nodes of radically * different performance characteristics. */ static int32_t circuit_build_times_default_num_xm_modes(void) { int32_t num = networkstatus_get_param(NULL, "cbtnummodes", CBT_DEFAULT_NUM_XM_MODES, CBT_MIN_NUM_XM_MODES, CBT_MAX_NUM_XM_MODES); if (!(get_options()->LearnCircuitBuildTimeout)) { log_debug(LD_BUG, "circuit_build_times_default_num_xm_modes() called, cbtnummodes" " is %d", num); } return num; }
/** * Retrieve and bounds-check the cbtrecentcount consensus paramter. * * Effect: This is the number of circuit build times to keep track of * for deciding if we hit cbtmaxtimeouts and need to reset our state * and learn a new timeout. */ static int32_t circuit_build_times_recent_circuit_count(networkstatus_t *ns) { int32_t num; num = networkstatus_get_param(ns, "cbtrecentcount", CBT_DEFAULT_RECENT_CIRCUITS, CBT_MIN_RECENT_CIRCUITS, CBT_MAX_RECENT_CIRCUITS); if (!(get_options()->LearnCircuitBuildTimeout)) { log_debug(LD_BUG, "circuit_build_times_recent_circuit_count() called, " "cbtrecentcount is %d", num); } return num; }
/** * Retrieve and bounds-check the cbtmaxtimeouts consensus paramter. * * Effect: When this many timeouts happen in the last 'cbtrecentcount' * circuit attempts, the client should discard all of its history and * begin learning a fresh timeout value. */ static int32_t circuit_build_times_max_timeouts(void) { int32_t cbt_maxtimeouts; cbt_maxtimeouts = networkstatus_get_param(NULL, "cbtmaxtimeouts", CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT, CBT_MIN_MAX_RECENT_TIMEOUT_COUNT, CBT_MAX_MAX_RECENT_TIMEOUT_COUNT); if (!(get_options()->LearnCircuitBuildTimeout)) { log_debug(LD_BUG, "circuit_build_times_max_timeouts() called, cbtmaxtimeouts is" " %d", cbt_maxtimeouts); } return cbt_maxtimeouts; }
/* Return the value of the circuit priority halflife from the options if * available or else from the consensus (in that order). If none can be found, * a default value is returned. * * The source_msg points to a string describing from where the value was * picked so it can be used for logging. */ static double get_circuit_priority_halflife(const or_options_t *options, const networkstatus_t *consensus, const char **source_msg) { int32_t halflife_ms; double halflife; /* Compute the default value now. We might need it. */ double halflife_default = ((double) CMUX_PRIORITY_HALFLIFE_MSEC_DEFAULT) / 1000.0; /* Try to get it from configuration file first. */ if (options && options->CircuitPriorityHalflife >= -EPSILON) { halflife = options->CircuitPriorityHalflife; *source_msg = "CircuitPriorityHalflife in configuration"; goto end; } /* Try to get the msec value from the consensus. */ halflife_ms = networkstatus_get_param(consensus, "CircuitPriorityHalflifeMsec", CMUX_PRIORITY_HALFLIFE_MSEC_DEFAULT, CMUX_PRIORITY_HALFLIFE_MSEC_MIN, CMUX_PRIORITY_HALFLIFE_MSEC_MAX); halflife = ((double) halflife_ms) / 1000.0; *source_msg = "CircuitPriorityHalflifeMsec in consensus"; end: /* We should never go below the EPSILON else we would consider it disabled * and we can't have that. */ if (halflife < EPSILON) { log_warn(LD_CONFIG, "CircuitPriorityHalflife is too small (%f). " "Adjusting to the smallest value allowed: %f.", halflife, halflife_default); halflife = halflife_default; } return halflife; }
/** * Retrieve and bounds-check the cbtinitialtimeout consensus paramter. * * Effect: This is the timeout value to use before computing a timeout, * in milliseconds. */ int32_t circuit_build_times_initial_timeout(void) { int32_t min = circuit_build_times_min_timeout(); int32_t param = networkstatus_get_param(NULL, "cbtinitialtimeout", CBT_DEFAULT_TIMEOUT_INITIAL_VALUE, CBT_MIN_TIMEOUT_INITIAL_VALUE, CBT_MAX_TIMEOUT_INITIAL_VALUE); if (!(get_options()->LearnCircuitBuildTimeout)) { log_debug(LD_BUG, "circuit_build_times_initial_timeout() called, " "cbtinitialtimeout is %d", param); } if (param < min) { log_warn(LD_DIR, "Consensus parameter cbtinitialtimeout is too small, " "raising to %d", min); param = min; } return param; }
/** * Retrieve and bounds-check the cbtclosequantile consensus paramter. * * Effect: This is the position on the quantile curve to use to set the * timeout value to use to actually close circuits. It is a percent * (0-99). */ static double circuit_build_times_close_quantile(void) { int32_t param; /* Cast is safe - circuit_build_times_quantile_cutoff() is capped */ int32_t min = (int)tor_lround(100*circuit_build_times_quantile_cutoff()); param = networkstatus_get_param(NULL, "cbtclosequantile", CBT_DEFAULT_CLOSE_QUANTILE, CBT_MIN_CLOSE_QUANTILE, CBT_MAX_CLOSE_QUANTILE); if (!(get_options()->LearnCircuitBuildTimeout)) { log_debug(LD_BUG, "circuit_build_times_close_quantile() called, cbtclosequantile" " is %d", param); } if (param < min) { log_warn(LD_DIR, "Consensus parameter cbtclosequantile is " "too small, raising to %d", min); param = min; } return param / 100.0; }
/** Look through the routerlist, the Mean Time Between Failure history, and * the Weighted Fractional Uptime history, and use them to set thresholds for * the Stable, Fast, and Guard flags. Update the fields stable_uptime, * stable_mtbf, enough_mtbf_info, guard_wfu, guard_tk, fast_bandwidth, * guard_bandwidth_including_exits, and guard_bandwidth_excluding_exits. * * Also, set the is_exit flag of each router appropriately. */ void dirserv_compute_performance_thresholds(digestmap_t *omit_as_sybil) { int n_active, n_active_nonexit, n_familiar; uint32_t *uptimes, *bandwidths_kb, *bandwidths_excluding_exits_kb; long *tks; double *mtbfs, *wfus; smartlist_t *nodelist; time_t now = time(NULL); const or_options_t *options = get_options(); /* Require mbw? */ int require_mbw = (dirserv_get_last_n_measured_bws() > options->MinMeasuredBWsForAuthToIgnoreAdvertised) ? 1 : 0; /* initialize these all here, in case there are no routers */ stable_uptime = 0; stable_mtbf = 0; fast_bandwidth_kb = 0; guard_bandwidth_including_exits_kb = 0; guard_bandwidth_excluding_exits_kb = 0; guard_tk = 0; guard_wfu = 0; nodelist_assert_ok(); nodelist = nodelist_get_list(); /* Initialize arrays that will hold values for each router. We'll * sort them and use that to compute thresholds. */ n_active = n_active_nonexit = 0; /* Uptime for every active router. */ uptimes = tor_calloc(smartlist_len(nodelist), sizeof(uint32_t)); /* Bandwidth for every active router. */ bandwidths_kb = tor_calloc(smartlist_len(nodelist), sizeof(uint32_t)); /* Bandwidth for every active non-exit router. */ bandwidths_excluding_exits_kb = tor_calloc(smartlist_len(nodelist), sizeof(uint32_t)); /* Weighted mean time between failure for each active router. */ mtbfs = tor_calloc(smartlist_len(nodelist), sizeof(double)); /* Time-known for each active router. */ tks = tor_calloc(smartlist_len(nodelist), sizeof(long)); /* Weighted fractional uptime for each active router. */ wfus = tor_calloc(smartlist_len(nodelist), sizeof(double)); /* Now, fill in the arrays. */ SMARTLIST_FOREACH_BEGIN(nodelist, node_t *, node) { if (options->BridgeAuthoritativeDir && node->ri && node->ri->purpose != ROUTER_PURPOSE_BRIDGE) continue; routerinfo_t *ri = node->ri; if (ri) { node->is_exit = (!router_exit_policy_rejects_all(ri) && exit_policy_is_general_exit(ri->exit_policy)); } if (router_counts_toward_thresholds(node, now, omit_as_sybil, require_mbw)) { const char *id = node->identity; uint32_t bw_kb; /* resolve spurious clang shallow analysis null pointer errors */ tor_assert(ri); uptimes[n_active] = (uint32_t)real_uptime(ri, now); mtbfs[n_active] = rep_hist_get_stability(id, now); tks [n_active] = rep_hist_get_weighted_time_known(id, now); bandwidths_kb[n_active] = bw_kb = dirserv_get_credible_bandwidth_kb(ri); if (!node->is_exit || node->is_bad_exit) { bandwidths_excluding_exits_kb[n_active_nonexit] = bw_kb; ++n_active_nonexit; } ++n_active; } } SMARTLIST_FOREACH_END(node); /* Now, compute thresholds. */ if (n_active) { /* The median uptime is stable. */ stable_uptime = median_uint32(uptimes, n_active); /* The median mtbf is stable, if we have enough mtbf info */ stable_mtbf = median_double(mtbfs, n_active); /* The 12.5th percentile bandwidth is fast. */ fast_bandwidth_kb = find_nth_uint32(bandwidths_kb, n_active, n_active/8); /* (Now bandwidths is sorted.) */ if (fast_bandwidth_kb < RELAY_REQUIRED_MIN_BANDWIDTH/(2 * 1000)) fast_bandwidth_kb = bandwidths_kb[n_active/4]; guard_bandwidth_including_exits_kb = third_quartile_uint32(bandwidths_kb, n_active); guard_tk = find_nth_long(tks, n_active, n_active/8); } if (guard_tk > TIME_KNOWN_TO_GUARANTEE_FAMILIAR) guard_tk = TIME_KNOWN_TO_GUARANTEE_FAMILIAR; { /* We can vote on a parameter for the minimum and maximum. */ #define ABSOLUTE_MIN_VALUE_FOR_FAST_FLAG 4 int32_t min_fast_kb, max_fast_kb, min_fast, max_fast; min_fast = networkstatus_get_param(NULL, "FastFlagMinThreshold", ABSOLUTE_MIN_VALUE_FOR_FAST_FLAG, ABSOLUTE_MIN_VALUE_FOR_FAST_FLAG, INT32_MAX); if (options->TestingTorNetwork) { min_fast = (int32_t)options->TestingMinFastFlagThreshold; } max_fast = networkstatus_get_param(NULL, "FastFlagMaxThreshold", INT32_MAX, min_fast, INT32_MAX); min_fast_kb = min_fast / 1000; max_fast_kb = max_fast / 1000; if (fast_bandwidth_kb < (uint32_t)min_fast_kb) fast_bandwidth_kb = min_fast_kb; if (fast_bandwidth_kb > (uint32_t)max_fast_kb) fast_bandwidth_kb = max_fast_kb; } /* Protect sufficiently fast nodes from being pushed out of the set * of Fast nodes. */ if (options->AuthDirFastGuarantee && fast_bandwidth_kb > options->AuthDirFastGuarantee/1000) fast_bandwidth_kb = (uint32_t)options->AuthDirFastGuarantee/1000; /* Now that we have a time-known that 7/8 routers are known longer than, * fill wfus with the wfu of every such "familiar" router. */ n_familiar = 0; SMARTLIST_FOREACH_BEGIN(nodelist, node_t *, node) { if (router_counts_toward_thresholds(node, now, omit_as_sybil, require_mbw)) { routerinfo_t *ri = node->ri; const char *id = ri->cache_info.identity_digest; long tk = rep_hist_get_weighted_time_known(id, now); if (tk < guard_tk) continue; wfus[n_familiar++] = rep_hist_get_weighted_fractional_uptime(id, now); } } SMARTLIST_FOREACH_END(node); if (n_familiar) guard_wfu = median_double(wfus, n_familiar); if (guard_wfu > WFU_TO_GUARANTEE_GUARD) guard_wfu = WFU_TO_GUARANTEE_GUARD; enough_mtbf_info = rep_hist_have_measured_enough_stability(); if (n_active_nonexit) { guard_bandwidth_excluding_exits_kb = find_nth_uint32(bandwidths_excluding_exits_kb, n_active_nonexit, n_active_nonexit*3/4); } log_info(LD_DIRSERV, "Cutoffs: For Stable, %lu sec uptime, %lu sec MTBF. " "For Fast: %lu kilobytes/sec. " "For Guard: WFU %.03f%%, time-known %lu sec, " "and bandwidth %lu or %lu kilobytes/sec. " "We%s have enough stability data.", (unsigned long)stable_uptime, (unsigned long)stable_mtbf, (unsigned long)fast_bandwidth_kb, guard_wfu*100, (unsigned long)guard_tk, (unsigned long)guard_bandwidth_including_exits_kb, (unsigned long)guard_bandwidth_excluding_exits_kb, enough_mtbf_info ? "" : " don't"); tor_free(uptimes); tor_free(mtbfs); tor_free(bandwidths_kb); tor_free(bandwidths_excluding_exits_kb); tor_free(tks); tor_free(wfus); }