mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-20 10:12:15 +01:00
Don't queue more cells as a middle relay than the spec allows to be in flight
This commit is contained in:
parent
6fc3997307
commit
459aada4d0
4
changes/bug9063
Normal file
4
changes/bug9063
Normal file
@ -0,0 +1,4 @@
|
||||
o Normal bugfixes:
|
||||
- Close any circuit that has 10% more cells queued than the spec permits
|
||||
and warn when the queue length exceeds that threshold. Fixes bug
|
||||
#9063; bugfix on 0.2.4.12.
|
20
src/or/or.h
20
src/or/or.h
@ -543,6 +543,8 @@ typedef enum {
|
||||
#define CIRCUIT_PURPOSE_IS_ESTABLISHED_REND(p) \
|
||||
((p) == CIRCUIT_PURPOSE_C_REND_JOINED || \
|
||||
(p) == CIRCUIT_PURPOSE_S_REND_JOINED)
|
||||
/** True iff the circuit_t c is actually an or_circuit_t */
|
||||
#define CIRCUIT_IS_ORCIRC(c) (((circuit_t *)(c))->magic == OR_CIRCUIT_MAGIC)
|
||||
|
||||
/** How many circuits do we want simultaneously in-progress to handle
|
||||
* a given stream? */
|
||||
@ -820,6 +822,18 @@ typedef enum {
|
||||
/** Amount to increment a stream window when we get a stream SENDME. */
|
||||
#define STREAMWINDOW_INCREMENT 50
|
||||
|
||||
/** Maximum number of queued cells on a circuit for which we are the
|
||||
* midpoint before we give up and kill it. This must be >= circwindow
|
||||
* to avoid killing innocent circuits. The ORCIRC_MAX_MIDDLE_KILL_THRESH
|
||||
* ratio controls the margin of error between emitting a warning and
|
||||
* killing the circuit.
|
||||
*/
|
||||
#define ORCIRC_MAX_MIDDLE_CELLS CIRCWINDOW_START_MAX
|
||||
/** Ratio of hard (circuit kill) to soft (warning) thresholds for the
|
||||
* ORCIRC_MAX_MIDDLE_CELLS tests.
|
||||
*/
|
||||
#define ORCIRC_MAX_MIDDLE_KILL_THRESH (1.1f)
|
||||
|
||||
/* Cell commands. These values are defined in tor-spec.txt. */
|
||||
#define CELL_PADDING 0
|
||||
#define CELL_CREATE 1
|
||||
@ -3157,6 +3171,12 @@ typedef struct or_circuit_t {
|
||||
* exit-ward queues of this circuit; reset every time when writing
|
||||
* buffer stats to disk. */
|
||||
uint64_t total_cell_waiting_time;
|
||||
|
||||
/** Maximum cell queue size for a middle relay; this is stored per circuit
|
||||
* so append_cell_to_circuit_queue() can adjust it if it changes. If set
|
||||
* to zero, it is initialized to the default value.
|
||||
*/
|
||||
uint32_t max_middle_cells;
|
||||
} or_circuit_t;
|
||||
|
||||
/** Convert a circuit subtype to a circuit_t. */
|
||||
|
@ -58,6 +58,7 @@ static void adjust_exit_policy_from_exitpolicy_failure(origin_circuit_t *circ,
|
||||
entry_connection_t *conn,
|
||||
node_t *node,
|
||||
const tor_addr_t *addr);
|
||||
static int get_max_middle_cells(void);
|
||||
|
||||
/** Stop reading on edge connections when we have this many cells
|
||||
* waiting on the appropriate queue. */
|
||||
@ -2461,6 +2462,18 @@ channel_flush_from_first_active_circuit(channel_t *chan, int max)
|
||||
return n_flushed;
|
||||
}
|
||||
|
||||
/** Indicate the current preferred cap for middle circuits; zero disables
|
||||
* the cap. Right now it's just a constant, ORCIRC_MAX_MIDDLE_CELLS, but
|
||||
* the logic in append_cell_to_circuit_queue() is written to be correct
|
||||
* if we want to base it on a consensus param or something that might change
|
||||
* in the future.
|
||||
*/
|
||||
static int
|
||||
get_max_middle_cells(void)
|
||||
{
|
||||
return ORCIRC_MAX_MIDDLE_CELLS;
|
||||
}
|
||||
|
||||
/** Add <b>cell</b> to the queue of <b>circ</b> writing to <b>chan</b>
|
||||
* transmitting in <b>direction</b>. */
|
||||
void
|
||||
@ -2468,8 +2481,11 @@ append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan,
|
||||
cell_t *cell, cell_direction_t direction,
|
||||
streamid_t fromstream)
|
||||
{
|
||||
or_circuit_t *orcirc = NULL;
|
||||
cell_queue_t *queue;
|
||||
int streams_blocked;
|
||||
uint32_t tgt_max_middle_cells, p_len, n_len, tmp, hard_max_middle_cells;
|
||||
|
||||
if (circ->marked_for_close)
|
||||
return;
|
||||
|
||||
@ -2477,11 +2493,88 @@ append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan,
|
||||
queue = &circ->n_chan_cells;
|
||||
streams_blocked = circ->streams_blocked_on_n_chan;
|
||||
} else {
|
||||
or_circuit_t *orcirc = TO_OR_CIRCUIT(circ);
|
||||
orcirc = TO_OR_CIRCUIT(circ);
|
||||
queue = &orcirc->p_chan_cells;
|
||||
streams_blocked = circ->streams_blocked_on_p_chan;
|
||||
}
|
||||
|
||||
/* Are we a middle circuit about to exceed ORCIRC_MAX_MIDDLE_CELLS? */
|
||||
if ((circ->n_chan != NULL) && CIRCUIT_IS_ORCIRC(circ)) {
|
||||
orcirc = TO_OR_CIRCUIT(circ);
|
||||
if (orcirc->p_chan) {
|
||||
/* We are a middle circuit if we have both n_chan and p_chan */
|
||||
/* We'll need to know the current preferred maximum */
|
||||
tgt_max_middle_cells = get_max_middle_cells();
|
||||
if (tgt_max_middle_cells > 0) {
|
||||
/* Do we need to initialize middle_max_cells? */
|
||||
if (orcirc->max_middle_cells == 0) {
|
||||
orcirc->max_middle_cells = tgt_max_middle_cells;
|
||||
} else {
|
||||
if (tgt_max_middle_cells > orcirc->max_middle_cells) {
|
||||
/* If we want to increase the cap, we can do so right away */
|
||||
orcirc->max_middle_cells = tgt_max_middle_cells;
|
||||
} else if (tgt_max_middle_cells < orcirc->max_middle_cells) {
|
||||
/*
|
||||
* If we're shrinking the cap, we can't shrink past either queue;
|
||||
* compare tgt_max_middle_cells rather than tgt_max_middle_cells *
|
||||
* ORCIRC_MAX_MIDDLE_KILL_THRESH so the queues don't shrink enough
|
||||
* to generate spurious warnings, either.
|
||||
*/
|
||||
n_len = circ->n_chan_cells.n;
|
||||
p_len = orcirc->p_chan_cells.n;
|
||||
tmp = tgt_max_middle_cells;
|
||||
if (tmp < n_len) tmp = n_len;
|
||||
if (tmp < p_len) tmp = p_len;
|
||||
orcirc->max_middle_cells = tmp;
|
||||
}
|
||||
/* else no change */
|
||||
}
|
||||
} else {
|
||||
/* tgt_max_middle_cells == 0 indicates we should disable the cap */
|
||||
orcirc->max_middle_cells = 0;
|
||||
}
|
||||
|
||||
/* Now we know orcirc->max_middle_cells is set correctly */
|
||||
if (orcirc->max_middle_cells > 0) {
|
||||
hard_max_middle_cells =
|
||||
(uint32_t)(((double)orcirc->max_middle_cells) *
|
||||
ORCIRC_MAX_MIDDLE_KILL_THRESH);
|
||||
|
||||
if (queue->n + 1 >= hard_max_middle_cells) {
|
||||
/* Queueing this cell would put queue over the kill theshold */
|
||||
log_warn(LD_CIRC,
|
||||
"Got a cell exceeding the hard cap of %u in the "
|
||||
"%s direction on middle circ ID %u on chan ID "
|
||||
U64_FORMAT "; killing the circuit.",
|
||||
hard_max_middle_cells,
|
||||
(direction == CELL_DIRECTION_OUT) ? "n" : "p",
|
||||
(direction == CELL_DIRECTION_OUT) ?
|
||||
circ->n_circ_id : orcirc->p_circ_id,
|
||||
U64_PRINTF_ARG(
|
||||
(direction == CELL_DIRECTION_OUT) ?
|
||||
circ->n_chan->global_identifier :
|
||||
orcirc->p_chan->global_identifier));
|
||||
circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
|
||||
return;
|
||||
} else if (queue->n + 1 == orcirc->max_middle_cells) {
|
||||
/* Only use ==, not >= for this test so we don't spam the log */
|
||||
log_warn(LD_CIRC,
|
||||
"While trying to queue a cell, reached the soft cap of %u "
|
||||
"in the %s direction on middle circ ID %u "
|
||||
"on chan ID " U64_FORMAT ".",
|
||||
orcirc->max_middle_cells,
|
||||
(direction == CELL_DIRECTION_OUT) ? "n" : "p",
|
||||
(direction == CELL_DIRECTION_OUT) ?
|
||||
circ->n_circ_id : orcirc->p_circ_id,
|
||||
U64_PRINTF_ARG(
|
||||
(direction == CELL_DIRECTION_OUT) ?
|
||||
circ->n_chan->global_identifier :
|
||||
orcirc->p_chan->global_identifier));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cell_queue_append_packed_copy(queue, cell, chan->wide_circ_ids);
|
||||
|
||||
/* If we have too many cells on the circuit, we should stop reading from
|
||||
|
Loading…
Reference in New Issue
Block a user