|
|
|
@@ -0,0 +1,281 @@
|
|
|
|
|
/* Copyright (c) 2023, The Tor Project, Inc. */
|
|
|
|
|
/* See LICENSE for licensing information */
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \file conflux_params.h
|
|
|
|
|
* \brief Header file for conflux_params.c.
|
|
|
|
|
**/
|
|
|
|
|
|
|
|
|
|
#include "core/or/or.h"
|
|
|
|
|
|
|
|
|
|
#include "app/config/config.h"
|
|
|
|
|
|
|
|
|
|
#include "core/or/conflux_params.h"
|
|
|
|
|
#include "core/or/congestion_control_common.h"
|
|
|
|
|
#include "core/or/circuitlist.h"
|
|
|
|
|
|
|
|
|
|
#include "feature/nodelist/networkstatus.h"
|
|
|
|
|
#include "feature/nodelist/networkstatus_st.h"
|
|
|
|
|
#include "feature/nodelist/routerstatus_st.h"
|
|
|
|
|
#include "feature/relay/routermode.h"
|
|
|
|
|
|
|
|
|
|
#include "core/or/origin_circuit_st.h"
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Consensus parameters defaults, minimums and maximums.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* For "cfx_enabled". */
|
|
|
|
|
#define CONFLUX_ENABLED_MIN (0)
|
|
|
|
|
#define CONFLUX_ENABLED_MAX (1)
|
|
|
|
|
#define CONFLUX_ENABLED_DEFAULT (1)
|
|
|
|
|
|
|
|
|
|
/* For "cfx_low_exit_threshold". This is a percentage scaled to 10000 so we can
|
|
|
|
|
* support two decimal points. For example, 65.78% would be 6578. */
|
|
|
|
|
#define LOW_EXIT_THRESHOLD_MIN (0)
|
|
|
|
|
#define LOW_EXIT_THRESHOLD_MAX (10000)
|
|
|
|
|
#define LOW_EXIT_THRESHOLD_DEFAULT (6000)
|
|
|
|
|
|
|
|
|
|
/* For "cfx_max_linked_set". */
|
|
|
|
|
#define MAX_LINKED_SET_MIN (0)
|
|
|
|
|
#define MAX_LINKED_SET_MAX (UINT8_MAX)
|
|
|
|
|
#define MAX_LINKED_SET_DEFAULT (10)
|
|
|
|
|
|
|
|
|
|
/* For "cfx_max_prebuilt_set". */
|
|
|
|
|
#define MAX_PREBUILT_SET_MIN (0)
|
|
|
|
|
#define MAX_PREBUILT_SET_MAX (UINT8_MAX)
|
|
|
|
|
#define MAX_PREBUILT_SET_DEFAULT (3)
|
|
|
|
|
|
|
|
|
|
/* For "cfx_max_leg_retry". */
|
|
|
|
|
#define MAX_UNLINKED_LEG_RETRY_DEFAULT (3)
|
|
|
|
|
#define MAX_UNLINKED_LEG_RETRY_MIN (0)
|
|
|
|
|
#define MAX_UNLINKED_LEG_RETRY_MAX (UINT8_MAX)
|
|
|
|
|
|
|
|
|
|
/* For "cfx_num_legs_set". */
|
|
|
|
|
#define NUM_LEGS_SET_MIN (0)
|
|
|
|
|
#define NUM_LEGS_SET_MAX (UINT8_MAX)
|
|
|
|
|
#define NUM_LEGS_SET_DEFAULT (2)
|
|
|
|
|
|
|
|
|
|
/* For "cfx_send_pct". */
|
|
|
|
|
#define CFX_SEND_PCT_MIN (0)
|
|
|
|
|
#define CFX_SEND_PCT_MAX (255)
|
|
|
|
|
#define CFX_SEND_PCT_DFLT 100
|
|
|
|
|
|
|
|
|
|
/* For "cfx_drain_pct". */
|
|
|
|
|
#define CFX_DRAIN_PCT_MIN (0)
|
|
|
|
|
#define CFX_DRAIN_PCT_MAX (255)
|
|
|
|
|
#define CFX_DRAIN_PCT_DFLT 0
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Cached consensus parameters.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* Indicate if conflux is enabled or disabled. */
|
|
|
|
|
static bool conflux_enabled = CONFLUX_ENABLED_DEFAULT;
|
|
|
|
|
/* Maximum number of linked set we are allowed to have (even if in use). */
|
|
|
|
|
static uint8_t max_linked_set = MAX_LINKED_SET_DEFAULT;
|
|
|
|
|
/* Maximum number of pre built set. */
|
|
|
|
|
static uint8_t max_prebuilt_set = MAX_PREBUILT_SET_DEFAULT;
|
|
|
|
|
/* Maximum number of unlinked leg retry that is how many times are we allowed
|
|
|
|
|
* to retry a leg until it successfully links. */
|
|
|
|
|
STATIC uint32_t max_unlinked_leg_retry = MAX_UNLINKED_LEG_RETRY_DEFAULT;
|
|
|
|
|
/* Number of legs per set. */
|
|
|
|
|
static uint8_t num_legs_set = NUM_LEGS_SET_DEFAULT;
|
|
|
|
|
/* The low Exit relay threshold, as a ratio between 0 and 1, used as a limit to
|
|
|
|
|
* decide the amount of pre-built set we build depending on how many Exit relay
|
|
|
|
|
* supports conflux in our current consensus. */
|
|
|
|
|
static double low_exit_threshold_ratio =
|
|
|
|
|
LOW_EXIT_THRESHOLD_DEFAULT / (double)LOW_EXIT_THRESHOLD_MAX;
|
|
|
|
|
|
|
|
|
|
static uint8_t cfx_drain_pct = CFX_DRAIN_PCT_DFLT;
|
|
|
|
|
static uint8_t cfx_send_pct = CFX_SEND_PCT_DFLT;
|
|
|
|
|
|
|
|
|
|
/* Ratio of Exit relays in our consensus supporting conflux. This is computed
|
|
|
|
|
* at every consensus and it is between 0 and 1. */
|
|
|
|
|
static double exit_conflux_ratio = 0.0;
|
|
|
|
|
|
|
|
|
|
/** Sets num_conflux_exit with the latest count of Exits in the given consensus
|
|
|
|
|
* that supports Conflux. */
|
|
|
|
|
static void
|
|
|
|
|
count_exit_with_conflux_support(const networkstatus_t *ns)
|
|
|
|
|
{
|
|
|
|
|
double supported = 0.0;
|
|
|
|
|
|
|
|
|
|
if (!ns || smartlist_len(ns->routerstatus_list) == 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, const routerstatus_t *, rs) {
|
|
|
|
|
if (rs->pv.supports_conflux) {
|
|
|
|
|
supported++;
|
|
|
|
|
}
|
|
|
|
|
} SMARTLIST_FOREACH_END(rs);
|
|
|
|
|
|
|
|
|
|
exit_conflux_ratio =
|
|
|
|
|
supported / smartlist_len(ns->routerstatus_list);
|
|
|
|
|
|
|
|
|
|
log_info(LD_GENERAL, "Consensus has %.2f %% Exit relays supporting Conflux",
|
|
|
|
|
exit_conflux_ratio * 100.0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Return true iff conflux feature is enabled and usable for a given circuit.
|
|
|
|
|
*
|
|
|
|
|
* Circ may be NULL, in which case we only check the consensus and torrc. */
|
|
|
|
|
bool
|
|
|
|
|
conflux_is_enabled(const circuit_t *circ)
|
|
|
|
|
{
|
|
|
|
|
const or_options_t *opts = get_options();
|
|
|
|
|
|
|
|
|
|
/* Conflux CAN NOT operate properly without congestion control and so
|
|
|
|
|
* automatically disabled conflux if we don't have CC enabled. */
|
|
|
|
|
if (!congestion_control_enabled()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (circ) {
|
|
|
|
|
/* If circuit is non-null, we need to check to see if congestion
|
|
|
|
|
* control was successfully negotiated. Conflux depends upon congestion
|
|
|
|
|
* control, and consensus checks are not enough because there can be a
|
|
|
|
|
* race between those checks and the consensus update to enable
|
|
|
|
|
* congestion control. This happens in Shadow, and at relay restart. */
|
|
|
|
|
if (CIRCUIT_IS_ORIGIN(circ)) {
|
|
|
|
|
tor_assert(CONST_TO_ORIGIN_CIRCUIT(circ)->cpath);
|
|
|
|
|
tor_assert(CONST_TO_ORIGIN_CIRCUIT(circ)->cpath->prev);
|
|
|
|
|
if (!CONST_TO_ORIGIN_CIRCUIT(circ)->cpath->prev->ccontrol)
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
if (!circ->ccontrol)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* For clients, this is mostly for sbws. For relays, this is an emergency
|
|
|
|
|
* emergency override, in case a bug is discovered by a relay operator
|
|
|
|
|
* and we can't set a consensus param fast enough. Basically gives them
|
|
|
|
|
* an option other than downgrading. */
|
|
|
|
|
if (opts->ConfluxEnabled != -1) {
|
|
|
|
|
if (server_mode(opts)) {
|
|
|
|
|
char *msg;
|
|
|
|
|
static ratelim_t rlimit = RATELIM_INIT(60 * 60); /* Hourly */
|
|
|
|
|
if ((msg = rate_limit_log(&rlimit, time(NULL)))) {
|
|
|
|
|
log_warn(LD_GENERAL,
|
|
|
|
|
"This tor is a relay and ConfluxEnabled is set to 0. "
|
|
|
|
|
"We would ask you to please write to us on "
|
|
|
|
|
"tor-relay@lists.torproject.org or file a bug explaining "
|
|
|
|
|
"why you have disabled this option. Without news from you, "
|
|
|
|
|
"we might end up marking your relay as a BadExit.");
|
|
|
|
|
tor_free(msg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return opts->ConfluxEnabled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return conflux_enabled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Return the maximum number of linked set we are allowed to have. */
|
|
|
|
|
uint8_t
|
|
|
|
|
conflux_params_get_max_linked_set(void)
|
|
|
|
|
{
|
|
|
|
|
return max_linked_set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Return the number of maximum pre built sets that is allowed to have. */
|
|
|
|
|
uint8_t
|
|
|
|
|
conflux_params_get_max_prebuilt(void)
|
|
|
|
|
{
|
|
|
|
|
/* Without any Exit supporting conflux, we won't be able to build a set. The
|
|
|
|
|
* float problem here is minimal because exit_conflux_ratio is either a flat
|
|
|
|
|
* 0 or else it means we do have at least an exit. */
|
|
|
|
|
if (exit_conflux_ratio <= 0.0) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Allow only 1 pre built set if we are lower than the low exit threshold
|
|
|
|
|
* parameter from the consensus. */
|
|
|
|
|
if (exit_conflux_ratio < low_exit_threshold_ratio) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
return max_prebuilt_set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Return the maximum number of retry we can do until a leg links. */
|
|
|
|
|
uint8_t
|
|
|
|
|
conflux_params_get_max_unlinked_leg_retry(void)
|
|
|
|
|
{
|
|
|
|
|
return max_unlinked_leg_retry;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Return the number of legs per set. */
|
|
|
|
|
uint8_t
|
|
|
|
|
conflux_params_get_num_legs_set(void)
|
|
|
|
|
{
|
|
|
|
|
return num_legs_set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Return the drain percent we must hit before switching */
|
|
|
|
|
uint8_t
|
|
|
|
|
conflux_params_get_drain_pct(void)
|
|
|
|
|
{
|
|
|
|
|
return cfx_drain_pct;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Return the percent of the congestion window to send before switching. */
|
|
|
|
|
uint8_t
|
|
|
|
|
conflux_params_get_send_pct(void)
|
|
|
|
|
{
|
|
|
|
|
return cfx_send_pct;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Update global conflux related consensus parameter values, every consensus
|
|
|
|
|
* update. */
|
|
|
|
|
void
|
|
|
|
|
conflux_params_new_consensus(const networkstatus_t *ns)
|
|
|
|
|
{
|
|
|
|
|
/* Params used by conflux_pool.c */
|
|
|
|
|
conflux_enabled =
|
|
|
|
|
networkstatus_get_param(ns, "cfx_enabled",
|
|
|
|
|
CONFLUX_ENABLED_DEFAULT,
|
|
|
|
|
CONFLUX_ENABLED_MIN, CONFLUX_ENABLED_MAX);
|
|
|
|
|
|
|
|
|
|
low_exit_threshold_ratio =
|
|
|
|
|
networkstatus_get_param(ns, "cfx_low_exit_threshold",
|
|
|
|
|
LOW_EXIT_THRESHOLD_DEFAULT,
|
|
|
|
|
LOW_EXIT_THRESHOLD_MIN, LOW_EXIT_THRESHOLD_MAX) /
|
|
|
|
|
(double)LOW_EXIT_THRESHOLD_MAX;
|
|
|
|
|
|
|
|
|
|
max_linked_set =
|
|
|
|
|
networkstatus_get_param(ns, "cfx_max_linked_set",
|
|
|
|
|
MAX_LINKED_SET_DEFAULT,
|
|
|
|
|
MAX_LINKED_SET_MIN, MAX_LINKED_SET_MAX);
|
|
|
|
|
|
|
|
|
|
max_prebuilt_set =
|
|
|
|
|
networkstatus_get_param(ns, "cfx_max_prebuilt_set",
|
|
|
|
|
MAX_PREBUILT_SET_DEFAULT,
|
|
|
|
|
MAX_PREBUILT_SET_MIN, MAX_PREBUILT_SET_MAX);
|
|
|
|
|
|
|
|
|
|
max_unlinked_leg_retry =
|
|
|
|
|
networkstatus_get_param(ns, "cfx_max_unlinked_leg_retry",
|
|
|
|
|
MAX_UNLINKED_LEG_RETRY_DEFAULT,
|
|
|
|
|
MAX_UNLINKED_LEG_RETRY_MIN,
|
|
|
|
|
MAX_UNLINKED_LEG_RETRY_MAX);
|
|
|
|
|
|
|
|
|
|
num_legs_set =
|
|
|
|
|
networkstatus_get_param(ns, "cfx_num_legs_set",
|
|
|
|
|
NUM_LEGS_SET_DEFAULT,
|
|
|
|
|
NUM_LEGS_SET_MIN, NUM_LEGS_SET_MAX);
|
|
|
|
|
|
|
|
|
|
/* Params used by conflux.c */
|
|
|
|
|
cfx_send_pct = networkstatus_get_param(ns, "cfx_send_pct",
|
|
|
|
|
CFX_SEND_PCT_DFLT,
|
|
|
|
|
CFX_SEND_PCT_MIN,
|
|
|
|
|
CFX_SEND_PCT_MAX);
|
|
|
|
|
|
|
|
|
|
cfx_drain_pct = networkstatus_get_param(ns, "cfx_drain_pct",
|
|
|
|
|
CFX_DRAIN_PCT_DFLT,
|
|
|
|
|
CFX_DRAIN_PCT_MIN,
|
|
|
|
|
CFX_DRAIN_PCT_MAX);
|
|
|
|
|
|
|
|
|
|
count_exit_with_conflux_support(ns);
|
|
|
|
|
}
|