Tor  0.4.7.0-alpha-dev
hs_dos.c
Go to the documentation of this file.
1 /* Copyright (c) 2019-2021, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
3 
4 /**
5  * \file hs_dos.c
6  * \brief Implement denial of service mitigation for the onion service
7  * subsystem.
8  *
9  * This module defenses:
10  *
11  * - Introduction Rate Limiting: If enabled by the consensus, an introduction
12  * point will rate limit client introduction towards the service (INTRODUCE2
13  * cells). It uses a token bucket model with a rate and burst per second.
14  *
15  * Proposal 305 will expand this module by allowing an operator to define
16  * these values into the ESTABLISH_INTRO cell. Not yet implemented.
17  **/
18 
19 #define HS_DOS_PRIVATE
20 
21 #include "core/or/or.h"
22 #include "app/config/config.h"
23 
24 #include "core/or/circuitlist.h"
25 
29 
31 
32 #include "feature/hs/hs_dos.h"
33 
34 /** Default value of the allowed INTRODUCE2 cell rate per second. Above that
35  * value per second, the introduction is denied. */
36 #define HS_DOS_INTRODUCE_DEFAULT_CELL_RATE_PER_SEC 25
37 
38 /** Default value of the allowed INTRODUCE2 cell burst per second. This is the
39  * maximum value a token bucket has per second. We thus allow up to this value
40  * of INTRODUCE2 cell per second but the bucket is refilled by the rate value
41  * but never goes above that burst value. */
42 #define HS_DOS_INTRODUCE_DEFAULT_CELL_BURST_PER_SEC 200
43 
44 /** Default value of the consensus parameter enabling or disabling the
45  * introduction DoS defense. Disabled by default. */
46 #define HS_DOS_INTRODUCE_ENABLED_DEFAULT 0
47 
48 /** INTRODUCE2 rejected request counter. */
49 static uint64_t intro2_rejected_count = 0;
50 
51 /* Consensus parameters. The ESTABLISH_INTRO DoS cell extension have higher
52  * priority than these values. If no extension is sent, these are used only by
53  * the introduction point. */
54 static uint32_t consensus_param_introduce_rate_per_sec =
56 static uint32_t consensus_param_introduce_burst_per_sec =
58 static uint32_t consensus_param_introduce_defense_enabled =
60 
61 STATIC uint32_t
62 get_intro2_enable_consensus_param(const networkstatus_t *ns)
63 {
64  return networkstatus_get_param(ns, "HiddenServiceEnableIntroDoSDefense",
66 }
67 
68 /** Return the parameter for the introduction rate per sec. */
69 STATIC uint32_t
71 {
72  return networkstatus_get_param(ns, "HiddenServiceEnableIntroDoSRatePerSec",
74  0, INT32_MAX);
75 }
76 
77 /** Return the parameter for the introduction burst per sec. */
78 STATIC uint32_t
80 {
81  return networkstatus_get_param(ns, "HiddenServiceEnableIntroDoSBurstPerSec",
83  0, INT32_MAX);
84 }
85 
86 /** Go over all introduction circuit relay side and adjust their rate/burst
87  * values using the global parameters. This is called right after the
88  * consensus parameters might have changed. */
89 static void
91 {
92  /* Returns all HS version intro circuits. */
94 
95  SMARTLIST_FOREACH_BEGIN(intro_circs, circuit_t *, circ) {
96  /* Ignore circuit if the defenses were set explicitly through the
97  * ESTABLISH_INTRO cell DoS extension. */
98  if (TO_OR_CIRCUIT(circ)->introduce2_dos_defense_explicit) {
99  continue;
100  }
101  /* Defenses might have been enabled or disabled. */
103  consensus_param_introduce_defense_enabled;
104  /* Adjust the rate/burst value that might have changed. */
105  token_bucket_ctr_adjust(&TO_OR_CIRCUIT(circ)->introduce2_bucket,
106  consensus_param_introduce_rate_per_sec,
107  consensus_param_introduce_burst_per_sec);
108  } SMARTLIST_FOREACH_END(circ);
109 
110  smartlist_free(intro_circs);
111 }
112 
113 /** Set consensus parameters. */
114 static void
116 {
117  consensus_param_introduce_rate_per_sec =
119  consensus_param_introduce_burst_per_sec =
121  consensus_param_introduce_defense_enabled =
122  get_intro2_enable_consensus_param(ns);
123 
124  /* The above might have changed which means we need to go through all
125  * introduction circuits (relay side) and update the token buckets. */
127 }
128 
129 /*
130  * Public API.
131  */
132 
133 /** Initialize the INTRODUCE2 token bucket for the DoS defenses using the
134  * consensus/default values. We might get a cell extension that changes those
135  * later but if we don't, the default or consensus parameters are used. */
136 void
138 {
139  tor_assert(circ);
140 
142  consensus_param_introduce_defense_enabled;
144  consensus_param_introduce_rate_per_sec,
145  consensus_param_introduce_burst_per_sec,
146  (uint32_t) approx_time());
147 }
148 
149 /** Called when the consensus has changed. We might have new consensus
150  * parameters to look at. */
151 void
153 {
154  /* No point on updating these values if we are not a public relay that can
155  * be picked to be an introduction point. */
157  return;
158  }
159 
161 }
162 
163 /** Return true iff an INTRODUCE2 cell can be sent on the given service
164  * introduction circuit. */
165 bool
167 {
168  tor_assert(s_intro_circ);
169 
170  /* Allow to send the cell if the DoS defenses are disabled on the circuit.
171  * This can be set by the consensus, the ESTABLISH_INTRO cell extension or
172  * the hardcoded values in tor code. */
173  if (!s_intro_circ->introduce2_dos_defense_enabled) {
174  goto allow;
175  }
176 
177  /* Should not happen but if so, scream loudly. */
178  if (BUG(TO_CIRCUIT(s_intro_circ)->purpose != CIRCUIT_PURPOSE_INTRO_POINT)) {
179  goto disallow;
180  }
181 
182  /* This is called just after we got a valid and parsed INTRODUCE1 cell. The
183  * service has been found and we have its introduction circuit.
184  *
185  * First, the INTRODUCE2 bucket will be refilled (if any). Then, decremented
186  * because we are about to send or not the cell we just got. Finally,
187  * evaluate if we can send it based on our token bucket state. */
188 
189  /* Refill INTRODUCE2 bucket. */
191  (uint32_t) approx_time());
192 
193  /* Decrement the bucket for this valid INTRODUCE1 cell we just got. Don't
194  * underflow else we end up with a too big of a bucket. */
195  if (token_bucket_ctr_get(&s_intro_circ->introduce2_bucket) > 0) {
196  token_bucket_ctr_dec(&s_intro_circ->introduce2_bucket, 1);
197  }
198 
199  /* Finally, we can send a new INTRODUCE2 if there are still tokens. */
200  if (token_bucket_ctr_get(&s_intro_circ->introduce2_bucket) > 0) {
201  goto allow;
202  }
203 
204  /* If we reach this point, then it means the bucket has reached zero, and
205  we're going to disallow. */
206 
207  disallow:
208  /* Increment stats counter, we are rejecting the INTRO2 cell. */
210  return false;
211 
212  allow:
213  return true;
214 }
215 
216 /** Return rolling count of rejected INTRO2. */
217 uint64_t
219 {
220  return intro2_rejected_count;
221 }
222 
223 /** Initialize the onion service Denial of Service subsystem. */
224 void
226 {
228 }
time_t approx_time(void)
Definition: approx_time.c:32
or_circuit_t * TO_OR_CIRCUIT(circuit_t *x)
Definition: circuitlist.c:154
Header file for circuitlist.c.
#define CIRCUIT_PURPOSE_INTRO_POINT
Definition: circuitlist.h:42
const or_options_t * get_options(void)
Definition: config.c:919
Header file for config.c.
smartlist_t * hs_circuitmap_get_all_intro_circ_relay_side(void)
Header file for hs_circuitmap.c.
static void set_consensus_parameters(const networkstatus_t *ns)
Definition: hs_dos.c:115
bool hs_dos_can_send_intro2(or_circuit_t *s_intro_circ)
Definition: hs_dos.c:166
static uint64_t intro2_rejected_count
Definition: hs_dos.c:49
void hs_dos_init(void)
Definition: hs_dos.c:225
void hs_dos_setup_default_intro2_defenses(or_circuit_t *circ)
Definition: hs_dos.c:137
static void update_intro_circuits(void)
Definition: hs_dos.c:90
uint64_t hs_dos_get_intro2_rejected_count(void)
Definition: hs_dos.c:218
STATIC uint32_t get_intro2_rate_consensus_param(const networkstatus_t *ns)
Definition: hs_dos.c:70
#define HS_DOS_INTRODUCE_DEFAULT_CELL_BURST_PER_SEC
Definition: hs_dos.c:42
void hs_dos_consensus_has_changed(const networkstatus_t *ns)
Definition: hs_dos.c:152
#define HS_DOS_INTRODUCE_DEFAULT_CELL_RATE_PER_SEC
Definition: hs_dos.c:36
STATIC uint32_t get_intro2_burst_consensus_param(const networkstatus_t *ns)
Definition: hs_dos.c:79
#define HS_DOS_INTRODUCE_ENABLED_DEFAULT
Definition: hs_dos.c:46
Header file containing denial of service defenses for the HS subsystem for all versions.
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.
Master header file for Tor-specific functionality.
#define TO_CIRCUIT(x)
Definition: or.h:845
int public_server_mode(const or_options_t *options)
Definition: routermode.c:43
Header file for routermode.c.
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
unsigned int introduce2_dos_defense_enabled
Definition: or_circuit_st.h:83
token_bucket_ctr_t introduce2_bucket
Definition: or_circuit_st.h:92
#define STATIC
Definition: testsupport.h:32
void token_bucket_ctr_init(token_bucket_ctr_t *bucket, uint32_t rate, uint32_t burst, uint32_t now_ts)
Definition: token_bucket.c:265
void token_bucket_ctr_refill(token_bucket_ctr_t *bucket, uint32_t now_ts)
Definition: token_bucket.c:294
void token_bucket_ctr_adjust(token_bucket_ctr_t *bucket, uint32_t rate, uint32_t burst)
Definition: token_bucket.c:276
Headers for token_bucket.c.
#define tor_assert(expr)
Definition: util_bug.h:102