aboutsummaryrefslogtreecommitdiff
path: root/src/or
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2011-07-07 14:54:54 -0400
committerNick Mathewson <nickm@torproject.org>2011-07-19 01:58:45 -0400
commitaef30547dc4aa77fc79517a6dcad7712b59af371 (patch)
treed73ae474b559433a0ff40b0a8930b034478e7df2 /src/or
parent20c0581a7935369fecb6c62b7cf5c7c244cdb533 (diff)
downloadtor-aef30547dc4aa77fc79517a6dcad7712b59af371.tar
tor-aef30547dc4aa77fc79517a6dcad7712b59af371.tar.gz
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.
Diffstat (limited to 'src/or')
-rw-r--r--src/or/circuituse.c35
-rw-r--r--src/or/config.c10
-rw-r--r--src/or/or.h5
3 files changed, 50 insertions, 0 deletions
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index 93098e527..dcb6bfa50 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 2ca9c6699..14acf5934 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 97418f574..09907c3a1 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. */