Merge branch 'maint-0.4.0'
[tor.git] / src / test / test_router.c
blob5477ab51e97c11e7960b2bdae547f39382a02327
1 /* Copyright (c) 2017-2019, The Tor Project, Inc. */
2 /* Copyright (c) 2017, isis agora lovecruft */
3 /* See LICENSE for licensing information */
5 /**
6 * \file test_router.c
7 * \brief Unittests for code in router.c
8 **/
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;
42 crypto_pk_t* tap_key;
43 time_t now;
45 if (!mock_routerinfo) {
46 /* Mock the published timestamp, otherwise router_dump_router_to_string()
47 * will poop its pants. */
48 time(&now);
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". */
77 static void
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;
85 char* desc = NULL;
86 char* found = NULL;
87 (void)arg;
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
105 * this test. */
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,
114 onion_pkey,
115 &ntor_keypair,
116 &signing_keypair);
117 crypto_pk_free(onion_pkey);
118 tt_ptr_op(desc, !=, NULL);
119 found = strstr(desc, needle);
120 tt_ptr_op(found, !=, NULL);
122 done:
123 NS_UNMOCK(router_get_my_routerinfo);
125 tor_free(desc);
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;
136 static long
137 mock_get_uptime_3h(void)
139 return 3*60*60;
142 static long
143 mock_get_uptime_1d(void)
145 return 24*60*60;
148 static int
149 mock_rep_hist_bandwidth_assess(void)
151 return 20001;
154 static int
155 mock_we_are_not_hibernating(void)
157 return 0;
160 static int
161 mock_we_are_hibernating(void)
163 return 0;
166 static void
167 test_router_check_descriptor_bandwidth_changed(void *arg)
169 (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.");
228 UNMOCK(get_uptime);
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();
240 done:
241 UNMOCK(get_uptime);
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)
250 (void)now;
251 return mock_ns;
254 static routerstatus_t *mock_rs = NULL;
255 static const routerstatus_t *
256 mock_networkstatus_vote_find_entry(networkstatus_t *ns, const char *digest)
258 (void)ns;
259 (void)digest;
260 return mock_rs;
263 static void
264 test_router_mark_if_too_old(void *arg)
266 (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);
272 routerstatus_t rs;
273 networkstatus_t ns;
274 memset(&rs, 0, sizeof(rs));
275 memset(&ns, 0, sizeof(ns));
276 mock_ns = &ns;
277 mock_ns->valid_after = now-3600;
278 mock_rs = &rs;
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.
288 mock_ns = NULL;
289 mark_my_descriptor_dirty_if_too_old(now);
290 tt_i64_op(desc_clean_since, OP_EQ, now-10);
291 mock_ns = &ns;
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;
327 mock_rs = 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");
333 done:
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)
342 (void)flags;
343 if (!strcasecmp(name, "crumpet"))
344 return &fake_node;
345 else
346 return NULL;
349 static void
350 test_router_get_my_family(void *arg)
352 (void)arg;
353 or_options_t *options = options_new();
354 smartlist_t *sl = NULL;
355 char *join = 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 { \
369 if (sl) { \
370 SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); \
371 smartlist_free(sl); \
373 tor_free(join); \
374 mock_clean_saved_logs(); \
375 } while (0)
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();
391 CLEAR();
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();
405 CLEAR();
407 // Nickname lookup will fail, so a nickname will appear verbatim.
408 config_line_append(&options->MyFamily, "MyFamily",
409 "BAGEL");
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 "
418 "bagel");
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.");
422 CLEAR();
424 // A bogus digest should fail entirely.
425 config_line_append(&options->MyFamily, "MyFamily",
426 "$painauchocolat");
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 "
435 "bagel");
436 // "BAGEL" is still there, but it won't make a warning, because we already
437 // warned about it.
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.");
441 CLEAR();
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",
449 "CRUmpeT");
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 "
459 "bagel");
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 "
466 "what you meant.");
467 CLEAR();
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();
478 done:
479 or_options_free(options);
480 teardown_capture_of_logs();
481 CLEAR();
482 UNMOCK(node_get_by_nickname);
484 #undef CLEAR
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),
495 END_OF_TESTCASES