Tor  0.4.4.0-alpha-dev
hs_dos.c
Go to the documentation of this file.
1 /* Copyright (c) 2019-2020, 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  /* Defenses might have been enabled or disabled. */
98  consensus_param_introduce_defense_enabled;
99  /* Adjust the rate/burst value that might have changed. */
100  token_bucket_ctr_adjust(&TO_OR_CIRCUIT(circ)->introduce2_bucket,
101  consensus_param_introduce_rate_per_sec,
102  consensus_param_introduce_burst_per_sec);
103  } SMARTLIST_FOREACH_END(circ);
104 
105  smartlist_free(intro_circs);
106 }
107 
108 /** Set consensus parameters. */
109 static void
111 {
112  consensus_param_introduce_rate_per_sec =
114  consensus_param_introduce_burst_per_sec =
116  consensus_param_introduce_defense_enabled =
117  get_intro2_enable_consensus_param(ns);
118 
119  /* The above might have changed which means we need to go through all
120  * introduction circuits (relay side) and update the token buckets. */
122 }
123 
124 /*
125  * Public API.
126  */
127 
128 /** Initialize the INTRODUCE2 token bucket for the DoS defenses using the
129  * consensus/default values. We might get a cell extension that changes those
130  * later but if we don't, the default or consensus parameters are used. */
131 void
133 {
134  tor_assert(circ);
135 
137  consensus_param_introduce_defense_enabled;
139  consensus_param_introduce_rate_per_sec,
140  consensus_param_introduce_burst_per_sec,
141  (uint32_t) approx_time());
142 }
143 
144 /** Called when the consensus has changed. We might have new consensus
145  * parameters to look at. */
146 void
148 {
149  /* No point on updating these values if we are not a public relay that can
150  * be picked to be an introduction point. */
152  return;
153  }
154 
156 }
157 
158 /** Return true iff an INTRODUCE2 cell can be sent on the given service
159  * introduction circuit. */
160 bool
162 {
163  tor_assert(s_intro_circ);
164 
165  /* Allow to send the cell if the DoS defenses are disabled on the circuit.
166  * This can be set by the consensus, the ESTABLISH_INTRO cell extension or
167  * the hardcoded values in tor code. */
168  if (!s_intro_circ->introduce2_dos_defense_enabled) {
169  goto allow;
170  }
171 
172  /* Should not happen but if so, scream loudly. */
173  if (BUG(TO_CIRCUIT(s_intro_circ)->purpose != CIRCUIT_PURPOSE_INTRO_POINT)) {
174  goto disallow;
175  }
176 
177  /* This is called just after we got a valid and parsed INTRODUCE1 cell. The
178  * service has been found and we have its introduction circuit.
179  *
180  * First, the INTRODUCE2 bucket will be refilled (if any). Then, decremented
181  * because we are about to send or not the cell we just got. Finally,
182  * evaluate if we can send it based on our token bucket state. */
183 
184  /* Refill INTRODUCE2 bucket. */
186  (uint32_t) approx_time());
187 
188  /* Decrement the bucket for this valid INTRODUCE1 cell we just got. Don't
189  * underflow else we end up with a too big of a bucket. */
190  if (token_bucket_ctr_get(&s_intro_circ->introduce2_bucket) > 0) {
191  token_bucket_ctr_dec(&s_intro_circ->introduce2_bucket, 1);
192  }
193 
194  /* Finally, we can send a new INTRODUCE2 if there are still tokens. */
195  if (token_bucket_ctr_get(&s_intro_circ->introduce2_bucket) > 0) {
196  goto allow;
197  }
198 
199  /* Fallthrough is to disallow since this means the bucket has reached 0. */
200  disallow:
201  /* Increment stats counter, we are rejecting the INTRO2 cell. */
203  return false;
204 
205  allow:
206  return true;
207 }
208 
209 /** Return rolling count of rejected INTRO2. */
210 uint64_t
212 {
213  return intro2_rejected_count;
214 }
215 
216 /** Initialize the onion service Denial of Service subsystem. */
217 void
219 {
221 }
Header file containing denial of service defenses for the HS subsystem for all versions.
bool hs_dos_can_send_intro2(or_circuit_t *s_intro_circ)
Definition: hs_dos.c:161
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
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)
void token_bucket_ctr_refill(token_bucket_ctr_t *bucket, uint32_t now_ts)
Definition: token_bucket.c:294
unsigned int introduce2_dos_defense_enabled
Definition: or_circuit_st.h:77
#define TO_CIRCUIT(x)
Definition: or.h:951
Header file for config.c.
const or_options_t * get_options(void)
Definition: config.c:926
#define tor_assert(expr)
Definition: util_bug.h:102
STATIC uint32_t get_intro2_burst_consensus_param(const networkstatus_t *ns)
Definition: hs_dos.c:79
#define STATIC
Definition: testsupport.h:32
smartlist_t * hs_circuitmap_get_all_intro_circ_relay_side(void)
STATIC uint32_t get_intro2_rate_consensus_param(const networkstatus_t *ns)
Definition: hs_dos.c:70
static void set_consensus_parameters(const networkstatus_t *ns)
Definition: hs_dos.c:110
#define HS_DOS_INTRODUCE_ENABLED_DEFAULT
Definition: hs_dos.c:46
Header file for routermode.c.
void token_bucket_ctr_adjust(token_bucket_ctr_t *bucket, uint32_t rate, uint32_t burst)
Definition: token_bucket.c:276
Master header file for Tor-specific functionality.
uint64_t hs_dos_get_intro2_rejected_count(void)
Definition: hs_dos.c:211
void hs_dos_init(void)
Definition: hs_dos.c:218
Headers for token_bucket.c.
Header file for hs_circuitmap.c.
Header file for circuitlist.c.
static uint64_t intro2_rejected_count
Definition: hs_dos.c:49
void hs_dos_consensus_has_changed(const networkstatus_t *ns)
Definition: hs_dos.c:147
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 hs_dos_setup_default_intro2_defenses(or_circuit_t *circ)
Definition: hs_dos.c:132
#define CIRCUIT_PURPOSE_INTRO_POINT
Definition: circuitlist.h:42
or_circuit_t * TO_OR_CIRCUIT(circuit_t *x)
Definition: circuitlist.c:153
time_t approx_time(void)
Definition: approx_time.c:32
static void update_intro_circuits(void)
Definition: hs_dos.c:90
int public_server_mode(const or_options_t *options)
Definition: routermode.c:43
#define HS_DOS_INTRODUCE_DEFAULT_CELL_RATE_PER_SEC
Definition: hs_dos.c:36
#define HS_DOS_INTRODUCE_DEFAULT_CELL_BURST_PER_SEC
Definition: hs_dos.c:42
token_bucket_ctr_t introduce2_bucket
Definition: or_circuit_st.h:82
Header file for networkstatus.c.