Tor 0.4.9.8
Loading...
Searching...
No Matches
dos.c
1/* Copyright (c) 2018-2021, The Tor Project, Inc. */
2/* See LICENSE for licensing information */
3
4/*
5 * \file dos.c
6 * \brief Implement Denial of Service mitigation subsystem.
7 */
8
9#define DOS_PRIVATE
10
11#include "core/or/or.h"
12#include "app/config/config.h"
15#include "core/or/channel.h"
17#include "core/or/relay.h"
18#include "feature/hs/hs_dos.h"
25
26#include "core/or/dos.h"
27#include "core/or/dos_sys.h"
28
31
32/*
33 * Circuit creation denial of service mitigation.
34 *
35 * Namespace used for this mitigation framework is "dos_cc_" where "cc" is for
36 * Circuit Creation.
37 */
38
39/* Is the circuit creation DoS mitigation enabled? */
40static unsigned int dos_cc_enabled = 0;
41
42/* Consensus parameters. They can be changed when a new consensus arrives.
43 * They are initialized with the hardcoded default values. */
44static uint32_t dos_cc_min_concurrent_conn;
45static uint32_t dos_cc_circuit_rate;
46static uint32_t dos_cc_circuit_burst;
47static dos_cc_defense_type_t dos_cc_defense_type;
48static int32_t dos_cc_defense_time_period;
49
50/* Keep some stats for the heartbeat so we can report out. */
51static uint64_t cc_num_rejected_cells;
52static uint32_t cc_num_marked_addrs;
53static uint32_t cc_num_marked_addrs_max_queue;
54
55/*
56 * Concurrent connection denial of service mitigation.
57 *
58 * Namespace used for this mitigation framework is "dos_conn_".
59 */
60
61/* Is the connection DoS mitigation enabled? */
62static unsigned int dos_conn_enabled = 0;
63
64/* Consensus parameters. They can be changed when a new consensus arrives.
65 * They are initialized with the hardcoded default values. */
66static uint32_t dos_conn_max_concurrent_count;
67static dos_conn_defense_type_t dos_conn_defense_type;
68static uint32_t dos_conn_connect_rate = DOS_CONN_CONNECT_RATE_DEFAULT;
69static uint32_t dos_conn_connect_burst = DOS_CONN_CONNECT_BURST_DEFAULT;
70static int32_t dos_conn_connect_defense_time_period =
71 DOS_CONN_CONNECT_DEFENSE_TIME_PERIOD_DEFAULT;
72
73/* Keep some stats for the heartbeat so we can report out. */
74static uint64_t conn_num_addr_rejected;
75static uint64_t conn_num_addr_connect_rejected;
76
77/** Consensus parameter: How many times a client IP is allowed to hit the
78 * circ_max_cell_queue_size_out limit before being marked. */
79static uint32_t dos_num_circ_max_outq;
80
81/*
82 * Stream denial of service mitigation.
83 *
84 * Namespace used for this mitigation framework is "dos_stream_".
85 */
86
87/* Is the connection DoS mitigation enabled? */
88static unsigned int dos_stream_enabled = 0;
89
90/* Consensus parameters. They can be changed when a new consensus arrives.
91 * They are initialized with the hardcoded default values. */
92static dos_stream_defense_type_t dos_stream_defense_type;
93static uint32_t dos_stream_rate = DOS_STREAM_RATE_DEFAULT;
94static uint32_t dos_stream_burst = DOS_STREAM_BURST_DEFAULT;
95
96/* Keep some stats for the heartbeat so we can report out. */
97static uint64_t stream_num_rejected;
98
99/*
100 * General interface of the denial of service mitigation subsystem.
101 */
102
103/* Keep stats for the heartbeat. */
104static uint64_t num_single_hop_client_refused;
105
106/** Return the consensus parameter for the outbound circ_max_cell_queue_size
107 * limit. */
108static uint32_t
109get_param_dos_num_circ_max_outq(const networkstatus_t *ns)
110{
111#define DOS_NUM_CIRC_MAX_OUTQ_DEFAULT 3
112#define DOS_NUM_CIRC_MAX_OUTQ_MIN 0
113#define DOS_NUM_CIRC_MAX_OUTQ_MAX INT32_MAX
114
115 /* Update the circuit max cell queue size from the consensus. */
116 return networkstatus_get_param(ns, "dos_num_circ_max_outq",
117 DOS_NUM_CIRC_MAX_OUTQ_DEFAULT,
118 DOS_NUM_CIRC_MAX_OUTQ_MIN,
119 DOS_NUM_CIRC_MAX_OUTQ_MAX);
120}
121
122/* Return true iff the circuit creation mitigation is enabled. We look at the
123 * consensus for this else a default value is returned. */
124MOCK_IMPL(STATIC unsigned int,
125get_param_cc_enabled, (const networkstatus_t *ns))
126{
127 if (dos_get_options()->DoSCircuitCreationEnabled != -1) {
128 return dos_get_options()->DoSCircuitCreationEnabled;
129 }
130
131 return !!networkstatus_get_param(ns, "DoSCircuitCreationEnabled",
132 DOS_CC_ENABLED_DEFAULT, 0, 1);
133}
134
135/* Return the parameter for the minimum concurrent connection at which we'll
136 * start counting circuit for a specific client address. */
137STATIC uint32_t
138get_param_cc_min_concurrent_connection(const networkstatus_t *ns)
139{
140 if (dos_get_options()->DoSCircuitCreationMinConnections) {
141 return dos_get_options()->DoSCircuitCreationMinConnections;
142 }
143 return networkstatus_get_param(ns, "DoSCircuitCreationMinConnections",
144 DOS_CC_MIN_CONCURRENT_CONN_DEFAULT,
145 1, INT32_MAX);
146}
147
148/* Return the parameter for the time rate that is how many circuits over this
149 * time span. */
150static uint32_t
151get_param_cc_circuit_rate(const networkstatus_t *ns)
152{
153 /* This is in seconds. */
154 if (dos_get_options()->DoSCircuitCreationRate) {
155 return dos_get_options()->DoSCircuitCreationRate;
156 }
157 return networkstatus_get_param(ns, "DoSCircuitCreationRate",
158 DOS_CC_CIRCUIT_RATE_DEFAULT,
159 1, INT32_MAX);
160}
161
162/* Return the parameter for the maximum circuit count for the circuit time
163 * rate. */
164STATIC uint32_t
165get_param_cc_circuit_burst(const networkstatus_t *ns)
166{
167 if (dos_get_options()->DoSCircuitCreationBurst) {
168 return dos_get_options()->DoSCircuitCreationBurst;
169 }
170 return networkstatus_get_param(ns, "DoSCircuitCreationBurst",
171 DOS_CC_CIRCUIT_BURST_DEFAULT,
172 1, INT32_MAX);
173}
174
175/* Return the consensus parameter of the circuit creation defense type. */
176static uint32_t
177get_param_cc_defense_type(const networkstatus_t *ns)
178{
179 if (dos_get_options()->DoSCircuitCreationDefenseType) {
180 return dos_get_options()->DoSCircuitCreationDefenseType;
181 }
182 return networkstatus_get_param(ns, "DoSCircuitCreationDefenseType",
183 DOS_CC_DEFENSE_TYPE_DEFAULT,
184 DOS_CC_DEFENSE_NONE, DOS_CC_DEFENSE_MAX);
185}
186
187/* Return the consensus parameter of the defense time period which is how much
188 * time should we defend against a malicious client address. */
189static int32_t
190get_param_cc_defense_time_period(const networkstatus_t *ns)
191{
192 /* Time in seconds. */
193 if (dos_get_options()->DoSCircuitCreationDefenseTimePeriod) {
194 return dos_get_options()->DoSCircuitCreationDefenseTimePeriod;
195 }
196 return networkstatus_get_param(ns, "DoSCircuitCreationDefenseTimePeriod",
197 DOS_CC_DEFENSE_TIME_PERIOD_DEFAULT,
198 0, INT32_MAX);
199}
200
201/* Return true iff connection mitigation is enabled. We look at the consensus
202 * for this else a default value is returned. */
203MOCK_IMPL(STATIC unsigned int,
204get_param_conn_enabled, (const networkstatus_t *ns))
205{
206 if (dos_get_options()->DoSConnectionEnabled != -1) {
207 return dos_get_options()->DoSConnectionEnabled;
208 }
209 return !!networkstatus_get_param(ns, "DoSConnectionEnabled",
210 DOS_CONN_ENABLED_DEFAULT, 0, 1);
211}
212
213/* Return the consensus parameter for the maximum concurrent connection
214 * allowed. */
215STATIC uint32_t
216get_param_conn_max_concurrent_count(const networkstatus_t *ns)
217{
218 if (dos_get_options()->DoSConnectionMaxConcurrentCount) {
219 return dos_get_options()->DoSConnectionMaxConcurrentCount;
220 }
221 return networkstatus_get_param(ns, "DoSConnectionMaxConcurrentCount",
222 DOS_CONN_MAX_CONCURRENT_COUNT_DEFAULT,
223 1, INT32_MAX);
224}
225
226/* Return the consensus parameter of the connection defense type. */
227static uint32_t
228get_param_conn_defense_type(const networkstatus_t *ns)
229{
230 if (dos_get_options()->DoSConnectionDefenseType) {
231 return dos_get_options()->DoSConnectionDefenseType;
232 }
233 return networkstatus_get_param(ns, "DoSConnectionDefenseType",
234 DOS_CONN_DEFENSE_TYPE_DEFAULT,
235 DOS_CONN_DEFENSE_NONE, DOS_CONN_DEFENSE_MAX);
236}
237
238/* Return the connection connect rate parameters either from the configuration
239 * file or, if not found, consensus parameter. */
240static uint32_t
241get_param_conn_connect_rate(const networkstatus_t *ns)
242{
243 if (dos_get_options()->DoSConnectionConnectRate) {
244 return dos_get_options()->DoSConnectionConnectRate;
245 }
246 return networkstatus_get_param(ns, "DoSConnectionConnectRate",
247 DOS_CONN_CONNECT_RATE_DEFAULT,
248 1, INT32_MAX);
249}
250
251/* Return the connection connect burst parameters either from the
252 * configuration file or, if not found, consensus parameter. */
253STATIC uint32_t
254get_param_conn_connect_burst(const networkstatus_t *ns)
255{
256 if (dos_get_options()->DoSConnectionConnectBurst) {
257 return dos_get_options()->DoSConnectionConnectBurst;
258 }
259 return networkstatus_get_param(ns, "DoSConnectionConnectBurst",
260 DOS_CONN_CONNECT_BURST_DEFAULT,
261 1, INT32_MAX);
262}
263
264/* Return the connection connect defense time period from the configuration
265 * file or, if not found, the consensus parameter. */
266static int32_t
267get_param_conn_connect_defense_time_period(const networkstatus_t *ns)
268{
269 /* Time in seconds. */
270 if (dos_get_options()->DoSConnectionConnectDefenseTimePeriod) {
271 return dos_get_options()->DoSConnectionConnectDefenseTimePeriod;
272 }
273 return networkstatus_get_param(ns, "DoSConnectionConnectDefenseTimePeriod",
274 DOS_CONN_CONNECT_DEFENSE_TIME_PERIOD_DEFAULT,
275 DOS_CONN_CONNECT_DEFENSE_TIME_PERIOD_MIN,
276 INT32_MAX);
277}
278
279/* Return true iff the stream creation mitigation is enabled. We look at the
280 * consensus for this else a default value is returned. */
281MOCK_IMPL(STATIC unsigned int,
282get_param_stream_enabled, (const networkstatus_t *ns))
283{
284 if (dos_get_options()->DoSStreamCreationEnabled != -1) {
285 return dos_get_options()->DoSStreamCreationEnabled;
286 }
287
288 return !!networkstatus_get_param(ns, "DoSStreamCreationEnabled",
289 DOS_STREAM_ENABLED_DEFAULT, 0, 1);
290}
291
292/* Return the parameter for the time rate that is how many stream per circuit
293 * over this time span. */
294static uint32_t
295get_param_stream_rate(const networkstatus_t *ns)
296{
297 /* This is in seconds. */
298 if (dos_get_options()->DoSStreamCreationRate) {
299 return dos_get_options()->DoSStreamCreationRate;
300 }
301 return networkstatus_get_param(ns, "DoSStreamCreationRate",
302 DOS_STREAM_RATE_DEFAULT,
303 1, INT32_MAX);
304}
305
306/* Return the parameter for the maximum circuit count for the circuit time
307 * rate. */
308static uint32_t
309get_param_stream_burst(const networkstatus_t *ns)
310{
311 if (dos_get_options()->DoSStreamCreationBurst) {
312 return dos_get_options()->DoSStreamCreationBurst;
313 }
314 return networkstatus_get_param(ns, "DoSStreamCreationBurst",
315 DOS_STREAM_BURST_DEFAULT,
316 1, INT32_MAX);
317}
318
319/* Return the consensus parameter of the circuit creation defense type. */
320static uint32_t
321get_param_stream_defense_type(const networkstatus_t *ns)
322{
323 if (dos_get_options()->DoSStreamCreationDefenseType) {
324 return dos_get_options()->DoSStreamCreationDefenseType;
325 }
326 return networkstatus_get_param(ns, "DoSStreamCreationDefenseType",
327 DOS_STREAM_DEFENSE_TYPE_DEFAULT,
328 DOS_STREAM_DEFENSE_NONE,
329 DOS_STREAM_DEFENSE_MAX);
330}
331
332/* Set circuit creation parameters located in the consensus or their default
333 * if none are present. Called at initialization or when the consensus
334 * changes. */
335static void
336set_dos_parameters(const networkstatus_t *ns)
337{
338 /* Get the default consensus param values. */
339 dos_cc_enabled = get_param_cc_enabled(ns);
340 dos_cc_min_concurrent_conn = get_param_cc_min_concurrent_connection(ns);
341 dos_cc_circuit_rate = get_param_cc_circuit_rate(ns);
342 dos_cc_circuit_burst = get_param_cc_circuit_burst(ns);
343 dos_cc_defense_time_period = get_param_cc_defense_time_period(ns);
344 dos_cc_defense_type = get_param_cc_defense_type(ns);
345
346 /* Connection detection. */
347 dos_conn_enabled = get_param_conn_enabled(ns);
348 dos_conn_max_concurrent_count = get_param_conn_max_concurrent_count(ns);
349 dos_conn_defense_type = get_param_conn_defense_type(ns);
350 dos_conn_connect_rate = get_param_conn_connect_rate(ns);
351 dos_conn_connect_burst = get_param_conn_connect_burst(ns);
352 dos_conn_connect_defense_time_period =
353 get_param_conn_connect_defense_time_period(ns);
354
355 /* Circuit. */
356 dos_num_circ_max_outq = get_param_dos_num_circ_max_outq(ns);
357
358 /* Stream. */
359 dos_stream_enabled = get_param_stream_enabled(ns);
360 dos_stream_defense_type = get_param_stream_defense_type(ns);
361 dos_stream_rate = get_param_stream_rate(ns);
362 dos_stream_burst = get_param_stream_burst(ns);
363}
364
365/* Free everything for the circuit creation DoS mitigation subsystem. */
366static void
367cc_free_all(void)
368{
369 /* If everything is freed, the circuit creation subsystem is not enabled. */
370 dos_cc_enabled = 0;
371}
372
373/* Called when the consensus has changed. Do appropriate actions for the
374 * circuit creation subsystem. */
375static void
376cc_consensus_has_changed(const networkstatus_t *ns)
377{
378 /* Looking at the consensus, is the circuit creation subsystem enabled? If
379 * not and it was enabled before, clean it up. */
380 if (dos_cc_enabled && !get_param_cc_enabled(ns)) {
381 cc_free_all();
382 }
383}
384
385/** Return the number of circuits we allow per second under the current
386 * configuration. */
387STATIC uint64_t
388get_circuit_rate_per_second(void)
389{
390 return dos_cc_circuit_rate;
391}
392
393/* Given the circuit creation client statistics object, refill the circuit
394 * bucket if needed. This also works if the bucket was never filled in the
395 * first place. The addr is only used for logging purposes. */
396STATIC void
397cc_stats_refill_bucket(cc_client_stats_t *stats, const tor_addr_t *addr)
398{
399 uint32_t new_circuit_bucket_count;
400 uint64_t num_token, elapsed_time_last_refill = 0, circuit_rate = 0;
401 time_t now;
402 int64_t last_refill_ts;
403
404 tor_assert(stats);
405 tor_assert(addr);
406
407 now = approx_time();
408 last_refill_ts = (int64_t)stats->last_circ_bucket_refill_ts;
409
410 /* If less than a second has elapsed, don't add any tokens.
411 * Note: If a relay's clock is ever 0, any new clients won't get a refill
412 * until the next second. But a relay that thinks it is 1970 will never
413 * validate the public consensus. */
414 if ((int64_t)now == last_refill_ts) {
415 goto done;
416 }
417
418 /* At this point, we know we might need to add token to the bucket. We'll
419 * first get the circuit rate that is how many circuit are we allowed to do
420 * per second. */
421 circuit_rate = get_circuit_rate_per_second();
422
423 /* We've never filled the bucket so fill it with the maximum being the burst
424 * and we are done.
425 * Note: If a relay's clock is ever 0, all clients that were last refilled
426 * in that zero second will get a full refill here. */
427 if (last_refill_ts == 0) {
428 num_token = dos_cc_circuit_burst;
429 goto end;
430 }
431
432 /* Our clock jumped backward so fill it up to the maximum. Not filling it
433 * could trigger a detection for a valid client. Also, if the clock jumped
434 * negative but we didn't notice until the elapsed time became positive
435 * again, then we potentially spent many seconds not refilling the bucket
436 * when we should have been refilling it. But the fact that we didn't notice
437 * until now means that no circuit creation requests came in during that
438 * time, so the client doesn't end up punished that much from this hopefully
439 * rare situation.*/
440 if ((int64_t)now < last_refill_ts) {
441 /* Use the maximum allowed value of token. */
442 num_token = dos_cc_circuit_burst;
443 goto end;
444 }
445
446 /* How many seconds have elapsed between now and the last refill?
447 * This subtraction can't underflow, because now >= last_refill_ts.
448 * And it can't overflow, because INT64_MAX - (-INT64_MIN) == UINT64_MAX. */
449 elapsed_time_last_refill = (uint64_t)now - last_refill_ts;
450
451 /* If the elapsed time is very large, it means our clock jumped forward.
452 * If the multiplication would overflow, use the maximum allowed value. */
453 if (elapsed_time_last_refill > UINT32_MAX) {
454 num_token = dos_cc_circuit_burst;
455 goto end;
456 }
457
458 /* Compute how many circuits we are allowed in that time frame which we'll
459 * add to the bucket. This can't overflow, because both multiplicands
460 * are less than or equal to UINT32_MAX, and num_token is uint64_t. */
461 num_token = elapsed_time_last_refill * circuit_rate;
462
463 end:
464 /* If the sum would overflow, use the maximum allowed value. */
465 if (num_token > UINT32_MAX - stats->circuit_bucket) {
466 new_circuit_bucket_count = dos_cc_circuit_burst;
467 } else {
468 /* We cap the bucket to the burst value else this could overflow uint32_t
469 * over time. */
470 new_circuit_bucket_count = MIN(stats->circuit_bucket + (uint32_t)num_token,
471 dos_cc_circuit_burst);
472 }
473
474 /* This function is not allowed to make the bucket count larger than the
475 * burst value */
476 tor_assert_nonfatal(new_circuit_bucket_count <= dos_cc_circuit_burst);
477 /* This function is not allowed to make the bucket count smaller, unless it
478 * is decreasing it to a newly configured, lower burst value. We allow the
479 * bucket to stay the same size, in case the circuit rate is zero. */
480 tor_assert_nonfatal(new_circuit_bucket_count >= stats->circuit_bucket ||
481 new_circuit_bucket_count == dos_cc_circuit_burst);
482
483 log_debug(LD_DOS, "DoS address %s has its circuit bucket value: %" PRIu32
484 ". Filling it to %" PRIu32 ". Circuit rate is %" PRIu64
485 ". Elapsed time is %" PRIi64,
486 fmt_addr(addr), stats->circuit_bucket, new_circuit_bucket_count,
487 circuit_rate, (int64_t)elapsed_time_last_refill);
488
489 stats->circuit_bucket = new_circuit_bucket_count;
490 stats->last_circ_bucket_refill_ts = now;
491
492 done:
493 return;
494}
495
496/* Return true iff the circuit bucket is down to 0 and the number of
497 * concurrent connections is greater or equal the minimum threshold set the
498 * consensus parameter. */
499static int
500cc_has_exhausted_circuits(const dos_client_stats_t *stats)
501{
502 tor_assert(stats);
503 return stats->cc_stats.circuit_bucket == 0 &&
504 stats->conn_stats.concurrent_count >= dos_cc_min_concurrent_conn;
505}
506
507/* Mark client address by setting a timestamp in the stats object which tells
508 * us until when it is marked as positively detected. */
509static void
510cc_mark_client(cc_client_stats_t *stats)
511{
512 tor_assert(stats);
513 /* We add a random offset of a maximum of half the defense time so it is
514 * less predictable. */
515 stats->marked_until_ts =
516 approx_time() + dos_cc_defense_time_period +
517 crypto_rand_int_range(1, dos_cc_defense_time_period / 2);
518}
519
520/* Return true iff the given channel address is marked as malicious. This is
521 * called a lot and part of the fast path of handling cells. It has to remain
522 * as fast as we can. */
523static int
524cc_channel_addr_is_marked(channel_t *chan)
525{
526 time_t now;
527 tor_addr_t addr;
528 clientmap_entry_t *entry;
529 cc_client_stats_t *stats = NULL;
530
531 if (chan == NULL) {
532 goto end;
533 }
534 /* Must be a client connection else we ignore. */
535 if (!channel_is_client(chan)) {
536 goto end;
537 }
538 /* Without an IP address, nothing can work. */
539 if (!channel_get_addr_if_possible(chan, &addr)) {
540 goto end;
541 }
542
543 /* We are only interested in client connection from the geoip cache. */
544 entry = geoip_lookup_client(&addr, NULL, GEOIP_CLIENT_CONNECT);
545 if (entry == NULL) {
546 /* We can have a connection creating circuits but not tracked by the geoip
547 * cache. Once this DoS subsystem is enabled, we can end up here with no
548 * entry for the channel. */
549 goto end;
550 }
551 now = approx_time();
552 stats = &entry->dos_stats.cc_stats;
553
554 end:
555 return stats && stats->marked_until_ts >= now;
556}
557
558/* Concurrent connection private API. */
559
560/* Mark client connection stats by setting a timestamp which tells us until
561 * when it is marked as positively detected. */
562static void
563conn_mark_client(conn_client_stats_t *stats)
564{
565 tor_assert(stats);
566
567 /* We add a random offset of a maximum of half the defense time so it is
568 * less predictable and thus more difficult to game. */
569 stats->marked_until_ts =
570 approx_time() + dos_conn_connect_defense_time_period +
571 crypto_rand_int_range(1, dos_conn_connect_defense_time_period / 2);
572}
573
574/* Free everything for the connection DoS mitigation subsystem. */
575static void
576conn_free_all(void)
577{
578 dos_conn_enabled = 0;
579}
580
581/* Called when the consensus has changed. Do appropriate actions for the
582 * connection mitigation subsystem. */
583static void
584conn_consensus_has_changed(const networkstatus_t *ns)
585{
586 /* Looking at the consensus, is the connection mitigation subsystem enabled?
587 * If not and it was enabled before, clean it up. */
588 if (dos_conn_enabled && !get_param_conn_enabled(ns)) {
589 conn_free_all();
590 }
591}
592
593/** Called when a new client connection has arrived. The following will update
594 * the client connection statistics.
595 *
596 * The addr is used for logging purposes only.
597 *
598 * If the connect counter reaches its limit, it is marked. */
599static void
600conn_update_on_connect(conn_client_stats_t *stats, const tor_addr_t *addr)
601{
602 tor_assert(stats);
603 tor_assert(addr);
604
605 /* Update concurrent count for this new connect. */
606 stats->concurrent_count++;
607
608 /* Refill connect connection count. */
609 token_bucket_ctr_refill(&stats->connect_count,
610 (uint32_t) monotime_coarse_absolute_sec());
611
612 /* Decrement counter for this new connection. */
613 if (token_bucket_ctr_get(&stats->connect_count) > 0) {
614 token_bucket_ctr_dec(&stats->connect_count, 1);
615 }
616
617 /* Assess connect counter. Mark it if counter is down to 0 and we haven't
618 * marked it before or it was reset. This is to avoid to re-mark it over and
619 * over again extending continuously the blocked time. */
620 if (token_bucket_ctr_get(&stats->connect_count) == 0 &&
621 stats->marked_until_ts == 0) {
622 conn_mark_client(stats);
623 }
624
625 log_debug(LD_DOS, "Client address %s has now %u concurrent connections. "
626 "Remaining %" TOR_PRIuSZ "/sec connections are allowed.",
627 fmt_addr(addr), stats->concurrent_count,
628 token_bucket_ctr_get(&stats->connect_count));
629}
630
631/** Called when a client connection is closed. The following will update
632 * the client connection statistics.
633 *
634 * The addr is used for logging purposes only. */
635static void
636conn_update_on_close(conn_client_stats_t *stats, const tor_addr_t *addr)
637{
638 /* Extra super duper safety. Going below 0 means an underflow which could
639 * lead to most likely a false positive. In theory, this should never happen
640 * but let's be extra safe. */
641 if (BUG(stats->concurrent_count == 0)) {
642 return;
643 }
644
645 stats->concurrent_count--;
646 log_debug(LD_DOS, "Client address %s has lost a connection. Concurrent "
647 "connections are now at %u",
648 fmt_addr(addr), stats->concurrent_count);
649}
650
651/* General private API */
652
653/* Return true iff we have at least one DoS detection enabled. This is used to
654 * decide if we need to allocate any kind of high level DoS object. */
655static inline int
656dos_is_enabled(void)
657{
658 return (dos_cc_enabled || dos_conn_enabled);
659}
660
661/* Circuit creation public API. */
662
663/** Return the number of rejected circuits. */
664uint64_t
665dos_get_num_cc_rejected(void)
666{
667 return cc_num_rejected_cells;
668}
669
670/** Return the number of marked addresses. */
671uint32_t
672dos_get_num_cc_marked_addr(void)
673{
674 return cc_num_marked_addrs;
675}
676
677/** Return the number of marked addresses due to max queue limit reached. */
678uint32_t
679dos_get_num_cc_marked_addr_maxq(void)
680{
681 return cc_num_marked_addrs_max_queue;
682}
683
684/** Return number of concurrent connections rejected. */
685uint64_t
686dos_get_num_conn_addr_rejected(void)
687{
688 return conn_num_addr_rejected;
689}
690
691/** Return the number of connection rejected. */
692uint64_t
693dos_get_num_conn_addr_connect_rejected(void)
694{
695 return conn_num_addr_connect_rejected;
696}
697
698/** Return the number of single hop refused. */
699uint64_t
700dos_get_num_single_hop_refused(void)
701{
702 return num_single_hop_client_refused;
703}
704
705/* Called when a CREATE cell is received from the given channel. */
706void
707dos_cc_new_create_cell(channel_t *chan)
708{
709 tor_addr_t addr;
710 clientmap_entry_t *entry;
711
712 tor_assert(chan);
713
714 /* Skip everything if not enabled. */
715 if (!dos_cc_enabled) {
716 goto end;
717 }
718
719 /* Must be a client connection else we ignore. */
720 if (!channel_is_client(chan)) {
721 goto end;
722 }
723 /* Without an IP address, nothing can work. */
724 if (!channel_get_addr_if_possible(chan, &addr)) {
725 goto end;
726 }
727
728 /* We are only interested in client connection from the geoip cache. */
729 entry = geoip_lookup_client(&addr, NULL, GEOIP_CLIENT_CONNECT);
730 if (entry == NULL) {
731 /* We can have a connection creating circuits but not tracked by the geoip
732 * cache. Once this DoS subsystem is enabled, we can end up here with no
733 * entry for the channel. */
734 goto end;
735 }
736
737 /* General comment. Even though the client can already be marked as
738 * malicious, we continue to track statistics. If it keeps going above
739 * threshold while marked, the defense period time will grow longer. There
740 * is really no point at unmarking a client that keeps DoSing us. */
741
742 /* First of all, we'll try to refill the circuit bucket opportunistically
743 * before we assess. */
744 cc_stats_refill_bucket(&entry->dos_stats.cc_stats, &addr);
745
746 /* Take a token out of the circuit bucket if we are above 0 so we don't
747 * underflow the bucket. */
748 if (entry->dos_stats.cc_stats.circuit_bucket > 0) {
749 entry->dos_stats.cc_stats.circuit_bucket--;
750 }
751
752 /* This is the detection. Assess at every CREATE cell if the client should
753 * get marked as malicious. This should be kept as fast as possible. */
754 if (cc_has_exhausted_circuits(&entry->dos_stats)) {
755 /* If this is the first time we mark this entry, log it.
756 * Under heavy DDoS, logging each time we mark would results in lots and
757 * lots of logs. */
758 if (entry->dos_stats.cc_stats.marked_until_ts == 0) {
759 log_debug(LD_DOS, "Detected circuit creation DoS by address: %s",
760 fmt_addr(&addr));
761 cc_num_marked_addrs++;
762 }
763 cc_mark_client(&entry->dos_stats.cc_stats);
764 }
765
766 end:
767 return;
768}
769
770/* Return the defense type that should be used for this circuit.
771 *
772 * This is part of the fast path and called a lot. */
773dos_cc_defense_type_t
774dos_cc_get_defense_type(channel_t *chan)
775{
776 tor_assert(chan);
777
778 /* Skip everything if not enabled. */
779 if (!dos_cc_enabled) {
780 goto end;
781 }
782
783 /* On an OR circuit, we'll check if the previous channel is a marked client
784 * connection detected by our DoS circuit creation mitigation subsystem. */
785 if (cc_channel_addr_is_marked(chan)) {
786 /* We've just assess that this circuit should trigger a defense for the
787 * cell it just seen. Note it down. */
788 cc_num_rejected_cells++;
789 return dos_cc_defense_type;
790 }
791
792 end:
793 return DOS_CC_DEFENSE_NONE;
794}
795
796/* Concurrent connection detection public API. */
797
798/* Return true iff the given address is permitted to open another connection.
799 * A defense value is returned for the caller to take appropriate actions. */
800dos_conn_defense_type_t
801dos_conn_addr_get_defense_type(const tor_addr_t *addr)
802{
803 clientmap_entry_t *entry;
804
805 tor_assert(addr);
806
807 /* Skip everything if not enabled. */
808 if (!dos_conn_enabled) {
809 goto end;
810 }
811
812 /* We are only interested in client connection from the geoip cache. */
813 entry = geoip_lookup_client(addr, NULL, GEOIP_CLIENT_CONNECT);
814 if (entry == NULL) {
815 goto end;
816 }
817
818 /* Is this address marked as making too many client connections? */
819 if (entry->dos_stats.conn_stats.marked_until_ts >= approx_time()) {
820 conn_num_addr_connect_rejected++;
821 return dos_conn_defense_type;
822 }
823 /* Reset it to 0 here so that if the marked timestamp has expired that is
824 * we've gone beyond it, we have to reset it so the detection can mark it
825 * again in the future. */
826 entry->dos_stats.conn_stats.marked_until_ts = 0;
827
828 /* Need to be above the maximum concurrent connection count to trigger a
829 * defense. */
830 if (entry->dos_stats.conn_stats.concurrent_count >
831 dos_conn_max_concurrent_count) {
832 conn_num_addr_rejected++;
833 return dos_conn_defense_type;
834 }
835
836 end:
837 return DOS_CONN_DEFENSE_NONE;
838}
839
840/* Stream creation public API. */
841
842/** Return the number of rejected stream and resolve. */
843uint64_t
844dos_get_num_stream_rejected(void)
845{
846 return stream_num_rejected;
847}
848
849/* Return the action to take against a BEGIN or RESOLVE cell. Return
850 * DOS_STREAM_DEFENSE_NONE when no action should be taken.
851 * Increment the appropriate counter when the cell was found to go over a
852 * limit. */
853dos_stream_defense_type_t
854dos_stream_new_begin_or_resolve_cell(or_circuit_t *circ)
855{
856 if (!dos_stream_enabled || circ == NULL)
857 return DOS_STREAM_DEFENSE_NONE;
858
860 (uint32_t) monotime_coarse_absolute_sec());
861
862 if (token_bucket_ctr_get(&circ->stream_limiter) > 0) {
863 token_bucket_ctr_dec(&circ->stream_limiter, 1);
864 return DOS_STREAM_DEFENSE_NONE;
865 }
866 /* if defense type is DOS_STREAM_DEFENSE_NONE but DoSStreamEnabled is true,
867 * we count offending cells as rejected, despite them being actually
868 * accepted. */
869 ++stream_num_rejected;
870 return dos_stream_defense_type;
871}
872
873/* Initialize the token bucket for stream rate limit on a circuit. */
874void
875dos_stream_init_circ_tbf(or_circuit_t *circ)
876{
877 token_bucket_ctr_init(&circ->stream_limiter, dos_stream_rate,
878 dos_stream_burst,
879 (uint32_t) monotime_coarse_absolute_sec());
880}
881
882/* General API */
883
884/* Take any appropriate actions for the given geoip entry that is about to get
885 * freed. This is called for every entry that is being freed.
886 *
887 * This function will clear out the connection tracked flag if the concurrent
888 * count of the entry is above 0 so if those connections end up being seen by
889 * this subsystem, we won't try to decrement the counter for a new geoip entry
890 * that might have been added after this call for the same address. */
891void
892dos_geoip_entry_about_to_free(const clientmap_entry_t *geoip_ent)
893{
894 tor_assert(geoip_ent);
895
896 /* The count is down to 0 meaning no connections right now, we can safely
897 * clear the geoip entry from the cache. */
898 if (geoip_ent->dos_stats.conn_stats.concurrent_count == 0) {
899 goto end;
900 }
901
902 /* For each connection matching the geoip entry address, we'll clear the
903 * tracked flag because the entry is about to get removed from the geoip
904 * cache. We do not try to decrement if the flag is not set. */
906 if (conn->type == CONN_TYPE_OR) {
907 or_connection_t *or_conn = TO_OR_CONN(conn);
908 if (!tor_addr_compare(&geoip_ent->addr, &TO_CONN(or_conn)->addr,
909 CMP_EXACT)) {
910 or_conn->tracked_for_dos_mitigation = 0;
911 }
912 }
913 } SMARTLIST_FOREACH_END(conn);
914
915 end:
916 return;
917}
918
919/** A new geoip client entry has been allocated, initialize its DoS object. */
920void
921dos_geoip_entry_init(clientmap_entry_t *geoip_ent)
922{
923 tor_assert(geoip_ent);
924
925 /* Initialize the connection count counter with the rate and burst
926 * parameters taken either from configuration or consensus.
927 *
928 * We do this even if the DoS connection detection is not enabled because it
929 * can be enabled at runtime and these counters need to be valid. */
930 token_bucket_ctr_init(&geoip_ent->dos_stats.conn_stats.connect_count,
931 dos_conn_connect_rate, dos_conn_connect_burst,
932 (uint32_t) monotime_coarse_absolute_sec());
933}
934
935/** Note that the given channel has sent outbound the maximum amount of cell
936 * allowed on the next channel. */
937void
938dos_note_circ_max_outq(const channel_t *chan)
939{
940 tor_addr_t addr;
941 clientmap_entry_t *entry;
942
943 tor_assert(chan);
944
945 /* Skip everything if circuit creation defense is disabled. */
946 if (!dos_cc_enabled) {
947 goto end;
948 }
949
950 /* Must be a client connection else we ignore. */
951 if (!channel_is_client(chan)) {
952 goto end;
953 }
954 /* Without an IP address, nothing can work. */
955 if (!channel_get_addr_if_possible(chan, &addr)) {
956 goto end;
957 }
958
959 /* We are only interested in client connection from the geoip cache. */
960 entry = geoip_lookup_client(&addr, NULL, GEOIP_CLIENT_CONNECT);
961 if (entry == NULL) {
962 goto end;
963 }
964
965 /* Is the client marked? If yes, just ignore. */
966 if (entry->dos_stats.cc_stats.marked_until_ts >= approx_time()) {
967 goto end;
968 }
969
970 /* If max outq parameter is 0, it means disabled, just ignore. */
971 if (dos_num_circ_max_outq == 0) {
972 goto end;
973 }
974
975 entry->dos_stats.num_circ_max_cell_queue_size++;
976
977 /* This is the detection. If we have reached the maximum amount of times a
978 * client IP is allowed to reach this limit, mark client. */
979 if (entry->dos_stats.num_circ_max_cell_queue_size >=
980 dos_num_circ_max_outq) {
981 /* Only account for this marked address if this is the first time we block
982 * it else our counter is inflated with non unique entries. */
983 if (entry->dos_stats.cc_stats.marked_until_ts == 0) {
984 cc_num_marked_addrs_max_queue++;
985 }
986 log_info(LD_DOS, "Detected outbound max circuit queue from addr: %s",
987 fmt_addr(&addr));
988 cc_mark_client(&entry->dos_stats.cc_stats);
989
990 /* Reset after being marked so once unmarked, we start back clean. */
991 entry->dos_stats.num_circ_max_cell_queue_size = 0;
992 }
993
994 end:
995 return;
996}
997
998/* Note down that we've just refused a single hop client. This increments a
999 * counter later used for the heartbeat. */
1000void
1001dos_note_refuse_single_hop_client(void)
1002{
1003 num_single_hop_client_refused++;
1004}
1005
1006/* Return true iff single hop client connection (ESTABLISH_RENDEZVOUS) should
1007 * be refused. */
1008int
1009dos_should_refuse_single_hop_client(void)
1010{
1011 /* If we aren't a public relay, this shouldn't apply to anything. */
1012 if (!public_server_mode(get_options())) {
1013 return 0;
1014 }
1015
1016 if (dos_get_options()->DoSRefuseSingleHopClientRendezvous != -1) {
1017 return dos_get_options()->DoSRefuseSingleHopClientRendezvous;
1018 }
1019
1020 return (int) networkstatus_get_param(NULL,
1021 "DoSRefuseSingleHopClientRendezvous",
1022 0 /* default */, 0, 1);
1023}
1024
1025/* Log a heartbeat message with some statistics. */
1026void
1027dos_log_heartbeat(void)
1028{
1029 smartlist_t *elems = smartlist_new();
1030
1031 /* Stats number coming from relay.c append_cell_to_circuit_queue(). */
1033 "%" PRIu64 " circuits killed with too many cells",
1035
1036 if (dos_cc_enabled) {
1038 "%" PRIu64 " circuits rejected, "
1039 "%" PRIu32 " marked addresses, "
1040 "%" PRIu32 " marked addresses for max queue",
1041 cc_num_rejected_cells, cc_num_marked_addrs,
1042 cc_num_marked_addrs_max_queue);
1043 } else {
1044 smartlist_add_asprintf(elems, "[DoSCircuitCreationEnabled disabled]");
1045 }
1046
1047 if (dos_conn_enabled) {
1049 "%" PRIu64 " same address concurrent "
1050 "connections rejected", conn_num_addr_rejected);
1052 "%" PRIu64 " connections rejected",
1053 conn_num_addr_connect_rejected);
1054 } else {
1055 smartlist_add_asprintf(elems, "[DoSConnectionEnabled disabled]");
1056 }
1057
1058 if (dos_should_refuse_single_hop_client()) {
1060 "%" PRIu64 " single hop clients refused",
1061 num_single_hop_client_refused);
1062 } else {
1064 "[DoSRefuseSingleHopClientRendezvous disabled]");
1065 }
1066
1067 if (dos_stream_enabled) {
1069 "%" PRIu64 " stream rejected",
1070 stream_num_rejected);
1071 } else {
1072 smartlist_add_asprintf(elems, "[DoSStreamCreationEnabled disabled]");
1073 }
1074
1075 /* HS DoS stats. */
1077 "%" PRIu64 " INTRODUCE2 rejected",
1079
1080 char *msg = smartlist_join_strings(elems, ", ", 0, NULL);
1081
1082 log_notice(LD_HEARTBEAT,
1083 "Heartbeat: DoS mitigation since startup: %s.", msg);
1084
1085 tor_free(msg);
1086 SMARTLIST_FOREACH(elems, char *, e, tor_free(e));
1087 smartlist_free(elems);
1088}
1089
1090/* Called when a new client connection has been established on the given
1091 * address. */
1092void
1093dos_new_client_conn(or_connection_t *or_conn, const char *transport_name)
1094{
1095 clientmap_entry_t *entry;
1096
1097 tor_assert(or_conn);
1098 tor_assert_nonfatal(!or_conn->tracked_for_dos_mitigation);
1099
1100 /* Past that point, we know we have at least one DoS detection subsystem
1101 * enabled so we'll start allocating stuff. */
1102 if (!dos_is_enabled()) {
1103 goto end;
1104 }
1105
1106 /* We are only interested in client connection from the geoip cache. */
1107 entry = geoip_lookup_client(&TO_CONN(or_conn)->addr, transport_name,
1109 if (BUG(entry == NULL)) {
1110 /* Should never happen because we note down the address in the geoip
1111 * cache before this is called. */
1112 goto end;
1113 }
1114
1115 /* Update stats from this new connect. */
1116 conn_update_on_connect(&entry->dos_stats.conn_stats,
1117 &TO_CONN(or_conn)->addr);
1118
1119 or_conn->tracked_for_dos_mitigation = 1;
1120
1121 end:
1122 return;
1123}
1124
1125/* Called when a client connection for the given IP address has been closed. */
1126void
1127dos_close_client_conn(const or_connection_t *or_conn)
1128{
1129 clientmap_entry_t *entry;
1130
1131 tor_assert(or_conn);
1132
1133 /* We have to decrement the count on tracked connection only even if the
1134 * subsystem has been disabled at runtime because it might be re-enabled
1135 * after and we need to keep a synchronized counter at all time. */
1136 if (!or_conn->tracked_for_dos_mitigation) {
1137 goto end;
1138 }
1139
1140 /* We are only interested in client connection from the geoip cache. */
1141 entry = geoip_lookup_client(&TO_CONN(or_conn)->addr, NULL,
1143 if (entry == NULL) {
1144 /* This can happen because we can close a connection before the channel
1145 * got to be noted down in the geoip cache. */
1146 goto end;
1147 }
1148
1149 /* Update stats from this new close. */
1150 conn_update_on_close(&entry->dos_stats.conn_stats, &TO_CONN(or_conn)->addr);
1151
1152 end:
1153 return;
1154}
1155
1156/* Called when the consensus has changed. We might have new consensus
1157 * parameters to look at. */
1158void
1159dos_consensus_has_changed(const networkstatus_t *ns)
1160{
1161 /* There are two ways to configure this subsystem, one at startup through
1162 * dos_init() which is called when the options are parsed. And this one
1163 * through the consensus. We don't want to enable any DoS mitigation if we
1164 * aren't a public relay. */
1165 if (!public_server_mode(get_options())) {
1166 return;
1167 }
1168
1169 cc_consensus_has_changed(ns);
1170 conn_consensus_has_changed(ns);
1171
1172 /* We were already enabled or we just became enabled but either way, set the
1173 * consensus parameters for all subsystems. */
1174 set_dos_parameters(ns);
1175}
1176
1177/* Return true iff the DoS mitigation subsystem is enabled. */
1178int
1179dos_enabled(void)
1180{
1181 return dos_is_enabled();
1182}
1183
1184/* Free everything from the Denial of Service subsystem. */
1185void
1186dos_free_all(void)
1187{
1188 /* Free the circuit creation mitigation subsystem. It is safe to do this
1189 * even if it wasn't initialized. */
1190 cc_free_all();
1191
1192 /* Free the connection mitigation subsystem. It is safe to do this even if
1193 * it wasn't initialized. */
1194 conn_free_all();
1195}
1196
1197/* Initialize the Denial of Service subsystem. */
1198void
1199dos_init(void)
1200{
1201 /* To initialize, we only need to get the parameters. */
1202 set_dos_parameters(NULL);
1203}
int tor_addr_compare(const tor_addr_t *addr1, const tor_addr_t *addr2, tor_addr_comparison_t how)
Definition address.c:984
#define fmt_addr(a)
Definition address.h:239
time_t approx_time(void)
Definition approx_time.c:32
int channel_is_client(const channel_t *chan)
Definition channel.c:2917
int channel_get_addr_if_possible(const channel_t *chan, tor_addr_t *addr_out)
Definition channel.c:2859
Header file for channel.c.
Functions and types for monotonic times.
const or_options_t * get_options(void)
Definition config.c:948
Header file for config.c.
Header file for connection.c.
#define CONN_TYPE_OR
Definition connection.h:44
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.
@ GEOIP_CLIENT_CONNECT
Definition geoip_stats.h:24
uint64_t hs_dos_get_intro2_rejected_count(void)
Definition hs_dos.c:219
Header file containing denial of service defenses for the HS subsystem for all versions.
#define LD_DOS
Definition log.h:113
#define LD_HEARTBEAT
Definition log.h:103
smartlist_t * get_connection_array(void)
Definition mainloop.c:443
Header file for mainloop.c.
#define tor_free(p)
Definition malloc.h:56
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.
Header file for nodelist.c.
Master header file for Tor-specific functionality.
#define TO_CONN(c)
Definition or.h:709
OR connection structure.
uint64_t stats_n_circ_max_cell_reached
Definition relay.c:144
Header file for relay.c.
Header file for routermode.c.
void smartlist_add_asprintf(struct smartlist_t *sl, const char *pattern,...)
Definition smartlist.c:36
char * smartlist_join_strings(smartlist_t *sl, const char *join, int terminate, size_t *len_out)
Definition smartlist.c:279
smartlist_t * smartlist_new(void)
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
#define SMARTLIST_FOREACH(sl, type, var, cmd)
Definition geoip_stats.h:82
uint32_t num_circ_max_cell_queue_size
Definition dos.h:63
AUTOBOOL DoSConnectionEnabled
POSINT DoSStreamCreationRate
INT DoSCircuitCreationDefenseType
POSINT DoSCircuitCreationMinConnections
POSINT DoSStreamCreationBurst
INT DoSStreamCreationDefenseType
POSINT DoSCircuitCreationBurst
POSINT DoSConnectionConnectBurst
POSINT DoSConnectionConnectRate
POSINT DoSCircuitCreationRate
INT DoSConnectionDefenseType
AUTOBOOL DoSCircuitCreationEnabled
INTERVAL DoSCircuitCreationDefenseTimePeriod
AUTOBOOL DoSRefuseSingleHopClientRendezvous
INTERVAL DoSConnectionConnectDefenseTimePeriod
POSINT DoSConnectionMaxConcurrentCount
AUTOBOOL DoSStreamCreationEnabled
token_bucket_ctr_t stream_limiter
unsigned int tracked_for_dos_mitigation
#define STATIC
Definition testsupport.h:32
#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_sec)
void token_bucket_ctr_refill(token_bucket_ctr_t *bucket, uint32_t now_ts_sec)
#define tor_assert(expr)
Definition util_bug.h:103