Merge remote-tracking branch 'teor/ticket28318-035' into maint-0.3.5
[tor.git] / src / test / test_dos.c
blob40a4c6ba298fc7584bad05e45c19fc3ffe602bbf
1 /* Copyright (c) 2018, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 #define DOS_PRIVATE
5 #define TOR_CHANNEL_INTERNAL_
6 #define CIRCUITLIST_PRIVATE
8 #include "core/or/or.h"
9 #include "core/or/dos.h"
10 #include "core/or/circuitlist.h"
11 #include "lib/crypt_ops/crypto_rand.h"
12 #include "feature/stats/geoip_stats.h"
13 #include "core/or/channel.h"
14 #include "feature/nodelist/microdesc.h"
15 #include "feature/nodelist/networkstatus.h"
16 #include "feature/nodelist/nodelist.h"
17 #include "feature/nodelist/routerlist.h"
19 #include "feature/nodelist/networkstatus_st.h"
20 #include "core/or/or_connection_st.h"
21 #include "feature/nodelist/routerstatus_st.h"
23 #include "test/test.h"
24 #include "test/log_test_helpers.h"
26 static networkstatus_t *dummy_ns = NULL;
27 static networkstatus_t *
28 mock_networkstatus_get_latest_consensus(void)
30 return dummy_ns;
33 static networkstatus_t *
34 mock_networkstatus_get_latest_consensus_by_flavor(consensus_flavor_t f)
36 tor_assert(f == FLAV_MICRODESC);
37 return dummy_ns;
40 /* Number of address a single node_t can have. Default to the production
41 * value. This is to control the size of the bloom filter. */
42 static int addr_per_node = 2;
43 static int
44 mock_get_estimated_address_per_node(void)
46 return addr_per_node;
49 static unsigned int
50 mock_enable_dos_protection(const networkstatus_t *ns)
52 (void) ns;
53 return 1;
56 /** Test that the connection tracker of the DoS subsystem will block clients
57 * who try to establish too many connections */
58 static void
59 test_dos_conn_creation(void *arg)
61 (void) arg;
63 MOCK(get_param_cc_enabled, mock_enable_dos_protection);
64 MOCK(get_param_conn_enabled, mock_enable_dos_protection);
66 /* Initialize test data */
67 or_connection_t or_conn;
68 time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */
69 tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.real_addr,
70 "18.0.0.1"));
71 tor_addr_t *addr = &or_conn.real_addr;
73 /* Get DoS subsystem limits */
74 dos_init();
75 uint32_t max_concurrent_conns = get_param_conn_max_concurrent_count(NULL);
77 /* Introduce new client */
78 geoip_note_client_seen(GEOIP_CLIENT_CONNECT, addr, NULL, now);
79 { /* Register many conns from this client but not enough to get it blocked */
80 unsigned int i;
81 for (i = 0; i < max_concurrent_conns; i++) {
82 dos_new_client_conn(&or_conn);
86 /* Check that new conns are still permitted */
87 tt_int_op(DOS_CONN_DEFENSE_NONE, OP_EQ,
88 dos_conn_addr_get_defense_type(addr));
90 /* Register another conn and check that new conns are not allowed anymore */
91 dos_new_client_conn(&or_conn);
92 tt_int_op(DOS_CONN_DEFENSE_CLOSE, OP_EQ,
93 dos_conn_addr_get_defense_type(addr));
95 /* Close a client conn and see that a new conn will be permitted again */
96 dos_close_client_conn(&or_conn);
97 tt_int_op(DOS_CONN_DEFENSE_NONE, OP_EQ,
98 dos_conn_addr_get_defense_type(addr));
100 /* Register another conn and see that defense measures get reactivated */
101 dos_new_client_conn(&or_conn);
102 tt_int_op(DOS_CONN_DEFENSE_CLOSE, OP_EQ,
103 dos_conn_addr_get_defense_type(addr));
105 done:
106 dos_free_all();
109 /** Helper mock: Place a fake IP addr for this channel in <b>addr_out</b> */
110 static int
111 mock_channel_get_addr_if_possible(channel_t *chan, tor_addr_t *addr_out)
113 (void)chan;
114 tt_int_op(AF_INET,OP_EQ, tor_addr_parse(addr_out, "18.0.0.1"));
115 return 1;
117 done:
118 return 0;
121 /** Test that the circuit tracker of the DoS subsystem will block clients who
122 * try to establish too many circuits. */
123 static void
124 test_dos_circuit_creation(void *arg)
126 (void) arg;
127 unsigned int i;
129 MOCK(get_param_cc_enabled, mock_enable_dos_protection);
130 MOCK(get_param_conn_enabled, mock_enable_dos_protection);
131 MOCK(channel_get_addr_if_possible,
132 mock_channel_get_addr_if_possible);
134 /* Initialize channels/conns/circs that will be used */
135 channel_t *chan = tor_malloc_zero(sizeof(channel_t));
136 channel_init(chan);
137 chan->is_client = 1;
139 /* Initialize test data */
140 or_connection_t or_conn;
141 time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */
142 tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.real_addr,
143 "18.0.0.1"));
144 tor_addr_t *addr = &or_conn.real_addr;
146 /* Get DoS subsystem limits */
147 dos_init();
148 uint32_t max_circuit_count = get_param_cc_circuit_burst(NULL);
149 uint32_t min_conc_conns_for_cc =
150 get_param_cc_min_concurrent_connection(NULL);
152 /* Introduce new client and establish enough connections to activate the
153 * circuit counting subsystem */
154 geoip_note_client_seen(GEOIP_CLIENT_CONNECT, addr, NULL, now);
155 for (i = 0; i < min_conc_conns_for_cc ; i++) {
156 dos_new_client_conn(&or_conn);
159 /* Register new circuits for this client and conn, but not enough to get
160 * detected as dos */
161 for (i=0; i < max_circuit_count-1; i++) {
162 dos_cc_new_create_cell(chan);
164 /* see that we didn't get detected for dosing */
165 tt_int_op(DOS_CC_DEFENSE_NONE, OP_EQ, dos_cc_get_defense_type(chan));
167 /* Register another CREATE cell that will push us over the limit. Check that
168 * the cell gets refused. */
169 dos_cc_new_create_cell(chan);
170 tt_int_op(DOS_CC_DEFENSE_REFUSE_CELL, OP_EQ, dos_cc_get_defense_type(chan));
172 /* TODO: Wait a few seconds before sending the cell, and check that the
173 buckets got refilled properly. */
174 /* TODO: Actually send a Tor cell (instead of calling the DoS function) and
175 * check that it will get refused */
177 done:
178 tor_free(chan);
179 dos_free_all();
182 /** Test that the DoS subsystem properly refills the circuit token buckets. */
183 static void
184 test_dos_bucket_refill(void *arg)
186 (void) arg;
187 int i;
188 /* For this test, this variable is set to the current circ count of the token
189 * bucket. */
190 uint32_t current_circ_count;
192 MOCK(get_param_cc_enabled, mock_enable_dos_protection);
193 MOCK(get_param_conn_enabled, mock_enable_dos_protection);
194 MOCK(channel_get_addr_if_possible,
195 mock_channel_get_addr_if_possible);
197 time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */
198 update_approx_time(now);
200 /* Initialize channels/conns/circs that will be used */
201 channel_t *chan = tor_malloc_zero(sizeof(channel_t));
202 channel_init(chan);
203 chan->is_client = 1;
204 or_connection_t or_conn;
205 tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.real_addr,
206 "18.0.0.1"));
207 tor_addr_t *addr = &or_conn.real_addr;
209 /* Initialize DoS subsystem and get relevant limits */
210 dos_init();
211 uint32_t max_circuit_count = get_param_cc_circuit_burst(NULL);
212 uint64_t circ_rate = get_circuit_rate_per_second();
213 /* Check that the circuit rate is a positive number and smaller than the max
214 * circuit count */
215 tt_u64_op(circ_rate, OP_GT, 1);
216 tt_u64_op(circ_rate, OP_LT, max_circuit_count);
218 /* Register this client */
219 geoip_note_client_seen(GEOIP_CLIENT_CONNECT, addr, NULL, now);
220 dos_new_client_conn(&or_conn);
222 /* Fetch this client from the geoip cache and get its DoS structs */
223 clientmap_entry_t *entry = geoip_lookup_client(addr, NULL,
224 GEOIP_CLIENT_CONNECT);
225 tt_assert(entry);
226 dos_client_stats_t* dos_stats = &entry->dos_stats;
227 /* Check that the circuit bucket is still uninitialized */
228 tt_uint_op(dos_stats->cc_stats.circuit_bucket, OP_EQ, 0);
230 /* Send a create cell: then check that the circ token bucket got initialized
231 * and one circ was subtracted. */
232 dos_cc_new_create_cell(chan);
233 current_circ_count = max_circuit_count - 1;
234 tt_uint_op(dos_stats->cc_stats.circuit_bucket, OP_EQ, current_circ_count);
236 /* Now send 29 more CREATEs and ensure that the bucket is missing 30
237 * tokens */
238 for (i=0; i < 29; i++) {
239 dos_cc_new_create_cell(chan);
240 current_circ_count--;
242 tt_uint_op(dos_stats->cc_stats.circuit_bucket, OP_EQ, current_circ_count);
244 /* OK! Progress time forward one sec, refill the bucket and check that the
245 * refill happened correctly. */
246 now += 1;
247 update_approx_time(now);
248 cc_stats_refill_bucket(&dos_stats->cc_stats, addr);
249 /* check refill */
250 current_circ_count += circ_rate;
251 tt_uint_op(dos_stats->cc_stats.circuit_bucket, OP_EQ, current_circ_count);
253 /* Now send as many CREATE cells as needed to deplete our token bucket
254 * completely */
255 for (; current_circ_count != 0; current_circ_count--) {
256 dos_cc_new_create_cell(chan);
258 tt_uint_op(current_circ_count, OP_EQ, 0);
259 tt_uint_op(dos_stats->cc_stats.circuit_bucket, OP_EQ, current_circ_count);
261 /* Now progress time a week forward, and check that the token bucket does not
262 * have more than max_circs allowance, even tho we let it simmer for so
263 * long. */
264 now += 604800; /* a week */
265 update_approx_time(now);
266 cc_stats_refill_bucket(&dos_stats->cc_stats, addr);
267 current_circ_count += max_circuit_count;
268 tt_uint_op(dos_stats->cc_stats.circuit_bucket, OP_EQ, current_circ_count);
270 /* Now send as many CREATE cells as needed to deplete our token bucket
271 * completely */
272 for (; current_circ_count != 0; current_circ_count--) {
273 dos_cc_new_create_cell(chan);
275 tt_uint_op(current_circ_count, OP_EQ, 0);
276 tt_uint_op(dos_stats->cc_stats.circuit_bucket, OP_EQ, current_circ_count);
278 /* Now use a very large time, and check that the token bucket does not have
279 * more than max_circs allowance, even tho we let it simmer for so long. */
280 now = INT32_MAX; /* 2038? */
281 update_approx_time(now);
282 cc_stats_refill_bucket(&dos_stats->cc_stats, addr);
283 current_circ_count += max_circuit_count;
284 tt_uint_op(dos_stats->cc_stats.circuit_bucket, OP_EQ, current_circ_count);
286 /* Now send as many CREATE cells as needed to deplete our token bucket
287 * completely */
288 for (; current_circ_count != 0; current_circ_count--) {
289 dos_cc_new_create_cell(chan);
291 tt_uint_op(current_circ_count, OP_EQ, 0);
292 tt_uint_op(dos_stats->cc_stats.circuit_bucket, OP_EQ, current_circ_count);
294 /* Now use a very small time, and check that the token bucket has exactly
295 * the max_circs allowance, because backward clock jumps are rare. */
296 now = INT32_MIN; /* 19?? */
297 update_approx_time(now);
298 cc_stats_refill_bucket(&dos_stats->cc_stats, addr);
299 current_circ_count += max_circuit_count;
300 tt_uint_op(dos_stats->cc_stats.circuit_bucket, OP_EQ, current_circ_count);
302 /* Now send as many CREATE cells as needed to deplete our token bucket
303 * completely */
304 for (; current_circ_count != 0; current_circ_count--) {
305 dos_cc_new_create_cell(chan);
307 tt_uint_op(current_circ_count, OP_EQ, 0);
308 tt_uint_op(dos_stats->cc_stats.circuit_bucket, OP_EQ, current_circ_count);
310 /* Progress time forward one sec again, refill the bucket and check that the
311 * refill happened correctly. */
312 now += 1;
313 update_approx_time(now);
314 cc_stats_refill_bucket(&dos_stats->cc_stats, addr);
315 /* check refill */
316 current_circ_count += circ_rate;
317 tt_uint_op(dos_stats->cc_stats.circuit_bucket, OP_EQ, current_circ_count);
319 /* Now send as many CREATE cells as needed to deplete our token bucket
320 * completely */
321 for (; current_circ_count != 0; current_circ_count--) {
322 dos_cc_new_create_cell(chan);
324 tt_uint_op(current_circ_count, OP_EQ, 0);
325 tt_uint_op(dos_stats->cc_stats.circuit_bucket, OP_EQ, current_circ_count);
327 /* Now use a very large time (again), and check that the token bucket does
328 * not have more than max_circs allowance, even tho we let it simmer for so
329 * long. */
330 now = INT32_MAX; /* 2038? */
331 update_approx_time(now);
332 cc_stats_refill_bucket(&dos_stats->cc_stats, addr);
333 current_circ_count += max_circuit_count;
334 tt_uint_op(dos_stats->cc_stats.circuit_bucket, OP_EQ, current_circ_count);
336 /* Now send as many CREATE cells as needed to deplete our token bucket
337 * completely */
338 for (; current_circ_count != 0; current_circ_count--) {
339 dos_cc_new_create_cell(chan);
341 tt_uint_op(current_circ_count, OP_EQ, 0);
342 tt_uint_op(dos_stats->cc_stats.circuit_bucket, OP_EQ, current_circ_count);
344 /* This code resets the time to zero with 32-bit time_t, which triggers the
345 * code that initialises the bucket. */
346 #if SIZEOF_TIME_T == 8
347 /* Now use a very very small time, and check that the token bucket has
348 * exactly the max_circs allowance, because backward clock jumps are rare.
350 now = (time_t)INT64_MIN; /* ???? */
351 update_approx_time(now);
352 cc_stats_refill_bucket(&dos_stats->cc_stats, addr);
353 current_circ_count += max_circuit_count;
354 tt_uint_op(dos_stats->cc_stats.circuit_bucket, OP_EQ, current_circ_count);
356 /* Now send as many CREATE cells as needed to deplete our token bucket
357 * completely */
358 for (; current_circ_count != 0; current_circ_count--) {
359 dos_cc_new_create_cell(chan);
361 tt_uint_op(current_circ_count, OP_EQ, 0);
362 tt_uint_op(dos_stats->cc_stats.circuit_bucket, OP_EQ, current_circ_count);
364 /* Progress time forward one sec again, refill the bucket and check that the
365 * refill happened correctly. */
366 now += 1;
367 update_approx_time(now);
368 cc_stats_refill_bucket(&dos_stats->cc_stats, addr);
369 /* check refill */
370 current_circ_count += circ_rate;
371 tt_uint_op(dos_stats->cc_stats.circuit_bucket, OP_EQ, current_circ_count);
373 /* Now send as many CREATE cells as needed to deplete our token bucket
374 * completely */
375 for (; current_circ_count != 0; current_circ_count--) {
376 dos_cc_new_create_cell(chan);
378 tt_uint_op(current_circ_count, OP_EQ, 0);
379 tt_uint_op(dos_stats->cc_stats.circuit_bucket, OP_EQ, current_circ_count);
381 /* Now use a very very small time, and check that the token bucket has
382 * exactly the max_circs allowance, because backward clock jumps are rare.
384 now = (time_t)INT64_MIN; /* ???? */
385 update_approx_time(now);
386 cc_stats_refill_bucket(&dos_stats->cc_stats, addr);
387 current_circ_count += max_circuit_count;
388 tt_uint_op(dos_stats->cc_stats.circuit_bucket, OP_EQ, current_circ_count);
390 /* Now send as many CREATE cells as needed to deplete our token bucket
391 * completely */
392 for (; current_circ_count != 0; current_circ_count--) {
393 dos_cc_new_create_cell(chan);
395 tt_uint_op(current_circ_count, OP_EQ, 0);
396 tt_uint_op(dos_stats->cc_stats.circuit_bucket, OP_EQ, current_circ_count);
398 /* Now use a very very large time, and check that the token bucket does not
399 * have more than max_circs allowance, even tho we let it simmer for so
400 * long. */
401 now = (time_t)INT64_MAX; /* ???? */
402 update_approx_time(now);
403 cc_stats_refill_bucket(&dos_stats->cc_stats, addr);
404 current_circ_count += max_circuit_count;
405 tt_uint_op(dos_stats->cc_stats.circuit_bucket, OP_EQ, current_circ_count);
407 /* Now send as many CREATE cells as needed to deplete our token bucket
408 * completely */
409 for (; current_circ_count != 0; current_circ_count--) {
410 dos_cc_new_create_cell(chan);
412 tt_uint_op(current_circ_count, OP_EQ, 0);
413 tt_uint_op(dos_stats->cc_stats.circuit_bucket, OP_EQ, current_circ_count);
414 #endif
416 done:
417 tor_free(chan);
418 dos_free_all();
421 /* Test if we avoid counting a known relay. */
422 static void
423 test_known_relay(void *arg)
425 clientmap_entry_t *entry = NULL;
426 routerstatus_t *rs = NULL; microdesc_t *md = NULL; routerinfo_t *ri = NULL;
428 (void) arg;
430 MOCK(networkstatus_get_latest_consensus,
431 mock_networkstatus_get_latest_consensus);
432 MOCK(networkstatus_get_latest_consensus_by_flavor,
433 mock_networkstatus_get_latest_consensus_by_flavor);
434 MOCK(get_estimated_address_per_node,
435 mock_get_estimated_address_per_node);
436 MOCK(get_param_cc_enabled, mock_enable_dos_protection);
438 dos_init();
440 dummy_ns = tor_malloc_zero(sizeof(*dummy_ns));
441 dummy_ns->flavor = FLAV_MICRODESC;
442 dummy_ns->routerstatus_list = smartlist_new();
444 /* Setup an OR conn so we can pass it to the DoS subsystem. */
445 or_connection_t or_conn;
446 tor_addr_parse(&or_conn.real_addr, "42.42.42.42");
448 rs = tor_malloc_zero(sizeof(*rs));
449 rs->addr = tor_addr_to_ipv4h(&or_conn.real_addr);
450 crypto_rand(rs->identity_digest, sizeof(rs->identity_digest));
451 smartlist_add(dummy_ns->routerstatus_list, rs);
453 /* This will make the nodelist bloom filter very large
454 * (the_nodelist->node_addrs) so we will fail the contain test rarely. */
455 addr_per_node = 1024;
456 nodelist_set_consensus(dummy_ns);
458 /* We have now a node in our list so we'll make sure we don't count it as a
459 * client connection. */
460 geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &or_conn.real_addr, NULL, 0);
461 /* Suppose we have 5 connections in rapid succession, the counter should
462 * always be 0 because we should ignore this. */
463 dos_new_client_conn(&or_conn);
464 dos_new_client_conn(&or_conn);
465 dos_new_client_conn(&or_conn);
466 dos_new_client_conn(&or_conn);
467 dos_new_client_conn(&or_conn);
468 entry = geoip_lookup_client(&or_conn.real_addr, NULL, GEOIP_CLIENT_CONNECT);
469 tt_assert(entry);
470 /* We should have a count of 0. */
471 tt_uint_op(entry->dos_stats.concurrent_count, OP_EQ, 0);
473 /* To make sure that his is working properly, make a unknown client
474 * connection and see if we do get it. */
475 tor_addr_parse(&or_conn.real_addr, "42.42.42.43");
476 geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &or_conn.real_addr, NULL, 0);
477 dos_new_client_conn(&or_conn);
478 dos_new_client_conn(&or_conn);
479 entry = geoip_lookup_client(&or_conn.real_addr, NULL, GEOIP_CLIENT_CONNECT);
480 tt_assert(entry);
481 /* We should have a count of 2. */
482 tt_uint_op(entry->dos_stats.concurrent_count, OP_EQ, 2);
484 done:
485 routerstatus_free(rs); routerinfo_free(ri); microdesc_free(md);
486 smartlist_clear(dummy_ns->routerstatus_list);
487 networkstatus_vote_free(dummy_ns);
488 dos_free_all();
489 UNMOCK(networkstatus_get_latest_consensus);
490 UNMOCK(networkstatus_get_latest_consensus_by_flavor);
491 UNMOCK(get_estimated_address_per_node);
492 UNMOCK(get_param_cc_enabled);
495 struct testcase_t dos_tests[] = {
496 { "conn_creation", test_dos_conn_creation, TT_FORK, NULL, NULL },
497 { "circuit_creation", test_dos_circuit_creation, TT_FORK, NULL, NULL },
498 { "bucket_refill", test_dos_bucket_refill, TT_FORK, NULL, NULL },
499 { "known_relay" , test_known_relay, TT_FORK,
500 NULL, NULL },
501 END_OF_TESTCASES