diff options
Diffstat (limited to 'src/test')
71 files changed, 3261 insertions, 338 deletions
diff --git a/src/test/conf_examples/empty_3/expected_log b/src/test/conf_examples/empty_3/expected_log index a42514f37f..e3f2365893 100644 --- a/src/test/conf_examples/empty_3/expected_log +++ b/src/test/conf_examples/empty_3/expected_log @@ -1 +1 @@ -Included configuration .*directory at recursion level 1.*included +Processing configuration path \".*included\" at recursion level 1\. diff --git a/src/test/conf_examples/include_1/expected_log b/src/test/conf_examples/include_1/expected_log index f95cad040d..0791a494d2 100644 --- a/src/test/conf_examples/include_1/expected_log +++ b/src/test/conf_examples/include_1/expected_log @@ -1 +1 @@ -Included configuration file .*at recursion level 2.*nested\.inc +Processing configuration path \".*nested\.inc\" at recursion level 2\. diff --git a/src/test/conf_examples/include_bug_31408/expected_log b/src/test/conf_examples/include_bug_31408/expected_log index a42514f37f..e3f2365893 100644 --- a/src/test/conf_examples/include_bug_31408/expected_log +++ b/src/test/conf_examples/include_bug_31408/expected_log @@ -1 +1 @@ -Included configuration .*directory at recursion level 1.*included +Processing configuration path \".*included\" at recursion level 1\. diff --git a/src/test/conf_examples/large_1/expected b/src/test/conf_examples/large_1/expected index 5866f5823e..99a12ffc84 100644 --- a/src/test/conf_examples/large_1/expected +++ b/src/test/conf_examples/large_1/expected @@ -15,7 +15,6 @@ CellStatistics 1 CircuitBuildTimeout 200 CircuitsAvailableTimeout 10 CircuitStreamTimeout 20 -ClientAutoIPv6ORPort 1 ClientOnly 1 ClientPreferIPv6DirPort 1 ClientPreferIPv6ORPort 1 diff --git a/src/test/conf_examples/large_1/expected_no_dirauth b/src/test/conf_examples/large_1/expected_no_dirauth index 17c11f85fc..26a33bdc7c 100644 --- a/src/test/conf_examples/large_1/expected_no_dirauth +++ b/src/test/conf_examples/large_1/expected_no_dirauth @@ -15,7 +15,6 @@ CellStatistics 1 CircuitBuildTimeout 200 CircuitsAvailableTimeout 10 CircuitStreamTimeout 20 -ClientAutoIPv6ORPort 1 ClientOnly 1 ClientPreferIPv6DirPort 1 ClientPreferIPv6ORPort 1 diff --git a/src/test/conf_examples/large_1/torrc b/src/test/conf_examples/large_1/torrc index e99acd9fb7..20ddf00e16 100644 --- a/src/test/conf_examples/large_1/torrc +++ b/src/test/conf_examples/large_1/torrc @@ -16,7 +16,6 @@ CircuitBuildTimeout 200 CircuitPadding 1 CircuitsAvailableTimeout 10 CircuitStreamTimeout 20 -ClientAutoIPv6ORPort 1 ClientOnly 1 ClientPreferIPv6DirPort 1 ClientPreferIPv6ORPort 1 diff --git a/src/test/conf_examples/relay_30/error_no_dirauth_relay b/src/test/conf_examples/relay_30/error_no_dirauth_relay new file mode 100644 index 0000000000..9f9c0fd8f3 --- /dev/null +++ b/src/test/conf_examples/relay_30/error_no_dirauth_relay @@ -0,0 +1 @@ +This tor was built with relay mode disabled. diff --git a/src/test/conf_examples/relay_30/expected b/src/test/conf_examples/relay_30/expected new file mode 100644 index 0000000000..3a4e9feb3f --- /dev/null +++ b/src/test/conf_examples/relay_30/expected @@ -0,0 +1,2 @@ +Nickname Unnamed +ORPort auto diff --git a/src/test/conf_examples/relay_30/expected_log b/src/test/conf_examples/relay_30/expected_log new file mode 100644 index 0000000000..d5478c1a15 --- /dev/null +++ b/src/test/conf_examples/relay_30/expected_log @@ -0,0 +1 @@ +Your ContactInfo config option is not set
\ No newline at end of file diff --git a/src/test/conf_examples/relay_30/torrc b/src/test/conf_examples/relay_30/torrc new file mode 100644 index 0000000000..bf8487fe16 --- /dev/null +++ b/src/test/conf_examples/relay_30/torrc @@ -0,0 +1,3 @@ +# Relay tests +# default (IPv4) ORPort auto +ORPort auto diff --git a/src/test/conf_examples/relay_31/error_no_dirauth_relay b/src/test/conf_examples/relay_31/error_no_dirauth_relay new file mode 100644 index 0000000000..9f9c0fd8f3 --- /dev/null +++ b/src/test/conf_examples/relay_31/error_no_dirauth_relay @@ -0,0 +1 @@ +This tor was built with relay mode disabled. diff --git a/src/test/conf_examples/relay_31/expected b/src/test/conf_examples/relay_31/expected new file mode 100644 index 0000000000..9a40cdd588 --- /dev/null +++ b/src/test/conf_examples/relay_31/expected @@ -0,0 +1,3 @@ +DirPort auto +Nickname Unnamed +ORPort auto diff --git a/src/test/conf_examples/relay_31/expected_log b/src/test/conf_examples/relay_31/expected_log new file mode 100644 index 0000000000..d5478c1a15 --- /dev/null +++ b/src/test/conf_examples/relay_31/expected_log @@ -0,0 +1 @@ +Your ContactInfo config option is not set
\ No newline at end of file diff --git a/src/test/conf_examples/relay_31/torrc b/src/test/conf_examples/relay_31/torrc new file mode 100644 index 0000000000..e662bb71b3 --- /dev/null +++ b/src/test/conf_examples/relay_31/torrc @@ -0,0 +1,4 @@ +# Relay tests +# default (IPv4) ORPort and DirPort auto +ORPort auto +DirPort auto diff --git a/src/test/conf_examples/relay_32/error_no_dirauth_relay b/src/test/conf_examples/relay_32/error_no_dirauth_relay new file mode 100644 index 0000000000..9f9c0fd8f3 --- /dev/null +++ b/src/test/conf_examples/relay_32/error_no_dirauth_relay @@ -0,0 +1 @@ +This tor was built with relay mode disabled. diff --git a/src/test/conf_examples/relay_32/expected b/src/test/conf_examples/relay_32/expected new file mode 100644 index 0000000000..14b36c8259 --- /dev/null +++ b/src/test/conf_examples/relay_32/expected @@ -0,0 +1,3 @@ +Nickname Unnamed +ORPort auto +ORPort [::1]:auto diff --git a/src/test/conf_examples/relay_32/expected_log b/src/test/conf_examples/relay_32/expected_log new file mode 100644 index 0000000000..d5478c1a15 --- /dev/null +++ b/src/test/conf_examples/relay_32/expected_log @@ -0,0 +1 @@ +Your ContactInfo config option is not set
\ No newline at end of file diff --git a/src/test/conf_examples/relay_32/torrc b/src/test/conf_examples/relay_32/torrc new file mode 100644 index 0000000000..95a66c4852 --- /dev/null +++ b/src/test/conf_examples/relay_32/torrc @@ -0,0 +1,4 @@ +# Relay tests +# default (IPv4) ORPort auto and IPv6 ORPort auto +ORPort auto +ORPort [::1]:auto diff --git a/src/test/conf_examples/relay_33/error_no_dirauth_relay b/src/test/conf_examples/relay_33/error_no_dirauth_relay new file mode 100644 index 0000000000..9f9c0fd8f3 --- /dev/null +++ b/src/test/conf_examples/relay_33/error_no_dirauth_relay @@ -0,0 +1 @@ +This tor was built with relay mode disabled. diff --git a/src/test/conf_examples/relay_33/expected b/src/test/conf_examples/relay_33/expected new file mode 100644 index 0000000000..22567cbe2e --- /dev/null +++ b/src/test/conf_examples/relay_33/expected @@ -0,0 +1,3 @@ +Nickname Unnamed +ORPort 127.0.0.1:auto +ORPort [::1]:auto diff --git a/src/test/conf_examples/relay_33/expected_log b/src/test/conf_examples/relay_33/expected_log new file mode 100644 index 0000000000..d5478c1a15 --- /dev/null +++ b/src/test/conf_examples/relay_33/expected_log @@ -0,0 +1 @@ +Your ContactInfo config option is not set
\ No newline at end of file diff --git a/src/test/conf_examples/relay_33/torrc b/src/test/conf_examples/relay_33/torrc new file mode 100644 index 0000000000..44d16ad31a --- /dev/null +++ b/src/test/conf_examples/relay_33/torrc @@ -0,0 +1,4 @@ +# Relay tests +# explicit IPv4 ORPort auto and IPv6 ORPort auto +ORPort 127.0.0.1:auto +ORPort [::1]:auto diff --git a/src/test/conf_examples/relay_34/error_no_dirauth_relay b/src/test/conf_examples/relay_34/error_no_dirauth_relay new file mode 100644 index 0000000000..9f9c0fd8f3 --- /dev/null +++ b/src/test/conf_examples/relay_34/error_no_dirauth_relay @@ -0,0 +1 @@ +This tor was built with relay mode disabled. diff --git a/src/test/conf_examples/relay_34/expected b/src/test/conf_examples/relay_34/expected new file mode 100644 index 0000000000..bccde684f3 --- /dev/null +++ b/src/test/conf_examples/relay_34/expected @@ -0,0 +1,4 @@ +DirPort 127.0.0.1:auto +Nickname Unnamed +ORPort 127.0.0.1:auto +ORPort [::1]:auto diff --git a/src/test/conf_examples/relay_34/expected_log b/src/test/conf_examples/relay_34/expected_log new file mode 100644 index 0000000000..d5478c1a15 --- /dev/null +++ b/src/test/conf_examples/relay_34/expected_log @@ -0,0 +1 @@ +Your ContactInfo config option is not set
\ No newline at end of file diff --git a/src/test/conf_examples/relay_34/torrc b/src/test/conf_examples/relay_34/torrc new file mode 100644 index 0000000000..01010a5c38 --- /dev/null +++ b/src/test/conf_examples/relay_34/torrc @@ -0,0 +1,5 @@ +# Relay tests +# explicit IPv4 ORPort and DirPort auto and IPv6 ORPort auto +ORPort 127.0.0.1:auto +ORPort [::1]:auto +DirPort 127.0.0.1:auto diff --git a/src/test/fuzz/fuzz_hsdescv3.c b/src/test/fuzz/fuzz_hsdescv3.c index 3955241389..8d7eab1a8d 100644 --- a/src/test/fuzz/fuzz_hsdescv3.c +++ b/src/test/fuzz/fuzz_hsdescv3.c @@ -85,12 +85,12 @@ int fuzz_main(const uint8_t *data, size_t sz) { hs_descriptor_t *desc = NULL; - uint8_t subcredential[DIGEST256_LEN]; + hs_subcredential_t subcredential; char *fuzzing_data = tor_memdup_nulterm(data, sz); - memset(subcredential, 'A', sizeof(subcredential)); + memset(&subcredential, 'A', sizeof(subcredential)); - hs_desc_decode_descriptor(fuzzing_data, subcredential, NULL, &desc); + hs_desc_decode_descriptor(fuzzing_data, &subcredential, NULL, &desc); if (desc) { log_debug(LD_GENERAL, "Decoding okay"); hs_descriptor_free(desc); @@ -101,4 +101,3 @@ fuzz_main(const uint8_t *data, size_t sz) tor_free(fuzzing_data); return 0; } - diff --git a/src/test/hs_test_helpers.c b/src/test/hs_test_helpers.c index e8b99aaac8..5116fc7169 100644 --- a/src/test/hs_test_helpers.c +++ b/src/test/hs_test_helpers.c @@ -13,9 +13,22 @@ #include "feature/hs/hs_service.h" #include "test/hs_test_helpers.h" +/** + * Create an introduction point taken straight out of an HSv3 descriptor. + * + * Use 'signing_kp' to sign the introduction point certificates. + * + * If 'intro_auth_kp' is provided use that as the introduction point + * authentication keypair, otherwise generate one on the fly. + * + * If 'intro_enc_kp' is provided use that as the introduction point encryption + * keypair, otherwise generate one on the fly. + */ hs_desc_intro_point_t * hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now, - const char *addr, int legacy) + const char *addr, int legacy, + const ed25519_keypair_t *intro_auth_kp, + const curve25519_keypair_t *intro_enc_kp) { int ret; ed25519_keypair_t auth_kp; @@ -56,8 +69,12 @@ hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now, smartlist_add(ip->link_specifiers, ls_ip); } - ret = ed25519_keypair_generate(&auth_kp, 0); - tt_int_op(ret, OP_EQ, 0); + if (intro_auth_kp) { + memcpy(&auth_kp, intro_auth_kp, sizeof(ed25519_keypair_t)); + } else { + ret = ed25519_keypair_generate(&auth_kp, 0); + tt_int_op(ret, OP_EQ, 0); + } ip->auth_key_cert = tor_cert_create(signing_kp, CERT_TYPE_AUTH_HS_IP_KEY, &auth_kp.pubkey, now, HS_DESC_CERT_LIFETIME, @@ -85,8 +102,12 @@ hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now, ed25519_keypair_t ed25519_kp; tor_cert_t *cross_cert; - ret = curve25519_keypair_generate(&curve25519_kp, 0); - tt_int_op(ret, OP_EQ, 0); + if (intro_enc_kp) { + memcpy(&curve25519_kp, intro_enc_kp, sizeof(curve25519_keypair_t)); + } else { + ret = curve25519_keypair_generate(&curve25519_kp, 0); + tt_int_op(ret, OP_EQ, 0); + } ed25519_keypair_from_curve25519_keypair(&ed25519_kp, &signbit, &curve25519_kp); cross_cert = tor_cert_create(signing_kp, CERT_TYPE_CROSS_HS_IP_KEYS, @@ -95,6 +116,8 @@ hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now, CERT_FLAG_INCLUDE_SIGNING_KEY); tt_assert(cross_cert); ip->enc_key_cert = cross_cert; + memcpy(ip->enc_key.public_key, curve25519_kp.pubkey.public_key, + CURVE25519_PUBKEY_LEN); } intro_point = ip; @@ -140,7 +163,7 @@ hs_helper_build_hs_desc_impl(unsigned int no_ip, desc->plaintext_data.lifetime_sec = 3 * 60 * 60; hs_get_subcredential(&signing_kp->pubkey, &blinded_kp.pubkey, - desc->subcredential); + &desc->subcredential); /* Setup superencrypted data section. */ ret = curve25519_keypair_generate(&auth_ephemeral_kp, 0); @@ -165,13 +188,17 @@ hs_helper_build_hs_desc_impl(unsigned int no_ip, if (!no_ip) { /* Add four intro points. */ smartlist_add(desc->encrypted_data.intro_points, - hs_helper_build_intro_point(signing_kp, now, "1.2.3.4", 0)); + hs_helper_build_intro_point(signing_kp, now, "1.2.3.4", 0, + NULL, NULL)); smartlist_add(desc->encrypted_data.intro_points, - hs_helper_build_intro_point(signing_kp, now, "[2600::1]", 0)); + hs_helper_build_intro_point(signing_kp, now, "[2600::1]", 0, + NULL, NULL)); smartlist_add(desc->encrypted_data.intro_points, - hs_helper_build_intro_point(signing_kp, now, "3.2.1.4", 1)); + hs_helper_build_intro_point(signing_kp, now, "3.2.1.4", 1, + NULL, NULL)); smartlist_add(desc->encrypted_data.intro_points, - hs_helper_build_intro_point(signing_kp, now, "5.6.7.8", 1)); + hs_helper_build_intro_point(signing_kp, now, "5.6.7.8", 1, + NULL, NULL)); } descp = desc; @@ -186,7 +213,7 @@ hs_helper_build_hs_desc_impl(unsigned int no_ip, * an HS. Used to decrypt descriptors in unittests. */ void hs_helper_get_subcred_from_identity_keypair(ed25519_keypair_t *signing_kp, - uint8_t *subcred_out) + hs_subcredential_t *subcred_out) { ed25519_keypair_t blinded_kp; uint64_t current_time_period = hs_get_time_period_num(approx_time()); @@ -233,7 +260,7 @@ hs_helper_build_hs_desc_with_client_auth( memcpy(&desc->superencrypted_data.auth_ephemeral_pubkey, &auth_ephemeral_kp.pubkey, sizeof(curve25519_public_key_t)); - hs_desc_build_authorized_client(desc->subcredential, client_pk, + hs_desc_build_authorized_client(&desc->subcredential, client_pk, &auth_ephemeral_kp.seckey, descriptor_cookie, desc_client); smartlist_add(desc->superencrypted_data.clients, desc_client); diff --git a/src/test/hs_test_helpers.h b/src/test/hs_test_helpers.h index a01fd45d63..23d11f2a4a 100644 --- a/src/test/hs_test_helpers.h +++ b/src/test/hs_test_helpers.h @@ -8,9 +8,11 @@ #include "feature/hs/hs_descriptor.h" /* Set of functions to help build and test descriptors. */ -hs_desc_intro_point_t *hs_helper_build_intro_point( - const ed25519_keypair_t *signing_kp, time_t now, - const char *addr, int legacy); +hs_desc_intro_point_t * +hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now, + const char *addr, int legacy, + const ed25519_keypair_t *intro_auth_kp, + const curve25519_keypair_t *intro_enc_kp); hs_descriptor_t *hs_helper_build_hs_desc_no_ip( const ed25519_keypair_t *signing_kp); hs_descriptor_t *hs_helper_build_hs_desc_with_ip( @@ -21,12 +23,11 @@ hs_descriptor_t *hs_helper_build_hs_desc_with_client_auth( const ed25519_keypair_t *signing_kp); void hs_helper_desc_equal(const hs_descriptor_t *desc1, const hs_descriptor_t *desc2); -void -hs_helper_get_subcred_from_identity_keypair(ed25519_keypair_t *signing_kp, - uint8_t *subcred_out); +struct hs_subcredential_t; +void hs_helper_get_subcred_from_identity_keypair(ed25519_keypair_t *signing_kp, + struct hs_subcredential_t *subcred_out); void hs_helper_add_client_auth(const ed25519_public_key_t *service_pk, const curve25519_secret_key_t *client_sk); #endif /* !defined(TOR_HS_TEST_HELPERS_H) */ - diff --git a/src/test/include.am b/src/test/include.am index 33556083df..7814dbca89 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -26,7 +26,6 @@ TESTSCRIPTS = \ src/test/test_switch_id.sh \ src/test/test_cmdline.sh \ src/test/test_parseconf.sh \ - src/test/test_switch_id.sh \ src/test/unittest_part1.sh \ src/test/unittest_part2.sh \ src/test/unittest_part3.sh \ @@ -46,7 +45,8 @@ TESTSCRIPTS += \ src/test/test_ntor.sh \ src/test/test_hs_ntor.sh \ src/test/test_bt.sh \ - scripts/maint/practracker/test_practracker.sh + scripts/maint/practracker/test_practracker.sh \ + scripts/maint/run_check_subsystem_order.sh if COVERAGE_ENABLED # ... @@ -70,13 +70,25 @@ TESTS += src/test/test-slow src/test/test-memwipe \ $(TESTSCRIPTS) # These flavors are run using automake's test-driver and test-network.sh -TEST_CHUTNEY_FLAVORS = basic-min bridges-min hs-v2-min hs-v3-min \ - single-onion-v23 + +# run a quick test or two +# this test only uses IPv4 +TEST_CHUTNEY_FLAVOR_QUICK = bridges+hs-v23 # only run if we can ping6 ::1 (localhost) +TEST_CHUTNEY_FLAVOR_QUICK_IPV6 = single-onion-v23-ipv6-md + +# run a basic set of tests, which only use IPv4 +TEST_CHUTNEY_FLAVORS = basic-min bridges-min hs-v23-min single-onion-v23 + +# only run if we can ping ::1 (localhost) TEST_CHUTNEY_FLAVORS_IPV6 = bridges+ipv6-min ipv6-exit-min hs-v23-ipv6-md \ single-onion-v23-ipv6-md + # only run if we can find a stable (or simply another) version of tor -TEST_CHUTNEY_FLAVORS_MIXED = mixed+hs-v2 +TEST_CHUTNEY_FLAVORS_MIXED = mixed+hs-v23 + +# only run if IPv6 and mixed networks are run +TEST_CHUTNEY_FLAVORS_IPV6_MIXED = mixed+hs-v23-ipv6 ### This is a lovely feature, but it requires automake >= 1.12, and Tor ### doesn't require that yet. @@ -176,6 +188,7 @@ src_test_test_SOURCES += \ src/test/test_hs_client.c \ src/test/test_hs_intropoint.c \ src/test/test_hs_control.c \ + src/test/test_hs_ob.c \ src/test/test_handles.c \ src/test/test_hs_cache.c \ src/test/test_hs_descriptor.c \ @@ -426,6 +439,7 @@ EXTRA_DIST += \ src/test/test_rebind.sh \ src/test/test_rebind.py \ src/test/zero_length_keys.sh \ + scripts/maint/run_check_subsystem_order.sh \ src/test/rust_supp.txt \ src/test/test_keygen.sh \ src/test/test_key_expiration.sh \ diff --git a/src/test/log_test_helpers.h b/src/test/log_test_helpers.h index e2ddf09466..c2d71c6bcd 100644 --- a/src/test/log_test_helpers.h +++ b/src/test/log_test_helpers.h @@ -78,7 +78,7 @@ void mock_dump_saved_logs(void); mock_saved_log_n_entries() == 1, \ ("expected log to contain exactly 1 message \"%s\"", \ str)); \ - } while (0); + } while (0) #define expect_single_log_msg_containing(str) \ do { \ @@ -86,30 +86,30 @@ void mock_dump_saved_logs(void); mock_saved_log_n_entries() == 1 , \ ("expected log to contain 1 message, containing \"%s\"",\ str)); \ - } while (0); + } while (0) #define expect_no_log_msg(str) \ assert_log_predicate(!mock_saved_log_has_message(str), \ - ("expected log to not contain \"%s\"",str)); + ("expected log to not contain \"%s\"",str)) #define expect_no_log_msg_containing(str) \ assert_log_predicate(!mock_saved_log_has_message_containing(str), \ - ("expected log to not contain \"%s\"", str)); + ("expected log to not contain \"%s\"", str)) #define expect_log_severity(severity) \ assert_log_predicate(mock_saved_log_has_severity(severity), \ - ("expected log to contain severity " # severity)); + ("expected log to contain severity " # severity)) #define expect_no_log_severity(severity) \ assert_log_predicate(!mock_saved_log_has_severity(severity), \ - ("expected log to not contain severity " # severity)); + ("expected log to not contain severity " # severity)) #define expect_log_entry() \ assert_log_predicate(mock_saved_log_has_entry(), \ - ("expected log to contain entries")); + ("expected log to contain entries")) #define expect_no_log_entry() \ assert_log_predicate(!mock_saved_log_has_entry(), \ - ("expected log to not contain entries")); + ("expected log to not contain entries")) #endif /* !defined(TOR_LOG_TEST_HELPERS_H) */ diff --git a/src/test/slow_ed25519.py b/src/test/slow_ed25519.py index afad678000..be4eeab857 100644 --- a/src/test/slow_ed25519.py +++ b/src/test/slow_ed25519.py @@ -1,5 +1,5 @@ # This is the ed25519 implementation from -# http://ed25519.cr.yp.to/python/ed25519.py . +# https://ed25519.cr.yp.to/python/ed25519.py . # It is in the public domain. # # It isn't constant-time. Don't use it except for testing. Also, see diff --git a/src/test/test.c b/src/test/test.c index 1742f1d952..4b6082ce4f 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -721,6 +721,7 @@ struct testgroup_t testgroups[] = { { "hs_dos/", hs_dos_tests }, { "hs_intropoint/", hs_intropoint_tests }, { "hs_ntor/", hs_ntor_tests }, + { "hs_ob/", hs_ob_tests }, { "hs_service/", hs_service_tests }, { "introduce/", introduce_tests }, { "keypin/", keypin_tests }, diff --git a/src/test/test.h b/src/test/test.h index 63e2faff95..18987719d0 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -141,6 +141,7 @@ extern struct testcase_t hs_descriptor[]; extern struct testcase_t hs_dos_tests[]; extern struct testcase_t hs_intropoint_tests[]; extern struct testcase_t hs_ntor_tests[]; +extern struct testcase_t hs_ob_tests[]; extern struct testcase_t hs_service_tests[]; extern struct testcase_t hs_tests[]; extern struct testcase_t introduce_tests[]; diff --git a/src/test/test_addr.c b/src/test/test_addr.c index 42232e467a..cf5aad7e71 100644 --- a/src/test/test_addr.c +++ b/src/test/test_addr.c @@ -659,12 +659,7 @@ test_addr_ip6_helpers(void *arg) tt_int_op(tor_addr_family(&t1),OP_EQ,AF_INET); tt_int_op(tor_addr_to_ipv4h(&t1),OP_EQ,0x01010202); r=tor_addr_parse_mask_ports("3.4.16.032:1-2",0,&t1, &mask, &port1, &port2); - tt_int_op(r, OP_EQ, AF_INET); - tt_int_op(mask,OP_EQ,32); - tt_int_op(tor_addr_family(&t1),OP_EQ,AF_INET); - tt_int_op(tor_addr_to_ipv4h(&t1),OP_EQ,0x03041020); - tt_uint_op(port1, OP_EQ, 1); - tt_uint_op(port2, OP_EQ, 2); + tt_int_op(r, OP_EQ, -1); r=tor_addr_parse_mask_ports("1.1.2.3/255.255.128.0",0,&t1, &mask,NULL,NULL); tt_int_op(r, OP_EQ, AF_INET); tt_int_op(mask,OP_EQ,17); @@ -1653,6 +1648,159 @@ test_addr_rfc6598(void *arg) ; } +#define TEST_ADDR_ATON(a, rv) STMT_BEGIN \ + struct in_addr addr; \ + tt_int_op(tor_inet_aton(a, &addr), OP_EQ, rv); \ + STMT_END; + +static void +test_addr_octal(void *arg) +{ + (void)arg; + + /* Test non-octal IP addresses. */ + TEST_ADDR_ATON("0.1.2.3", 1); + TEST_ADDR_ATON("1.0.2.3", 1); + TEST_ADDR_ATON("1.2.3.0", 1); + + /* Test octal IP addresses. */ + TEST_ADDR_ATON("01.1.2.3", 0); + TEST_ADDR_ATON("1.02.3.4", 0); + TEST_ADDR_ATON("1.2.3.04", 0); + done: + ; +} + +#define get_ipv4(test_addr, str, iprv) STMT_BEGIN \ + test_addr = tor_malloc(sizeof(tor_addr_t)); \ + test_addr->family = AF_INET; \ + iprv = tor_inet_aton(str, &test_addr->addr.in_addr); \ + tor_assert(iprv); \ + STMT_END; + +#define get_ipv6(test_addr, str, iprv) STMT_BEGIN \ + test_addr = tor_malloc(sizeof(tor_addr_t)); \ + test_addr->family = AF_INET6; \ + iprv = tor_inet_pton(AF_INET6, str, &test_addr->addr.in6_addr); \ + tor_assert(iprv); \ + STMT_END; + +#define get_af_unix(test_addr) STMT_BEGIN \ + test_addr = tor_malloc_zero(sizeof(tor_addr_t)); \ + test_addr->family = AF_UNIX; \ + STMT_END; + +#define get_af_unspec(test_addr) STMT_BEGIN \ + test_addr = tor_malloc_zero(sizeof(tor_addr_t)); \ + test_addr->family = AF_UNSPEC; \ + STMT_END; + +#define TEST_ADDR_VALIDITY(a, lis, rv) STMT_BEGIN \ + tor_assert(a); \ + tt_int_op(tor_addr_is_valid(a, lis), OP_EQ, rv); \ + STMT_END; + +/* Here we can change the addresses we are testing for. */ +#define IP4_TEST_ADDR "123.98.45.1" +#define IP6_TEST_ADDR "2001:0DB8:AC10:FE01::" + +static void +test_addr_is_valid(void *arg) +{ + (void)arg; + tor_addr_t *test_addr; + int iprv; + + /* Tests for IPv4 addresses. */ + + /* Test for null IPv4 address. */ + get_ipv4(test_addr, "0.0.0.0", iprv); + TEST_ADDR_VALIDITY(test_addr, 0, 0); + TEST_ADDR_VALIDITY(test_addr, 1, 1); + tor_free(test_addr); + + /* Test for non-null IPv4 address. */ + get_ipv4(test_addr, IP4_TEST_ADDR, iprv); + TEST_ADDR_VALIDITY(test_addr, 0, 1); + TEST_ADDR_VALIDITY(test_addr, 1, 1); + tor_free(test_addr); + + /* Tests for IPv6 addresses. */ + + /* Test for null IPv6 address. */ + get_ipv6(test_addr, "::", iprv); + TEST_ADDR_VALIDITY(test_addr, 0, 0); + TEST_ADDR_VALIDITY(test_addr, 1, 1); + tor_free(test_addr); + + /* Test for non-null IPv6 address. */ + get_ipv6(test_addr, IP6_TEST_ADDR, iprv); + TEST_ADDR_VALIDITY(test_addr, 0, 1); + TEST_ADDR_VALIDITY(test_addr, 1, 1); + tor_free(test_addr); + + /* Test for address of type AF_UNIX. */ + + get_af_unix(test_addr); + TEST_ADDR_VALIDITY(test_addr, 0, 0); + TEST_ADDR_VALIDITY(test_addr, 1, 0); + tor_free(test_addr); + + /* Test for address of type AF_UNSPEC. */ + + get_af_unspec(test_addr); + TEST_ADDR_VALIDITY(test_addr, 0, 0); + TEST_ADDR_VALIDITY(test_addr, 1, 0); + + done: + tor_free(test_addr); +} + +#define TEST_ADDR_IS_NULL(a, rv) STMT_BEGIN \ + tor_assert(a); \ + tt_int_op(tor_addr_is_null(a), OP_EQ, rv); \ + STMT_END; + +static void +test_addr_is_null(void *arg) +{ + (void)arg; + tor_addr_t *test_addr; + int iprv; + + /* Test for null IPv4. */ + get_ipv4(test_addr, "0.0.0.0", iprv); + TEST_ADDR_IS_NULL(test_addr, 1); + tor_free(test_addr); + + /* Test for non-null IPv4. */ + get_ipv4(test_addr, IP4_TEST_ADDR, iprv); + TEST_ADDR_IS_NULL(test_addr, 0); + tor_free(test_addr); + + /* Test for null IPv6. */ + get_ipv6(test_addr, "::", iprv); + TEST_ADDR_IS_NULL(test_addr, 1); + tor_free(test_addr); + + /* Test for non-null IPv6. */ + get_ipv6(test_addr, IP6_TEST_ADDR, iprv); + TEST_ADDR_IS_NULL(test_addr, 0); + tor_free(test_addr); + + /* Test for address family AF_UNIX. */ + get_af_unix(test_addr); + TEST_ADDR_IS_NULL(test_addr, 1); + tor_free(test_addr); + + /* Test for address family AF_UNSPEC. */ + get_af_unspec(test_addr); + TEST_ADDR_IS_NULL(test_addr, 1); + + done: + tor_free(test_addr); +} + #ifndef COCCI #define ADDR_LEGACY(name) \ { #name, test_addr_ ## name , 0, NULL, NULL } @@ -1671,5 +1819,8 @@ struct testcase_t addr_tests[] = { { "is_loopback", test_addr_is_loopback, 0, NULL, NULL }, { "make_null", test_addr_make_null, 0, NULL, NULL }, { "rfc6598", test_addr_rfc6598, 0, NULL, NULL }, + { "octal", test_addr_octal, 0, NULL, NULL }, + { "address_validity", test_addr_is_valid, 0, NULL, NULL }, + { "address_is_null", test_addr_is_null, 0, NULL, NULL }, END_OF_TESTCASES }; diff --git a/src/test/test_address.c b/src/test/test_address.c index e068c99d97..4cedbda347 100644 --- a/src/test/test_address.c +++ b/src/test/test_address.c @@ -460,7 +460,7 @@ test_address_ifreq_to_smartlist(void *arg) ifc->ifc_len = sizeof(struct ifreq); ifc->ifc_ifcu.ifcu_req = ifr; - results = ifreq_to_smartlist(ifc->ifc_buf,ifc->ifc_len); + results = ifreq_to_smartlist((const uint8_t *)ifc->ifc_buf,ifc->ifc_len); tt_int_op(smartlist_len(results),OP_EQ,1); tor_addr = smartlist_get(results, 0); @@ -483,7 +483,7 @@ test_address_ifreq_to_smartlist(void *arg) SMARTLIST_FOREACH(results, tor_addr_t *, t, tor_free(t)); smartlist_free(results); - results = ifreq_to_smartlist(ifc->ifc_buf,ifc->ifc_len); + results = ifreq_to_smartlist((const uint8_t *)ifc->ifc_buf,ifc->ifc_len); tt_int_op(smartlist_len(results),OP_EQ,2); tor_addr = smartlist_get(results, 0); diff --git a/src/test/test_cell_formats.c b/src/test/test_cell_formats.c index 8d6d1940fd..f9ff101c98 100644 --- a/src/test/test_cell_formats.c +++ b/src/test/test_cell_formats.c @@ -713,16 +713,20 @@ test_cfmt_extend_cells(void *arg) tt_mem_op(cc->onionskin,OP_EQ, b, 99+20); tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec)); tt_int_op(p2_cmd, OP_EQ, RELAY_COMMAND_EXTEND2); - /* We'll generate it minus the IPv6 address and minus the konami code */ - tt_int_op(p2_len, OP_EQ, 89+99-34-20); + /* We'll generate it minus the konami code */ + tt_int_op(p2_len, OP_EQ, 89+99-34); test_memeq_hex(p2, - /* Two items: one that same darn IP address. */ - "02000612F40001F0F1" - /* The next is a digest : anthropomorphization */ - "0214616e7468726f706f6d6f727068697a6174696f6e" + /* Three items */ + "03" + /* IPv4 address */ + "0006" "12F40001" "F0F1" + /* The next is an RSA digest: anthropomorphization */ + "0214" "616e7468726f706f6d6f727068697a6174696f6e" + /*IPv6 address */ + "0112" "20020000000000000000000000f0c51e" "1112" /* Now the handshake prologue */ "01050063"); - tt_mem_op(p2+1+8+22+4,OP_EQ, b, 99+20); + tt_mem_op(p2+1+8+22+20+4, OP_EQ, b, 99+20); tt_int_op(0, OP_EQ, create_cell_format_relayed(&cell, cc)); /* Now let's add an ed25519 key to that extend2 cell. */ @@ -732,22 +736,31 @@ test_cfmt_extend_cells(void *arg) /* As before, since we aren't extending by ed25519. */ get_options_mutable()->ExtendByEd25519ID = 0; tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec)); - tt_int_op(p2_len, OP_EQ, 89+99-34-20); + tt_int_op(p2_len, OP_EQ, 89+99-34); test_memeq_hex(p2, - "02000612F40001F0F1" + "03" + "000612F40001F0F1" "0214616e7468726f706f6d6f727068697a6174696f6e" + "011220020000000000000000000000f0c51e1112" "01050063"); /* Now try with the ed25519 ID. */ get_options_mutable()->ExtendByEd25519ID = 1; tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec)); - tt_int_op(p2_len, OP_EQ, 89+99-34-20 + 34); + tt_int_op(p2_len, OP_EQ, 89+99); test_memeq_hex(p2, - "03000612F40001F0F1" + /* Four items */ + "04" + /* IPv4 address */ + "0006" "12F40001" "F0F1" + /* The next is an RSA digest: anthropomorphization */ "0214616e7468726f706f6d6f727068697a6174696f6e" - // ed digest follows: + /* Then an ed public key: brownshoesdontmakeit/brownshoesd */ "0320" "62726f776e73686f6573646f6e746d616b656" "9742f62726f776e73686f657364" + /*IPv6 address */ + "0112" "20020000000000000000000000f0c51e" "1112" + /* Now the handshake prologue */ "01050063"); /* Can we parse that? Did the key come through right? */ memset(&ec, 0, sizeof(ec)); @@ -756,6 +769,40 @@ test_cfmt_extend_cells(void *arg) tt_mem_op("brownshoesdontmakeit/brownshoesd", OP_EQ, ec.ed_pubkey.pubkey, 32); + /* Now try IPv6 without IPv4 */ + memset(p, 0, sizeof(p)); + memcpy(p, "\x02", 1); + memcpy(p+1, "\x02\x14" "anthropomorphization", 22); + memcpy(p+23, "\x01\x12" "xxxxxxxxxxxxxxxxYY", 20); + memcpy(p+43, "\xff\xff\x00\x20", 4); + tt_int_op(0, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, + p, sizeof(p))); + tt_int_op(RELAY_COMMAND_EXTEND2, OP_EQ, ec.cell_type); + tt_assert(fast_mem_is_zero((const char *)&ec.orport_ipv4.addr, + sizeof(tor_addr_t))); + tt_int_op(0, OP_EQ, ec.orport_ipv4.port); + tt_str_op("7878:7878:7878:7878:7878:7878:7878:7878", + OP_EQ, fmt_addr(&ec.orport_ipv6.addr)); + tt_int_op(22873, OP_EQ, ec.orport_ipv6.port); + tt_assert(ed25519_public_key_is_zero(&ec.ed_pubkey)); + tt_mem_op(ec.node_id,OP_EQ, "anthropomorphization", 20); + tt_int_op(cc->cell_type, OP_EQ, CELL_CREATE2); + tt_int_op(cc->handshake_type, OP_EQ, 0xffff); + tt_int_op(cc->handshake_len, OP_EQ, 32); + tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec)); + tt_int_op(p2_cmd, OP_EQ, RELAY_COMMAND_EXTEND2); + tt_int_op(p2_len, OP_EQ, 47+32); + test_memeq_hex(p2, + /* Two items */ + "02" + /* The next is an RSA digest: anthropomorphization */ + "0214" "616e7468726f706f6d6f727068697a6174696f6e" + /*IPv6 address */ + "0112" "78787878787878787878787878787878" "5959" + /* Now the handshake prologue */ + "ffff0020"); + tt_int_op(0, OP_EQ, create_cell_format_relayed(&cell, cc)); + /* == Now try parsing some junk */ /* Try a too-long handshake */ @@ -811,13 +858,6 @@ test_cfmt_extend_cells(void *arg) memcpy(p+48, "\xff\xff\x00\x20", 4); tt_int_op(-1, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, p, sizeof(p))); - memset(p, 0, sizeof(p)); - memcpy(p, "\x02", 1); - memcpy(p+1, "\x02\x14" "anarchoindividualist", 22); - memcpy(p+23, "\x01\x12" "xxxxxxxxxxxxxxxxYY", 18); - memcpy(p+41, "\xff\xff\x00\x20", 4); - tt_int_op(-1, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, - p, sizeof(p))); /* Running out of space in specifiers */ memset(p,0,sizeof(p)); diff --git a/src/test/test_channel.c b/src/test/test_channel.c index 01aa01b4db..83b69cc80b 100644 --- a/src/test/test_channel.c +++ b/src/test/test_channel.c @@ -1321,7 +1321,7 @@ test_channel_for_extend(void *arg) channel_t *ret_chan = NULL; char digest[DIGEST_LEN]; ed25519_public_key_t ed_id; - tor_addr_t addr; + tor_addr_t ipv4_addr, ipv6_addr; const char *msg; int launch; time_t now = time(NULL); @@ -1331,6 +1331,9 @@ test_channel_for_extend(void *arg) memset(digest, 'A', sizeof(digest)); memset(&ed_id, 'B', sizeof(ed_id)); + tor_addr_make_null(&ipv4_addr, AF_INET); + tor_addr_make_null(&ipv6_addr, AF_INET6); + chan1 = new_fake_channel(); tt_assert(chan1); /* Need to be registered to get added to the id map. */ @@ -1364,7 +1367,8 @@ test_channel_for_extend(void *arg) tt_ptr_op(channel_find_by_remote_identity(digest, &ed_id), OP_EQ, chan1); /* The expected result is chan2 because it is older than chan1. */ - ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch); + ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr, + &msg, &launch); tt_assert(ret_chan); tt_ptr_op(ret_chan, OP_EQ, chan2); tt_int_op(launch, OP_EQ, 0); @@ -1372,16 +1376,18 @@ test_channel_for_extend(void *arg) /* Switch that around from previous test. */ chan2->timestamp_created = chan1->timestamp_created + 1; - ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch); + ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr, + &msg, &launch); tt_assert(ret_chan); tt_ptr_op(ret_chan, OP_EQ, chan1); tt_int_op(launch, OP_EQ, 0); tt_str_op(msg, OP_EQ, "Connection is fine; using it."); /* Same creation time, num circuits will be used and they both have 0 so the - * channel 2 should be picked due to how channel_is_better() work. */ + * channel 2 should be picked due to how channel_is_better() works. */ chan2->timestamp_created = chan1->timestamp_created; - ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch); + ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr, + &msg, &launch); tt_assert(ret_chan); tt_ptr_op(ret_chan, OP_EQ, chan1); tt_int_op(launch, OP_EQ, 0); @@ -1392,7 +1398,8 @@ test_channel_for_extend(void *arg) /* Condemned the older channel. */ chan1->state = CHANNEL_STATE_CLOSING; - ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch); + ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr, + &msg, &launch); tt_assert(ret_chan); tt_ptr_op(ret_chan, OP_EQ, chan2); tt_int_op(launch, OP_EQ, 0); @@ -1401,7 +1408,8 @@ test_channel_for_extend(void *arg) /* Make the older channel a client one. */ channel_mark_client(chan1); - ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch); + ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr, + &msg, &launch); tt_assert(ret_chan); tt_ptr_op(ret_chan, OP_EQ, chan2); tt_int_op(launch, OP_EQ, 0); @@ -1411,8 +1419,9 @@ test_channel_for_extend(void *arg) /* Non matching ed identity with valid digest. */ ed25519_public_key_t dumb_ed_id; memset(&dumb_ed_id, 0, sizeof(dumb_ed_id)); - ret_chan = channel_get_for_extend(digest, &dumb_ed_id, &addr, &msg, - &launch); + ret_chan = channel_get_for_extend(digest, &dumb_ed_id, + &ipv4_addr, &ipv6_addr, + &msg, &launch); tt_assert(!ret_chan); tt_str_op(msg, OP_EQ, "Not connected. Connecting."); tt_int_op(launch, OP_EQ, 1); @@ -1421,7 +1430,8 @@ test_channel_for_extend(void *arg) test_chan_should_match_target = 1; chan1->state = CHANNEL_STATE_OPENING; chan2->state = CHANNEL_STATE_OPENING; - ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch); + ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr, + &msg, &launch); tt_assert(!ret_chan); tt_str_op(msg, OP_EQ, "Connection in progress; waiting."); tt_int_op(launch, OP_EQ, 0); @@ -1430,7 +1440,8 @@ test_channel_for_extend(void *arg) /* Mark channel 1 as bad for circuits. */ channel_mark_bad_for_new_circs(chan1); - ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch); + ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr, + &msg, &launch); tt_assert(ret_chan); tt_ptr_op(ret_chan, OP_EQ, chan2); tt_int_op(launch, OP_EQ, 0); @@ -1440,7 +1451,8 @@ test_channel_for_extend(void *arg) /* Mark both channels as unusable. */ channel_mark_bad_for_new_circs(chan1); channel_mark_bad_for_new_circs(chan2); - ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch); + ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr, + &msg, &launch); tt_assert(!ret_chan); tt_str_op(msg, OP_EQ, "Connections all too old, or too non-canonical. " " Launching a new one."); @@ -1451,7 +1463,8 @@ test_channel_for_extend(void *arg) /* Non canonical channels. */ test_chan_should_be_canonical = 0; test_chan_should_match_target = 0; - ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch); + ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr, + &msg, &launch); tt_assert(!ret_chan); tt_str_op(msg, OP_EQ, "Connections all too old, or too non-canonical. " " Launching a new one."); diff --git a/src/test/test_channeltls.c b/src/test/test_channeltls.c index 94ce56f2be..f4f5cb447e 100644 --- a/src/test/test_channeltls.c +++ b/src/test/test_channeltls.c @@ -14,6 +14,7 @@ #include "core/mainloop/connection.h" #include "core/or/connection_or.h" #include "app/config/config.h" +#include "app/config/resolve_addr.h" /* For init/free stuff */ #include "core/or/scheduler.h" #include "lib/tls/tortls.h" diff --git a/src/test/test_circuitbuild.c b/src/test/test_circuitbuild.c index 70920c0c52..03fd176ead 100644 --- a/src/test/test_circuitbuild.c +++ b/src/test/test_circuitbuild.c @@ -8,18 +8,32 @@ #define ENTRYNODES_PRIVATE #include "core/or/or.h" + #include "test/test.h" #include "test/test_helpers.h" #include "test/log_test_helpers.h" + +#define CONFIG_PRIVATE #include "app/config/config.h" + +#include "core/or/channel.h" #include "core/or/circuitbuild.h" #include "core/or/circuitlist.h" +#include "core/or/onion.h" +#include "core/or/cell_st.h" #include "core/or/cpath_build_state_st.h" #include "core/or/extend_info_st.h" #include "core/or/origin_circuit_st.h" +#include "core/or/or_circuit_st.h" #include "feature/client/entrynodes.h" +#include "feature/nodelist/nodelist.h" +#include "feature/relay/circuitbuild_relay.h" +#include "feature/relay/router.h" +#include "feature/relay/routermode.h" + +#include "feature/nodelist/node_st.h" /* Dummy nodes smartlist for testing */ static smartlist_t dummy_nodes; @@ -114,6 +128,14 @@ test_new_route_len_unhandled_exit(void *arg) int r; (void)arg; +#ifdef ALL_BUGS_ARE_FATAL + /* Coverity (and maybe clang analyser) complain that the code following + * tt_skip() is unconditionally unreachable. */ +#if !defined(__COVERITY__) && !defined(__clang_analyzer__) + tt_skip(); +#endif +#endif /* defined(ALL_BUGS_ARE_FATAL) */ + MOCK(count_acceptable_nodes, mock_count_acceptable_nodes); tor_capture_bugs_(1); @@ -125,10 +147,10 @@ test_new_route_len_unhandled_exit(void *arg) "!(exit_ei && !known_purpose)"); expect_single_log_msg_containing("Unhandled purpose"); expect_single_log_msg_containing("with a chosen exit; assuming routelen"); - teardown_capture_of_logs(); - tor_end_capture_bugs_(); done: + teardown_capture_of_logs(); + tor_end_capture_bugs_(); UNMOCK(count_acceptable_nodes); } @@ -172,12 +194,1361 @@ test_upgrade_from_guard_wait(void *arg) entry_guard_free_(guard); } +static int server = 0; +static int +mock_server_mode(const or_options_t *options) +{ + (void)options; + return server; +} + +/* Test the different cases in circuit_extend_state_valid_helper(). */ +static void +test_circuit_extend_state_valid(void *arg) +{ + (void)arg; + circuit_t *circ = tor_malloc_zero(sizeof(circuit_t)); + + server = 0; + MOCK(server_mode, mock_server_mode); + + setup_full_capture_of_logs(LOG_INFO); + + /* Clients can't extend */ + server = 0; + tt_int_op(circuit_extend_state_valid_helper(NULL), OP_EQ, -1); + expect_log_msg("Got an extend cell, but running as a client. Closing.\n"); + mock_clean_saved_logs(); + +#ifndef ALL_BUGS_ARE_FATAL + /* Circuit must be non-NULL */ + tor_capture_bugs_(1); + server = 1; + tt_int_op(circuit_extend_state_valid_helper(NULL), OP_EQ, -1); + tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); + tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ, + "!(ASSERT_PREDICT_UNLIKELY_(!circ))"); + tor_end_capture_bugs_(); + mock_clean_saved_logs(); +#endif /* !defined(ALL_BUGS_ARE_FATAL) */ + + /* n_chan and n_hop are NULL, this should succeed */ + server = 1; + tt_int_op(circuit_extend_state_valid_helper(circ), OP_EQ, 0); + mock_clean_saved_logs(); + + /* But clients still can't extend */ + server = 0; + tt_int_op(circuit_extend_state_valid_helper(circ), OP_EQ, -1); + expect_log_msg("Got an extend cell, but running as a client. Closing.\n"); + mock_clean_saved_logs(); + + /* n_chan must be NULL */ + circ->n_chan = tor_malloc_zero(sizeof(channel_t)); + server = 1; + tt_int_op(circuit_extend_state_valid_helper(circ), OP_EQ, -1); + expect_log_msg("n_chan already set. Bug/attack. Closing.\n"); + mock_clean_saved_logs(); + tor_free(circ->n_chan); + + /* n_hop must be NULL */ + circ->n_hop = tor_malloc_zero(sizeof(extend_info_t)); + server = 1; + tt_int_op(circuit_extend_state_valid_helper(circ), OP_EQ, -1); + expect_log_msg("conn to next hop already launched. Bug/attack. Closing.\n"); + mock_clean_saved_logs(); + tor_free(circ->n_hop); + + done: + tor_end_capture_bugs_(); + teardown_capture_of_logs(); + + UNMOCK(server_mode); + server = 0; + + tor_free(circ->n_chan); + tor_free(circ->n_hop); + tor_free(circ); +} + +static node_t *mocked_node = NULL; +static const node_t * +mock_node_get_by_id(const char *identity_digest) +{ + (void)identity_digest; + return mocked_node; +} + +static int mocked_supports_ed25519_link_authentication = 0; +static int +mock_node_supports_ed25519_link_authentication(const node_t *node, + int compatible_with_us) +{ + (void)node; + (void)compatible_with_us; + return mocked_supports_ed25519_link_authentication; +} + +static ed25519_public_key_t * mocked_ed25519_id = NULL; +static const ed25519_public_key_t * +mock_node_get_ed25519_id(const node_t *node) +{ + (void)node; + return mocked_ed25519_id; +} + +/* Test the different cases in circuit_extend_add_ed25519_helper(). */ +static void +test_circuit_extend_add_ed25519(void *arg) +{ + (void)arg; + extend_cell_t *ec = tor_malloc_zero(sizeof(extend_cell_t)); + extend_cell_t *old_ec = tor_malloc_zero(sizeof(extend_cell_t)); + extend_cell_t *zero_ec = tor_malloc_zero(sizeof(extend_cell_t)); + + node_t *fake_node = tor_malloc_zero(sizeof(node_t)); + ed25519_public_key_t *fake_ed25519_id = NULL; + fake_ed25519_id = tor_malloc_zero(sizeof(ed25519_public_key_t)); + + MOCK(node_get_by_id, mock_node_get_by_id); + MOCK(node_supports_ed25519_link_authentication, + mock_node_supports_ed25519_link_authentication); + MOCK(node_get_ed25519_id, mock_node_get_ed25519_id); + + setup_full_capture_of_logs(LOG_INFO); + +#ifndef ALL_BUGS_ARE_FATAL + /* The extend cell must be non-NULL */ + tor_capture_bugs_(1); + tt_int_op(circuit_extend_add_ed25519_helper(NULL), OP_EQ, -1); + tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); + tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ, + "!(ASSERT_PREDICT_UNLIKELY_(!ec))"); + tor_end_capture_bugs_(); + mock_clean_saved_logs(); +#endif /* !defined(ALL_BUGS_ARE_FATAL) */ + + /* The node id must be non-zero */ + memcpy(old_ec, ec, sizeof(extend_cell_t)); + tt_int_op(circuit_extend_add_ed25519_helper(ec), OP_EQ, -1); + expect_log_msg( + "Client asked me to extend without specifying an id_digest.\n"); + /* And nothing should have changed */ + tt_mem_op(ec, OP_EQ, old_ec, sizeof(extend_cell_t)); + mock_clean_saved_logs(); + + /* Fill in fake node_id, and try again */ + memset(ec->node_id, 0xAA, sizeof(ec->node_id)); + memcpy(old_ec, ec, sizeof(extend_cell_t)); + tt_int_op(circuit_extend_add_ed25519_helper(ec), OP_EQ, 0); + /* There's no node with that id, so the ed pubkey should still be zeroed */ + tt_mem_op(&ec->ed_pubkey, OP_EQ, &zero_ec->ed_pubkey, sizeof(ec->ed_pubkey)); + /* In fact, nothing should have changed */ + tt_mem_op(ec, OP_EQ, old_ec, sizeof(extend_cell_t)); + mock_clean_saved_logs(); + + /* Provide 2 out of 3 of node, supports link auth, and ed_id. + * The ed_id should remain zeroed. */ + + /* Provide node and supports link auth */ + memset(ec->node_id, 0xAA, sizeof(ec->node_id)); + memcpy(old_ec, ec, sizeof(extend_cell_t)); + /* Set up the fake variables */ + mocked_node = fake_node; + mocked_supports_ed25519_link_authentication = 1; + /* Do the test */ + tt_int_op(circuit_extend_add_ed25519_helper(ec), OP_EQ, 0); + /* The ed pubkey should still be zeroed */ + tt_mem_op(&ec->ed_pubkey, OP_EQ, &zero_ec->ed_pubkey, sizeof(ec->ed_pubkey)); + /* In fact, nothing should have changed */ + tt_mem_op(ec, OP_EQ, old_ec, sizeof(extend_cell_t)); + /* Cleanup */ + mock_clean_saved_logs(); + mocked_node = NULL; + mocked_supports_ed25519_link_authentication = 0; + mocked_ed25519_id = NULL; + memset(fake_ed25519_id, 0x00, sizeof(ed25519_public_key_t)); + + /* Provide supports link auth and ed id */ + memset(ec->node_id, 0xAA, sizeof(ec->node_id)); + memcpy(old_ec, ec, sizeof(extend_cell_t)); + /* Set up the fake variables */ + mocked_supports_ed25519_link_authentication = 1; + memset(fake_ed25519_id, 0xEE, sizeof(ed25519_public_key_t)); + mocked_ed25519_id = fake_ed25519_id; + /* Do the test */ + tt_int_op(circuit_extend_add_ed25519_helper(ec), OP_EQ, 0); + /* The ed pubkey should still be zeroed */ + tt_mem_op(&ec->ed_pubkey, OP_EQ, &zero_ec->ed_pubkey, sizeof(ec->ed_pubkey)); + /* In fact, nothing should have changed */ + tt_mem_op(ec, OP_EQ, old_ec, sizeof(extend_cell_t)); + /* Cleanup */ + mock_clean_saved_logs(); + mocked_node = NULL; + mocked_supports_ed25519_link_authentication = 0; + mocked_ed25519_id = NULL; + memset(fake_ed25519_id, 0x00, sizeof(ed25519_public_key_t)); + + /* Provide node and ed id */ + memset(ec->node_id, 0xAA, sizeof(ec->node_id)); + memcpy(old_ec, ec, sizeof(extend_cell_t)); + /* Set up the fake variables */ + mocked_node = fake_node; + memset(fake_ed25519_id, 0xEE, sizeof(ed25519_public_key_t)); + mocked_ed25519_id = fake_ed25519_id; + /* Do the test */ + tt_int_op(circuit_extend_add_ed25519_helper(ec), OP_EQ, 0); + /* The ed pubkey should still be zeroed */ + tt_mem_op(&ec->ed_pubkey, OP_EQ, &zero_ec->ed_pubkey, sizeof(ec->ed_pubkey)); + /* In fact, nothing should have changed */ + tt_mem_op(ec, OP_EQ, old_ec, sizeof(extend_cell_t)); + /* Cleanup */ + mock_clean_saved_logs(); + mocked_node = NULL; + mocked_supports_ed25519_link_authentication = 0; + mocked_ed25519_id = NULL; + memset(fake_ed25519_id, 0x00, sizeof(ed25519_public_key_t)); + + /* Now do the real lookup */ + memset(ec->node_id, 0xAA, sizeof(ec->node_id)); + memcpy(old_ec, ec, sizeof(extend_cell_t)); + /* Set up the fake variables */ + mocked_node = fake_node; + mocked_supports_ed25519_link_authentication = 1; + memset(fake_ed25519_id, 0xEE, sizeof(ed25519_public_key_t)); + mocked_ed25519_id = fake_ed25519_id; + /* Do the test */ + tt_int_op(circuit_extend_add_ed25519_helper(ec), OP_EQ, 0); + /* The ed pubkey should match */ + tt_mem_op(&ec->ed_pubkey, OP_EQ, fake_ed25519_id, sizeof(ec->ed_pubkey)); + /* Nothing else should have changed */ + memcpy(&ec->ed_pubkey, &old_ec->ed_pubkey, sizeof(ec->ed_pubkey)); + tt_mem_op(ec, OP_EQ, old_ec, sizeof(extend_cell_t)); + /* Cleanup */ + mock_clean_saved_logs(); + mocked_node = NULL; + mocked_supports_ed25519_link_authentication = 0; + mocked_ed25519_id = NULL; + memset(fake_ed25519_id, 0x00, sizeof(ed25519_public_key_t)); + + /* Now do the real lookup, but with a zeroed ed id */ + memset(ec->node_id, 0xAA, sizeof(ec->node_id)); + memcpy(old_ec, ec, sizeof(extend_cell_t)); + /* Set up the fake variables */ + mocked_node = fake_node; + mocked_supports_ed25519_link_authentication = 1; + memset(fake_ed25519_id, 0x00, sizeof(ed25519_public_key_t)); + mocked_ed25519_id = fake_ed25519_id; + /* Do the test */ + tt_int_op(circuit_extend_add_ed25519_helper(ec), OP_EQ, 0); + /* The ed pubkey should match */ + tt_mem_op(&ec->ed_pubkey, OP_EQ, fake_ed25519_id, sizeof(ec->ed_pubkey)); + /* Nothing else should have changed */ + memcpy(&ec->ed_pubkey, &old_ec->ed_pubkey, sizeof(ec->ed_pubkey)); + tt_mem_op(ec, OP_EQ, old_ec, sizeof(extend_cell_t)); + /* Cleanup */ + mock_clean_saved_logs(); + mocked_node = NULL; + mocked_supports_ed25519_link_authentication = 0; + mocked_ed25519_id = NULL; + memset(fake_ed25519_id, 0x00, sizeof(ed25519_public_key_t)); + + done: + UNMOCK(node_get_by_id); + UNMOCK(node_supports_ed25519_link_authentication); + UNMOCK(node_get_ed25519_id); + + tor_end_capture_bugs_(); + teardown_capture_of_logs(); + + tor_free(ec); + tor_free(old_ec); + tor_free(zero_ec); + + tor_free(fake_ed25519_id); + tor_free(fake_node); +} + +static or_options_t *mocked_options = NULL; +static const or_options_t * +mock_get_options(void) +{ + return mocked_options; +} + +#define PUBLIC_IPV4 "1.2.3.4" +#define INTERNAL_IPV4 "0.0.0.1" + +#define PUBLIC_IPV6 "1234::cdef" +#define INTERNAL_IPV6 "::1" + +#define VALID_PORT 0x1234 + +/* Test the different cases in circuit_extend_lspec_valid_helper(). */ +static void +test_circuit_extend_lspec_valid(void *arg) +{ + (void)arg; + extend_cell_t *ec = tor_malloc_zero(sizeof(extend_cell_t)); + channel_t *p_chan = tor_malloc_zero(sizeof(channel_t)); + or_circuit_t *or_circ = tor_malloc_zero(sizeof(or_circuit_t)); + circuit_t *circ = TO_CIRCUIT(or_circ); + + or_options_t *fake_options = options_new(); + MOCK(get_options, mock_get_options); + mocked_options = fake_options; + + setup_full_capture_of_logs(LOG_INFO); + +#ifndef ALL_BUGS_ARE_FATAL + /* Extend cell must be non-NULL */ + tor_capture_bugs_(1); + tt_int_op(circuit_extend_lspec_valid_helper(NULL, circ), OP_EQ, -1); + tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); + tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ, + "!(ASSERT_PREDICT_UNLIKELY_(!ec))"); + tor_end_capture_bugs_(); + mock_clean_saved_logs(); + + /* Circuit must be non-NULL */ + tor_capture_bugs_(1); + tt_int_op(circuit_extend_lspec_valid_helper(ec, NULL), OP_EQ, -1); + tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); + tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ, + "!(ASSERT_PREDICT_UNLIKELY_(!circ))"); + tor_end_capture_bugs_(); + mock_clean_saved_logs(); + + /* Extend cell and circuit must be non-NULL */ + tor_capture_bugs_(1); + tt_int_op(circuit_extend_lspec_valid_helper(NULL, NULL), OP_EQ, -1); + /* Since we're using IF_BUG_ONCE(), we might not log any bugs */ + tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_GE, 0); + tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_LE, 2); + tor_end_capture_bugs_(); + mock_clean_saved_logs(); +#endif /* !defined(ALL_BUGS_ARE_FATAL) */ + + /* IPv4 and IPv6 addr and port are all zero, this should fail */ + tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1); + expect_log_msg("Client asked me to extend to a zero destination port " + "or unspecified address '[scrubbed]'.\n"); + mock_clean_saved_logs(); + + /* Now ask for the actual address in the logs */ + fake_options->SafeLogging_ = SAFELOG_SCRUB_NONE; + + /* IPv4 port is 0, IPv6 addr and port are both zero, this should fail */ + tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4); + tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1); + expect_log_msg("Client asked me to extend to a zero destination port " + "or IPv4 address '1.2.3.4:0'.\n"); + mock_clean_saved_logs(); + tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET); + tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6); + + /* IPv4 addr is 0, IPv6 addr and port are both zero, this should fail */ + ec->orport_ipv4.port = VALID_PORT; + tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1); + expect_log_msg("Client asked me to extend to a zero destination port " + "or IPv4 address '0.0.0.0:4660'.\n"); + mock_clean_saved_logs(); + ec->orport_ipv4.port = 0; + tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET); + tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6); + + /* IPv4 addr is internal, and port is valid. + * (IPv6 addr and port are both zero.) + * Result depends on ExtendAllowPrivateAddresses. */ + tor_addr_parse(&ec->orport_ipv4.addr, INTERNAL_IPV4); + ec->orport_ipv4.port = VALID_PORT; + + fake_options->ExtendAllowPrivateAddresses = 0; + tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1); + expect_log_msg("Client asked me to extend " + "to a private IPv4 address '0.0.0.1'.\n"); + mock_clean_saved_logs(); + fake_options->ExtendAllowPrivateAddresses = 0; + tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET); + tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6); + + /* Now do the same tests, but for IPv6 */ + + /* IPv6 port is 0, IPv4 addr and port are both zero, this should fail */ + tor_addr_parse(&ec->orport_ipv6.addr, PUBLIC_IPV6); + tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1); + expect_log_msg("Client asked me to extend to a zero destination port " + "or IPv6 address '[1234::cdef]:0'.\n"); + mock_clean_saved_logs(); + tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET); + tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6); + + /* IPv6 addr is 0, IPv4 addr and port are both zero, this should fail */ + ec->orport_ipv6.port = VALID_PORT; + tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1); + expect_log_msg("Client asked me to extend to a zero destination port " + "or IPv6 address '[::]:4660'.\n"); + mock_clean_saved_logs(); + ec->orport_ipv4.port = 0; + tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET); + tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6); + + /* IPv6 addr is internal, and port is valid. + * (IPv4 addr and port are both zero.) + * Result depends on ExtendAllowPrivateAddresses. */ + tor_addr_parse(&ec->orport_ipv6.addr, INTERNAL_IPV6); + ec->orport_ipv6.port = VALID_PORT; + + fake_options->ExtendAllowPrivateAddresses = 0; + tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1); + expect_log_msg("Client asked me to extend " + "to a private IPv6 address '[::1]'.\n"); + mock_clean_saved_logs(); + fake_options->ExtendAllowPrivateAddresses = 0; + tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET); + tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6); + + /* Both addresses are internal. + * Result depends on ExtendAllowPrivateAddresses. */ + tor_addr_parse(&ec->orport_ipv4.addr, INTERNAL_IPV4); + ec->orport_ipv4.port = VALID_PORT; + tor_addr_parse(&ec->orport_ipv6.addr, INTERNAL_IPV6); + ec->orport_ipv6.port = VALID_PORT; + + fake_options->ExtendAllowPrivateAddresses = 0; + tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1); + expect_log_msg("Client asked me to extend " + "to a private IPv4 address '0.0.0.1'.\n"); + expect_log_msg("Client asked me to extend " + "to a private IPv6 address '[::1]'.\n"); + mock_clean_saved_logs(); + fake_options->ExtendAllowPrivateAddresses = 0; + tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET); + tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6); + +#ifndef ALL_BUGS_ARE_FATAL + /* If we pass the private address check, but don't have the right + * OR circuit magic number, we trigger another bug */ + tor_addr_parse(&ec->orport_ipv4.addr, INTERNAL_IPV4); + ec->orport_ipv4.port = VALID_PORT; + tor_addr_parse(&ec->orport_ipv6.addr, INTERNAL_IPV6); + ec->orport_ipv6.port = VALID_PORT; + fake_options->ExtendAllowPrivateAddresses = 1; + + tor_capture_bugs_(1); + tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1); + tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); + tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ, + "!(ASSERT_PREDICT_UNLIKELY_(circ->magic != 0x98ABC04Fu))"); + tor_end_capture_bugs_(); + mock_clean_saved_logs(); + fake_options->ExtendAllowPrivateAddresses = 0; + tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET); + tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6); + + /* Fail again, but this time only set an IPv4 address. */ + tor_addr_parse(&ec->orport_ipv4.addr, INTERNAL_IPV4); + ec->orport_ipv4.port = VALID_PORT; + fake_options->ExtendAllowPrivateAddresses = 1; + tor_capture_bugs_(1); + tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1); + /* Since we're using IF_BUG_ONCE(), expect 0-1 bug logs */ + tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_GE, 0); + tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_LE, 1); + tor_end_capture_bugs_(); + mock_clean_saved_logs(); + fake_options->ExtendAllowPrivateAddresses = 0; +#endif /* !defined(ALL_BUGS_ARE_FATAL) */ + + /* Now set the right magic */ + or_circ->base_.magic = OR_CIRCUIT_MAGIC; + +#ifndef ALL_BUGS_ARE_FATAL + /* If we pass the OR circuit magic check, but don't have p_chan, + * we trigger another bug */ + fake_options->ExtendAllowPrivateAddresses = 1; + tor_capture_bugs_(1); + tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1); + tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); + tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ, + "!(ASSERT_PREDICT_UNLIKELY_(!p_chan))"); + tor_end_capture_bugs_(); + mock_clean_saved_logs(); + fake_options->ExtendAllowPrivateAddresses = 0; + + /* We can also pass the OR circuit magic check with a public address */ + tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4); + fake_options->ExtendAllowPrivateAddresses = 0; + tor_capture_bugs_(1); + tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1); + /* Since we're using IF_BUG_ONCE(), expect 0-1 bug logs */ + tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_GE, 0); + tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_LE, 1); + tor_end_capture_bugs_(); + mock_clean_saved_logs(); + fake_options->ExtendAllowPrivateAddresses = 0; + + tor_addr_make_null(&ec->orport_ipv4.addr, AF_INET); + ec->orport_ipv4.port = 0x0000; +#endif /* !defined(ALL_BUGS_ARE_FATAL) */ + + /* Now let's fake a p_chan and the addresses */ + tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4); + ec->orport_ipv4.port = VALID_PORT; + or_circ->p_chan = p_chan; + + /* This is a trivial failure: node_id and p_chan->identity_digest are both + * zeroed */ + tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1); + expect_log_msg("Client asked me to extend back to the previous hop.\n"); + mock_clean_saved_logs(); + + /* Let's check with non-zero identities as well */ + memset(ec->node_id, 0xAA, sizeof(ec->node_id)); + memset(p_chan->identity_digest, 0xAA, sizeof(p_chan->identity_digest)); + + tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1); + expect_log_msg("Client asked me to extend back to the previous hop.\n"); + mock_clean_saved_logs(); + + memset(ec->node_id, 0, sizeof(ec->node_id)); + memset(p_chan->identity_digest, 0, sizeof(p_chan->identity_digest)); + + /* Let's pass the node_id test */ + memset(ec->node_id, 0xAA, sizeof(ec->node_id)); + memset(p_chan->identity_digest, 0xBB, sizeof(p_chan->identity_digest)); + + /* ed_pubkey is zero, and that's allowed, so we should succeed */ + tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, 0); + mock_clean_saved_logs(); + + /* Now let's check that we warn, but succeed, when only one address is + * private */ + tor_addr_parse(&ec->orport_ipv4.addr, INTERNAL_IPV4); + ec->orport_ipv4.port = VALID_PORT; + tor_addr_parse(&ec->orport_ipv6.addr, PUBLIC_IPV6); + ec->orport_ipv6.port = VALID_PORT; + fake_options->ExtendAllowPrivateAddresses = 0; + + tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, 0); + expect_log_msg("Client asked me to extend " + "to a private IPv4 address '0.0.0.1'.\n"); + mock_clean_saved_logs(); + tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET); + tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6); + + /* Now with private IPv6 */ + tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4); + ec->orport_ipv4.port = VALID_PORT; + tor_addr_parse(&ec->orport_ipv6.addr, INTERNAL_IPV6); + ec->orport_ipv6.port = VALID_PORT; + fake_options->ExtendAllowPrivateAddresses = 0; + + tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, 0); + expect_log_msg("Client asked me to extend " + "to a private IPv6 address '[::1]'.\n"); + mock_clean_saved_logs(); + tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET); + tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6); + + /* Now reset to public IPv4 and IPv6 */ + tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4); + ec->orport_ipv4.port = VALID_PORT; + tor_addr_parse(&ec->orport_ipv6.addr, PUBLIC_IPV6); + ec->orport_ipv6.port = VALID_PORT; + + /* Fail on matching non-zero identities */ + memset(&ec->ed_pubkey, 0xEE, sizeof(ec->ed_pubkey)); + memset(&p_chan->ed25519_identity, 0xEE, sizeof(p_chan->ed25519_identity)); + + tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1); + expect_log_msg("Client asked me to extend back to the previous hop " + "(by Ed25519 ID).\n"); + mock_clean_saved_logs(); + + memset(&ec->ed_pubkey, 0, sizeof(ec->ed_pubkey)); + memset(&p_chan->ed25519_identity, 0, sizeof(p_chan->ed25519_identity)); + + /* Succeed on different, non-zero identities */ + memset(&ec->ed_pubkey, 0xDD, sizeof(ec->ed_pubkey)); + memset(&p_chan->ed25519_identity, 0xEE, sizeof(p_chan->ed25519_identity)); + + tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, 0); + mock_clean_saved_logs(); + + memset(&ec->ed_pubkey, 0, sizeof(ec->ed_pubkey)); + memset(&p_chan->ed25519_identity, 0, sizeof(p_chan->ed25519_identity)); + + /* Succeed if the client knows the identity, but we don't */ + memset(&ec->ed_pubkey, 0xDD, sizeof(ec->ed_pubkey)); + memset(&p_chan->ed25519_identity, 0x00, sizeof(p_chan->ed25519_identity)); + + tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, 0); + mock_clean_saved_logs(); + + memset(&ec->ed_pubkey, 0, sizeof(ec->ed_pubkey)); + memset(&p_chan->ed25519_identity, 0, sizeof(p_chan->ed25519_identity)); + + /* Succeed if we know the identity, but the client doesn't */ + memset(&ec->ed_pubkey, 0x00, sizeof(ec->ed_pubkey)); + memset(&p_chan->ed25519_identity, 0xEE, sizeof(p_chan->ed25519_identity)); + + tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, 0); + mock_clean_saved_logs(); + + memset(&ec->ed_pubkey, 0, sizeof(ec->ed_pubkey)); + memset(&p_chan->ed25519_identity, 0, sizeof(p_chan->ed25519_identity)); + + /* Cleanup the node ids */ + memset(ec->node_id, 0, sizeof(ec->node_id)); + memset(p_chan->identity_digest, 0, sizeof(p_chan->identity_digest)); + + /* Cleanup the p_chan and the addresses */ + tor_addr_make_null(&ec->orport_ipv4.addr, AF_UNSPEC); + ec->orport_ipv4.port = 0; + or_circ->p_chan = NULL; + + done: + tor_end_capture_bugs_(); + teardown_capture_of_logs(); + + UNMOCK(get_options); + or_options_free(fake_options); + mocked_options = NULL; + + tor_free(ec); + tor_free(or_circ); + tor_free(p_chan); +} + +static bool can_extend_over_ipv6_result = false; +static int mock_router_can_extend_over_ipv6_calls = 0; +static bool +mock_router_can_extend_over_ipv6(const or_options_t *options) +{ + (void)options; + mock_router_can_extend_over_ipv6_calls++; + return can_extend_over_ipv6_result; +} + +/* Test the different cases in circuit_choose_ip_ap_for_extend(). */ +static void +test_circuit_choose_ip_ap_for_extend(void *arg) +{ + (void)arg; + tor_addr_port_t ipv4_ap; + tor_addr_port_t ipv6_ap; + + /* Set up valid addresses */ + tor_addr_parse(&ipv4_ap.addr, PUBLIC_IPV4); + ipv4_ap.port = VALID_PORT; + tor_addr_parse(&ipv6_ap.addr, PUBLIC_IPV6); + ipv6_ap.port = VALID_PORT; + + or_options_t *fake_options = options_new(); + MOCK(get_options, mock_get_options); + mocked_options = fake_options; + + MOCK(router_can_extend_over_ipv6, + mock_router_can_extend_over_ipv6); + can_extend_over_ipv6_result = true; + mock_router_can_extend_over_ipv6_calls = 0; + + /* No valid addresses */ + can_extend_over_ipv6_result = true; + mock_router_can_extend_over_ipv6_calls = 0; + tt_ptr_op(circuit_choose_ip_ap_for_extend(NULL, NULL), OP_EQ, NULL); + tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1); + + can_extend_over_ipv6_result = false; + mock_router_can_extend_over_ipv6_calls = 0; + tt_ptr_op(circuit_choose_ip_ap_for_extend(NULL, NULL), OP_EQ, NULL); + tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1); + + /* One valid address: IPv4 */ + can_extend_over_ipv6_result = true; + mock_router_can_extend_over_ipv6_calls = 0; + tt_ptr_op(circuit_choose_ip_ap_for_extend(&ipv4_ap, NULL), OP_EQ, &ipv4_ap); + tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1); + + can_extend_over_ipv6_result = false; + mock_router_can_extend_over_ipv6_calls = 0; + tt_ptr_op(circuit_choose_ip_ap_for_extend(&ipv4_ap, NULL), OP_EQ, &ipv4_ap); + tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1); + + /* One valid address: IPv6 */ + can_extend_over_ipv6_result = true; + mock_router_can_extend_over_ipv6_calls = 0; + tt_ptr_op(circuit_choose_ip_ap_for_extend(NULL, &ipv6_ap), OP_EQ, &ipv6_ap); + tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1); + + can_extend_over_ipv6_result = false; + mock_router_can_extend_over_ipv6_calls = 0; + tt_ptr_op(circuit_choose_ip_ap_for_extend(NULL, &ipv6_ap), OP_EQ, NULL); + tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1); + + /* Two valid addresses */ + const tor_addr_port_t *chosen_addr = NULL; + + can_extend_over_ipv6_result = true; + mock_router_can_extend_over_ipv6_calls = 0; + chosen_addr = circuit_choose_ip_ap_for_extend(&ipv4_ap, &ipv6_ap); + tt_assert(chosen_addr == &ipv4_ap || chosen_addr == &ipv6_ap); + tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1); + + can_extend_over_ipv6_result = false; + mock_router_can_extend_over_ipv6_calls = 0; + tt_ptr_op(circuit_choose_ip_ap_for_extend(&ipv4_ap, &ipv6_ap), + OP_EQ, &ipv4_ap); + tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1); + + done: + UNMOCK(get_options); + or_options_free(fake_options); + mocked_options = NULL; + + UNMOCK(router_can_extend_over_ipv6); + + tor_free(fake_options); +} + +static int mock_circuit_close_calls = 0; +static void +mock_circuit_mark_for_close_(circuit_t *circ, int reason, + int line, const char *cfile) +{ + (void)circ; + (void)reason; + (void)line; + (void)cfile; + mock_circuit_close_calls++; +} + +static int mock_channel_connect_calls = 0; +static channel_t *mock_channel_connect_nchan = NULL; +static channel_t * +mock_channel_connect_for_circuit(const tor_addr_t *addr, + uint16_t port, + const char *id_digest, + const struct ed25519_public_key_t *ed_id) +{ + (void)addr; + (void)port; + (void)id_digest; + (void)ed_id; + mock_channel_connect_calls++; + return mock_channel_connect_nchan; +} + +/* Test the different cases in circuit_open_connection_for_extend(). + * Chooses different IP addresses depending on the first character in arg: + * - 4: IPv4 + * - 6: IPv6 + * - d: IPv4 and IPv6 (dual-stack) + */ +static void +test_circuit_open_connection_for_extend(void *arg) +{ + const char ip_version = ((const char *)arg)[0]; + const bool use_ipv4 = (ip_version == '4' || ip_version == 'd'); + const bool use_ipv6 = (ip_version == '6' || ip_version == 'd'); + tor_assert(use_ipv4 || use_ipv6); + + extend_cell_t *ec = tor_malloc_zero(sizeof(extend_cell_t)); + circuit_t *circ = tor_malloc_zero(sizeof(circuit_t)); + channel_t *fake_n_chan = tor_malloc_zero(sizeof(channel_t)); + + or_options_t *fake_options = options_new(); + MOCK(get_options, mock_get_options); + mocked_options = fake_options; + + MOCK(circuit_mark_for_close_, mock_circuit_mark_for_close_); + mock_circuit_close_calls = 0; + MOCK(channel_connect_for_circuit, mock_channel_connect_for_circuit); + mock_channel_connect_calls = 0; + mock_channel_connect_nchan = NULL; + + MOCK(router_can_extend_over_ipv6, + mock_router_can_extend_over_ipv6); + can_extend_over_ipv6_result = true; + + setup_full_capture_of_logs(LOG_INFO); + +#ifndef ALL_BUGS_ARE_FATAL + /* Circuit must be non-NULL */ + mock_circuit_close_calls = 0; + mock_channel_connect_calls = 0; + tor_capture_bugs_(1); + circuit_open_connection_for_extend(ec, NULL, 0); + /* We can't close a NULL circuit */ + tt_int_op(mock_circuit_close_calls, OP_EQ, 0); + tt_int_op(mock_channel_connect_calls, OP_EQ, 0); + tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); + tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ, + "!(ASSERT_PREDICT_UNLIKELY_(!circ))"); + tor_end_capture_bugs_(); + mock_clean_saved_logs(); + + /* Extend cell must be non-NULL */ + mock_circuit_close_calls = 0; + mock_channel_connect_calls = 0; + tor_capture_bugs_(1); + circuit_open_connection_for_extend(NULL, circ, 0); + tt_int_op(mock_circuit_close_calls, OP_EQ, 1); + tt_int_op(mock_channel_connect_calls, OP_EQ, 0); + tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); + tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ, + "!(ASSERT_PREDICT_UNLIKELY_(!ec))"); + tor_end_capture_bugs_(); + mock_clean_saved_logs(); + + /* Extend cell and circuit must be non-NULL */ + mock_circuit_close_calls = 0; + mock_channel_connect_calls = 0; + tor_capture_bugs_(1); + circuit_open_connection_for_extend(NULL, NULL, 0); + /* We can't close a NULL circuit */ + tt_int_op(mock_circuit_close_calls, OP_EQ, 0); + tt_int_op(mock_channel_connect_calls, OP_EQ, 0); + /* Since we're using IF_BUG_ONCE(), we might not log any bugs */ + tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_GE, 0); + tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_LE, 2); + tor_end_capture_bugs_(); + mock_clean_saved_logs(); + + /* Fail, because neither address is valid */ + mock_circuit_close_calls = 0; + mock_channel_connect_calls = 0; + tor_capture_bugs_(1); + circuit_open_connection_for_extend(ec, circ, 0); + /* Close the circuit, don't connect */ + tt_int_op(mock_circuit_close_calls, OP_EQ, 1); + tt_int_op(mock_channel_connect_calls, OP_EQ, 0); + /* Check state */ + tt_ptr_op(circ->n_hop, OP_EQ, NULL); + tt_ptr_op(circ->n_chan_create_cell, OP_EQ, NULL); + tt_int_op(circ->state, OP_EQ, 0); + /* Cleanup */ + tor_end_capture_bugs_(); + mock_clean_saved_logs(); +#endif /* !defined(ALL_BUGS_ARE_FATAL) */ + + /* Set up valid addresses */ + if (use_ipv4) { + tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4); + ec->orport_ipv4.port = VALID_PORT; + } + if (use_ipv6) { + tor_addr_parse(&ec->orport_ipv6.addr, PUBLIC_IPV6); + ec->orport_ipv6.port = VALID_PORT; + } + + /* Succeed, but don't try to open a connection */ + mock_circuit_close_calls = 0; + mock_channel_connect_calls = 0; + circuit_open_connection_for_extend(ec, circ, 0); + /* If we haven't closed the circuit, that's success */ + tt_int_op(mock_circuit_close_calls, OP_EQ, 0); + tt_int_op(mock_channel_connect_calls, OP_EQ, 0); + /* Check state */ + tt_ptr_op(circ->n_hop, OP_NE, NULL); + tt_ptr_op(circ->n_chan_create_cell, OP_NE, NULL); + tt_int_op(circ->state, OP_EQ, CIRCUIT_STATE_CHAN_WAIT); + /* Cleanup */ + mock_clean_saved_logs(); + tor_free(circ->n_hop); + tor_free(circ->n_chan_create_cell); + circ->state = 0; + + /* Try to open a connection, but fail with a NULL n_chan */ + mock_circuit_close_calls = 0; + mock_channel_connect_calls = 0; + circuit_open_connection_for_extend(ec, circ, 1); + /* Try to connect, but fail, and close the circuit */ + tt_int_op(mock_circuit_close_calls, OP_EQ, 1); + tt_int_op(mock_channel_connect_calls, OP_EQ, 1); + expect_log_msg("Launching n_chan failed. Closing circuit.\n"); + /* Check state */ + tt_ptr_op(circ->n_hop, OP_NE, NULL); + tt_ptr_op(circ->n_chan_create_cell, OP_NE, NULL); + tt_int_op(circ->state, OP_EQ, CIRCUIT_STATE_CHAN_WAIT); + /* Cleanup */ + mock_clean_saved_logs(); + tor_free(circ->n_hop); + tor_free(circ->n_chan_create_cell); + circ->state = 0; + + /* Try to open a connection, and succeed, because n_chan is not NULL */ + mock_channel_connect_nchan = fake_n_chan; + mock_circuit_close_calls = 0; + mock_channel_connect_calls = 0; + circuit_open_connection_for_extend(ec, circ, 1); + /* Connection attempt succeeded, leaving the circuit open */ + tt_int_op(mock_circuit_close_calls, OP_EQ, 0); + tt_int_op(mock_channel_connect_calls, OP_EQ, 1); + /* Check state */ + tt_ptr_op(circ->n_hop, OP_NE, NULL); + tt_ptr_op(circ->n_chan_create_cell, OP_NE, NULL); + tt_int_op(circ->state, OP_EQ, CIRCUIT_STATE_CHAN_WAIT); + /* Cleanup */ + mock_clean_saved_logs(); + tor_free(circ->n_hop); + tor_free(circ->n_chan_create_cell); + circ->state = 0; + mock_channel_connect_nchan = NULL; + + done: + tor_end_capture_bugs_(); + teardown_capture_of_logs(); + + UNMOCK(circuit_mark_for_close_); + mock_circuit_close_calls = 0; + UNMOCK(channel_connect_for_circuit); + mock_channel_connect_calls = 0; + + UNMOCK(get_options); + or_options_free(fake_options); + mocked_options = NULL; + + UNMOCK(router_can_extend_over_ipv6); + + tor_free(ec); + tor_free(circ->n_hop); + tor_free(circ->n_chan_create_cell); + tor_free(circ); + tor_free(fake_n_chan); +} + +/* Guaranteed to be initialised to zero. */ +static extend_cell_t mock_extend_cell_parse_cell_out; +static int mock_extend_cell_parse_result = 0; +static int mock_extend_cell_parse_calls = 0; + +static int +mock_extend_cell_parse(extend_cell_t *cell_out, + const uint8_t command, + const uint8_t *payload_in, + size_t payload_len) +{ + (void)command; + (void)payload_in; + (void)payload_len; + + mock_extend_cell_parse_calls++; + memcpy(cell_out, &mock_extend_cell_parse_cell_out, + sizeof(extend_cell_t)); + return mock_extend_cell_parse_result; +} + +static int mock_channel_get_for_extend_calls = 0; +static int mock_channel_get_for_extend_launch_out = 0; +static channel_t *mock_channel_get_for_extend_nchan = NULL; +static channel_t * +mock_channel_get_for_extend(const char *rsa_id_digest, + const ed25519_public_key_t *ed_id, + const tor_addr_t *target_ipv4_addr, + const tor_addr_t *target_ipv6_addr, + const char **msg_out, + int *launch_out) +{ + (void)rsa_id_digest; + (void)ed_id; + (void)target_ipv4_addr; + (void)target_ipv6_addr; + + /* channel_get_for_extend() requires non-NULL arguments */ + tt_ptr_op(msg_out, OP_NE, NULL); + tt_ptr_op(launch_out, OP_NE, NULL); + + mock_channel_get_for_extend_calls++; + *msg_out = NULL; + *launch_out = mock_channel_get_for_extend_launch_out; + return mock_channel_get_for_extend_nchan; + + done: + return NULL; +} + +static const char * +mock_channel_get_canonical_remote_descr(channel_t *chan) +{ + (void)chan; + return "mock_channel_get_canonical_remote_descr()"; +} + +static int mock_circuit_deliver_create_cell_calls = 0; +static int mock_circuit_deliver_create_cell_result = 0; +static int +mock_circuit_deliver_create_cell(circuit_t *circ, + const struct create_cell_t *create_cell, + int relayed) +{ + (void)create_cell; + + /* circuit_deliver_create_cell() requires non-NULL arguments, + * but we only check circ and circ->n_chan here. */ + tt_ptr_op(circ, OP_NE, NULL); + tt_ptr_op(circ->n_chan, OP_NE, NULL); + + /* We should only ever get relayed cells from extends */ + tt_int_op(relayed, OP_EQ, 1); + + mock_circuit_deliver_create_cell_calls++; + return mock_circuit_deliver_create_cell_result; + + done: + return -1; +} + +/* Test the different cases in circuit_extend(). */ +static void +test_circuit_extend(void *arg) +{ + (void)arg; + cell_t *cell = tor_malloc_zero(sizeof(cell_t)); + channel_t *p_chan = tor_malloc_zero(sizeof(channel_t)); + or_circuit_t *or_circ = tor_malloc_zero(sizeof(or_circuit_t)); + circuit_t *circ = TO_CIRCUIT(or_circ); + channel_t *fake_n_chan = tor_malloc_zero(sizeof(channel_t)); + + server = 0; + MOCK(server_mode, mock_server_mode); + + /* Mock a debug function, but otherwise ignore it */ + MOCK(channel_get_canonical_remote_descr, + mock_channel_get_canonical_remote_descr); + + setup_full_capture_of_logs(LOG_INFO); + +#ifndef ALL_BUGS_ARE_FATAL + /* Circuit must be non-NULL */ + tor_capture_bugs_(1); + tt_int_op(circuit_extend(cell, NULL), OP_EQ, -1); + tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); + tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ, + "!(ASSERT_PREDICT_UNLIKELY_(!circ))"); + tor_end_capture_bugs_(); + mock_clean_saved_logs(); + + /* Cell must be non-NULL */ + tor_capture_bugs_(1); + tt_int_op(circuit_extend(NULL, circ), OP_EQ, -1); + tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); + tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ, + "!(ASSERT_PREDICT_UNLIKELY_(!cell))"); + tor_end_capture_bugs_(); + mock_clean_saved_logs(); + + /* Extend cell and circuit must be non-NULL */ + tor_capture_bugs_(1); + tt_int_op(circuit_extend(NULL, NULL), OP_EQ, -1); + /* Since we're using IF_BUG_ONCE(), we might not log any bugs */ + tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_GE, 0); + tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_LE, 2); + tor_end_capture_bugs_(); + mock_clean_saved_logs(); +#endif /* !defined(ALL_BUGS_ARE_FATAL) */ + + /* Clients can't extend */ + server = 0; + tt_int_op(circuit_extend(cell, circ), OP_EQ, -1); + expect_log_msg("Got an extend cell, but running as a client. Closing.\n"); + mock_clean_saved_logs(); + + /* But servers can. Unpack the cell, but fail parsing. */ + server = 1; + tt_int_op(circuit_extend(cell, circ), OP_EQ, -1); + expect_log_msg("Can't parse extend cell. Closing circuit.\n"); + mock_clean_saved_logs(); + + /* Now mock parsing */ + MOCK(extend_cell_parse, mock_extend_cell_parse); + + /* And make parsing succeed, but fail on adding ed25519 */ + memset(&mock_extend_cell_parse_cell_out, 0, + sizeof(mock_extend_cell_parse_cell_out)); + mock_extend_cell_parse_result = 0; + mock_extend_cell_parse_calls = 0; + + tt_int_op(circuit_extend(cell, circ), OP_EQ, -1); + tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1); + expect_log_msg( + "Client asked me to extend without specifying an id_digest.\n"); + mock_clean_saved_logs(); + mock_extend_cell_parse_calls = 0; + + /* Now add a node_id. Fail the lspec check because IPv4 and port are zero. */ + memset(&mock_extend_cell_parse_cell_out.node_id, 0xAA, + sizeof(mock_extend_cell_parse_cell_out.node_id)); + + tt_int_op(circuit_extend(cell, circ), OP_EQ, -1); + tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1); + expect_log_msg("Client asked me to extend to a zero destination port " + "or unspecified address '[scrubbed]'.\n"); + mock_clean_saved_logs(); + mock_extend_cell_parse_calls = 0; + + /* Now add a valid IPv4 and port. Fail the OR circuit magic check. */ + tor_addr_parse(&mock_extend_cell_parse_cell_out.orport_ipv4.addr, + PUBLIC_IPV4); + mock_extend_cell_parse_cell_out.orport_ipv4.port = VALID_PORT; + +#ifndef ALL_BUGS_ARE_FATAL + tor_capture_bugs_(1); + tt_int_op(circuit_extend(cell, circ), OP_EQ, -1); + tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1); + tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); + tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ, + "!(ASSERT_PREDICT_UNLIKELY_(circ->magic != 0x98ABC04Fu))"); + tor_end_capture_bugs_(); + mock_clean_saved_logs(); + mock_extend_cell_parse_calls = 0; +#endif /* !defined(ALL_BUGS_ARE_FATAL) */ + + /* Now add the right magic and a p_chan. */ + or_circ->base_.magic = OR_CIRCUIT_MAGIC; + or_circ->p_chan = p_chan; + + /* Mock channel_get_for_extend(), so it doesn't crash. */ + mock_channel_get_for_extend_calls = 0; + MOCK(channel_get_for_extend, mock_channel_get_for_extend); + + /* Test circuit not established, but don't launch another one */ + mock_channel_get_for_extend_launch_out = 0; + mock_channel_get_for_extend_nchan = NULL; + tt_int_op(circuit_extend(cell, circ), OP_EQ, 0); + tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1); + tt_int_op(mock_channel_get_for_extend_calls, OP_EQ, 1); + + /* cleanup */ + mock_clean_saved_logs(); + mock_extend_cell_parse_calls = 0; + mock_channel_get_for_extend_calls = 0; + /* circ and or_circ are the same object */ + tor_free(circ->n_hop); + tor_free(circ->n_chan_create_cell); + + /* Mock channel_connect_for_circuit(), so we don't crash */ + mock_channel_connect_calls = 0; + MOCK(channel_connect_for_circuit, mock_channel_connect_for_circuit); + + /* Test circuit not established, and successful launch of a channel */ + mock_channel_get_for_extend_launch_out = 1; + mock_channel_get_for_extend_nchan = NULL; + mock_channel_connect_nchan = fake_n_chan; + tt_int_op(circuit_extend(cell, circ), OP_EQ, 0); + tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1); + tt_int_op(mock_channel_get_for_extend_calls, OP_EQ, 1); + tt_int_op(mock_channel_connect_calls, OP_EQ, 1); + + /* cleanup */ + mock_clean_saved_logs(); + mock_extend_cell_parse_calls = 0; + mock_channel_get_for_extend_calls = 0; + mock_channel_connect_calls = 0; + /* circ and or_circ are the same object */ + tor_free(circ->n_hop); + tor_free(circ->n_chan_create_cell); + + /* Mock circuit_deliver_create_cell(), so it doesn't crash */ + mock_circuit_deliver_create_cell_calls = 0; + MOCK(circuit_deliver_create_cell, mock_circuit_deliver_create_cell); + + /* Test circuit established, re-using channel, successful delivery */ + mock_channel_get_for_extend_launch_out = 0; + mock_channel_get_for_extend_nchan = fake_n_chan; + mock_channel_connect_nchan = NULL; + mock_circuit_deliver_create_cell_result = 0; + tt_int_op(circuit_extend(cell, circ), OP_EQ, 0); + tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1); + tt_int_op(mock_channel_get_for_extend_calls, OP_EQ, 1); + tt_int_op(mock_channel_connect_calls, OP_EQ, 0); + tt_int_op(mock_circuit_deliver_create_cell_calls, OP_EQ, 1); + tt_ptr_op(circ->n_chan, OP_EQ, fake_n_chan); + + /* cleanup */ + circ->n_chan = NULL; + mock_clean_saved_logs(); + mock_extend_cell_parse_calls = 0; + mock_channel_get_for_extend_calls = 0; + mock_channel_connect_calls = 0; + mock_circuit_deliver_create_cell_calls = 0; + /* circ and or_circ are the same object */ + tor_free(circ->n_hop); + tor_free(circ->n_chan_create_cell); + + /* Test circuit established, re-using channel, failed delivery */ + mock_channel_get_for_extend_launch_out = 0; + mock_channel_get_for_extend_nchan = fake_n_chan; + mock_channel_connect_nchan = NULL; + mock_circuit_deliver_create_cell_result = -1; + tt_int_op(circuit_extend(cell, circ), OP_EQ, -1); + tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1); + tt_int_op(mock_channel_get_for_extend_calls, OP_EQ, 1); + tt_int_op(mock_channel_connect_calls, OP_EQ, 0); + tt_int_op(mock_circuit_deliver_create_cell_calls, OP_EQ, 1); + tt_ptr_op(circ->n_chan, OP_EQ, fake_n_chan); + + /* cleanup */ + circ->n_chan = NULL; + mock_clean_saved_logs(); + mock_extend_cell_parse_calls = 0; + mock_channel_get_for_extend_calls = 0; + mock_channel_connect_calls = 0; + mock_circuit_deliver_create_cell_calls = 0; + /* circ and or_circ are the same object */ + tor_free(circ->n_hop); + tor_free(circ->n_chan_create_cell); + + done: + tor_end_capture_bugs_(); + teardown_capture_of_logs(); + + UNMOCK(server_mode); + server = 0; + + UNMOCK(channel_get_canonical_remote_descr); + + UNMOCK(extend_cell_parse); + memset(&mock_extend_cell_parse_cell_out, 0, + sizeof(mock_extend_cell_parse_cell_out)); + mock_extend_cell_parse_result = 0; + mock_extend_cell_parse_calls = 0; + + UNMOCK(channel_get_for_extend); + mock_channel_get_for_extend_calls = 0; + mock_channel_get_for_extend_launch_out = 0; + mock_channel_get_for_extend_nchan = NULL; + + UNMOCK(channel_connect_for_circuit); + mock_channel_connect_calls = 0; + mock_channel_connect_nchan = NULL; + + UNMOCK(circuit_deliver_create_cell); + mock_circuit_deliver_create_cell_calls = 0; + mock_circuit_deliver_create_cell_result = 0; + + tor_free(cell); + /* circ and or_circ are the same object */ + tor_free(circ->n_hop); + tor_free(circ->n_chan_create_cell); + tor_free(or_circ); + tor_free(p_chan); + tor_free(fake_n_chan); +} + +/* Test the different cases in onionskin_answer(). */ +static void +test_onionskin_answer(void *arg) +{ + (void)arg; + created_cell_t *created_cell = tor_malloc_zero(sizeof(created_cell_t)); + or_circuit_t *or_circ = tor_malloc_zero(sizeof(or_circuit_t)); + char keys[CPATH_KEY_MATERIAL_LEN] = {0}; + uint8_t rend_circ_nonce[DIGEST_LEN] = {0}; + + setup_full_capture_of_logs(LOG_INFO); + +#ifndef ALL_BUGS_ARE_FATAL + /* Circuit must be non-NULL */ + tor_capture_bugs_(1); + tt_int_op(onionskin_answer(NULL, created_cell, + keys, CPATH_KEY_MATERIAL_LEN, + rend_circ_nonce), OP_EQ, -1); + tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); + tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ, + "!(ASSERT_PREDICT_UNLIKELY_(!circ))"); + tor_end_capture_bugs_(); + mock_clean_saved_logs(); + + /* Created cell must be non-NULL */ + tor_capture_bugs_(1); + tt_int_op(onionskin_answer(or_circ, NULL, + keys, CPATH_KEY_MATERIAL_LEN, + rend_circ_nonce), OP_EQ, -1); + tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); + tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ, + "!(ASSERT_PREDICT_UNLIKELY_(!created_cell))"); + tor_end_capture_bugs_(); + mock_clean_saved_logs(); + + /* Keys must be non-NULL */ + tor_capture_bugs_(1); + tt_int_op(onionskin_answer(or_circ, created_cell, + NULL, CPATH_KEY_MATERIAL_LEN, + rend_circ_nonce), OP_EQ, -1); + tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); + tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ, + "!(ASSERT_PREDICT_UNLIKELY_(!keys))"); + tor_end_capture_bugs_(); + mock_clean_saved_logs(); + + /* The rend circuit nonce must be non-NULL */ + tor_capture_bugs_(1); + tt_int_op(onionskin_answer(or_circ, created_cell, + keys, CPATH_KEY_MATERIAL_LEN, + NULL), OP_EQ, -1); + tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); + tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ, + "!(ASSERT_PREDICT_UNLIKELY_(!rend_circ_nonce))"); + tor_end_capture_bugs_(); + mock_clean_saved_logs(); +#endif /* !defined(ALL_BUGS_ARE_FATAL) */ + + /* Also, the keys length must be CPATH_KEY_MATERIAL_LEN, but we can't catch + * asserts in unit tests. */ + + /* Fail when formatting the created cell */ + tt_int_op(onionskin_answer(or_circ, created_cell, + keys, CPATH_KEY_MATERIAL_LEN, + rend_circ_nonce), OP_EQ, -1); + expect_log_msg("couldn't format created cell (type=0, len=0).\n"); + mock_clean_saved_logs(); + + /* TODO: test the rest of onionskin_answer(), see #33860 */ + /* TODO: mock created_cell_format for the next test */ + + done: + tor_end_capture_bugs_(); + teardown_capture_of_logs(); + + tor_free(created_cell); + tor_free(or_circ); +} + +#define TEST(name, flags, setup, cleanup) \ + { #name, test_ ## name, flags, setup, cleanup } + +#define TEST_NEW_ROUTE_LEN(name, flags) \ + { #name, test_new_route_len_ ## name, flags, NULL, NULL } + +#define TEST_CIRCUIT(name, flags) \ + { #name, test_circuit_ ## name, flags, NULL, NULL } + +#ifndef COCCI +#define TEST_CIRCUIT_PASSTHROUGH(name, flags, arg) \ + { #name "/" arg, test_circuit_ ## name, flags, \ + &passthrough_setup, (void *)(arg) } +#endif + struct testcase_t circuitbuild_tests[] = { - { "noexit", test_new_route_len_noexit, 0, NULL, NULL }, - { "safe_exit", test_new_route_len_safe_exit, 0, NULL, NULL }, - { "unsafe_exit", test_new_route_len_unsafe_exit, 0, NULL, NULL }, - { "unhandled_exit", test_new_route_len_unhandled_exit, 0, NULL, NULL }, - { "upgrade_from_guard_wait", test_upgrade_from_guard_wait, TT_FORK, - &helper_pubsub_setup, NULL }, + TEST_NEW_ROUTE_LEN(noexit, 0), + TEST_NEW_ROUTE_LEN(safe_exit, 0), + TEST_NEW_ROUTE_LEN(unsafe_exit, 0), + TEST_NEW_ROUTE_LEN(unhandled_exit, 0), + + TEST(upgrade_from_guard_wait, TT_FORK, &helper_pubsub_setup, NULL), + + TEST_CIRCUIT(extend_state_valid, TT_FORK), + TEST_CIRCUIT(extend_add_ed25519, TT_FORK), + TEST_CIRCUIT(extend_lspec_valid, TT_FORK), + TEST_CIRCUIT(choose_ip_ap_for_extend, 0), + TEST_CIRCUIT_PASSTHROUGH(open_connection_for_extend, TT_FORK, "4"), + TEST_CIRCUIT_PASSTHROUGH(open_connection_for_extend, TT_FORK, "6"), + TEST_CIRCUIT_PASSTHROUGH(open_connection_for_extend, TT_FORK, "dual-stack"), + TEST_CIRCUIT(extend, TT_FORK), + + TEST(onionskin_answer, TT_FORK, NULL, NULL), + END_OF_TESTCASES }; diff --git a/src/test/test_config.c b/src/test/test_config.c index 8ea744d4fd..71beb93f67 100644 --- a/src/test/test_config.c +++ b/src/test/test_config.c @@ -18,6 +18,7 @@ #include "core/or/circuitmux_ewma.h" #include "core/or/circuitbuild.h" #include "app/config/config.h" +#include "app/config/resolve_addr.h" #include "feature/relay/relay_config.h" #include "feature/relay/transport_config.h" #include "lib/confmgt/confmgt.h" @@ -42,6 +43,7 @@ #include "core/or/policies.h" #include "feature/rend/rendclient.h" #include "feature/rend/rendservice.h" +#include "feature/relay/relay_find_addr.h" #include "feature/relay/router.h" #include "feature/relay/routermode.h" #include "feature/nodelist/dirlist.h" @@ -4160,8 +4162,6 @@ test_config_parse_port_config__ports__ports_given(void *data) /* Test entry port defaults as initialised in port_parse_config */ tt_int_op(port_cfg->entry_cfg.dns_request, OP_EQ, 1); tt_int_op(port_cfg->entry_cfg.ipv4_traffic, OP_EQ, 1); - tt_int_op(port_cfg->entry_cfg.ipv6_traffic, OP_EQ, 1); - tt_int_op(port_cfg->entry_cfg.prefer_ipv6, OP_EQ, 0); tt_int_op(port_cfg->entry_cfg.onion_traffic, OP_EQ, 1); tt_int_op(port_cfg->entry_cfg.cache_ipv4_answers, OP_EQ, 0); tt_int_op(port_cfg->entry_cfg.prefer_ipv6_virtaddr, OP_EQ, 1); diff --git a/src/test/test_connection.c b/src/test/test_connection.c index 05f7009bf4..b1252864f5 100644 --- a/src/test/test_connection.c +++ b/src/test/test_connection.c @@ -968,9 +968,14 @@ test_failed_orconn_tracker(void *arg) #define CONNECTION_TESTCASE(name, fork, setup) \ { #name, test_conn_##name, fork, &setup, NULL } +#define STR(x) #x /* where arg is an expression (constant, variable, compound expression) */ -#define CONNECTION_TESTCASE_ARG(name, fork, setup, arg) \ - { #name "_" #arg, test_conn_##name, fork, &setup, (void *)arg } +#define CONNECTION_TESTCASE_ARG(name, fork, setup, arg) \ + { #name "_" STR(x), \ + test_conn_##name, \ + fork, \ + &setup, \ + (void *)arg } #endif /* !defined(COCCI) */ static const unsigned int PROXY_CONNECT_ARG = PROXY_CONNECT; diff --git a/src/test/test_consdiff.c b/src/test/test_consdiff.c index e4cfece9c3..242e2f7818 100644 --- a/src/test/test_consdiff.c +++ b/src/test/test_consdiff.c @@ -1030,7 +1030,7 @@ test_consdiff_apply_diff(void *arg) /* diff doesn't have enough lines. */ cons2 = consdiff_apply_diff(cons1, diff, &digests1); tt_ptr_op(NULL, OP_EQ, cons2); - expect_single_log_msg_containing("too short") + expect_single_log_msg_containing("too short"); /* first line doesn't match format-version string. */ smartlist_add_linecpy(diff, area, "foo-bar"); @@ -1038,7 +1038,7 @@ test_consdiff_apply_diff(void *arg) mock_clean_saved_logs(); cons2 = consdiff_apply_diff(cons1, diff, &digests1); tt_ptr_op(NULL, OP_EQ, cons2); - expect_single_log_msg_containing("format is not known") + expect_single_log_msg_containing("format is not known"); /* The first word of the second header line is not "hash". */ smartlist_clear(diff); @@ -1048,7 +1048,7 @@ test_consdiff_apply_diff(void *arg) mock_clean_saved_logs(); cons2 = consdiff_apply_diff(cons1, diff, &digests1); tt_ptr_op(NULL, OP_EQ, cons2); - expect_single_log_msg_containing("does not include the necessary digests") + expect_single_log_msg_containing("does not include the necessary digests"); /* Wrong number of words after "hash". */ smartlist_clear(diff); @@ -1057,7 +1057,7 @@ test_consdiff_apply_diff(void *arg) mock_clean_saved_logs(); cons2 = consdiff_apply_diff(cons1, diff, &digests1); tt_ptr_op(NULL, OP_EQ, cons2); - expect_single_log_msg_containing("does not include the necessary digests") + expect_single_log_msg_containing("does not include the necessary digests"); /* base16 digests do not have the expected length. */ smartlist_clear(diff); @@ -1067,7 +1067,7 @@ test_consdiff_apply_diff(void *arg) cons2 = consdiff_apply_diff(cons1, diff, &digests1); tt_ptr_op(NULL, OP_EQ, cons2); expect_single_log_msg_containing("includes base16-encoded digests of " - "incorrect size") + "incorrect size"); /* base16 digests contain non-base16 characters. */ smartlist_clear(diff); @@ -1078,7 +1078,7 @@ test_consdiff_apply_diff(void *arg) mock_clean_saved_logs(); cons2 = consdiff_apply_diff(cons1, diff, &digests1); tt_ptr_op(NULL, OP_EQ, cons2); - expect_single_log_msg_containing("includes malformed digests") + expect_single_log_msg_containing("includes malformed digests"); /* Invalid ed diff. * As tested in apply_ed_diff, but check that apply_diff does return NULL if @@ -1095,7 +1095,7 @@ test_consdiff_apply_diff(void *arg) cons2 = consdiff_apply_diff(cons1, diff, &digests1); tt_ptr_op(NULL, OP_EQ, cons2); expect_single_log_msg_containing("because an ed command was missing a line " - "number") + "number"); /* Base consensus doesn't match its digest as found in the diff. */ smartlist_clear(diff); diff --git a/src/test/test_crypto_slow.c b/src/test/test_crypto_slow.c index 56319f2c72..1702427b08 100644 --- a/src/test/test_crypto_slow.c +++ b/src/test/test_crypto_slow.c @@ -342,7 +342,7 @@ test_crypto_scrypt_vectors(void *arg) #endif /* Test vectors from - http://tools.ietf.org/html/draft-josefsson-scrypt-kdf-00 section 11. + https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-00 section 11. Note that the names of 'r' and 'N' are switched in that section. Or possibly in libscrypt. diff --git a/src/test/test_dir.c b/src/test/test_dir.c index 3b2ba64d2c..3a0b8237cb 100644 --- a/src/test/test_dir.c +++ b/src/test/test_dir.c @@ -47,7 +47,7 @@ #include "feature/dirclient/dlstatus.h" #include "feature/dircommon/directory.h" #include "feature/dircommon/fp_pair.h" -#include "feature/dircommon/voting_schedule.h" +#include "feature/dirauth/voting_schedule.h" #include "feature/hibernate/hibernate.h" #include "feature/nodelist/authcert.h" #include "feature/nodelist/dirlist.h" @@ -3005,6 +3005,7 @@ test_dir_param_voting_lookup(void *arg) tt_int_op(99, OP_EQ, dirvote_get_intermediate_param_value(lst, "abcd", 1000)); +#ifndef ALL_BUGS_ARE_FATAL /* moomin appears twice. That's a bug. */ tor_capture_bugs_(1); tt_int_op(-100, OP_EQ, @@ -3022,7 +3023,7 @@ test_dir_param_voting_lookup(void *arg) dirvote_get_intermediate_param_value(lst, "jack", -100)); tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ, - "!(! ok)"); + "!(!ok)"); tor_end_capture_bugs_(); /* electricity and opa aren't integers. */ tor_capture_bugs_(1); @@ -3030,7 +3031,7 @@ test_dir_param_voting_lookup(void *arg) dirvote_get_intermediate_param_value(lst, "electricity", -100)); tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ, - "!(! ok)"); + "!(!ok)"); tor_end_capture_bugs_(); tor_capture_bugs_(1); @@ -3038,8 +3039,9 @@ test_dir_param_voting_lookup(void *arg) dirvote_get_intermediate_param_value(lst, "opa", -100)); tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ, - "!(! ok)"); + "!(!ok)"); tor_end_capture_bugs_(); +#endif /* !defined(ALL_BUGS_ARE_FATAL) */ done: SMARTLIST_FOREACH(lst, char *, cp, tor_free(cp)); @@ -3610,7 +3612,7 @@ test_a_networkstatus( sign_skey_2 = crypto_pk_new(); sign_skey_3 = crypto_pk_new(); sign_skey_leg1 = pk_generate(4); - voting_schedule_recalculate_timing(get_options(), now); + dirauth_sched_recalculate_timing(get_options(), now); sr_state_init(0, 0); tt_assert(!crypto_pk_read_private_key_from_string(sign_skey_1, @@ -4989,6 +4991,14 @@ test_dir_purpose_needs_anonymity_returns_true_by_default(void *arg) { (void)arg; +#ifdef ALL_BUGS_ARE_FATAL + /* Coverity (and maybe clang analyser) complain that the code following + * tt_skip() is unconditionally unreachable. */ +#if !defined(__COVERITY__) && !defined(__clang_analyzer__) + tt_skip(); +#endif +#endif /* defined(ALL_BUGS_ARE_FATAL) */ + tor_capture_bugs_(1); setup_full_capture_of_logs(LOG_WARN); tt_int_op(1, OP_EQ, purpose_needs_anonymity(0, 0, NULL)); diff --git a/src/test/test_dir_common.c b/src/test/test_dir_common.c index 4533ad5c03..f2b4e8724b 100644 --- a/src/test/test_dir_common.c +++ b/src/test/test_dir_common.c @@ -13,7 +13,7 @@ #include "feature/dirparse/authcert_parse.h" #include "feature/dirparse/ns_parse.h" #include "test/test_dir_common.h" -#include "feature/dircommon/voting_schedule.h" +#include "feature/dirauth/voting_schedule.h" #include "feature/nodelist/authority_cert_st.h" #include "feature/nodelist/networkstatus_st.h" diff --git a/src/test/test_dir_handle_get.c b/src/test/test_dir_handle_get.c index 6293839b0d..f446bbb5eb 100644 --- a/src/test/test_dir_handle_get.c +++ b/src/test/test_dir_handle_get.c @@ -38,7 +38,7 @@ #include "feature/dircache/dirserv.h" #include "feature/dirauth/dirvote.h" #include "test/log_test_helpers.h" -#include "feature/dircommon/voting_schedule.h" +#include "feature/dirauth/voting_schedule.h" #include "feature/dircommon/dir_connection_st.h" #include "feature/dirclient/dir_server_st.h" @@ -2080,12 +2080,12 @@ test_dir_handle_get_status_vote_d(void* data) mock_options->TestingV3AuthInitialDistDelay = 1; time_t now = 1441223455 -1; - voting_schedule_recalculate_timing(mock_options, now); + dirauth_sched_recalculate_timing(mock_options, now); const char *msg_out = NULL; int status_out = 0; - struct pending_vote_t *pv = dirvote_add_vote(VOTE_BODY_V3, &msg_out, - &status_out); + struct pending_vote_t *pv = dirvote_add_vote(VOTE_BODY_V3, 0, + &msg_out, &status_out); tt_assert(pv); status_vote_current_d_test(&header, &body, &body_used); @@ -2457,10 +2457,10 @@ test_dir_handle_get_status_vote_next_authority(void* data) mock_options->TestingV3AuthInitialDistDelay = 1; time_t now = 1441223455 -1; - voting_schedule_recalculate_timing(mock_options, now); + dirauth_sched_recalculate_timing(mock_options, now); - struct pending_vote_t *vote = dirvote_add_vote(VOTE_BODY_V3, &msg_out, - &status_out); + struct pending_vote_t *vote = dirvote_add_vote(VOTE_BODY_V3, 0, + &msg_out, &status_out); tt_assert(vote); MOCK(get_my_v3_authority_cert, get_my_v3_authority_cert_m); @@ -2617,10 +2617,10 @@ test_dir_handle_get_status_vote_current_authority(void* data) mock_options->TestingV3AuthInitialDistDelay = 1; time_t now = 1441223455; - voting_schedule_recalculate_timing(mock_options, now-1); + dirauth_sched_recalculate_timing(mock_options, now-1); - struct pending_vote_t *vote = dirvote_add_vote(VOTE_BODY_V3, &msg_out, - &status_out); + struct pending_vote_t *vote = dirvote_add_vote(VOTE_BODY_V3, 0, + &msg_out, &status_out); tt_assert(vote); // move the pending vote to previous vote @@ -2658,6 +2658,183 @@ test_dir_handle_get_status_vote_current_authority(void* data) dirvote_free_all(); } +/* Test that a late vote is rejected, but an on-time vote is accepted. */ +static void +test_dir_handle_get_status_vote_too_late(void* data) +{ + dir_connection_t *conn = NULL; + char *header = NULL, *body = NULL; + const char *msg_out = NULL; + int status_out = 0; + size_t body_used = 0; + const char digest[DIGEST_LEN] = ""; + + dir_server_t *ds = NULL; + const char* mode = (const char *)data; + + clear_dir_servers(); + routerlist_free_all(); + dirvote_free_all(); + + mock_cert = authority_cert_parse_from_string(TEST_CERTIFICATE, + strlen(TEST_CERTIFICATE), + NULL); + + /* create a trusted ds */ + ds = trusted_dir_server_new("ds", "127.0.0.1", 9059, 9060, NULL, digest, + NULL, V3_DIRINFO, 1.0); + tt_assert(ds); + dir_server_add(ds); + + /* ds v3_identity_digest is the certificate's identity_key */ + base16_decode(ds->v3_identity_digest, DIGEST_LEN, + TEST_CERT_IDENT_KEY, HEX_DIGEST_LEN); + + tt_int_op(0, OP_EQ, trusted_dirs_load_certs_from_string(TEST_CERTIFICATE, + TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST, 1, NULL)); + + init_mock_options(); + mock_options->AuthoritativeDir = 1; + mock_options->V3AuthoritativeDir = 1; + + int base_delay = 0; + int vote_interval = 0; + int start_offset = 0; + + tt_assert(mode); + /* Set the required timings, see below for details */ + if (strcmp(mode, "min") == 0) { + /* The minimum valid test network timing */ + base_delay = 2; + vote_interval = 10; + start_offset = vote_interval - 5; + } else if (strcmp(mode, "chutney") == 0) { + /* The test network timing used by chutney */ + base_delay = 4; + vote_interval = 20; + start_offset = vote_interval - 5; + } else if (strcmp(mode, "half-public") == 0) { + /* The short consensus failure timing used in the public network */ + base_delay = 5*60; + vote_interval = 30*60; + start_offset = vote_interval - 9*60 - 5; + } else if (strcmp(mode, "public") == 0) { + /* The standard timing used in the public network */ + base_delay = 5*60; + vote_interval = 60*60; + start_offset = vote_interval - 9*60 - 5; + } + + tt_assert(base_delay > 0); + tt_assert(vote_interval > 0); + tt_assert(start_offset > 0); + + /* Skew the time to fit the fixed time in the vote */ + mock_options->TestingV3AuthVotingStartOffset = start_offset; + /* Calculate the rest of the timings */ + mock_options->TestingV3AuthInitialVotingInterval = vote_interval; + mock_options->TestingV3AuthInitialVoteDelay = base_delay; + mock_options->TestingV3AuthInitialDistDelay = base_delay; + + time_t now = 1441223455; + dirauth_sched_recalculate_timing(mock_options, now-1); + const time_t voting_starts = voting_schedule.voting_starts; + const time_t fetch_missing = voting_schedule.fetch_missing_votes; + + struct pending_vote_t *vote = NULL; + + /* Next voting interval */ + vote = dirvote_add_vote(VOTE_BODY_V3, + fetch_missing + vote_interval, + &msg_out, &status_out); + tt_assert(!vote); + tt_int_op(status_out, OP_EQ, 400); + tt_str_op(msg_out, OP_EQ, + "Posted vote received too late, would be dangerous to count it"); + + /* Just after fetch missing */ + vote = dirvote_add_vote(VOTE_BODY_V3, + fetch_missing + 1, + &msg_out, &status_out); + tt_assert(!vote); + tt_int_op(status_out, OP_EQ, 400); + tt_str_op(msg_out, OP_EQ, + "Posted vote received too late, would be dangerous to count it"); + + /* On fetch missing */ + vote = dirvote_add_vote(VOTE_BODY_V3, + fetch_missing, + &msg_out, &status_out); + tt_assert(vote); + + /* Move the pending vote to previous vote */ + dirvote_act(mock_options, now+1); + /* And reset the timing */ + dirauth_sched_recalculate_timing(mock_options, now-1); + + /* Between voting starts and fetch missing */ + vote = dirvote_add_vote(VOTE_BODY_V3, + voting_starts + 1, + &msg_out, &status_out); + tt_assert(vote); + + /* Move the pending vote to previous vote */ + dirvote_act(mock_options, now+1); + /* And reset the timing */ + dirauth_sched_recalculate_timing(mock_options, now-1); + + /* On voting starts */ + vote = dirvote_add_vote(VOTE_BODY_V3, + voting_starts, + &msg_out, &status_out); + tt_assert(vote); + + /* Move the pending vote to previous vote */ + dirvote_act(mock_options, now+1); + /* And reset the timing */ + dirauth_sched_recalculate_timing(mock_options, now-1); + + /* Just before voting starts */ + vote = dirvote_add_vote(VOTE_BODY_V3, + voting_starts - 1, + &msg_out, &status_out); + tt_assert(vote); + + /* Move the pending vote to previous vote */ + dirvote_act(mock_options, now+1); + + MOCK(get_my_v3_authority_cert, get_my_v3_authority_cert_m); + MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); + + conn = new_dir_conn(); + tt_int_op(0, OP_EQ, directory_handle_command_get(conn, + GET("/tor/status-vote/current/authority"), NULL, 0)); + + fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, + &body, &body_used, strlen(VOTE_BODY_V3)+1, 0); + + tt_assert(header); + tt_ptr_op(strstr(header, "HTTP/1.0 200 OK\r\n"), OP_EQ, header); + tt_assert(strstr(header, "Content-Type: text/plain\r\n")); + tt_assert(strstr(header, "Content-Encoding: identity\r\n")); + tt_assert(strstr(header, "Content-Length: 4135\r\n")); + + tt_str_op(VOTE_BODY_V3, OP_EQ, body); + + done: + UNMOCK(connection_write_to_buf_impl_); + UNMOCK(get_my_v3_authority_cert); + connection_free_minimal(TO_CONN(conn)); + tor_free(header); + tor_free(body); + authority_cert_free(mock_cert); mock_cert = NULL; + or_options_free(mock_options); mock_options = NULL; + + clear_dir_servers(); + routerlist_free_all(); + dirvote_free_all(); +} + static void test_dir_handle_get_parse_accept_encoding(void *arg) { @@ -2708,6 +2885,16 @@ test_dir_handle_get_parse_accept_encoding(void *arg) #define DIR_HANDLE_CMD(name,flags) \ { #name, test_dir_handle_get_##name, (flags), NULL, NULL } +#ifdef COCCI +/* Coccinelle doesn't like the stringification in this macro */ +#define DIR_HANDLE_CMD_ARG(name,flags,arg) \ + DIR_HANDLE_CMD(name,flags) +#else +#define DIR_HANDLE_CMD_ARG(name,flags,arg) \ + { #name "/" arg, test_dir_handle_get_##name, (flags), \ + &passthrough_setup, (void *)(arg) } +#endif /* defined(COCCI) */ + struct testcase_t dir_handle_get_tests[] = { DIR_HANDLE_CMD(not_found, 0), DIR_HANDLE_CMD(bad_request, 0), @@ -2747,6 +2934,10 @@ struct testcase_t dir_handle_get_tests[] = { DIR_HANDLE_CMD(status_vote_next_not_found, 0), DIR_HANDLE_CMD(status_vote_current_authority_not_found, 0), DIR_HANDLE_CMD(status_vote_current_authority, 0), + DIR_HANDLE_CMD_ARG(status_vote_too_late, 0, "min"), + DIR_HANDLE_CMD_ARG(status_vote_too_late, 0, "chutney"), + DIR_HANDLE_CMD_ARG(status_vote_too_late, 0, "half-public"), + DIR_HANDLE_CMD_ARG(status_vote_too_late, 0, "public"), DIR_HANDLE_CMD(status_vote_next_authority_not_found, 0), DIR_HANDLE_CMD(status_vote_next_authority, 0), DIR_HANDLE_CMD(status_vote_next_bandwidth_not_found, 0), diff --git a/src/test/test_dns.c b/src/test/test_dns.c index ec17e9e91e..299321ab64 100644 --- a/src/test/test_dns.c +++ b/src/test/test_dns.c @@ -80,11 +80,11 @@ test_dns_clip_ttl(void *arg) { (void)arg; - uint32_t ttl_mid = MIN_DNS_TTL_AT_EXIT / 2 + MAX_DNS_TTL_AT_EXIT / 2; + uint32_t ttl_mid = MIN_DNS_TTL / 2 + MAX_DNS_TTL / 2; - tt_int_op(dns_clip_ttl(MIN_DNS_TTL_AT_EXIT - 1),OP_EQ,MIN_DNS_TTL_AT_EXIT); - tt_int_op(dns_clip_ttl(ttl_mid),OP_EQ,MAX_DNS_TTL_AT_EXIT); - tt_int_op(dns_clip_ttl(MAX_DNS_TTL_AT_EXIT + 1),OP_EQ,MAX_DNS_TTL_AT_EXIT); + tt_int_op(clip_dns_ttl(MIN_DNS_TTL - 1),OP_EQ,MIN_DNS_TTL); + tt_int_op(clip_dns_ttl(ttl_mid),OP_EQ,MAX_DNS_TTL); + tt_int_op(clip_dns_ttl(MAX_DNS_TTL + 1),OP_EQ,MAX_DNS_TTL); done: return; diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c index 12b4fcde3c..5ddd1a3db0 100644 --- a/src/test/test_entrynodes.c +++ b/src/test/test_entrynodes.c @@ -390,12 +390,13 @@ test_entry_guard_encode_for_state_minimal(void *arg) eg->confirmed_idx = -1; char *s = NULL; - s = entry_guard_encode_for_state(eg); + s = entry_guard_encode_for_state(eg, 0); tt_str_op(s, OP_EQ, "in=wubwub " "rsa_id=706C75727079666C75727079736C75727079646F " "sampled_on=2016-11-14T00:00:00 " + "sampled_idx=0 " "listed=0"); done: @@ -421,10 +422,11 @@ test_entry_guard_encode_for_state_maximal(void *arg) eg->currently_listed = 1; eg->confirmed_on_date = 1479081690; eg->confirmed_idx = 333; + eg->sampled_idx = 42; eg->extra_state_fields = tor_strdup("and the green grass grew all around"); char *s = NULL; - s = entry_guard_encode_for_state(eg); + s = entry_guard_encode_for_state(eg, 0); tt_str_op(s, OP_EQ, "in=default " @@ -432,6 +434,7 @@ test_entry_guard_encode_for_state_maximal(void *arg) "bridge_addr=8.8.4.4:9999 " "nickname=Fred " "sampled_on=2016-11-14T00:00:00 " + "sampled_idx=0 " "sampled_by=1.2.3 " "unlisted_since=2016-11-14T00:00:45 " "listed=1 " @@ -621,39 +624,47 @@ test_entry_guard_parse_from_state_full(void *arg) const char STATE[] = "Guard in=default rsa_id=214F44BD5B638E8C817D47FF7C97397790BF0345 " "nickname=TotallyNinja sampled_on=2016-11-12T19:32:49 " + "sampled_idx=0 " "sampled_by=0.3.0.0-alpha-dev " "listed=1\n" "Guard in=default rsa_id=052900AB0EA3ED54BAB84AE8A99E74E8693CE2B2 " "nickname=5OfNovember sampled_on=2016-11-20T04:32:05 " + "sampled_idx=1 " "sampled_by=0.3.0.0-alpha-dev " "listed=1 confirmed_on=2016-11-22T08:13:28 confirmed_idx=0 " "pb_circ_attempts=4.000000 pb_circ_successes=2.000000 " "pb_successful_circuits_closed=2.000000\n" "Guard in=default rsa_id=7B700C0C207EBD0002E00F499BE265519AC3C25A " "nickname=dc6jgk11 sampled_on=2016-11-28T11:50:13 " + "sampled_idx=2 " "sampled_by=0.3.0.0-alpha-dev " "listed=1 confirmed_on=2016-11-24T08:45:30 confirmed_idx=4 " "pb_circ_attempts=5.000000 pb_circ_successes=5.000000 " "pb_successful_circuits_closed=5.000000\n" "Guard in=wobblesome rsa_id=7B700C0C207EBD0002E00F499BE265519AC3C25A " "nickname=dc6jgk11 sampled_on=2016-11-28T11:50:13 " + "sampled_idx=0 " "sampled_by=0.3.0.0-alpha-dev " "listed=1\n" "Guard in=default rsa_id=E9025AD60D86875D5F11548D536CC6AF60F0EF5E " "nickname=maibrunn sampled_on=2016-11-25T22:36:38 " + "sampled_idx=3 " "sampled_by=0.3.0.0-alpha-dev listed=1\n" "Guard in=default rsa_id=DCD30B90BA3A792DA75DC54A327EF353FB84C38E " "nickname=Unnamed sampled_on=2016-11-25T14:34:00 " + "sampled_idx=10 " "sampled_by=0.3.0.0-alpha-dev listed=1\n" "Guard in=bridges rsa_id=8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2E " "bridge_addr=24.1.1.1:443 sampled_on=2016-11-25T06:44:14 " + "sampled_idx=0 " "sampled_by=0.3.0.0-alpha-dev listed=1 " "confirmed_on=2016-11-29T10:36:06 confirmed_idx=0 " "pb_circ_attempts=8.000000 pb_circ_successes=8.000000 " "pb_successful_circuits_closed=13.000000\n" "Guard in=bridges rsa_id=5800000000000000000000000000000000000000 " "bridge_addr=37.218.246.143:28366 " - "sampled_on=2016-11-18T15:07:34 sampled_by=0.3.0.0-alpha-dev listed=1\n"; + "sampled_on=2016-11-18T15:07:34 sampled_idx=1 " + "sampled_by=0.3.0.0-alpha-dev listed=1\n"; config_line_t *lines = NULL; or_state_t *state = tor_malloc_zero(sizeof(or_state_t)); @@ -729,35 +740,42 @@ test_entry_guard_parse_from_state_full(void *arg) tt_str_op(joined, OP_EQ, "Guard in=default rsa_id=052900AB0EA3ED54BAB84AE8A99E74E8693CE2B2 " "nickname=5OfNovember sampled_on=2016-11-20T04:32:05 " + "sampled_idx=0 " "sampled_by=0.3.0.0-alpha-dev " "listed=1 confirmed_on=2016-11-22T08:13:28 confirmed_idx=0 " "pb_circ_attempts=4.000000 pb_circ_successes=2.000000 " "pb_successful_circuits_closed=2.000000\n" "Guard in=default rsa_id=7B700C0C207EBD0002E00F499BE265519AC3C25A " "nickname=dc6jgk11 sampled_on=2016-11-28T11:50:13 " + "sampled_idx=1 " "sampled_by=0.3.0.0-alpha-dev " "listed=1 confirmed_on=2016-11-24T08:45:30 confirmed_idx=1 " "pb_circ_attempts=5.000000 pb_circ_successes=5.000000 " "pb_successful_circuits_closed=5.000000\n" "Guard in=default rsa_id=E9025AD60D86875D5F11548D536CC6AF60F0EF5E " "nickname=maibrunn sampled_on=2016-11-25T22:36:38 " + "sampled_idx=2 " "sampled_by=0.3.0.0-alpha-dev listed=1\n" "Guard in=default rsa_id=DCD30B90BA3A792DA75DC54A327EF353FB84C38E " "nickname=Unnamed sampled_on=2016-11-25T14:34:00 " + "sampled_idx=3 " "sampled_by=0.3.0.0-alpha-dev listed=1\n" "Guard in=wobblesome rsa_id=7B700C0C207EBD0002E00F499BE265519AC3C25A " "nickname=dc6jgk11 sampled_on=2016-11-28T11:50:13 " + "sampled_idx=0 " "sampled_by=0.3.0.0-alpha-dev " "listed=1\n" "Guard in=bridges rsa_id=8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2E " "bridge_addr=24.1.1.1:443 sampled_on=2016-11-25T06:44:14 " + "sampled_idx=0 " "sampled_by=0.3.0.0-alpha-dev listed=1 " "confirmed_on=2016-11-29T10:36:06 confirmed_idx=0 " "pb_circ_attempts=8.000000 pb_circ_successes=8.000000 " "pb_successful_circuits_closed=13.000000\n" "Guard in=bridges rsa_id=5800000000000000000000000000000000000000 " "bridge_addr=37.218.246.143:28366 " - "sampled_on=2016-11-18T15:07:34 sampled_by=0.3.0.0-alpha-dev listed=1\n"); + "sampled_on=2016-11-18T15:07:34 sampled_idx=1 " + "sampled_by=0.3.0.0-alpha-dev listed=1\n"); done: config_free_lines(lines); @@ -1461,8 +1479,8 @@ test_entry_guard_confirming_guards(void *arg) tt_i64_op(g1->confirmed_on_date, OP_EQ, start+10); tt_i64_op(g2->confirmed_on_date, OP_EQ, start); tt_i64_op(g3->confirmed_on_date, OP_EQ, start+10); - tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 0), OP_EQ, g2); - tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 1), OP_EQ, g1); + tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 0), OP_EQ, g1); + tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 1), OP_EQ, g2); tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 2), OP_EQ, g3); /* Now make sure we can regenerate the confirmed_entry_guards list. */ @@ -1474,8 +1492,8 @@ test_entry_guard_confirming_guards(void *arg) tt_int_op(g1->confirmed_idx, OP_EQ, 1); tt_int_op(g2->confirmed_idx, OP_EQ, 0); tt_int_op(g3->confirmed_idx, OP_EQ, 2); - tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 0), OP_EQ, g2); - tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 1), OP_EQ, g1); + tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 0), OP_EQ, g1); + tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 1), OP_EQ, g2); tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 2), OP_EQ, g3); /* Now make sure we can regenerate the confirmed_entry_guards list if @@ -1492,9 +1510,9 @@ test_entry_guard_confirming_guards(void *arg) g1 = smartlist_get(gs->confirmed_entry_guards, 0); g2 = smartlist_get(gs->confirmed_entry_guards, 1); g3 = smartlist_get(gs->confirmed_entry_guards, 2); - tt_int_op(g1->confirmed_idx, OP_EQ, 0); - tt_int_op(g2->confirmed_idx, OP_EQ, 1); - tt_int_op(g3->confirmed_idx, OP_EQ, 2); + tt_int_op(g1->sampled_idx, OP_EQ, 0); + tt_int_op(g2->sampled_idx, OP_EQ, 1); + tt_int_op(g3->sampled_idx, OP_EQ, 8); tt_assert(g1 != g2); tt_assert(g1 != g3); tt_assert(g2 != g3); @@ -1510,9 +1528,6 @@ test_entry_guard_sample_reachable_filtered(void *arg) (void)arg; guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL); entry_guards_expand_sample(gs); - const int N = 10000; - bitarray_t *selected = NULL; - int i, j; /* We've got a sampled list now; let's make one non-usable-filtered; some * confirmed, some primary, some pending. @@ -1547,32 +1562,21 @@ test_entry_guard_sample_reachable_filtered(void *arg) { SAMPLE_EXCLUDE_PENDING, 0 }, { -1, -1}, }; - + int j; for (j = 0; tests[j].flag >= 0; ++j) { - selected = bitarray_init_zero(n_guards); const int excluded_flags = tests[j].flag; const int excluded_idx = tests[j].idx; - for (i = 0; i < N; ++i) { - g = sample_reachable_filtered_entry_guards(gs, NULL, excluded_flags); - tor_assert(g); - int pos = smartlist_pos(gs->sampled_entry_guards, g); - tt_int_op(smartlist_len(gs->sampled_entry_guards), OP_EQ, n_guards); - tt_int_op(pos, OP_GE, 0); - tt_int_op(pos, OP_LT, n_guards); - bitarray_set(selected, pos); - } - for (i = 0; i < n_guards; ++i) { - const int should_be_set = (i != excluded_idx && - i != 3); // filtered out. - tt_int_op(!!bitarray_is_set(selected, i), OP_EQ, should_be_set); - } - bitarray_free(selected); - selected = NULL; + g = first_reachable_filtered_entry_guard(gs, NULL, excluded_flags); + tor_assert(g); + int pos = smartlist_pos(gs->sampled_entry_guards, g); + tt_int_op(smartlist_len(gs->sampled_entry_guards), OP_EQ, n_guards); + const int should_be_set = (pos != excluded_idx && + pos != 3); // filtered out. + tt_int_op(1, OP_EQ, should_be_set); } done: guard_selection_free(gs); - bitarray_free(selected); } static void @@ -1584,7 +1588,7 @@ test_entry_guard_sample_reachable_filtered_empty(void *arg) SMARTLIST_FOREACH(big_fake_net_nodes, node_t *, n, n->is_possible_guard = 0); - entry_guard_t *g = sample_reachable_filtered_entry_guards(gs, NULL, 0); + entry_guard_t *g = first_reachable_filtered_entry_guard(gs, NULL, 0); tt_ptr_op(g, OP_EQ, NULL); done: @@ -1675,10 +1679,13 @@ test_entry_guard_manage_primary(void *arg) tt_ptr_op(g, OP_EQ, smartlist_get(prev_guards, g_sl_idx)); }); - /* If we have one confirmed guard, that guards becomes the first primary - * guard, and the other primary guards get kept. */ + /** + * If we have one confirmed guard, that guards becomes the first primary + * only if its sampled_idx is smaller + * */ - /* find a non-primary guard... */ + /* find a non-primary guard... it should have a sampled_idx higher than + * existing primary guards */ entry_guard_t *confirmed = NULL; SMARTLIST_FOREACH(gs->sampled_entry_guards, entry_guard_t *, g, { if (! g->is_primary) { @@ -1694,15 +1701,13 @@ test_entry_guard_manage_primary(void *arg) smartlist_add_all(prev_guards, gs->primary_entry_guards); entry_guards_update_primary(gs); - /* and see what's primary now! */ + /* the confirmed guard should be at the end of the primary list! Hopefully, + * one of the primary guards with a lower sampled_idx will confirm soon :) + * Doing this won't make the client switches between primaries depending on + * the order of confirming events */ tt_int_op(smartlist_len(gs->primary_entry_guards), OP_EQ, n_primary); - tt_ptr_op(smartlist_get(gs->primary_entry_guards, 0), OP_EQ, confirmed); - SMARTLIST_FOREACH(gs->primary_entry_guards, entry_guard_t *, g, { - tt_assert(g->is_primary); - if (g_sl_idx == 0) - continue; - tt_ptr_op(g, OP_EQ, smartlist_get(prev_guards, g_sl_idx - 1)); - }); + tt_ptr_op(smartlist_get(gs->primary_entry_guards, + smartlist_len(gs->primary_entry_guards)-1), OP_EQ, confirmed); { entry_guard_t *prev_last_guard = smartlist_get(prev_guards, n_primary-1); tt_assert(! prev_last_guard->is_primary); @@ -1793,6 +1798,57 @@ test_entry_guard_guard_preferred(void *arg) } static void +test_entry_guard_correct_cascading_order(void *arg) +{ + (void)arg; + smartlist_t *old_primary_guards = smartlist_new(); + guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL); + entry_guards_expand_sample(gs); + /** First, a test in which the primary guards need be pulled from different + * lists to fill up the primary list -- this may happen, if for example, not + * enough guards have confirmed yet */ + entry_guard_t *g; + /** just one confirmed */ + g = smartlist_get(gs->sampled_entry_guards, 2); + make_guard_confirmed(gs, g); + entry_guards_update_primary(gs); + g = smartlist_get(gs->primary_entry_guards, 0); + tt_int_op(g->sampled_idx, OP_EQ, 0); + g = smartlist_get(gs->primary_entry_guards, 1); + tt_int_op(g->sampled_idx, OP_EQ, 1); + g = smartlist_get(gs->primary_entry_guards, 2); + tt_int_op(g->sampled_idx, OP_EQ, 2); + + /** Now the primaries get all confirmed, and the primary list should not + * change */ + make_guard_confirmed(gs, smartlist_get(gs->primary_entry_guards, 0)); + make_guard_confirmed(gs, smartlist_get(gs->primary_entry_guards, 1)); + smartlist_add_all(old_primary_guards, gs->primary_entry_guards); + entry_guards_update_primary(gs); + smartlist_ptrs_eq(gs->primary_entry_guards, old_primary_guards); + /** the confirmed guards should also have the same set of guards, in the same + * order :-) */ + smartlist_ptrs_eq(gs->confirmed_entry_guards, gs->primary_entry_guards); + /** Now select a guard for a circuit, and make sure it is the first primary + * guard */ + unsigned state = 9999; + g = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL, &state); + tt_ptr_op(g, OP_EQ, smartlist_get(gs->primary_entry_guards, 0)); + /** Now, let's mark this guard as unreachable and let's update the lists */ + g->is_reachable = GUARD_REACHABLE_NO; + g->failing_since = approx_time() - 10; + g->last_tried_to_connect = approx_time() - 10; + state = 9999; + entry_guards_update_primary(gs); + g = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL, &state); + /** we should have switched to the next one is sampled order */ + tt_int_op(g->sampled_idx, OP_EQ, 1); + done: + smartlist_free(old_primary_guards); + guard_selection_free(gs); +} + +static void test_entry_guard_select_for_circuit_no_confirmed(void *arg) { /* Simpler cases: no gaurds are confirmed yet. */ @@ -3094,6 +3150,7 @@ struct testcase_t entrynodes_tests[] = { BFN_TEST(sample_reachable_filtered_empty), BFN_TEST(retry_unreachable), BFN_TEST(manage_primary), + BFN_TEST(correct_cascading_order), EN_TEST_FORK(guard_preferred), diff --git a/src/test/test_hs_cache.c b/src/test/test_hs_cache.c index a1df2b0eea..df96b2c791 100644 --- a/src/test/test_hs_cache.c +++ b/src/test/test_hs_cache.c @@ -370,7 +370,7 @@ test_hsdir_revision_counter_check(void *arg) hs_descriptor_t *published_desc = NULL; char *published_desc_str = NULL; - uint8_t subcredential[DIGEST256_LEN]; + hs_subcredential_t subcredential; char *received_desc_str = NULL; hs_descriptor_t *received_desc = NULL; @@ -407,11 +407,11 @@ test_hsdir_revision_counter_check(void *arg) const ed25519_public_key_t *blinded_key; blinded_key = &published_desc->plaintext_data.blinded_pubkey; - hs_get_subcredential(&signing_kp.pubkey, blinded_key, subcredential); + hs_get_subcredential(&signing_kp.pubkey, blinded_key, &subcredential); received_desc_str = helper_fetch_desc_from_hsdir(blinded_key); retval = hs_desc_decode_descriptor(received_desc_str, - subcredential, NULL, &received_desc); + &subcredential, NULL, &received_desc); tt_int_op(retval, OP_EQ, HS_DESC_DECODE_OK); tt_assert(received_desc); @@ -444,7 +444,7 @@ test_hsdir_revision_counter_check(void *arg) received_desc_str = helper_fetch_desc_from_hsdir(blinded_key); retval = hs_desc_decode_descriptor(received_desc_str, - subcredential, NULL, &received_desc); + &subcredential, NULL, &received_desc); tt_int_op(retval, OP_EQ, HS_DESC_DECODE_OK); tt_assert(received_desc); @@ -477,7 +477,7 @@ test_client_cache(void *arg) ed25519_keypair_t signing_kp; hs_descriptor_t *published_desc = NULL; char *published_desc_str = NULL; - uint8_t wanted_subcredential[DIGEST256_LEN]; + hs_subcredential_t wanted_subcredential; response_handler_args_t *args = NULL; dir_connection_t *conn = NULL; @@ -506,8 +506,10 @@ test_client_cache(void *arg) retval = hs_desc_encode_descriptor(published_desc, &signing_kp, NULL, &published_desc_str); tt_int_op(retval, OP_EQ, 0); - memcpy(wanted_subcredential, published_desc->subcredential, DIGEST256_LEN); - tt_assert(!fast_mem_is_zero((char*)wanted_subcredential, DIGEST256_LEN)); + memcpy(&wanted_subcredential, &published_desc->subcredential, + sizeof(hs_subcredential_t)); + tt_assert(!fast_mem_is_zero((char*)wanted_subcredential.subcred, + DIGEST256_LEN)); } /* Test handle_response_fetch_hsdesc_v3() */ @@ -541,8 +543,9 @@ test_client_cache(void *arg) const hs_descriptor_t *cached_desc = NULL; cached_desc = hs_cache_lookup_as_client(&signing_kp.pubkey); tt_assert(cached_desc); - tt_mem_op(cached_desc->subcredential, OP_EQ, wanted_subcredential, - DIGEST256_LEN); + tt_mem_op(cached_desc->subcredential.subcred, + OP_EQ, wanted_subcredential.subcred, + SUBCRED_LEN); } /* Progress time to next TP and check that desc was cleaned */ diff --git a/src/test/test_hs_client.c b/src/test/test_hs_client.c index e797fdedd0..0cd7d81eea 100644 --- a/src/test/test_hs_client.c +++ b/src/test/test_hs_client.c @@ -435,9 +435,10 @@ test_client_pick_intro(void *arg) const hs_descriptor_t *fetched_desc = hs_cache_lookup_as_client(&service_kp.pubkey); tt_assert(fetched_desc); - tt_mem_op(fetched_desc->subcredential, OP_EQ, desc->subcredential, - DIGEST256_LEN); - tt_assert(!fast_mem_is_zero((char*)fetched_desc->subcredential, + tt_mem_op(fetched_desc->subcredential.subcred, + OP_EQ, desc->subcredential.subcred, + SUBCRED_LEN); + tt_assert(!fast_mem_is_zero((char*)fetched_desc->subcredential.subcred, DIGEST256_LEN)); tor_free(encoded); } @@ -1194,7 +1195,11 @@ static void test_socks_hs_errors(void *arg) { int ret; + char digest[DIGEST_LEN]; char *desc_encoded = NULL; + circuit_t *circ = NULL; + origin_circuit_t *ocirc = NULL; + tor_addr_t addr; ed25519_keypair_t service_kp; ed25519_keypair_t signing_kp; entry_connection_t *socks_conn = NULL; @@ -1241,6 +1246,73 @@ test_socks_hs_errors(void *arg) desc = hs_helper_build_hs_desc_with_ip(&service_kp); tt_assert(desc); + /* Before testing the client authentication error code, encode the + * descriptor with no client auth. */ + ret = hs_desc_encode_descriptor(desc, &service_kp, NULL, &desc_encoded); + tt_int_op(ret, OP_EQ, 0); + tt_assert(desc_encoded); + + /* + * Test the introduction failure codes (X'F2' and X'F7') + */ + + /* First, we have to put all the IPs in the failure cache. */ + SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points, + hs_desc_intro_point_t *, ip) { + hs_cache_client_intro_state_note(&service_kp.pubkey, + &ip->auth_key_cert->signed_key, + INTRO_POINT_FAILURE_GENERIC); + } SMARTLIST_FOREACH_END(ip); + + hs_client_dir_fetch_done(dir_conn, "Reason", desc_encoded, 200); + tt_int_op(socks_conn->socks_request->socks_extended_error_code, OP_EQ, + SOCKS5_HS_INTRO_FAILED); + + /* Purge client cache of the descriptor so we can go again. */ + hs_cache_purge_as_client(); + + /* Second, set all failures to be time outs. */ + SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points, + hs_desc_intro_point_t *, ip) { + hs_cache_client_intro_state_note(&service_kp.pubkey, + &ip->auth_key_cert->signed_key, + INTRO_POINT_FAILURE_TIMEOUT); + } SMARTLIST_FOREACH_END(ip); + + hs_client_dir_fetch_done(dir_conn, "Reason", desc_encoded, 200); + tt_int_op(socks_conn->socks_request->socks_extended_error_code, OP_EQ, + SOCKS5_HS_INTRO_TIMEDOUT); + + /* Purge client cache of the descriptor so we can go again. */ + hs_cache_purge_as_client(); + + /* + * Test the rendezvous failure codes (X'F3') + */ + + circ = dummy_origin_circuit_new(0); + tt_assert(circ); + circ->purpose = CIRCUIT_PURPOSE_C_REND_READY; + ocirc = TO_ORIGIN_CIRCUIT(circ); + ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey); + ocirc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t)); + /* Code path will log this exit so build it. */ + ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest, + NULL, NULL, NULL, &addr, + 4242); + /* Attach socks connection to this rendezvous circuit. */ + ocirc->p_streams = ENTRY_TO_EDGE_CONN(socks_conn); + /* Trigger the rendezvous failure. Timeout the circuit and free. */ + circuit_mark_for_close(circ, END_CIRC_REASON_TIMEOUT); + + tt_int_op(socks_conn->socks_request->socks_extended_error_code, OP_EQ, + SOCKS5_HS_REND_FAILED); + + /* + * Test client authorization codes. + */ + + tor_free(desc_encoded); crypto_rand((char *) descriptor_cookie, sizeof(descriptor_cookie)); ret = hs_desc_encode_descriptor(desc, &service_kp, descriptor_cookie, &desc_encoded); @@ -1282,6 +1354,7 @@ test_socks_hs_errors(void *arg) connection_free_minimal(TO_CONN(dir_conn)); hs_descriptor_free(desc); tor_free(desc_encoded); + circuit_free(circ); hs_free_all(); diff --git a/src/test/test_hs_common.c b/src/test/test_hs_common.c index 6f5f21f49a..e3d130fb32 100644 --- a/src/test/test_hs_common.c +++ b/src/test/test_hs_common.c @@ -32,7 +32,7 @@ #include "app/config/statefile.h" #include "core/or/circuitlist.h" #include "feature/dirauth/shared_random.h" -#include "feature/dircommon/voting_schedule.h" +#include "feature/dirauth/voting_schedule.h" #include "feature/nodelist/microdesc_st.h" #include "feature/nodelist/networkstatus_st.h" @@ -53,14 +53,14 @@ test_validate_address(void *arg) setup_full_capture_of_logs(LOG_WARN); ret = hs_address_is_valid("blah"); tt_int_op(ret, OP_EQ, 0); - expect_log_msg_containing("has an invalid length"); + expect_log_msg_containing("Invalid length"); teardown_capture_of_logs(); setup_full_capture_of_logs(LOG_WARN); ret = hs_address_is_valid( "p3xnclpu4mu22dwaurjtsybyqk4xfjmcfz6z62yl24uwmhjatiwnlnadb"); tt_int_op(ret, OP_EQ, 0); - expect_log_msg_containing("has an invalid length"); + expect_log_msg_containing("Invalid length"); teardown_capture_of_logs(); /* Invalid checksum (taken from prop224) */ @@ -83,7 +83,7 @@ test_validate_address(void *arg) ret = hs_address_is_valid( "????????????????????????????????????????????????????????"); tt_int_op(ret, OP_EQ, 0); - expect_log_msg_containing("can't be decoded"); + expect_log_msg_containing("Unable to base32 decode"); teardown_capture_of_logs(); /* Valid address. */ @@ -799,6 +799,8 @@ test_parse_extended_hostname(void *arg) "www.25njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid.onion"; char address9[] = "www.15njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid.onion"; + char address10[] = + "15njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid7jdl.onion"; tt_assert(!parse_extended_hostname(address1, &type)); tt_int_op(type, OP_EQ, BAD_HOSTNAME); @@ -831,7 +833,11 @@ test_parse_extended_hostname(void *arg) /* Invalid v3 address. */ tt_assert(!parse_extended_hostname(address9, &type)); - tt_int_op(type, OP_EQ, ONION_V3_HOSTNAME); + tt_int_op(type, OP_EQ, BAD_HOSTNAME); + + /* Invalid v3 address: too long */ + tt_assert(!parse_extended_hostname(address10, &type)); + tt_int_op(type, OP_EQ, BAD_HOSTNAME); done: ; } @@ -860,7 +866,7 @@ test_time_between_tp_and_srv(void *arg) tt_int_op(ret, OP_EQ, 0); ret = parse_rfc1123_time("Sat, 26 Oct 1985 01:00:00 UTC", &ns.fresh_until); tt_int_op(ret, OP_EQ, 0); - voting_schedule_recalculate_timing(get_options(), ns.valid_after); + dirauth_sched_recalculate_timing(get_options(), ns.valid_after); ret = hs_in_period_between_tp_and_srv(&ns, 0); tt_int_op(ret, OP_EQ, 0); @@ -868,7 +874,7 @@ test_time_between_tp_and_srv(void *arg) tt_int_op(ret, OP_EQ, 0); ret = parse_rfc1123_time("Sat, 26 Oct 1985 12:00:00 UTC", &ns.fresh_until); tt_int_op(ret, OP_EQ, 0); - voting_schedule_recalculate_timing(get_options(), ns.valid_after); + dirauth_sched_recalculate_timing(get_options(), ns.valid_after); ret = hs_in_period_between_tp_and_srv(&ns, 0); tt_int_op(ret, OP_EQ, 0); @@ -876,7 +882,7 @@ test_time_between_tp_and_srv(void *arg) tt_int_op(ret, OP_EQ, 0); ret = parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC", &ns.fresh_until); tt_int_op(ret, OP_EQ, 0); - voting_schedule_recalculate_timing(get_options(), ns.valid_after); + dirauth_sched_recalculate_timing(get_options(), ns.valid_after); ret = hs_in_period_between_tp_and_srv(&ns, 0); tt_int_op(ret, OP_EQ, 1); @@ -884,7 +890,7 @@ test_time_between_tp_and_srv(void *arg) tt_int_op(ret, OP_EQ, 0); ret = parse_rfc1123_time("Sat, 27 Oct 1985 00:00:00 UTC", &ns.fresh_until); tt_int_op(ret, OP_EQ, 0); - voting_schedule_recalculate_timing(get_options(), ns.valid_after); + dirauth_sched_recalculate_timing(get_options(), ns.valid_after); ret = hs_in_period_between_tp_and_srv(&ns, 0); tt_int_op(ret, OP_EQ, 1); @@ -892,7 +898,7 @@ test_time_between_tp_and_srv(void *arg) tt_int_op(ret, OP_EQ, 0); ret = parse_rfc1123_time("Sat, 27 Oct 1985 01:00:00 UTC", &ns.fresh_until); tt_int_op(ret, OP_EQ, 0); - voting_schedule_recalculate_timing(get_options(), ns.valid_after); + dirauth_sched_recalculate_timing(get_options(), ns.valid_after); ret = hs_in_period_between_tp_and_srv(&ns, 0); tt_int_op(ret, OP_EQ, 0); @@ -1382,7 +1388,7 @@ run_reachability_scenario(const reachability_cfg_t *cfg, int num_scenario) &mock_service_ns->valid_until); set_consensus_times(cfg->service_valid_until, &mock_service_ns->fresh_until); - voting_schedule_recalculate_timing(get_options(), + dirauth_sched_recalculate_timing(get_options(), mock_service_ns->valid_after); /* Check that service is in the right time period point */ tt_int_op(hs_in_period_between_tp_and_srv(mock_service_ns, 0), OP_EQ, @@ -1395,7 +1401,7 @@ run_reachability_scenario(const reachability_cfg_t *cfg, int num_scenario) &mock_client_ns->valid_until); set_consensus_times(cfg->client_valid_until, &mock_client_ns->fresh_until); - voting_schedule_recalculate_timing(get_options(), + dirauth_sched_recalculate_timing(get_options(), mock_client_ns->valid_after); /* Check that client is in the right time period point */ tt_int_op(hs_in_period_between_tp_and_srv(mock_client_ns, 0), OP_EQ, @@ -1618,7 +1624,7 @@ helper_set_consensus_and_system_time(networkstatus_t *ns, int position) } else { tt_assert(0); } - voting_schedule_recalculate_timing(get_options(), ns->valid_after); + dirauth_sched_recalculate_timing(get_options(), ns->valid_after); /* Set system time: pretend to be just 2 minutes before consensus expiry */ real_time = ns->valid_until - 120; diff --git a/src/test/test_hs_config.c b/src/test/test_hs_config.c index b2537b746b..dc3b598c34 100644 --- a/src/test/test_hs_config.c +++ b/src/test/test_hs_config.c @@ -62,8 +62,9 @@ test_invalid_service(void *arg) setup_full_capture_of_logs(LOG_WARN); ret = helper_config_service(conf, 1); tt_int_op(ret, OP_EQ, -1); - expect_log_msg_containing("HiddenServiceAllowUnknownPorts must be " - "between 0 and 1, not 2"); + expect_log_msg_containing("Could not parse " + "HiddenServiceAllowUnknownPorts: Unrecognized " + "value 2. Allowed values are 0 and 1."); teardown_capture_of_logs(); } @@ -76,8 +77,9 @@ test_invalid_service(void *arg) setup_full_capture_of_logs(LOG_WARN); ret = helper_config_service(conf, 1); tt_int_op(ret, OP_EQ, -1); - expect_log_msg_containing("HiddenServiceDirGroupReadable must be " - "between 0 and 1, not 2"); + expect_log_msg_containing("Could not parse " + "HiddenServiceDirGroupReadable: " + "Unrecognized value 2."); teardown_capture_of_logs(); } @@ -90,8 +92,9 @@ test_invalid_service(void *arg) setup_full_capture_of_logs(LOG_WARN); ret = helper_config_service(conf, 1); tt_int_op(ret, OP_EQ, -1); - expect_log_msg_containing("HiddenServiceMaxStreamsCloseCircuit must " - "be between 0 and 1, not 2"); + expect_log_msg_containing("Could not parse " + "HiddenServiceMaxStreamsCloseCircuit: " + "Unrecognized value 2"); teardown_capture_of_logs(); } @@ -228,8 +231,8 @@ test_invalid_service_v2(void *arg) setup_full_capture_of_logs(LOG_WARN); ret = helper_config_service(conf, validate_only); tt_int_op(ret, OP_EQ, -1); - expect_log_msg_containing("HiddenServiceNumIntroductionPoints should " - "be between 0 and 10, not 11"); + expect_log_msg_containing("HiddenServiceNumIntroductionPoints must " + "be between 0 and 10, not 11."); teardown_capture_of_logs(); } @@ -243,8 +246,9 @@ test_invalid_service_v2(void *arg) setup_full_capture_of_logs(LOG_WARN); ret = helper_config_service(conf, validate_only); tt_int_op(ret, OP_EQ, -1); - expect_log_msg_containing("HiddenServiceNumIntroductionPoints should " - "be between 0 and 10, not -1"); + expect_log_msg_containing("Could not parse " + "HiddenServiceNumIntroductionPoints: " + "Integer -1 is malformed or out of bounds."); teardown_capture_of_logs(); } @@ -532,9 +536,10 @@ test_dos_parameters(void *arg) setup_full_capture_of_logs(LOG_WARN); ret = helper_config_service(conf, 0); tt_int_op(ret, OP_EQ, -1); - expect_log_msg_containing("HiddenServiceEnableIntroDoSRatePerSec must " - "be between 0 and 2147483647, " - "not 137438953472"); + expect_log_msg_containing("Could not parse " + "HiddenServiceEnableIntroDoSRatePerSec: " + "Integer 137438953472 is malformed or out of " + "bounds."); teardown_capture_of_logs(); } @@ -551,9 +556,10 @@ test_dos_parameters(void *arg) setup_full_capture_of_logs(LOG_WARN); ret = helper_config_service(conf, 0); tt_int_op(ret, OP_EQ, -1); - expect_log_msg_containing("HiddenServiceEnableIntroDoSBurstPerSec must " - "be between 0 and 2147483647, " - "not 274877906944"); + expect_log_msg_containing("Could not parse " + "HiddenServiceEnableIntroDoSBurstPerSec: " + "Integer 274877906944 is malformed or out " + "of bounds."); teardown_capture_of_logs(); } @@ -588,8 +594,9 @@ test_dos_parameters(void *arg) setup_full_capture_of_logs(LOG_WARN); ret = helper_config_service(conf, 0); tt_int_op(ret, OP_EQ, -1); - expect_log_msg_containing("HiddenServiceEnableIntroDoSRatePerSec must be " - "between 0 and 2147483647, not -1"); + expect_log_msg_containing("Could not parse " + "HiddenServiceEnableIntroDoSRatePerSec: " + "Integer -1 is malformed or out of bounds."); teardown_capture_of_logs(); } diff --git a/src/test/test_hs_control.c b/src/test/test_hs_control.c index 8ba9f1173c..80bbf547dc 100644 --- a/src/test/test_hs_control.c +++ b/src/test/test_hs_control.c @@ -212,7 +212,8 @@ test_hs_control_good_onion_client_auth_add(void *arg) MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); int retval; - ed25519_public_key_t service_identity_pk_2fv, service_identity_pk_jt4; + ed25519_public_key_t service_identity_pk_2fv, service_identity_pk_jt4, + service_identity_pk_jam; control_connection_t conn; char *args = NULL; char *cp1 = NULL; @@ -238,6 +239,12 @@ test_hs_control_good_onion_client_auth_add(void *arg) &service_identity_pk_jt4, NULL, NULL); tt_int_op(retval, OP_EQ, 0); + + retval = hs_parse_address( + "jamie3vkiwibfiwucd6vxijskbhpjdyajmzeor4mc4i7yopvpo4p7cyd", + &service_identity_pk_jam, + NULL, NULL); + tt_int_op(retval, OP_EQ, 0); } digest256map_t *client_auths = get_hs_client_auths_map(); @@ -268,10 +275,24 @@ test_hs_control_good_onion_client_auth_add(void *arg) cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); tt_str_op(cp1, OP_EQ, "250 OK\r\n"); tor_free(cp1); + tor_free(args); + + /* Register second service (even with an unrecognized argument) */ + args = tor_strdup("jamie3vkiwibfiwucd6vxijskbhpjdyajmzeor4mc4i7yopvpo4p7cyd " + "x25519:FCV0c0ELDKKDpSFgVIB8Yow8Evj5iD+GoiTtK878NkQ= " + "ClientName=MeganNicole "); + + retval = handle_control_command(&conn, (uint32_t) strlen(args), args); + tt_int_op(retval, OP_EQ, 0); + + /* Check contents */ + cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); + tt_str_op(cp1, OP_EQ, "250 OK\r\n"); + tor_free(cp1); client_auths = get_hs_client_auths_map(); tt_assert(client_auths); - tt_uint_op(digest256map_size(client_auths), OP_EQ, 2); + tt_uint_op(digest256map_size(client_auths), OP_EQ, 3); hs_client_service_authorization_t *client_2fv = digest256map_get(client_auths, service_identity_pk_2fv.pubkey); @@ -283,6 +304,11 @@ test_hs_control_good_onion_client_auth_add(void *arg) tt_assert(client_jt4); tt_int_op(client_jt4->flags, OP_EQ, 0); + hs_client_service_authorization_t *client_jam = + digest256map_get(client_auths, service_identity_pk_jam.pubkey); + tt_assert(client_jam); + tt_int_op(client_jam->flags, OP_EQ, 0); + /* Now let's VIEW the auth credentials */ tor_free(conn.current_cmd); conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_VIEW"); @@ -294,6 +320,9 @@ test_hs_control_good_onion_client_auth_add(void *arg) #define VIEW_CORRECT_REPLY_NO_ADDR "250-ONION_CLIENT_AUTH_VIEW\r\n" \ "250-CLIENT 2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd " \ "x25519:iJ1tjKCrMAbiFT2bVrCjhbfMDnE1fpaRbIS5ZHKUvEQ=\r\n" \ + "250-CLIENT jamie3vkiwibfiwucd6vxijskbhpjdyajmzeor4mc4i7yopvpo4p7cyd " \ + "x25519:FCV0c0ELDKKDpSFgVIB8Yow8Evj5iD+GoiTtK878NkQ= " \ + "ClientName=MeganNicole\r\n" \ "250-CLIENT jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd " \ "x25519:eIIdIGoSZwI2Q/lSzpf92akGki5I+PZIDz37MA5BhlA=\r\n" \ "250 OK\r\n" @@ -364,7 +393,19 @@ test_hs_control_good_onion_client_auth_add(void *arg) /* Now also remove the other one */ tor_free(args); - args =tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd"); + args = + tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd"); + + retval = handle_control_command(&conn, (uint32_t) strlen(args), args); + tt_int_op(retval, OP_EQ, 0); + cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); + tt_str_op(cp1, OP_EQ, "250 OK\r\n"); + tor_free(cp1); + + /* Now also remove the other one */ + tor_free(args); + args = + tor_strdup("jamie3vkiwibfiwucd6vxijskbhpjdyajmzeor4mc4i7yopvpo4p7cyd"); retval = handle_control_command(&conn, (uint32_t) strlen(args), args); tt_int_op(retval, OP_EQ, 0); @@ -393,7 +434,7 @@ test_hs_control_good_onion_client_auth_add(void *arg) retval = handle_control_command(&conn, (uint32_t) strlen(args), args); tt_int_op(retval, OP_EQ, 0); cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); - tt_str_op(cp1, OP_EQ, "512 Invalid v3 addr \"house\"\r\n"); + tt_str_op(cp1, OP_EQ, "512 Invalid v3 address \"house\"\r\n"); done: tor_free(args); diff --git a/src/test/test_hs_descriptor.c b/src/test/test_hs_descriptor.c index c5077f7143..782b78306c 100644 --- a/src/test/test_hs_descriptor.c +++ b/src/test/test_hs_descriptor.c @@ -243,7 +243,7 @@ test_decode_descriptor(void *arg) hs_descriptor_t *desc = NULL; hs_descriptor_t *decoded = NULL; hs_descriptor_t *desc_no_ip = NULL; - uint8_t subcredential[DIGEST256_LEN]; + hs_subcredential_t subcredential; (void) arg; @@ -252,10 +252,10 @@ test_decode_descriptor(void *arg) desc = hs_helper_build_hs_desc_with_ip(&signing_kp); hs_helper_get_subcred_from_identity_keypair(&signing_kp, - subcredential); + &subcredential); /* Give some bad stuff to the decoding function. */ - ret = hs_desc_decode_descriptor("hladfjlkjadf", subcredential, + ret = hs_desc_decode_descriptor("hladfjlkjadf", &subcredential, NULL, &decoded); tt_int_op(ret, OP_EQ, HS_DESC_DECODE_PLAINTEXT_ERROR); @@ -263,7 +263,7 @@ test_decode_descriptor(void *arg) tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK); tt_assert(encoded); - ret = hs_desc_decode_descriptor(encoded, subcredential, NULL, &decoded); + ret = hs_desc_decode_descriptor(encoded, &subcredential, NULL, &decoded); tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK); tt_assert(decoded); @@ -275,7 +275,7 @@ test_decode_descriptor(void *arg) ret = ed25519_keypair_generate(&signing_kp_no_ip, 0); tt_int_op(ret, OP_EQ, 0); hs_helper_get_subcred_from_identity_keypair(&signing_kp_no_ip, - subcredential); + &subcredential); desc_no_ip = hs_helper_build_hs_desc_no_ip(&signing_kp_no_ip); tt_assert(desc_no_ip); tor_free(encoded); @@ -284,7 +284,7 @@ test_decode_descriptor(void *arg) tt_int_op(ret, OP_EQ, 0); tt_assert(encoded); hs_descriptor_free(decoded); - ret = hs_desc_decode_descriptor(encoded, subcredential, NULL, &decoded); + ret = hs_desc_decode_descriptor(encoded, &subcredential, NULL, &decoded); tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK); tt_assert(decoded); } @@ -308,14 +308,14 @@ test_decode_descriptor(void *arg) &auth_ephemeral_kp.pubkey, CURVE25519_PUBKEY_LEN); hs_helper_get_subcred_from_identity_keypair(&signing_kp, - subcredential); + &subcredential); /* Build and add the auth client to the descriptor. */ clients = desc->superencrypted_data.clients; if (!clients) { clients = smartlist_new(); } - hs_desc_build_authorized_client(subcredential, + hs_desc_build_authorized_client(&subcredential, &client_kp.pubkey, &auth_ephemeral_kp.seckey, descriptor_cookie, client); @@ -337,21 +337,21 @@ test_decode_descriptor(void *arg) /* If we do not have the client secret key, the decoding must fail. */ hs_descriptor_free(decoded); - ret = hs_desc_decode_descriptor(encoded, subcredential, + ret = hs_desc_decode_descriptor(encoded, &subcredential, NULL, &decoded); tt_int_op(ret, OP_EQ, HS_DESC_DECODE_NEED_CLIENT_AUTH); tt_assert(!decoded); /* If we have an invalid client secret key, the decoding must fail. */ hs_descriptor_free(decoded); - ret = hs_desc_decode_descriptor(encoded, subcredential, + ret = hs_desc_decode_descriptor(encoded, &subcredential, &invalid_client_kp.seckey, &decoded); tt_int_op(ret, OP_EQ, HS_DESC_DECODE_BAD_CLIENT_AUTH); tt_assert(!decoded); /* If we have the client secret key, the decoding must succeed and the * decoded descriptor must be correct. */ - ret = hs_desc_decode_descriptor(encoded, subcredential, + ret = hs_desc_decode_descriptor(encoded, &subcredential, &client_kp.seckey, &decoded); tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK); tt_assert(decoded); @@ -784,7 +784,7 @@ test_build_authorized_client(void *arg) "07d087f1d8c68393721f6e70316d3b29"; const char client_pubkey_b16[] = "8c1298fa6050e372f8598f6deca32e27b0ad457741422c2629ebb132cf7fae37"; - uint8_t subcredential[DIGEST256_LEN]; + hs_subcredential_t subcredential; char *mem_op_hex_tmp=NULL; (void) arg; @@ -796,7 +796,7 @@ test_build_authorized_client(void *arg) tt_int_op(ret, OP_EQ, 0); curve25519_public_key_generate(&client_auth_pk, &client_auth_sk); - memset(subcredential, 42, sizeof(subcredential)); + memset(subcredential.subcred, 42, sizeof(subcredential)); desc_client = tor_malloc_zero(sizeof(hs_desc_authorized_client_t)); @@ -817,7 +817,7 @@ test_build_authorized_client(void *arg) testing_enable_prefilled_rng("\x01", 1); - hs_desc_build_authorized_client(subcredential, + hs_desc_build_authorized_client(&subcredential, &client_auth_pk, &auth_ephemeral_sk, descriptor_cookie, desc_client); diff --git a/src/test/test_hs_intropoint.c b/src/test/test_hs_intropoint.c index 5337188427..e6b27d7a50 100644 --- a/src/test/test_hs_intropoint.c +++ b/src/test/test_hs_intropoint.c @@ -757,12 +757,15 @@ test_introduce1_validation(void *arg) cell = helper_create_introduce1_cell(); tt_assert(cell); +#ifndef ALL_BUGS_ARE_FATAL /* It should NOT be a legacy cell which will trigger a BUG(). */ memset(cell->legacy_key_id, 'a', sizeof(cell->legacy_key_id)); tor_capture_bugs_(1); ret = validate_introduce1_parsed_cell(cell); tor_end_capture_bugs_(); tt_int_op(ret, OP_EQ, -1); +#endif /* !defined(ALL_BUGS_ARE_FATAL) */ + /* Reset legacy ID and make sure it's correct. */ memset(cell->legacy_key_id, 0, sizeof(cell->legacy_key_id)); ret = validate_introduce1_parsed_cell(cell); diff --git a/src/test/test_hs_ntor.c b/src/test/test_hs_ntor.c index 4f98bc85dc..7867740a1a 100644 --- a/src/test/test_hs_ntor.c +++ b/src/test/test_hs_ntor.c @@ -23,7 +23,7 @@ test_hs_ntor(void *arg) { int retval; - uint8_t subcredential[DIGEST256_LEN]; + hs_subcredential_t subcredential; ed25519_keypair_t service_intro_auth_keypair; curve25519_keypair_t service_intro_enc_keypair; @@ -42,7 +42,7 @@ test_hs_ntor(void *arg) /* Generate fake data for this unittest */ { /* Generate fake subcredential */ - memset(subcredential, 'Z', DIGEST256_LEN); + memset(subcredential.subcred, 'Z', DIGEST256_LEN); /* service */ curve25519_keypair_generate(&service_intro_enc_keypair, 0); @@ -57,7 +57,7 @@ test_hs_ntor(void *arg) hs_ntor_client_get_introduce1_keys(&service_intro_auth_keypair.pubkey, &service_intro_enc_keypair.pubkey, &client_ephemeral_enc_keypair, - subcredential, + &subcredential, &client_hs_ntor_intro_cell_keys); tt_int_op(retval, OP_EQ, 0); @@ -66,7 +66,7 @@ test_hs_ntor(void *arg) hs_ntor_service_get_introduce1_keys(&service_intro_auth_keypair.pubkey, &service_intro_enc_keypair, &client_ephemeral_enc_keypair.pubkey, - subcredential, + &subcredential, &service_hs_ntor_intro_cell_keys); tt_int_op(retval, OP_EQ, 0); diff --git a/src/test/test_hs_ntor_cl.c b/src/test/test_hs_ntor_cl.c index a7cebc6af4..3acd7ef0bc 100644 --- a/src/test/test_hs_ntor_cl.c +++ b/src/test/test_hs_ntor_cl.c @@ -53,7 +53,7 @@ client1(int argc, char **argv) curve25519_public_key_t intro_enc_pubkey; ed25519_public_key_t intro_auth_pubkey; curve25519_keypair_t client_ephemeral_enc_keypair; - uint8_t subcredential[DIGEST256_LEN]; + hs_subcredential_t subcredential; /* Output */ hs_ntor_intro_cell_keys_t hs_ntor_intro_cell_keys; @@ -65,7 +65,7 @@ client1(int argc, char **argv) BASE16(3, intro_enc_pubkey.public_key, CURVE25519_PUBKEY_LEN); BASE16(4, client_ephemeral_enc_keypair.seckey.secret_key, CURVE25519_SECKEY_LEN); - BASE16(5, subcredential, DIGEST256_LEN); + BASE16(5, subcredential.subcred, DIGEST256_LEN); /* Generate keypair */ curve25519_public_key_generate(&client_ephemeral_enc_keypair.pubkey, @@ -74,7 +74,7 @@ client1(int argc, char **argv) retval = hs_ntor_client_get_introduce1_keys(&intro_auth_pubkey, &intro_enc_pubkey, &client_ephemeral_enc_keypair, - subcredential, + &subcredential, &hs_ntor_intro_cell_keys); if (retval < 0) { goto done; @@ -106,7 +106,7 @@ server1(int argc, char **argv) curve25519_keypair_t intro_enc_keypair; ed25519_public_key_t intro_auth_pubkey; curve25519_public_key_t client_ephemeral_enc_pubkey; - uint8_t subcredential[DIGEST256_LEN]; + hs_subcredential_t subcredential; /* Output */ hs_ntor_intro_cell_keys_t hs_ntor_intro_cell_keys; @@ -119,7 +119,7 @@ server1(int argc, char **argv) BASE16(2, intro_auth_pubkey.pubkey, ED25519_PUBKEY_LEN); BASE16(3, intro_enc_keypair.seckey.secret_key, CURVE25519_SECKEY_LEN); BASE16(4, client_ephemeral_enc_pubkey.public_key, CURVE25519_PUBKEY_LEN); - BASE16(5, subcredential, DIGEST256_LEN); + BASE16(5, subcredential.subcred, DIGEST256_LEN); /* Generate keypair */ curve25519_public_key_generate(&intro_enc_keypair.pubkey, @@ -130,7 +130,7 @@ server1(int argc, char **argv) retval = hs_ntor_service_get_introduce1_keys(&intro_auth_pubkey, &intro_enc_keypair, &client_ephemeral_enc_pubkey, - subcredential, + &subcredential, &hs_ntor_intro_cell_keys); if (retval < 0) { goto done; @@ -188,7 +188,7 @@ client2(int argc, char **argv) ed25519_public_key_t intro_auth_pubkey; curve25519_keypair_t client_ephemeral_enc_keypair; curve25519_public_key_t service_ephemeral_rend_pubkey; - uint8_t subcredential[DIGEST256_LEN]; + hs_subcredential_t subcredential; /* Output */ hs_ntor_rend_cell_keys_t hs_ntor_rend_cell_keys; @@ -201,7 +201,7 @@ client2(int argc, char **argv) CURVE25519_SECKEY_LEN); BASE16(4, intro_enc_pubkey.public_key, CURVE25519_PUBKEY_LEN); BASE16(5, service_ephemeral_rend_pubkey.public_key, CURVE25519_PUBKEY_LEN); - BASE16(6, subcredential, DIGEST256_LEN); + BASE16(6, subcredential.subcred, DIGEST256_LEN); /* Generate keypair */ curve25519_public_key_generate(&client_ephemeral_enc_keypair.pubkey, diff --git a/src/test/test_hs_ob.c b/src/test/test_hs_ob.c new file mode 100644 index 0000000000..7f40187b5f --- /dev/null +++ b/src/test/test_hs_ob.c @@ -0,0 +1,268 @@ +/* Copyright (c) 2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file test_hs_ob.c + * \brief Test hidden service onion balance functionality. + */ + +#define CONFIG_PRIVATE +#define HS_SERVICE_PRIVATE +#define HS_OB_PRIVATE + +#include "test/test.h" +#include "test/test_helpers.h" +#include "test/log_test_helpers.h" + +#include "app/config/config.h" +#include "feature/hs/hs_config.h" +#include "feature/hs/hs_ob.h" +#include "feature/hs/hs_service.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/networkstatus_st.h" + +static ed25519_keypair_t onion_addr_kp_1; +static char onion_addr_1[HS_SERVICE_ADDR_LEN_BASE32 + 1]; + +static ed25519_keypair_t onion_addr_kp_2; +static char onion_addr_2[HS_SERVICE_ADDR_LEN_BASE32 + 1]; + +static bool config_is_good = true; + +static int +helper_tor_config(const char *conf) +{ + int ret = -1; + or_options_t *options = helper_parse_options(conf); + tt_assert(options); + ret = hs_config_service_all(options, 0); + done: + or_options_free(options); + return ret; +} + +static networkstatus_t mock_ns; + +static networkstatus_t * +mock_networkstatus_get_live_consensus(time_t now) +{ + (void) now; + return &mock_ns; +} + +static char * +mock_read_file_to_str(const char *filename, int flags, struct stat *stat_out) +{ + char *ret = NULL; + + (void) flags; + (void) stat_out; + + if (!strcmp(filename, get_fname("hs3" PATH_SEPARATOR "ob_config"))) { + if (config_is_good) { + tor_asprintf(&ret, "MasterOnionAddress %s.onion\n" + "MasterOnionAddress %s.onion\n", + onion_addr_1, onion_addr_2); + } else { + tor_asprintf(&ret, "MasterOnionAddress JUNKJUNKJUNK.onion\n" + "UnknownOption BLAH\n"); + } + goto done; + } + + done: + return ret; +} + +static void +test_parse_config_file(void *arg) +{ + int ret; + char *conf = NULL; + const ed25519_public_key_t *pkey; + + (void) arg; + + hs_init(); + + MOCK(read_file_to_str, mock_read_file_to_str); + +#define fmt_conf \ + "HiddenServiceDir %s\n" \ + "HiddenServicePort 22\n" \ + "HiddenServiceOnionBalanceInstance 1\n" + tor_asprintf(&conf, fmt_conf, get_fname("hs3")); +#undef fmt_conf + + /* Build the OB frontend onion addresses. */ + ed25519_keypair_generate(&onion_addr_kp_1, 0); + hs_build_address(&onion_addr_kp_1.pubkey, HS_VERSION_THREE, onion_addr_1); + ed25519_keypair_generate(&onion_addr_kp_2, 0); + hs_build_address(&onion_addr_kp_2.pubkey, HS_VERSION_THREE, onion_addr_2); + + ret = helper_tor_config(conf); + tor_free(conf); + tt_int_op(ret, OP_EQ, 0); + + /* Load the keys for the service. After that, the v3 service should be + * registered in the global map and we'll be able to access it. */ + tt_int_op(get_hs_service_staging_list_size(), OP_EQ, 1); + hs_service_load_all_keys(); + tt_int_op(get_hs_service_map_size(), OP_EQ, 1); + const hs_service_t *s = get_first_service(); + tt_assert(s); + tt_assert(s->config.ob_master_pubkeys); + tt_assert(hs_ob_service_is_instance(s)); + tt_assert(smartlist_len(s->config.ob_master_pubkeys) == 2); + + /* Test the public keys we've added. */ + pkey = smartlist_get(s->config.ob_master_pubkeys, 0); + tt_mem_op(&onion_addr_kp_1.pubkey, OP_EQ, pkey, ED25519_PUBKEY_LEN); + pkey = smartlist_get(s->config.ob_master_pubkeys, 1); + tt_mem_op(&onion_addr_kp_2.pubkey, OP_EQ, pkey, ED25519_PUBKEY_LEN); + + done: + hs_free_all(); + + UNMOCK(read_file_to_str); +} + +static void +test_parse_config_file_bad(void *arg) +{ + int ret; + char *conf = NULL; + + (void) arg; + + hs_init(); + + MOCK(read_file_to_str, mock_read_file_to_str); + + /* Indicate mock_read_file_to_str() to use the bad config. */ + config_is_good = false; + +#define fmt_conf \ + "HiddenServiceDir %s\n" \ + "HiddenServicePort 22\n" \ + "HiddenServiceOnionBalanceInstance 1\n" + tor_asprintf(&conf, fmt_conf, get_fname("hs3")); +#undef fmt_conf + + setup_full_capture_of_logs(LOG_INFO); + ret = helper_tor_config(conf); + tor_free(conf); + tt_int_op(ret, OP_EQ, -1); + expect_log_msg_containing("OnionBalance: MasterOnionAddress " + "JUNKJUNKJUNK.onion is invalid"); + expect_log_msg_containing("Found unrecognized option \'UnknownOption\'; " + "saving it."); + teardown_capture_of_logs(); + + done: + hs_free_all(); + + UNMOCK(read_file_to_str); +} + +static void +test_get_subcredentials(void *arg) +{ + int ret; + hs_service_t *service = NULL; + hs_service_config_t config; + hs_subcredential_t *subcreds = NULL; + + (void) arg; + + MOCK(networkstatus_get_live_consensus, + mock_networkstatus_get_live_consensus); + + /* Setup consensus with proper time so we can compute the time period. */ + ret = parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC", + &mock_ns.valid_after); + tt_int_op(ret, OP_EQ, 0); + ret = parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC", + &mock_ns.fresh_until); + tt_int_op(ret, OP_EQ, 0); + + config.ob_master_pubkeys = smartlist_new(); + tt_assert(config.ob_master_pubkeys); + + /* Set up an instance */ + service = tor_malloc_zero(sizeof(hs_service_t)); + service->config = config; + /* Setup the service descriptors */ + service->desc_current = service_descriptor_new(); + service->desc_next = service_descriptor_new(); + + /* First try to compute subcredentials but with no OB keys. Make sure that + * subcreds get NULLed. To do this check we first poison subcreds. */ + subcreds = (void*)999; + tt_ptr_op(subcreds, OP_NE, NULL); + size_t num = compute_subcredentials(service, &subcreds); + tt_ptr_op(subcreds, OP_EQ, NULL); + + /* Generate a keypair to add to the OB keys list. */ + ed25519_keypair_generate(&onion_addr_kp_1, 0); + smartlist_add(config.ob_master_pubkeys, &onion_addr_kp_1.pubkey); + + /* Set up the instance subcredentials */ + char current_subcred[SUBCRED_LEN]; + char next_subcred[SUBCRED_LEN]; + memset(current_subcred, 'C', SUBCRED_LEN); + memset(next_subcred, 'N', SUBCRED_LEN); + memcpy(service->desc_current->desc->subcredential.subcred, current_subcred, + SUBCRED_LEN); + memcpy(service->desc_next->desc->subcredential.subcred, next_subcred, + SUBCRED_LEN); + + /* See that subcreds are computed properly */ + num = compute_subcredentials(service, &subcreds); + /* 5 subcredentials: 3 for the frontend, 2 for the instance */ + tt_uint_op(num, OP_EQ, 5); + tt_ptr_op(subcreds, OP_NE, NULL); + + /* Validate the subcredentials we just got. We'll build them oursevles with + * the right time period steps and compare. */ + const uint64_t tp = hs_get_time_period_num(0); + const int steps[3] = {0, -1, 1}; + + unsigned int i; + for (i = 0; i < 3; i++) { + hs_subcredential_t subcredential; + ed25519_public_key_t blinded_pubkey; + hs_build_blinded_pubkey(&onion_addr_kp_1.pubkey, NULL, 0, tp + steps[i], + &blinded_pubkey); + hs_get_subcredential(&onion_addr_kp_1.pubkey, &blinded_pubkey, + &subcredential); + tt_mem_op(subcreds[i].subcred, OP_EQ, subcredential.subcred, + SUBCRED_LEN); + } + + tt_mem_op(subcreds[i++].subcred, OP_EQ, current_subcred, SUBCRED_LEN); + tt_mem_op(subcreds[i++].subcred, OP_EQ, next_subcred, SUBCRED_LEN); + + done: + tor_free(subcreds); + + smartlist_free(config.ob_master_pubkeys); + if (service) { + memset(&service->config, 0, sizeof(hs_service_config_t)); + hs_service_free(service); + } + + UNMOCK(networkstatus_get_live_consensus); +} + +struct testcase_t hs_ob_tests[] = { + { "parse_config_file", test_parse_config_file, TT_FORK, + NULL, NULL }, + { "parse_config_file_bad", test_parse_config_file_bad, TT_FORK, + NULL, NULL }, + + { "get_subcredentials", test_get_subcredentials, TT_FORK, + NULL, NULL }, + + END_OF_TESTCASES +}; diff --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c index 49c8d29d27..8b94bb6cf1 100644 --- a/src/test/test_hs_service.c +++ b/src/test/test_hs_service.c @@ -44,13 +44,15 @@ #include "core/or/versions.h" #include "feature/dirauth/dirvote.h" #include "feature/dirauth/shared_random_state.h" -#include "feature/dircommon/voting_schedule.h" +#include "feature/dirauth/voting_schedule.h" #include "feature/hs/hs_circuit.h" #include "feature/hs/hs_circuitmap.h" #include "feature/hs/hs_client.h" #include "feature/hs/hs_common.h" #include "feature/hs/hs_config.h" #include "feature/hs/hs_ident.h" +#include "feature/hs/hs_ob.h" +#include "feature/hs/hs_cell.h" #include "feature/hs/hs_intropoint.h" #include "feature/hs/hs_service.h" #include "feature/nodelist/networkstatus.h" @@ -88,6 +90,14 @@ mock_networkstatus_get_reasonably_live_consensus(time_t now, int flavor) return &mock_ns; } +static networkstatus_t * +mock_networkstatus_get_reasonably_live_consensus_null(time_t now, int flavor) +{ + (void) now; + (void) flavor; + return NULL; +} + static or_state_t *dummy_state = NULL; /* Mock function to get fake or state (used for rev counters) */ @@ -110,6 +120,9 @@ mock_circuit_mark_for_close(circuit_t *circ, int reason, int line, return; } +static size_t relay_payload_len; +static char relay_payload[RELAY_PAYLOAD_SIZE]; + static int mock_relay_send_command_from_edge(streamid_t stream_id, circuit_t *circ, uint8_t relay_command, const char *payload, @@ -125,6 +138,24 @@ mock_relay_send_command_from_edge(streamid_t stream_id, circuit_t *circ, (void) cpath_layer; (void) filename; (void) lineno; + + memcpy(relay_payload, payload, payload_len); + relay_payload_len = payload_len; + + return 0; +} + +static unsigned int num_intro_points = 0; +static unsigned int +mock_count_desc_circuit_established(const hs_service_descriptor_t *desc) +{ + (void) desc; + return num_intro_points; +} + +static int +mock_router_have_minimum_dir_info_false(void) +{ return 0; } @@ -1161,7 +1192,7 @@ test_closing_intro_circs(void *arg) /** Test sending and receiving introduce2 cells */ static void -test_introduce2(void *arg) +test_bad_introduce2(void *arg) { int ret; int flags = CIRCLAUNCH_NEED_UPTIME | CIRCLAUNCH_IS_INTERNAL; @@ -1357,7 +1388,7 @@ test_rotate_descriptors(void *arg) ret = parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC", &mock_ns.fresh_until); tt_int_op(ret, OP_EQ, 0); - voting_schedule_recalculate_timing(get_options(), mock_ns.valid_after); + dirauth_sched_recalculate_timing(get_options(), mock_ns.valid_after); update_approx_time(mock_ns.valid_after+1); now = mock_ns.valid_after+1; @@ -1398,7 +1429,7 @@ test_rotate_descriptors(void *arg) ret = parse_rfc1123_time("Sat, 27 Oct 1985 02:00:00 UTC", &mock_ns.fresh_until); tt_int_op(ret, OP_EQ, 0); - voting_schedule_recalculate_timing(get_options(), mock_ns.valid_after); + dirauth_sched_recalculate_timing(get_options(), mock_ns.valid_after); update_approx_time(mock_ns.valid_after+1); now = mock_ns.valid_after+1; @@ -1466,7 +1497,7 @@ test_build_update_descriptors(void *arg) ret = parse_rfc1123_time("Sat, 26 Oct 1985 04:00:00 UTC", &mock_ns.fresh_until); tt_int_op(ret, OP_EQ, 0); - voting_schedule_recalculate_timing(get_options(), mock_ns.valid_after); + dirauth_sched_recalculate_timing(get_options(), mock_ns.valid_after); update_approx_time(mock_ns.valid_after+1); @@ -1697,7 +1728,7 @@ test_build_descriptors(void *arg) ret = parse_rfc1123_time("Sat, 26 Oct 1985 04:00:00 UTC", &mock_ns.fresh_until); tt_int_op(ret, OP_EQ, 0); - voting_schedule_recalculate_timing(get_options(), mock_ns.valid_after); + dirauth_sched_recalculate_timing(get_options(), mock_ns.valid_after); /* Generate a valid number of fake auth clients when a client authorization * is disabled. */ @@ -1798,7 +1829,7 @@ test_upload_descriptors(void *arg) ret = parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC", &mock_ns.fresh_until); tt_int_op(ret, OP_EQ, 0); - voting_schedule_recalculate_timing(get_options(), mock_ns.valid_after); + dirauth_sched_recalculate_timing(get_options(), mock_ns.valid_after); update_approx_time(mock_ns.valid_after+1); now = mock_ns.valid_after+1; @@ -2170,6 +2201,490 @@ test_export_client_circuit_id(void *arg) tor_free(cp2); } +static smartlist_t * +mock_node_get_link_specifier_smartlist(const node_t *node, bool direct_conn) +{ + (void) node; + (void) direct_conn; + + smartlist_t *lspecs = smartlist_new(); + link_specifier_t *ls_legacy = link_specifier_new(); + smartlist_add(lspecs, ls_legacy); + + return lspecs; +} + +static node_t *fake_node = NULL; + +static const node_t * +mock_build_state_get_exit_node(cpath_build_state_t *state) +{ + (void) state; + + if (!fake_node) { + curve25519_secret_key_t seckey; + curve25519_secret_key_generate(&seckey, 0); + + fake_node = tor_malloc_zero(sizeof(node_t)); + fake_node->ri = tor_malloc_zero(sizeof(routerinfo_t)); + fake_node->ri->onion_curve25519_pkey = + tor_malloc_zero(sizeof(curve25519_public_key_t)); + curve25519_public_key_generate(fake_node->ri->onion_curve25519_pkey, + &seckey); + } + + return fake_node; +} + +static void +mock_launch_rendezvous_point_circuit(const hs_service_t *service, + const hs_service_intro_point_t *ip, + const hs_cell_introduce2_data_t *data) +{ + (void) service; + (void) ip; + (void) data; + return; +} + +/** + * Test that INTRO2 cells are handled well by onion services in the normal + * case and also when onionbalance is enabled. + */ +static void +test_intro2_handling(void *arg) +{ + (void)arg; + + MOCK(build_state_get_exit_node, mock_build_state_get_exit_node); + MOCK(relay_send_command_from_edge_, mock_relay_send_command_from_edge); + MOCK(node_get_link_specifier_smartlist, + mock_node_get_link_specifier_smartlist); + MOCK(launch_rendezvous_point_circuit, mock_launch_rendezvous_point_circuit); + + memset(relay_payload, 0, sizeof(relay_payload)); + + int retval; + time_t now = 0101010101; + update_approx_time(now); + + /** OK this is the play: + * + * In Act I, we have a standalone onion service X (without onionbalance + * enabled). We test that X can properly handle INTRO2 cells sent by a + * client Alice. + * + * In Act II, we create an onionbalance setup with frontend being Z which + * includes instances X and Y. We then setup onionbalance on X and test that + * Alice who addresses Z can communicate with X through INTRO2 cells. + * + * In Act III, we test that Alice can also communicate with X + * directly even tho onionbalance is enabled. + * + * And finally in Act IV, we check various cases where the INTRO2 cell + * should not go through because the subcredentials don't line up + * (e.g. Alice sends INTRO2 to X using Y's subcredential). + */ + + /** Let's start with some setup! Create the instances and the frontend + service, create Alice, etc: */ + + /* Create instance X */ + hs_service_t x_service; + memset(&x_service, 0, sizeof(hs_service_t)); + /* Disable onionbalance */ + x_service.config.ob_master_pubkeys = NULL; + x_service.state.replay_cache_rend_cookie = replaycache_new(0,0); + + /* Create subcredential for x: */ + ed25519_keypair_t x_identity_keypair; + hs_subcredential_t x_subcred; + ed25519_keypair_generate(&x_identity_keypair, 0); + hs_helper_get_subcred_from_identity_keypair(&x_identity_keypair, + &x_subcred); + + /* Create the x instance's intro point */ + hs_service_intro_point_t *x_ip = NULL; + { + curve25519_secret_key_t seckey; + curve25519_public_key_t pkey; + curve25519_secret_key_generate(&seckey, 0); + curve25519_public_key_generate(&pkey, &seckey); + + node_t intro_node; + memset(&intro_node, 0, sizeof(intro_node)); + routerinfo_t ri; + memset(&ri, 0, sizeof(routerinfo_t)); + ri.onion_curve25519_pkey = &pkey; + intro_node.ri = &ri; + + x_ip = service_intro_point_new(&intro_node); + } + + /* Create z frontend's subcredential */ + ed25519_keypair_t z_identity_keypair; + hs_subcredential_t z_subcred; + ed25519_keypair_generate(&z_identity_keypair, 0); + hs_helper_get_subcred_from_identity_keypair(&z_identity_keypair, + &z_subcred); + + /* Create y instance's subcredential */ + ed25519_keypair_t y_identity_keypair; + hs_subcredential_t y_subcred; + ed25519_keypair_generate(&y_identity_keypair, 0); + hs_helper_get_subcred_from_identity_keypair(&y_identity_keypair, + &y_subcred); + + /* Create Alice's intro point */ + hs_desc_intro_point_t *alice_ip; + ed25519_keypair_t signing_kp; + ed25519_keypair_generate(&signing_kp, 0); + alice_ip = hs_helper_build_intro_point(&signing_kp, now, "1.2.3.4", 0, + &x_ip->auth_key_kp, + &x_ip->enc_key_kp); + + /* Create Alice's intro and rend circuits */ + origin_circuit_t *intro_circ = origin_circuit_new(); + intro_circ->cpath = tor_malloc_zero(sizeof(crypt_path_t)); + intro_circ->cpath->prev = intro_circ->cpath; + intro_circ->hs_ident = tor_malloc_zero(sizeof(*intro_circ->hs_ident)); + origin_circuit_t rend_circ; + rend_circ.hs_ident = tor_malloc_zero(sizeof(*rend_circ.hs_ident)); + curve25519_keypair_generate(&rend_circ.hs_ident->rendezvous_client_kp, 0); + memset(rend_circ.hs_ident->rendezvous_cookie, 'r', HS_REND_COOKIE_LEN); + + /* ************************************************************ */ + + /* Act I: + * + * Where Alice connects to X without onionbalance in the picture */ + + /* Create INTRODUCE1 */ + tt_assert(fast_mem_is_zero(relay_payload, sizeof(relay_payload))); + retval = hs_circ_send_introduce1(intro_circ, &rend_circ, + alice_ip, &x_subcred); + + /* Check that the payload was written successfully */ + tt_int_op(retval, OP_EQ, 0); + tt_assert(!fast_mem_is_zero(relay_payload, sizeof(relay_payload))); + tt_int_op(relay_payload_len, OP_NE, 0); + + /* Handle the cell */ + retval = hs_circ_handle_introduce2(&x_service, + intro_circ, x_ip, + &x_subcred, + (uint8_t*)relay_payload,relay_payload_len); + tt_int_op(retval, OP_EQ, 0); + + /* ************************************************************ */ + + /* Act II: + * + * We now create an onionbalance setup with Z being the frontend and X and Y + * being the backend instances. Make sure that Alice can talk with the + * backend instance X even tho she thinks she is talking to the frontend Z. + */ + + /* Now configure the X instance to do onionbalance with Z as the frontend */ + x_service.config.ob_master_pubkeys = smartlist_new(); + smartlist_add(x_service.config.ob_master_pubkeys, + &z_identity_keypair.pubkey); + + /* Create descriptors for x and load next descriptor with the x's + * subcredential so that it can accept connections for itself. */ + x_service.desc_current = service_descriptor_new(); + memset(x_service.desc_current->desc->subcredential.subcred, 'C',SUBCRED_LEN); + x_service.desc_next = service_descriptor_new(); + memcpy(&x_service.desc_next->desc->subcredential, &x_subcred, SUBCRED_LEN); + + /* Refresh OB keys */ + hs_ob_refresh_keys(&x_service); + + /* Create INTRODUCE1 from Alice to X through Z */ + memset(relay_payload, 0, sizeof(relay_payload)); + retval = hs_circ_send_introduce1(intro_circ, &rend_circ, + alice_ip, &z_subcred); + + /* Check that the payload was written successfully */ + tt_int_op(retval, OP_EQ, 0); + tt_assert(!fast_mem_is_zero(relay_payload, sizeof(relay_payload))); + tt_int_op(relay_payload_len, OP_NE, 0); + + /* Deliver INTRODUCE1 to X even tho it carries Z's subcredential */ + replaycache_free(x_service.state.replay_cache_rend_cookie); + x_service.state.replay_cache_rend_cookie = replaycache_new(0, 0); + + retval = hs_circ_handle_introduce2(&x_service, + intro_circ, x_ip, + &z_subcred, + (uint8_t*)relay_payload, relay_payload_len); + tt_int_op(retval, OP_EQ, 0); + + replaycache_free(x_ip->replay_cache); + x_ip->replay_cache = replaycache_new(0, 0); + + replaycache_free(x_service.state.replay_cache_rend_cookie); + x_service.state.replay_cache_rend_cookie = replaycache_new(0, 0); + + /* ************************************************************ */ + + /* Act III: + * + * Now send a direct INTRODUCE cell from Alice to X using X's subcredential + * and check that it succeeds even with onionbalance enabled. + */ + + /* Refresh OB keys (just to check for memleaks) */ + hs_ob_refresh_keys(&x_service); + + /* Create INTRODUCE1 from Alice to X using X's subcred. */ + memset(relay_payload, 0, sizeof(relay_payload)); + retval = hs_circ_send_introduce1(intro_circ, &rend_circ, + alice_ip, &x_subcred); + + /* Check that the payload was written successfully */ + tt_int_op(retval, OP_EQ, 0); + tt_assert(!fast_mem_is_zero(relay_payload, sizeof(relay_payload))); + tt_int_op(relay_payload_len, OP_NE, 0); + + /* Send INTRODUCE1 to X with X's subcredential (should succeed) */ + replaycache_free(x_service.state.replay_cache_rend_cookie); + x_service.state.replay_cache_rend_cookie = replaycache_new(0, 0); + + retval = hs_circ_handle_introduce2(&x_service, + intro_circ, x_ip, + &x_subcred, + (uint8_t*)relay_payload, relay_payload_len); + tt_int_op(retval, OP_EQ, 0); + + /* ************************************************************ */ + + /* Act IV: + * + * Test cases where the INTRO2 cell should not be able to decode. + */ + + /* Try sending the exact same INTRODUCE2 cell again and see that the intro + * point replay cache triggers: */ + setup_full_capture_of_logs(LOG_WARN); + retval = hs_circ_handle_introduce2(&x_service, + intro_circ, x_ip, + &x_subcred, + (uint8_t*)relay_payload, relay_payload_len); + tt_int_op(retval, OP_EQ, -1); + expect_log_msg_containing("with the same ENCRYPTED section"); + teardown_capture_of_logs(); + + /* Now cleanup the intro point replay cache but not the service replay cache + and see that this one triggers this time. */ + replaycache_free(x_ip->replay_cache); + x_ip->replay_cache = replaycache_new(0, 0); + setup_full_capture_of_logs(LOG_INFO); + retval = hs_circ_handle_introduce2(&x_service, + intro_circ, x_ip, + &x_subcred, + (uint8_t*)relay_payload, relay_payload_len); + tt_int_op(retval, OP_EQ, -1); + expect_log_msg_containing("with same REND_COOKIE"); + teardown_capture_of_logs(); + + /* Now just to make sure cleanup both replay caches and make sure that the + cell gets through */ + replaycache_free(x_ip->replay_cache); + x_ip->replay_cache = replaycache_new(0, 0); + replaycache_free(x_service.state.replay_cache_rend_cookie); + x_service.state.replay_cache_rend_cookie = replaycache_new(0, 0); + retval = hs_circ_handle_introduce2(&x_service, + intro_circ, x_ip, + &x_subcred, + (uint8_t*)relay_payload, relay_payload_len); + tt_int_op(retval, OP_EQ, 0); + + /* As a final thing, create an INTRODUCE1 cell from Alice to X using Y's + * subcred (should fail since Y is just another instance and not the frontend + * service!) */ + memset(relay_payload, 0, sizeof(relay_payload)); + retval = hs_circ_send_introduce1(intro_circ, &rend_circ, + alice_ip, &y_subcred); + tt_int_op(retval, OP_EQ, 0); + + /* Check that the payload was written successfully */ + tt_assert(!fast_mem_is_zero(relay_payload, sizeof(relay_payload))); + tt_int_op(relay_payload_len, OP_NE, 0); + + retval = hs_circ_handle_introduce2(&x_service, + intro_circ, x_ip, + &y_subcred, + (uint8_t*)relay_payload, relay_payload_len); + tt_int_op(retval, OP_EQ, -1); + + done: + /* Start cleaning up X */ + replaycache_free(x_service.state.replay_cache_rend_cookie); + smartlist_free(x_service.config.ob_master_pubkeys); + tor_free(x_service.state.ob_subcreds); + service_descriptor_free(x_service.desc_current); + service_descriptor_free(x_service.desc_next); + service_intro_point_free(x_ip); + + /* Clean up Alice */ + hs_desc_intro_point_free(alice_ip); + tor_free(rend_circ.hs_ident); + + if (fake_node) { + tor_free(fake_node->ri->onion_curve25519_pkey); + tor_free(fake_node->ri); + tor_free(fake_node); + } + + UNMOCK(build_state_get_exit_node); + UNMOCK(relay_send_command_from_edge_); + UNMOCK(node_get_link_specifier_smartlist); + UNMOCK(launch_rendezvous_point_circuit); +} + +static void +test_cannot_upload_descriptors(void *arg) +{ + int ret; + time_t now; + hs_service_t *service; + + (void) arg; + + hs_init(); + MOCK(get_or_state, + get_or_state_replacement); + MOCK(networkstatus_get_reasonably_live_consensus, + mock_networkstatus_get_reasonably_live_consensus); + + dummy_state = or_state_new(); + + ret = parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC", + &mock_ns.valid_after); + tt_int_op(ret, OP_EQ, 0); + ret = parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC", + &mock_ns.fresh_until); + tt_int_op(ret, OP_EQ, 0); + dirauth_sched_recalculate_timing(get_options(), mock_ns.valid_after); + + update_approx_time(mock_ns.valid_after + 1); + now = mock_ns.valid_after + 1; + + /* Create a service with no descriptor. It's added to the global map. */ + service = hs_service_new(get_options()); + tt_assert(service); + service->config.version = HS_VERSION_THREE; + ed25519_secret_key_generate(&service->keys.identity_sk, 0); + ed25519_public_key_generate(&service->keys.identity_pk, + &service->keys.identity_sk); + /* Register service to global map. */ + ret = register_service(get_hs_service_map(), service); + tt_int_op(ret, OP_EQ, 0); + /* But first, build our descriptor. */ + build_all_descriptors(now); + + /* 1. Testing missing intro points reason. */ + { + digest256map_t *cur = service->desc_current->intro_points.map; + digest256map_t *tmp = digest256map_new(); + service->desc_current->intro_points.map = tmp; + service->desc_current->missing_intro_points = 1; + setup_full_capture_of_logs(LOG_INFO); + run_upload_descriptor_event(now); + digest256map_free(tmp, tor_free_); + service->desc_current->intro_points.map = cur; + expect_log_msg_containing( + "Service [scrubbed] can't upload its current descriptor: " + "Missing intro points"); + teardown_capture_of_logs(); + /* Reset. */ + service->desc_current->missing_intro_points = 0; + } + + /* 2. Testing non established intro points. */ + { + setup_full_capture_of_logs(LOG_INFO); + run_upload_descriptor_event(now); + expect_log_msg_containing( + "Service [scrubbed] can't upload its current descriptor: " + "Intro circuits aren't yet all established (0/3)."); + teardown_capture_of_logs(); + } + + /* We need to pass the established circuit tests and thus from now on, we + * MOCK this to return 3 intro points. */ + MOCK(count_desc_circuit_established, mock_count_desc_circuit_established); + num_intro_points = 3; + + /* 3. Testing non established intro points. */ + { + service->desc_current->next_upload_time = now + 1000; + setup_full_capture_of_logs(LOG_INFO); + run_upload_descriptor_event(now); + expect_log_msg_containing( + "Service [scrubbed] can't upload its current descriptor: " + "Next upload time is"); + teardown_capture_of_logs(); + /* Reset. */ + service->desc_current->next_upload_time = 0; + } + + /* 4. Testing missing live consensus. */ + { + MOCK(networkstatus_get_reasonably_live_consensus, + mock_networkstatus_get_reasonably_live_consensus_null); + setup_full_capture_of_logs(LOG_INFO); + run_upload_descriptor_event(now); + expect_log_msg_containing( + "Service [scrubbed] can't upload its current descriptor: " + "No reasonably live consensus"); + teardown_capture_of_logs(); + /* Reset. */ + MOCK(networkstatus_get_reasonably_live_consensus, + mock_networkstatus_get_reasonably_live_consensus); + } + + /* 5. Test missing minimum directory information. */ + { + MOCK(router_have_minimum_dir_info, + mock_router_have_minimum_dir_info_false); + setup_full_capture_of_logs(LOG_INFO); + run_upload_descriptor_event(now); + expect_log_msg_containing( + "Service [scrubbed] can't upload its current descriptor: " + "Not enough directory information"); + teardown_capture_of_logs(); + + /* Running it again shouldn't trigger anything due to rate limitation. */ + setup_full_capture_of_logs(LOG_INFO); + run_upload_descriptor_event(now); + expect_no_log_entry(); + teardown_capture_of_logs(); + UNMOCK(router_have_minimum_dir_info); + } + + /* Increase time and redo test (5) in order to test the rate limiting. */ + update_approx_time(mock_ns.valid_after + 61); + { + MOCK(router_have_minimum_dir_info, + mock_router_have_minimum_dir_info_false); + setup_full_capture_of_logs(LOG_INFO); + run_upload_descriptor_event(now); + expect_log_msg_containing( + "Service [scrubbed] can't upload its current descriptor: " + "Not enough directory information"); + teardown_capture_of_logs(); + UNMOCK(router_have_minimum_dir_info); + } + + done: + hs_free_all(); + UNMOCK(count_desc_circuit_established); + UNMOCK(networkstatus_get_reasonably_live_consensus); + UNMOCK(get_or_state); +} + struct testcase_t hs_service_tests[] = { { "e2e_rend_circuit_setup", test_e2e_rend_circuit_setup, TT_FORK, NULL, NULL }, @@ -2195,7 +2710,7 @@ struct testcase_t hs_service_tests[] = { NULL, NULL }, { "rdv_circuit_opened", test_rdv_circuit_opened, TT_FORK, NULL, NULL }, - { "introduce2", test_introduce2, TT_FORK, + { "bad_introduce2", test_bad_introduce2, TT_FORK, NULL, NULL }, { "service_event", test_service_event, TT_FORK, NULL, NULL }, @@ -2207,12 +2722,15 @@ struct testcase_t hs_service_tests[] = { NULL, NULL }, { "upload_descriptors", test_upload_descriptors, TT_FORK, NULL, NULL }, + { "cannot_upload_descriptors", test_cannot_upload_descriptors, TT_FORK, + NULL, NULL }, { "rendezvous1_parsing", test_rendezvous1_parsing, TT_FORK, NULL, NULL }, { "authorized_client_config_equal", test_authorized_client_config_equal, TT_FORK, NULL, NULL }, { "export_client_circuit_id", test_export_client_circuit_id, TT_FORK, NULL, NULL }, + { "intro2_handling", test_intro2_handling, TT_FORK, NULL, NULL }, END_OF_TESTCASES }; diff --git a/src/test/test_link_handshake.c b/src/test/test_link_handshake.c index 96542ce7ac..1566b349ed 100644 --- a/src/test/test_link_handshake.c +++ b/src/test/test_link_handshake.c @@ -18,6 +18,7 @@ #include "feature/relay/routerkeys.h" #include "core/or/scheduler.h" #include "feature/nodelist/torcert.h" +#include "feature/relay/relay_handshake.h" #include "core/or/or_connection_st.h" #include "core/or/or_handshake_certs_st.h" diff --git a/src/test/test_options.c b/src/test/test_options.c index 9cd1d11d29..8e0d19f126 100644 --- a/src/test/test_options.c +++ b/src/test/test_options.c @@ -2362,7 +2362,7 @@ test_options_validate__rend(void *ignored) expect_log_msg("UseEntryGuards is disabled, but you" " have configured one or more hidden services on this Tor " "instance. Your hidden services will be very easy to locate using" - " a well-known attack -- see http://freehaven.net/anonbib/#hs-" + " a well-known attack -- see https://freehaven.net/anonbib/#hs-" "attack06 for details.\n"); tor_free(msg); @@ -2378,7 +2378,7 @@ test_options_validate__rend(void *ignored) expect_no_log_msg("UseEntryGuards is disabled, but you" " have configured one or more hidden services on this Tor " "instance. Your hidden services will be very easy to locate using" - " a well-known attack -- see http://freehaven.net/anonbib/#hs-" + " a well-known attack -- see https://freehaven.net/anonbib/#hs-" "attack06 for details.\n"); free_options_test_data(tdata); diff --git a/src/test/test_policy.c b/src/test/test_policy.c index 762241249c..7949e90e9e 100644 --- a/src/test/test_policy.c +++ b/src/test/test_policy.c @@ -62,8 +62,8 @@ test_policy_summary_helper_family_flags(const char *policy_str, short_policy_t *short_policy = NULL; int success = 0; - line.key = (char*)"foo"; - line.value = (char *)policy_str; + line.key = (char *) "foo"; + line.value = (char *) policy_str; line.next = NULL; r = policies_parse_exit_policy(&line, &policy, @@ -2124,20 +2124,6 @@ test_policies_fascist_firewall_allows_address(void *arg) teardown_capture_of_logs(); \ STMT_END -/** Mock the preferred address function to return zero (prefer IPv4). */ -static int -mock_fascist_firewall_rand_prefer_ipv6_addr_use_ipv4(void) -{ - return 0; -} - -/** Mock the preferred address function to return one (prefer IPv6). */ -static int -mock_fascist_firewall_rand_prefer_ipv6_addr_use_ipv6(void) -{ - return 1; -} - /** Run unit tests for fascist_firewall_choose_address */ static void test_policies_fascist_firewall_choose_address(void *arg) @@ -2536,42 +2522,6 @@ test_policies_fascist_firewall_choose_address(void *arg) CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_DIR_CONNECTION, 1, 1, ipv4_dir_ap); - /* Test ClientAutoIPv6ORPort and pretend we prefer IPv4. */ - memset(&mock_options, 0, sizeof(or_options_t)); - mock_options.ClientAutoIPv6ORPort = 1; - mock_options.ClientUseIPv4 = 1; - mock_options.ClientUseIPv6 = 1; - MOCK(fascist_firewall_rand_prefer_ipv6_addr, - mock_fascist_firewall_rand_prefer_ipv6_addr_use_ipv4); - /* Simulate the initialisation of fake_node.ipv6_preferred */ - fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport( - &mock_options); - - CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1, - ipv4_or_ap); - CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 1, 1, - ipv4_or_ap); - - UNMOCK(fascist_firewall_rand_prefer_ipv6_addr); - - /* Test ClientAutoIPv6ORPort and pretend we prefer IPv6. */ - memset(&mock_options, 0, sizeof(or_options_t)); - mock_options.ClientAutoIPv6ORPort = 1; - mock_options.ClientUseIPv4 = 1; - mock_options.ClientUseIPv6 = 1; - MOCK(fascist_firewall_rand_prefer_ipv6_addr, - mock_fascist_firewall_rand_prefer_ipv6_addr_use_ipv6); - /* Simulate the initialisation of fake_node.ipv6_preferred */ - fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport( - &mock_options); - - CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1, - ipv6_or_ap); - CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 1, 1, - ipv6_or_ap); - - UNMOCK(fascist_firewall_rand_prefer_ipv6_addr); - /* Test firewall_choose_address_ls(). To do this, we make a fake link * specifier. */ smartlist_t *lspecs = smartlist_new(), diff --git a/src/test/test_prob_distr.c b/src/test/test_prob_distr.c index c3d1c80d70..541a81df3a 100644 --- a/src/test/test_prob_distr.c +++ b/src/test/test_prob_distr.c @@ -893,7 +893,7 @@ test_uniform_interval(void *arg) * * NIST/SEMATECH e-Handbook of Statistical Methods, Section * 1.3.6.7.4 `Critical Values of the Chi-Square Distribution', - * <http://www.itl.nist.gov/div898/handbook/eda/section3/eda3674.htm>, + * <https://www.itl.nist.gov/div898/handbook/eda/section3/eda3674.htm>, * retrieved 2018-10-28. */ @@ -1223,14 +1223,16 @@ test_stochastic_weibull_impl(double lambda, double k) .k = k, }; +// clang-format off /* * XXX Consider applying a Tiku-Singh test: * * M.L. Tiku and M. Singh, `Testing the two-parameter * Weibull distribution', Communications in Statistics -- * Theory and Methods A10(9), 1981, 907--918. - *https://www.tandfonline.com/doi/pdf/10.1080/03610928108828082?needAccess=true +https://www.tandfonline.com/doi/pdf/10.1080/03610928108828082?needAccess=true */ +// clang-format on return test_psi_dist_sample(&dist.base); } diff --git a/src/test/test_protover.c b/src/test/test_protover.c index 7341631ccc..71f984a0ac 100644 --- a/src/test/test_protover.c +++ b/src/test/test_protover.c @@ -2,6 +2,7 @@ /* See LICENSE for licensing information */ #define PROTOVER_PRIVATE +#define DIRVOTE_PRIVATE #include "orconfig.h" #include "test/test.h" @@ -12,6 +13,8 @@ #include "core/or/connection_or.h" #include "lib/tls/tortls.h" +#include "feature/dirauth/dirvote.h" + static void test_protover_parse(void *arg) { @@ -271,6 +274,7 @@ test_protover_all_supported(void *arg) tt_assert(protover_all_supported("Fribble=", &msg)); tt_ptr_op(msg, OP_EQ, NULL); +#ifndef ALL_BUGS_ARE_FATAL /* If we get a completely unparseable list, protover_all_supported should * hit a fatal assertion for BUG(entries == NULL). */ tor_capture_bugs_(1); @@ -282,9 +286,10 @@ test_protover_all_supported(void *arg) tor_capture_bugs_(1); tt_assert(protover_all_supported("Sleen=1-4294967295", &msg)); tor_end_capture_bugs_(); +#endif /* !defined(ALL_BUGS_ARE_FATAL) */ /* Protocol name too long */ -#ifndef HAVE_RUST // XXXXXX ????? +#if !defined(HAVE_RUST) && !defined(ALL_BUGS_ARE_FATAL) tor_capture_bugs_(1); tt_assert(protover_all_supported( "DoSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" @@ -292,7 +297,7 @@ test_protover_all_supported(void *arg) "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaa=1-65536", &msg)); tor_end_capture_bugs_(); -#endif /* !defined(HAVE_RUST) */ +#endif /* !defined(HAVE_RUST) && !defined(ALL_BUGS_ARE_FATAL) */ done: tor_end_capture_bugs_(); @@ -587,6 +592,43 @@ test_protover_vote_roundtrip(void *args) tor_free(result); } +static void +test_protover_vote_roundtrip_ours(void *args) +{ + (void) args; + const char *examples[] = { + protover_get_supported_protocols(), + DIRVOTE_RECOMMEND_RELAY_PROTO, + DIRVOTE_RECOMMEND_CLIENT_PROTO, + DIRVOTE_REQUIRE_RELAY_PROTO, + DIRVOTE_REQUIRE_CLIENT_PROTO, + }; + unsigned u; + smartlist_t *votes = smartlist_new(); + char *result = NULL; + + for (u = 0; u < ARRAY_LENGTH(examples); ++u) { + tt_assert(examples[u]); + const char *input = examples[u]; + const char *expected_output = examples[u]; + + smartlist_add(votes, (void*)input); + result = protover_compute_vote(votes, 1); + if (expected_output != NULL) { + tt_str_op(result, OP_EQ, expected_output); + } else { + tt_str_op(result, OP_EQ, ""); + } + + smartlist_clear(votes); + tor_free(result); + } + + done: + smartlist_free(votes); + tor_free(result); +} + #define PV_TEST(name, flags) \ { #name, test_protover_ ##name, (flags), NULL, NULL } @@ -600,5 +642,6 @@ struct testcase_t protover_tests[] = { PV_TEST(supports_version, 0), PV_TEST(supported_protocols, 0), PV_TEST(vote_roundtrip, 0), + PV_TEST(vote_roundtrip_ours, 0), END_OF_TESTCASES }; diff --git a/src/test/test_pt.c b/src/test/test_pt.c index 26eaf7b7e7..893fec3674 100644 --- a/src/test/test_pt.c +++ b/src/test/test_pt.c @@ -579,8 +579,10 @@ test_get_pt_proxy_uri(void *arg) tor_free(uri); } +#ifndef COCCI #define PT_LEGACY(name) \ - { #name, test_pt_ ## name , 0, NULL, NULL } + { (#name), test_pt_ ## name , 0, NULL, NULL } +#endif struct testcase_t pt_tests[] = { PT_LEGACY(parsing), diff --git a/src/test/test_shared_random.c b/src/test/test_shared_random.c index 8cb2238248..9e49e835c9 100644 --- a/src/test/test_shared_random.c +++ b/src/test/test_shared_random.c @@ -21,7 +21,7 @@ #include "feature/nodelist/dirlist.h" #include "feature/dirparse/authcert_parse.h" #include "feature/hs_common/shared_random_client.h" -#include "feature/dircommon/voting_schedule.h" +#include "feature/dirauth/voting_schedule.h" #include "feature/dirclient/dir_server_st.h" #include "feature/nodelist/networkstatus_st.h" @@ -204,7 +204,7 @@ test_get_state_valid_until_time(void *arg) retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:01 UTC", ¤t_time); tt_int_op(retval, OP_EQ, 0); - voting_schedule_recalculate_timing(get_options(), current_time); + dirauth_sched_recalculate_timing(get_options(), current_time); valid_until_time = get_state_valid_until_time(current_time); /* Compare it with the correct result */ @@ -216,7 +216,7 @@ test_get_state_valid_until_time(void *arg) retval = parse_rfc1123_time("Mon, 20 Apr 2015 19:22:00 UTC", ¤t_time); tt_int_op(retval, OP_EQ, 0); - voting_schedule_recalculate_timing(get_options(), current_time); + dirauth_sched_recalculate_timing(get_options(), current_time); valid_until_time = get_state_valid_until_time(current_time); format_iso_time(tbuf, valid_until_time); @@ -227,7 +227,7 @@ test_get_state_valid_until_time(void *arg) retval = parse_rfc1123_time("Mon, 20 Apr 2015 23:59:00 UTC", ¤t_time); tt_int_op(retval, OP_EQ, 0); - voting_schedule_recalculate_timing(get_options(), current_time); + dirauth_sched_recalculate_timing(get_options(), current_time); valid_until_time = get_state_valid_until_time(current_time); format_iso_time(tbuf, valid_until_time); @@ -238,7 +238,7 @@ test_get_state_valid_until_time(void *arg) retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:00 UTC", ¤t_time); tt_int_op(retval, OP_EQ, 0); - voting_schedule_recalculate_timing(get_options(), current_time); + dirauth_sched_recalculate_timing(get_options(), current_time); valid_until_time = get_state_valid_until_time(current_time); format_iso_time(tbuf, valid_until_time); @@ -278,7 +278,7 @@ test_get_start_time_of_current_run(void *arg) retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:01 UTC", ¤t_time); tt_int_op(retval, OP_EQ, 0); - voting_schedule_recalculate_timing(get_options(), current_time); + dirauth_sched_recalculate_timing(get_options(), current_time); run_start_time = sr_state_get_start_time_of_current_protocol_run(); /* Compare it with the correct result */ @@ -290,7 +290,7 @@ test_get_start_time_of_current_run(void *arg) retval = parse_rfc1123_time("Mon, 20 Apr 2015 23:59:59 UTC", ¤t_time); tt_int_op(retval, OP_EQ, 0); - voting_schedule_recalculate_timing(get_options(), current_time); + dirauth_sched_recalculate_timing(get_options(), current_time); run_start_time = sr_state_get_start_time_of_current_protocol_run(); /* Compare it with the correct result */ @@ -302,7 +302,7 @@ test_get_start_time_of_current_run(void *arg) retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:00 UTC", ¤t_time); tt_int_op(retval, OP_EQ, 0); - voting_schedule_recalculate_timing(get_options(), current_time); + dirauth_sched_recalculate_timing(get_options(), current_time); run_start_time = sr_state_get_start_time_of_current_protocol_run(); /* Compare it with the correct result */ @@ -332,7 +332,7 @@ test_get_start_time_of_current_run(void *arg) ¤t_time); tt_int_op(retval, OP_EQ, 0); update_approx_time(current_time); - voting_schedule_recalculate_timing(get_options(), current_time); + dirauth_sched_recalculate_timing(get_options(), current_time); run_start_time = sr_state_get_start_time_of_current_protocol_run(); @@ -340,7 +340,7 @@ test_get_start_time_of_current_run(void *arg) format_iso_time(tbuf, run_start_time); tt_str_op("2015-04-19 00:00:00", OP_EQ, tbuf); /* Check that voting_schedule.interval_starts is at 01:00 (see above) */ - time_t interval_starts = voting_schedule_get_next_valid_after_time(); + time_t interval_starts = dirauth_sched_get_next_valid_after_time(); format_iso_time(tbuf, interval_starts); tt_str_op("2015-04-20 01:00:00", OP_EQ, tbuf); } @@ -360,7 +360,7 @@ test_get_start_time_of_current_run(void *arg) retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:15:32 UTC", ¤t_time); tt_int_op(retval, OP_EQ, 0); - voting_schedule_recalculate_timing(get_options(), current_time); + dirauth_sched_recalculate_timing(get_options(), current_time); run_start_time = sr_state_get_start_time_of_current_protocol_run(); /* Compare it with the correct result */ @@ -392,13 +392,13 @@ test_get_start_time_functions(void *arg) tt_int_op(retval, OP_EQ, 0); time_t now = mock_consensus.valid_after; - voting_schedule_recalculate_timing(get_options(), now); + dirauth_sched_recalculate_timing(get_options(), now); time_t start_time_of_protocol_run = sr_state_get_start_time_of_current_protocol_run(); tt_assert(start_time_of_protocol_run); /* Check that the round start time of the beginning of the run, is itself */ - tt_int_op(get_start_time_of_current_round(), OP_EQ, + tt_int_op(dirauth_sched_get_cur_valid_after_time(), OP_EQ, start_time_of_protocol_run); done: diff --git a/src/test/test_util.c b/src/test/test_util.c index e7f4106d91..2aee07a26a 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -1898,6 +1898,56 @@ test_util_config_line_crlf(void *arg) tor_free(k); tor_free(v); } +static void +test_util_config_line_partition(void *arg) +{ + (void)arg; + config_line_t *lines = NULL, *orig, *rest = NULL; + + config_line_append(&lines, "Header", "X"); + config_line_append(&lines, "Item", "Y"); + config_line_append(&lines, "Thing", "Z"); + + config_line_append(&lines, "HEADER", "X2"); + + config_line_append(&lines, "header", "X3"); + config_line_append(&lines, "Item3", "Foob"); + + /* set up h2 and h3 to point to the places where we hope the headers will + be. */ + config_line_t *h2 = lines->next->next->next; + config_line_t *h3 = h2->next; + tt_str_op(h2->key, OP_EQ, "HEADER"); + tt_str_op(h3->key, OP_EQ, "header"); + + orig = lines; + rest = config_lines_partition(lines, "Header"); + tt_ptr_op(lines, OP_EQ, orig); + tt_ptr_op(rest, OP_EQ, h2); + tt_str_op(lines->next->key, OP_EQ, "Item"); + tt_str_op(lines->next->next->key, OP_EQ, "Thing"); + tt_ptr_op(lines->next->next->next, OP_EQ, NULL); + config_free_lines(lines); + + orig = lines = rest; + rest = config_lines_partition(lines, "Header"); + tt_ptr_op(lines, OP_EQ, orig); + tt_ptr_op(rest, OP_EQ, h3); + tt_ptr_op(lines->next, OP_EQ, NULL); + config_free_lines(lines); + + orig = lines = rest; + rest = config_lines_partition(lines, "Header"); + tt_ptr_op(lines, OP_EQ, orig); + tt_ptr_op(rest, OP_EQ, NULL); + tt_str_op(lines->next->key, OP_EQ, "Item3"); + tt_ptr_op(lines->next->next, OP_EQ, NULL); + + done: + config_free_lines(lines); + config_free_lines(rest); +} + #ifndef DISABLE_PWDB_TESTS static void test_util_expand_filename(void *arg) @@ -4620,6 +4670,35 @@ test_util_di_ops(void *arg) } static void +test_util_memcpy_iftrue_timei(void *arg) +{ + (void)arg; + char buf1[25]; + char buf2[25]; + char buf3[25]; + + for (int i = 0; i < 100; ++i) { + crypto_rand(buf1, sizeof(buf1)); + crypto_rand(buf2, sizeof(buf2)); + memcpy(buf3, buf1, sizeof(buf1)); + + /* We just copied buf1 into buf3. Now we're going to copy buf2 into buf2, + iff our coin flip comes up heads. */ + bool coinflip = crypto_rand_int(2) == 0; + + memcpy_if_true_timei(coinflip, buf3, buf2, sizeof(buf3)); + + if (coinflip) { + tt_mem_op(buf3, OP_EQ, buf2, sizeof(buf2)); + } else { + tt_mem_op(buf3, OP_EQ, buf1, sizeof(buf1)); + } + } + done: + ; +} + +static void test_util_di_map(void *arg) { (void)arg; @@ -5620,7 +5699,7 @@ test_util_hostname_validation(void *arg) tt_assert(string_is_valid_nonrfc_hostname("luck.y13.")); // We allow punycode TLDs. For examples, see - // http://data.iana.org/TLD/tlds-alpha-by-domain.txt + // https://data.iana.org/TLD/tlds-alpha-by-domain.txt tt_assert(string_is_valid_nonrfc_hostname("example.xn--l1acc")); done: @@ -6353,42 +6432,42 @@ test_util_map_anon_nofork(void *arg) #ifndef COCCI #define UTIL_LEGACY(name) \ - { #name, test_util_ ## name , 0, NULL, NULL } + { (#name), test_util_ ## name , 0, NULL, NULL } #define UTIL_TEST(name, flags) \ - { #name, test_util_ ## name, flags, NULL, NULL } + { (#name), test_util_ ## name, flags, NULL, NULL } #define COMPRESS(name, identifier) \ - { "compress/" #name, test_util_compress, 0, &compress_setup, \ + { ("compress/" #name), test_util_compress, 0, &compress_setup, \ (char*)(identifier) } #define COMPRESS_CONCAT(name, identifier) \ - { "compress_concat/" #name, test_util_decompress_concatenated, 0, \ + { ("compress_concat/" #name), test_util_decompress_concatenated, 0, \ &compress_setup, \ (char*)(identifier) } #define COMPRESS_JUNK(name, identifier) \ - { "compress_junk/" #name, test_util_decompress_junk, 0, \ + { ("compress_junk/" #name), test_util_decompress_junk, 0, \ &compress_setup, \ (char*)(identifier) } #define COMPRESS_DOS(name, identifier) \ - { "compress_dos/" #name, test_util_decompress_dos, 0, \ + { ("compress_dos/" #name), test_util_decompress_dos, 0, \ &compress_setup, \ (char*)(identifier) } -#endif /* !defined(COCCI) */ #ifdef _WIN32 #define UTIL_TEST_WIN_ONLY(n, f) UTIL_TEST(n, (f)) #else -#define UTIL_TEST_WIN_ONLY(n, f) { #n, NULL, TT_SKIP, NULL, NULL } +#define UTIL_TEST_WIN_ONLY(n, f) { (#n), NULL, TT_SKIP, NULL, NULL } #endif #ifdef DISABLE_PWDB_TESTS -#define UTIL_TEST_PWDB(n, f) { #n, NULL, TT_SKIP, NULL, NULL } +#define UTIL_TEST_PWDB(n, f) { (#n), NULL, TT_SKIP, NULL, NULL } #else #define UTIL_TEST_PWDB(n, f) UTIL_TEST(n, (f)) #endif +#endif /* !defined(COCCI) */ struct testcase_t util_tests[] = { UTIL_LEGACY(time), @@ -6398,6 +6477,7 @@ struct testcase_t util_tests[] = { UTIL_LEGACY(config_line_comment_character), UTIL_LEGACY(config_line_escaped_content), UTIL_LEGACY(config_line_crlf), + UTIL_TEST(config_line_partition, 0), UTIL_TEST_PWDB(expand_filename, 0), UTIL_LEGACY(escape_string_socks), UTIL_LEGACY(string_is_key_value), @@ -6434,6 +6514,7 @@ struct testcase_t util_tests[] = { UTIL_LEGACY(path_is_relative), UTIL_LEGACY(strtok), UTIL_LEGACY(di_ops), + UTIL_TEST(memcpy_iftrue_timei, 0), UTIL_TEST(di_map, 0), UTIL_TEST(round_to_next_multiple_of, 0), UTIL_TEST(laplace, 0), diff --git a/src/test/test_util_process.c b/src/test/test_util_process.c index 0e17e009f3..fc79fe9b1f 100644 --- a/src/test/test_util_process.c +++ b/src/test/test_util_process.c @@ -67,15 +67,16 @@ test_util_process_clear_waitpid_callback(void *ignored) } #endif /* !defined(_WIN32) */ +#ifndef COCCI #ifndef _WIN32 -#define TEST(name) { #name, test_util_process_##name, 0, NULL, NULL } +#define TEST(name) { (#name), test_util_process_##name, 0, NULL, NULL } #else -#define TEST(name) { #name, NULL, TT_SKIP, NULL, NULL } +#define TEST(name) { (#name), NULL, TT_SKIP, NULL, NULL } #endif +#endif /* !defined(COCCI) */ struct testcase_t util_process_tests[] = { TEST(set_waitpid_callback), TEST(clear_waitpid_callback), END_OF_TESTCASES }; - diff --git a/src/test/test_voting_schedule.c b/src/test/test_voting_schedule.c index 54d1815a77..df64b79167 100644 --- a/src/test/test_voting_schedule.c +++ b/src/test/test_voting_schedule.c @@ -4,14 +4,15 @@ #include "orconfig.h" #include "core/or/or.h" -#include "feature/dircommon/voting_schedule.h" +#include "feature/dirauth/voting_schedule.h" +#include "feature/nodelist/networkstatus.h" #include "test/test.h" static void test_voting_schedule_interval_start(void *arg) { -#define next_interval voting_schedule_get_start_of_next_interval +#define next_interval voting_sched_get_start_of_interval_after (void)arg; char buf[ISO_TIME_LEN+1]; @@ -61,4 +62,3 @@ struct testcase_t voting_schedule_tests[] = { VS(interval_start, 0), END_OF_TESTCASES }; - diff --git a/src/test/testing_common.c b/src/test/testing_common.c index d7c6edb646..d68dfa4047 100644 --- a/src/test/testing_common.c +++ b/src/test/testing_common.c @@ -273,7 +273,7 @@ main(int c, const char **v) int loglevel = LOG_ERR; int accel_crypto = 0; - subsystems_init_upto(SUBSYS_LEVEL_LIBS); + subsystems_init(); options = options_new(); |