aboutsummaryrefslogtreecommitdiff
path: root/src/core/or/dos.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/or/dos.c')
-rw-r--r--src/core/or/dos.c127
1 files changed, 127 insertions, 0 deletions
diff --git a/src/core/or/dos.c b/src/core/or/dos.c
index ccdb30dbee..b789f87aae 100644
--- a/src/core/or/dos.c
+++ b/src/core/or/dos.c
@@ -79,6 +79,24 @@ static uint64_t conn_num_addr_connect_rejected;
static uint32_t dos_num_circ_max_outq;
/*
+ * Stream denial of service mitigation.
+ *
+ * Namespace used for this mitigation framework is "dos_stream_".
+ */
+
+/* Is the connection DoS mitigation enabled? */
+static unsigned int dos_stream_enabled = 0;
+
+/* Consensus parameters. They can be changed when a new consensus arrives.
+ * They are initialized with the hardcoded default values. */
+static dos_stream_defense_type_t dos_stream_defense_type;
+static uint32_t dos_stream_rate = DOS_STREAM_RATE_DEFAULT;
+static uint32_t dos_stream_burst = DOS_STREAM_BURST_DEFAULT;
+
+/* Keep some stats for the heartbeat so we can report out. */
+static uint64_t stream_num_rejected;
+
+/*
* General interface of the denial of service mitigation subsystem.
*/
@@ -258,6 +276,59 @@ get_param_conn_connect_defense_time_period(const networkstatus_t *ns)
INT32_MAX);
}
+/* Return true iff the stream creation mitigation is enabled. We look at the
+ * consensus for this else a default value is returned. */
+MOCK_IMPL(STATIC unsigned int,
+get_param_stream_enabled, (const networkstatus_t *ns))
+{
+ if (dos_get_options()->DoSStreamCreationEnabled != -1) {
+ return dos_get_options()->DoSStreamCreationEnabled;
+ }
+
+ return !!networkstatus_get_param(ns, "DoSStreamCreationEnabled",
+ DOS_STREAM_ENABLED_DEFAULT, 0, 1);
+}
+
+/* Return the parameter for the time rate that is how many stream per circuit
+ * over this time span. */
+static uint32_t
+get_param_stream_rate(const networkstatus_t *ns)
+{
+ /* This is in seconds. */
+ if (dos_get_options()->DoSStreamCreationRate) {
+ return dos_get_options()->DoSStreamCreationRate;
+ }
+ return networkstatus_get_param(ns, "DoSStreamCreationRate",
+ DOS_STREAM_RATE_DEFAULT,
+ 1, INT32_MAX);
+}
+
+/* Return the parameter for the maximum circuit count for the circuit time
+ * rate. */
+static uint32_t
+get_param_stream_burst(const networkstatus_t *ns)
+{
+ if (dos_get_options()->DoSStreamCreationBurst) {
+ return dos_get_options()->DoSStreamCreationBurst;
+ }
+ return networkstatus_get_param(ns, "DoSStreamCreationBurst",
+ DOS_STREAM_BURST_DEFAULT,
+ 1, INT32_MAX);
+}
+
+/* Return the consensus parameter of the circuit creation defense type. */
+static uint32_t
+get_param_stream_defense_type(const networkstatus_t *ns)
+{
+ if (dos_get_options()->DoSStreamCreationDefenseType) {
+ return dos_get_options()->DoSStreamCreationDefenseType;
+ }
+ return networkstatus_get_param(ns, "DoSStreamCreationDefenseType",
+ DOS_STREAM_DEFENSE_TYPE_DEFAULT,
+ DOS_STREAM_DEFENSE_NONE,
+ DOS_STREAM_DEFENSE_MAX);
+}
+
/* Set circuit creation parameters located in the consensus or their default
* if none are present. Called at initialization or when the consensus
* changes. */
@@ -283,6 +354,12 @@ set_dos_parameters(const networkstatus_t *ns)
/* Circuit. */
dos_num_circ_max_outq = get_param_dos_num_circ_max_outq(ns);
+
+ /* Stream. */
+ dos_stream_enabled = get_param_stream_enabled(ns);
+ dos_stream_defense_type = get_param_stream_defense_type(ns);
+ dos_stream_rate = get_param_stream_rate(ns);
+ dos_stream_burst = get_param_stream_burst(ns);
}
/* Free everything for the circuit creation DoS mitigation subsystem. */
@@ -760,6 +837,48 @@ dos_conn_addr_get_defense_type(const tor_addr_t *addr)
return DOS_CONN_DEFENSE_NONE;
}
+/* Stream creation public API. */
+
+/** Return the number of rejected stream and resolve. */
+uint64_t
+dos_get_num_stream_rejected(void)
+{
+ return stream_num_rejected;
+}
+
+/* Return the action to take against a BEGIN or RESOLVE cell. Return
+ * DOS_STREAM_DEFENSE_NONE when no action should be taken.
+ * Increment the appropriate counter when the cell was found to go over a
+ * limit. */
+dos_stream_defense_type_t
+dos_stream_new_begin_or_resolve_cell(or_circuit_t *circ)
+{
+ if (!dos_stream_enabled || circ == NULL)
+ return DOS_STREAM_DEFENSE_NONE;
+
+ token_bucket_ctr_refill(&circ->stream_limiter,
+ (uint32_t) monotime_coarse_absolute_sec());
+
+ if (token_bucket_ctr_get(&circ->stream_limiter) > 0) {
+ token_bucket_ctr_dec(&circ->stream_limiter, 1);
+ return DOS_STREAM_DEFENSE_NONE;
+ }
+ /* if defense type is DOS_STREAM_DEFENSE_NONE but DoSStreamEnabled is true,
+ * we count offending cells as rejected, despite them being actually
+ * accepted. */
+ ++stream_num_rejected;
+ return dos_stream_defense_type;
+}
+
+/* Initialize the token bucket for stream rate limit on a circuit. */
+void
+dos_stream_init_circ_tbf(or_circuit_t *circ)
+{
+ token_bucket_ctr_init(&circ->stream_limiter, dos_stream_rate,
+ dos_stream_burst,
+ (uint32_t) monotime_coarse_absolute_sec());
+}
+
/* General API */
/* Take any appropriate actions for the given geoip entry that is about to get
@@ -945,6 +1064,14 @@ dos_log_heartbeat(void)
"[DoSRefuseSingleHopClientRendezvous disabled]");
}
+ if (dos_stream_enabled) {
+ smartlist_add_asprintf(elems,
+ "%" PRIu64 " stream rejected",
+ stream_num_rejected);
+ } else {
+ smartlist_add_asprintf(elems, "[DoSStreamCreationEnabled disabled]");
+ }
+
/* HS DoS stats. */
smartlist_add_asprintf(elems,
"%" PRIu64 " INTRODUCE2 rejected",