commit aef30547dc4aa77fc79517a6dcad7712b59af371 Author: Nick Mathewson nickm@torproject.org Date: Thu Jul 7 14:54:54 2011 -0400
Add an option to limit the number of non-open client circuits.
This is mainly meant as a way to keep clients from accidentally DOSing themselves by (e.g.) enabling IsolateDestAddr or IsolateDestPort on a port that they use for HTTP. --- src/or/circuituse.c | 35 +++++++++++++++++++++++++++++++++++ src/or/config.c | 10 ++++++++++ src/or/or.h | 5 +++++ 3 files changed, 50 insertions(+), 0 deletions(-)
diff --git a/src/or/circuituse.c b/src/or/circuituse.c index 93098e5..dcb6bfa 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -288,6 +288,27 @@ circuit_get_best(const edge_connection_t *conn, return best; }
+/** Return the number of not-yet-open general-purpose origin circuits. */ +static int +count_pending_general_client_circuits(void) +{ + const circuit_t *circ; + + int count = 0; + + for (circ = global_circuitlist; circ; circ = circ->next) { + if (circ->marked_for_close || + circ->state == CIRCUIT_STATE_OPEN || + circ->purpose != CIRCUIT_PURPOSE_C_GENERAL || + !CIRCUIT_IS_ORIGIN(circ)) + continue; + + ++count; + } + + return count; +} + #if 0 /** Check whether, according to the policies in <b>options</b>, the * circuit <b>circ</b> makes sense. */ @@ -1347,6 +1368,20 @@ circuit_get_open_circ_or_launch(edge_connection_t *conn, if (!circ) { extend_info_t *extend_info=NULL; uint8_t new_circ_purpose; + const int n_pending = count_pending_general_client_circuits(); + + if (n_pending >= options->MaxClientCircuitsPending) { + static ratelim_t delay_limit = RATELIM_INIT(10*60); + char *m; + if ((m = rate_limit_log(&delay_limit, approx_time()))) { + log_notice(LD_APP, "We'd like to launch a circuit to handle a " + "connection, but we already have %d general-purpose client " + "circuits pending. Waiting until some finish.", + n_pending); + tor_free(m); + } + return 0; + }
if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) { /* need to pick an intro point */ diff --git a/src/or/config.c b/src/or/config.c index 2ca9c66..14acf59 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -315,6 +315,7 @@ static config_var_t _option_vars[] = { VAR("MapAddress", LINELIST, AddressMap, NULL), V(MaxAdvertisedBandwidth, MEMUNIT, "1 GB"), V(MaxCircuitDirtiness, INTERVAL, "10 minutes"), + V(MaxClientCircuitsPending, UINT, "32"), V(MaxOnionsPending, UINT, "100"), OBSOLETE("MonthlyAccountingStart"), V(MyFamily, STRING, NULL), @@ -3215,6 +3216,15 @@ options_validate(or_options_t *old_options, or_options_t *options, return -1; }
+ if (options->MaxClientCircuitsPending <= 0 || + options->MaxClientCircuitsPending > MAX_MAX_CLIENT_CIRCUITS_PENDING) { + tor_asprintf(msg, + "MaxClientCircuitsPending must be between 1 and %d, but " + "was set to %d", MAX_MAX_CLIENT_CIRCUITS_PENDING, + options->MaxClientCircuitsPending); + return -1; + } + if (validate_ports_csv(options->FirewallPorts, "FirewallPorts", msg) < 0) return -1;
diff --git a/src/or/or.h b/src/or/or.h index 97418f5..09907c3 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -3230,6 +3230,11 @@ typedef struct { /** Should that file be group-readable? */ int ControlPortFileGroupReadable;
+#define MAX_MAX_CLIENT_CIRCUITS_PENDING 1024 + /** Maximum number of non-open general-purpose origin circuits to allow at + * once. */ + int MaxClientCircuitsPending; + } or_options_t;
/** Persistent state for an onion router, as saved to disk. */