tor  0.4.2.1-alpha-dev
hs_dos.c
Go to the documentation of this file.
1 /* Copyright (c) 2019, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
3 
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 /* Consensus parameters. The ESTABLISH_INTRO DoS cell extension have higher
49  * priority than these values. If no extension is sent, these are used only by
50  * the introduction point. */
51 static uint32_t consensus_param_introduce_rate_per_sec =
52  HS_DOS_INTRODUCE_DEFAULT_CELL_RATE_PER_SEC;
53 static uint32_t consensus_param_introduce_burst_per_sec =
54  HS_DOS_INTRODUCE_DEFAULT_CELL_BURST_PER_SEC;
55 static uint32_t consensus_param_introduce_defense_enabled =
56  HS_DOS_INTRODUCE_ENABLED_DEFAULT;
57 
58 STATIC uint32_t
59 get_intro2_enable_consensus_param(const networkstatus_t *ns)
60 {
61  return networkstatus_get_param(ns, "HiddenServiceEnableIntroDoSDefense",
62  HS_DOS_INTRODUCE_ENABLED_DEFAULT, 0, 1);
63 }
64 
65 /* Return the parameter for the introduction rate per sec. */
66 STATIC uint32_t
67 get_intro2_rate_consensus_param(const networkstatus_t *ns)
68 {
69  return networkstatus_get_param(ns, "HiddenServiceEnableIntroDoSRatePerSec",
70  HS_DOS_INTRODUCE_DEFAULT_CELL_RATE_PER_SEC,
71  0, INT32_MAX);
72 }
73 
74 /* Return the parameter for the introduction burst per sec. */
75 STATIC uint32_t
76 get_intro2_burst_consensus_param(const networkstatus_t *ns)
77 {
78  return networkstatus_get_param(ns, "HiddenServiceEnableIntroDoSBurstPerSec",
79  HS_DOS_INTRODUCE_DEFAULT_CELL_BURST_PER_SEC,
80  0, INT32_MAX);
81 }
82 
83 /* Go over all introduction circuit relay side and adjust their rate/burst
84  * values using the global parameters. This is called right after the
85  * consensus parameters might have changed. */
86 static void
87 update_intro_circuits(void)
88 {
89  /* Returns all HS version intro circuits. */
90  smartlist_t *intro_circs = hs_circuitmap_get_all_intro_circ_relay_side();
91 
92  SMARTLIST_FOREACH_BEGIN(intro_circs, circuit_t *, circ) {
93  /* Defenses might have been enabled or disabled. */
95  consensus_param_introduce_defense_enabled;
96  /* Adjust the rate/burst value that might have changed. */
97  token_bucket_ctr_adjust(&TO_OR_CIRCUIT(circ)->introduce2_bucket,
98  consensus_param_introduce_rate_per_sec,
99  consensus_param_introduce_burst_per_sec);
100  } SMARTLIST_FOREACH_END(circ);
101 
102  smartlist_free(intro_circs);
103 }
104 
105 /* Set consensus parameters. */
106 static void
107 set_consensus_parameters(const networkstatus_t *ns)
108 {
109  consensus_param_introduce_rate_per_sec =
110  get_intro2_rate_consensus_param(ns);
111  consensus_param_introduce_burst_per_sec =
112  get_intro2_burst_consensus_param(ns);
113  consensus_param_introduce_defense_enabled =
114  get_intro2_enable_consensus_param(ns);
115 
116  /* The above might have changed which means we need to go through all
117  * introduction circuits (relay side) and update the token buckets. */
118  update_intro_circuits();
119 }
120 
121 /*
122  * Public API.
123  */
124 
125 /* Initialize the INTRODUCE2 token bucket for the DoS defenses using the
126  * consensus/default values. We might get a cell extension that changes those
127  * later but if we don't, the default or consensus parameters are used. */
128 void
129 hs_dos_setup_default_intro2_defenses(or_circuit_t *circ)
130 {
131  tor_assert(circ);
132 
134  consensus_param_introduce_defense_enabled;
136  consensus_param_introduce_rate_per_sec,
137  consensus_param_introduce_burst_per_sec,
138  (uint32_t) approx_time());
139 }
140 
141 /* Called when the consensus has changed. We might have new consensus
142  * parameters to look at. */
143 void
144 hs_dos_consensus_has_changed(const networkstatus_t *ns)
145 {
146  /* No point on updating these values if we are not a public relay that can
147  * be picked to be an introduction point. */
148  if (!public_server_mode(get_options())) {
149  return;
150  }
151 
152  set_consensus_parameters(ns);
153 }
154 
155 /* Return true iff an INTRODUCE2 cell can be sent on the given service
156  * introduction circuit. */
157 bool
158 hs_dos_can_send_intro2(or_circuit_t *s_intro_circ)
159 {
160  tor_assert(s_intro_circ);
161 
162  /* Allow to send the cell if the DoS defenses are disabled on the circuit.
163  * This can be set by the consensus, the ESTABLISH_INTRO cell extension or
164  * the hardcoded values in tor code. */
165  if (!s_intro_circ->introduce2_dos_defense_enabled) {
166  return true;
167  }
168 
169  /* Should not happen but if so, scream loudly. */
170  if (BUG(TO_CIRCUIT(s_intro_circ)->purpose != CIRCUIT_PURPOSE_INTRO_POINT)) {
171  return false;
172  }
173 
174  /* This is called just after we got a valid and parsed INTRODUCE1 cell. The
175  * service has been found and we have its introduction circuit.
176  *
177  * First, the INTRODUCE2 bucket will be refilled (if any). Then, decremented
178  * because we are about to send or not the cell we just got. Finally,
179  * evaluate if we can send it based on our token bucket state. */
180 
181  /* Refill INTRODUCE2 bucket. */
183  (uint32_t) approx_time());
184 
185  /* Decrement the bucket for this valid INTRODUCE1 cell we just got. Don't
186  * underflow else we end up with a too big of a bucket. */
187  if (token_bucket_ctr_get(&s_intro_circ->introduce2_bucket) > 0) {
188  token_bucket_ctr_dec(&s_intro_circ->introduce2_bucket, 1);
189  }
190 
191  /* Finally, we can send a new INTRODUCE2 if there are still tokens. */
192  return token_bucket_ctr_get(&s_intro_circ->introduce2_bucket) > 0;
193 }
194 
195 /* Initialize the onion service Denial of Service subsystem. */
196 void
197 hs_dos_init(void)
198 {
199  set_consensus_parameters(NULL);
200 }
Header file containing denial of service defenses for the HS subsystem for all versions.
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
void token_bucket_ctr_refill(token_bucket_ctr_t *bucket, uint32_t now_ts)
Definition: token_bucket.c:294
#define TO_CIRCUIT(x)
Definition: or.h:951
Header file for config.c.
tor_assert(buffer)
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.
Headers for token_bucket.c.
unsigned int introduce2_dos_defense_enabled
Definition: or_circuit_st.h:77
Header file for hs_circuitmap.c.
Header file for circuitlist.c.
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
#define CIRCUIT_PURPOSE_INTRO_POINT
Definition: circuitlist.h:41
or_circuit_t * TO_OR_CIRCUIT(circuit_t *x)
Definition: circuitlist.c:151
time_t approx_time(void)
Definition: approx_time.c:32
token_bucket_ctr_t introduce2_bucket
Definition: or_circuit_st.h:82
Header file for networkstatus.c.