25 #include "core/or/dos.h"
39 static unsigned int dos_cc_enabled = 0;
43 static uint32_t dos_cc_min_concurrent_conn;
44 static uint32_t dos_cc_circuit_rate;
45 static uint32_t dos_cc_circuit_burst;
46 static dos_cc_defense_type_t dos_cc_defense_type;
47 static int32_t dos_cc_defense_time_period;
50 static uint64_t cc_num_rejected_cells;
51 static uint32_t cc_num_marked_addrs;
60 static unsigned int dos_conn_enabled = 0;
64 static uint32_t dos_conn_max_concurrent_count;
65 static dos_conn_defense_type_t dos_conn_defense_type;
66 static uint32_t dos_conn_connect_rate = DOS_CONN_CONNECT_RATE_DEFAULT;
67 static uint32_t dos_conn_connect_burst = DOS_CONN_CONNECT_BURST_DEFAULT;
68 static int32_t dos_conn_connect_defense_time_period =
69 DOS_CONN_CONNECT_DEFENSE_TIME_PERIOD_DEFAULT;
72 static uint64_t conn_num_addr_rejected;
73 static uint64_t conn_num_addr_connect_rejected;
80 static uint64_t num_single_hop_client_refused;
87 if (dos_get_options()->DoSCircuitCreationEnabled != -1) {
92 DOS_CC_ENABLED_DEFAULT, 0, 1);
100 if (dos_get_options()->DoSCircuitCreationMinConnections) {
104 DOS_CC_MIN_CONCURRENT_CONN_DEFAULT,
114 if (dos_get_options()->DoSCircuitCreationRate) {
118 DOS_CC_CIRCUIT_RATE_DEFAULT,
127 if (dos_get_options()->DoSCircuitCreationBurst) {
131 DOS_CC_CIRCUIT_BURST_DEFAULT,
139 if (dos_get_options()->DoSCircuitCreationDefenseType) {
143 DOS_CC_DEFENSE_TYPE_DEFAULT,
144 DOS_CC_DEFENSE_NONE, DOS_CC_DEFENSE_MAX);
153 if (dos_get_options()->DoSCircuitCreationDefenseTimePeriod) {
157 DOS_CC_DEFENSE_TIME_PERIOD_DEFAULT,
166 if (dos_get_options()->DoSConnectionEnabled != -1) {
170 DOS_CONN_ENABLED_DEFAULT, 0, 1);
178 if (dos_get_options()->DoSConnectionMaxConcurrentCount) {
182 DOS_CONN_MAX_CONCURRENT_COUNT_DEFAULT,
190 if (dos_get_options()->DoSConnectionDefenseType) {
194 DOS_CONN_DEFENSE_TYPE_DEFAULT,
195 DOS_CONN_DEFENSE_NONE, DOS_CONN_DEFENSE_MAX);
203 if (dos_get_options()->DoSConnectionConnectRate) {
207 DOS_CONN_CONNECT_RATE_DEFAULT,
216 if (dos_get_options()->DoSConnectionConnectBurst) {
220 DOS_CONN_CONNECT_BURST_DEFAULT,
230 if (dos_get_options()->DoSConnectionConnectDefenseTimePeriod) {
234 DOS_CONN_CONNECT_DEFENSE_TIME_PERIOD_DEFAULT,
235 DOS_CONN_CONNECT_DEFENSE_TIME_PERIOD_MIN,
246 dos_cc_enabled = get_param_cc_enabled(ns);
247 dos_cc_min_concurrent_conn = get_param_cc_min_concurrent_connection(ns);
248 dos_cc_circuit_rate = get_param_cc_circuit_rate(ns);
249 dos_cc_circuit_burst = get_param_cc_circuit_burst(ns);
250 dos_cc_defense_time_period = get_param_cc_defense_time_period(ns);
251 dos_cc_defense_type = get_param_cc_defense_type(ns);
254 dos_conn_enabled = get_param_conn_enabled(ns);
255 dos_conn_max_concurrent_count = get_param_conn_max_concurrent_count(ns);
256 dos_conn_defense_type = get_param_conn_defense_type(ns);
257 dos_conn_connect_rate = get_param_conn_connect_rate(ns);
258 dos_conn_connect_burst = get_param_conn_connect_burst(ns);
259 dos_conn_connect_defense_time_period =
260 get_param_conn_connect_defense_time_period(ns);
278 if (dos_cc_enabled && !get_param_cc_enabled(ns)) {
286 get_circuit_rate_per_second(
void)
288 return dos_cc_circuit_rate;
297 uint32_t new_circuit_bucket_count;
298 uint64_t num_token, elapsed_time_last_refill = 0, circuit_rate = 0;
300 int64_t last_refill_ts;
306 last_refill_ts = (int64_t)stats->last_circ_bucket_refill_ts;
312 if ((int64_t)now == last_refill_ts) {
319 circuit_rate = get_circuit_rate_per_second();
325 if (last_refill_ts == 0) {
326 num_token = dos_cc_circuit_burst;
338 if ((int64_t)now < last_refill_ts) {
340 num_token = dos_cc_circuit_burst;
347 elapsed_time_last_refill = (uint64_t)now - last_refill_ts;
351 if (elapsed_time_last_refill > UINT32_MAX) {
352 num_token = dos_cc_circuit_burst;
359 num_token = elapsed_time_last_refill * circuit_rate;
363 if (num_token > UINT32_MAX - stats->circuit_bucket) {
364 new_circuit_bucket_count = dos_cc_circuit_burst;
368 new_circuit_bucket_count = MIN(stats->circuit_bucket + (uint32_t)num_token,
369 dos_cc_circuit_burst);
374 tor_assert_nonfatal(new_circuit_bucket_count <= dos_cc_circuit_burst);
378 tor_assert_nonfatal(new_circuit_bucket_count >= stats->circuit_bucket ||
379 new_circuit_bucket_count == dos_cc_circuit_burst);
381 log_debug(
LD_DOS,
"DoS address %s has its circuit bucket value: %" PRIu32
382 ". Filling it to %" PRIu32
". Circuit rate is %" PRIu64
383 ". Elapsed time is %" PRIi64,
384 fmt_addr(addr), stats->circuit_bucket, new_circuit_bucket_count,
385 circuit_rate, (int64_t)elapsed_time_last_refill);
387 stats->circuit_bucket = new_circuit_bucket_count;
388 stats->last_circ_bucket_refill_ts = now;
401 return stats->cc_stats.circuit_bucket == 0 &&
402 stats->conn_stats.concurrent_count >= dos_cc_min_concurrent_conn;
413 stats->marked_until_ts =
422 cc_channel_addr_is_marked(
channel_t *chan)
450 stats = &entry->dos_stats.cc_stats;
453 return stats && stats->marked_until_ts >= now;
467 stats->marked_until_ts =
468 approx_time() + dos_conn_connect_defense_time_period +
476 dos_conn_enabled = 0;
486 if (dos_conn_enabled && !get_param_conn_enabled(ns)) {
504 stats->concurrent_count++;
510 if (token_bucket_ctr_get(&stats->connect_count) > 0) {
511 token_bucket_ctr_dec(&stats->connect_count, 1);
517 if (token_bucket_ctr_get(&stats->connect_count) == 0 &&
518 stats->marked_until_ts == 0) {
519 conn_mark_client(stats);
522 log_debug(
LD_DOS,
"Client address %s has now %u concurrent connections. "
523 "Remaining %" TOR_PRIuSZ
"/sec connections are allowed.",
524 fmt_addr(addr), stats->concurrent_count,
525 token_bucket_ctr_get(&stats->connect_count));
538 if (BUG(stats->concurrent_count == 0)) {
542 stats->concurrent_count--;
543 log_debug(
LD_DOS,
"Client address %s has lost a connection. Concurrent "
544 "connections are now at %u",
545 fmt_addr(addr), stats->concurrent_count);
555 return (dos_cc_enabled || dos_conn_enabled);
570 if (!dos_cc_enabled) {
599 cc_stats_refill_bucket(&entry->dos_stats.cc_stats, &addr);
603 if (entry->dos_stats.cc_stats.circuit_bucket > 0) {
604 entry->dos_stats.cc_stats.circuit_bucket--;
609 if (cc_has_exhausted_circuits(&entry->dos_stats)) {
613 if (entry->dos_stats.cc_stats.marked_until_ts == 0) {
614 log_debug(
LD_DOS,
"Detected circuit creation DoS by address: %s",
616 cc_num_marked_addrs++;
618 cc_mark_client(&entry->dos_stats.cc_stats);
628 dos_cc_defense_type_t
634 if (!dos_cc_enabled) {
640 if (cc_channel_addr_is_marked(chan)) {
643 cc_num_rejected_cells++;
644 return dos_cc_defense_type;
648 return DOS_CC_DEFENSE_NONE;
655 dos_conn_defense_type_t
656 dos_conn_addr_get_defense_type(
const tor_addr_t *addr)
663 if (!dos_conn_enabled) {
674 if (entry->dos_stats.conn_stats.marked_until_ts >=
approx_time()) {
675 conn_num_addr_connect_rejected++;
676 return dos_conn_defense_type;
681 entry->dos_stats.conn_stats.marked_until_ts = 0;
685 if (entry->dos_stats.conn_stats.concurrent_count >
686 dos_conn_max_concurrent_count) {
687 conn_num_addr_rejected++;
688 return dos_conn_defense_type;
692 return DOS_CONN_DEFENSE_NONE;
711 if (geoip_ent->dos_stats.conn_stats.concurrent_count == 0) {
726 } SMARTLIST_FOREACH_END(conn);
744 dos_conn_connect_rate, dos_conn_connect_burst,
751 dos_note_refuse_single_hop_client(
void)
753 num_single_hop_client_refused++;
759 dos_should_refuse_single_hop_client(
void)
766 if (dos_get_options()->DoSRefuseSingleHopClientRendezvous != -1) {
771 "DoSRefuseSingleHopClientRendezvous",
777 dos_log_heartbeat(
void)
783 "%" PRIu64
" circuits killed with too many cells",
786 if (dos_cc_enabled) {
788 "%" PRIu64
" circuits rejected, "
789 "%" PRIu32
" marked addresses",
790 cc_num_rejected_cells, cc_num_marked_addrs);
795 if (dos_conn_enabled) {
797 "%" PRIu64
" same address concurrent "
798 "connections rejected", conn_num_addr_rejected);
800 "%" PRIu64
" connections rejected",
801 conn_num_addr_connect_rejected);
806 if (dos_should_refuse_single_hop_client()) {
808 "%" PRIu64
" single hop clients refused",
809 num_single_hop_client_refused);
812 "[DoSRefuseSingleHopClientRendezvous disabled]");
817 "%" PRIu64
" INTRODUCE2 rejected",
823 "Heartbeat: DoS mitigation since startup: %s.", msg);
827 smartlist_free(elems);
833 dos_new_client_conn(
or_connection_t *or_conn,
const char *transport_name)
841 if (!dos_is_enabled()) {
854 entry = geoip_lookup_client(&
TO_CONN(or_conn)->addr, transport_name,
856 if (BUG(entry == NULL)) {
863 conn_update_on_connect(&entry->dos_stats.conn_stats,
888 entry = geoip_lookup_client(&
TO_CONN(or_conn)->addr, NULL,
897 conn_update_on_close(&entry->dos_stats.conn_stats, &
TO_CONN(or_conn)->addr);
916 cc_consensus_has_changed(ns);
917 conn_consensus_has_changed(ns);
921 set_dos_parameters(ns);
928 return dos_is_enabled();
949 set_dos_parameters(NULL);
int tor_addr_compare(const tor_addr_t *addr1, const tor_addr_t *addr2, tor_addr_comparison_t how)
int channel_is_client(const channel_t *chan)
int channel_get_addr_if_possible(const channel_t *chan, tor_addr_t *addr_out)
Header file for channel.c.
const or_options_t * get_options(void)
Header file for config.c.
Header file for connection.c.
or_connection_t * TO_OR_CONN(connection_t *c)
Header file for connection_or.c.
Common functions for using (pseudo-)random number generators.
int crypto_rand_int_range(unsigned int min, unsigned int max)
Structure dos_options_t to hold options for the DoS subsystem.
Header for core/or/dos_sys.c.
Header file for geoip_stats.c.
uint64_t hs_dos_get_intro2_rejected_count(void)
Header file containing denial of service defenses for the HS subsystem for all versions.
smartlist_t * get_connection_array(void)
Header file for mainloop.c.
int32_t networkstatus_get_param(const networkstatus_t *ns, const char *param_name, int32_t default_val, int32_t min_val, int32_t max_val)
Header file for networkstatus.c.
int nodelist_probably_contains_address(const tor_addr_t *addr)
Header file for nodelist.c.
Master header file for Tor-specific functionality.
uint64_t stats_n_circ_max_cell_reached
int public_server_mode(const or_options_t *options)
Header file for routermode.c.
void smartlist_add_asprintf(struct smartlist_t *sl, const char *pattern,...)
char * smartlist_join_strings(smartlist_t *sl, const char *join, int terminate, size_t *len_out)
smartlist_t * smartlist_new(void)
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
#define SMARTLIST_FOREACH(sl, type, var, cmd)
AUTOBOOL DoSConnectionEnabled
INT DoSCircuitCreationDefenseType
POSINT DoSCircuitCreationMinConnections
POSINT DoSCircuitCreationBurst
POSINT DoSConnectionConnectBurst
POSINT DoSConnectionConnectRate
POSINT DoSCircuitCreationRate
INT DoSConnectionDefenseType
AUTOBOOL DoSCircuitCreationEnabled
INTERVAL DoSCircuitCreationDefenseTimePeriod
AUTOBOOL DoSRefuseSingleHopClientRendezvous
INTERVAL DoSConnectionConnectDefenseTimePeriod
POSINT DoSConnectionMaxConcurrentCount
unsigned int tracked_for_dos_mitigation
#define MOCK_IMPL(rv, funcname, arglist)
void token_bucket_ctr_init(token_bucket_ctr_t *bucket, uint32_t rate, uint32_t burst, uint32_t now_ts)
void token_bucket_ctr_refill(token_bucket_ctr_t *bucket, uint32_t now_ts)