1 /* Copyright (c) 2017-2019, The Tor Project, Inc. */
2 /* Copyright (c) 2017, isis agora lovecruft */
3 /* See LICENSE for licensing information */
7 * \brief Unittests for code in router.c
10 #define CONFIG_PRIVATE
11 #define ROUTER_PRIVATE
13 #include "core/or/or.h"
14 #include "app/config/config.h"
15 #include "core/mainloop/mainloop.h"
16 #include "feature/hibernate/hibernate.h"
17 #include "feature/nodelist/networkstatus.h"
18 #include "feature/nodelist/networkstatus_st.h"
19 #include "feature/nodelist/node_st.h"
20 #include "feature/nodelist/nodelist.h"
21 #include "feature/nodelist/routerinfo_st.h"
22 #include "feature/nodelist/routerlist.h"
23 #include "feature/nodelist/routerstatus_st.h"
24 #include "feature/relay/router.h"
25 #include "feature/stats/rephist.h"
26 #include "lib/crypt_ops/crypto_curve25519.h"
27 #include "lib/crypt_ops/crypto_ed25519.h"
28 #include "lib/encoding/confline.h"
30 /* Test suite stuff */
31 #include "test/test.h"
32 #include "test/log_test_helpers.h"
34 NS_DECL(const routerinfo_t
*, router_get_my_routerinfo
, (void));
36 static routerinfo_t
* mock_routerinfo
;
38 static const routerinfo_t
*
39 NS(router_get_my_routerinfo
)(void)
41 crypto_pk_t
* ident_key
;
45 if (!mock_routerinfo
) {
46 /* Mock the published timestamp, otherwise router_dump_router_to_string()
47 * will poop its pants. */
50 /* We'll need keys, or router_dump_router_to_string() would return NULL. */
51 ident_key
= pk_generate(0);
52 tap_key
= pk_generate(0);
54 tor_assert(ident_key
!= NULL
);
55 tor_assert(tap_key
!= NULL
);
57 mock_routerinfo
= tor_malloc_zero(sizeof(routerinfo_t
));
58 mock_routerinfo
->nickname
= tor_strdup("ConlonNancarrow");
59 mock_routerinfo
->addr
= 123456789;
60 mock_routerinfo
->or_port
= 443;
61 mock_routerinfo
->platform
= tor_strdup("unittest");
62 mock_routerinfo
->cache_info
.published_on
= now
;
63 mock_routerinfo
->identity_pkey
= crypto_pk_dup_key(ident_key
);
64 router_set_rsa_onion_pkey(tap_key
, &mock_routerinfo
->onion_pkey
,
65 &mock_routerinfo
->onion_pkey_len
);
66 mock_routerinfo
->bandwidthrate
= 9001;
67 mock_routerinfo
->bandwidthburst
= 9002;
68 crypto_pk_free(ident_key
);
69 crypto_pk_free(tap_key
);
72 return mock_routerinfo
;
75 /* If no distribution option was set, then check_bridge_distribution_setting()
76 * should have set it to "any". */
78 test_router_dump_router_to_string_no_bridge_distribution_method(void *arg
)
80 const char* needle
= "bridge-distribution-request any";
81 or_options_t
* options
= get_options_mutable();
82 routerinfo_t
* router
= NULL
;
83 curve25519_keypair_t ntor_keypair
;
84 ed25519_keypair_t signing_keypair
;
89 NS_MOCK(router_get_my_routerinfo
);
91 options
->ORPort_set
= 1;
92 options
->BridgeRelay
= 1;
94 /* Generate keys which router_dump_router_to_string() expects to exist. */
95 tt_int_op(0, ==, curve25519_keypair_generate(&ntor_keypair
, 0));
96 tt_int_op(0, ==, ed25519_keypair_generate(&signing_keypair
, 0));
98 /* Set up part of our routerinfo_t so that we don't trigger any other
99 * assertions in router_dump_router_to_string(). */
100 router
= (routerinfo_t
*)router_get_my_routerinfo();
101 tt_ptr_op(router
, !=, NULL
);
103 /* The real router_get_my_routerinfo() looks up onion_curve25519_pkey using
104 * get_current_curve25519_keypair(), but we don't initialise static data in
106 router
->onion_curve25519_pkey
= &ntor_keypair
.pubkey
;
108 /* Generate our server descriptor and ensure that the substring
109 * "bridge-distribution-request any" occurs somewhere within it. */
110 crypto_pk_t
*onion_pkey
= router_get_rsa_onion_pkey(router
->onion_pkey
,
111 router
->onion_pkey_len
);
112 desc
= router_dump_router_to_string(router
,
113 router
->identity_pkey
,
117 crypto_pk_free(onion_pkey
);
118 tt_ptr_op(desc
, !=, NULL
);
119 found
= strstr(desc
, needle
);
120 tt_ptr_op(found
, !=, NULL
);
123 NS_UNMOCK(router_get_my_routerinfo
);
128 static routerinfo_t
*mock_router_get_my_routerinfo_result
= NULL
;
130 static const routerinfo_t
*
131 mock_router_get_my_routerinfo(void)
133 return mock_router_get_my_routerinfo_result
;
137 mock_get_uptime_3h(void)
143 mock_get_uptime_1d(void)
149 mock_rep_hist_bandwidth_assess(void)
155 mock_we_are_not_hibernating(void)
161 mock_we_are_hibernating(void)
167 test_router_check_descriptor_bandwidth_changed(void *arg
)
170 routerinfo_t routerinfo
;
171 memset(&routerinfo
, 0, sizeof(routerinfo
));
172 mock_router_get_my_routerinfo_result
= NULL
;
174 MOCK(we_are_hibernating
, mock_we_are_not_hibernating
);
175 MOCK(router_get_my_routerinfo
, mock_router_get_my_routerinfo
);
176 mock_router_get_my_routerinfo_result
= &routerinfo
;
178 /* When uptime is less than 24h, no previous bandwidth, no last_changed
179 * Uptime: 10800, last_changed: 0, Previous bw: 0, Current bw: 0 */
180 routerinfo
.bandwidthcapacity
= 0;
181 MOCK(get_uptime
, mock_get_uptime_3h
);
182 setup_full_capture_of_logs(LOG_INFO
);
183 check_descriptor_bandwidth_changed(time(NULL
));
184 expect_log_msg_not_containing(
185 "Measured bandwidth has changed; rebuilding descriptor.");
186 teardown_capture_of_logs();
188 /* When uptime is less than 24h, previous bandwidth,
189 * last_changed more than 3h ago
190 * Uptime: 10800, last_changed: 0, Previous bw: 10000, Current bw: 0 */
191 routerinfo
.bandwidthcapacity
= 10000;
192 setup_full_capture_of_logs(LOG_INFO
);
193 check_descriptor_bandwidth_changed(time(NULL
));
194 expect_log_msg_containing(
195 "Measured bandwidth has changed; rebuilding descriptor.");
196 teardown_capture_of_logs();
198 /* When uptime is less than 24h, previous bandwidth,
199 * last_changed more than 3h ago, and hibernating
200 * Uptime: 10800, last_changed: 0, Previous bw: 10000, Current bw: 0 */
202 UNMOCK(we_are_hibernating
);
203 MOCK(we_are_hibernating
, mock_we_are_hibernating
);
204 routerinfo
.bandwidthcapacity
= 10000;
205 setup_full_capture_of_logs(LOG_INFO
);
206 check_descriptor_bandwidth_changed(time(NULL
));
207 expect_log_msg_not_containing(
208 "Measured bandwidth has changed; rebuilding descriptor.");
209 teardown_capture_of_logs();
210 UNMOCK(we_are_hibernating
);
211 MOCK(we_are_hibernating
, mock_we_are_not_hibernating
);
213 /* When uptime is less than 24h, last_changed is not more than 3h ago
214 * Uptime: 10800, last_changed: x, Previous bw: 10000, Current bw: 0 */
215 setup_full_capture_of_logs(LOG_INFO
);
216 check_descriptor_bandwidth_changed(time(NULL
));
217 expect_log_msg_not_containing(
218 "Measured bandwidth has changed; rebuilding descriptor.");
219 teardown_capture_of_logs();
221 /* When uptime is less than 24h and bandwidthcapacity does not change
222 * Uptime: 10800, last_changed: x, Previous bw: 10000, Current bw: 20001 */
223 MOCK(rep_hist_bandwidth_assess
, mock_rep_hist_bandwidth_assess
);
224 setup_full_capture_of_logs(LOG_INFO
);
225 check_descriptor_bandwidth_changed(time(NULL
) + 6*60*60 + 1);
226 expect_log_msg_containing(
227 "Measured bandwidth has changed; rebuilding descriptor.");
229 UNMOCK(rep_hist_bandwidth_assess
);
230 teardown_capture_of_logs();
232 /* When uptime is more than 24h */
233 MOCK(get_uptime
, mock_get_uptime_1d
);
234 setup_full_capture_of_logs(LOG_INFO
);
235 check_descriptor_bandwidth_changed(time(NULL
));
236 expect_log_msg_not_containing(
237 "Measured bandwidth has changed; rebuilding descriptor.");
238 teardown_capture_of_logs();
242 UNMOCK(router_get_my_routerinfo
);
243 UNMOCK(we_are_hibernating
);
246 static networkstatus_t
*mock_ns
= NULL
;
247 static networkstatus_t
*
248 mock_networkstatus_get_live_consensus(time_t now
)
254 static routerstatus_t
*mock_rs
= NULL
;
255 static const routerstatus_t
*
256 mock_networkstatus_vote_find_entry(networkstatus_t
*ns
, const char *digest
)
264 test_router_mark_if_too_old(void *arg
)
267 time_t now
= approx_time();
268 MOCK(networkstatus_get_live_consensus
,
269 mock_networkstatus_get_live_consensus
);
270 MOCK(networkstatus_vote_find_entry
, mock_networkstatus_vote_find_entry
);
274 memset(&rs
, 0, sizeof(rs
));
275 memset(&ns
, 0, sizeof(ns
));
277 mock_ns
->valid_after
= now
-3600;
279 mock_rs
->published_on
= now
- 10;
281 // no reason to mark this time.
282 desc_clean_since
= now
-10;
283 desc_dirty_reason
= NULL
;
284 mark_my_descriptor_dirty_if_too_old(now
);
285 tt_i64_op(desc_clean_since
, OP_EQ
, now
-10);
287 // Doesn't appear in consensus? Still don't mark it.
289 mark_my_descriptor_dirty_if_too_old(now
);
290 tt_i64_op(desc_clean_since
, OP_EQ
, now
-10);
293 // No new descriptor in a long time? Mark it.
294 desc_clean_since
= now
- 3600 * 96;
295 mark_my_descriptor_dirty_if_too_old(now
);
296 tt_i64_op(desc_clean_since
, OP_EQ
, 0);
297 tt_str_op(desc_dirty_reason
, OP_EQ
, "time for new descriptor");
299 // Version in consensus published a long time ago? We won't mark it
300 // if it's been clean for only a short time.
301 desc_clean_since
= now
- 10;
302 desc_dirty_reason
= NULL
;
303 mock_rs
->published_on
= now
- 3600 * 96;
304 mark_my_descriptor_dirty_if_too_old(now
);
305 tt_i64_op(desc_clean_since
, OP_EQ
, now
- 10);
307 // ... but if it's been clean a while, we mark.
308 desc_clean_since
= now
- 2 * 3600;
309 mark_my_descriptor_dirty_if_too_old(now
);
310 tt_i64_op(desc_clean_since
, OP_EQ
, 0);
311 tt_str_op(desc_dirty_reason
, OP_EQ
,
312 "version listed in consensus is quite old");
314 // same deal if we're marked stale.
315 desc_clean_since
= now
- 2 * 3600;
316 desc_dirty_reason
= NULL
;
317 mock_rs
->published_on
= now
- 10;
318 mock_rs
->is_staledesc
= 1;
319 mark_my_descriptor_dirty_if_too_old(now
);
320 tt_i64_op(desc_clean_since
, OP_EQ
, 0);
321 tt_str_op(desc_dirty_reason
, OP_EQ
,
322 "listed as stale in consensus");
324 // same deal if we're absent from the consensus.
325 desc_clean_since
= now
- 2 * 3600;
326 desc_dirty_reason
= NULL
;
328 mark_my_descriptor_dirty_if_too_old(now
);
329 tt_i64_op(desc_clean_since
, OP_EQ
, 0);
330 tt_str_op(desc_dirty_reason
, OP_EQ
,
331 "not listed in consensus");
334 UNMOCK(networkstatus_get_live_consensus
);
335 UNMOCK(networkstatus_vote_find_entry
);
338 static node_t fake_node
;
339 static const node_t
*
340 mock_node_get_by_nickname(const char *name
, unsigned flags
)
343 if (!strcasecmp(name
, "crumpet"))
350 test_router_get_my_family(void *arg
)
353 or_options_t
*options
= options_new();
354 smartlist_t
*sl
= NULL
;
356 // Overwrite the result of router_get_my_identity_digest(). This
357 // happens to be okay, but only for testing.
358 set_server_identity_key_digest_testing(
359 (const uint8_t*)"holeinthebottomofthe");
361 setup_capture_of_logs(LOG_WARN
);
363 // No family listed -- so there's no list.
364 sl
= get_my_declared_family(options
);
365 tt_ptr_op(sl
, OP_EQ
, NULL
);
366 expect_no_log_entry();
368 #define CLEAR() do { \
370 SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); \
371 smartlist_free(sl); \
374 mock_clean_saved_logs(); \
377 // Add a single nice friendly hex member. This should be enough
378 // to have our own ID added.
379 tt_ptr_op(options
->MyFamily
, OP_EQ
, NULL
);
380 config_line_append(&options
->MyFamily
, "MyFamily",
381 "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
383 sl
= get_my_declared_family(options
);
384 tt_ptr_op(sl
, OP_NE
, NULL
);
385 tt_int_op(smartlist_len(sl
), OP_EQ
, 2);
386 join
= smartlist_join_strings(sl
, " ", 0, NULL
);
387 tt_str_op(join
, OP_EQ
,
388 "$686F6C65696E746865626F74746F6D6F66746865 "
389 "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
390 expect_no_log_entry();
393 // Add a hex member with a ~. The ~ part should get removed.
394 config_line_append(&options
->MyFamily
, "MyFamily",
395 "$0123456789abcdef0123456789abcdef01234567~Muffin");
396 sl
= get_my_declared_family(options
);
397 tt_ptr_op(sl
, OP_NE
, NULL
);
398 tt_int_op(smartlist_len(sl
), OP_EQ
, 3);
399 join
= smartlist_join_strings(sl
, " ", 0, NULL
);
400 tt_str_op(join
, OP_EQ
,
401 "$0123456789ABCDEF0123456789ABCDEF01234567 "
402 "$686F6C65696E746865626F74746F6D6F66746865 "
403 "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
404 expect_no_log_entry();
407 // Nickname lookup will fail, so a nickname will appear verbatim.
408 config_line_append(&options
->MyFamily
, "MyFamily",
410 sl
= get_my_declared_family(options
);
411 tt_ptr_op(sl
, OP_NE
, NULL
);
412 tt_int_op(smartlist_len(sl
), OP_EQ
, 4);
413 join
= smartlist_join_strings(sl
, " ", 0, NULL
);
414 tt_str_op(join
, OP_EQ
,
415 "$0123456789ABCDEF0123456789ABCDEF01234567 "
416 "$686F6C65696E746865626F74746F6D6F66746865 "
417 "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA "
419 expect_single_log_msg_containing(
420 "There is a router named \"BAGEL\" in my declared family, but "
421 "I have no descriptor for it.");
424 // A bogus digest should fail entirely.
425 config_line_append(&options
->MyFamily
, "MyFamily",
427 sl
= get_my_declared_family(options
);
428 tt_ptr_op(sl
, OP_NE
, NULL
);
429 tt_int_op(smartlist_len(sl
), OP_EQ
, 4);
430 join
= smartlist_join_strings(sl
, " ", 0, NULL
);
431 tt_str_op(join
, OP_EQ
,
432 "$0123456789ABCDEF0123456789ABCDEF01234567 "
433 "$686F6C65696E746865626F74746F6D6F66746865 "
434 "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA "
436 // "BAGEL" is still there, but it won't make a warning, because we already
438 expect_single_log_msg_containing(
439 "There is a router named \"$painauchocolat\" in my declared "
440 "family, but that isn't a legal digest or nickname. Skipping it.");
443 // Let's introduce a node we can look up by nickname
444 memset(&fake_node
, 0, sizeof(fake_node
));
445 memcpy(fake_node
.identity
, "whydoyouasknonononon", DIGEST_LEN
);
446 MOCK(node_get_by_nickname
, mock_node_get_by_nickname
);
448 config_line_append(&options
->MyFamily
, "MyFamily",
450 sl
= get_my_declared_family(options
);
451 tt_ptr_op(sl
, OP_NE
, NULL
);
452 tt_int_op(smartlist_len(sl
), OP_EQ
, 5);
453 join
= smartlist_join_strings(sl
, " ", 0, NULL
);
454 tt_str_op(join
, OP_EQ
,
455 "$0123456789ABCDEF0123456789ABCDEF01234567 "
456 "$686F6C65696E746865626F74746F6D6F66746865 "
457 "$776879646F796F7561736B6E6F6E6F6E6F6E6F6E "
458 "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA "
460 // "BAGEL" is still there, but it won't make a warning, because we already
461 // warned about it. Some with "$painauchocolat".
462 expect_single_log_msg_containing(
463 "There is a router named \"CRUmpeT\" in my declared "
464 "family, but it wasn't listed by digest. Please consider saying "
465 "$776879646F796F7561736B6E6F6E6F6E6F6E6F6E instead, if that's "
468 UNMOCK(node_get_by_nickname
);
470 // Try a singleton list containing only us: It should give us NULL.
471 config_free_lines(options
->MyFamily
);
472 config_line_append(&options
->MyFamily
, "MyFamily",
473 "$686F6C65696E746865626F74746F6D6F66746865");
474 sl
= get_my_declared_family(options
);
475 tt_ptr_op(sl
, OP_EQ
, NULL
);
476 expect_no_log_entry();
479 or_options_free(options
);
480 teardown_capture_of_logs();
482 UNMOCK(node_get_by_nickname
);
487 #define ROUTER_TEST(name, flags) \
488 { #name, test_router_ ## name, flags, NULL, NULL }
490 struct testcase_t router_tests
[] = {
491 ROUTER_TEST(check_descriptor_bandwidth_changed
, TT_FORK
),
492 ROUTER_TEST(dump_router_to_string_no_bridge_distribution_method
, TT_FORK
),
493 ROUTER_TEST(mark_if_too_old
, TT_FORK
),
494 ROUTER_TEST(get_my_family
, TT_FORK
),