tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

commit c1cbbd0e279b9a2b5b448e6cff423612130976f7
parent 3cf78706400715cf41ae53bd29c1234ce62b1aeb
Author: David Goulet <dgoulet@torproject.org>
Date:   Thu,  6 Nov 2025 14:01:21 -0500

conflux: New consensus parameter to cap OOO queue

We introduce the "cfx_max_oooq_bytes" consensus parameter in this commit which
puts a cap on the OOO queue of a single conflux set.

This is a parameter to be used with care as too low could create a large amount
of false positive leading to severe UX degradation due to conflux set being
shutdown during normal operation.

At this commit, it is set to a huge value as by default we rely on the OOM
handler to clear circuits under memory pressure.

This parameter is essentially an extra knob in case of severe DDoS attacks in
the network leading to heavy memory pressure, we can alleviate relays with
this.

Related to #41155

Signed-off-by: David Goulet <dgoulet@torproject.org>

Diffstat:
Msrc/core/or/conflux.c | 12++++++++++++
Msrc/core/or/conflux_params.c | 21+++++++++++++++++++++
Msrc/core/or/conflux_params.h | 1+
3 files changed, 34 insertions(+), 0 deletions(-)

diff --git a/src/core/or/conflux.c b/src/core/or/conflux.c @@ -885,6 +885,18 @@ conflux_process_cell(conflux_t *cfx, circuit_t *in_circ, circuit_mark_for_close(in_circ, END_CIRC_REASON_INTERNAL); return false; } else { + uint32_t n_bytes_in_q = smartlist_len(cfx->ooo_q) * sizeof(conflux_cell_t); + if (n_bytes_in_q >= conflux_params_get_max_oooq()) { + /* Log rate limit every hour. In heavy DDoS scenario, this could be + * triggered many times so avoid the spam. */ + static ratelim_t rlimit = RATELIM_INIT(60 * 60); + log_fn_ratelim(&rlimit, LOG_WARN, LD_CIRC, + "Conflux OOO queue is at maximum. Currently at " + "%u bytes, maximum allowed is %u bytes. Closing.", + n_bytes_in_q, conflux_params_get_max_oooq()); + circuit_mark_for_close(in_circ, END_CIRC_REASON_RESOURCELIMIT); + return false; + } conflux_cell_t *c_cell = tor_malloc_zero(sizeof(conflux_cell_t)); c_cell->seq = leg->last_seq_recv; diff --git a/src/core/or/conflux_params.c b/src/core/or/conflux_params.c @@ -71,6 +71,11 @@ #define CFX_DRAIN_PCT_MAX (255) #define CFX_DRAIN_PCT_DFLT 0 +/* For "max_ooo_queue_bytes". */ +#define MAX_OOO_QUEUE_BYTES_MIN (0) +#define MAX_OOO_QUEUE_BYTES_MAX (INT32_MAX) +#define MAX_OOO_QUEUE_BYTES_DEFAULT MAX_OOO_QUEUE_BYTES_MAX + /* * Cached consensus parameters. */ @@ -97,6 +102,10 @@ static double low_exit_threshold_ratio = static uint8_t cfx_drain_pct = CFX_DRAIN_PCT_DFLT; static uint8_t cfx_send_pct = CFX_SEND_PCT_DFLT; +/* The maximum number of bytes allowed in a single OOO queue. Above this value, + * the conflux set is closed. */ +static uint32_t max_ooo_queue_bytes = MAX_OOO_QUEUE_BYTES_DEFAULT; + /* 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; @@ -251,6 +260,13 @@ conflux_params_get_send_pct(void) return cfx_send_pct; } +/** Return maximum allowed bytes in a single OOO queue. */ +uint32_t +conflux_params_get_max_oooq(void) +{ + return max_ooo_queue_bytes; +} + /** Update global conflux related consensus parameter values, every consensus * update. */ void @@ -305,5 +321,10 @@ conflux_params_new_consensus(const networkstatus_t *ns) CFX_DRAIN_PCT_MIN, CFX_DRAIN_PCT_MAX); + max_ooo_queue_bytes = networkstatus_get_param(ns, "cfx_max_oooq_bytes", + MAX_OOO_QUEUE_BYTES_DEFAULT, + MAX_OOO_QUEUE_BYTES_MIN, + MAX_OOO_QUEUE_BYTES_MAX); + count_exit_with_conflux_support(ns); } diff --git a/src/core/or/conflux_params.h b/src/core/or/conflux_params.h @@ -19,6 +19,7 @@ uint8_t conflux_params_get_num_legs_set(void); uint8_t conflux_params_get_max_legs_set(void); uint8_t conflux_params_get_drain_pct(void); uint8_t conflux_params_get_send_pct(void); +uint32_t conflux_params_get_max_oooq(void); void conflux_params_new_consensus(const networkstatus_t *ns);